s3-talloc Change TALLOC_ARRAY() to talloc_array()
[kai/samba.git] / source3 / auth / auth_util.c
index 825452026e3892e3f3aa1126760e888ab83a2b2a..25d84e9d86095da0d65add26331398c8f88662a9 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/dom_sid.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
@@ -96,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));
@@ -435,11 +441,48 @@ static NTSTATUS log_nt_token(struct security_token *token)
  * server_info->sids (the info3/sam groups). Find the unix gids.
  */
 
-NTSTATUS create_local_token(struct auth_serversupplied_info *server_info)
+NTSTATUS create_local_token(TALLOC_CTX *mem_ctx,
+                           const struct auth_serversupplied_info *server_info,
+                           DATA_BLOB *session_key,
+                           struct auth_serversupplied_info **session_info_out)
 {
+       struct security_token *t;
        NTSTATUS status;
        size_t i;
        struct dom_sid tmp_sid;
+       struct auth_serversupplied_info *session_info;
+       struct wbcUnixId *ids;
+
+       /* Ensure we can't possible take a code path leading to a
+        * null defref. */
+       if (!server_info) {
+               return NT_STATUS_LOGON_FAILURE;
+       }
+
+       session_info = copy_serverinfo(mem_ctx, server_info);
+
+       if (!session_info) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if (session_key) {
+               data_blob_free(&session_info->session_key);
+               session_info->session_key = data_blob_talloc(session_info,
+                                                                 session_key->data,
+                                                                 session_key->length);
+               if (!session_info->session_key.data && session_key->length) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+       }
+
+       if (session_info->security_token) {
+               /* Just copy the token, it has already been finalised
+                * (nasty hack to support a cached guest session_info,
+                * and a possible strategy for auth_samba4 to pass in
+                * a finalised session) */
+               *session_info_out = session_info;
+               return NT_STATUS_OK;
+       }
 
        /*
         * If winbind is not around, we can not make much use of the SIDs the
@@ -448,21 +491,21 @@ NTSTATUS create_local_token(struct auth_serversupplied_info *server_info)
         */
 
        if (((lp_server_role() == ROLE_DOMAIN_MEMBER) && !winbind_ping()) ||
-           (server_info->nss_token)) {
-               status = create_token_from_username(server_info,
-                                                   server_info->unix_name,
-                                                   server_info->guest,
-                                                   &server_info->utok.uid,
-                                                   &server_info->utok.gid,
-                                                   &server_info->unix_name,
-                                                   &server_info->ptok);
+           (session_info->nss_token)) {
+               status = create_token_from_username(session_info,
+                                                   session_info->unix_name,
+                                                   session_info->guest,
+                                                   &session_info->utok.uid,
+                                                   &session_info->utok.gid,
+                                                   &session_info->unix_name,
+                                                   &session_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);
+               status = create_local_nt_token_from_info3(session_info,
+                                                         session_info->guest,
+                                                         session_info->info3,
+                                                         &session_info->extra,
+                                                         &session_info->security_token);
        }
 
        if (!NT_STATUS_IS_OK(status)) {
@@ -471,23 +514,37 @@ NTSTATUS create_local_token(struct auth_serversupplied_info *server_info)
 
        /* Convert the SIDs to gids. */
 
-       server_info->utok.ngroups = 0;
-       server_info->utok.groups = NULL;
+       session_info->utok.ngroups = 0;
+       session_info->utok.groups = NULL;
+
+       t = session_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(session_info, ids[i].id.gid,
+                                            &session_info->utok.groups,
+                                            &session_info->utok.ngroups)) {
+                       return NT_STATUS_NO_MEMORY;
+               }
        }
 
        /*
@@ -503,28 +560,33 @@ NTSTATUS create_local_token(struct auth_serversupplied_info *server_info)
         * the nt token.
         */
 
-       uid_to_unix_users_sid(server_info->utok.uid, &tmp_sid);
+       uid_to_unix_users_sid(session_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(session_info->security_token, &tmp_sid,
+                               &session_info->security_token->sids,
+                               &session_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);
+       for ( i=0; i<session_info->utok.ngroups; i++ ) {
+               gid_to_unix_groups_sid(session_info->utok.groups[i], &tmp_sid);
+               add_sid_to_array_unique(session_info->security_token, &tmp_sid,
+                                       &session_info->security_token->sids,
+                                       &session_info->security_token->num_sids);
        }
 
-       debug_nt_user_token(DBGC_AUTH, 10, server_info->ptok);
+       security_token_debug(DBGC_AUTH, 10, session_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);
+                             session_info->utok.uid,
+                             session_info->utok.gid,
+                             session_info->utok.ngroups,
+                             session_info->utok.groups);
 
-       status = log_nt_token(server_info->ptok);
-       return status;
+       status = log_nt_token(session_info->security_token);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       *session_info_out = session_info;
+       return NT_STATUS_OK;
 }
 
 /***************************************************************************
@@ -641,7 +703,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));
@@ -684,10 +746,16 @@ static NTSTATUS get_guest_info3(TALLOC_CTX *mem_ctx,
  Make (and fill) a user_info struct for a guest login.
  This *must* succeed for smbd to start. If there is no mapping entry for
  the guest gid, then create one.
+
+ The resulting structure is a 'session_info' because
+ create_local_token() has already been called on it.  This is quite
+ nasty, as the auth subsystem isn't expect this, but the behaviour is
+ left as-is for now.
 ***************************************************************************/
 
