*id_to_*id call reshape to return NTSTATUS errors
[ira/wip.git] / source3 / auth / auth_util.c
index 78dc0d4ee4443532dae7263db34be6e9ad70f86d..e8f2af41f32cfe96761a356309489ae5eba78d2f 100644 (file)
@@ -26,7 +26,6 @@
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_AUTH
 
-extern pstring global_myname;
 extern DOM_SID global_sid_World;
 extern DOM_SID global_sid_Network;
 extern DOM_SID global_sid_Builtin_Guests;
@@ -78,6 +77,36 @@ void smb_user_control(const auth_usersupplied_info *user_info, auth_serversuppli
        }
 }
 
+/****************************************************************************
+ Create a SAM_ACCOUNT - either by looking in the pdb, or by faking it up from
+ unix info.
+****************************************************************************/
+
+NTSTATUS auth_get_sam_account(const char *user, SAM_ACCOUNT **account) 
+{
+       BOOL pdb_ret;
+       NTSTATUS nt_status;
+       if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam(account))) {
+               return nt_status;
+       }
+       
+       become_root();
+       pdb_ret = pdb_getsampwnam(*account, user);
+       unbecome_root();
+
+       if (!pdb_ret) {
+               
+               struct passwd *pass = Get_Pwnam(user);
+               if (!pass) 
+                       return NT_STATUS_NO_SUCH_USER;
+
+               if (!NT_STATUS_IS_OK(nt_status = pdb_fill_sam_pw(*account, pass))) {
+                       return nt_status;
+               }
+       }
+       return NT_STATUS_OK;
+}
+
 /****************************************************************************
  Create an auth_usersupplied_data structure
 ****************************************************************************/
