/* generate a krb5 GSS-API wrapper packet given a ticket */ DATA_BLOB spnego_gen_krb5_wrap(DATA_BLOB ticket, const uint8 tok_id[2]) { ASN1_DATA data; DATA_BLOB ret; memset(&data, 0, sizeof(data)); asn1_push_tag(&data, ASN1_APPLICATION(0)); asn1_write_OID(&data, OID_KERBEROS5); asn1_write(&data, tok_id, 2); asn1_write(&data, ticket.data, ticket.length); asn1_pop_tag(&data); if (data.has_error) { DEBUG(1,("Failed to build krb5 wrapper at offset %d\n", (int)data.ofs)); asn1_free(&data); } ret = data_blob(data.data, data.length); asn1_free(&data); return ret; }
ssize_t read_spnego_data(DATA_BLOB data, SPNEGO_DATA *token) { ASN1_DATA asn1; ssize_t ret = -1; ZERO_STRUCTP(token); ZERO_STRUCT(asn1); asn1_load(&asn1, data); switch (asn1.data[asn1.ofs]) { case ASN1_APPLICATION(0): asn1_start_tag(&asn1, ASN1_APPLICATION(0)); asn1_check_OID(&asn1, OID_SPNEGO); if (read_negTokenInit(&asn1, &token->negTokenInit)) { token->type = SPNEGO_NEG_TOKEN_INIT; } asn1_end_tag(&asn1); break; case ASN1_CONTEXT(1): if (read_negTokenTarg(&asn1, &token->negTokenTarg)) { token->type = SPNEGO_NEG_TOKEN_TARG; } break; default: break; } if (!asn1.has_error) ret = asn1.ofs; asn1_free(&asn1); return ret; }
/* generate a krb5 GSS-API wrapper packet given a ticket */ DATA_BLOB spnego_gen_krb5_wrap(TALLOC_CTX *ctx, const DATA_BLOB ticket, const uint8_t tok_id[2]) { ASN1_DATA *data; DATA_BLOB ret = data_blob_null; data = asn1_init(talloc_tos()); if (data == NULL) { return data_blob_null; } if (!asn1_push_tag(data, ASN1_APPLICATION(0))) goto err; if (!asn1_write_OID(data, OID_KERBEROS5)) goto err; if (!asn1_write(data, tok_id, 2)) goto err; if (!asn1_write(data, ticket.data, ticket.length)) goto err; if (!asn1_pop_tag(data)) goto err; if (!asn1_extract_blob(data, ctx, &ret)) { goto err; } err: if (asn1_has_error(data)) { DEBUG(1, ("Failed to build krb5 wrapper at offset %d\n", (int)asn1_current_ofs(data))); } asn1_free(data); return ret; }
ssize_t spnego_write_data(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct spnego_data *spnego) { struct asn1_data *asn1 = asn1_init(mem_ctx); ssize_t ret = -1; if (asn1 == NULL) { return -1; } switch (spnego->type) { case SPNEGO_NEG_TOKEN_INIT: asn1_push_tag(asn1, ASN1_APPLICATION(0)); asn1_write_OID(asn1, GENSEC_OID_SPNEGO); write_negTokenInit(asn1, &spnego->negTokenInit); asn1_pop_tag(asn1); break; case SPNEGO_NEG_TOKEN_TARG: write_negTokenTarg(asn1, &spnego->negTokenTarg); break; default: asn1->has_error = true; break; } if (!asn1->has_error) { *blob = data_blob_talloc(mem_ctx, asn1->data, asn1->length); ret = asn1->ofs; } asn1_free(asn1); return ret; }
/* parse a krb5 GSS-API wrapper packet giving a ticket */ static bool gensec_gssapi_parse_krb5_wrap(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, DATA_BLOB *ticket, uint8_t tok_id[2]) { bool ret; struct asn1_data *data = asn1_init(mem_ctx); int data_remaining; if (!data) { return false; } asn1_load(data, *blob); asn1_start_tag(data, ASN1_APPLICATION(0)); asn1_check_OID(data, GENSEC_OID_KERBEROS5); data_remaining = asn1_tag_remaining(data); if (data_remaining < 3) { data->has_error = true; } else { asn1_read(data, tok_id, 2); data_remaining -= 2; *ticket = data_blob_talloc(mem_ctx, NULL, data_remaining); asn1_read(data, ticket->data, ticket->length); } asn1_end_tag(data); ret = !data->has_error; asn1_free(data); return ret; }
ssize_t write_spnego_data(DATA_BLOB *blob, SPNEGO_DATA *spnego) { ASN1_DATA asn1; ssize_t ret = -1; ZERO_STRUCT(asn1); switch (spnego->type) { case SPNEGO_NEG_TOKEN_INIT: asn1_push_tag(&asn1, ASN1_APPLICATION(0)); asn1_write_OID(&asn1, OID_SPNEGO); write_negTokenInit(&asn1, &spnego->negTokenInit); asn1_pop_tag(&asn1); break; case SPNEGO_NEG_TOKEN_TARG: write_negTokenTarg(&asn1, &spnego->negTokenTarg); break; default: asn1.has_error = True; break; } if (!asn1.has_error) { *blob = data_blob(asn1.data, asn1.length); ret = asn1.ofs; } asn1_free(&asn1); return ret; }
/* parse a krb5 GSS-API wrapper packet giving a ticket */ BOOL spnego_parse_krb5_wrap(DATA_BLOB blob, DATA_BLOB *ticket, uint8 tok_id[2]) { BOOL ret; ASN1_DATA data; int data_remaining; asn1_load(&data, blob); asn1_start_tag(&data, ASN1_APPLICATION(0)); asn1_check_OID(&data, OID_KERBEROS5); data_remaining = asn1_tag_remaining(&data); if (data_remaining < 3) { data.has_error = True; } else { asn1_read(&data, tok_id, 2); data_remaining -= 2; *ticket = data_blob(NULL, data_remaining); asn1_read(&data, ticket->data, ticket->length); } asn1_end_tag(&data); ret = !data.has_error; asn1_free(&data); return ret; }
/* generate a krb5 GSS-API wrapper packet given a ticket */ DATA_BLOB spnego_gen_krb5_wrap(TALLOC_CTX *ctx, const DATA_BLOB ticket, const uint8 tok_id[2]) { ASN1_DATA *data; DATA_BLOB ret; data = asn1_init(talloc_tos()); if (data == NULL) { return data_blob_null; } asn1_push_tag(data, ASN1_APPLICATION(0)); asn1_write_OID(data, OID_KERBEROS5); asn1_write(data, tok_id, 2); asn1_write(data, ticket.data, ticket.length); asn1_pop_tag(data); if (data->has_error) { DEBUG(1,("Failed to build krb5 wrapper at offset %d\n", (int)data->ofs)); } ret = data_blob_talloc(ctx, data->data, data->length); asn1_free(data); return ret; }
/* generate a krb5 GSS-API wrapper packet given a ticket */ static DATA_BLOB gensec_gssapi_gen_krb5_wrap(TALLOC_CTX *mem_ctx, const DATA_BLOB *ticket, const uint8_t tok_id[2]) { struct asn1_data *data; DATA_BLOB ret; data = asn1_init(mem_ctx); if (!data || !ticket->data) { return data_blob(NULL,0); } asn1_push_tag(data, ASN1_APPLICATION(0)); asn1_write_OID(data, GENSEC_OID_KERBEROS5); asn1_write(data, tok_id, 2); asn1_write(data, ticket->data, ticket->length); asn1_pop_tag(data); if (data->has_error) { DEBUG(1,("Failed to build krb5 wrapper at offset %d\n", (int)data->ofs)); asn1_free(data); return data_blob(NULL,0); } ret = data_blob_talloc(mem_ctx, data->data, data->length); asn1_free(data); return ret; }
ssize_t spnego_read_data(TALLOC_CTX *mem_ctx, DATA_BLOB data, struct spnego_data *token) { struct asn1_data *asn1; ssize_t ret = -1; uint8_t context; ZERO_STRUCTP(token); if (data.length == 0) { return ret; } asn1 = asn1_init(mem_ctx); if (asn1 == NULL) { return -1; } asn1_load(asn1, data); if (!asn1_peek_uint8(asn1, &context)) { asn1->has_error = true; } else { switch (context) { case ASN1_APPLICATION(0): asn1_start_tag(asn1, ASN1_APPLICATION(0)); asn1_check_OID(asn1, GENSEC_OID_SPNEGO); if (read_negTokenInit(asn1, mem_ctx, &token->negTokenInit)) { token->type = SPNEGO_NEG_TOKEN_INIT; } asn1_end_tag(asn1); break; case ASN1_CONTEXT(1): if (read_negTokenTarg(asn1, mem_ctx, &token->negTokenTarg)) { token->type = SPNEGO_NEG_TOKEN_TARG; } break; default: asn1->has_error = true; break; } } if (!asn1->has_error) ret = asn1->ofs; asn1_free(asn1); return ret; }
DATA_BLOB spnego_gen_negTokenInit(TALLOC_CTX *ctx, const char *OIDs[], DATA_BLOB *psecblob, const char *principal) { int i; ASN1_DATA *data; DATA_BLOB ret; data = asn1_init(talloc_tos()); if (data == NULL) { return data_blob_null; } asn1_push_tag(data,ASN1_APPLICATION(0)); asn1_write_OID(data,OID_SPNEGO); asn1_push_tag(data,ASN1_CONTEXT(0)); asn1_push_tag(data,ASN1_SEQUENCE(0)); asn1_push_tag(data,ASN1_CONTEXT(0)); asn1_push_tag(data,ASN1_SEQUENCE(0)); for (i=0; OIDs[i]; i++) { asn1_write_OID(data,OIDs[i]); } asn1_pop_tag(data); asn1_pop_tag(data); if (psecblob && psecblob->length && psecblob->data) { asn1_push_tag(data, ASN1_CONTEXT(2)); asn1_write_OctetString(data,psecblob->data, psecblob->length); asn1_pop_tag(data); } if (principal) { asn1_push_tag(data, ASN1_CONTEXT(3)); asn1_push_tag(data, ASN1_SEQUENCE(0)); asn1_push_tag(data, ASN1_CONTEXT(0)); asn1_write_GeneralString(data,principal); asn1_pop_tag(data); asn1_pop_tag(data); asn1_pop_tag(data); } asn1_pop_tag(data); asn1_pop_tag(data); asn1_pop_tag(data); if (data->has_error) { DEBUG(1,("Failed to build negTokenInit at offset %d\n", (int)data->ofs)); } ret = data_blob_talloc(ctx, data->data, data->length); asn1_free(data); return ret; }
/* generate a negTokenInit packet given a GUID, a list of supported OIDs (the mechanisms) and a principal name string */ DATA_BLOB spnego_gen_negTokenInit(uint8 guid[16], const char *OIDs[], const char *principal) { int i; ASN1_DATA data; DATA_BLOB ret; memset(&data, 0, sizeof(data)); asn1_write(&data, guid, 16); asn1_push_tag(&data,ASN1_APPLICATION(0)); asn1_write_OID(&data,OID_SPNEGO); asn1_push_tag(&data,ASN1_CONTEXT(0)); asn1_push_tag(&data,ASN1_SEQUENCE(0)); asn1_push_tag(&data,ASN1_CONTEXT(0)); asn1_push_tag(&data,ASN1_SEQUENCE(0)); for (i=0; OIDs[i]; i++) { asn1_write_OID(&data,OIDs[i]); } asn1_pop_tag(&data); asn1_pop_tag(&data); asn1_push_tag(&data, ASN1_CONTEXT(3)); asn1_push_tag(&data, ASN1_SEQUENCE(0)); asn1_push_tag(&data, ASN1_CONTEXT(0)); asn1_write_GeneralString(&data,principal); asn1_pop_tag(&data); asn1_pop_tag(&data); asn1_pop_tag(&data); asn1_pop_tag(&data); asn1_pop_tag(&data); asn1_pop_tag(&data); if (data.has_error) { DEBUG(1,("Failed to build negTokenInit at offset %d\n", (int)data.ofs)); asn1_free(&data); } ret = data_blob(data.data, data.length); asn1_free(&data); return ret; }
/* magic check a GSS-API wrapper packet for an Kerberos OID */ static bool gensec_gssapi_check_oid(const DATA_BLOB *blob, const char *oid) { bool ret; struct asn1_data *data = asn1_init(NULL); if (!data) return false; asn1_load(data, *blob); asn1_start_tag(data, ASN1_APPLICATION(0)); asn1_check_OID(data, oid); ret = !data->has_error; asn1_free(data); return ret; }
/* parse a negTokenInit packet giving a GUID, a list of supported OIDs (the mechanisms) and a principal name string */ BOOL spnego_parse_negTokenInit(DATA_BLOB blob, char *OIDs[ASN1_MAX_OIDS], char **principal) { int i; BOOL ret; ASN1_DATA data; asn1_load(&data, blob); asn1_start_tag(&data,ASN1_APPLICATION(0)); asn1_check_OID(&data,OID_SPNEGO); asn1_start_tag(&data,ASN1_CONTEXT(0)); asn1_start_tag(&data,ASN1_SEQUENCE(0)); asn1_start_tag(&data,ASN1_CONTEXT(0)); asn1_start_tag(&data,ASN1_SEQUENCE(0)); for (i=0; asn1_tag_remaining(&data) > 0 && i < ASN1_MAX_OIDS; i++) { char *oid_str = NULL; asn1_read_OID(&data,&oid_str); OIDs[i] = oid_str; } OIDs[i] = NULL; asn1_end_tag(&data); asn1_end_tag(&data); asn1_start_tag(&data, ASN1_CONTEXT(3)); asn1_start_tag(&data, ASN1_SEQUENCE(0)); asn1_start_tag(&data, ASN1_CONTEXT(0)); asn1_read_GeneralString(&data,principal); asn1_end_tag(&data); asn1_end_tag(&data); asn1_end_tag(&data); asn1_end_tag(&data); asn1_end_tag(&data); asn1_end_tag(&data); ret = !data.has_error; asn1_free(&data); return ret; }
/* generate a negTokenTarg packet given a list of OIDs and a security blob */ DATA_BLOB gen_negTokenTarg(const char *OIDs[], DATA_BLOB blob) { int i; ASN1_DATA data; DATA_BLOB ret; memset(&data, 0, sizeof(data)); asn1_push_tag(&data, ASN1_APPLICATION(0)); asn1_write_OID(&data,OID_SPNEGO); asn1_push_tag(&data, ASN1_CONTEXT(0)); asn1_push_tag(&data, ASN1_SEQUENCE(0)); asn1_push_tag(&data, ASN1_CONTEXT(0)); asn1_push_tag(&data, ASN1_SEQUENCE(0)); for (i=0; OIDs[i]; i++) { asn1_write_OID(&data,OIDs[i]); } asn1_pop_tag(&data); asn1_pop_tag(&data); asn1_push_tag(&data, ASN1_CONTEXT(2)); asn1_write_OctetString(&data,blob.data,blob.length); asn1_pop_tag(&data); asn1_pop_tag(&data); asn1_pop_tag(&data); asn1_pop_tag(&data); if (data.has_error) { DEBUG(1,("Failed to build negTokenTarg at offset %d\n", (int)data.ofs)); asn1_free(&data); } ret = data_blob(data.data, data.length); asn1_free(&data); return ret; }
/* parse a negTokenTarg packet giving a list of OIDs and a security blob */ BOOL parse_negTokenTarg(DATA_BLOB blob, char *OIDs[ASN1_MAX_OIDS], DATA_BLOB *secblob) { int i; ASN1_DATA data; asn1_load(&data, blob); asn1_start_tag(&data, ASN1_APPLICATION(0)); asn1_check_OID(&data,OID_SPNEGO); asn1_start_tag(&data, ASN1_CONTEXT(0)); asn1_start_tag(&data, ASN1_SEQUENCE(0)); asn1_start_tag(&data, ASN1_CONTEXT(0)); asn1_start_tag(&data, ASN1_SEQUENCE(0)); for (i=0; asn1_tag_remaining(&data) > 0 && i < ASN1_MAX_OIDS; i++) { char *oid_str = NULL; asn1_read_OID(&data,&oid_str); OIDs[i] = oid_str; } OIDs[i] = NULL; asn1_end_tag(&data); asn1_end_tag(&data); asn1_start_tag(&data, ASN1_CONTEXT(2)); asn1_read_OctetString(&data,secblob); asn1_end_tag(&data); asn1_end_tag(&data); asn1_end_tag(&data); asn1_end_tag(&data); if (data.has_error) { DEBUG(1,("Failed to parse negTokenTarg at offset %d\n", (int)data.ofs)); asn1_free(&data); return False; } asn1_free(&data); return True; }
/* parse a krb5 GSS-API wrapper packet giving a ticket */ bool spnego_parse_krb5_wrap(TALLOC_CTX *ctx, DATA_BLOB blob, DATA_BLOB *ticket, uint8 tok_id[2]) { bool ret; ASN1_DATA *data; int data_remaining; data = asn1_init(talloc_tos()); if (data == NULL) { return false; } asn1_load(data, blob); asn1_start_tag(data, ASN1_APPLICATION(0)); asn1_check_OID(data, OID_KERBEROS5); data_remaining = asn1_tag_remaining(data); if (data_remaining < 3) { data->has_error = True; } else { asn1_read(data, tok_id, 2); data_remaining -= 2; *ticket = data_blob_talloc(ctx, NULL, data_remaining); asn1_read(data, ticket->data, ticket->length); } asn1_end_tag(data); ret = !data->has_error; if (data->has_error) { data_blob_free(ticket); } asn1_free(data); return ret; }
/* receive a cldap netlogon reply */ static int recv_cldap_netlogon(int sock, struct cldap_netlogon_reply *reply) { int ret; ASN1_DATA data; DATA_BLOB blob; DATA_BLOB os1, os2, os3; uint32 i1; char *p; blob = data_blob(NULL, 8192); ret = read(sock, blob.data, blob.length); if (ret <= 0) { d_printf("no reply received to cldap netlogon\n"); return -1; } blob.length = ret; asn1_load(&data, blob); asn1_start_tag(&data, ASN1_SEQUENCE(0)); asn1_read_Integer(&data, &i1); asn1_start_tag(&data, ASN1_APPLICATION(4)); asn1_read_OctetString(&data, &os1); asn1_start_tag(&data, ASN1_SEQUENCE(0)); asn1_start_tag(&data, ASN1_SEQUENCE(0)); asn1_read_OctetString(&data, &os2); asn1_start_tag(&data, ASN1_SET); asn1_read_OctetString(&data, &os3); asn1_end_tag(&data); asn1_end_tag(&data); asn1_end_tag(&data); asn1_end_tag(&data); asn1_end_tag(&data); if (data.has_error) { d_printf("Failed to parse cldap reply\n"); return -1; } p = (char *)os3.data; reply->type = IVAL(p, 0); p += 4; reply->flags = IVAL(p, 0); p += 4; memcpy(&reply->guid.info, p, UUID_FLAT_SIZE); p += UUID_FLAT_SIZE; p += pull_netlogon_string(reply->forest, p, (const char *)os3.data); p += pull_netlogon_string(reply->domain, p, (const char *)os3.data); p += pull_netlogon_string(reply->hostname, p, (const char *)os3.data); p += pull_netlogon_string(reply->netbios_domain, p, (const char *)os3.data); p += pull_netlogon_string(reply->netbios_hostname, p, (const char *)os3.data); p += pull_netlogon_string(reply->unk, p, (const char *)os3.data); if (reply->type == SAMLOGON_AD_R) { p += pull_netlogon_string(reply->user_name, p, (const char *)os3.data); } else { *reply->user_name = 0; } p += pull_netlogon_string(reply->site_name, p, (const char *)os3.data); p += pull_netlogon_string(reply->site_name_2, p, (const char *)os3.data); reply->version = IVAL(p, 0); reply->lmnt_token = SVAL(p, 4); reply->lm20_token = SVAL(p, 6); data_blob_free(&os1); data_blob_free(&os2); data_blob_free(&os3); data_blob_free(&blob); return 0; }
static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf, char *outbuf, int length,int bufsize) { uint8 *p; DATA_BLOB blob1; int ret; size_t bufrem; fstring native_os, native_lanman, primary_domain; char *p2; uint16 data_blob_len = SVAL(inbuf, smb_vwv7); enum remote_arch_types ra_type = get_remote_arch(); int vuid = SVAL(inbuf,smb_uid); user_struct *vuser = NULL; NTSTATUS status = NT_STATUS_OK; uint16 smbpid = SVAL(inbuf,smb_pid); DEBUG(3,("Doing spnego session setup\n")); if (global_client_caps == 0) { global_client_caps = IVAL(inbuf,smb_vwv10); if (!(global_client_caps & CAP_STATUS32)) { remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES); } } p = (uint8 *)smb_buf(inbuf); if (data_blob_len == 0) { /* an invalid request */ return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE)); } bufrem = smb_bufrem(inbuf, p); /* pull the spnego blob */ blob1 = data_blob(p, MIN(bufrem, data_blob_len)); #if 0 file_save("negotiate.dat", blob1.data, blob1.length); #endif p2 = inbuf + smb_vwv13 + data_blob_len; p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE); p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE); p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE); DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", native_os, native_lanman, primary_domain)); if ( ra_type == RA_WIN2K ) { /* Vista sets neither the OS or lanman strings */ if ( !strlen(native_os) && !strlen(native_lanman) ) set_remote_arch(RA_VISTA); /* Windows 2003 doesn't set the native lanman string, but does set primary domain which is a bug I think */ if ( !strlen(native_lanman) ) { ra_lanman_string( primary_domain ); } else { ra_lanman_string( native_lanman ); } } vuser = get_partial_auth_user_struct(vuid); if (!vuser) { struct pending_auth_data *pad = get_pending_auth_data(smbpid); if (pad) { DEBUG(10,("reply_sesssetup_and_X_spnego: found pending vuid %u\n", (unsigned int)pad->vuid )); vuid = pad->vuid; vuser = get_partial_auth_user_struct(vuid); } } if (!vuser) { vuid = register_vuid(NULL, data_blob(NULL, 0), data_blob(NULL, 0), NULL); if (vuid == UID_FIELD_INVALID ) { data_blob_free(&blob1); return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER)); } vuser = get_partial_auth_user_struct(vuid); } if (!vuser) { data_blob_free(&blob1); return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER)); } SSVAL(outbuf,smb_uid,vuid); /* Large (greater than 4k) SPNEGO blobs are split into multiple * sessionsetup requests as the Windows limit on the security blob * field is 4k. Bug #4400. JRA. */ status = check_spnego_blob_complete(smbpid, vuid, &blob1); if (!NT_STATUS_IS_OK(status)) { if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { /* Real error - kill the intermediate vuid */ invalidate_vuid(vuid); } data_blob_free(&blob1); return ERROR_NT(nt_status_squash(status)); } if (blob1.data[0] == ASN1_APPLICATION(0)) { /* its a negTokenTarg packet */ ret = reply_spnego_negotiate(conn, inbuf, outbuf, vuid, length, bufsize, blob1, &vuser->auth_ntlmssp_state); data_blob_free(&blob1); return ret; } if (blob1.data[0] == ASN1_CONTEXT(1)) { /* its a auth packet */ ret = reply_spnego_auth(conn, inbuf, outbuf, vuid, length, bufsize, blob1, &vuser->auth_ntlmssp_state); data_blob_free(&blob1); return ret; } if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) { DATA_BLOB chal; if (!vuser->auth_ntlmssp_state) { status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state); if (!NT_STATUS_IS_OK(status)) { /* Kill the intermediate vuid */ invalidate_vuid(vuid); data_blob_free(&blob1); return ERROR_NT(nt_status_squash(status)); } } status = auth_ntlmssp_update(vuser->auth_ntlmssp_state, blob1, &chal); data_blob_free(&blob1); reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, &vuser->auth_ntlmssp_state, &chal, status, False); data_blob_free(&chal); return -1; } /* what sort of packet is this? */ DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n")); data_blob_free(&blob1); return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE)); }
/* receive a cldap netlogon reply */ static int recv_cldap_netlogon(TALLOC_CTX *mem_ctx, int sock, uint32_t *nt_version, union nbt_cldap_netlogon **reply) { int ret; ASN1_DATA data; DATA_BLOB blob = data_blob_null; DATA_BLOB os1 = data_blob_null; DATA_BLOB os2 = data_blob_null; DATA_BLOB os3 = data_blob_null; int i1; /* half the time of a regular ldap timeout, not less than 3 seconds. */ unsigned int al_secs = MAX(3,lp_ldap_timeout()/2); union nbt_cldap_netlogon *r = NULL; blob = data_blob(NULL, 8192); if (blob.data == NULL) { DEBUG(1, ("data_blob failed\n")); errno = ENOMEM; return -1; } /* Setup timeout */ gotalarm = 0; CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig); alarm(al_secs); /* End setup timeout. */ ret = read(sock, blob.data, blob.length); /* Teardown timeout. */ CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN); alarm(0); if (ret <= 0) { DEBUG(1,("no reply received to cldap netlogon\n")); data_blob_free(&blob); return -1; } blob.length = ret; asn1_load(&data, blob); asn1_start_tag(&data, ASN1_SEQUENCE(0)); asn1_read_Integer(&data, &i1); asn1_start_tag(&data, ASN1_APPLICATION(4)); asn1_read_OctetString(&data, &os1); asn1_start_tag(&data, ASN1_SEQUENCE(0)); asn1_start_tag(&data, ASN1_SEQUENCE(0)); asn1_read_OctetString(&data, &os2); asn1_start_tag(&data, ASN1_SET); asn1_read_OctetString(&data, &os3); asn1_end_tag(&data); asn1_end_tag(&data); asn1_end_tag(&data); asn1_end_tag(&data); asn1_end_tag(&data); if (data.has_error) { data_blob_free(&blob); data_blob_free(&os1); data_blob_free(&os2); data_blob_free(&os3); asn1_free(&data); DEBUG(1,("Failed to parse cldap reply\n")); return -1; } r = TALLOC_ZERO_P(mem_ctx, union nbt_cldap_netlogon); if (!r) { errno = ENOMEM; data_blob_free(&os1); data_blob_free(&os2); data_blob_free(&os3); data_blob_free(&blob); return -1; } if (!pull_mailslot_cldap_reply(mem_ctx, &os3, r, nt_version)) { data_blob_free(&os1); data_blob_free(&os2); data_blob_free(&os3); data_blob_free(&blob); TALLOC_FREE(r); return -1; } data_blob_free(&os1); data_blob_free(&os2); data_blob_free(&os3); data_blob_free(&blob); asn1_free(&data); if (reply) { *reply = r; } else { TALLOC_FREE(r); } return 0; }
static NTSTATUS smbd_smb2_spnego_auth(struct smbd_smb2_session *session, struct smbd_smb2_request *smb2req, uint8_t in_security_mode, DATA_BLOB in_security_buffer, uint16_t *out_session_flags, DATA_BLOB *out_security_buffer, uint64_t *out_session_id) { DATA_BLOB auth = data_blob_null; DATA_BLOB auth_out = data_blob_null; NTSTATUS status; if (!spnego_parse_auth(talloc_tos(), in_security_buffer, &auth)) { TALLOC_FREE(session); return NT_STATUS_LOGON_FAILURE; } if (auth.data[0] == ASN1_APPLICATION(0)) { /* Might be a second negTokenTarg packet */ DATA_BLOB secblob_in = data_blob_null; char *kerb_mech = NULL; status = parse_spnego_mechanisms(talloc_tos(), in_security_buffer, &secblob_in, &kerb_mech); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(session); return status; } #ifdef HAVE_KRB5 if (kerb_mech && ((lp_security()==SEC_ADS) || USE_KERBEROS_KEYTAB) ) { status = smbd_smb2_session_setup_krb5(session, smb2req, in_security_mode, &secblob_in, kerb_mech, out_session_flags, out_security_buffer, out_session_id); data_blob_free(&secblob_in); TALLOC_FREE(kerb_mech); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(session); } return status; } #endif /* Can't blunder into NTLMSSP auth if we have * a krb5 ticket. */ if (kerb_mech) { DEBUG(3,("smb2: network " "misconfiguration, client sent us a " "krb5 ticket and kerberos security " "not enabled\n")); TALLOC_FREE(session); data_blob_free(&secblob_in); TALLOC_FREE(kerb_mech); return NT_STATUS_LOGON_FAILURE; } data_blob_free(&secblob_in); } if (session->auth_ntlmssp_state == NULL) { status = auth_ntlmssp_prepare(session->sconn->remote_address, &session->auth_ntlmssp_state); if (!NT_STATUS_IS_OK(status)) { data_blob_free(&auth); TALLOC_FREE(session); return status; } auth_ntlmssp_want_feature(session->auth_ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY); status = auth_ntlmssp_start(session->auth_ntlmssp_state); if (!NT_STATUS_IS_OK(status)) { data_blob_free(&auth); TALLOC_FREE(session); return status; } } status = auth_ntlmssp_update(session->auth_ntlmssp_state, talloc_tos(), auth, &auth_out); /* If status is NT_STATUS_OK then we need to get the token. * Map to guest is now internal to auth_ntlmssp */ if (NT_STATUS_IS_OK(status)) { status = auth_ntlmssp_session_info(session, session->auth_ntlmssp_state, &session->session_info); } if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { TALLOC_FREE(session->auth_ntlmssp_state); data_blob_free(&auth); TALLOC_FREE(session); return status; } data_blob_free(&auth); *out_security_buffer = spnego_gen_auth_response(smb2req, &auth_out, status, NULL); if (out_security_buffer->data == NULL) { TALLOC_FREE(session->auth_ntlmssp_state); TALLOC_FREE(session); return NT_STATUS_NO_MEMORY; } *out_session_id = session->vuid; if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { return NT_STATUS_MORE_PROCESSING_REQUIRED; } /* We're done - claim the session. */ return smbd_smb2_common_ntlmssp_auth_return(session, smb2req, in_security_mode, in_security_buffer, out_session_flags, out_session_id); }
static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, uint16 vuid, int length, int bufsize, DATA_BLOB blob1, AUTH_NTLMSSP_STATE **auth_ntlmssp_state) { DATA_BLOB auth = data_blob(NULL,0); DATA_BLOB auth_reply = data_blob(NULL,0); DATA_BLOB secblob = data_blob(NULL,0); NTSTATUS status = NT_STATUS_INVALID_PARAMETER; if (!spnego_parse_auth(blob1, &auth)) { #if 0 file_save("auth.dat", blob1.data, blob1.length); #endif /* Kill the intermediate vuid */ invalidate_vuid(vuid); return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER)); } if (auth.data[0] == ASN1_APPLICATION(0)) { /* Might be a second negTokenTarg packet */ BOOL got_krb5_mechanism = False; status = parse_spnego_mechanisms(auth, &secblob, &got_krb5_mechanism); if (NT_STATUS_IS_OK(status)) { DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n", (unsigned long)secblob.length)); #ifdef HAVE_KRB5 if ( got_krb5_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) { BOOL destroy_vuid = True; int ret = reply_spnego_kerberos(conn, inbuf, outbuf, length, bufsize, &secblob, &destroy_vuid); data_blob_free(&secblob); data_blob_free(&auth); if (destroy_vuid) { /* Kill the intermediate vuid */ invalidate_vuid(vuid); } return ret; } #endif } } /* If we get here it wasn't a negTokenTarg auth packet. */ data_blob_free(&secblob); if (!*auth_ntlmssp_state) { /* Kill the intermediate vuid */ invalidate_vuid(vuid); /* auth before negotiatiate? */ return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER)); } status = auth_ntlmssp_update(*auth_ntlmssp_state, auth, &auth_reply); data_blob_free(&auth); reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state, &auth_reply, status, True); data_blob_free(&auth_reply); /* and tell smbd that we have already replied to this packet */ return -1; }
/* parse a negTokenInit packet giving a GUID, a list of supported OIDs (the mechanisms) and a principal name string */ bool spnego_parse_negTokenInit(TALLOC_CTX *ctx, DATA_BLOB blob, char *OIDs[ASN1_MAX_OIDS], char **principal, DATA_BLOB *secblob) { int i; bool ret; ASN1_DATA *data; data = asn1_init(talloc_tos()); if (data == NULL) { return false; } asn1_load(data, blob); asn1_start_tag(data,ASN1_APPLICATION(0)); asn1_check_OID(data,OID_SPNEGO); /* negTokenInit [0] NegTokenInit */ asn1_start_tag(data,ASN1_CONTEXT(0)); asn1_start_tag(data,ASN1_SEQUENCE(0)); /* mechTypes [0] MechTypeList OPTIONAL */ /* Not really optional, we depend on this to decide * what mechanisms we have to work with. */ asn1_start_tag(data,ASN1_CONTEXT(0)); asn1_start_tag(data,ASN1_SEQUENCE(0)); for (i=0; asn1_tag_remaining(data) > 0 && i < ASN1_MAX_OIDS-1; i++) { asn1_read_OID(data,ctx, &OIDs[i]); if (data->has_error) { break; } } OIDs[i] = NULL; asn1_end_tag(data); asn1_end_tag(data); if (principal) { *principal = NULL; } if (secblob) { *secblob = data_blob_null; } /* Win7 + Live Sign-in Assistant attaches a mechToken ASN1_CONTEXT(2) to the negTokenInit packet which breaks our negotiation if we just assume the next tag is ASN1_CONTEXT(3). */ if (asn1_peek_tag(data, ASN1_CONTEXT(1))) { uint8 flags; /* reqFlags [1] ContextFlags OPTIONAL */ asn1_start_tag(data, ASN1_CONTEXT(1)); asn1_start_tag(data, ASN1_BIT_STRING); while (asn1_tag_remaining(data) > 0) { asn1_read_uint8(data, &flags); } asn1_end_tag(data); asn1_end_tag(data); } if (asn1_peek_tag(data, ASN1_CONTEXT(2))) { DATA_BLOB sblob = data_blob_null; /* mechToken [2] OCTET STRING OPTIONAL */ asn1_start_tag(data, ASN1_CONTEXT(2)); asn1_read_OctetString(data, ctx, &sblob); asn1_end_tag(data); if (secblob) { *secblob = sblob; } else { data_blob_free(&sblob); } } if (asn1_peek_tag(data, ASN1_CONTEXT(3))) { char *princ = NULL; /* mechListMIC [3] OCTET STRING OPTIONAL */ asn1_start_tag(data, ASN1_CONTEXT(3)); asn1_start_tag(data, ASN1_SEQUENCE(0)); asn1_start_tag(data, ASN1_CONTEXT(0)); asn1_read_GeneralString(data, ctx, &princ); asn1_end_tag(data); asn1_end_tag(data); asn1_end_tag(data); if (principal) { *principal = princ; } else { TALLOC_FREE(princ); } } asn1_end_tag(data); asn1_end_tag(data); asn1_end_tag(data); ret = !data->has_error; if (data->has_error) { int j; if (principal) { TALLOC_FREE(*principal); } if (secblob) { data_blob_free(secblob); } for(j = 0; j < i && j < ASN1_MAX_OIDS-1; j++) { TALLOC_FREE(OIDs[j]); } } asn1_free(data); return ret; }
static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf, char *outbuf, int length,int bufsize) { uint8 *p; DATA_BLOB blob1; int ret; size_t bufrem; fstring native_os, native_lanman, primary_domain; char *p2; uint16 data_blob_len = SVAL(inbuf, smb_vwv7); enum remote_arch_types ra_type = get_remote_arch(); DEBUG(3,("Doing spnego session setup\n")); if (global_client_caps == 0) { global_client_caps = IVAL(inbuf,smb_vwv10); if (!(global_client_caps & CAP_STATUS32)) { remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES); } } p = (uint8 *)smb_buf(inbuf); if (data_blob_len == 0) { /* an invalid request */ return ERROR_NT(NT_STATUS_LOGON_FAILURE); } bufrem = smb_bufrem(inbuf, p); /* pull the spnego blob */ blob1 = data_blob(p, MIN(bufrem, data_blob_len)); #if 0 file_save("negotiate.dat", blob1.data, blob1.length); #endif p2 = inbuf + smb_vwv13 + data_blob_len; p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE); p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE); p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE); DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", native_os, native_lanman, primary_domain)); if ( ra_type == RA_WIN2K ) { /* Windows 2003 doesn't set the native lanman string, but does set primary domain which is a bug I think */ if ( !strlen(native_lanman) ) ra_lanman_string( primary_domain ); else ra_lanman_string( native_lanman ); } if (blob1.data[0] == ASN1_APPLICATION(0)) { /* its a negTokenTarg packet */ ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1); data_blob_free(&blob1); return ret; } if (blob1.data[0] == ASN1_CONTEXT(1)) { /* its a auth packet */ ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1); data_blob_free(&blob1); return ret; } /* what sort of packet is this? */ DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n")); data_blob_free(&blob1); return ERROR_NT(NT_STATUS_LOGON_FAILURE); }
/* do a cldap netlogon query */ static int send_cldap_netlogon(int sock, const char *domain, const char *hostname, unsigned ntversion) { ASN1_DATA data; char ntver[4]; #ifdef CLDAP_USER_QUERY char aac[4]; SIVAL(aac, 0, 0x00000180); #endif SIVAL(ntver, 0, ntversion); memset(&data, 0, sizeof(data)); asn1_push_tag(&data,ASN1_SEQUENCE(0)); asn1_write_Integer(&data, 4); asn1_push_tag(&data, ASN1_APPLICATION(3)); asn1_write_OctetString(&data, NULL, 0); asn1_write_enumerated(&data, 0); asn1_write_enumerated(&data, 0); asn1_write_Integer(&data, 0); asn1_write_Integer(&data, 0); asn1_write_BOOLEAN2(&data, False); asn1_push_tag(&data, ASN1_CONTEXT(0)); if (domain) { asn1_push_tag(&data, ASN1_CONTEXT(3)); asn1_write_OctetString(&data, "DnsDomain", 9); asn1_write_OctetString(&data, domain, strlen(domain)); asn1_pop_tag(&data); } asn1_push_tag(&data, ASN1_CONTEXT(3)); asn1_write_OctetString(&data, "Host", 4); asn1_write_OctetString(&data, hostname, strlen(hostname)); asn1_pop_tag(&data); #ifdef CLDAP_USER_QUERY asn1_push_tag(&data, ASN1_CONTEXT(3)); asn1_write_OctetString(&data, "User", 4); asn1_write_OctetString(&data, "SAMBA$", 6); asn1_pop_tag(&data); asn1_push_tag(&data, ASN1_CONTEXT(3)); asn1_write_OctetString(&data, "AAC", 4); asn1_write_OctetString(&data, aac, 4); asn1_pop_tag(&data); #endif asn1_push_tag(&data, ASN1_CONTEXT(3)); asn1_write_OctetString(&data, "NtVer", 5); asn1_write_OctetString(&data, ntver, 4); asn1_pop_tag(&data); asn1_pop_tag(&data); asn1_push_tag(&data,ASN1_SEQUENCE(0)); asn1_write_OctetString(&data, "NetLogon", 8); asn1_pop_tag(&data); asn1_pop_tag(&data); asn1_pop_tag(&data); if (data.has_error) { DEBUG(2,("Failed to build cldap netlogon at offset %d\n", (int)data.ofs)); asn1_free(&data); return -1; } if (write(sock, data.data, data.length) != (ssize_t)data.length) { DEBUG(2,("failed to send cldap query (%s)\n", strerror(errno))); asn1_free(&data); return -1; } asn1_free(&data); return 0; }
static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid, DATA_BLOB *pblob) { struct pending_auth_data *pad = NULL; ASN1_DATA data; size_t needed_len = 0; pad = get_pending_auth_data(smbpid); /* Ensure we have some data. */ if (pblob->length == 0) { /* Caller can cope. */ DEBUG(2,("check_spnego_blob_complete: zero blob length !\n")); delete_partial_auth(pad); return NT_STATUS_OK; } /* Were we waiting for more data ? */ if (pad) { DATA_BLOB tmp_blob; size_t copy_len = MIN(65536, pblob->length); /* Integer wrap paranoia.... */ if (pad->partial_data.length + copy_len < pad->partial_data.length || pad->partial_data.length + copy_len < copy_len) { DEBUG(2,("check_spnego_blob_complete: integer wrap " "pad->partial_data.length = %u, " "copy_len = %u\n", (unsigned int)pad->partial_data.length, (unsigned int)copy_len )); delete_partial_auth(pad); return NT_STATUS_INVALID_PARAMETER; } DEBUG(10,("check_spnego_blob_complete: " "pad->partial_data.length = %u, " "pad->needed_len = %u, " "copy_len = %u, " "pblob->length = %u,\n", (unsigned int)pad->partial_data.length, (unsigned int)pad->needed_len, (unsigned int)copy_len, (unsigned int)pblob->length )); tmp_blob = data_blob(NULL, pad->partial_data.length + copy_len); /* Concatenate the two (up to copy_len) bytes. */ memcpy(tmp_blob.data, pad->partial_data.data, pad->partial_data.length); memcpy(tmp_blob.data + pad->partial_data.length, pblob->data, copy_len); /* Replace the partial data. */ data_blob_free(&pad->partial_data); pad->partial_data = tmp_blob; ZERO_STRUCT(tmp_blob); /* Are we done ? */ if (pblob->length >= pad->needed_len) { /* Yes, replace pblob. */ data_blob_free(pblob); *pblob = pad->partial_data; ZERO_STRUCT(pad->partial_data); delete_partial_auth(pad); return NT_STATUS_OK; } /* Still need more data. */ pad->needed_len -= copy_len; return NT_STATUS_MORE_PROCESSING_REQUIRED; } if ((pblob->data[0] != ASN1_APPLICATION(0)) && (pblob->data[0] != ASN1_CONTEXT(1))) { /* Not something we can determine the * length of. */ return NT_STATUS_OK; } /* This is a new SPNEGO sessionsetup - see if * the data given in this blob is enough. */ asn1_load(&data, *pblob); asn1_start_tag(&data, pblob->data[0]); if (data.has_error || data.nesting == NULL) { asn1_free(&data); /* Let caller catch. */ return NT_STATUS_OK; } /* Integer wrap paranoia.... */ if (data.nesting->taglen + data.nesting->start < data.nesting->taglen || data.nesting->taglen + data.nesting->start < data.nesting->start) { DEBUG(2,("check_spnego_blob_complete: integer wrap " "data.nesting->taglen = %u, " "data.nesting->start = %u\n", (unsigned int)data.nesting->taglen, (unsigned int)data.nesting->start )); asn1_free(&data); return NT_STATUS_INVALID_PARAMETER; } /* Total length of the needed asn1 is the tag length * plus the current offset. */ needed_len = data.nesting->taglen + data.nesting->start; asn1_free(&data); DEBUG(10,("check_spnego_blob_complete: needed_len = %u, " "pblob->length = %u\n", (unsigned int)needed_len, (unsigned int)pblob->length )); if (needed_len <= pblob->length) { /* Nothing to do - blob is complete. */ return NT_STATUS_OK; } /* Refuse the blob if it's bigger than 64k. */ if (needed_len > 65536) { DEBUG(2,("check_spnego_blob_complete: needed_len too large (%u)\n", (unsigned int)needed_len )); return NT_STATUS_INVALID_PARAMETER; } /* We must store this blob until complete. */ pad = SMB_MALLOC(sizeof(struct pending_auth_data)); if (!pad) { return NT_STATUS_NO_MEMORY; } pad->needed_len = needed_len - pblob->length; pad->partial_data = data_blob(pblob->data, pblob->length); if (pad->partial_data.data == NULL) { SAFE_FREE(pad); return NT_STATUS_NO_MEMORY; } pad->smbpid = smbpid; pad->vuid = vuid; DLIST_ADD(pd_list, pad); return NT_STATUS_MORE_PROCESSING_REQUIRED; }
DATA_BLOB spnego_gen_negTokenInit(TALLOC_CTX *ctx, const char *OIDs[], DATA_BLOB *psecblob, const char *principal) { int i; ASN1_DATA *data; DATA_BLOB ret = data_blob_null; data = asn1_init(talloc_tos()); if (data == NULL) { return data_blob_null; } if (!asn1_push_tag(data,ASN1_APPLICATION(0))) goto err; if (!asn1_write_OID(data,OID_SPNEGO)) goto err; if (!asn1_push_tag(data,ASN1_CONTEXT(0))) goto err; if (!asn1_push_tag(data,ASN1_SEQUENCE(0))) goto err; if (!asn1_push_tag(data,ASN1_CONTEXT(0))) goto err; if (!asn1_push_tag(data,ASN1_SEQUENCE(0))) goto err; for (i=0; OIDs[i]; i++) { if (!asn1_write_OID(data,OIDs[i])) goto err; } if (!asn1_pop_tag(data)) goto err; if (!asn1_pop_tag(data)) goto err; if (psecblob && psecblob->length && psecblob->data) { if (!asn1_push_tag(data, ASN1_CONTEXT(2))) goto err; if (!asn1_write_OctetString(data,psecblob->data, psecblob->length)) goto err; if (!asn1_pop_tag(data)) goto err; } if (principal) { if (!asn1_push_tag(data, ASN1_CONTEXT(3))) goto err; if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) goto err; if (!asn1_push_tag(data, ASN1_CONTEXT(0))) goto err; if (!asn1_write_GeneralString(data,principal)) goto err; if (!asn1_pop_tag(data)) goto err; if (!asn1_pop_tag(data)) goto err; if (!asn1_pop_tag(data)) goto err; } if (!asn1_pop_tag(data)) goto err; if (!asn1_pop_tag(data)) goto err; if (!asn1_pop_tag(data)) goto err; if (!asn1_extract_blob(data, ctx, &ret)) { goto err; } err: if (asn1_has_error(data)) { DEBUG(1, ("Failed to build negTokenInit at offset %d\n", (int)asn1_current_ofs(data))); } asn1_free(data); return ret; }
static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf, char *outbuf, int length,int bufsize) { uint8 *p; DATA_BLOB blob1; int ret; size_t bufrem; fstring native_os, native_lanman, primary_domain; char *p2; uint16 data_blob_len = SVAL(inbuf, smb_vwv7); enum remote_arch_types ra_type = get_remote_arch(); DEBUG(3,("Doing spnego session setup\n")); if (global_client_caps == 0) { global_client_caps = IVAL(inbuf,smb_vwv10); if (!(global_client_caps & CAP_STATUS32)) { remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES); } } p = (uint8 *)smb_buf(inbuf); if (data_blob_len == 0) { /* an invalid request */ return ERROR_NT(NT_STATUS_LOGON_FAILURE); } bufrem = smb_bufrem(inbuf, p); /* pull the spnego blob */ blob1 = data_blob(p, MIN(bufrem, data_blob_len)); #if 0 file_save("negotiate.dat", blob1.data, blob1.length); #endif p2 = inbuf + smb_vwv13 + data_blob_len; p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE); p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE); p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE); DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", native_os, native_lanman, primary_domain)); if ( ra_type == RA_WIN2K ) { /* Windows 2003 doesn't set the native lanman string, but does set primary domain which is a bug I think */ if ( !strlen(native_lanman) ) ra_lanman_string( primary_domain ); else ra_lanman_string( native_lanman ); } if (blob1.data[0] == ASN1_APPLICATION(0)) { /* its a negTokenTarg packet */ ret = reply_spnego_negotiate(conn, inbuf, outbuf, length, bufsize, blob1); data_blob_free(&blob1); return ret; } if (blob1.data[0] == ASN1_CONTEXT(1)) { /* its a auth packet */ ret = reply_spnego_auth(conn, inbuf, outbuf, length, bufsize, blob1); data_blob_free(&blob1); return ret; } /* Foxconn modified start pling 12/29/2011 */ /* Fix Android partial auth issue. * Port from Samba 3.0.24 (used by WNDR3800) */ if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) { DATA_BLOB chal; NTSTATUS nt_status; if (!global_ntlmssp_state) { nt_status = auth_ntlmssp_start(&global_ntlmssp_state); if (!NT_STATUS_IS_OK(nt_status)) { return ERROR_NT(nt_status_squash(nt_status)); } } nt_status = auth_ntlmssp_update(global_ntlmssp_state, blob1, &chal); data_blob_free(&blob1); reply_spnego_ntlmssp(conn, inbuf, outbuf, &global_ntlmssp_state, &chal, nt_status, False); data_blob_free(&chal); return -1; } /* Foxconn added end pling 12/29/2011 */ /* what sort of packet is this? */ DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n")); data_blob_free(&blob1); return ERROR_NT(NT_STATUS_LOGON_FAILURE); }