-static NTSTATUS make_new_server_info_guest(struct auth_serversupplied_info **server_info)
+static NTSTATUS make_new_server_info_guest(struct auth_serversupplied_info **session_info)
 {
+       struct auth_serversupplied_info *server_info;
        static const char zeros[16] = {0};
        const char *guest_account = lp_guestaccount();
        const char *domain = global_myname();
@@ -711,29 +779,34 @@ static NTSTATUS make_new_server_info_guest(struct auth_serversupplied_info **ser
        status = make_server_info_info3(tmp_ctx,
                                        guest_account,
                                        domain,
-                                       server_info,
+                                       &server_info,
                                        &info3);
        if (!NT_STATUS_IS_OK(status)) {
                goto done;
        }
 
-       (*server_info)->guest = True;
+       server_info->guest = True;
 
-       status = create_local_token(*server_info);
+       /* This should not be done here (we should produce a server
+        * info, and later construct a session info from it), but for
+        * now this does not change the previous behaviours */
+       status = create_local_token(tmp_ctx, server_info, NULL, session_info);
+       TALLOC_FREE(server_info);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(10, ("create_local_token failed: %s\n",
                           nt_errstr(status)));
                goto done;
        }
+       talloc_steal(NULL, *session_info);
 
        /* annoying, but the Guest really does have a session key, and it is
           all zeros! */
-       (*server_info)->user_session_key = data_blob(zeros, sizeof(zeros));
-       (*server_info)->lm_session_key = data_blob(zeros, sizeof(zeros));
+       (*session_info)->session_key = data_blob(zeros, sizeof(zeros));
+       (*session_info)->lm_session_key = data_blob(zeros, sizeof(zeros));
 
-       alpha_strcpy(tmp, (*server_info)->info3->base.account_name.string,
+       alpha_strcpy(tmp, (*session_info)->info3->base.account_name.string,
                     ". _-$", sizeof(tmp));
-       (*server_info)->sanitized_username = talloc_strdup(*server_info, tmp);
+       (*session_info)->sanitized_username = talloc_strdup(*session_info, tmp);
 
        status = NT_STATUS_OK;
 done:
@@ -742,48 +815,60 @@ done:
 }
 
 /***************************************************************************
- 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_session_info_from_username(mem_ctx,
+                                                pwd->pw_name,
+                                                false,
+                                                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;
 }
 
 /****************************************************************************
-  Fake a auth_serversupplied_info just from a username
+  Fake a auth_serversupplied_info just from a username (as a
+  session_info structure, with create_local_token() already called on
+  it.
 ****************************************************************************/
 
-NTSTATUS make_serverinfo_from_username(TALLOC_CTX *mem_ctx,
-                                      const char *username,
-                                      bool is_guest,
-                                      struct auth_serversupplied_info **presult)
+NTSTATUS make_session_info_from_username(TALLOC_CTX *mem_ctx,
+                                        const char *username,
+                                        bool is_guest,
+                                        struct auth_serversupplied_info **session_info)
 {
        struct auth_serversupplied_info *result;
        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;
        }
@@ -799,15 +884,10 @@ NTSTATUS make_serverinfo_from_username(TALLOC_CTX *mem_ctx,
        result->nss_token = true;
        result->guest = is_guest;
 
-       status = create_local_token(result);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               TALLOC_FREE(result);
-               return status;
-       }
-
-       *presult = result;
-       return NT_STATUS_OK;
+       /* Now turn the server_info into a session_info with the full token etc */
+       status = create_local_token(mem_ctx, result, NULL, session_info);
+       talloc_free(result);
+       return status;
 }
 
 
@@ -834,16 +914,16 @@ 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;
                }
        }
 
-       dst->user_session_key = data_blob_talloc( dst, src->user_session_key.data,
-                                               src->user_session_key.length);
+       dst->session_key = data_blob_talloc( dst, src->session_key.data,
+                                               src->session_key.length);
 
        dst->lm_session_key = data_blob_talloc(dst, src->lm_session_key.data,
                                                src->lm_session_key.length);
@@ -855,7 +935,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);
@@ -876,15 +955,15 @@ 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);
+       TALLOC_FREE(info->session_key.data);
 
-       info->user_session_key = data_blob_talloc(
+       info->session_key = data_blob_talloc(
                info, session_key.data, session_key.length);
 
-       return (info->user_session_key.data != NULL);
+       return (info->session_key.data != NULL);
 }
 
 static struct auth_serversupplied_info *guest_info = NULL;
@@ -906,23 +985,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;
 }
@@ -963,27 +1042,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 
@@ -1004,31 +1101,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' */
 
@@ -1039,12 +1136,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;
                }
 
@@ -1052,8 +1157,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 */
@@ -1076,9 +1183,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;
 }
 
@@ -1201,9 +1308,9 @@ NTSTATUS make_server_info_info3(TALLOC_CTX *mem_ctx,
        /* ensure we are never given NULL session keys */
 
        if (memcmp(info3->base.key.key, zeros, sizeof(zeros)) == 0) {
-               result->user_session_key = data_blob_null;
+               result->session_key = data_blob_null;
        } else {
-               result->user_session_key = data_blob_talloc(
+               result->session_key = data_blob_talloc(
                        result, info3->base.key.key,
                        sizeof(info3->base.key.key));
        }