s3-auth: Don't lookup the system user in pdb.
[ddiss/samba.git] / source3 / auth / auth_util.c
index 9dbe04f4ca28687acf250b3c1b62301eb19194d2..c7e266a97bdf5f976489620357b4434628aa5fbf 100644 (file)
 */
 
 #include "includes.h"
-#include "smbd/globals.h"
+#include "auth.h"
 #include "../libcli/auth/libcli_auth.h"
 #include "../lib/crypto/arcfour.h"
 #include "rpc_client/init_lsa.h"
+#include "../libcli/security/security.h"
+#include "../lib/util/util_pw.h"
+#include "lib/winbind_util.h"
+#include "passdb.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_AUTH
@@ -95,9 +99,12 @@ NTSTATUS make_user_info_map(struct auth_usersupplied_info **user_info,
        const char *domain;
        NTSTATUS result;
        bool was_mapped;
-       fstring internal_username;
-       fstrcpy(internal_username, smb_name);
-       was_mapped = map_username(internal_username);
+       char *internal_username = NULL;
+
+       was_mapped = map_username(talloc_tos(), smb_name, &internal_username);
+       if (!internal_username) {
+               return NT_STATUS_NO_MEMORY;
+       }
 
        DEBUG(5, ("Mapping user [%s]\\[%s] from workstation [%s]\n",
                 client_domain, smb_name, workstation_name));
@@ -388,7 +395,7 @@ bool make_user_info_guest(struct auth_usersupplied_info **user_info)
        return NT_STATUS_IS_OK(nt_status) ? True : False;
 }
 
