s3-talloc Change TALLOC_ZERO_P() to talloc_zero()
[nivanova/samba-autobuild/.git] / source3 / auth / server_info.c
index d9b25bda68bbe5b9fae4a5992e0b2dccefdf9d74..a53e556d283d2b11fca194e8972c7a4dc4f6ee33 100644 (file)
 */
 
 #include "includes.h"
+#include "auth.h"
 #include "../lib/crypto/arcfour.h"
+#include "../librpc/gen_ndr/netlogon.h"
+#include "../libcli/security/security.h"
+#include "rpc_client/util_netlogon.h"
+#include "nsswitch/libwbclient/wbclient.h"
+#include "passdb.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_AUTH
@@ -39,7 +45,7 @@ struct auth_serversupplied_info *make_server_info(TALLOC_CTX *mem_ctx)
 {
        struct auth_serversupplied_info *result;
 
-       result = TALLOC_ZERO_P(mem_ctx, struct auth_serversupplied_info);
+       result = talloc_zero(mem_ctx, struct auth_serversupplied_info);
        if (result == NULL) {
                DEBUG(0, ("talloc failed\n"));
                return NULL;
@@ -53,6 +59,7 @@ struct auth_serversupplied_info *make_server_info(TALLOC_CTX *mem_ctx)
 
        result->utok.uid = -1;
        result->utok.gid = -1;
+
        return result;
 }
 
@@ -73,11 +80,11 @@ NTSTATUS serverinfo_to_SamInfo2(struct auth_serversupplied_info *server_info,
                return NT_STATUS_NO_MEMORY;
        }
 
-       if (server_info->user_session_key.length) {
+       if (server_info->session_key.length) {
                memcpy(info3->base.key.key,
-                      server_info->user_session_key.data,
+                      server_info->session_key.data,
                       MIN(sizeof(info3->base.key.key),
-                          server_info->user_session_key.length));
+                          server_info->session_key.length));
                if (pipe_session_key) {
                        arcfour_crypt(info3->base.key.key,
                                      pipe_session_key, 16);
@@ -104,7 +111,7 @@ NTSTATUS serverinfo_to_SamInfo2(struct auth_serversupplied_info *server_info,
  already be initialized and is used as the talloc parent for its members.
 *****************************************************************************/
 
-NTSTATUS serverinfo_to_SamInfo3(struct auth_serversupplied_info *server_info,
+NTSTATUS serverinfo_to_SamInfo3(const struct auth_serversupplied_info *server_info,
                                uint8_t *pipe_session_key,
                                size_t pipe_session_key_len,
                                struct netr_SamInfo3 *sam3)
@@ -116,11 +123,11 @@ NTSTATUS serverinfo_to_SamInfo3(struct auth_serversupplied_info *server_info,
                return NT_STATUS_NO_MEMORY;
        }
 
-       if (server_info->user_session_key.length) {
+       if (server_info->session_key.length) {
                memcpy(info3->base.key.key,
-                      server_info->user_session_key.data,
+                      server_info->session_key.data,
                       MIN(sizeof(info3->base.key.key),
-                          server_info->user_session_key.length));
+                          server_info->session_key.length));
                if (pipe_session_key) {
                        arcfour_crypt(info3->base.key.key,
                                      pipe_session_key, 16);
@@ -174,11 +181,11 @@ NTSTATUS serverinfo_to_SamInfo6(struct auth_serversupplied_info *server_info,
                return NT_STATUS_NO_MEMORY;
        }
 
-       if (server_info->user_session_key.length) {
+       if (server_info->session_key.length) {
                memcpy(info3->base.key.key,
-                      server_info->user_session_key.data,
+                      server_info->session_key.data,
                       MIN(sizeof(info3->base.key.key),
-                          server_info->user_session_key.length));
+                          server_info->session_key.length));
                if (pipe_session_key) {
                        arcfour_crypt(info3->base.key.key,
                                      pipe_session_key, 16);
@@ -215,37 +222,81 @@ NTSTATUS serverinfo_to_SamInfo6(struct auth_serversupplied_info *server_info,
        return NT_STATUS_OK;
 }
 
-static NTSTATUS sids_to_samr_RidWithAttributeArray(
-                               TALLOC_CTX *mem_ctx,
-                               struct samr_RidWithAttributeArray *groups,
-                               const struct dom_sid *domain_sid,
-                               const struct dom_sid *sids,
-                               size_t num_sids)
+static NTSTATUS append_netr_SidAttr(TALLOC_CTX *mem_ctx,
+                                   struct netr_SidAttr **sids,
+                                   uint32_t *count,
+                                   const struct dom_sid2 *asid,
+                                   uint32_t attributes)
+{
+       uint32_t t = *count;
+
+       *sids = talloc_realloc(mem_ctx, *sids, struct netr_SidAttr, t + 1);
+       if (*sids == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       (*sids)[t].sid = dom_sid_dup(*sids, asid);
+       if ((*sids)[t].sid == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       (*sids)[t].attributes = attributes;
+       *count = t + 1;
+
+       return NT_STATUS_OK;
+}
+
+/* Fills the samr_RidWithAttributeArray with the provided sids.
+ * If it happens that we have additional groups that do not belong
+ * to the domain, add their sids as extra sids */
+static NTSTATUS group_sids_to_info3(struct netr_SamInfo3 *info3,
+                                   const struct dom_sid *sids,
+                                   size_t num_sids)
 {
+       uint32_t attributes = SE_GROUP_MANDATORY |
+                               SE_GROUP_ENABLED_BY_DEFAULT |
+                               SE_GROUP_ENABLED;
+       struct samr_RidWithAttributeArray *groups;
+       struct dom_sid *domain_sid;
        unsigned int i;
+       NTSTATUS status;
+       uint32_t rid;
        bool ok;
 
-       groups->rids = talloc_array(mem_ctx,
+       domain_sid = info3->base.domain_sid;
+       groups = &info3->base.groups;
+
+       groups->rids = talloc_array(info3,
                                    struct samr_RidWithAttribute, num_sids);
        if (!groups->rids) {
                return NT_STATUS_NO_MEMORY;
        }
 
        for (i = 0; i < num_sids; i++) {
-               ok = sid_peek_check_rid(domain_sid, &sids[i],
-                                       &groups->rids[i].rid);
-               if (!ok) continue;
+               ok = sid_peek_check_rid(domain_sid, &sids[i], &rid);
+               if (ok) {
+
+                       /* if it is the primary gid, skip it, we
+                        * obviously already have it */
+                       if (info3->base.primary_gid == rid) continue;
+
+                       /* store domain group rid */
+                       groups->rids[i].rid = rid;
+                       groups->rids[i].attributes = attributes;
+                       groups->count++;
+                       continue;
+               }
 
-               groups->rids[i].attributes = SE_GROUP_MANDATORY |
-                                            SE_GROUP_ENABLED_BY_DEFAULT |
-                                            SE_GROUP_ENABLED;
-               groups->count++;
+               /* if this wasn't a domain sid, add it as extra sid */
+               status = append_netr_SidAttr(info3, &info3->sids,
+                                            &info3->sidcount,
+                                            &sids[i], attributes);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
        }
 
        return NT_STATUS_OK;
 }
 
-
 #define RET_NOMEM(ptr) do { \
        if (!ptr) { \
                TALLOC_FREE(info3); \
@@ -255,14 +306,15 @@ static NTSTATUS sids_to_samr_RidWithAttributeArray(
 NTSTATUS samu_to_SamInfo3(TALLOC_CTX *mem_ctx,
                          struct samu *samu,
                          const char *login_server,
-                         struct netr_SamInfo3 **_info3)
+                         struct netr_SamInfo3 **_info3,
+                         struct extra_auth_info *extra)
 {
        struct netr_SamInfo3 *info3;
        const struct dom_sid *user_sid;
        const struct dom_sid *group_sid;
        struct dom_sid domain_sid;
        struct dom_sid *group_sids;
-       size_t num_group_sids;
+       uint32_t num_group_sids = 0;
        const char *tmp;
        gid_t *gids;
        NTSTATUS status;
@@ -281,6 +333,67 @@ NTSTATUS samu_to_SamInfo3(TALLOC_CTX *mem_ctx,
                return NT_STATUS_NO_MEMORY;
        }
 
+       ZERO_STRUCT(domain_sid);
+
+       /* check if this is a "Unix Users" domain user,
+        * we need to handle it in a special way if that's the case */
+       if (sid_check_is_in_unix_users(user_sid)) {
+               /* in info3 you can only set rids for the user and the
+                * primary group, and the domain sid must be that of
+                * the sam domain.
+                *
+                * Store a completely bogus value here.
+                * The real SID is stored in the extra sids.
+                * Other code will know to look there if (-1) is found
+                */
+               info3->base.rid = (uint32_t)(-1);
+               sid_copy(&extra->user_sid, user_sid);
+
+               DEBUG(10, ("Unix User found in struct samu. Rid marked as "
+                          "special and sid (%s) saved as extra sid\n",
+                          sid_string_dbg(user_sid)));
+       } else {
+               sid_copy(&domain_sid, user_sid);
+               sid_split_rid(&domain_sid, &info3->base.rid);
+       }
+
+       if (is_null_sid(&domain_sid)) {
+               sid_copy(&domain_sid, get_global_sam_sid());
+       }
+
+       /* check if this is a "Unix Groups" domain group,
+        * if so we need special handling */
+       if (sid_check_is_in_unix_groups(group_sid)) {
+               /* in info3 you can only set rids for the user and the
+                * primary group, and the domain sid must be that of
+                * the sam domain.
+                *
+                * Store a completely bogus value here.
+                * The real SID is stored in the extra sids.
+                * Other code will know to look there if (-1) is found
+                */
+               info3->base.primary_gid = (uint32_t)(-1);
+               sid_copy(&extra->pgid_sid, group_sid);
+
+               DEBUG(10, ("Unix Group found in struct samu. Rid marked as "
+                          "special and sid (%s) saved as extra sid\n",
+                          sid_string_dbg(group_sid)));
+
+       } else {
+               ok = sid_peek_check_rid(&domain_sid, group_sid,
+                                       &info3->base.primary_gid);
+               if (!ok) {
+                       DEBUG(1, ("The primary group domain sid(%s) does not "
+                                 "match the domain sid(%s) for %s(%s)\n",
+                                 sid_string_dbg(group_sid),
+                                 sid_string_dbg(&domain_sid),
+                                 pdb_get_username(samu),
+                                 sid_string_dbg(user_sid)));
+                       TALLOC_FREE(info3);
+                       return NT_STATUS_UNSUCCESSFUL;
+               }
+       }
+
        unix_to_nt_time(&info3->base.last_logon, pdb_get_logon_time(samu));
        unix_to_nt_time(&info3->base.last_logoff, get_time_t_max());
        unix_to_nt_time(&info3->base.acct_expiry, get_time_t_max());
@@ -306,14 +419,17 @@ NTSTATUS samu_to_SamInfo3(TALLOC_CTX *mem_ctx,
                info3->base.logon_script.string = talloc_strdup(info3, tmp);
                RET_NOMEM(info3->base.logon_script.string);
        }
+       tmp = pdb_get_profile_path(samu);
        if (tmp) {
                info3->base.profile_path.string = talloc_strdup(info3, tmp);
                RET_NOMEM(info3->base.profile_path.string);
        }
+       tmp = pdb_get_homedir(samu);
        if (tmp) {
                info3->base.home_directory.string = talloc_strdup(info3, tmp);
                RET_NOMEM(info3->base.home_directory.string);
        }
+       tmp = pdb_get_dir_drive(samu);
        if (tmp) {
                info3->base.home_drive.string = talloc_strdup(info3, tmp);
                RET_NOMEM(info3->base.home_drive.string);
@@ -322,19 +438,6 @@ NTSTATUS samu_to_SamInfo3(TALLOC_CTX *mem_ctx,
        info3->base.logon_count = pdb_get_logon_count(samu);
        info3->base.bad_password_count = pdb_get_bad_password_count(samu);
 
-       sid_copy(&domain_sid, user_sid);
-       sid_split_rid(&domain_sid, &info3->base.rid);
-
-       ok = sid_peek_check_rid(&domain_sid, group_sid,
-                               &info3->base.primary_gid);
-       if (!ok) {
-               DEBUG(1, ("The primary group sid domain does not"
-                         "match user sid domain for user: %s\n",
-                         pdb_get_username(samu)));
-               TALLOC_FREE(info3);
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-
        status = pdb_enum_group_memberships(mem_ctx, samu,
                                            &group_sids, &gids,
                                            &num_group_sids);
@@ -344,14 +447,12 @@ NTSTATUS samu_to_SamInfo3(TALLOC_CTX *mem_ctx,
                return status;
        }
 
-       status = sids_to_samr_RidWithAttributeArray(info3,
-                                                   &info3->base.groups,
-                                                   &domain_sid,
-                                                   group_sids,
-                                                   num_group_sids);
-       if (!NT_STATUS_IS_OK(status)) {
-               TALLOC_FREE(info3);
-               return status;
+       if (num_group_sids) {
+               status = group_sids_to_info3(info3, group_sids, num_group_sids);
+               if (!NT_STATUS_IS_OK(status)) {
+                       TALLOC_FREE(info3);
+                       return status;
+               }
        }
 
        /* We don't need sids and gids after the conversion */
@@ -371,7 +472,7 @@ NTSTATUS samu_to_SamInfo3(TALLOC_CTX *mem_ctx,
                                                  pdb_get_domain(samu));
        RET_NOMEM(info3->base.domain.string);
 
-       info3->base.domain_sid = sid_dup_talloc(info3, &domain_sid);
+       info3->base.domain_sid = dom_sid_dup(info3, &domain_sid);
        RET_NOMEM(info3->base.domain_sid);
 
        info3->base.acct_flags = pdb_get_acct_ctrl(samu);
@@ -392,52 +493,31 @@ struct netr_SamInfo3 *copy_netr_SamInfo3(TALLOC_CTX *mem_ctx,
                                         struct netr_SamInfo3 *orig)
 {
        struct netr_SamInfo3 *info3;
+       unsigned int i;
+       NTSTATUS status;
 
-       info3 = talloc(mem_ctx, struct netr_SamInfo3);
+       info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
        if (!info3) return NULL;
 
-       /* first copy all, then realloc pointers */
-       info3->base = orig->base;
-
-       info3->base.account_name.string =
-               talloc_strdup(info3, orig->base.account_name.string);
-       RET_NOMEM(info3->base.account_name.string);
-       info3->base.full_name.string =
-               talloc_strdup(info3, orig->base.full_name.string);
-       RET_NOMEM(info3->base.full_name.string);
-       info3->base.logon_script.string =
-               talloc_strdup(info3, orig->base.logon_script.string);
-       RET_NOMEM(info3->base.logon_script.string);
-       info3->base.profile_path.string =
-               talloc_strdup(info3, orig->base.profile_path.string);
-       RET_NOMEM(info3->base.profile_path.string);
-       info3->base.home_directory.string =
-               talloc_strdup(info3, orig->base.home_directory.string);
-       RET_NOMEM(info3->base.home_directory.string);
-       info3->base.home_drive.string =
-               talloc_strdup(info3, orig->base.home_drive.string);
-       RET_NOMEM(info3->base.home_drive.string);
-
-       info3->base.groups.rids =
-               talloc_memdup(info3, orig->base.groups.rids,
-                       (sizeof(struct samr_RidWithAttribute) *
-                               orig->base.groups.count));
-       RET_NOMEM(info3->base.groups.rids);
-
-       info3->base.logon_server.string =
-               talloc_strdup(info3, orig->base.logon_server.string);
-       RET_NOMEM(info3->base.logon_server.string);
-       info3->base.domain.string =
-               talloc_strdup(info3, orig->base.domain.string);
-       RET_NOMEM(info3->base.domain.string);
-
-       info3->base.domain_sid = sid_dup_talloc(info3, orig->base.domain_sid);
-       RET_NOMEM(info3->base.domain_sid);
+       status = copy_netr_SamBaseInfo(info3, &orig->base, &info3->base);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(info3);
+               return NULL;
+       }
 
-       info3->sids = talloc_memdup(info3, orig->sids,
-                                   (sizeof(struct netr_SidAttr) *
-                                                       orig->sidcount));
-       RET_NOMEM(info3->sids);
+       if (orig->sidcount) {
+               info3->sidcount = orig->sidcount;
+               info3->sids = talloc_array(info3, struct netr_SidAttr,
+                                          orig->sidcount);
+               RET_NOMEM(info3->sids);
+               for (i = 0; i < orig->sidcount; i++) {
+                       info3->sids[i].sid = dom_sid_dup(info3->sids,
+                                                           orig->sids[i].sid);
+                       RET_NOMEM(info3->sids[i].sid);
+                       info3->sids[i].attributes =
+                               orig->sids[i].attributes;
+               }
+       }
 
        return info3;
 }
@@ -493,9 +573,11 @@ struct netr_SamInfo3 *wbcAuthUserInfo_to_netr_SamInfo3(TALLOC_CTX *mem_ctx,
        info3->base.last_logon = info->logon_time;
        info3->base.last_logoff = info->logoff_time;
        info3->base.acct_expiry = info->kickoff_time;
-       info3->base.last_password_change = info->pass_last_set_time;
-       info3->base.allow_password_change = info->pass_can_change_time;
-       info3->base.force_password_change = info->pass_must_change_time;
+       unix_to_nt_time(&info3->base.last_password_change, info->pass_last_set_time);
+       unix_to_nt_time(&info3->base.allow_password_change,
+                       info->pass_can_change_time);
+       unix_to_nt_time(&info3->base.force_password_change,
+                       info->pass_must_change_time);
 
        if (info->account_name) {
                info3->base.account_name.string =
@@ -568,7 +650,7 @@ struct netr_SamInfo3 *wbcAuthUserInfo_to_netr_SamInfo3(TALLOC_CTX *mem_ctx,
                RET_NOMEM(info3->base.domain.string);
        }
 
-       info3->base.domain_sid = sid_dup_talloc(info3, &domain_sid);
+       info3->base.domain_sid = dom_sid_dup(info3, &domain_sid);
        RET_NOMEM(info3->base.domain_sid);
 
        memcpy(info3->base.LMSessKey.key, info->lm_session_key, 8);