diff options
Diffstat (limited to 'source3/smbd/password.c')
-rw-r--r-- | source3/smbd/password.c | 297 |
1 files changed, 165 insertions, 132 deletions
diff --git a/source3/smbd/password.c b/source3/smbd/password.c index 1a7dc33c61..847b8db082 100644 --- a/source3/smbd/password.c +++ b/source3/smbd/password.c @@ -30,13 +30,12 @@ static user_struct *validated_users; static int next_vuid = VUID_OFFSET; static int num_validated_vuids; -/**************************************************************************** - Check if a uid has been validated, and return an pointer to the user_struct - if it has. NULL if not. vuid is biased by an offset. This allows us to - tell random client vuid's (normally zero) from valid vuids. -****************************************************************************/ +enum server_allocated_state { SERVER_ALLOCATED_REQUIRED_YES, + SERVER_ALLOCATED_REQUIRED_NO, + SERVER_ALLOCATED_REQUIRED_ANY}; -user_struct *get_valid_user_struct(uint16 vuid) +static user_struct *get_valid_user_struct_internal(uint16 vuid, + enum server_allocated_state server_allocated) { user_struct *usp; int count=0; @@ -45,7 +44,20 @@ user_struct *get_valid_user_struct(uint16 vuid) return NULL; for (usp=validated_users;usp;usp=usp->next,count++) { - if (vuid == usp->vuid && usp->server_info) { + if (vuid == usp->vuid) { + switch (server_allocated) { + case SERVER_ALLOCATED_REQUIRED_YES: + if (usp->server_info == NULL) { + continue; + } + break; + case SERVER_ALLOCATED_REQUIRED_NO: + if (usp->server_info != NULL) { + continue; + } + case SERVER_ALLOCATED_REQUIRED_ANY: + break; + } if (count > 10) { DLIST_PROMOTE(validated_users, usp); } @@ -57,27 +69,33 @@ user_struct *get_valid_user_struct(uint16 vuid) } /**************************************************************************** - Get the user struct of a partial NTLMSSP login + Check if a uid has been validated, and return an pointer to the user_struct + if it has. NULL if not. vuid is biased by an offset. This allows us to + tell random client vuid's (normally zero) from valid vuids. ****************************************************************************/ -user_struct *get_partial_auth_user_struct(uint16 vuid) +user_struct *get_valid_user_struct(uint16 vuid) { - user_struct *usp; - int count=0; - - if (vuid == UID_FIELD_INVALID) - return NULL; + return get_valid_user_struct_internal(vuid, SERVER_ALLOCATED_REQUIRED_YES); +} - for (usp=validated_users;usp;usp=usp->next,count++) { - if (vuid == usp->vuid && !usp->server_info) { - if (count > 10) { - DLIST_PROMOTE(validated_users, usp); - } - return usp; - } +BOOL is_partial_auth_vuid(uint16 vuid) +{ + if (vuid == UID_FIELD_INVALID) { + return False; } + return get_valid_user_struct_internal(vuid, + SERVER_ALLOCATED_REQUIRED_NO) ? True : False; +} - return NULL; +/**************************************************************************** + Get the user struct of a partial NTLMSSP login +****************************************************************************/ + +user_struct *get_partial_auth_user_struct(uint16 vuid) +{ + return get_valid_user_struct_internal(vuid, + SERVER_ALLOCATED_REQUIRED_NO); } /**************************************************************************** @@ -86,11 +104,18 @@ user_struct *get_partial_auth_user_struct(uint16 vuid) void invalidate_vuid(uint16 vuid) { - user_struct *vuser = get_valid_user_struct(vuid); + user_struct *vuser = NULL; - if (vuser == NULL) + if (vuid == UID_FIELD_INVALID) { return; - + } + + vuser = get_valid_user_struct_internal(vuid, + SERVER_ALLOCATED_REQUIRED_ANY); + if (vuser == NULL) { + return; + } + session_yield(vuser); data_blob_free(&vuser->session_key); @@ -115,116 +140,127 @@ void invalidate_all_vuids(void) for (usp=validated_users;usp;usp=next) { next = usp->next; - invalidate_vuid(usp->vuid); } } -/** - * register that a valid login has been performed, establish 'session'. - * @param server_info The token returned from the authentication process. - * (now 'owned' by register_vuid) - * - * @param session_key The User session key for the login session (now also - * 'owned' by register_vuid) - * - * @param respose_blob The NT challenge-response, if available. (May be - * freed after this call) - * - * @param smb_name The untranslated name of the user - * - * @return Newly allocated vuid, biased by an offset. (This allows us to - * tell random client vuid's (normally zero) from valid vuids.) - * - */ +/**************************************************** + Create a new partial auth user struct. +*****************************************************/ -int register_vuid(auth_serversupplied_info *server_info, - DATA_BLOB session_key, DATA_BLOB response_blob, - const char *smb_name) +int register_initial_vuid(void) { user_struct *vuser; /* Paranoia check. */ if(lp_security() == SEC_SHARE) { - smb_panic("Tried to register uid in security=share"); + smb_panic("register_initial_vuid: " + "Tried to register uid in security=share"); } /* 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 = TALLOC_ZERO_P(NULL, user_struct)) == NULL) { - DEBUG(0,("Failed to talloc users struct!\n")); - data_blob_free(&session_key); + if((vuser = talloc_zero(NULL, user_struct)) == NULL) { + DEBUG(0,("register_initial_vuid: " + "Failed to talloc users struct!\n")); return UID_FIELD_INVALID; } - /* Allocate a free vuid. Yes this is a linear search... :-) */ - while( get_valid_user_struct(next_vuid) != NULL ) { + /* Allocate a free vuid. Yes this is a linear search... */ + while( get_valid_user_struct_internal(next_vuid, + SERVER_ALLOCATED_REQUIRED_ANY) != NULL ) { next_vuid++; /* Check for vuid wrap. */ - if (next_vuid == UID_FIELD_INVALID) + if (next_vuid == UID_FIELD_INVALID) { next_vuid = VUID_OFFSET; + } } - DEBUG(10,("register_vuid: allocated vuid = %u\n", - (unsigned int)next_vuid )); + DEBUG(10,("register_initial_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; + /* + * 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++; + + DLIST_ADD(validated_users, vuser); + return vuser->vuid; +} + +/** + * register that a valid login has been performed, establish 'session'. + * @param server_info The token returned from the authentication process. + * (now 'owned' by register_existing_vuid) + * + * @param session_key The User session key for the login session (now also + * 'owned' by register_existing_vuid) + * + * @param respose_blob The NT challenge-response, if available. (May be + * freed after this call) + * + * @param smb_name The untranslated name of the user + * + * @return Newly allocated vuid, biased by an offset. (This allows us to + * tell random client vuid's (normally zero) from valid vuids.) + * + */ + +int register_existing_vuid(uint16 vuid, + auth_serversupplied_info *server_info, + DATA_BLOB session_key, + DATA_BLOB response_blob, + const char *smb_name) +{ + user_struct *vuser = get_partial_auth_user_struct(vuid); + if (!vuser) { + goto fail; } - /* use this to keep tabs on all our info from the authentication */ + /* Use this to keep tabs on all our info from the authentication */ vuser->server_info = server_info; - /* Ensure that the server_info will dissapear with the vuser it is now attached to */ + + /* Ensure that the server_info will disappear with + * the vuser it is now attached to */ + talloc_steal(vuser, vuser->server_info); /* 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 *)talloc_memdup(vuser, server_info->groups, - sizeof(gid_t) * - vuser->n_groups))) { - DEBUG(0,("register_vuid: failed to talloc_memdup " - "vuser->groups\n")); - data_blob_free(&session_key); - TALLOC_FREE(vuser); - return UID_FIELD_INVALID; + if (!(vuser->groups = (gid_t *)talloc_memdup(vuser, + server_info->groups, + sizeof(gid_t)*vuser->n_groups))) { + DEBUG(0,("register_existing_vuid: " + "failed to talloc_memdup vuser->groups\n")); + goto fail; } } vuser->guest = server_info->guest; - fstrcpy(vuser->user.unix_name, server_info->unix_name); + 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)); + 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)); + pdb_get_fullname(server_info->sam_account)); { /* Keep the homedir handy */ @@ -234,7 +270,7 @@ int register_vuid(auth_serversupplied_info *server_info, pdb_get_logon_script(server_info->sam_account); if (!IS_SAM_DEFAULT(server_info->sam_account, - PDB_UNIXHOMEDIR)) { + PDB_UNIXHOMEDIR)) { const char *unix_homedir = pdb_get_unix_homedir(server_info->sam_account); if (unix_homedir) { @@ -252,7 +288,7 @@ int register_vuid(auth_serversupplied_info *server_info, TALLOC_FREE(passwd); } } - + if (homedir) { vuser->homedir = homedir; } @@ -260,86 +296,83 @@ int register_vuid(auth_serversupplied_info *server_info, vuser->logon_script = 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(10,("register_existing_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)); + DEBUG(3, ("register_existing_vuid: User name: %s\t" + "Real name: %s\n", vuser->user.unix_name, + vuser->user.full_name)); - if (server_info->ptok) { + if (server_info->ptok) { vuser->nt_user_token = dup_nt_token(vuser, server_info->ptok); } else { - DEBUG(1, ("server_info does not contain a user_token - " - "cannot continue\n")); - TALLOC_FREE(vuser); - data_blob_free(&session_key); - return UID_FIELD_INVALID; + DEBUG(1, ("register_existing_vuid: server_info does not " + "contain a user_token - cannot continue\n")); + goto fail; } - DEBUG(3,("UNIX uid %d is UNIX user %s, and will be vuid %u\n", - (int)vuser->uid,vuser->user.unix_name, vuser->vuid)); + DEBUG(3,("register_existing_vuid: 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; + 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 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 . */ + /* 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->guest) && vuser->unix_homedir && *(vuser->unix_homedir)) - { + 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", + "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); + 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) )); + "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()) { + !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; + fail: - return vuser->vuid; + if (vuser) { + invalidate_vuid(vuid); + } + return UID_FIELD_INVALID; } /**************************************************************************** |