-static NTSTATUS log_nt_token(NT_USER_TOKEN *token)
+static NTSTATUS log_nt_token(struct security_token *token)
 {
        TALLOC_CTX *frame = talloc_stackframe();
        char *command;
@@ -436,9 +443,11 @@ static NTSTATUS log_nt_token(NT_USER_TOKEN *token)
 
 NTSTATUS create_local_token(struct auth_serversupplied_info *server_info)
 {
+       struct security_token *t;
        NTSTATUS status;
        size_t i;
        struct dom_sid tmp_sid;
+       struct wbcUnixId *ids;
 
        /*
         * If winbind is not around, we can not make much use of the SIDs the
@@ -454,14 +463,14 @@ NTSTATUS create_local_token(struct auth_serversupplied_info *server_info)
                                                    &server_info->utok.uid,
                                                    &server_info->utok.gid,
                                                    &server_info->unix_name,
-                                                   &server_info->ptok);
+                                                   &server_info->security_token);
 
        } else {
                status = create_local_nt_token_from_info3(server_info,
                                                          server_info->guest,
                                                          server_info->info3,
                                                          &server_info->extra,
-                                                         &server_info->ptok);
+                                                         &server_info->security_token);
        }
 
        if (!NT_STATUS_IS_OK(status)) {
@@ -473,20 +482,34 @@ NTSTATUS create_local_token(struct auth_serversupplied_info *server_info)
        server_info->utok.ngroups = 0;
        server_info->utok.groups = NULL;
 
+       t = server_info->security_token;
+
+       ids = TALLOC_ARRAY(talloc_tos(), struct wbcUnixId,
+                          t->num_sids);
+       if (ids == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if (!sids_to_unix_ids(t->sids, t->num_sids, ids)) {
+               TALLOC_FREE(ids);
+               return NT_STATUS_NO_MEMORY;
+       }
+
        /* Start at index 1, where the groups start. */
 
-       for (i=1; i<server_info->ptok->num_sids; i++) {
-               gid_t gid;
-               struct dom_sid *sid = &server_info->ptok->sids[i];
+       for (i=1; i<t->num_sids; i++) {
 
-               if (!sid_to_gid(sid, &gid)) {
+               if (ids[i].type != WBC_ID_TYPE_GID) {
                        DEBUG(10, ("Could not convert SID %s to gid, "
-                                  "ignoring it\n", sid_string_dbg(sid)));
+                                  "ignoring it\n",
+                                  sid_string_dbg(&t->sids[i])));
                        continue;
                }
-               add_gid_to_array_unique(server_info, gid,
-                                       &server_info->utok.groups,
-                                       &server_info->utok.ngroups);
+               if (!add_gid_to_array_unique(server_info, ids[i].id.gid,
+                                            &server_info->utok.groups,
+                                            &server_info->utok.ngroups)) {
+                       return NT_STATUS_NO_MEMORY;
+               }
        }
 
        /*
@@ -504,25 +527,25 @@ NTSTATUS create_local_token(struct auth_serversupplied_info *server_info)
 
        uid_to_unix_users_sid(server_info->utok.uid, &tmp_sid);
 
-       add_sid_to_array_unique(server_info->ptok, &tmp_sid,
-                               &server_info->ptok->sids,
-                               &server_info->ptok->num_sids);
+       add_sid_to_array_unique(server_info->security_token, &tmp_sid,
+                               &server_info->security_token->sids,
+                               &server_info->security_token->num_sids);
 
        for ( i=0; i<server_info->utok.ngroups; i++ ) {
                gid_to_unix_groups_sid(server_info->utok.groups[i], &tmp_sid);
-               add_sid_to_array_unique(server_info->ptok, &tmp_sid,
-                                       &server_info->ptok->sids,
-                                       &server_info->ptok->num_sids);
+               add_sid_to_array_unique(server_info->security_token, &tmp_sid,
+                                       &server_info->security_token->sids,
+                                       &server_info->security_token->num_sids);
        }
 
-       debug_nt_user_token(DBGC_AUTH, 10, server_info->ptok);
+       security_token_debug(DBGC_AUTH, 10, server_info->security_token);
        debug_unix_user_token(DBGC_AUTH, 10,
                              server_info->utok.uid,
                              server_info->utok.gid,
                              server_info->utok.ngroups,
                              server_info->utok.groups);
 
-       status = log_nt_token(server_info->ptok);
+       status = log_nt_token(server_info->security_token);
        return status;
 }
 
@@ -632,6 +655,44 @@ NTSTATUS make_server_info_pw(struct auth_serversupplied_info **server_info,
        return NT_STATUS_OK;
 }
 
+static NTSTATUS get_system_info3(TALLOC_CTX *mem_ctx,
+                                struct passwd *pwd,
+                                struct netr_SamInfo3 *info3)
+{
+       struct dom_sid domain_sid;
+       const char *tmp;
+
+       /* Set account name */
+       tmp = talloc_strdup(mem_ctx, pwd->pw_name);
+       if (tmp == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       init_lsa_String(&info3->base.account_name, tmp);
+
+       /* Set domain name */
+       tmp = talloc_strdup(mem_ctx, get_global_sam_name());
+       if (tmp == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       init_lsa_StringLarge(&info3->base.domain, tmp);
+
+       /* Domain sid */
+       sid_copy(&domain_sid, get_global_sam_sid());
+
+       info3->base.domain_sid = dom_sid_dup(mem_ctx, &domain_sid);
+       if (info3->base.domain_sid == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       /* Admin rid */
+       info3->base.rid = DOMAIN_RID_ADMINISTRATOR;
+
+       /* Primary gid */
+       info3->base.primary_gid = BUILTIN_RID_ADMINISTRATORS;
+
+       return NT_STATUS_OK;
+}
+
 static NTSTATUS get_guest_info3(TALLOC_CTX *mem_ctx,
                                struct netr_SamInfo3 *info3)
 {
@@ -640,7 +701,7 @@ static NTSTATUS get_guest_info3(TALLOC_CTX *mem_ctx,
        struct passwd *pwd;
        const char *tmp;
 
-       pwd = getpwnam_alloc(mem_ctx, guest_account);
+       pwd = Get_Pwnam_alloc(mem_ctx, guest_account);
        if (pwd == NULL) {
                DEBUG(0,("SamInfo3_for_guest: Unable to locate guest "
                         "account [%s]!\n", guest_account));
@@ -664,7 +725,7 @@ static NTSTATUS get_guest_info3(TALLOC_CTX *mem_ctx,
        /* Domain sid */
        sid_copy(&domain_sid, get_global_sam_sid());
 
-       info3->base.domain_sid = sid_dup_talloc(mem_ctx, &domain_sid);
+       info3->base.domain_sid = dom_sid_dup(mem_ctx, &domain_sid);
        if (info3->base.domain_sid == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -737,34 +798,99 @@ static NTSTATUS make_new_server_info_guest(struct auth_serversupplied_info **ser
        status = NT_STATUS_OK;
 done:
        TALLOC_FREE(tmp_ctx);
-       return NT_STATUS_OK;
+       return status;
+}
+
+/****************************************************************************
+  Fake a auth_session_info just from a username (as a
+  session_info structure, with create_local_token() already called on
+  it.
+****************************************************************************/
+
+static NTSTATUS make_system_session_info_from_pw(TALLOC_CTX *mem_ctx,
+                                                struct passwd *pwd,
+                                                struct auth_serversupplied_info **server_info)
+{
+       const char *domain = global_myname();
+       struct netr_SamInfo3 info3;
+       TALLOC_CTX *tmp_ctx;
+       NTSTATUS status;
+
+       tmp_ctx = talloc_stackframe();
+       if (tmp_ctx == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       ZERO_STRUCT(info3);
+
+       status = get_system_info3(tmp_ctx, pwd, &info3);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("Failed creating system info3 with %s\n",
+                         nt_errstr(status)));
+               goto done;
+       }
+
+       status = make_server_info_info3(mem_ctx,
+                                       pwd->pw_name,
+                                       domain,
+                                       server_info,
+                                       &info3);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("make_server_info_info3 failed with %s\n",
+                         nt_errstr(status)));
+               goto done;
+       }
+
+       (*server_info)->nss_token = true;
+
+       /* Now turn the server_info into a session_info with the full token etc */
+       status = create_local_token(*server_info);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("create_local_token failed: %s\n",
+                         nt_errstr(status)));
+               goto done;
+       }
+
+       status = NT_STATUS_OK;
+done:
+       TALLOC_FREE(tmp_ctx);
+       return status;
 }
 
 /***************************************************************************
- Make (and fill) a user_info struct for a system user login.
+ Make (and fill) a auth_session_info struct for a system user login.
  This *must* succeed for smbd to start.
 ***************************************************************************/
 
-static NTSTATUS make_new_server_info_system(TALLOC_CTX *mem_ctx,
-                                           struct auth_serversupplied_info **server_info)
+static NTSTATUS make_new_session_info_system(TALLOC_CTX *mem_ctx,
+                                           struct auth_serversupplied_info **session_info)
 {
        struct passwd *pwd;
        NTSTATUS status;
 
        pwd = getpwuid_alloc(mem_ctx, sec_initial_uid());
        if (pwd == NULL) {
-               return NT_STATUS_NO_MEMORY;
+               return NT_STATUS_NO_SUCH_USER;
        }
 
-       status = make_serverinfo_from_username(mem_ctx,
-                                            pwd->pw_name,
-                                            false,
-                                            server_info);
+       status = make_system_session_info_from_pw(mem_ctx,
+                                                 pwd,
+                                                 session_info);
+       TALLOC_FREE(pwd);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       (*server_info)->system = true;
+       (*session_info)->system = true;
+
+       status = add_sid_to_array_unique((*session_info)->security_token->sids,
+                                        &global_sid_System,
+                                        &(*session_info)->security_token->sids,
+                                        &(*session_info)->security_token->num_sids);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE((*session_info));
+               return status;
+       }
 
        return NT_STATUS_OK;
 }
@@ -782,7 +908,7 @@ NTSTATUS make_serverinfo_from_username(TALLOC_CTX *mem_ctx,
        struct passwd *pwd;
        NTSTATUS status;
 
-       pwd = getpwnam_alloc(talloc_tos(), username);
+       pwd = Get_Pwnam_alloc(talloc_tos(), username);
        if (pwd == NULL) {
                return NT_STATUS_NO_SUCH_USER;
        }
@@ -805,7 +931,7 @@ NTSTATUS make_serverinfo_from_username(TALLOC_CTX *mem_ctx,
                return status;
        }
 
-       *presult = result;
+       *presult = talloc_steal(mem_ctx, result);
        return NT_STATUS_OK;
 }
 
@@ -833,9 +959,9 @@ struct auth_serversupplied_info *copy_serverinfo(TALLOC_CTX *mem_ctx,
                dst->utok.groups = NULL;
        }
 
-       if (src->ptok) {
-               dst->ptok = dup_nt_token(dst, src->ptok);
-               if (!dst->ptok) {
+       if (src->security_token) {
+               dst->security_token = dup_nt_token(dst, src->security_token);
+               if (!dst->security_token) {
                        TALLOC_FREE(dst);
                        return NULL;
                }
@@ -854,7 +980,6 @@ struct auth_serversupplied_info *copy_serverinfo(TALLOC_CTX *mem_ctx,
        }
        dst->extra = src->extra;
 
-       dst->pam_handle = NULL;
        dst->unix_name = talloc_strdup(dst, src->unix_name);
        if (!dst->unix_name) {
                TALLOC_FREE(dst);
@@ -875,7 +1000,7 @@ struct auth_serversupplied_info *copy_serverinfo(TALLOC_CTX *mem_ctx,
  * SMB level session key with SystemLibraryDTC
  */
 
-bool server_info_set_session_key(struct auth_serversupplied_info *info,
+bool session_info_set_session_key(struct auth_serversupplied_info *info,
                                 DATA_BLOB session_key)
 {
        TALLOC_FREE(info->user_session_key.data);
@@ -905,23 +1030,23 @@ NTSTATUS make_server_info_guest(TALLOC_CTX *mem_ctx,
 
 static struct auth_serversupplied_info *system_info = NULL;
 
-bool init_system_info(void)
+NTSTATUS init_system_info(void)
 {
        if (system_info != NULL)
-               return True;
+               return NT_STATUS_OK;
 
-       return NT_STATUS_IS_OK(make_new_server_info_system(talloc_autofree_context(), &system_info));
+       return make_new_session_info_system(NULL, &system_info);
 }
 
-NTSTATUS make_server_info_system(TALLOC_CTX *mem_ctx,
-                               struct auth_serversupplied_info **server_info)
+NTSTATUS make_session_info_system(TALLOC_CTX *mem_ctx,
+                               struct auth_serversupplied_info **session_info)
 {
        if (system_info == NULL) return NT_STATUS_UNSUCCESSFUL;
-       *server_info = copy_serverinfo(mem_ctx, system_info);
-       return (*server_info != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
+       *session_info = copy_serverinfo(mem_ctx, system_info);
+       return (*session_info != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
 }
 
-const struct auth_serversupplied_info *get_server_info_system(void)
+const struct auth_serversupplied_info *get_session_info_system(void)
 {
     return system_info;
 }
@@ -929,7 +1054,7 @@ const struct auth_serversupplied_info *get_server_info_system(void)
 bool copy_current_user(struct current_user *dst, struct current_user *src)
 {
        gid_t *groups;
-       NT_USER_TOKEN *nt_token;
+       struct security_token *nt_token;
 
        groups = (gid_t *)memdup(src->ut.groups,
                                 sizeof(gid_t) * src->ut.ngroups);
@@ -962,27 +1087,45 @@ static NTSTATUS check_account(TALLOC_CTX *mem_ctx, const char *domain,
                              struct passwd **pwd,
                              bool *username_was_mapped)
 {
-       fstring dom_user, lower_username;
-       fstring real_username;
+       char *orig_dom_user = NULL;
+       char *dom_user = NULL;
+       char *lower_username = NULL;
+       char *real_username = NULL;
        struct passwd *passwd;
 
-       fstrcpy( lower_username, username );
+       lower_username = talloc_strdup(mem_ctx, username);
+       if (!lower_username) {
+               return NT_STATUS_NO_MEMORY;
+       }
        strlower_m( lower_username );
 
-       fstr_sprintf(dom_user, "%s%c%s", domain, *lp_winbind_separator(), 
-               lower_username);
+       orig_dom_user = talloc_asprintf(mem_ctx,
+                               "%s%c%s",
+                               domain,
+                               *lp_winbind_separator(),
+                               lower_username);
+       if (!orig_dom_user) {
+               return NT_STATUS_NO_MEMORY;
+       }
 
        /* Get the passwd struct.  Try to create the account if necessary. */
 
-       *username_was_mapped = map_username(dom_user);
+       *username_was_mapped = map_username(mem_ctx, orig_dom_user, &dom_user);
+       if (!dom_user) {
+               return NT_STATUS_NO_MEMORY;
+       }
 
-       passwd = smb_getpwnam( NULL, dom_user, real_username, True );
+       passwd = smb_getpwnam(mem_ctx, dom_user, &real_username, True );
        if (!passwd) {
                DEBUG(3, ("Failed to find authenticated user %s via "
                          "getpwnam(), denying access.\n", dom_user));
                return NT_STATUS_NO_SUCH_USER;
        }
 
+       if (!real_username) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
        *pwd = passwd;
 
        /* This is pointless -- there is no suport for differing 
@@ -1003,31 +1146,31 @@ static NTSTATUS check_account(TALLOC_CTX *mem_ctx, const char *domain,
  ****************************************************************************/
 
 struct passwd *smb_getpwnam( TALLOC_CTX *mem_ctx, const char *domuser,
-                            fstring save_username, bool create )
+                            char **p_save_username, bool create )
 {
        struct passwd *pw = NULL;
-       char *p;
-       fstring username;
+       char *p = NULL;
+       char *username = NULL;
 
        /* we only save a copy of the username it has been mangled 
           by winbindd use default domain */
-
-       save_username[0] = '\0';
+       *p_save_username = NULL;
 
        /* don't call map_username() here since it has to be done higher 
           up the stack so we don't call it multiple times */
 
-       fstrcpy( username, domuser );
+       username = talloc_strdup(mem_ctx, domuser);
+       if (!username) {
+               return NULL;
+       }
 
        p = strchr_m( username, *lp_winbind_separator() );
 
        /* code for a DOMAIN\user string */
 
        if ( p ) {
-               fstring strip_username;
-
                pw = Get_Pwnam_alloc( mem_ctx, domuser );
-               if ( pw ) {     
+               if ( pw ) {
                        /* make sure we get the case of the username correct */
                        /* work around 'winbind use default domain = yes' */
 
@@ -1038,12 +1181,20 @@ struct passwd *smb_getpwnam( TALLOC_CTX *mem_ctx, const char *domuser,
                                *p = '\0';
                                domain = username;
 
-                               fstr_sprintf(save_username, "%s%c%s", domain, *lp_winbind_separator(), pw->pw_name);
+                               *p_save_username = talloc_asprintf(mem_ctx,
+                                                               "%s%c%s",
+                                                               domain,
+                                                               *lp_winbind_separator(),
+                                                               pw->pw_name);
+                               if (!*p_save_username) {
+                                       TALLOC_FREE(pw);
+                                       return NULL;
+                               }
+                       } else {
+                               *p_save_username = talloc_strdup(mem_ctx, pw->pw_name);
                        }
-                       else
-                               fstrcpy( save_username, pw->pw_name );
 
-                       /* whew -- done! */             
+                       /* whew -- done! */
                        return pw;
                }
 
@@ -1051,8 +1202,10 @@ struct passwd *smb_getpwnam( TALLOC_CTX *mem_ctx, const char *domuser,
                /* remember that p and username are overlapping memory */
 
                p++;
-               fstrcpy( strip_username, p );
-               fstrcpy( username, strip_username );
+               username = talloc_strdup(mem_ctx, p);
+               if (!username) {
+                       return NULL;
+               }
        }
 
        /* just lookup a plain username */
@@ -1075,9 +1228,9 @@ struct passwd *smb_getpwnam( TALLOC_CTX *mem_ctx, const char *domuser,
 
        /* one last check for a valid passwd struct */
 
-       if ( pw )
-               fstrcpy( save_username, pw->pw_name );
-
+       if (pw) {
+               *p_save_username = talloc_strdup(mem_ctx, pw->pw_name);
+       }
        return pw;
 }