Add my copyright.
[samba.git] / source3 / utils / net_rpc_samsync.c
1 /*
2    Unix SMB/CIFS implementation.
3    dump the remote SAM using rpc samsync operations
4
5    Copyright (C) Andrew Tridgell 2002
6    Copyright (C) Tim Potter 2001,2002
7    Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2005
8    Modified by Volker Lendecke 2002
9    Copyright (C) Jeremy Allison 2005.
10    Copyright (C) Guenther Deschner 2008.
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3 of the License, or
15    (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "includes.h"
27 #include "utils/net.h"
28
29 /* uid's and gid's for writing deltas to ldif */
30 static uint32 ldif_gid = 999;
31 static uint32 ldif_uid = 999;
32 /* Keep track of ldap initialization */
33 static int init_ldap = 1;
34
35 static void display_group_mem_info(uint32_t rid,
36                                    struct netr_DELTA_GROUP_MEMBER *r)
37 {
38         int i;
39         d_printf("Group mem %u: ", rid);
40         for (i=0; i< r->num_rids; i++) {
41                 d_printf("%u ", r->rids[i]);
42         }
43         d_printf("\n");
44 }
45
46 static void display_alias_info(uint32_t rid,
47                                struct netr_DELTA_ALIAS *r)
48 {
49         d_printf("Alias '%s' ", r->alias_name.string);
50         d_printf("desc='%s' rid=%u\n", r->description.string, r->rid);
51 }
52
53 static void display_alias_mem(uint32_t rid,
54                               struct netr_DELTA_ALIAS_MEMBER *r)
55 {
56         int i;
57         d_printf("Alias rid %u: ", rid);
58         for (i=0; i< r->sids.num_sids; i++) {
59                 d_printf("%s ", sid_string_tos(r->sids.sids[i].sid));
60         }
61         d_printf("\n");
62 }
63
64 static void display_account_info(uint32_t rid,
65                                  struct netr_DELTA_USER *r)
66 {
67         fstring hex_nt_passwd, hex_lm_passwd;
68         uchar lm_passwd[16], nt_passwd[16];
69         static uchar zero_buf[16];
70
71         /* Decode hashes from password hash (if they are not NULL) */
72
73         if (memcmp(r->lmpassword.hash, zero_buf, 16) != 0) {
74                 sam_pwd_hash(r->rid, r->lmpassword.hash, lm_passwd, 0);
75                 pdb_sethexpwd(hex_lm_passwd, lm_passwd, r->acct_flags);
76         } else {
77                 pdb_sethexpwd(hex_lm_passwd, NULL, 0);
78         }
79
80         if (memcmp(r->ntpassword.hash, zero_buf, 16) != 0) {
81                 sam_pwd_hash(r->rid, r->ntpassword.hash, nt_passwd, 0);
82                 pdb_sethexpwd(hex_nt_passwd, nt_passwd, r->acct_flags);
83         } else {
84                 pdb_sethexpwd(hex_nt_passwd, NULL, 0);
85         }
86
87         printf("%s:%d:%s:%s:%s:LCT-0\n",
88                 r->account_name.string,
89                 r->rid, hex_lm_passwd, hex_nt_passwd,
90                 pdb_encode_acct_ctrl(r->acct_flags, NEW_PW_FORMAT_SPACE_PADDED_LEN));
91 }
92
93 static time_t uint64s_nt_time_to_unix_abs(const uint64 *src)
94 {
95         NTTIME nttime;
96         nttime = *src;
97         return nt_time_to_unix_abs(&nttime);
98 }
99
100 static void display_domain_info(struct netr_DELTA_DOMAIN *r)
101 {
102         time_t u_logout;
103
104         u_logout = uint64s_nt_time_to_unix_abs((const uint64 *)&r->force_logoff_time);
105
106         d_printf("Domain name: %s\n", r->domain_name.string);
107
108         d_printf("Minimal Password Length: %d\n", r->min_password_length);
109         d_printf("Password History Length: %d\n", r->password_history_length);
110
111         d_printf("Force Logoff: %d\n", (int)u_logout);
112
113         d_printf("Max Password Age: %s\n", display_time(r->max_password_age));
114         d_printf("Min Password Age: %s\n", display_time(r->min_password_age));
115
116 #if 0
117         /* FIXME - gd */
118         d_printf("Lockout Time: %s\n", display_time(a->account_lockout.lockout_duration));
119         d_printf("Lockout Reset Time: %s\n", display_time(a->account_lockout.reset_count));
120         d_printf("Bad Attempt Lockout: %d\n", a->account_lockout.bad_attempt_lockout);
121 #endif
122         d_printf("User must logon to change password: %d\n", r->logon_to_chgpass);
123 }
124
125 static void display_group_info(uint32_t rid, struct netr_DELTA_GROUP *r)
126 {
127         d_printf("Group '%s' ", r->group_name.string);
128         d_printf("desc='%s', rid=%u\n", r->description.string, rid);
129 }
130
131 static void display_sam_entry(struct netr_DELTA_ENUM *r)
132 {
133         union netr_DELTA_UNION u = r->delta_union;
134         union netr_DELTA_ID_UNION id = r->delta_id_union;
135
136         switch (r->delta_type) {
137         case NETR_DELTA_DOMAIN:
138                 display_domain_info(u.domain);
139                 break;
140         case NETR_DELTA_GROUP:
141                 display_group_info(id.rid, u.group);
142                 break;
143 #if 0
144         case NETR_DELTA_DELETE_GROUP:
145                 printf("Delete Group: %d\n",
146                         u.delete_account.unknown);
147                 break;
148         case NETR_DELTA_RENAME_GROUP:
149                 printf("Rename Group: %s -> %s\n",
150                         u.rename_group->OldName.string,
151                         u.rename_group->NewName.string);
152                 break;
153 #endif
154         case NETR_DELTA_USER:
155                 display_account_info(id.rid, u.user);
156                 break;
157 #if 0
158         case NETR_DELTA_DELETE_USER:
159                 printf("Delete User: %d\n",
160                         id.rid);
161                 break;
162         case NETR_DELTA_RENAME_USER:
163                 printf("Rename user: %s -> %s\n",
164                         u.rename_user->OldName.string,
165                         u.rename_user->NewName.string);
166                 break;
167 #endif
168         case NETR_DELTA_GROUP_MEMBER:
169                 display_group_mem_info(id.rid, u.group_member);
170                 break;
171         case NETR_DELTA_ALIAS:
172                 display_alias_info(id.rid, u.alias);
173                 break;
174 #if 0
175         case NETR_DELTA_DELETE_ALIAS:
176                 printf("Delete Alias: %d\n",
177                         id.rid);
178                 break;
179         case NETR_DELTA_RENAME_ALIAS:
180                 printf("Rename alias: %s -> %s\n",
181                         u.rename_alias->OldName.string,
182                         u.rename_alias->NewName.string);
183                 break;
184 #endif
185         case NETR_DELTA_ALIAS_MEMBER:
186                 display_alias_mem(id.rid, u.alias_member);
187                 break;
188 #if 0
189         case NETR_DELTA_POLICY:
190                 printf("Policy\n");
191                 break;
192         case NETR_DELTA_TRUSTED_DOMAIN:
193                 printf("Trusted Domain: %s\n",
194                         u.trusted_domain->domain_name.string);
195                 break;
196         case NETR_DELTA_DELETE_TRUST:
197                 printf("Delete Trust: %d\n",
198                         u.delete_trust.unknown);
199                 break;
200         case NETR_DELTA_ACCOUNT:
201                 printf("Account\n");
202                 break;
203         case NETR_DELTA_DELETE_ACCOUNT:
204                 printf("Delete Account: %d\n",
205                         u.delete_account.unknown);
206                 break;
207         case NETR_DELTA_SECRET:
208                 printf("Secret\n");
209                 break;
210         case NETR_DELTA_DELETE_SECRET:
211                 printf("Delete Secret: %d\n",
212                         u.delete_secret.unknown);
213                 break;
214         case NETR_DELTA_DELETE_GROUP2:
215                 printf("Delete Group2: %s\n",
216                         u.delete_group->account_name);
217                 break;
218         case NETR_DELTA_DELETE_USER2:
219                 printf("Delete User2: %s\n",
220                         u.delete_user->account_name);
221                 break;
222         case NETR_DELTA_MODIFY_COUNT:
223                 printf("sam sequence update: 0x%016llx\n",
224                         (unsigned long long) *u.modified_count);
225                 break;
226 #endif
227         /* The following types are recognised but not handled */
228         case NETR_DELTA_RENAME_GROUP:
229                 d_printf("NETR_DELTA_RENAME_GROUP not handled\n");
230                 break;
231         case NETR_DELTA_RENAME_USER:
232                 d_printf("NETR_DELTA_RENAME_USER not handled\n");
233                 break;
234         case NETR_DELTA_RENAME_ALIAS:
235                 d_printf("NETR_DELTA_RENAME_ALIAS not handled\n");
236                 break;
237         case NETR_DELTA_POLICY:
238                 d_printf("NETR_DELTA_POLICY not handled\n");
239                 break;
240         case NETR_DELTA_TRUSTED_DOMAIN:
241                 d_printf("NETR_DELTA_TRUSTED_DOMAIN not handled\n");
242                 break;
243         case NETR_DELTA_ACCOUNT:
244                 d_printf("NETR_DELTA_ACCOUNT not handled\n");
245                 break;
246         case NETR_DELTA_SECRET:
247                 d_printf("NETR_DELTA_SECRET not handled\n");
248                 break;
249         case NETR_DELTA_DELETE_GROUP:
250                 d_printf("NETR_DELTA_DELETE_GROUP not handled\n");
251                 break;
252         case NETR_DELTA_DELETE_USER:
253                 d_printf("NETR_DELTA_DELETE_USER not handled\n");
254                 break;
255         case NETR_DELTA_MODIFY_COUNT:
256                 d_printf("NETR_DELTA_MODIFY_COUNT not handled\n");
257                 break;
258         case NETR_DELTA_DELETE_ALIAS:
259                 d_printf("NETR_DELTA_DELETE_ALIAS not handled\n");
260                 break;
261         case NETR_DELTA_DELETE_TRUST:
262                 d_printf("NETR_DELTA_DELETE_TRUST not handled\n");
263                 break;
264         case NETR_DELTA_DELETE_ACCOUNT:
265                 d_printf("NETR_DELTA_DELETE_ACCOUNT not handled\n");
266                 break;
267         case NETR_DELTA_DELETE_SECRET:
268                 d_printf("NETR_DELTA_DELETE_SECRET not handled\n");
269                 break;
270         case NETR_DELTA_DELETE_GROUP2:
271                 d_printf("NETR_DELTA_DELETE_GROUP2 not handled\n");
272                 break;
273         case NETR_DELTA_DELETE_USER2:
274                 d_printf("NETR_DELTA_DELETE_USER2 not handled\n");
275                 break;
276         default:
277                 printf("unknown delta type 0x%02x\n",
278                         r->delta_type);
279                 break;
280         }
281 }
282
283 static void dump_database(struct rpc_pipe_client *pipe_hnd, uint32 db_type)
284 {
285         NTSTATUS result;
286         int i;
287         TALLOC_CTX *mem_ctx;
288         const char *logon_server = pipe_hnd->cli->desthost;
289         const char *computername = global_myname();
290         struct netr_Authenticator credential;
291         struct netr_Authenticator return_authenticator;
292         enum netr_SamDatabaseID database_id = db_type;
293         uint16_t restart_state = 0;
294         uint32_t sync_context = 0;
295
296         if (!(mem_ctx = talloc_init("dump_database"))) {
297                 return;
298         }
299
300         switch( db_type ) {
301         case SAM_DATABASE_DOMAIN:
302                 d_printf("Dumping DOMAIN database\n");
303                 break;
304         case SAM_DATABASE_BUILTIN:
305                 d_printf("Dumping BUILTIN database\n");
306                 break;
307         case SAM_DATABASE_PRIVS:
308                 d_printf("Dumping PRIVS databases\n");
309                 break;
310         default:
311                 d_printf("Dumping unknown database type %u\n", db_type );
312                 break;
313         }
314
315         do {
316                 struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
317
318                 netlogon_creds_client_step(pipe_hnd->dc, &credential);
319
320                 result = rpccli_netr_DatabaseSync2(pipe_hnd, mem_ctx,
321                                                    logon_server,
322                                                    computername,
323                                                    &credential,
324                                                    &return_authenticator,
325                                                    database_id,
326                                                    restart_state,
327                                                    &sync_context,
328                                                    &delta_enum_array,
329                                                    0xffff);
330
331                 /* Check returned credentials. */
332                 if (!netlogon_creds_client_check(pipe_hnd->dc,
333                                                  &return_authenticator.cred)) {
334                         DEBUG(0,("credentials chain check failed\n"));
335                         return;
336                 }
337
338                 if (NT_STATUS_IS_ERR(result)) {
339                         break;
340                 }
341
342                 /* Display results */
343                 for (i = 0; i < delta_enum_array->num_deltas; i++) {
344                         display_sam_entry(&delta_enum_array->delta_enum[i]);
345                 }
346
347                 TALLOC_FREE(delta_enum_array);
348
349         } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
350
351         talloc_destroy(mem_ctx);
352 }
353
354 /* dump sam database via samsync rpc calls */
355 NTSTATUS rpc_samdump_internals(const DOM_SID *domain_sid,
356                                 const char *domain_name,
357                                 struct cli_state *cli,
358                                 struct rpc_pipe_client *pipe_hnd,
359                                 TALLOC_CTX *mem_ctx,
360                                 int argc,
361                                 const char **argv)
362 {
363 #if 0
364         /* net_rpc.c now always tries to create an schannel pipe.. */
365
366         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
367         uchar trust_password[16];
368         uint32 neg_flags = NETLOGON_NEG_SELECT_AUTH2_FLAGS;
369         uint32 sec_channel_type = 0;
370
371         if (!secrets_fetch_trust_account_password(domain_name,
372                                                   trust_password,
373                                                   NULL, &sec_channel_type)) {
374                 DEBUG(0,("Could not fetch trust account password\n"));
375                 goto fail;
376         }
377
378         nt_status = rpccli_netlogon_setup_creds(pipe_hnd,
379                                                 cli->desthost,
380                                                 domain_name,
381                                                 global_myname(),
382                                                 trust_password,
383                                                 sec_channel_type,
384                                                 &neg_flags);
385
386         if (!NT_STATUS_IS_OK(nt_status)) {
387                 DEBUG(0,("Error connecting to NETLOGON pipe\n"));
388                 goto fail;
389         }
390 #endif
391
392         dump_database(pipe_hnd, SAM_DATABASE_DOMAIN);
393         dump_database(pipe_hnd, SAM_DATABASE_BUILTIN);
394         dump_database(pipe_hnd, SAM_DATABASE_PRIVS);
395
396         return NT_STATUS_OK;
397 }
398
399 /* Convert a struct samu_DELTA to a struct samu. */
400 #define STRING_CHANGED (old_string && !new_string) ||\
401                     (!old_string && new_string) ||\
402                 (old_string && new_string && (strcmp(old_string, new_string) != 0))
403
404 #define STRING_CHANGED_NC(s1,s2) ((s1) && !(s2)) ||\
405                     (!(s1) && (s2)) ||\
406                 ((s1) && (s2) && (strcmp((s1), (s2)) != 0))
407
408 static NTSTATUS sam_account_from_delta(struct samu *account,
409                                        struct netr_DELTA_USER *r)
410 {
411         const char *old_string, *new_string;
412         time_t unix_time, stored_time;
413         uchar lm_passwd[16], nt_passwd[16];
414         static uchar zero_buf[16];
415
416         /* Username, fullname, home dir, dir drive, logon script, acct
417            desc, workstations, profile. */
418
419         if (r->account_name.string) {
420                 old_string = pdb_get_nt_username(account);
421                 new_string = r->account_name.string;
422
423                 if (STRING_CHANGED) {
424                         pdb_set_nt_username(account, new_string, PDB_CHANGED);
425                 }
426
427                 /* Unix username is the same - for sanity */
428                 old_string = pdb_get_username( account );
429                 if (STRING_CHANGED) {
430                         pdb_set_username(account, new_string, PDB_CHANGED);
431                 }
432         }
433
434         if (r->full_name.string) {
435                 old_string = pdb_get_fullname(account);
436                 new_string = r->full_name.string;
437
438                 if (STRING_CHANGED)
439                         pdb_set_fullname(account, new_string, PDB_CHANGED);
440         }
441
442         if (r->home_directory.string) {
443                 old_string = pdb_get_homedir(account);
444                 new_string = r->home_directory.string;
445
446                 if (STRING_CHANGED)
447                         pdb_set_homedir(account, new_string, PDB_CHANGED);
448         }
449
450         if (r->home_drive.string) {
451                 old_string = pdb_get_dir_drive(account);
452                 new_string = r->home_drive.string;
453
454                 if (STRING_CHANGED)
455                         pdb_set_dir_drive(account, new_string, PDB_CHANGED);
456         }
457
458         if (r->logon_script.string) {
459                 old_string = pdb_get_logon_script(account);
460                 new_string = r->logon_script.string;
461
462                 if (STRING_CHANGED)
463                         pdb_set_logon_script(account, new_string, PDB_CHANGED);
464         }
465
466         if (r->description.string) {
467                 old_string = pdb_get_acct_desc(account);
468                 new_string = r->description.string;
469
470                 if (STRING_CHANGED)
471                         pdb_set_acct_desc(account, new_string, PDB_CHANGED);
472         }
473
474         if (r->workstations.string) {
475                 old_string = pdb_get_workstations(account);
476                 new_string = r->workstations.string;
477
478                 if (STRING_CHANGED)
479                         pdb_set_workstations(account, new_string, PDB_CHANGED);
480         }
481
482         if (r->profile_path.string) {
483                 old_string = pdb_get_profile_path(account);
484                 new_string = r->profile_path.string;
485
486                 if (STRING_CHANGED)
487                         pdb_set_profile_path(account, new_string, PDB_CHANGED);
488         }
489
490         if (r->parameters.string) {
491                 DATA_BLOB mung;
492                 char *newstr;
493                 old_string = pdb_get_munged_dial(account);
494                 mung.length = r->parameters.length;
495                 mung.data = (uint8 *) r->parameters.string;
496                 newstr = (mung.length == 0) ? NULL :
497                         base64_encode_data_blob(talloc_tos(), mung);
498
499                 if (STRING_CHANGED_NC(old_string, newstr))
500                         pdb_set_munged_dial(account, newstr, PDB_CHANGED);
501                 TALLOC_FREE(newstr);
502         }
503
504         /* User and group sid */
505         if (pdb_get_user_rid(account) != r->rid)
506                 pdb_set_user_sid_from_rid(account, r->rid, PDB_CHANGED);
507         if (pdb_get_group_rid(account) != r->primary_gid)
508                 pdb_set_group_sid_from_rid(account, r->primary_gid, PDB_CHANGED);
509
510         /* Logon and password information */
511         if (!nt_time_is_zero(&r->last_logon)) {
512                 unix_time = nt_time_to_unix(r->last_logon);
513                 stored_time = pdb_get_logon_time(account);
514                 if (stored_time != unix_time)
515                         pdb_set_logon_time(account, unix_time, PDB_CHANGED);
516         }
517
518         if (!nt_time_is_zero(&r->last_logoff)) {
519                 unix_time = nt_time_to_unix(r->last_logoff);
520                 stored_time = pdb_get_logoff_time(account);
521                 if (stored_time != unix_time)
522                         pdb_set_logoff_time(account, unix_time,PDB_CHANGED);
523         }
524
525         /* Logon Divs */
526         if (pdb_get_logon_divs(account) != r->logon_hours.units_per_week)
527                 pdb_set_logon_divs(account, r->logon_hours.units_per_week, PDB_CHANGED);
528
529 #if 0
530         /* no idea what to do with this one - gd */
531         /* Max Logon Hours */
532         if (delta->unknown1 != pdb_get_unknown_6(account)) {
533                 pdb_set_unknown_6(account, delta->unknown1, PDB_CHANGED);
534         }
535 #endif
536         /* Logon Hours Len */
537         if (r->logon_hours.units_per_week/8 != pdb_get_hours_len(account)) {
538                 pdb_set_hours_len(account, r->logon_hours.units_per_week/8, PDB_CHANGED);
539         }
540
541         /* Logon Hours */
542         if (r->logon_hours.bits) {
543                 char oldstr[44], newstr[44];
544                 pdb_sethexhours(oldstr, pdb_get_hours(account));
545                 pdb_sethexhours(newstr, r->logon_hours.bits);
546                 if (!strequal(oldstr, newstr))
547                         pdb_set_hours(account, r->logon_hours.bits, PDB_CHANGED);
548         }
549
550         if (pdb_get_bad_password_count(account) != r->bad_password_count)
551                 pdb_set_bad_password_count(account, r->bad_password_count, PDB_CHANGED);
552
553         if (pdb_get_logon_count(account) != r->logon_count)
554                 pdb_set_logon_count(account, r->logon_count, PDB_CHANGED);
555
556         if (!nt_time_is_zero(&r->last_password_change)) {
557                 unix_time = nt_time_to_unix(r->last_password_change);
558                 stored_time = pdb_get_pass_last_set_time(account);
559                 if (stored_time != unix_time)
560                         pdb_set_pass_last_set_time(account, unix_time, PDB_CHANGED);
561         } else {
562                 /* no last set time, make it now */
563                 pdb_set_pass_last_set_time(account, time(NULL), PDB_CHANGED);
564         }
565
566         if (!nt_time_is_zero(&r->acct_expiry)) {
567                 unix_time = nt_time_to_unix(r->acct_expiry);
568                 stored_time = pdb_get_kickoff_time(account);
569                 if (stored_time != unix_time)
570                         pdb_set_kickoff_time(account, unix_time, PDB_CHANGED);
571         }
572
573         /* Decode hashes from password hash
574            Note that win2000 may send us all zeros for the hashes if it doesn't
575            think this channel is secure enough - don't set the passwords at all
576            in that case
577         */
578         if (memcmp(r->ntpassword.hash, zero_buf, 16) != 0) {
579                 sam_pwd_hash(r->rid, r->ntpassword.hash, lm_passwd, 0);
580                 pdb_set_lanman_passwd(account, lm_passwd, PDB_CHANGED);
581         }
582
583         if (memcmp(r->lmpassword.hash, zero_buf, 16) != 0) {
584                 sam_pwd_hash(r->rid, r->lmpassword.hash, nt_passwd, 0);
585                 pdb_set_nt_passwd(account, nt_passwd, PDB_CHANGED);
586         }
587
588         /* TODO: account expiry time */
589
590         pdb_set_acct_ctrl(account, r->acct_flags, PDB_CHANGED);
591
592         pdb_set_domain(account, lp_workgroup(), PDB_CHANGED);
593
594         return NT_STATUS_OK;
595 }
596
597 static NTSTATUS fetch_account_info(uint32_t rid,
598                                    struct netr_DELTA_USER *r)
599 {
600
601         NTSTATUS nt_ret = NT_STATUS_UNSUCCESSFUL;
602         fstring account;
603         char *add_script = NULL;
604         struct samu *sam_account=NULL;
605         GROUP_MAP map;
606         struct group *grp;
607         DOM_SID user_sid;
608         DOM_SID group_sid;
609         struct passwd *passwd;
610         fstring sid_string;
611
612         fstrcpy(account, r->account_name.string);
613         d_printf("Creating account: %s\n", account);
614
615         if ( !(sam_account = samu_new( NULL )) ) {
616                 return NT_STATUS_NO_MEMORY;
617         }
618
619         if (!(passwd = Get_Pwnam_alloc(sam_account, account))) {
620                 /* Create appropriate user */
621                 if (r->acct_flags & ACB_NORMAL) {
622                         add_script = talloc_strdup(sam_account,
623                                         lp_adduser_script());
624                 } else if ( (r->acct_flags & ACB_WSTRUST) ||
625                             (r->acct_flags & ACB_SVRTRUST) ||
626                             (r->acct_flags & ACB_DOMTRUST) ) {
627                         add_script = talloc_strdup(sam_account,
628                                         lp_addmachine_script());
629                 } else {
630                         DEBUG(1, ("Unknown user type: %s\n",
631                                   pdb_encode_acct_ctrl(r->acct_flags, NEW_PW_FORMAT_SPACE_PADDED_LEN)));
632                         nt_ret = NT_STATUS_UNSUCCESSFUL;
633                         goto done;
634                 }
635                 if (!add_script) {
636                         nt_ret = NT_STATUS_NO_MEMORY;
637                         goto done;
638                 }
639                 if (*add_script) {
640                         int add_ret;
641                         add_script = talloc_all_string_sub(sam_account,
642                                         add_script,
643                                         "%u",
644                                         account);
645                         if (!add_script) {
646                                 nt_ret = NT_STATUS_NO_MEMORY;
647                                 goto done;
648                         }
649                         add_ret = smbrun(add_script,NULL);
650                         DEBUG(add_ret ? 0 : 1,("fetch_account: Running the command `%s' "
651                                  "gave %d\n", add_script, add_ret));
652                         if (add_ret == 0) {
653                                 smb_nscd_flush_user_cache();
654                         }
655                 }
656
657                 /* try and find the possible unix account again */
658                 if ( !(passwd = Get_Pwnam_alloc(sam_account, account)) ) {
659                         d_fprintf(stderr, "Could not create posix account info for '%s'\n", account);
660                         nt_ret = NT_STATUS_NO_SUCH_USER;
661                         goto done;
662                 }
663         }
664
665         sid_copy(&user_sid, get_global_sam_sid());
666         sid_append_rid(&user_sid, r->rid);
667
668         DEBUG(3, ("Attempting to find SID %s for user %s in the passdb\n",
669                   sid_to_fstring(sid_string, &user_sid), account));
670         if (!pdb_getsampwsid(sam_account, &user_sid)) {
671                 sam_account_from_delta(sam_account, r);
672                 DEBUG(3, ("Attempting to add user SID %s for user %s in the passdb\n",
673                           sid_to_fstring(sid_string, &user_sid),
674                           pdb_get_username(sam_account)));
675                 if (!NT_STATUS_IS_OK(pdb_add_sam_account(sam_account))) {
676                         DEBUG(1, ("SAM Account for %s failed to be added to the passdb!\n",
677                                   account));
678                         return NT_STATUS_ACCESS_DENIED;
679                 }
680         } else {
681                 sam_account_from_delta(sam_account, r);
682                 DEBUG(3, ("Attempting to update user SID %s for user %s in the passdb\n",
683                           sid_to_fstring(sid_string, &user_sid),
684                           pdb_get_username(sam_account)));
685                 if (!NT_STATUS_IS_OK(pdb_update_sam_account(sam_account))) {
686                         DEBUG(1, ("SAM Account for %s failed to be updated in the passdb!\n",
687                                   account));
688                         TALLOC_FREE(sam_account);
689                         return NT_STATUS_ACCESS_DENIED;
690                 }
691         }
692
693         if (pdb_get_group_sid(sam_account) == NULL) {
694                 return NT_STATUS_UNSUCCESSFUL;
695         }
696
697         group_sid = *pdb_get_group_sid(sam_account);
698
699         if (!pdb_getgrsid(&map, group_sid)) {
700                 DEBUG(0, ("Primary group of %s has no mapping!\n",
701                           pdb_get_username(sam_account)));
702         } else {
703                 if (map.gid != passwd->pw_gid) {
704                         if (!(grp = getgrgid(map.gid))) {
705                                 DEBUG(0, ("Could not find unix group %lu for user %s (group SID=%s)\n",
706                                           (unsigned long)map.gid, pdb_get_username(sam_account), sid_string_tos(&group_sid)));
707                         } else {
708                                 smb_set_primary_group(grp->gr_name, pdb_get_username(sam_account));
709                         }
710                 }
711         }
712
713         if ( !passwd ) {
714                 DEBUG(1, ("No unix user for this account (%s), cannot adjust mappings\n",
715                         pdb_get_username(sam_account)));
716         }
717
718  done:
719         TALLOC_FREE(sam_account);
720         return nt_ret;
721 }
722
723 static NTSTATUS fetch_group_info(uint32_t rid,
724                                  struct netr_DELTA_GROUP *r)
725 {
726         fstring name;
727         fstring comment;
728         struct group *grp = NULL;
729         DOM_SID group_sid;
730         fstring sid_string;
731         GROUP_MAP map;
732         bool insert = True;
733
734         fstrcpy(name, r->group_name.string);
735         fstrcpy(comment, r->description.string);
736
737         /* add the group to the mapping table */
738         sid_copy(&group_sid, get_global_sam_sid());
739         sid_append_rid(&group_sid, rid);
740         sid_to_fstring(sid_string, &group_sid);
741
742         if (pdb_getgrsid(&map, group_sid)) {
743                 if ( map.gid != -1 )
744                         grp = getgrgid(map.gid);
745                 insert = False;
746         }
747
748         if (grp == NULL) {
749                 gid_t gid;
750
751                 /* No group found from mapping, find it from its name. */
752                 if ((grp = getgrnam(name)) == NULL) {
753
754                         /* No appropriate group found, create one */
755
756                         d_printf("Creating unix group: '%s'\n", name);
757
758                         if (smb_create_group(name, &gid) != 0)
759                                 return NT_STATUS_ACCESS_DENIED;
760
761                         if ((grp = getgrnam(name)) == NULL)
762                                 return NT_STATUS_ACCESS_DENIED;
763                 }
764         }
765
766         map.gid = grp->gr_gid;
767         map.sid = group_sid;
768         map.sid_name_use = SID_NAME_DOM_GRP;
769         fstrcpy(map.nt_name, name);
770         if (r->description.string) {
771                 fstrcpy(map.comment, comment);
772         } else {
773                 fstrcpy(map.comment, "");
774         }
775
776         if (insert)
777                 pdb_add_group_mapping_entry(&map);
778         else
779                 pdb_update_group_mapping_entry(&map);
780
781         return NT_STATUS_OK;
782 }
783
784 static NTSTATUS fetch_group_mem_info(uint32_t rid,
785                                      struct netr_DELTA_GROUP_MEMBER *r)
786 {
787         int i;
788         TALLOC_CTX *t = NULL;
789         char **nt_members = NULL;
790         char **unix_members;
791         DOM_SID group_sid;
792         GROUP_MAP map;
793         struct group *grp;
794
795         if (r->num_rids == 0) {
796                 return NT_STATUS_OK;
797         }
798
799         sid_copy(&group_sid, get_global_sam_sid());
800         sid_append_rid(&group_sid, rid);
801
802         if (!get_domain_group_from_sid(group_sid, &map)) {
803                 DEBUG(0, ("Could not find global group %d\n", rid));
804                 return NT_STATUS_NO_SUCH_GROUP;
805         }
806
807         if (!(grp = getgrgid(map.gid))) {
808                 DEBUG(0, ("Could not find unix group %lu\n", (unsigned long)map.gid));
809                 return NT_STATUS_NO_SUCH_GROUP;
810         }
811
812         d_printf("Group members of %s: ", grp->gr_name);
813
814         if (!(t = talloc_init("fetch_group_mem_info"))) {
815                 DEBUG(0, ("could not talloc_init\n"));
816                 return NT_STATUS_NO_MEMORY;
817         }
818
819         if (r->num_rids) {
820                 if ((nt_members = TALLOC_ZERO_ARRAY(t, char *, r->num_rids)) == NULL) {
821                         DEBUG(0, ("talloc failed\n"));
822                         talloc_free(t);
823                         return NT_STATUS_NO_MEMORY;
824                 }
825         } else {
826                 nt_members = NULL;
827         }
828
829         for (i=0; i < r->num_rids; i++) {
830                 struct samu *member = NULL;
831                 DOM_SID member_sid;
832
833                 if ( !(member = samu_new(t)) ) {
834                         talloc_destroy(t);
835                         return NT_STATUS_NO_MEMORY;
836                 }
837
838                 sid_copy(&member_sid, get_global_sam_sid());
839                 sid_append_rid(&member_sid, r->rids[i]);
840
841                 if (!pdb_getsampwsid(member, &member_sid)) {
842                         DEBUG(1, ("Found bogus group member: %d (member_sid=%s group=%s)\n",
843                                   r->rids[i], sid_string_tos(&member_sid), grp->gr_name));
844                         TALLOC_FREE(member);
845                         continue;
846                 }
847
848                 if (pdb_get_group_rid(member) == rid) {
849                         d_printf("%s(primary),", pdb_get_username(member));
850                         TALLOC_FREE(member);
851                         continue;
852                 }
853
854                 d_printf("%s,", pdb_get_username(member));
855                 nt_members[i] = talloc_strdup(t, pdb_get_username(member));
856                 TALLOC_FREE(member);
857         }
858
859         d_printf("\n");
860
861         unix_members = grp->gr_mem;
862
863         while (*unix_members) {
864                 bool is_nt_member = False;
865                 for (i=0; i < r->num_rids; i++) {
866                         if (nt_members[i] == NULL) {
867                                 /* This was a primary group */
868                                 continue;
869                         }
870
871                         if (strcmp(*unix_members, nt_members[i]) == 0) {
872                                 is_nt_member = True;
873                                 break;
874                         }
875                 }
876                 if (!is_nt_member) {
877                         /* We look at a unix group member that is not
878                            an nt group member. So, remove it. NT is
879                            boss here. */
880                         smb_delete_user_group(grp->gr_name, *unix_members);
881                 }
882                 unix_members += 1;
883         }
884
885         for (i=0; i < r->num_rids; i++) {
886                 bool is_unix_member = False;
887
888                 if (nt_members[i] == NULL) {
889                         /* This was the primary group */
890                         continue;
891                 }
892
893                 unix_members = grp->gr_mem;
894
895                 while (*unix_members) {
896                         if (strcmp(*unix_members, nt_members[i]) == 0) {
897                                 is_unix_member = True;
898                                 break;
899                         }
900                         unix_members += 1;
901                 }
902
903                 if (!is_unix_member) {
904                         /* We look at a nt group member that is not a
905                            unix group member currently. So, add the nt
906                            group member. */
907                         smb_add_user_group(grp->gr_name, nt_members[i]);
908                 }
909         }
910
911         talloc_destroy(t);
912         return NT_STATUS_OK;
913 }
914
915 static NTSTATUS fetch_alias_info(uint32_t rid,
916                                  struct netr_DELTA_ALIAS *r,
917                                  DOM_SID dom_sid)
918 {
919         fstring name;
920         fstring comment;
921         struct group *grp = NULL;
922         DOM_SID alias_sid;
923         fstring sid_string;
924         GROUP_MAP map;
925         bool insert = True;
926
927         fstrcpy(name, r->alias_name.string);
928         fstrcpy(comment, r->description.string);
929
930         /* Find out whether the group is already mapped */
931         sid_copy(&alias_sid, &dom_sid);
932         sid_append_rid(&alias_sid, rid);
933         sid_to_fstring(sid_string, &alias_sid);
934
935         if (pdb_getgrsid(&map, alias_sid)) {
936                 grp = getgrgid(map.gid);
937                 insert = False;
938         }
939
940         if (grp == NULL) {
941                 gid_t gid;
942
943                 /* No group found from mapping, find it from its name. */
944                 if ((grp = getgrnam(name)) == NULL) {
945                         /* No appropriate group found, create one */
946                         d_printf("Creating unix group: '%s'\n", name);
947                         if (smb_create_group(name, &gid) != 0)
948                                 return NT_STATUS_ACCESS_DENIED;
949                         if ((grp = getgrgid(gid)) == NULL)
950                                 return NT_STATUS_ACCESS_DENIED;
951                 }
952         }
953
954         map.gid = grp->gr_gid;
955         map.sid = alias_sid;
956
957         if (sid_equal(&dom_sid, &global_sid_Builtin))
958                 map.sid_name_use = SID_NAME_WKN_GRP;
959         else
960                 map.sid_name_use = SID_NAME_ALIAS;
961
962         fstrcpy(map.nt_name, name);
963         fstrcpy(map.comment, comment);
964
965         if (insert)
966                 pdb_add_group_mapping_entry(&map);
967         else
968                 pdb_update_group_mapping_entry(&map);
969
970         return NT_STATUS_OK;
971 }
972
973 static NTSTATUS fetch_alias_mem(uint32_t rid,
974                                 struct netr_DELTA_ALIAS_MEMBER *r,
975                                 DOM_SID dom_sid)
976 {
977         return NT_STATUS_OK;
978 }
979
980 static NTSTATUS fetch_domain_info(uint32_t rid,
981                                   struct netr_DELTA_DOMAIN *r)
982 {
983         time_t u_max_age, u_min_age, u_logout;
984 #if 0
985         /* FIXME: gd */
986         time_t u_lockoutreset, u_lockouttime;
987 #endif
988         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
989         const char *domname;
990
991         u_max_age = uint64s_nt_time_to_unix_abs((uint64 *)&r->max_password_age);
992         u_min_age = uint64s_nt_time_to_unix_abs((uint64 *)&r->min_password_age);
993         u_logout = uint64s_nt_time_to_unix_abs((uint64 *)&r->force_logoff_time);
994 #if 0
995         /* FIXME: gd */
996         u_lockoutreset = uint64s_nt_time_to_unix_abs(&delta->account_lockout.reset_count);
997         u_lockouttime = uint64s_nt_time_to_unix_abs(&delta->account_lockout.lockout_duration);
998 #endif
999         domname = r->domain_name.string;
1000         if (!domname) {
1001                 return NT_STATUS_NO_MEMORY;
1002         }
1003
1004         /* we don't handle BUILTIN account policies */
1005         if (!strequal(domname, get_global_sam_name())) {
1006                 printf("skipping SAM_DOMAIN_INFO delta for '%s' (is not my domain)\n", domname);
1007                 return NT_STATUS_OK;
1008         }
1009
1010
1011         if (!pdb_set_account_policy(AP_PASSWORD_HISTORY,
1012                                     r->password_history_length))
1013                 return nt_status;
1014
1015         if (!pdb_set_account_policy(AP_MIN_PASSWORD_LEN,
1016                                     r->min_password_length))
1017                 return nt_status;
1018
1019         if (!pdb_set_account_policy(AP_MAX_PASSWORD_AGE, (uint32)u_max_age))
1020                 return nt_status;
1021
1022         if (!pdb_set_account_policy(AP_MIN_PASSWORD_AGE, (uint32)u_min_age))
1023                 return nt_status;
1024
1025         if (!pdb_set_account_policy(AP_TIME_TO_LOGOUT, (uint32)u_logout))
1026                 return nt_status;
1027 #if 0
1028 /* FIXME: gd */
1029         if (!pdb_set_account_policy(AP_BAD_ATTEMPT_LOCKOUT, delta->account_lockout.bad_attempt_lockout))
1030                 return nt_status;
1031
1032         if (!pdb_set_account_policy(AP_RESET_COUNT_TIME, (uint32)u_lockoutreset/60))
1033                 return nt_status;
1034
1035         if (u_lockouttime != -1)
1036                 u_lockouttime /= 60;
1037
1038         if (!pdb_set_account_policy(AP_LOCK_ACCOUNT_DURATION, (uint32)u_lockouttime))
1039                 return nt_status;
1040 #endif
1041
1042         if (!pdb_set_account_policy(AP_USER_MUST_LOGON_TO_CHG_PASS,
1043                                     r->logon_to_chgpass))
1044                 return nt_status;
1045
1046         return NT_STATUS_OK;
1047 }
1048
1049 static void fetch_sam_entry(struct netr_DELTA_ENUM *r, DOM_SID dom_sid)
1050 {
1051         switch(r->delta_type) {
1052         case NETR_DELTA_USER:
1053                 fetch_account_info(r->delta_id_union.rid,
1054                                    r->delta_union.user);
1055                 break;
1056         case NETR_DELTA_GROUP:
1057                 fetch_group_info(r->delta_id_union.rid,
1058                                  r->delta_union.group);
1059                 break;
1060         case NETR_DELTA_GROUP_MEMBER:
1061                 fetch_group_mem_info(r->delta_id_union.rid,
1062                                      r->delta_union.group_member);
1063                 break;
1064         case NETR_DELTA_ALIAS:
1065                 fetch_alias_info(r->delta_id_union.rid,
1066                                  r->delta_union.alias,
1067                                  dom_sid);
1068                 break;
1069         case NETR_DELTA_ALIAS_MEMBER:
1070                 fetch_alias_mem(r->delta_id_union.rid,
1071                                 r->delta_union.alias_member,
1072                                 dom_sid);
1073                 break;
1074         case NETR_DELTA_DOMAIN:
1075                 fetch_domain_info(r->delta_id_union.rid,
1076                                   r->delta_union.domain);
1077                 break;
1078         /* The following types are recognised but not handled */
1079         case NETR_DELTA_RENAME_GROUP:
1080                 d_printf("NETR_DELTA_RENAME_GROUP not handled\n");
1081                 break;
1082         case NETR_DELTA_RENAME_USER:
1083                 d_printf("NETR_DELTA_RENAME_USER not handled\n");
1084                 break;
1085         case NETR_DELTA_RENAME_ALIAS:
1086                 d_printf("NETR_DELTA_RENAME_ALIAS not handled\n");
1087                 break;
1088         case NETR_DELTA_POLICY:
1089                 d_printf("NETR_DELTA_POLICY not handled\n");
1090                 break;
1091         case NETR_DELTA_TRUSTED_DOMAIN:
1092                 d_printf("NETR_DELTA_TRUSTED_DOMAIN not handled\n");
1093                 break;
1094         case NETR_DELTA_ACCOUNT:
1095                 d_printf("NETR_DELTA_ACCOUNT not handled\n");
1096                 break;
1097         case NETR_DELTA_SECRET:
1098                 d_printf("NETR_DELTA_SECRET not handled\n");
1099                 break;
1100         case NETR_DELTA_DELETE_GROUP:
1101                 d_printf("NETR_DELTA_DELETE_GROUP not handled\n");
1102                 break;
1103         case NETR_DELTA_DELETE_USER:
1104                 d_printf("NETR_DELTA_DELETE_USER not handled\n");
1105                 break;
1106         case NETR_DELTA_MODIFY_COUNT:
1107                 d_printf("NETR_DELTA_MODIFY_COUNT not handled\n");
1108                 break;
1109         case NETR_DELTA_DELETE_ALIAS:
1110                 d_printf("NETR_DELTA_DELETE_ALIAS not handled\n");
1111                 break;
1112         case NETR_DELTA_DELETE_TRUST:
1113                 d_printf("NETR_DELTA_DELETE_TRUST not handled\n");
1114                 break;
1115         case NETR_DELTA_DELETE_ACCOUNT:
1116                 d_printf("NETR_DELTA_DELETE_ACCOUNT not handled\n");
1117                 break;
1118         case NETR_DELTA_DELETE_SECRET:
1119                 d_printf("NETR_DELTA_DELETE_SECRET not handled\n");
1120                 break;
1121         case NETR_DELTA_DELETE_GROUP2:
1122                 d_printf("NETR_DELTA_DELETE_GROUP2 not handled\n");
1123                 break;
1124         case NETR_DELTA_DELETE_USER2:
1125                 d_printf("NETR_DELTA_DELETE_USER2 not handled\n");
1126                 break;
1127         default:
1128                 d_printf("Unknown delta record type %d\n", r->delta_type);
1129                 break;
1130         }
1131 }
1132
1133 static NTSTATUS fetch_database(struct rpc_pipe_client *pipe_hnd, uint32 db_type, DOM_SID dom_sid)
1134 {
1135         NTSTATUS result;
1136         int i;
1137         TALLOC_CTX *mem_ctx;
1138         const char *logon_server = pipe_hnd->cli->desthost;
1139         const char *computername = global_myname();
1140         struct netr_Authenticator credential;
1141         struct netr_Authenticator return_authenticator;
1142         enum netr_SamDatabaseID database_id = db_type;
1143         uint16_t restart_state = 0;
1144         uint32_t sync_context = 0;
1145
1146         if (!(mem_ctx = talloc_init("fetch_database")))
1147                 return NT_STATUS_NO_MEMORY;
1148
1149         switch( db_type ) {
1150         case SAM_DATABASE_DOMAIN:
1151                 d_printf("Fetching DOMAIN database\n");
1152                 break;
1153         case SAM_DATABASE_BUILTIN:
1154                 d_printf("Fetching BUILTIN database\n");
1155                 break;
1156         case SAM_DATABASE_PRIVS:
1157                 d_printf("Fetching PRIVS databases\n");
1158                 break;
1159         default:
1160                 d_printf("Fetching unknown database type %u\n", db_type );
1161                 break;
1162         }
1163
1164         do {
1165                 struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
1166
1167                 netlogon_creds_client_step(pipe_hnd->dc, &credential);
1168
1169                 result = rpccli_netr_DatabaseSync2(pipe_hnd, mem_ctx,
1170                                                    logon_server,
1171                                                    computername,
1172                                                    &credential,
1173                                                    &return_authenticator,
1174                                                    database_id,
1175                                                    restart_state,
1176                                                    &sync_context,
1177                                                    &delta_enum_array,
1178                                                    0xffff);
1179
1180                 /* Check returned credentials. */
1181                 if (!netlogon_creds_client_check(pipe_hnd->dc,
1182                                                  &return_authenticator.cred)) {
1183                         DEBUG(0,("credentials chain check failed\n"));
1184                         return NT_STATUS_ACCESS_DENIED;
1185                 }
1186
1187                 if (NT_STATUS_IS_ERR(result)) {
1188                         break;
1189                 }
1190
1191                 for (i = 0; i < delta_enum_array->num_deltas; i++) {
1192                         fetch_sam_entry(&delta_enum_array->delta_enum[i], dom_sid);
1193                 }
1194
1195         } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
1196
1197         talloc_destroy(mem_ctx);
1198
1199         return result;
1200 }
1201
1202 static NTSTATUS populate_ldap_for_ldif(fstring sid, const char *suffix, const char
1203                        *builtin_sid, FILE *add_fd)
1204 {
1205         const char *user_suffix, *group_suffix, *machine_suffix, *idmap_suffix;
1206         char *user_attr=NULL, *group_attr=NULL;
1207         char *suffix_attr;
1208         int len;
1209
1210         /* Get the suffix attribute */
1211         suffix_attr = sstring_sub(suffix, '=', ',');
1212         if (suffix_attr == NULL) {
1213                 len = strlen(suffix);
1214                 suffix_attr = (char*)SMB_MALLOC(len+1);
1215                 memcpy(suffix_attr, suffix, len);
1216                 suffix_attr[len] = '\0';
1217         }
1218
1219         /* Write the base */
1220         fprintf(add_fd, "# %s\n", suffix);
1221         fprintf(add_fd, "dn: %s\n", suffix);
1222         fprintf(add_fd, "objectClass: dcObject\n");
1223         fprintf(add_fd, "objectClass: organization\n");
1224         fprintf(add_fd, "o: %s\n", suffix_attr);
1225         fprintf(add_fd, "dc: %s\n", suffix_attr);
1226         fprintf(add_fd, "\n");
1227         fflush(add_fd);
1228
1229         user_suffix = lp_ldap_user_suffix();
1230         if (user_suffix == NULL) {
1231                 SAFE_FREE(suffix_attr);
1232                 return NT_STATUS_NO_MEMORY;
1233         }
1234         /* If it exists and is distinct from other containers,
1235            Write the Users entity */
1236         if (*user_suffix && strcmp(user_suffix, suffix)) {
1237                 user_attr = sstring_sub(lp_ldap_user_suffix(), '=', ',');
1238                 fprintf(add_fd, "# %s\n", user_suffix);
1239                 fprintf(add_fd, "dn: %s\n", user_suffix);
1240                 fprintf(add_fd, "objectClass: organizationalUnit\n");
1241                 fprintf(add_fd, "ou: %s\n", user_attr);
1242                 fprintf(add_fd, "\n");
1243                 fflush(add_fd);
1244         }
1245
1246
1247         group_suffix = lp_ldap_group_suffix();
1248         if (group_suffix == NULL) {
1249                 SAFE_FREE(suffix_attr);
1250                 SAFE_FREE(user_attr);
1251                 return NT_STATUS_NO_MEMORY;
1252         }
1253         /* If it exists and is distinct from other containers,
1254            Write the Groups entity */
1255         if (*group_suffix && strcmp(group_suffix, suffix)) {
1256                 group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
1257                 fprintf(add_fd, "# %s\n", group_suffix);
1258                 fprintf(add_fd, "dn: %s\n", group_suffix);
1259                 fprintf(add_fd, "objectClass: organizationalUnit\n");
1260                 fprintf(add_fd, "ou: %s\n", group_attr);
1261                 fprintf(add_fd, "\n");
1262                 fflush(add_fd);
1263         }
1264
1265         /* If it exists and is distinct from other containers,
1266            Write the Computers entity */
1267         machine_suffix = lp_ldap_machine_suffix();
1268         if (machine_suffix == NULL) {
1269                 SAFE_FREE(suffix_attr);
1270                 SAFE_FREE(user_attr);
1271                 SAFE_FREE(group_attr);
1272                 return NT_STATUS_NO_MEMORY;
1273         }
1274         if (*machine_suffix && strcmp(machine_suffix, user_suffix) &&
1275             strcmp(machine_suffix, suffix)) {
1276                 char *machine_ou = NULL;
1277                 fprintf(add_fd, "# %s\n", machine_suffix);
1278                 fprintf(add_fd, "dn: %s\n", machine_suffix);
1279                 fprintf(add_fd, "objectClass: organizationalUnit\n");
1280                 /* this isn't totally correct as it assumes that
1281                    there _must_ be an ou. just fixing memleak now. jmcd */
1282                 machine_ou = sstring_sub(lp_ldap_machine_suffix(), '=', ',');
1283                 fprintf(add_fd, "ou: %s\n", machine_ou);
1284                 SAFE_FREE(machine_ou);
1285                 fprintf(add_fd, "\n");
1286                 fflush(add_fd);
1287         }
1288
1289         /* If it exists and is distinct from other containers,
1290            Write the IdMap entity */
1291         idmap_suffix = lp_ldap_idmap_suffix();
1292         if (idmap_suffix == NULL) {
1293                 SAFE_FREE(suffix_attr);
1294                 SAFE_FREE(user_attr);
1295                 SAFE_FREE(group_attr);
1296                 return NT_STATUS_NO_MEMORY;
1297         }
1298         if (*idmap_suffix &&
1299             strcmp(idmap_suffix, user_suffix) &&
1300             strcmp(idmap_suffix, suffix)) {
1301                 char *s;
1302                 fprintf(add_fd, "# %s\n", idmap_suffix);
1303                 fprintf(add_fd, "dn: %s\n", idmap_suffix);
1304                 fprintf(add_fd, "ObjectClass: organizationalUnit\n");
1305                 s = sstring_sub(lp_ldap_idmap_suffix(), '=', ',');
1306                 fprintf(add_fd, "ou: %s\n", s);
1307                 SAFE_FREE(s);
1308                 fprintf(add_fd, "\n");
1309                 fflush(add_fd);
1310         }
1311
1312         /* Write the domain entity */
1313         fprintf(add_fd, "# %s, %s\n", lp_workgroup(), suffix);
1314         fprintf(add_fd, "dn: sambaDomainName=%s,%s\n", lp_workgroup(),
1315                 suffix);
1316         fprintf(add_fd, "objectClass: sambaDomain\n");
1317         fprintf(add_fd, "objectClass: sambaUnixIdPool\n");
1318         fprintf(add_fd, "sambaDomainName: %s\n", lp_workgroup());
1319         fprintf(add_fd, "sambaSID: %s\n", sid);
1320         fprintf(add_fd, "uidNumber: %d\n", ++ldif_uid);
1321         fprintf(add_fd, "gidNumber: %d\n", ++ldif_gid);
1322         fprintf(add_fd, "\n");
1323         fflush(add_fd);
1324
1325         /* Write the Domain Admins entity */
1326         fprintf(add_fd, "# Domain Admins, %s, %s\n", group_attr,
1327                 suffix);
1328         fprintf(add_fd, "dn: cn=Domain Admins,ou=%s,%s\n", group_attr,
1329                 suffix);
1330         fprintf(add_fd, "objectClass: posixGroup\n");
1331         fprintf(add_fd, "objectClass: sambaGroupMapping\n");
1332         fprintf(add_fd, "cn: Domain Admins\n");
1333         fprintf(add_fd, "memberUid: Administrator\n");
1334         fprintf(add_fd, "description: Netbios Domain Administrators\n");
1335         fprintf(add_fd, "gidNumber: 512\n");
1336         fprintf(add_fd, "sambaSID: %s-512\n", sid);
1337         fprintf(add_fd, "sambaGroupType: 2\n");
1338         fprintf(add_fd, "displayName: Domain Admins\n");
1339         fprintf(add_fd, "\n");
1340         fflush(add_fd);
1341
1342         /* Write the Domain Users entity */
1343         fprintf(add_fd, "# Domain Users, %s, %s\n", group_attr,
1344                 suffix);
1345         fprintf(add_fd, "dn: cn=Domain Users,ou=%s,%s\n", group_attr,
1346                 suffix);
1347         fprintf(add_fd, "objectClass: posixGroup\n");
1348         fprintf(add_fd, "objectClass: sambaGroupMapping\n");
1349         fprintf(add_fd, "cn: Domain Users\n");
1350         fprintf(add_fd, "description: Netbios Domain Users\n");
1351         fprintf(add_fd, "gidNumber: 513\n");
1352         fprintf(add_fd, "sambaSID: %s-513\n", sid);
1353         fprintf(add_fd, "sambaGroupType: 2\n");
1354         fprintf(add_fd, "displayName: Domain Users\n");
1355         fprintf(add_fd, "\n");
1356         fflush(add_fd);
1357
1358         /* Write the Domain Guests entity */
1359         fprintf(add_fd, "# Domain Guests, %s, %s\n", group_attr,
1360                 suffix);
1361         fprintf(add_fd, "dn: cn=Domain Guests,ou=%s,%s\n", group_attr,
1362                 suffix);
1363         fprintf(add_fd, "objectClass: posixGroup\n");
1364         fprintf(add_fd, "objectClass: sambaGroupMapping\n");
1365         fprintf(add_fd, "cn: Domain Guests\n");
1366         fprintf(add_fd, "description: Netbios Domain Guests\n");
1367         fprintf(add_fd, "gidNumber: 514\n");
1368         fprintf(add_fd, "sambaSID: %s-514\n", sid);
1369         fprintf(add_fd, "sambaGroupType: 2\n");
1370         fprintf(add_fd, "displayName: Domain Guests\n");
1371         fprintf(add_fd, "\n");
1372         fflush(add_fd);
1373
1374         /* Write the Domain Computers entity */
1375         fprintf(add_fd, "# Domain Computers, %s, %s\n", group_attr,
1376                 suffix);
1377         fprintf(add_fd, "dn: cn=Domain Computers,ou=%s,%s\n",
1378                 group_attr, suffix);
1379         fprintf(add_fd, "objectClass: posixGroup\n");
1380         fprintf(add_fd, "objectClass: sambaGroupMapping\n");
1381         fprintf(add_fd, "gidNumber: 515\n");
1382         fprintf(add_fd, "cn: Domain Computers\n");
1383         fprintf(add_fd, "description: Netbios Domain Computers accounts\n");
1384         fprintf(add_fd, "sambaSID: %s-515\n", sid);
1385         fprintf(add_fd, "sambaGroupType: 2\n");
1386         fprintf(add_fd, "displayName: Domain Computers\n");
1387         fprintf(add_fd, "\n");
1388         fflush(add_fd);
1389
1390         /* Write the Admininistrators Groups entity */
1391         fprintf(add_fd, "# Administrators, %s, %s\n", group_attr,
1392                 suffix);
1393         fprintf(add_fd, "dn: cn=Administrators,ou=%s,%s\n", group_attr,
1394                 suffix);
1395         fprintf(add_fd, "objectClass: posixGroup\n");
1396         fprintf(add_fd, "objectClass: sambaGroupMapping\n");
1397         fprintf(add_fd, "gidNumber: 544\n");
1398         fprintf(add_fd, "cn: Administrators\n");
1399         fprintf(add_fd, "description: Netbios Domain Members can fully administer the computer/sambaDomainName\n");
1400         fprintf(add_fd, "sambaSID: %s-544\n", builtin_sid);
1401         fprintf(add_fd, "sambaGroupType: 5\n");
1402         fprintf(add_fd, "displayName: Administrators\n");
1403         fprintf(add_fd, "\n");
1404
1405         /* Write the Print Operator entity */
1406         fprintf(add_fd, "# Print Operators, %s, %s\n", group_attr,
1407                 suffix);
1408         fprintf(add_fd, "dn: cn=Print Operators,ou=%s,%s\n",
1409                 group_attr, suffix);
1410         fprintf(add_fd, "objectClass: posixGroup\n");
1411         fprintf(add_fd, "objectClass: sambaGroupMapping\n");
1412         fprintf(add_fd, "gidNumber: 550\n");
1413         fprintf(add_fd, "cn: Print Operators\n");
1414         fprintf(add_fd, "description: Netbios Domain Print Operators\n");
1415         fprintf(add_fd, "sambaSID: %s-550\n", builtin_sid);
1416         fprintf(add_fd, "sambaGroupType: 5\n");
1417         fprintf(add_fd, "displayName: Print Operators\n");
1418         fprintf(add_fd, "\n");
1419         fflush(add_fd);
1420
1421         /* Write the Backup Operators entity */
1422         fprintf(add_fd, "# Backup Operators, %s, %s\n", group_attr,
1423                 suffix);
1424         fprintf(add_fd, "dn: cn=Backup Operators,ou=%s,%s\n",
1425                 group_attr, suffix);
1426         fprintf(add_fd, "objectClass: posixGroup\n");
1427         fprintf(add_fd, "objectClass: sambaGroupMapping\n");
1428         fprintf(add_fd, "gidNumber: 551\n");
1429         fprintf(add_fd, "cn: Backup Operators\n");
1430         fprintf(add_fd, "description: Netbios Domain Members can bypass file security to back up files\n");
1431         fprintf(add_fd, "sambaSID: %s-551\n", builtin_sid);
1432         fprintf(add_fd, "sambaGroupType: 5\n");
1433         fprintf(add_fd, "displayName: Backup Operators\n");
1434         fprintf(add_fd, "\n");
1435         fflush(add_fd);
1436
1437         /* Write the Replicators entity */
1438         fprintf(add_fd, "# Replicators, %s, %s\n", group_attr, suffix);
1439         fprintf(add_fd, "dn: cn=Replicators,ou=%s,%s\n", group_attr,
1440                 suffix);
1441         fprintf(add_fd, "objectClass: posixGroup\n");
1442         fprintf(add_fd, "objectClass: sambaGroupMapping\n");
1443         fprintf(add_fd, "gidNumber: 552\n");
1444         fprintf(add_fd, "cn: Replicators\n");
1445         fprintf(add_fd, "description: Netbios Domain Supports file replication in a sambaDomainName\n");
1446         fprintf(add_fd, "sambaSID: %s-552\n", builtin_sid);
1447         fprintf(add_fd, "sambaGroupType: 5\n");
1448         fprintf(add_fd, "displayName: Replicators\n");
1449         fprintf(add_fd, "\n");
1450         fflush(add_fd);
1451
1452         /* Deallocate memory, and return */
1453         SAFE_FREE(suffix_attr);
1454         SAFE_FREE(user_attr);
1455         SAFE_FREE(group_attr);
1456         return NT_STATUS_OK;
1457 }
1458
1459 static NTSTATUS map_populate_groups(GROUPMAP *groupmap, ACCOUNTMAP *accountmap, fstring sid,
1460                     const char *suffix, const char *builtin_sid)
1461 {
1462         char *group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
1463
1464         /* Map the groups created by populate_ldap_for_ldif */
1465         groupmap[0].rid = 512;
1466         groupmap[0].gidNumber = 512;
1467         snprintf(groupmap[0].sambaSID, sizeof(groupmap[0].sambaSID),
1468                         "%s-512", sid);
1469         snprintf(groupmap[0].group_dn, sizeof(groupmap[0].group_dn),
1470                         "cn=Domain Admins,ou=%s,%s",
1471                         group_attr, suffix);
1472         accountmap[0].rid = 512;
1473         snprintf(accountmap[0].cn, sizeof(accountmap[0].cn),
1474                         "%s", "Domain Admins");
1475
1476         groupmap[1].rid = 513;
1477         groupmap[1].gidNumber = 513;
1478         snprintf(groupmap[1].sambaSID, sizeof(groupmap[1].sambaSID),
1479                         "%s-513", sid);
1480         snprintf(groupmap[1].group_dn, sizeof(groupmap[1].group_dn),
1481                         "cn=Domain Users,ou=%s,%s",
1482                         group_attr, suffix);
1483         accountmap[1].rid = 513;
1484         snprintf(accountmap[1].cn, sizeof(accountmap[1].cn),
1485                         "%s", "Domain Users");
1486
1487         groupmap[2].rid = 514;
1488         groupmap[2].gidNumber = 514;
1489         snprintf(groupmap[2].sambaSID, sizeof(groupmap[2].sambaSID),
1490                         "%s-514", sid);
1491         snprintf(groupmap[2].group_dn, sizeof(groupmap[2].group_dn),
1492                         "cn=Domain Guests,ou=%s,%s",
1493                         group_attr, suffix);
1494         accountmap[2].rid = 514;
1495         snprintf(accountmap[2].cn, sizeof(accountmap[2].cn),
1496                         "%s", "Domain Guests");
1497
1498         groupmap[3].rid = 515;
1499         groupmap[3].gidNumber = 515;
1500         snprintf(groupmap[3].sambaSID, sizeof(groupmap[3].sambaSID),
1501                         "%s-515", sid);
1502         snprintf(groupmap[3].group_dn, sizeof(groupmap[3].group_dn),
1503                         "cn=Domain Computers,ou=%s,%s",
1504                         group_attr, suffix);
1505         accountmap[3].rid = 515;
1506         snprintf(accountmap[3].cn, sizeof(accountmap[3].cn),
1507                         "%s", "Domain Computers");
1508
1509         groupmap[4].rid = 544;
1510         groupmap[4].gidNumber = 544;
1511         snprintf(groupmap[4].sambaSID, sizeof(groupmap[4].sambaSID),
1512                         "%s-544", builtin_sid);
1513         snprintf(groupmap[4].group_dn, sizeof(groupmap[4].group_dn),
1514                         "cn=Administrators,ou=%s,%s",
1515                         group_attr, suffix);
1516         accountmap[4].rid = 515;
1517         snprintf(accountmap[4].cn, sizeof(accountmap[4].cn),
1518                         "%s", "Administrators");
1519
1520         groupmap[5].rid = 550;
1521         groupmap[5].gidNumber = 550;
1522         snprintf(groupmap[5].sambaSID, sizeof(groupmap[5].sambaSID),
1523                         "%s-550", builtin_sid);
1524         snprintf(groupmap[5].group_dn, sizeof(groupmap[5].group_dn),
1525                         "cn=Print Operators,ou=%s,%s",
1526                         group_attr, suffix);
1527         accountmap[5].rid = 550;
1528         snprintf(accountmap[5].cn, sizeof(accountmap[5].cn),
1529                         "%s", "Print Operators");
1530
1531         groupmap[6].rid = 551;
1532         groupmap[6].gidNumber = 551;
1533         snprintf(groupmap[6].sambaSID, sizeof(groupmap[6].sambaSID),
1534                         "%s-551", builtin_sid);
1535         snprintf(groupmap[6].group_dn, sizeof(groupmap[6].group_dn),
1536                         "cn=Backup Operators,ou=%s,%s",
1537                         group_attr, suffix);
1538         accountmap[6].rid = 551;
1539         snprintf(accountmap[6].cn, sizeof(accountmap[6].cn),
1540                         "%s", "Backup Operators");
1541
1542         groupmap[7].rid = 552;
1543         groupmap[7].gidNumber = 552;
1544         snprintf(groupmap[7].sambaSID, sizeof(groupmap[7].sambaSID),
1545                         "%s-552", builtin_sid);
1546         snprintf(groupmap[7].group_dn, sizeof(groupmap[7].group_dn),
1547                         "cn=Replicators,ou=%s,%s",
1548                         group_attr, suffix);
1549         accountmap[7].rid = 551;
1550         snprintf(accountmap[7].cn, sizeof(accountmap[7].cn),
1551                         "%s", "Replicators");
1552         SAFE_FREE(group_attr);
1553         return NT_STATUS_OK;
1554 }
1555
1556 /*
1557  * This is a crap routine, but I think it's the quickest way to solve the
1558  * UTF8->base64 problem.
1559  */
1560
1561 static int fprintf_attr(FILE *add_fd, const char *attr_name,
1562                         const char *fmt, ...)
1563 {
1564         va_list ap;
1565         char *value, *p, *base64;
1566         DATA_BLOB base64_blob;
1567         bool do_base64 = False;
1568         int res;
1569
1570         va_start(ap, fmt);
1571         value = talloc_vasprintf(NULL, fmt, ap);
1572         va_end(ap);
1573
1574         SMB_ASSERT(value != NULL);
1575
1576         for (p=value; *p; p++) {
1577                 if (*p & 0x80) {
1578                         do_base64 = True;
1579                         break;
1580                 }
1581         }
1582
1583         if (!do_base64) {
1584                 bool only_whitespace = True;
1585                 for (p=value; *p; p++) {
1586                         /*
1587                          * I know that this not multibyte safe, but we break
1588                          * on the first non-whitespace character anyway.
1589                          */
1590                         if (!isspace(*p)) {
1591                                 only_whitespace = False;
1592                                 break;
1593                         }
1594                 }
1595                 if (only_whitespace) {
1596                         do_base64 = True;
1597                 }
1598         }
1599
1600         if (!do_base64) {
1601                 res = fprintf(add_fd, "%s: %s\n", attr_name, value);
1602                 TALLOC_FREE(value);
1603                 return res;
1604         }
1605
1606         base64_blob.data = (unsigned char *)value;
1607         base64_blob.length = strlen(value);
1608
1609         base64 = base64_encode_data_blob(value, base64_blob);
1610         SMB_ASSERT(base64 != NULL);
1611
1612         res = fprintf(add_fd, "%s:: %s\n", attr_name, base64);
1613         TALLOC_FREE(value);
1614         return res;
1615 }
1616
1617 static NTSTATUS fetch_group_info_to_ldif(struct netr_DELTA_GROUP *r, GROUPMAP *groupmap,
1618                          FILE *add_fd, fstring sid, char *suffix)
1619 {
1620         fstring groupname;
1621         uint32 grouptype = 0, g_rid = 0;
1622         char *group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
1623
1624         /* Get the group name */
1625         fstrcpy(groupname, r->group_name.string);
1626
1627         /* Set up the group type (always 2 for group info) */
1628         grouptype = 2;
1629
1630         /* These groups are entered by populate_ldap_for_ldif */
1631         if (strcmp(groupname, "Domain Admins") == 0 ||
1632             strcmp(groupname, "Domain Users") == 0 ||
1633             strcmp(groupname, "Domain Guests") == 0 ||
1634             strcmp(groupname, "Domain Computers") == 0 ||
1635             strcmp(groupname, "Administrators") == 0 ||
1636             strcmp(groupname, "Print Operators") == 0 ||
1637             strcmp(groupname, "Backup Operators") == 0 ||
1638             strcmp(groupname, "Replicators") == 0) {
1639                 SAFE_FREE(group_attr);
1640                 return NT_STATUS_OK;
1641         } else {
1642                 /* Increment the gid for the new group */
1643                 ldif_gid++;
1644         }
1645
1646         /* Map the group rid, gid, and dn */
1647         g_rid = r->rid;
1648         groupmap->rid = g_rid;
1649         groupmap->gidNumber = ldif_gid;
1650         snprintf(groupmap->sambaSID, sizeof(groupmap->sambaSID),
1651                         "%s-%d", sid, g_rid);
1652         snprintf(groupmap->group_dn, sizeof(groupmap->group_dn),
1653                      "cn=%s,ou=%s,%s", groupname, group_attr, suffix);
1654
1655         /* Write the data to the temporary add ldif file */
1656         fprintf(add_fd, "# %s, %s, %s\n", groupname, group_attr,
1657                 suffix);
1658         fprintf_attr(add_fd, "dn", "cn=%s,ou=%s,%s", groupname, group_attr,
1659                      suffix);
1660         fprintf(add_fd, "objectClass: posixGroup\n");
1661         fprintf(add_fd, "objectClass: sambaGroupMapping\n");
1662         fprintf_attr(add_fd, "cn", "%s", groupname);
1663         fprintf(add_fd, "gidNumber: %d\n", ldif_gid);
1664         fprintf(add_fd, "sambaSID: %s\n", groupmap->sambaSID);
1665         fprintf(add_fd, "sambaGroupType: %d\n", grouptype);
1666         fprintf_attr(add_fd, "displayName", "%s", groupname);
1667         fprintf(add_fd, "\n");
1668         fflush(add_fd);
1669
1670         SAFE_FREE(group_attr);
1671         /* Return */
1672         return NT_STATUS_OK;
1673 }
1674
1675 static NTSTATUS fetch_account_info_to_ldif(struct netr_DELTA_USER *r,
1676                                            GROUPMAP *groupmap,
1677                                            ACCOUNTMAP *accountmap,
1678                                            FILE *add_fd,
1679                                            fstring sid, char *suffix,
1680                                            int alloced)
1681 {
1682         fstring username, logonscript, homedrive, homepath = "", homedir = "";
1683         fstring hex_nt_passwd, hex_lm_passwd;
1684         fstring description, profilepath, fullname, sambaSID;
1685         uchar lm_passwd[16], nt_passwd[16];
1686         char *flags, *user_rdn;
1687         const char *ou;
1688         const char* nopasswd = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
1689         static uchar zero_buf[16];
1690         uint32 rid = 0, group_rid = 0, gidNumber = 0;
1691         time_t unix_time;
1692         int i;
1693
1694         /* Get the username */
1695         fstrcpy(username, r->account_name.string);
1696
1697         /* Get the rid */
1698         rid = r->rid;
1699
1700         /* Map the rid and username for group member info later */
1701         accountmap->rid = rid;
1702         snprintf(accountmap->cn, sizeof(accountmap->cn), "%s", username);
1703
1704         /* Get the home directory */
1705         if (r->acct_flags & ACB_NORMAL) {
1706                 fstrcpy(homedir, r->home_directory.string);
1707                 if (!*homedir) {
1708                         snprintf(homedir, sizeof(homedir), "/home/%s", username);
1709                 } else {
1710                         snprintf(homedir, sizeof(homedir), "/nobodyshomedir");
1711                 }
1712                 ou = lp_ldap_user_suffix();
1713         } else {
1714                 ou = lp_ldap_machine_suffix();
1715                 snprintf(homedir, sizeof(homedir), "/machinehomedir");
1716         }
1717
1718         /* Get the logon script */
1719         fstrcpy(logonscript, r->logon_script.string);
1720
1721         /* Get the home drive */
1722         fstrcpy(homedrive, r->home_drive.string);
1723
1724         /* Get the home path */
1725         fstrcpy(homepath, r->home_directory.string);
1726
1727         /* Get the description */
1728         fstrcpy(description, r->description.string);
1729
1730         /* Get the display name */
1731         fstrcpy(fullname, r->full_name.string);
1732
1733         /* Get the profile path */
1734         fstrcpy(profilepath, r->profile_path.string);
1735
1736         /* Get lm and nt password data */
1737         if (memcmp(r->lmpassword.hash, zero_buf, 16) != 0) {
1738                 sam_pwd_hash(r->rid, r->lmpassword.hash, lm_passwd, 0);
1739                 pdb_sethexpwd(hex_lm_passwd, lm_passwd, r->acct_flags);
1740         } else {
1741                 pdb_sethexpwd(hex_lm_passwd, NULL, 0);
1742         }
1743         if (memcmp(r->ntpassword.hash, zero_buf, 16) != 0) {
1744                 sam_pwd_hash(r->rid, r->ntpassword.hash, nt_passwd, 0);
1745                 pdb_sethexpwd(hex_nt_passwd, nt_passwd, r->acct_flags);
1746         } else {
1747                 pdb_sethexpwd(hex_nt_passwd, NULL, 0);
1748         }
1749         unix_time = nt_time_to_unix(r->last_password_change);
1750
1751         /* Increment the uid for the new user */
1752         ldif_uid++;
1753
1754         /* Set up group id and sambaSID for the user */
1755         group_rid = r->primary_gid;
1756         for (i=0; i<alloced; i++) {
1757                 if (groupmap[i].rid == group_rid) break;
1758         }
1759         if (i == alloced){
1760                 DEBUG(1, ("Could not find rid %d in groupmap array\n",
1761                           group_rid));
1762                 return NT_STATUS_UNSUCCESSFUL;
1763         }
1764         gidNumber = groupmap[i].gidNumber;
1765         snprintf(sambaSID, sizeof(sambaSID), groupmap[i].sambaSID);
1766
1767         /* Set up sambaAcctFlags */
1768         flags = pdb_encode_acct_ctrl(r->acct_flags,
1769                                      NEW_PW_FORMAT_SPACE_PADDED_LEN);
1770
1771         /* Add the user to the temporary add ldif file */
1772         /* this isn't quite right...we can't assume there's just OU=. jmcd */
1773         user_rdn = sstring_sub(ou, '=', ',');
1774         fprintf(add_fd, "# %s, %s, %s\n", username, user_rdn, suffix);
1775         fprintf_attr(add_fd, "dn", "uid=%s,ou=%s,%s", username, user_rdn,
1776                      suffix);
1777         SAFE_FREE(user_rdn);
1778         fprintf(add_fd, "ObjectClass: top\n");
1779         fprintf(add_fd, "objectClass: inetOrgPerson\n");
1780         fprintf(add_fd, "objectClass: posixAccount\n");
1781         fprintf(add_fd, "objectClass: shadowAccount\n");
1782         fprintf(add_fd, "objectClass: sambaSamAccount\n");
1783         fprintf_attr(add_fd, "cn", "%s", username);
1784         fprintf_attr(add_fd, "sn", "%s", username);
1785         fprintf_attr(add_fd, "uid", "%s", username);
1786         fprintf(add_fd, "uidNumber: %d\n", ldif_uid);
1787         fprintf(add_fd, "gidNumber: %d\n", gidNumber);
1788         fprintf_attr(add_fd, "homeDirectory", "%s", homedir);
1789         if (*homepath)
1790                 fprintf_attr(add_fd, "sambaHomePath", "%s", homepath);
1791         if (*homedrive)
1792                 fprintf_attr(add_fd, "sambaHomeDrive", "%s", homedrive);
1793         if (*logonscript)
1794                 fprintf_attr(add_fd, "sambaLogonScript", "%s", logonscript);
1795         fprintf(add_fd, "loginShell: %s\n",
1796                 ((r->acct_flags & ACB_NORMAL) ?
1797                  "/bin/bash" : "/bin/false"));
1798         fprintf(add_fd, "gecos: System User\n");
1799         if (*description)
1800                 fprintf_attr(add_fd, "description", "%s", description);
1801         fprintf(add_fd, "sambaSID: %s-%d\n", sid, rid);
1802         fprintf(add_fd, "sambaPrimaryGroupSID: %s\n", sambaSID);
1803         if(*fullname)
1804                 fprintf_attr(add_fd, "displayName", "%s", fullname);
1805         if(*profilepath)
1806                 fprintf_attr(add_fd, "sambaProfilePath", "%s", profilepath);
1807         if (strcmp(nopasswd, hex_lm_passwd) != 0)
1808                 fprintf(add_fd, "sambaLMPassword: %s\n", hex_lm_passwd);
1809         if (strcmp(nopasswd, hex_nt_passwd) != 0)
1810                 fprintf(add_fd, "sambaNTPassword: %s\n", hex_nt_passwd);
1811         fprintf(add_fd, "sambaPwdLastSet: %d\n", (int)unix_time);
1812         fprintf(add_fd, "sambaAcctFlags: %s\n", flags);
1813         fprintf(add_fd, "\n");
1814         fflush(add_fd);
1815
1816         /* Return */
1817         return NT_STATUS_OK;
1818 }
1819
1820 static NTSTATUS fetch_alias_info_to_ldif(struct netr_DELTA_ALIAS *r,
1821                                          GROUPMAP *groupmap,
1822                                          FILE *add_fd, fstring sid,
1823                                          char *suffix,
1824                                          unsigned db_type)
1825 {
1826         fstring aliasname, description;
1827         uint32 grouptype = 0, g_rid = 0;
1828         char *group_attr = sstring_sub(lp_ldap_group_suffix(), '=', ',');
1829
1830         /* Get the alias name */
1831         fstrcpy(aliasname, r->alias_name.string);
1832
1833         /* Get the alias description */
1834         fstrcpy(description, r->description.string);
1835
1836         /* Set up the group type */
1837         switch (db_type) {
1838         case SAM_DATABASE_DOMAIN:
1839                 grouptype = 4;
1840                 break;
1841         case SAM_DATABASE_BUILTIN:
1842                 grouptype = 5;
1843                 break;
1844         default:
1845                 grouptype = 4;
1846                 break;
1847         }
1848
1849         /*
1850           These groups are entered by populate_ldap_for_ldif
1851           Note that populate creates a group called Relicators,
1852           but NT returns a group called Replicator
1853         */
1854         if (strcmp(aliasname, "Domain Admins") == 0 ||
1855             strcmp(aliasname, "Domain Users") == 0 ||
1856             strcmp(aliasname, "Domain Guests") == 0 ||
1857             strcmp(aliasname, "Domain Computers") == 0 ||
1858             strcmp(aliasname, "Administrators") == 0 ||
1859             strcmp(aliasname, "Print Operators") == 0 ||
1860             strcmp(aliasname, "Backup Operators") == 0 ||
1861             strcmp(aliasname, "Replicator") == 0) {
1862                 SAFE_FREE(group_attr);
1863                 return NT_STATUS_OK;
1864         } else {
1865                 /* Increment the gid for the new group */
1866                 ldif_gid++;
1867         }
1868
1869         /* Map the group rid and gid */
1870         g_rid = r->rid;
1871         groupmap->gidNumber = ldif_gid;
1872         snprintf(groupmap->sambaSID, sizeof(groupmap->sambaSID),
1873                         "%s-%d", sid, g_rid);
1874
1875         /* Write the data to the temporary add ldif file */
1876         fprintf(add_fd, "# %s, %s, %s\n", aliasname, group_attr,
1877                 suffix);
1878         fprintf_attr(add_fd, "dn", "cn=%s,ou=%s,%s", aliasname, group_attr,
1879                      suffix);
1880         fprintf(add_fd, "objectClass: posixGroup\n");
1881         fprintf(add_fd, "objectClass: sambaGroupMapping\n");
1882         fprintf(add_fd, "cn: %s\n", aliasname);
1883         fprintf(add_fd, "gidNumber: %d\n", ldif_gid);
1884         fprintf(add_fd, "sambaSID: %s\n", groupmap->sambaSID);
1885         fprintf(add_fd, "sambaGroupType: %d\n", grouptype);
1886         fprintf_attr(add_fd, "displayName", "%s", aliasname);
1887         if (description[0])
1888                 fprintf_attr(add_fd, "description", "%s", description);
1889         fprintf(add_fd, "\n");
1890         fflush(add_fd);
1891
1892         SAFE_FREE(group_attr);
1893         /* Return */
1894         return NT_STATUS_OK;
1895 }
1896
1897 static NTSTATUS fetch_groupmem_info_to_ldif(struct netr_DELTA_GROUP_MEMBER *r,
1898                                             uint32_t id_rid,
1899                                             GROUPMAP *groupmap,
1900                                             ACCOUNTMAP *accountmap,
1901                                             FILE *mod_fd, int alloced)
1902 {
1903         fstring group_dn;
1904         uint32 group_rid = 0, rid = 0;
1905         int i, j, k;
1906
1907         /* Get the dn for the group */
1908         if (r->num_rids > 0) {
1909                 group_rid = id_rid;
1910                 for (j=0; j<alloced; j++) {
1911                         if (groupmap[j].rid == group_rid) break;
1912                 }
1913                 if (j == alloced){
1914                         DEBUG(1, ("Could not find rid %d in groupmap array\n",
1915                                   group_rid));
1916                         return NT_STATUS_UNSUCCESSFUL;
1917                 }
1918                 snprintf(group_dn, sizeof(group_dn), "%s", groupmap[j].group_dn);
1919                 fprintf(mod_fd, "dn: %s\n", group_dn);
1920
1921                 /* Get the cn for each member */
1922                 for (i=0; i < r->num_rids; i++) {
1923                         rid = r->rids[i];
1924                         for (k=0; k<alloced; k++) {
1925                                 if (accountmap[k].rid == rid) break;
1926                         }
1927                         if (k == alloced){
1928                                 DEBUG(1, ("Could not find rid %d in "
1929                                           "accountmap array\n", rid));
1930                                 return NT_STATUS_UNSUCCESSFUL;
1931                         }
1932                         fprintf(mod_fd, "memberUid: %s\n", accountmap[k].cn);
1933                 }
1934                 fprintf(mod_fd, "\n");
1935         }
1936         fflush(mod_fd);
1937
1938         /* Return */
1939         return NT_STATUS_OK;
1940 }
1941
1942 static NTSTATUS fetch_database_to_ldif(struct rpc_pipe_client *pipe_hnd,
1943                                        uint32 db_type,
1944                                        DOM_SID dom_sid,
1945                                        const char *user_file)
1946 {
1947         char *suffix;
1948         const char *builtin_sid = "S-1-5-32";
1949         char *add_name = NULL, *mod_name = NULL;
1950         const char *add_template = "/tmp/add.ldif.XXXXXX";
1951         const char *mod_template = "/tmp/mod.ldif.XXXXXX";
1952         fstring sid, domainname;
1953         NTSTATUS ret = NT_STATUS_OK, result;
1954         int k;
1955         TALLOC_CTX *mem_ctx;
1956         uint32 num_deltas;
1957         FILE *add_file = NULL, *mod_file = NULL, *ldif_file = NULL;
1958         int num_alloced = 0, g_index = 0, a_index = 0;
1959         const char *logon_server = pipe_hnd->cli->desthost;
1960         const char *computername = global_myname();
1961         struct netr_Authenticator credential;
1962         struct netr_Authenticator return_authenticator;
1963         enum netr_SamDatabaseID database_id = db_type;
1964         uint16_t restart_state = 0;
1965         uint32_t sync_context = 0;
1966
1967         /* Set up array for mapping accounts to groups */
1968         /* Array element is the group rid */
1969         GROUPMAP *groupmap = NULL;
1970
1971         /* Set up array for mapping account rid's to cn's */
1972         /* Array element is the account rid */
1973         ACCOUNTMAP *accountmap = NULL;
1974
1975         if (!(mem_ctx = talloc_init("fetch_database"))) {
1976                 return NT_STATUS_NO_MEMORY;
1977         }
1978
1979         /* Ensure we have an output file */
1980         if (user_file)
1981                 ldif_file = fopen(user_file, "a");
1982         else
1983                 ldif_file = stdout;
1984
1985         if (!ldif_file) {
1986                 fprintf(stderr, "Could not open %s\n", user_file);
1987                 DEBUG(1, ("Could not open %s\n", user_file));
1988                 ret = NT_STATUS_UNSUCCESSFUL;
1989                 goto done;
1990         }
1991
1992         add_name = talloc_strdup(mem_ctx, add_template);
1993         mod_name = talloc_strdup(mem_ctx, mod_template);
1994         if (!add_name || !mod_name) {
1995                 ret = NT_STATUS_NO_MEMORY;
1996                 goto done;
1997         }
1998
1999         /* Open the add and mod ldif files */
2000         if (!(add_file = fdopen(smb_mkstemp(add_name),"w"))) {
2001                 DEBUG(1, ("Could not open %s\n", add_name));
2002                 ret = NT_STATUS_UNSUCCESSFUL;
2003                 goto done;
2004         }
2005         if (!(mod_file = fdopen(smb_mkstemp(mod_name),"w"))) {
2006                 DEBUG(1, ("Could not open %s\n", mod_name));
2007                 ret = NT_STATUS_UNSUCCESSFUL;
2008                 goto done;
2009         }
2010
2011         /* Get the sid */
2012         sid_to_fstring(sid, &dom_sid);
2013
2014         /* Get the ldap suffix */
2015         suffix = lp_ldap_suffix();
2016         if (suffix == NULL || strcmp(suffix, "") == 0) {
2017                 DEBUG(0,("ldap suffix missing from smb.conf--exiting\n"));
2018                 exit(1);
2019         }
2020
2021         /* Get other smb.conf data */
2022         if (!(lp_workgroup()) || !*(lp_workgroup())) {
2023                 DEBUG(0,("workgroup missing from smb.conf--exiting\n"));
2024                 exit(1);
2025         }
2026
2027         /* Allocate initial memory for groupmap and accountmap arrays */
2028         if (init_ldap == 1) {
2029                 groupmap = SMB_MALLOC_ARRAY(GROUPMAP, 8);
2030                 accountmap = SMB_MALLOC_ARRAY(ACCOUNTMAP, 8);
2031                 if (groupmap == NULL || accountmap == NULL) {
2032                         DEBUG(1,("GROUPMAP malloc failed\n"));
2033                         ret = NT_STATUS_NO_MEMORY;
2034                         goto done;
2035                 }
2036
2037                 /* Initialize the arrays */
2038                 memset(groupmap, 0, sizeof(GROUPMAP)*8);
2039                 memset(accountmap, 0, sizeof(ACCOUNTMAP)*8);
2040
2041                 /* Remember how many we malloced */
2042                 num_alloced = 8;
2043
2044                 /* Initial database population */
2045                 populate_ldap_for_ldif(sid, suffix, builtin_sid, add_file);
2046                 map_populate_groups(groupmap, accountmap, sid, suffix,
2047                                     builtin_sid);
2048
2049                 /* Don't do this again */
2050                 init_ldap = 0;
2051         }
2052
2053         /* Announce what we are doing */
2054         switch( db_type ) {
2055         case SAM_DATABASE_DOMAIN:
2056                 d_fprintf(stderr, "Fetching DOMAIN database\n");
2057                 break;
2058         case SAM_DATABASE_BUILTIN:
2059                 d_fprintf(stderr, "Fetching BUILTIN database\n");
2060                 break;
2061         case SAM_DATABASE_PRIVS:
2062                 d_fprintf(stderr, "Fetching PRIVS databases\n");
2063                 break;
2064         default:
2065                 d_fprintf(stderr,
2066                           "Fetching unknown database type %u\n",
2067                           db_type );
2068                 break;
2069         }
2070
2071         do {
2072                 struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
2073
2074                 netlogon_creds_client_step(pipe_hnd->dc, &credential);
2075
2076                 result = rpccli_netr_DatabaseSync2(pipe_hnd, mem_ctx,
2077                                                    logon_server,
2078                                                    computername,
2079                                                    &credential,
2080                                                    &return_authenticator,
2081                                                    database_id,
2082                                                    restart_state,
2083                                                    &sync_context,
2084                                                    &delta_enum_array,
2085                                                    0xffff);
2086
2087                 /* Check returned credentials. */
2088                 if (!netlogon_creds_client_check(pipe_hnd->dc,
2089                                                  &return_authenticator.cred)) {
2090                         DEBUG(0,("credentials chain check failed\n"));
2091                         return NT_STATUS_ACCESS_DENIED;
2092                 }
2093
2094                 if (NT_STATUS_IS_ERR(result)) {
2095                         break;
2096                 }
2097
2098                 num_deltas = delta_enum_array->num_deltas;
2099
2100                 /* Re-allocate memory for groupmap and accountmap arrays */
2101                 groupmap = SMB_REALLOC_ARRAY(groupmap, GROUPMAP,
2102                                              num_deltas+num_alloced);
2103                 accountmap = SMB_REALLOC_ARRAY(accountmap, ACCOUNTMAP,
2104                                                num_deltas+num_alloced);
2105                 if (groupmap == NULL || accountmap == NULL) {
2106                         DEBUG(1,("GROUPMAP malloc failed\n"));
2107                         ret = NT_STATUS_NO_MEMORY;
2108                         goto done;
2109                 }
2110
2111                 /* Initialize the new records */
2112                 memset(&groupmap[num_alloced], 0,
2113                        sizeof(GROUPMAP)*num_deltas);
2114                 memset(&accountmap[num_alloced], 0,
2115                        sizeof(ACCOUNTMAP)*num_deltas);
2116
2117                 /* Remember how many we alloced this time */
2118                 num_alloced += num_deltas;
2119
2120                 /* Loop through the deltas */
2121                 for (k=0; k<num_deltas; k++) {
2122
2123                         union netr_DELTA_UNION u =
2124                                 delta_enum_array->delta_enum[k].delta_union;
2125                         union netr_DELTA_ID_UNION id =
2126                                 delta_enum_array->delta_enum[k].delta_id_union;
2127
2128                         switch(delta_enum_array->delta_enum[k].delta_type) {
2129                         case NETR_DELTA_DOMAIN:
2130                                 /* Is this case needed? */
2131                                 fstrcpy(domainname,
2132                                         u.domain->domain_name.string);
2133                                 break;
2134
2135                         case NETR_DELTA_GROUP:
2136                                 fetch_group_info_to_ldif(
2137                                         u.group,
2138                                         &groupmap[g_index],
2139                                         add_file, sid, suffix);
2140                                 g_index++;
2141                                 break;
2142
2143                         case NETR_DELTA_USER:
2144                                 fetch_account_info_to_ldif(
2145                                         u.user, groupmap,
2146                                         &accountmap[a_index], add_file,
2147                                         sid, suffix, num_alloced);
2148                                 a_index++;
2149                                 break;
2150
2151                         case NETR_DELTA_ALIAS:
2152                                 fetch_alias_info_to_ldif(
2153                                         u.alias, &groupmap[g_index],
2154                                         add_file, sid, suffix, db_type);
2155                                 g_index++;
2156                                 break;
2157
2158                         case NETR_DELTA_GROUP_MEMBER:
2159                                 fetch_groupmem_info_to_ldif(
2160                                         u.group_member, id.rid,
2161                                         groupmap, accountmap,
2162                                         mod_file, num_alloced);
2163                                 break;
2164
2165                         case NETR_DELTA_ALIAS_MEMBER:
2166                         case NETR_DELTA_POLICY:
2167                         case NETR_DELTA_ACCOUNT:
2168                         case NETR_DELTA_TRUSTED_DOMAIN:
2169                         case NETR_DELTA_SECRET:
2170                         case NETR_DELTA_RENAME_GROUP:
2171                         case NETR_DELTA_RENAME_USER:
2172                         case NETR_DELTA_RENAME_ALIAS:
2173                         case NETR_DELTA_DELETE_GROUP:
2174                         case NETR_DELTA_DELETE_USER:
2175                         case NETR_DELTA_MODIFY_COUNT:
2176                         default:
2177                                 break;
2178                         } /* end of switch */
2179                 } /* end of for loop */
2180
2181                 /* Increment sync_context */
2182                 sync_context += 1;
2183
2184         } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
2185
2186         /* Write ldif data to the user's file */
2187         if (db_type == SAM_DATABASE_DOMAIN) {
2188                 fprintf(ldif_file,
2189                         "# SAM_DATABASE_DOMAIN: ADD ENTITIES\n");
2190                 fprintf(ldif_file,
2191                         "# =================================\n\n");
2192                 fflush(ldif_file);
2193         } else if (db_type == SAM_DATABASE_BUILTIN) {
2194                 fprintf(ldif_file,
2195                         "# SAM_DATABASE_BUILTIN: ADD ENTITIES\n");
2196                 fprintf(ldif_file,
2197                         "# ==================================\n\n");
2198                 fflush(ldif_file);
2199         }
2200         fseek(add_file, 0, SEEK_SET);
2201         transfer_file(fileno(add_file), fileno(ldif_file), (size_t) -1);
2202
2203         if (db_type == SAM_DATABASE_DOMAIN) {
2204                 fprintf(ldif_file,
2205                         "# SAM_DATABASE_DOMAIN: MODIFY ENTITIES\n");
2206                 fprintf(ldif_file,
2207                         "# ====================================\n\n");
2208                 fflush(ldif_file);
2209         } else if (db_type == SAM_DATABASE_BUILTIN) {
2210                 fprintf(ldif_file,
2211                         "# SAM_DATABASE_BUILTIN: MODIFY ENTITIES\n");
2212                 fprintf(ldif_file,
2213                         "# =====================================\n\n");
2214                 fflush(ldif_file);
2215         }
2216         fseek(mod_file, 0, SEEK_SET);
2217         transfer_file(fileno(mod_file), fileno(ldif_file), (size_t) -1);
2218
2219
2220  done:
2221         /* Close and delete the ldif files */
2222         if (add_file) {
2223                 fclose(add_file);
2224         }
2225
2226         if ((add_name != NULL) &&
2227             strcmp(add_name, add_template) && (unlink(add_name))) {
2228                 DEBUG(1,("unlink(%s) failed, error was (%s)\n",
2229                          add_name, strerror(errno)));
2230         }
2231
2232         if (mod_file) {
2233                 fclose(mod_file);
2234         }
2235
2236         if ((mod_name != NULL) &&
2237             strcmp(mod_name, mod_template) && (unlink(mod_name))) {
2238                 DEBUG(1,("unlink(%s) failed, error was (%s)\n",
2239                          mod_name, strerror(errno)));
2240         }
2241
2242         if (ldif_file && (ldif_file != stdout)) {
2243                 fclose(ldif_file);
2244         }
2245
2246         /* Deallocate memory for the mapping arrays */
2247         SAFE_FREE(groupmap);
2248         SAFE_FREE(accountmap);
2249
2250         /* Return */
2251         talloc_destroy(mem_ctx);
2252         return ret;
2253 }
2254
2255 /**
2256  * Basic usage function for 'net rpc vampire'
2257  * @param argc  Standard main() style argc
2258  * @param argc  Standard main() style argv.  Initial components are already
2259  *              stripped
2260  **/
2261
2262 int rpc_vampire_usage(int argc, const char **argv)
2263 {
2264         d_printf("net rpc vampire [ldif [<ldif-filename>] [options]\n"
2265                  "\t to pull accounts from a remote PDC where we are a BDC\n"
2266                  "\t\t no args puts accounts in local passdb from smb.conf\n"
2267                  "\t\t ldif - put accounts in ldif format (file defaults to "
2268                  "/tmp/tmp.ldif\n");
2269
2270         net_common_flags_usage(argc, argv);
2271         return -1;
2272 }
2273
2274
2275 /* dump sam database via samsync rpc calls */
2276 NTSTATUS rpc_vampire_internals(const DOM_SID *domain_sid,
2277                                 const char *domain_name,
2278                                 struct cli_state *cli,
2279                                 struct rpc_pipe_client *pipe_hnd,
2280                                 TALLOC_CTX *mem_ctx,
2281                                 int argc,
2282                                 const char **argv)
2283 {
2284         NTSTATUS result;
2285         fstring my_dom_sid_str;
2286         fstring rem_dom_sid_str;
2287
2288         if (!sid_equal(domain_sid, get_global_sam_sid())) {
2289                 d_printf("Cannot import users from %s at this time, "
2290                          "as the current domain:\n\t%s: %s\nconflicts "
2291                          "with the remote domain\n\t%s: %s\n"
2292                          "Perhaps you need to set: \n\n\tsecurity=user\n\t"
2293                          "workgroup=%s\n\n in your smb.conf?\n",
2294                          domain_name,
2295                          get_global_sam_name(),
2296                          sid_to_fstring(my_dom_sid_str,
2297                                         get_global_sam_sid()),
2298                          domain_name, sid_to_fstring(rem_dom_sid_str,
2299                                                      domain_sid),
2300                          domain_name);
2301                 return NT_STATUS_UNSUCCESSFUL;
2302         }
2303
2304         if (argc >= 1 && (strcmp(argv[0], "ldif") == 0)) {
2305                 result = fetch_database_to_ldif(pipe_hnd, SAM_DATABASE_DOMAIN,
2306                                                 *domain_sid, argv[1]);
2307         } else {
2308                 result = fetch_database(pipe_hnd, SAM_DATABASE_DOMAIN,
2309                                         *domain_sid);
2310         }
2311
2312         if (!NT_STATUS_IS_OK(result)) {
2313                 d_fprintf(stderr, "Failed to fetch domain database: %s\n",
2314                           nt_errstr(result));
2315                 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED))
2316                         d_fprintf(stderr, "Perhaps %s is a Windows 2000 "
2317                                   "native mode domain?\n", domain_name);
2318                 goto fail;
2319         }
2320
2321         if (argc >= 1 && (strcmp(argv[0], "ldif") == 0)) {
2322                 result = fetch_database_to_ldif(pipe_hnd, SAM_DATABASE_BUILTIN,
2323                                                 global_sid_Builtin, argv[1]);
2324         } else {
2325                 result = fetch_database(pipe_hnd, SAM_DATABASE_BUILTIN,
2326                                         global_sid_Builtin);
2327         }
2328
2329         if (!NT_STATUS_IS_OK(result)) {
2330                 d_fprintf(stderr, "Failed to fetch builtin database: %s\n",
2331                           nt_errstr(result));
2332                 goto fail;
2333         }
2334
2335         /* Currently we crash on PRIVS somewhere in unmarshalling */
2336         /* Dump_database(cli, SAM_DATABASE_PRIVS, &ret_creds); */
2337
2338  fail:
2339         return result;
2340 }