Changeset 988 for vendor/current/source3/libsmb/clispnego.c
- Timestamp:
- Nov 24, 2016, 1:14:11 PM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
vendor/current/source3/libsmb/clispnego.c
r746 r988 27 27 28 28 /* 29 generate a negTokenInit packet given a list of supported30 OIDs (the mechanisms) a blob, and a principal name string31 */32 33 DATA_BLOB spnego_gen_negTokenInit(TALLOC_CTX *ctx,34 const char *OIDs[],35 DATA_BLOB *psecblob,36 const char *principal)37 {38 int i;39 ASN1_DATA *data;40 DATA_BLOB ret;41 42 data = asn1_init(talloc_tos());43 if (data == NULL) {44 return data_blob_null;45 }46 47 asn1_push_tag(data,ASN1_APPLICATION(0));48 asn1_write_OID(data,OID_SPNEGO);49 asn1_push_tag(data,ASN1_CONTEXT(0));50 asn1_push_tag(data,ASN1_SEQUENCE(0));51 52 asn1_push_tag(data,ASN1_CONTEXT(0));53 asn1_push_tag(data,ASN1_SEQUENCE(0));54 for (i=0; OIDs[i]; i++) {55 asn1_write_OID(data,OIDs[i]);56 }57 asn1_pop_tag(data);58 asn1_pop_tag(data);59 60 if (psecblob && psecblob->length && psecblob->data) {61 asn1_push_tag(data, ASN1_CONTEXT(2));62 asn1_write_OctetString(data,psecblob->data,63 psecblob->length);64 asn1_pop_tag(data);65 }66 67 if (principal) {68 asn1_push_tag(data, ASN1_CONTEXT(3));69 asn1_push_tag(data, ASN1_SEQUENCE(0));70 asn1_push_tag(data, ASN1_CONTEXT(0));71 asn1_write_GeneralString(data,principal);72 asn1_pop_tag(data);73 asn1_pop_tag(data);74 asn1_pop_tag(data);75 }76 77 asn1_pop_tag(data);78 asn1_pop_tag(data);79 80 asn1_pop_tag(data);81 82 if (data->has_error) {83 DEBUG(1,("Failed to build negTokenInit at offset %d\n", (int)data->ofs));84 }85 86 ret = data_blob_talloc(ctx, data->data, data->length);87 asn1_free(data);88 89 return ret;90 }91 92 /*93 29 parse a negTokenInit packet giving a GUID, a list of supported 94 30 OIDs (the mechanisms) and a principal name string … … 101 37 { 102 38 int i; 103 bool ret ;39 bool ret = false; 104 40 ASN1_DATA *data; 105 41 106 42 for (i = 0; i < ASN1_MAX_OIDS; i++) { 107 43 OIDs[i] = NULL; 44 } 45 46 if (principal) { 47 *principal = NULL; 48 } 49 if (secblob) { 50 *secblob = data_blob_null; 108 51 } 109 52 … … 113 56 } 114 57 115 asn1_load(data, blob);116 117 asn1_start_tag(data,ASN1_APPLICATION(0));118 119 asn1_check_OID(data,OID_SPNEGO);58 if (!asn1_load(data, blob)) goto err; 59 60 if (!asn1_start_tag(data,ASN1_APPLICATION(0))) goto err; 61 62 if (!asn1_check_OID(data,OID_SPNEGO)) goto err; 120 63 121 64 /* negTokenInit [0] NegTokenInit */ 122 asn1_start_tag(data,ASN1_CONTEXT(0));123 asn1_start_tag(data,ASN1_SEQUENCE(0));65 if (!asn1_start_tag(data,ASN1_CONTEXT(0))) goto err; 66 if (!asn1_start_tag(data,ASN1_SEQUENCE(0))) goto err; 124 67 125 68 /* mechTypes [0] MechTypeList OPTIONAL */ … … 128 71 * what mechanisms we have to work with. */ 129 72 130 asn1_start_tag(data,ASN1_CONTEXT(0));131 asn1_start_tag(data,ASN1_SEQUENCE(0));73 if (!asn1_start_tag(data,ASN1_CONTEXT(0))) goto err; 74 if (!asn1_start_tag(data,ASN1_SEQUENCE(0))) goto err; 132 75 for (i=0; asn1_tag_remaining(data) > 0 && i < ASN1_MAX_OIDS-1; i++) { 133 asn1_read_OID(data,ctx, &OIDs[i]); 134 if (data->has_error) { 135 break; 76 if (!asn1_read_OID(data,ctx, &OIDs[i])) { 77 goto err; 78 } 79 if (asn1_has_error(data)) { 80 goto err; 136 81 } 137 82 } 138 83 OIDs[i] = NULL; 139 asn1_end_tag(data); 140 asn1_end_tag(data); 141 142 if (principal) { 143 *principal = NULL; 144 } 145 if (secblob) { 146 *secblob = data_blob_null; 147 } 84 if (!asn1_end_tag(data)) goto err; 85 if (!asn1_end_tag(data)) goto err; 148 86 149 87 /* … … 155 93 156 94 if (asn1_peek_tag(data, ASN1_CONTEXT(1))) { 157 uint8 flags;95 uint8_t flags; 158 96 159 97 /* reqFlags [1] ContextFlags OPTIONAL */ 160 asn1_start_tag(data, ASN1_CONTEXT(1));161 asn1_start_tag(data, ASN1_BIT_STRING);98 if (!asn1_start_tag(data, ASN1_CONTEXT(1))) goto err; 99 if (!asn1_start_tag(data, ASN1_BIT_STRING)) goto err; 162 100 while (asn1_tag_remaining(data) > 0) { 163 asn1_read_uint8(data, &flags);164 } 165 asn1_end_tag(data);166 asn1_end_tag(data);101 if (!asn1_read_uint8(data, &flags)) goto err; 102 } 103 if (!asn1_end_tag(data)) goto err; 104 if (!asn1_end_tag(data)) goto err; 167 105 } 168 106 … … 170 108 DATA_BLOB sblob = data_blob_null; 171 109 /* mechToken [2] OCTET STRING OPTIONAL */ 172 asn1_start_tag(data, ASN1_CONTEXT(2)); 173 asn1_read_OctetString(data, ctx, &sblob); 174 asn1_end_tag(data); 110 if (!asn1_start_tag(data, ASN1_CONTEXT(2))) goto err; 111 if (!asn1_read_OctetString(data, ctx, &sblob)) goto err; 112 if (!asn1_end_tag(data)) { 113 data_blob_free(&sblob); 114 goto err; 115 } 175 116 if (secblob) { 176 117 *secblob = sblob; … … 183 124 char *princ = NULL; 184 125 /* mechListMIC [3] OCTET STRING OPTIONAL */ 185 asn1_start_tag(data, ASN1_CONTEXT(3));186 asn1_start_tag(data, ASN1_SEQUENCE(0));187 asn1_start_tag(data, ASN1_CONTEXT(0));188 asn1_read_GeneralString(data, ctx, &princ);189 asn1_end_tag(data);190 asn1_end_tag(data);191 asn1_end_tag(data);126 if (!asn1_start_tag(data, ASN1_CONTEXT(3))) goto err; 127 if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto err; 128 if (!asn1_start_tag(data, ASN1_CONTEXT(0))) goto err; 129 if (!asn1_read_GeneralString(data, ctx, &princ)) goto err; 130 if (!asn1_end_tag(data)) goto err; 131 if (!asn1_end_tag(data)) goto err; 132 if (!asn1_end_tag(data)) goto err; 192 133 if (principal) { 193 134 *principal = princ; … … 197 138 } 198 139 199 asn1_end_tag(data); 200 asn1_end_tag(data); 201 202 asn1_end_tag(data); 203 204 ret = !data->has_error; 205 if (data->has_error) { 140 if (!asn1_end_tag(data)) goto err; 141 if (!asn1_end_tag(data)) goto err; 142 143 if (!asn1_end_tag(data)) goto err; 144 145 ret = !asn1_has_error(data); 146 147 err: 148 149 if (asn1_has_error(data)) { 206 150 int j; 207 151 if (principal) { … … 223 167 generate a krb5 GSS-API wrapper packet given a ticket 224 168 */ 225 DATA_BLOB spnego_gen_krb5_wrap(TALLOC_CTX *ctx, const DATA_BLOB ticket, const uint8 tok_id[2])169 DATA_BLOB spnego_gen_krb5_wrap(TALLOC_CTX *ctx, const DATA_BLOB ticket, const uint8_t tok_id[2]) 226 170 { 227 171 ASN1_DATA *data; 228 DATA_BLOB ret ;172 DATA_BLOB ret = data_blob_null; 229 173 230 174 data = asn1_init(talloc_tos()); … … 233 177 } 234 178 235 asn1_push_tag(data, ASN1_APPLICATION(0)); 236 asn1_write_OID(data, OID_KERBEROS5); 237 238 asn1_write(data, tok_id, 2); 239 asn1_write(data, ticket.data, ticket.length); 240 asn1_pop_tag(data); 241 242 if (data->has_error) { 243 DEBUG(1,("Failed to build krb5 wrapper at offset %d\n", (int)data->ofs)); 244 } 245 246 ret = data_blob_talloc(ctx, data->data, data->length); 179 if (!asn1_push_tag(data, ASN1_APPLICATION(0))) goto err; 180 if (!asn1_write_OID(data, OID_KERBEROS5)) goto err; 181 182 if (!asn1_write(data, tok_id, 2)) goto err; 183 if (!asn1_write(data, ticket.data, ticket.length)) goto err; 184 if (!asn1_pop_tag(data)) goto err; 185 186 if (!asn1_extract_blob(data, ctx, &ret)) { 187 goto err; 188 } 189 247 190 asn1_free(data); 191 data = NULL; 192 193 err: 194 195 if (data != NULL) { 196 if (asn1_has_error(data)) { 197 DEBUG(1, ("Failed to build krb5 wrapper at offset %d\n", 198 (int)asn1_current_ofs(data))); 199 } 200 201 asn1_free(data); 202 } 248 203 249 204 return ret; 250 205 } 251 252 /*253 parse a krb5 GSS-API wrapper packet giving a ticket254 */255 bool spnego_parse_krb5_wrap(TALLOC_CTX *ctx, DATA_BLOB blob, DATA_BLOB *ticket, uint8 tok_id[2])256 {257 bool ret;258 ASN1_DATA *data;259 int data_remaining;260 *ticket = data_blob_null;261 262 data = asn1_init(talloc_tos());263 if (data == NULL) {264 return false;265 }266 267 asn1_load(data, blob);268 asn1_start_tag(data, ASN1_APPLICATION(0));269 asn1_check_OID(data, OID_KERBEROS5);270 271 data_remaining = asn1_tag_remaining(data);272 273 if (data_remaining < 3) {274 data->has_error = True;275 } else {276 asn1_read(data, tok_id, 2);277 data_remaining -= 2;278 *ticket = data_blob_talloc(ctx, NULL, data_remaining);279 asn1_read(data, ticket->data, ticket->length);280 }281 282 asn1_end_tag(data);283 284 ret = !data->has_error;285 286 if (data->has_error) {287 data_blob_free(ticket);288 }289 290 asn1_free(data);291 292 return ret;293 }294 295 296 /*297 generate a SPNEGO krb5 negTokenInit packet, ready for a EXTENDED_SECURITY298 kerberos session setup299 */300 int spnego_gen_krb5_negTokenInit(TALLOC_CTX *ctx,301 const char *principal, int time_offset,302 DATA_BLOB *targ,303 DATA_BLOB *session_key_krb5, uint32 extra_ap_opts,304 time_t *expire_time)305 {306 int retval;307 DATA_BLOB tkt, tkt_wrapped;308 const char *krb_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, OID_NTLMSSP, NULL};309 310 /* get a kerberos ticket for the service and extract the session key */311 retval = cli_krb5_get_ticket(ctx, principal, time_offset,312 &tkt, session_key_krb5,313 extra_ap_opts, NULL,314 expire_time, NULL);315 if (retval) {316 return retval;317 }318 319 /* wrap that up in a nice GSS-API wrapping */320 tkt_wrapped = spnego_gen_krb5_wrap(ctx, tkt, TOK_ID_KRB_AP_REQ);321 322 /* and wrap that in a shiny SPNEGO wrapper */323 *targ = spnego_gen_negTokenInit(ctx, krb_mechs, &tkt_wrapped, NULL);324 325 data_blob_free(&tkt_wrapped);326 data_blob_free(&tkt);327 328 return retval;329 }330 331 332 /*333 parse a spnego NTLMSSP challenge packet giving two security blobs334 */335 bool spnego_parse_challenge(TALLOC_CTX *ctx, const DATA_BLOB blob,336 DATA_BLOB *chal1, DATA_BLOB *chal2)337 {338 bool ret;339 ASN1_DATA *data;340 341 ZERO_STRUCTP(chal1);342 ZERO_STRUCTP(chal2);343 344 data = asn1_init(talloc_tos());345 if (data == NULL) {346 return false;347 }348 349 asn1_load(data, blob);350 asn1_start_tag(data,ASN1_CONTEXT(1));351 asn1_start_tag(data,ASN1_SEQUENCE(0));352 353 asn1_start_tag(data,ASN1_CONTEXT(0));354 asn1_check_enumerated(data,1);355 asn1_end_tag(data);356 357 asn1_start_tag(data,ASN1_CONTEXT(1));358 asn1_check_OID(data, OID_NTLMSSP);359 asn1_end_tag(data);360 361 asn1_start_tag(data,ASN1_CONTEXT(2));362 asn1_read_OctetString(data, ctx, chal1);363 asn1_end_tag(data);364 365 /* the second challenge is optional (XP doesn't send it) */366 if (asn1_tag_remaining(data)) {367 asn1_start_tag(data,ASN1_CONTEXT(3));368 asn1_read_OctetString(data, ctx, chal2);369 asn1_end_tag(data);370 }371 372 asn1_end_tag(data);373 asn1_end_tag(data);374 375 ret = !data->has_error;376 377 if (data->has_error) {378 data_blob_free(chal1);379 data_blob_free(chal2);380 }381 382 asn1_free(data);383 return ret;384 }385 386 387 /*388 generate a SPNEGO auth packet. This will contain the encrypted passwords389 */390 DATA_BLOB spnego_gen_auth(TALLOC_CTX *ctx, DATA_BLOB blob)391 {392 ASN1_DATA *data;393 DATA_BLOB ret;394 395 data = asn1_init(talloc_tos());396 if (data == NULL) {397 return data_blob_null;398 }399 400 asn1_push_tag(data, ASN1_CONTEXT(1));401 asn1_push_tag(data, ASN1_SEQUENCE(0));402 asn1_push_tag(data, ASN1_CONTEXT(2));403 asn1_write_OctetString(data,blob.data,blob.length);404 asn1_pop_tag(data);405 asn1_pop_tag(data);406 asn1_pop_tag(data);407 408 ret = data_blob_talloc(ctx, data->data, data->length);409 410 asn1_free(data);411 412 return ret;413 }414 415 /*416 parse a SPNEGO auth packet. This contains the encrypted passwords417 */418 bool spnego_parse_auth_and_mic(TALLOC_CTX *ctx, DATA_BLOB blob,419 DATA_BLOB *auth, DATA_BLOB *signature)420 {421 ssize_t len;422 struct spnego_data token;423 424 len = spnego_read_data(talloc_tos(), blob, &token);425 if (len == -1) {426 DEBUG(3,("spnego_parse_auth: spnego_read_data failed\n"));427 return false;428 }429 430 if (token.type != SPNEGO_NEG_TOKEN_TARG) {431 DEBUG(3,("spnego_parse_auth: wrong token type: %d\n",432 token.type));433 spnego_free_data(&token);434 return false;435 }436 437 *auth = data_blob_talloc(ctx,438 token.negTokenTarg.responseToken.data,439 token.negTokenTarg.responseToken.length);440 441 if (!signature) {442 goto done;443 }444 445 *signature = data_blob_talloc(ctx,446 token.negTokenTarg.mechListMIC.data,447 token.negTokenTarg.mechListMIC.length);448 449 done:450 spnego_free_data(&token);451 452 return true;453 }454 455 bool spnego_parse_auth(TALLOC_CTX *ctx, DATA_BLOB blob, DATA_BLOB *auth)456 {457 return spnego_parse_auth_and_mic(ctx, blob, auth, NULL);458 }459 460 /*461 generate a minimal SPNEGO response packet. Doesn't contain much.462 */463 DATA_BLOB spnego_gen_auth_response_and_mic(TALLOC_CTX *ctx,464 NTSTATUS nt_status,465 const char *mechOID,466 DATA_BLOB *reply,467 DATA_BLOB *mechlistMIC)468 {469 ASN1_DATA *data;470 DATA_BLOB ret;471 uint8 negResult;472 473 if (NT_STATUS_IS_OK(nt_status)) {474 negResult = SPNEGO_ACCEPT_COMPLETED;475 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {476 negResult = SPNEGO_ACCEPT_INCOMPLETE;477 } else {478 negResult = SPNEGO_REJECT;479 }480 481 data = asn1_init(talloc_tos());482 if (data == NULL) {483 return data_blob_null;484 }485 486 asn1_push_tag(data, ASN1_CONTEXT(1));487 asn1_push_tag(data, ASN1_SEQUENCE(0));488 asn1_push_tag(data, ASN1_CONTEXT(0));489 asn1_write_enumerated(data, negResult);490 asn1_pop_tag(data);491 492 if (mechOID) {493 asn1_push_tag(data,ASN1_CONTEXT(1));494 asn1_write_OID(data, mechOID);495 asn1_pop_tag(data);496 }497 498 if (reply && reply->data != NULL) {499 asn1_push_tag(data,ASN1_CONTEXT(2));500 asn1_write_OctetString(data, reply->data, reply->length);501 asn1_pop_tag(data);502 }503 504 if (mechlistMIC && mechlistMIC->data != NULL) {505 asn1_push_tag(data, ASN1_CONTEXT(3));506 asn1_write_OctetString(data,507 mechlistMIC->data,508 mechlistMIC->length);509 asn1_pop_tag(data);510 }511 512 asn1_pop_tag(data);513 asn1_pop_tag(data);514 515 ret = data_blob_talloc(ctx, data->data, data->length);516 asn1_free(data);517 return ret;518 }519 520 DATA_BLOB spnego_gen_auth_response(TALLOC_CTX *ctx, DATA_BLOB *reply,521 NTSTATUS nt_status, const char *mechOID)522 {523 return spnego_gen_auth_response_and_mic(ctx, nt_status,524 mechOID, reply, NULL);525 }526 527 /*528 parse a SPNEGO auth packet. This contains the encrypted passwords529 */530 bool spnego_parse_auth_response(TALLOC_CTX *ctx,531 DATA_BLOB blob, NTSTATUS nt_status,532 const char *mechOID,533 DATA_BLOB *auth)534 {535 ASN1_DATA *data;536 uint8 negResult;537 538 if (NT_STATUS_IS_OK(nt_status)) {539 negResult = SPNEGO_ACCEPT_COMPLETED;540 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {541 negResult = SPNEGO_ACCEPT_INCOMPLETE;542 } else {543 negResult = SPNEGO_REJECT;544 }545 546 data = asn1_init(talloc_tos());547 if (data == NULL) {548 return false;549 }550 551 asn1_load(data, blob);552 asn1_start_tag(data, ASN1_CONTEXT(1));553 asn1_start_tag(data, ASN1_SEQUENCE(0));554 asn1_start_tag(data, ASN1_CONTEXT(0));555 asn1_check_enumerated(data, negResult);556 asn1_end_tag(data);557 558 *auth = data_blob_null;559 560 if (asn1_tag_remaining(data)) {561 asn1_start_tag(data,ASN1_CONTEXT(1));562 asn1_check_OID(data, mechOID);563 asn1_end_tag(data);564 565 if (asn1_tag_remaining(data)) {566 asn1_start_tag(data,ASN1_CONTEXT(2));567 asn1_read_OctetString(data, ctx, auth);568 asn1_end_tag(data);569 }570 } else if (negResult == SPNEGO_ACCEPT_INCOMPLETE) {571 data->has_error = 1;572 }573 574 /* Binding against Win2K DC returns a duplicate of the responseToken in575 * the optional mechListMIC field. This is a bug in Win2K. We ignore576 * this field if it exists. Win2K8 may return a proper mechListMIC at577 * which point we need to implement the integrity checking. */578 if (asn1_tag_remaining(data)) {579 DATA_BLOB mechList = data_blob_null;580 asn1_start_tag(data, ASN1_CONTEXT(3));581 asn1_read_OctetString(data, ctx, &mechList);582 asn1_end_tag(data);583 data_blob_free(&mechList);584 DEBUG(5,("spnego_parse_auth_response received mechListMIC, "585 "ignoring.\n"));586 }587 588 asn1_end_tag(data);589 asn1_end_tag(data);590 591 if (data->has_error) {592 DEBUG(3,("spnego_parse_auth_response failed at %d\n", (int)data->ofs));593 asn1_free(data);594 data_blob_free(auth);595 return False;596 }597 598 asn1_free(data);599 return True;600 }601 602 bool spnego_mech_list_blob(TALLOC_CTX *mem_ctx,603 char **oid_list, DATA_BLOB *raw_data)604 {605 ASN1_DATA *data;606 unsigned int idx;607 608 if (!oid_list || !oid_list[0] || !raw_data) {609 return false;610 }611 612 data = asn1_init(talloc_tos());613 if (data == NULL) {614 return false;615 }616 617 asn1_push_tag(data, ASN1_SEQUENCE(0));618 for (idx = 0; oid_list[idx]; idx++) {619 asn1_write_OID(data, oid_list[idx]);620 }621 asn1_pop_tag(data);622 623 if (data->has_error) {624 DEBUG(3, (__location__ " failed at %d\n", (int)data->ofs));625 asn1_free(data);626 return false;627 }628 629 *raw_data = data_blob_talloc(mem_ctx, data->data, data->length);630 if (!raw_data->data) {631 DEBUG(3, (__location__": data_blob_talloc() failed!\n"));632 asn1_free(data);633 return false;634 }635 636 asn1_free(data);637 return true;638 }
Note:
See TracChangeset
for help on using the changeset viewer.