static int reply_spnego_negotiate(connection_struct *conn, char *inbuf, char *outbuf, uint16 vuid, int length, int bufsize, DATA_BLOB blob1, AUTH_NTLMSSP_STATE **auth_ntlmssp_state) { DATA_BLOB secblob; DATA_BLOB chal; BOOL got_kerberos_mechanism = False; NTSTATUS status; status = parse_spnego_mechanisms(blob1, &secblob, &got_kerberos_mechanism); if (!NT_STATUS_IS_OK(status)) { /* Kill the intermediate vuid */ invalidate_vuid(vuid); return ERROR_NT(nt_status_squash(status)); } DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n", (unsigned long)secblob.length)); #ifdef HAVE_KRB5 if ( got_kerberos_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); if (destroy_vuid) { /* Kill the intermediate vuid */ invalidate_vuid(vuid); } return ret; } #endif if (*auth_ntlmssp_state) { auth_ntlmssp_end(auth_ntlmssp_state); } status = auth_ntlmssp_start(auth_ntlmssp_state); if (!NT_STATUS_IS_OK(status)) { /* Kill the intermediate vuid */ invalidate_vuid(vuid); return ERROR_NT(nt_status_squash(status)); } status = auth_ntlmssp_update(*auth_ntlmssp_state, secblob, &chal); data_blob_free(&secblob); reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state, &chal, status, True); data_blob_free(&chal); /* already replied */ return -1; }
void invalidate_all_vuids(void) { user_struct *usp, *next=NULL; for (usp=validated_users;usp;usp=next) { next = usp->next; invalidate_vuid(usp->vuid); } }
static int smbd_smb2_session_destructor(struct smbd_smb2_session *session) { if (session->sconn == NULL) { return 0; } /* first free all tcons */ while (session->tcons.list) { talloc_free(session->tcons.list); } idr_remove(session->sconn->smb2.sessions.idtree, session->vuid); DLIST_REMOVE(session->sconn->smb2.sessions.list, session); invalidate_vuid(session->sconn, session->vuid); session->vuid = 0; session->status = NT_STATUS_USER_SESSION_DELETED; session->sconn = NULL; return 0; }
int register_vuid(auth_serversupplied_info *server_info, DATA_BLOB session_key, DATA_BLOB response_blob, const char *smb_name) { user_struct *vuser = NULL; /* Paranoia check. */ if(lp_security() == SEC_SHARE) { smb_panic("Tried to register uid in security=share\n"); } /* Limit allowed vuids to 16bits - VUID_OFFSET. */ if (num_validated_vuids >= 0xFFFF-VUID_OFFSET) { data_blob_free(&session_key); return UID_FIELD_INVALID; } if((vuser = SMB_MALLOC_P(user_struct)) == NULL) { DEBUG(0,("Failed to malloc users struct!\n")); data_blob_free(&session_key); return UID_FIELD_INVALID; } ZERO_STRUCTP(vuser); /* Allocate a free vuid. Yes this is a linear search... :-) */ while( get_valid_user_struct(next_vuid) != NULL ) { next_vuid++; /* Check for vuid wrap. */ if (next_vuid == UID_FIELD_INVALID) next_vuid = VUID_OFFSET; } DEBUG(10,("register_vuid: allocated vuid = %u\n", (unsigned int)next_vuid )); vuser->vuid = next_vuid; if (!server_info) { /* * This happens in an unfinished NTLMSSP session setup. We * need to allocate a vuid between the first and second calls * to NTLMSSP. */ next_vuid++; num_validated_vuids++; vuser->server_info = NULL; DLIST_ADD(validated_users, vuser); return vuser->vuid; } /* the next functions should be done by a SID mapping system (SMS) as * the new real sam db won't have reference to unix uids or gids */ vuser->uid = server_info->uid; vuser->gid = server_info->gid; vuser->n_groups = server_info->n_groups; if (vuser->n_groups) { if (!(vuser->groups = (gid_t *)memdup(server_info->groups, sizeof(gid_t) * vuser->n_groups))) { DEBUG(0,("register_vuid: failed to memdup " "vuser->groups\n")); data_blob_free(&session_key); free(vuser); TALLOC_FREE(server_info); return UID_FIELD_INVALID; } } vuser->guest = server_info->guest; fstrcpy(vuser->user.unix_name, server_info->unix_name); /* This is a potentially untrusted username */ alpha_strcpy(vuser->user.smb_name, smb_name, ". _-$", sizeof(vuser->user.smb_name)); fstrcpy(vuser->user.domain, pdb_get_domain(server_info->sam_account)); fstrcpy(vuser->user.full_name, pdb_get_fullname(server_info->sam_account)); { /* Keep the homedir handy */ const char *homedir = pdb_get_homedir(server_info->sam_account); const char *logon_script = pdb_get_logon_script(server_info->sam_account); if (!IS_SAM_DEFAULT(server_info->sam_account, PDB_UNIXHOMEDIR)) { const char *unix_homedir = pdb_get_unix_homedir(server_info->sam_account); if (unix_homedir) { vuser->unix_homedir = smb_xstrdup(unix_homedir); } } else { struct passwd *passwd = getpwnam_alloc(NULL, vuser->user.unix_name); if (passwd) { vuser->unix_homedir = smb_xstrdup(passwd->pw_dir); TALLOC_FREE(passwd); } } if (homedir) { vuser->homedir = smb_xstrdup(homedir); } if (logon_script) { vuser->logon_script = smb_xstrdup(logon_script); } } vuser->session_key = session_key; DEBUG(10,("register_vuid: (%u,%u) %s %s %s guest=%d\n", (unsigned int)vuser->uid, (unsigned int)vuser->gid, vuser->user.unix_name, vuser->user.smb_name, vuser->user.domain, vuser->guest )); DEBUG(3, ("User name: %s\tReal name: %s\n", vuser->user.unix_name, vuser->user.full_name)); if (server_info->ptok) { vuser->nt_user_token = dup_nt_token(NULL, server_info->ptok); } else { DEBUG(1, ("server_info does not contain a user_token - " "cannot continue\n")); TALLOC_FREE(server_info); data_blob_free(&session_key); SAFE_FREE(vuser->homedir); SAFE_FREE(vuser->unix_homedir); SAFE_FREE(vuser->logon_script); SAFE_FREE(vuser); return UID_FIELD_INVALID; } /* use this to keep tabs on all our info from the authentication */ vuser->server_info = server_info; DEBUG(3,("UNIX uid %d is UNIX user %s, and will be vuid %u\n", (int)vuser->uid,vuser->user.unix_name, vuser->vuid)); next_vuid++; num_validated_vuids++; DLIST_ADD(validated_users, vuser); if (!session_claim(vuser)) { DEBUG(1, ("Failed to claim session for vuid=%d\n", vuser->vuid)); invalidate_vuid(vuser->vuid); return UID_FIELD_INVALID; } /* Register a home dir service for this user iff (a) This is not a guest connection, (b) we have a home directory defined (c) there s not an existing static share by that name If a share exists by this name (autoloaded or not) reuse it . */ vuser->homes_snum = -1; if ( (!vuser->guest) && vuser->unix_homedir && *(vuser->unix_homedir)) { int servicenumber = lp_servicenumber(vuser->user.unix_name); if ( servicenumber == -1 ) { DEBUG(3, ("Adding homes service for user '%s' using " "home directory: '%s'\n", vuser->user.unix_name, vuser->unix_homedir)); vuser->homes_snum = add_home_service(vuser->user.unix_name, vuser->user.unix_name, vuser->unix_homedir); } else { DEBUG(3, ("Using static (or previously created) " "service for user '%s'; path = '%s'\n", vuser->user.unix_name, lp_pathname(servicenumber) )); vuser->homes_snum = servicenumber; } } if (srv_is_signing_negotiated() && !vuser->guest && !srv_signing_started()) { /* Try and turn on server signing on the first non-guest * sessionsetup. */ srv_set_signing(vuser->session_key, response_blob); } /* fill in the current_user_info struct */ set_current_user_info( &vuser->user ); return vuser->vuid; }
int register_existing_vuid(uint16 vuid, auth_serversupplied_info *server_info, DATA_BLOB response_blob, const char *smb_name) { fstring tmp; user_struct *vuser; vuser = get_partial_auth_user_struct(vuid); if (!vuser) { goto fail; } /* Use this to keep tabs on all our info from the authentication */ vuser->server_info = talloc_move(vuser, &server_info); /* This is a potentially untrusted username */ alpha_strcpy(tmp, smb_name, ". _-$", sizeof(tmp)); vuser->server_info->sanitized_username = talloc_strdup( vuser->server_info, tmp); DEBUG(10,("register_existing_vuid: (%u,%u) %s %s %s guest=%d\n", (unsigned int)vuser->server_info->utok.uid, (unsigned int)vuser->server_info->utok.gid, vuser->server_info->unix_name, vuser->server_info->sanitized_username, pdb_get_domain(vuser->server_info->sam_account), vuser->server_info->guest )); DEBUG(3, ("register_existing_vuid: User name: %s\t" "Real name: %s\n", vuser->server_info->unix_name, pdb_get_fullname(vuser->server_info->sam_account))); if (!vuser->server_info->ptok) { DEBUG(1, ("register_existing_vuid: server_info does not " "contain a user_token - cannot continue\n")); goto fail; } DEBUG(3,("register_existing_vuid: UNIX uid %d is UNIX user %s, " "and will be vuid %u\n", (int)vuser->server_info->utok.uid, vuser->server_info->unix_name, vuser->vuid)); if (!session_claim(vuser)) { DEBUG(1, ("register_existing_vuid: Failed to claim session " "for vuid=%d\n", vuser->vuid)); goto fail; } /* Register a home dir service for this user if (a) This is not a guest connection, (b) we have a home directory defined (c) there s not an existing static share by that name If a share exists by this name (autoloaded or not) reuse it . */ vuser->homes_snum = -1; if (!vuser->server_info->guest) { vuser->homes_snum = register_homes_share( vuser->server_info->unix_name); } if (srv_is_signing_negotiated() && !vuser->server_info->guest && !srv_signing_started()) { /* Try and turn on server signing on the first non-guest * sessionsetup. */ srv_set_signing(vuser->server_info->user_session_key, response_blob); } /* fill in the current_user_info struct */ set_current_user_info( vuser->server_info->sanitized_username, vuser->server_info->unix_name, pdb_get_domain(vuser->server_info->sam_account)); return vuser->vuid; fail: if (vuser) { invalidate_vuid(vuid); } return UID_FIELD_INVALID; }
void invalidate_all_vuids(void) { while (validated_users != NULL) { invalidate_vuid(validated_users->vuid); } }
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; }
static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf, uint16 vuid, AUTH_NTLMSSP_STATE **auth_ntlmssp_state, DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status, BOOL wrap) { BOOL ret; DATA_BLOB response; struct auth_serversupplied_info *server_info = NULL; if (NT_STATUS_IS_OK(nt_status)) { server_info = (*auth_ntlmssp_state)->server_info; } else { nt_status = do_map_to_guest(nt_status, &server_info, (*auth_ntlmssp_state)->ntlmssp_state->user, (*auth_ntlmssp_state)->ntlmssp_state->domain); } if (NT_STATUS_IS_OK(nt_status)) { int sess_vuid; DATA_BLOB nullblob = data_blob(NULL, 0); DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length); /* register_vuid keeps the server info */ sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user); (*auth_ntlmssp_state)->server_info = NULL; if (sess_vuid == UID_FIELD_INVALID ) { nt_status = NT_STATUS_LOGON_FAILURE; } else { /* current_user_info is changed on new vuid */ reload_services( True ); set_message(outbuf,4,0,True); SSVAL(outbuf, smb_vwv3, 0); if (server_info->guest) { SSVAL(outbuf,smb_vwv2,1); } SSVAL(outbuf,smb_uid,sess_vuid); sessionsetup_start_signing_engine(server_info, inbuf); } } if (wrap) { response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP); } else { response = *ntlmssp_blob; } ret = reply_sesssetup_blob(conn, outbuf, response, nt_status); if (wrap) { data_blob_free(&response); } /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us, and the other end, that we are not finished yet. */ if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { /* NB. This is *NOT* an error case. JRA */ auth_ntlmssp_end(auth_ntlmssp_state); /* Kill the intermediate vuid */ invalidate_vuid(vuid); } 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(); 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)); }