@@ -190,35 +219,18 @@ NTSTATUS make_user_info_map(auth_usersupplied_info **user_info,
                   where it doens't supply a domain for logon script
                   'net use' commands.
 
-                  The way I do it here is by checking if the fully
-                  qualified username exists. This is rather reliant
-                  on winbind, but until we have a better method this
-                  will have to do 
+                  Finally, we do this by looking up a cache of trusted domains!
                */
 
                domain = client_domain;
 
-               if ((smb_name) && (*smb_name)) { /* Don't do this for guests */
-                       char *user = NULL;
-                       if (asprintf(&user, "%s%s%s", 
-                                client_domain, lp_winbind_separator(), 
-                                smb_name) < 0) {
-                               DEBUG(0, ("make_user_info_map: asprintf() failed!\n"));
-                               return NT_STATUS_NO_MEMORY;
-                       }
-
-                       DEBUG(5, ("make_user_info_map: testing for user %s\n", user));
-                       
-                       if (Get_Pwnam(user) == NULL) {
-                               DEBUG(5, ("make_user_info_map: test for user %s failed\n", user));
-                               domain = lp_workgroup();
-                               DEBUG(5, ("make_user_info_map: trusted domain %s doesn't appear to exist, using %s\n", 
-                                         client_domain, domain));
-                       } else {
-                               DEBUG(5, ("make_user_info_map: using trusted domain %s\n", domain));
-                       }
-                       SAFE_FREE(user);
+               if (is_trusted_domain(domain)) {
+                       return make_user_info(user_info, smb_name, internal_username,
+                                             client_domain, domain, wksta_name,
+                                             lm_pwd, nt_pwd, plaintext, ntlmssp_flags,
+                                             encrypted);
                }
+
        } else {
                domain = lp_workgroup();
        }
@@ -476,14 +488,34 @@ BOOL make_user_info_guest(auth_usersupplied_info **user_info)
 void debug_nt_user_token(int dbg_class, int dbg_lev, NT_USER_TOKEN *token)
 {
        fstring sid_str;
-       int     i;
+       size_t     i;
+       
+       if (!token) {
+               DEBUGC(dbg_class, dbg_lev, ("NT user token: (NULL)\n"));
+               return;
+       }
        
        DEBUGC(dbg_class, dbg_lev, ("NT user token of user %s\n",
-               sid_to_string(sid_str, &token->user_sids[0]) ));
+                                   sid_to_string(sid_str, &token->user_sids[0]) ));
        DEBUGADDC(dbg_class, dbg_lev, ("contains %i SIDs\n", token->num_sids));
        for (i = 0; i < token->num_sids; i++)
                DEBUGADDC(dbg_class, dbg_lev, ("SID[%3i]: %s\n", i, 
-                       sid_to_string(sid_str, &token->user_sids[i])));
+                                              sid_to_string(sid_str, &token->user_sids[i])));
+}
+
+/****************************************************************************
+ prints a UNIX 'token' to debug output.
+****************************************************************************/
+
+void debug_unix_user_token(int dbg_class, int dbg_lev, uid_t uid, gid_t gid, int n_groups, gid_t *groups)
+{
+       int     i;
+       DEBUGC(dbg_class, dbg_lev, ("UNIX token of user %ld\n", (long int)uid));
+
+       DEBUGADDC(dbg_class, dbg_lev, ("Primary group is %ld and contains %i supplementary groups\n", (long int)gid, n_groups));
+       for (i = 0; i < n_groups; i++)
+               DEBUGADDC(dbg_class, dbg_lev, ("Group[%3i]: %ld\n", i, 
+                       (long int)groups[i]));
 }
 
 /****************************************************************************
@@ -545,7 +577,7 @@ static NTSTATUS create_nt_user_token(const DOM_SID *user_sid, const DOM_SID *gro
        sid_ndx = 5; /* next available spot */
 
        for (i = 0; i < n_groupSIDs; i++) {
-               int check_sid_idx;
+               size_t check_sid_idx;
                for (check_sid_idx = 1; check_sid_idx < ptoken->num_sids; check_sid_idx++) {
                        if (sid_equal(&ptoken->user_sids[check_sid_idx], 
                                      &groupSIDs[i])) {
@@ -579,21 +611,21 @@ NT_USER_TOKEN *create_nt_token(uid_t uid, gid_t gid, int ngroups, gid_t *groups,
        NT_USER_TOKEN *token;
        int i;
 
-       if (!uid_to_sid(&user_sid, uid)) {
+       if (NT_STATUS_IS_ERR(uid_to_sid(&user_sid, uid))) {
                return NULL;
        }
-       if (!gid_to_sid(&group_sid, gid)) {
+       if (NT_STATUS_IS_ERR(gid_to_sid(&group_sid, gid))) {
                return NULL;
        }
 
-       group_sids   = malloc(sizeof(DOM_SID) * ngroups);
+       group_sids = malloc(sizeof(DOM_SID) * ngroups);
        if (!group_sids) {
                DEBUG(0, ("create_nt_token: malloc() failed for DOM_SID list!\n"));
                return NULL;
        }
 
        for (i = 0; i < ngroups; i++) {
-               if (!gid_to_sid(&(group_sids)[i], (groups)[i])) {
+               if (NT_STATUS_IS_ERR(gid_to_sid(&(group_sids)[i], (groups)[i]))) {
                        DEBUG(1, ("create_nt_token: failed to convert gid %ld to a sid!\n", (long int)groups[i]));
                        SAFE_FREE(group_sids);
                        return NULL;
@@ -616,69 +648,57 @@ NT_USER_TOKEN *create_nt_token(uid_t uid, gid_t gid, int ngroups, gid_t *groups,
  * If this samba server is a DC of the domain the user belongs to, it returns 
  * both domain groups and local / builtin groups. If the user is in a trusted
  * domain, or samba is a member server of a domain, then this function returns
- * local and builtin groups the user is a member of. 
+ * local and builtin groups the user is a member of.
  *
  * currently this is a hack, as there is no sam implementation that is capable
  * of groups.
  ******************************************************************************/
 
-static NTSTATUS get_user_groups_from_local_sam(const DOM_SID *user_sid, 
+static NTSTATUS get_user_groups_from_local_sam(SAM_ACCOUNT *sampass,
                                               int *n_groups, DOM_SID **groups, gid_t **unix_groups)
 {
        uid_t             uid;
-       enum SID_NAME_USE snu;
-       fstring           str;
+       gid_t             gid;
        int               n_unix_groups;
        int               i;
-       struct passwd    *usr;  
-       
+
        *n_groups = 0;
        *groups   = NULL;
-       
-       if (!sid_to_uid(user_sid,  &uid, &snu)) {
-               DEBUG(2, ("get_user_groups_from_local_sam: Failed to convert user SID %s to a uid!\n", 
-                         sid_to_string(str, user_sid)));
-               /* This might be a non-unix account */
-               return NT_STATUS_OK;
-       }
 
-       /*
-        * This is _essential_ to prevent occasional segfaults when
-        * winbind can't find uid -> username mapping
-        */
-       if (!(usr = getpwuid_alloc(uid))) {
-               DEBUG(0, ("Couldn't find passdb structure for UID = %d ! Aborting.\n", uid));
-               return NT_STATUS_NO_SUCH_USER;
-       };
+       if (NT_STATUS_IS_ERR(sid_to_uid(pdb_get_user_sid(sampass), &uid)) || NT_STATUS_IS_ERR(sid_to_gid(pdb_get_group_sid(sampass), &gid))) {
+               DEBUG(0, ("get_user_groups_from_local_sam: error fetching uid or gid for user!\n"));
+               return NT_STATUS_UNSUCCESSFUL;
+       }
        
        n_unix_groups = groups_max();
-       if ((*unix_groups = malloc( sizeof(gid_t) * groups_max() ) ) == NULL) {
+       if ((*unix_groups = malloc( sizeof(gid_t) * n_unix_groups ) ) == NULL) {
                DEBUG(0, ("get_user_groups_from_local_sam: Out of memory allocating unix group list\n"));
-               passwd_free(&usr);
                return NT_STATUS_NO_MEMORY;
        }
        
-       if (sys_getgrouplist(usr->pw_name, usr->pw_gid, *unix_groups, &n_unix_groups) == -1) {
-               *unix_groups = Realloc(unix_groups, sizeof(gid_t) * n_unix_groups);
-               if (sys_getgrouplist(usr->pw_name, usr->pw_gid, *unix_groups, &n_unix_groups) == -1) {
+       if (sys_getgrouplist(pdb_get_username(sampass), gid, *unix_groups, &n_unix_groups) == -1) {
+               gid_t *groups_tmp;
+               groups_tmp = Realloc(*unix_groups, sizeof(gid_t) * n_unix_groups);
+               if (!groups_tmp) {
+                       SAFE_FREE(*unix_groups);
+                       return NT_STATUS_NO_MEMORY;
+               }
+               *unix_groups = groups_tmp;
+
+               if (sys_getgrouplist(pdb_get_username(sampass), gid, *unix_groups, &n_unix_groups) == -1) {
                        DEBUG(0, ("get_user_groups_from_local_sam: failed to get the unix group list\n"));
-                       SAFE_FREE(unix_groups);
-                       passwd_free(&usr);
+                       SAFE_FREE(*unix_groups);
                        return NT_STATUS_NO_SUCH_USER; /* what should this return value be? */
                }
        }
 
-       passwd_free(&usr);
+       debug_unix_user_token(DBGC_CLASS, 5, uid, gid, n_unix_groups, *unix_groups);
        
-       DEBUG(5,("get_user_groups_from_local_sam: user is in the unix following groups\n"));
-       for (i = 0; i < n_unix_groups; i++)
-               DEBUGADD(5,("supplementary group gid:%ld\n",(long int)(*unix_groups)[i]));
-
        if (n_unix_groups > 0) {
                *groups   = malloc(sizeof(DOM_SID) * n_unix_groups);
                if (!*groups) {
                        DEBUG(0, ("get_user_group_from_local_sam: malloc() failed for DOM_SID list!\n"));
-                       SAFE_FREE(unix_groups);
+                       SAFE_FREE(*unix_groups);
                        return NT_STATUS_NO_MEMORY;
                }
        }
@@ -686,10 +706,10 @@ static NTSTATUS get_user_groups_from_local_sam(const DOM_SID *user_sid,
        *n_groups = n_unix_groups;
 
        for (i = 0; i < *n_groups; i++) {
-               if (!gid_to_sid(&(*groups)[i], (*unix_groups)[i])) {
-                       DEBUG(1, ("get_user_groups_from_local_sam: failed to convert gid %ld to a sid!\n", (long int)unix_groups[i+1]));
-                       SAFE_FREE(groups);
-                       SAFE_FREE(unix_groups);
+               if (NT_STATUS_IS_ERR(gid_to_sid(&(*groups)[i], (*unix_groups)[i]))) {
+                       DEBUG(1, ("get_user_groups_from_local_sam: failed to convert gid %ld to a sid!\n", (long int)(*unix_groups)[i+1]));
+                       SAFE_FREE(*groups);
+                       SAFE_FREE(*unix_groups);
                        return NT_STATUS_NO_SUCH_USER;
                }
        }
@@ -703,6 +723,8 @@ static NTSTATUS get_user_groups_from_local_sam(const DOM_SID *user_sid,
 
 static NTSTATUS make_server_info(auth_serversupplied_info **server_info, SAM_ACCOUNT *sampass)
 {
+       NTSTATUS ret;
+
        *server_info = malloc(sizeof(**server_info));
        if (!*server_info) {
                DEBUG(0,("make_server_info: malloc failed!\n"));
@@ -712,6 +734,10 @@ static NTSTATUS make_server_info(auth_serversupplied_info **server_info, SAM_ACC
 
        (*server_info)->sam_fill_level = SAM_FILL_ALL;
        (*server_info)->sam_account    = sampass;
+       if (NT_STATUS_IS_ERR(ret = sid_to_uid(pdb_get_user_sid(sampass), &((*server_info)->uid))))
+               return ret;
+       if (NT_STATUS_IS_ERR(ret = sid_to_gid(pdb_get_group_sid(sampass), &((*server_info)->gid))))
+               return ret;
 
        return NT_STATUS_OK;
 }
@@ -738,7 +764,7 @@ NTSTATUS make_server_info_sam(auth_serversupplied_info **server_info,
        }
        
        if (!NT_STATUS_IS_OK(nt_status 
-                            = get_user_groups_from_local_sam(pdb_get_user_sid(sampass)
+                            = get_user_groups_from_local_sam(sampass
                &n_groupSIDs, &groupSIDs, &unix_groups)))
        {
                DEBUG(4,("get_user_groups_from_local_sam failed\n"));
@@ -766,8 +792,6 @@ NTSTATUS make_server_info_sam(auth_serversupplied_info **server_info,
 
        (*server_info)->ptok = token;
        
-       debug_nt_user_token(DBGC_AUTH, 5, token);
-
        DEBUG(5,("make_server_info_sam: made server info for user %s\n",
                 pdb_get_username((*server_info)->sam_account)));
 
@@ -806,13 +830,18 @@ NTSTATUS make_server_info_guest(auth_serversupplied_info **server_info)
        sid_copy(&guest_sid, get_global_sam_sid());
        sid_append_rid(&guest_sid, DOMAIN_USER_RID_GUEST);
 
+       become_root();
        if (!pdb_getsampwsid(sampass, &guest_sid)) {
+               unbecome_root();
                return NT_STATUS_NO_SUCH_USER;
        }
+       unbecome_root();
 
        nt_status = make_server_info_sam(server_info, sampass);
 
-       (*server_info)->guest = True;
+       if (NT_STATUS_IS_OK(nt_status)) {
+               (*server_info)->guest = True;
+       }
 
        return nt_status;
 }
@@ -839,8 +868,8 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx,
 
        struct passwd *passwd;
 
-       uid_t uid;
-       gid_t gid;
+       unid_t u_id, g_id;
+       int u_type, g_type;
 
        int n_lgroupSIDs;
        DOM_SID *lgroupSIDs   = NULL;
@@ -849,7 +878,7 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx,
        NT_USER_TOKEN *token;
 
        DOM_SID *all_group_SIDs;
-       int i;
+       size_t i;
 
        /* 
           Here is where we should check the list of
@@ -877,9 +906,11 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx,
                domain = domain;
        }
 
-       if (winbind_sid_to_uid(&uid, &user_sid) 
-           && winbind_sid_to_gid(&gid, &group_sid) 
-           && ((passwd = getpwuid_alloc(uid)))) {
+       u_type = ID_USERID;
+       g_type = ID_GROUPID;
+       if (NT_STATUS_IS_OK(idmap_get_id_from_sid(&u_id, &u_type, &user_sid))
+           && NT_STATUS_IS_OK(idmap_get_id_from_sid(&g_id, &g_type, &group_sid))
+           && ((passwd = getpwuid_alloc(u_id.uid)))) {
                nt_status = pdb_init_sam_pw(&sam_account, passwd);
                passwd_free(&passwd);
        } else {
@@ -915,47 +946,47 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx,
                return nt_status;
        }
                
-       if (!pdb_set_user_sid(sam_account, &user_sid)) {
+       if (!pdb_set_user_sid(sam_account, &user_sid, PDB_CHANGED)) {
                pdb_free_sam(&sam_account);
                return NT_STATUS_UNSUCCESSFUL;
        }
 
-       if (!pdb_set_group_sid(sam_account, &group_sid)) {
+       if (!pdb_set_group_sid(sam_account, &group_sid, PDB_CHANGED)) {
                pdb_free_sam(&sam_account);
                return NT_STATUS_UNSUCCESSFUL;
        }
                
-       if (!pdb_set_nt_username(sam_account, nt_username)) {
+       if (!pdb_set_nt_username(sam_account, nt_username, PDB_CHANGED)) {
                pdb_free_sam(&sam_account);
                return NT_STATUS_NO_MEMORY;
        }
 
-       if (!pdb_set_domain(sam_account, nt_domain)) {
+       if (!pdb_set_domain(sam_account, nt_domain, PDB_CHANGED)) {
                pdb_free_sam(&sam_account);
                return NT_STATUS_NO_MEMORY;
        }
 
-       if (!pdb_set_fullname(sam_account, pdb_unistr2_convert(&(info3->uni_full_name)))) {
+       if (!pdb_set_fullname(sam_account, unistr2_static(&(info3->uni_full_name)), PDB_CHANGED)) {
                pdb_free_sam(&sam_account);
                return NT_STATUS_NO_MEMORY;
        }
 
-       if (!pdb_set_logon_script(sam_account, pdb_unistr2_convert(&(info3->uni_logon_script)), True)) {
+       if (!pdb_set_logon_script(sam_account, unistr2_static(&(info3->uni_logon_script)), PDB_CHANGED)) {
                pdb_free_sam(&sam_account);
                return NT_STATUS_NO_MEMORY;
        }
 
-       if (!pdb_set_profile_path(sam_account, pdb_unistr2_convert(&(info3->uni_profile_path)), True)) {
+       if (!pdb_set_profile_path(sam_account, unistr2_static(&(info3->uni_profile_path)), PDB_CHANGED)) {
                pdb_free_sam(&sam_account);
                return NT_STATUS_NO_MEMORY;
        }
 
-       if (!pdb_set_homedir(sam_account, pdb_unistr2_convert(&(info3->uni_home_dir)), True)) {
+       if (!pdb_set_homedir(sam_account, unistr2_static(&(info3->uni_home_dir)), PDB_CHANGED)) {
                pdb_free_sam(&sam_account);
                return NT_STATUS_NO_MEMORY;
        }
 
-       if (!pdb_set_dir_drive(sam_account, pdb_unistr2_convert(&(info3->uni_dir_drive)), True)) {
+       if (!pdb_set_dir_drive(sam_account, unistr2_static(&(info3->uni_dir_drive)), PDB_CHANGED)) {
                pdb_free_sam(&sam_account);
                return NT_STATUS_NO_MEMORY;
        }
@@ -970,7 +1001,7 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx,
           returned to the caller. */
        
        if (!NT_STATUS_IS_OK(nt_status 
-                            = get_user_groups_from_local_sam(&user_sid
+                            = get_user_groups_from_local_sam(sam_account
                                                              &n_lgroupSIDs, 
                                                              &lgroupSIDs, 
                                                              &unix_groups)))
@@ -983,7 +1014,9 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx,
        (*server_info)->n_groups = n_lgroupSIDs;
        
        /* Create a 'combined' list of all SIDs we might want in the SD */
-       all_group_SIDs   = malloc(sizeof(DOM_SID) * (n_lgroupSIDs+info3->num_groups2));
+       all_group_SIDs   = malloc(sizeof(DOM_SID) * 
+                                 (n_lgroupSIDs + info3->num_groups2 +
+                                  info3->num_other_sids));
        if (!all_group_SIDs) {
                DEBUG(0, ("create_nt_token_info3: malloc() failed for DOM_SID list!\n"));
                SAFE_FREE(lgroupSIDs);
@@ -1006,12 +1039,25 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx,
                }
        }
 
+       /* Copy 'other' sids.  We need to do sid filtering here to
+          prevent possible elevation of privileges.  See:
+
+           http://www.microsoft.com/windows2000/techinfo/administration/security/sidfilter.asp
+         */
+
+       for (i = 0; i < info3->num_other_sids; i++) 
+               sid_copy(&all_group_SIDs[
+                                n_lgroupSIDs + info3->num_groups2 + i],
+                        &info3->other_sids[i].sid);
+       
        /* Where are the 'global' sids... */
 
        /* can the user be guest? if yes, where is it stored? */
-       if (!NT_STATUS_IS_OK(nt_status = create_nt_user_token(&user_sid, &group_sid,
-                                                            n_lgroupSIDs+info3->num_groups2, all_group_SIDs, 
-                                                             False, &token))) {
+       if (!NT_STATUS_IS_OK(
+                   nt_status = create_nt_user_token(
+                           &user_sid, &group_sid,
+                           n_lgroupSIDs + info3->num_groups2 + info3->num_other_sids, 
+                           all_group_SIDs, False, &token))) {
                DEBUG(4,("create_nt_user_token failed\n"));
                SAFE_FREE(all_group_SIDs);
                return nt_status;
@@ -1021,8 +1067,9 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx,
 
        SAFE_FREE(all_group_SIDs);
        
-       debug_nt_user_token(DBGC_AUTH, 5, token);
-       
+       memcpy((*server_info)->session_key, info3->user_sess_key, sizeof((*server_info)->session_key)/* 16 */);
+       memcpy((*server_info)->first_8_lm_hash, info3->padding, 8);
+
        return NT_STATUS_OK;
 }