690838d779c4a489fecc492139f03603aa096342
[kai/samba.git] / source3 / auth / server_info.c
1 /*
2    Unix SMB/CIFS implementation.
3    Authentication utility functions
4    Copyright (C) Volker Lendecke 2010
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "../lib/crypto/arcfour.h"
22 #include "../librpc/gen_ndr/netlogon.h"
23 #include "../libcli/security/dom_sid.h"
24
25 #undef DBGC_CLASS
26 #define DBGC_CLASS DBGC_AUTH
27
28 /* FIXME: do we really still need this ? */
29 static int server_info_dtor(struct auth_serversupplied_info *server_info)
30 {
31         TALLOC_FREE(server_info->info3);
32         ZERO_STRUCTP(server_info);
33         return 0;
34 }
35
36 /***************************************************************************
37  Make a server_info struct. Free with TALLOC_FREE().
38 ***************************************************************************/
39
40 struct auth_serversupplied_info *make_server_info(TALLOC_CTX *mem_ctx)
41 {
42         struct auth_serversupplied_info *result;
43
44         result = TALLOC_ZERO_P(mem_ctx, struct auth_serversupplied_info);
45         if (result == NULL) {
46                 DEBUG(0, ("talloc failed\n"));
47                 return NULL;
48         }
49
50         talloc_set_destructor(result, server_info_dtor);
51
52         /* Initialise the uid and gid values to something non-zero
53            which may save us from giving away root access if there
54            is a bug in allocating these fields. */
55
56         result->utok.uid = -1;
57         result->utok.gid = -1;
58
59         return result;
60 }
61
62 /****************************************************************************
63  inits a netr_SamInfo2 structure from an auth_serversupplied_info. sam2 must
64  already be initialized and is used as the talloc parent for its members.
65 *****************************************************************************/
66
67 NTSTATUS serverinfo_to_SamInfo2(struct auth_serversupplied_info *server_info,
68                                 uint8_t *pipe_session_key,
69                                 size_t pipe_session_key_len,
70                                 struct netr_SamInfo2 *sam2)
71 {
72         struct netr_SamInfo3 *info3;
73
74         info3 = copy_netr_SamInfo3(sam2, server_info->info3);
75         if (!info3) {
76                 return NT_STATUS_NO_MEMORY;
77         }
78
79         if (server_info->user_session_key.length) {
80                 memcpy(info3->base.key.key,
81                        server_info->user_session_key.data,
82                        MIN(sizeof(info3->base.key.key),
83                            server_info->user_session_key.length));
84                 if (pipe_session_key) {
85                         arcfour_crypt(info3->base.key.key,
86                                       pipe_session_key, 16);
87                 }
88         }
89         if (server_info->lm_session_key.length) {
90                 memcpy(info3->base.LMSessKey.key,
91                        server_info->lm_session_key.data,
92                        MIN(sizeof(info3->base.LMSessKey.key),
93                            server_info->lm_session_key.length));
94                 if (pipe_session_key) {
95                         arcfour_crypt(info3->base.LMSessKey.key,
96                                       pipe_session_key, 8);
97                 }
98         }
99
100         sam2->base = info3->base;
101
102         return NT_STATUS_OK;
103 }
104
105 /****************************************************************************
106  inits a netr_SamInfo3 structure from an auth_serversupplied_info. sam3 must
107  already be initialized and is used as the talloc parent for its members.
108 *****************************************************************************/
109
110 NTSTATUS serverinfo_to_SamInfo3(struct auth_serversupplied_info *server_info,
111                                 uint8_t *pipe_session_key,
112                                 size_t pipe_session_key_len,
113                                 struct netr_SamInfo3 *sam3)
114 {
115         struct netr_SamInfo3 *info3;
116
117         info3 = copy_netr_SamInfo3(sam3, server_info->info3);
118         if (!info3) {
119                 return NT_STATUS_NO_MEMORY;
120         }
121
122         if (server_info->user_session_key.length) {
123                 memcpy(info3->base.key.key,
124                        server_info->user_session_key.data,
125                        MIN(sizeof(info3->base.key.key),
126                            server_info->user_session_key.length));
127                 if (pipe_session_key) {
128                         arcfour_crypt(info3->base.key.key,
129                                       pipe_session_key, 16);
130                 }
131         }
132         if (server_info->lm_session_key.length) {
133                 memcpy(info3->base.LMSessKey.key,
134                        server_info->lm_session_key.data,
135                        MIN(sizeof(info3->base.LMSessKey.key),
136                            server_info->lm_session_key.length));
137                 if (pipe_session_key) {
138                         arcfour_crypt(info3->base.LMSessKey.key,
139                                       pipe_session_key, 8);
140                 }
141         }
142
143         sam3->base = info3->base;
144
145         sam3->sidcount          = 0;
146         sam3->sids              = NULL;
147
148         return NT_STATUS_OK;
149 }
150
151 /****************************************************************************
152  inits a netr_SamInfo6 structure from an auth_serversupplied_info. sam6 must
153  already be initialized and is used as the talloc parent for its members.
154 *****************************************************************************/
155
156 NTSTATUS serverinfo_to_SamInfo6(struct auth_serversupplied_info *server_info,
157                                 uint8_t *pipe_session_key,
158                                 size_t pipe_session_key_len,
159                                 struct netr_SamInfo6 *sam6)
160 {
161         struct pdb_domain_info *dominfo;
162         struct netr_SamInfo3 *info3;
163
164         if ((pdb_capabilities() & PDB_CAP_ADS) == 0) {
165                 DEBUG(10,("Not adding validation info level 6 "
166                            "without ADS passdb backend\n"));
167                 return NT_STATUS_INVALID_INFO_CLASS;
168         }
169
170         dominfo = pdb_get_domain_info(sam6);
171         if (dominfo == NULL) {
172                 return NT_STATUS_NO_MEMORY;
173         }
174
175         info3 = copy_netr_SamInfo3(sam6, server_info->info3);
176         if (!info3) {
177                 return NT_STATUS_NO_MEMORY;
178         }
179
180         if (server_info->user_session_key.length) {
181                 memcpy(info3->base.key.key,
182                        server_info->user_session_key.data,
183                        MIN(sizeof(info3->base.key.key),
184                            server_info->user_session_key.length));
185                 if (pipe_session_key) {
186                         arcfour_crypt(info3->base.key.key,
187                                       pipe_session_key, 16);
188                 }
189         }
190         if (server_info->lm_session_key.length) {
191                 memcpy(info3->base.LMSessKey.key,
192                        server_info->lm_session_key.data,
193                        MIN(sizeof(info3->base.LMSessKey.key),
194                            server_info->lm_session_key.length));
195                 if (pipe_session_key) {
196                         arcfour_crypt(info3->base.LMSessKey.key,
197                                       pipe_session_key, 8);
198                 }
199         }
200
201         sam6->base = info3->base;
202
203         sam6->sidcount          = 0;
204         sam6->sids              = NULL;
205
206         sam6->dns_domainname.string = talloc_strdup(sam6, dominfo->dns_domain);
207         if (sam6->dns_domainname.string == NULL) {
208                 return NT_STATUS_NO_MEMORY;
209         }
210
211         sam6->principle.string  = talloc_asprintf(sam6, "%s@%s",
212                                                   sam6->base.account_name.string,
213                                                   sam6->dns_domainname.string);
214         if (sam6->principle.string == NULL) {
215                 return NT_STATUS_NO_MEMORY;
216         }
217
218         return NT_STATUS_OK;
219 }
220
221 static NTSTATUS append_netr_SidAttr(TALLOC_CTX *mem_ctx,
222                                     struct netr_SidAttr **sids,
223                                     uint32_t *count,
224                                     const struct dom_sid2 *asid,
225                                     uint32_t attributes)
226 {
227         uint32_t t = *count;
228
229         *sids = talloc_realloc(mem_ctx, *sids, struct netr_SidAttr, t + 1);
230         if (*sids == NULL) {
231                 return NT_STATUS_NO_MEMORY;
232         }
233         (*sids)[t].sid = dom_sid_dup(*sids, asid);
234         if ((*sids)[t].sid == NULL) {
235                 return NT_STATUS_NO_MEMORY;
236         }
237         (*sids)[t].attributes = attributes;
238         *count = t + 1;
239
240         return NT_STATUS_OK;
241 }
242
243 /* Fils the samr_RidWithAttributeArray with the provided sids.
244  * If it happens that we have additional groups that do not belong
245  * to the domain, add their sids as extra sids */
246 static NTSTATUS group_sids_to_info3(struct netr_SamInfo3 *info3,
247                                     const struct dom_sid *sids,
248                                     size_t num_sids)
249 {
250         uint32_t attributes = SE_GROUP_MANDATORY |
251                                 SE_GROUP_ENABLED_BY_DEFAULT |
252                                 SE_GROUP_ENABLED;
253         struct samr_RidWithAttributeArray *groups;
254         struct dom_sid *domain_sid;
255         unsigned int i;
256         NTSTATUS status;
257         uint32_t rid;
258         bool ok;
259
260         domain_sid = info3->base.domain_sid;
261         groups = &info3->base.groups;
262
263         groups->rids = talloc_array(info3,
264                                     struct samr_RidWithAttribute, num_sids);
265         if (!groups->rids) {
266                 return NT_STATUS_NO_MEMORY;
267         }
268
269         for (i = 0; i < num_sids; i++) {
270                 ok = sid_peek_check_rid(domain_sid, &sids[i], &rid);
271                 if (ok) {
272
273                         /* if it is the primary gid, skip it, we
274                          * obviously already have it */
275                         if (info3->base.primary_gid == rid) continue;
276
277                         /* store domain group rid */
278                         groups->rids[i].rid = rid;
279                         groups->rids[i].attributes = attributes;
280                         groups->count++;
281                         continue;
282                 }
283
284                 /* if this wasn't a domain sid, add it as extra sid */
285                 status = append_netr_SidAttr(info3, &info3->sids,
286                                              &info3->sidcount,
287                                              &sids[i], attributes);
288                 if (!NT_STATUS_IS_OK(status)) {
289                         return status;
290                 }
291         }
292
293         return NT_STATUS_OK;
294 }
295
296 #define RET_NOMEM(ptr) do { \
297         if (!ptr) { \
298                 TALLOC_FREE(info3); \
299                 return NT_STATUS_NO_MEMORY; \
300         } } while(0)
301
302 NTSTATUS samu_to_SamInfo3(TALLOC_CTX *mem_ctx,
303                           struct samu *samu,
304                           const char *login_server,
305                           struct netr_SamInfo3 **_info3,
306                           struct extra_auth_info *extra)
307 {
308         struct netr_SamInfo3 *info3;
309         const struct dom_sid *user_sid;
310         const struct dom_sid *group_sid;
311         struct dom_sid domain_sid;
312         struct dom_sid *group_sids;
313         size_t num_group_sids = 0;
314         const char *tmp;
315         gid_t *gids;
316         NTSTATUS status;
317         bool ok;
318
319         user_sid = pdb_get_user_sid(samu);
320         group_sid = pdb_get_group_sid(samu);
321
322         if (!user_sid || !group_sid) {
323                 DEBUG(1, ("Sam account is missing sids!\n"));
324                 return NT_STATUS_UNSUCCESSFUL;
325         }
326
327         info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
328         if (!info3) {
329                 return NT_STATUS_NO_MEMORY;
330         }
331
332         ZERO_STRUCT(domain_sid);
333
334         /* check if this is a "Unix Users" domain user,
335          * we need to handle it in a special way if that's the case */
336         if (dom_sid_compare_domain(user_sid, &global_sid_Unix_Users) == 0) {
337                 /* in info3 you can only set rids for the user and the
338                  * primary group, and the domain sid must be that of
339                  * the sam domain.
340                  *
341                  * Store a completely bogus value here.
342                  * The real SID is stored in the extra sids.
343                  * Other code will know to look there if (-1) is found
344                  */
345                 info3->base.rid = (uint32_t)(-1);
346                 sid_copy(&extra->user_sid, user_sid);
347
348                 DEBUG(10, ("Unix User found in struct samu. Rid marked as "
349                            "special and sid (%s) saved as extra sid\n",
350                            sid_string_dbg(user_sid)));
351         } else {
352                 sid_copy(&domain_sid, user_sid);
353                 sid_split_rid(&domain_sid, &info3->base.rid);
354         }
355
356         if (is_null_sid(&domain_sid)) {
357                 sid_copy(&domain_sid, get_global_sam_sid());
358         }
359
360         /* check if this is a "Unix Groups" domain group,
361          * if so we need special handling */
362         if (dom_sid_compare_domain(group_sid, &global_sid_Unix_Groups) == 0) {
363                 /* in info3 you can only set rids for the user and the
364                  * primary group, and the domain sid must be that of
365                  * the sam domain.
366                  *
367                  * Store a completely bogus value here.
368                  * The real SID is stored in the extra sids.
369                  * Other code will know to look there if (-1) is found
370                  */
371                 info3->base.primary_gid = (uint32_t)(-1);
372                 sid_copy(&extra->pgid_sid, group_sid);
373
374                 DEBUG(10, ("Unix Group found in struct samu. Rid marked as "
375                            "special and sid (%s) saved as extra sid\n",
376                            sid_string_dbg(group_sid)));
377
378         } else {
379                 ok = sid_peek_check_rid(&domain_sid, group_sid,
380                                         &info3->base.primary_gid);
381                 if (!ok) {
382                         DEBUG(1, ("The primary group domain sid(%s) does not "
383                                   "match the domain sid(%s) for %s(%s)\n",
384                                   sid_string_dbg(group_sid),
385                                   sid_string_dbg(&domain_sid),
386                                   pdb_get_username(samu),
387                                   sid_string_dbg(user_sid)));
388                         TALLOC_FREE(info3);
389                         return NT_STATUS_UNSUCCESSFUL;
390                 }
391         }
392
393         unix_to_nt_time(&info3->base.last_logon, pdb_get_logon_time(samu));
394         unix_to_nt_time(&info3->base.last_logoff, get_time_t_max());
395         unix_to_nt_time(&info3->base.acct_expiry, get_time_t_max());
396         unix_to_nt_time(&info3->base.last_password_change,
397                         pdb_get_pass_last_set_time(samu));
398         unix_to_nt_time(&info3->base.allow_password_change,
399                         pdb_get_pass_can_change_time(samu));
400         unix_to_nt_time(&info3->base.force_password_change,
401                         pdb_get_pass_must_change_time(samu));
402
403         tmp = pdb_get_username(samu);
404         if (tmp) {
405                 info3->base.account_name.string = talloc_strdup(info3, tmp);
406                 RET_NOMEM(info3->base.account_name.string);
407         }
408         tmp = pdb_get_fullname(samu);
409         if (tmp) {
410                 info3->base.full_name.string = talloc_strdup(info3, tmp);
411                 RET_NOMEM(info3->base.full_name.string);
412         }
413         tmp = pdb_get_logon_script(samu);
414         if (tmp) {
415                 info3->base.logon_script.string = talloc_strdup(info3, tmp);
416                 RET_NOMEM(info3->base.logon_script.string);
417         }
418         tmp = pdb_get_profile_path(samu);
419         if (tmp) {
420                 info3->base.profile_path.string = talloc_strdup(info3, tmp);
421                 RET_NOMEM(info3->base.profile_path.string);
422         }
423         tmp = pdb_get_homedir(samu);
424         if (tmp) {
425                 info3->base.home_directory.string = talloc_strdup(info3, tmp);
426                 RET_NOMEM(info3->base.home_directory.string);
427         }
428         tmp = pdb_get_dir_drive(samu);
429         if (tmp) {
430                 info3->base.home_drive.string = talloc_strdup(info3, tmp);
431                 RET_NOMEM(info3->base.home_drive.string);
432         }
433
434         info3->base.logon_count = pdb_get_logon_count(samu);
435         info3->base.bad_password_count = pdb_get_bad_password_count(samu);
436
437         status = pdb_enum_group_memberships(mem_ctx, samu,
438                                             &group_sids, &gids,
439                                             &num_group_sids);
440         if (!NT_STATUS_IS_OK(status)) {
441                 DEBUG(1, ("Failed to get groups from sam account.\n"));
442                 TALLOC_FREE(info3);
443                 return status;
444         }
445
446         if (num_group_sids) {
447                 status = group_sids_to_info3(info3, group_sids, num_group_sids);
448                 if (!NT_STATUS_IS_OK(status)) {
449                         TALLOC_FREE(info3);
450                         return status;
451                 }
452         }
453
454         /* We don't need sids and gids after the conversion */
455         TALLOC_FREE(group_sids);
456         TALLOC_FREE(gids);
457         num_group_sids = 0;
458
459         /* FIXME: should we add other flags ? */
460         info3->base.user_flags = NETLOGON_EXTRA_SIDS;
461
462         if (login_server) {
463                 info3->base.logon_server.string = talloc_strdup(info3, login_server);
464                 RET_NOMEM(info3->base.logon_server.string);
465         }
466
467         info3->base.domain.string = talloc_strdup(info3,
468                                                   pdb_get_domain(samu));
469         RET_NOMEM(info3->base.domain.string);
470
471         info3->base.domain_sid = dom_sid_dup(info3, &domain_sid);
472         RET_NOMEM(info3->base.domain_sid);
473
474         info3->base.acct_flags = pdb_get_acct_ctrl(samu);
475
476         *_info3 = info3;
477         return NT_STATUS_OK;
478 }
479
480 #undef RET_NOMEM
481
482 #define RET_NOMEM(ptr) do { \
483         if (!ptr) { \
484                 TALLOC_FREE(info3); \
485                 return NULL; \
486         } } while(0)
487
488 struct netr_SamInfo3 *copy_netr_SamInfo3(TALLOC_CTX *mem_ctx,
489                                          struct netr_SamInfo3 *orig)
490 {
491         struct netr_SamInfo3 *info3;
492         unsigned int i;
493
494         info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
495         if (!info3) return NULL;
496
497         /* first copy all, then realloc pointers */
498         info3->base = orig->base;
499
500         if (orig->base.account_name.string) {
501                 info3->base.account_name.string =
502                         talloc_strdup(info3, orig->base.account_name.string);
503                 RET_NOMEM(info3->base.account_name.string);
504         }
505         if (orig->base.full_name.string) {
506                 info3->base.full_name.string =
507                         talloc_strdup(info3, orig->base.full_name.string);
508                 RET_NOMEM(info3->base.full_name.string);
509         }
510         if (orig->base.logon_script.string) {
511                 info3->base.logon_script.string =
512                         talloc_strdup(info3, orig->base.logon_script.string);
513                 RET_NOMEM(info3->base.logon_script.string);
514         }
515         if (orig->base.profile_path.string) {
516                 info3->base.profile_path.string =
517                         talloc_strdup(info3, orig->base.profile_path.string);
518                 RET_NOMEM(info3->base.profile_path.string);
519         }
520         if (orig->base.home_directory.string) {
521                 info3->base.home_directory.string =
522                         talloc_strdup(info3, orig->base.home_directory.string);
523                 RET_NOMEM(info3->base.home_directory.string);
524         }
525         if (orig->base.home_drive.string) {
526                 info3->base.home_drive.string =
527                         talloc_strdup(info3, orig->base.home_drive.string);
528                 RET_NOMEM(info3->base.home_drive.string);
529         }
530
531         if (orig->base.groups.count) {
532                 info3->base.groups.rids = (struct samr_RidWithAttribute *)
533                         talloc_memdup(info3, orig->base.groups.rids,
534                                 (sizeof(struct samr_RidWithAttribute) *
535                                         orig->base.groups.count));
536                 RET_NOMEM(info3->base.groups.rids);
537         }
538
539         if (orig->base.logon_server.string) {
540                 info3->base.logon_server.string =
541                         talloc_strdup(info3, orig->base.logon_server.string);
542                 RET_NOMEM(info3->base.logon_server.string);
543         }
544         if (orig->base.domain.string) {
545                 info3->base.domain.string =
546                         talloc_strdup(info3, orig->base.domain.string);
547                 RET_NOMEM(info3->base.domain.string);
548         }
549
550         if (orig->base.domain_sid) {
551                 info3->base.domain_sid = dom_sid_dup(info3, orig->base.domain_sid);
552                 RET_NOMEM(info3->base.domain_sid);
553         }
554
555         if (orig->sidcount) {
556                 info3->sidcount = orig->sidcount;
557                 info3->sids = talloc_array(info3, struct netr_SidAttr,
558                                            orig->sidcount);
559                 RET_NOMEM(info3->sids);
560                 for (i = 0; i < orig->sidcount; i++) {
561                         info3->sids[i].sid = dom_sid_dup(info3->sids,
562                                                             orig->sids[i].sid);
563                         RET_NOMEM(info3->sids[i].sid);
564                         info3->sids[i].attributes =
565                                 orig->sids[i].attributes;
566                 }
567         }
568
569         return info3;
570 }
571
572 static NTSTATUS wbcsids_to_samr_RidWithAttributeArray(
573                                 TALLOC_CTX *mem_ctx,
574                                 struct samr_RidWithAttributeArray *groups,
575                                 const struct dom_sid *domain_sid,
576                                 const struct wbcSidWithAttr *sids,
577                                 size_t num_sids)
578 {
579         unsigned int i;
580         bool ok;
581
582         groups->rids = talloc_array(mem_ctx,
583                                     struct samr_RidWithAttribute, num_sids);
584         if (!groups->rids) {
585                 return NT_STATUS_NO_MEMORY;
586         }
587
588         /* a wbcDomainSid is the same as a dom_sid */
589         for (i = 0; i < num_sids; i++) {
590                 ok = sid_peek_check_rid(domain_sid,
591                                         (const struct dom_sid *)&sids[i].sid,
592                                         &groups->rids[i].rid);
593                 if (!ok) continue;
594
595                 groups->rids[i].attributes = SE_GROUP_MANDATORY |
596                                              SE_GROUP_ENABLED_BY_DEFAULT |
597                                              SE_GROUP_ENABLED;
598                 groups->count++;
599         }
600
601         return NT_STATUS_OK;
602 }
603
604 struct netr_SamInfo3 *wbcAuthUserInfo_to_netr_SamInfo3(TALLOC_CTX *mem_ctx,
605                                         const struct wbcAuthUserInfo *info)
606 {
607         struct netr_SamInfo3 *info3;
608         struct dom_sid user_sid;
609         struct dom_sid group_sid;
610         struct dom_sid domain_sid;
611         NTSTATUS status;
612         bool ok;
613
614         memcpy(&user_sid, &info->sids[0].sid, sizeof(user_sid));
615         memcpy(&group_sid, &info->sids[1].sid, sizeof(group_sid));
616
617         info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
618         if (!info3) return NULL;
619
620         info3->base.last_logon = info->logon_time;
621         info3->base.last_logoff = info->logoff_time;
622         info3->base.acct_expiry = info->kickoff_time;
623         info3->base.last_password_change = info->pass_last_set_time;
624         info3->base.allow_password_change = info->pass_can_change_time;
625         info3->base.force_password_change = info->pass_must_change_time;
626
627         if (info->account_name) {
628                 info3->base.account_name.string =
629                                 talloc_strdup(info3, info->account_name);
630                 RET_NOMEM(info3->base.account_name.string);
631         }
632         if (info->full_name) {
633                 info3->base.full_name.string =
634                                 talloc_strdup(info3, info->full_name);
635                 RET_NOMEM(info3->base.full_name.string);
636         }
637         if (info->logon_script) {
638                 info3->base.logon_script.string =
639                                 talloc_strdup(info3, info->logon_script);
640                 RET_NOMEM(info3->base.logon_script.string);
641         }
642         if (info->profile_path) {
643                 info3->base.profile_path.string =
644                                 talloc_strdup(info3, info->profile_path);
645                 RET_NOMEM(info3->base.profile_path.string);
646         }
647         if (info->home_directory) {
648                 info3->base.home_directory.string =
649                                 talloc_strdup(info3, info->home_directory);
650                 RET_NOMEM(info3->base.home_directory.string);
651         }
652         if (info->home_drive) {
653                 info3->base.home_drive.string =
654                                 talloc_strdup(info3, info->home_drive);
655                 RET_NOMEM(info3->base.home_drive.string);
656         }
657
658         info3->base.logon_count = info->logon_count;
659         info3->base.bad_password_count = info->bad_password_count;
660
661         sid_copy(&domain_sid, &user_sid);
662         sid_split_rid(&domain_sid, &info3->base.rid);
663
664         ok = sid_peek_check_rid(&domain_sid, &group_sid,
665                                 &info3->base.primary_gid);
666         if (!ok) {
667                 DEBUG(1, ("The primary group sid domain does not"
668                           "match user sid domain for user: %s\n",
669                           info->account_name));
670                 TALLOC_FREE(info3);
671                 return NULL;
672         }
673
674         status = wbcsids_to_samr_RidWithAttributeArray(info3,
675                                                        &info3->base.groups,
676                                                        &domain_sid,
677                                                        &info->sids[1],
678                                                        info->num_sids - 1);
679         if (!NT_STATUS_IS_OK(status)) {
680                 TALLOC_FREE(info3);
681                 return NULL;
682         }
683
684         info3->base.user_flags = info->user_flags;
685         memcpy(info3->base.key.key, info->user_session_key, 16);
686
687         if (info->logon_server) {
688                 info3->base.logon_server.string =
689                                 talloc_strdup(info3, info->logon_server);
690                 RET_NOMEM(info3->base.logon_server.string);
691         }
692         if (info->domain_name) {
693                 info3->base.domain.string =
694                                 talloc_strdup(info3, info->domain_name);
695                 RET_NOMEM(info3->base.domain.string);
696         }
697
698         info3->base.domain_sid = dom_sid_dup(info3, &domain_sid);
699         RET_NOMEM(info3->base.domain_sid);
700
701         memcpy(info3->base.LMSessKey.key, info->lm_session_key, 8);
702         info3->base.acct_flags = info->acct_flags;
703
704         return info3;
705 }