r24589: Refactor our vuid code so that we keep the same
[samba.git] / source / smbd / password.c
index 1a7dc33c61e5c2de5a7286fdcee9cd2bc24bbfb7..847b8db082985e914acc7f3432a4350030ecc577 100644 (file)
@@ -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;
 }
 
 /****************************************************************************