r13590: * replace all pdb_init_sam[_talloc]() calls with samu_new()
[obnox/samba/samba-obnox.git] / source3 / utils / pdbedit.c
1 /* 
2    Unix SMB/CIFS implementation.
3    passdb editing frontend
4    
5    Copyright (C) Simo Sorce      2000
6    Copyright (C) Andrew Bartlett 2001   
7    Copyright (C) Jelmer Vernooij 2002
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25
26 #define BIT_BACKEND     0x00000004
27 #define BIT_VERBOSE     0x00000008
28 #define BIT_SPSTYLE     0x00000010
29 #define BIT_CAN_CHANGE  0x00000020
30 #define BIT_MUST_CHANGE 0x00000040
31 #define BIT_USERSIDS    0x00000080
32 #define BIT_FULLNAME    0x00000100
33 #define BIT_HOMEDIR     0x00000200
34 #define BIT_HDIRDRIVE   0x00000400
35 #define BIT_LOGSCRIPT   0x00000800
36 #define BIT_PROFILE     0x00001000
37 #define BIT_MACHINE     0x00002000
38 #define BIT_USERDOMAIN  0x00004000
39 #define BIT_USER        0x00008000
40 #define BIT_LIST        0x00010000
41 #define BIT_MODIFY      0x00020000
42 #define BIT_CREATE      0x00040000
43 #define BIT_DELETE      0x00080000
44 #define BIT_ACCPOLICY   0x00100000
45 #define BIT_ACCPOLVAL   0x00200000
46 #define BIT_ACCTCTRL    0x00400000
47 #define BIT_RESERV_7    0x00800000
48 #define BIT_IMPORT      0x01000000
49 #define BIT_EXPORT      0x02000000
50 #define BIT_FIX_INIT    0x04000000
51 #define BIT_BADPWRESET  0x08000000
52 #define BIT_LOGONHOURS  0x10000000
53
54 #define MASK_ALWAYS_GOOD        0x0000001F
55 #define MASK_USER_GOOD          0x00405FE0
56
57 /*********************************************************
58  Reset account policies to their default values and remove marker
59  ********************************************************/
60
61 static int reinit_account_policies (void) 
62 {
63         int i;
64
65         for (i=1; decode_account_policy_name(i) != NULL; i++) {
66                 uint32 policy_value;
67                 if (!account_policy_get_default(i, &policy_value)) {
68                         fprintf(stderr, "Can't get default account policy\n");
69                         return -1;
70                 }
71                 if (!account_policy_set(i, policy_value)) {
72                         fprintf(stderr, "Can't set account policy in tdb\n");
73                         return -1;
74                 }
75         }
76
77         if (!remove_account_policy_migrated()) {
78                 fprintf(stderr, "Can't remove marker from tdb\n");
79                 return -1;
80         }
81
82         return 0;
83 }
84
85 /*********************************************************
86  Print info from sam structure
87 **********************************************************/
88
89 static int print_sam_info (struct samu *sam_pwent, BOOL verbosity, BOOL smbpwdstyle)
90 {
91         uid_t uid;
92         time_t tmp;
93
94         /* TODO: chaeck if entry is a user or a workstation */
95         if (!sam_pwent) return -1;
96         
97         if (verbosity) {
98                 pstring temp;
99                 const uint8 *hours;
100                 
101                 printf ("Unix username:        %s\n", pdb_get_username(sam_pwent));
102                 printf ("NT username:          %s\n", pdb_get_nt_username(sam_pwent));
103                 printf ("Account Flags:        %s\n", pdb_encode_acct_ctrl(pdb_get_acct_ctrl(sam_pwent), NEW_PW_FORMAT_SPACE_PADDED_LEN));
104                 printf ("User SID:             %s\n",
105                         sid_string_static(pdb_get_user_sid(sam_pwent)));
106                 printf ("Primary Group SID:    %s\n",
107                         sid_string_static(pdb_get_group_sid(sam_pwent)));
108                 printf ("Full Name:            %s\n", pdb_get_fullname(sam_pwent));
109                 printf ("Home Directory:       %s\n", pdb_get_homedir(sam_pwent));
110                 printf ("HomeDir Drive:        %s\n", pdb_get_dir_drive(sam_pwent));
111                 printf ("Logon Script:         %s\n", pdb_get_logon_script(sam_pwent));
112                 printf ("Profile Path:         %s\n", pdb_get_profile_path(sam_pwent));
113                 printf ("Domain:               %s\n", pdb_get_domain(sam_pwent));
114                 printf ("Account desc:         %s\n", pdb_get_acct_desc(sam_pwent));
115                 printf ("Workstations:         %s\n", pdb_get_workstations(sam_pwent));
116                 printf ("Munged dial:          %s\n", pdb_get_munged_dial(sam_pwent));
117                 
118                 tmp = pdb_get_logon_time(sam_pwent);
119                 printf ("Logon time:           %s\n", tmp ? http_timestring(tmp) : "0");
120                 
121                 tmp = pdb_get_logoff_time(sam_pwent);
122                 printf ("Logoff time:          %s\n", tmp ? http_timestring(tmp) : "0");
123                 
124                 tmp = pdb_get_kickoff_time(sam_pwent);
125                 printf ("Kickoff time:         %s\n", tmp ? http_timestring(tmp) : "0");
126                 
127                 tmp = pdb_get_pass_last_set_time(sam_pwent);
128                 printf ("Password last set:    %s\n", tmp ? http_timestring(tmp) : "0");
129                 
130                 tmp = pdb_get_pass_can_change_time(sam_pwent);
131                 printf ("Password can change:  %s\n", tmp ? http_timestring(tmp) : "0");
132                 
133                 tmp = pdb_get_pass_must_change_time(sam_pwent);
134                 printf ("Password must change: %s\n", tmp ? http_timestring(tmp) : "0");
135
136                 tmp = pdb_get_bad_password_time(sam_pwent);
137                 printf ("Last bad password   : %s\n", tmp ? http_timestring(tmp) : "0");
138                 printf ("Bad password count  : %d\n", 
139                         pdb_get_bad_password_count(sam_pwent));
140                 
141                 hours = pdb_get_hours(sam_pwent);
142                 pdb_sethexhours(temp, hours);
143                 printf ("Logon hours         : %s\n", temp);
144                 
145         } else if (smbpwdstyle) {
146                 char lm_passwd[33];
147                 char nt_passwd[33];
148
149                 uid = nametouid(pdb_get_username(sam_pwent));
150                 pdb_sethexpwd(lm_passwd, pdb_get_lanman_passwd(sam_pwent), pdb_get_acct_ctrl(sam_pwent));
151                 pdb_sethexpwd(nt_passwd, pdb_get_nt_passwd(sam_pwent), pdb_get_acct_ctrl(sam_pwent));
152                         
153                 printf("%s:%lu:%s:%s:%s:LCT-%08X:\n",
154                        pdb_get_username(sam_pwent),
155                        (unsigned long)uid,
156                        lm_passwd,
157                        nt_passwd,
158                        pdb_encode_acct_ctrl(pdb_get_acct_ctrl(sam_pwent),NEW_PW_FORMAT_SPACE_PADDED_LEN),
159                        (uint32)pdb_get_pass_last_set_time(sam_pwent));
160         } else {
161                 uid = nametouid(pdb_get_username(sam_pwent));
162                 printf ("%s:%lu:%s\n", pdb_get_username(sam_pwent), (unsigned long)uid, 
163                         pdb_get_fullname(sam_pwent));
164         }
165
166         return 0;       
167 }
168
169 /*********************************************************
170  Get an Print User Info
171 **********************************************************/
172
173 static int print_user_info (struct pdb_methods *in, const char *username, BOOL verbosity, BOOL smbpwdstyle)
174 {
175         struct samu *sam_pwent=NULL;
176         BOOL ret;
177
178         if ( !(sam_pwent = samu_new( NULL )) ) {
179                 return -1;
180         }
181
182         ret = NT_STATUS_IS_OK(in->getsampwnam (in, sam_pwent, username));
183
184         if (ret==False) {
185                 fprintf (stderr, "Username not found!\n");
186                 TALLOC_FREE(sam_pwent);
187                 return -1;
188         }
189
190         ret=print_sam_info (sam_pwent, verbosity, smbpwdstyle);
191         TALLOC_FREE(sam_pwent);
192         
193         return ret;
194 }
195         
196 /*********************************************************
197  List Users
198 **********************************************************/
199 static int print_users_list (struct pdb_methods *in, BOOL verbosity, BOOL smbpwdstyle)
200 {
201         struct samu *sam_pwent=NULL;
202         BOOL check;
203         
204         check = NT_STATUS_IS_OK(in->setsampwent(in, False, 0));
205         if (!check) {
206                 return 1;
207         }
208
209         check = True;
210         if ( !(sam_pwent = samu_new( NULL )) ) {
211                 return 1;
212         }
213
214         while (check && NT_STATUS_IS_OK(in->getsampwent (in, sam_pwent))) {
215                 if (verbosity)
216                         printf ("---------------\n");
217                 print_sam_info (sam_pwent, verbosity, smbpwdstyle);
218                 TALLOC_FREE(sam_pwent);
219                 
220                 if ( !(sam_pwent = samu_new( NULL )) ) {
221                         check = False;
222                 }
223         }
224         if (check) 
225                 TALLOC_FREE(sam_pwent);
226         
227         in->endsampwent(in);
228         return 0;
229 }
230
231 /*********************************************************
232  Fix a list of Users for uninitialised passwords
233 **********************************************************/
234 static int fix_users_list (struct pdb_methods *in)
235 {
236         struct samu *sam_pwent=NULL;
237         BOOL check;
238         
239         check = NT_STATUS_IS_OK(in->setsampwent(in, False, 0));
240         if (!check) {
241                 return 1;
242         }
243
244         check = True;
245         if ( !(sam_pwent = samu_new( NULL )) ) {
246                 return 1;
247         }
248
249         while (check && NT_STATUS_IS_OK(in->getsampwent (in, sam_pwent))) {
250                 printf("Updating record for user %s\n", pdb_get_username(sam_pwent));
251         
252                 if (!NT_STATUS_IS_OK(pdb_update_sam_account(sam_pwent))) {
253                         printf("Update of user %s failed!\n", pdb_get_username(sam_pwent));
254                 }
255                 TALLOC_FREE(sam_pwent);
256                 if ( !(sam_pwent = samu_new( NULL )) ) {
257                         check = False;
258                 }
259                 if (!check) {
260                         fprintf(stderr, "Failed to initialise new struct samu structure (out of memory?)\n");
261                 }
262                         
263         }
264         if (check) 
265                 TALLOC_FREE(sam_pwent);
266         
267         in->endsampwent(in);
268         return 0;
269 }
270
271 /*********************************************************
272  Set User Info
273 **********************************************************/
274
275 static int set_user_info (struct pdb_methods *in, const char *username, 
276                           const char *fullname, const char *homedir, 
277                           const char *acct_desc, 
278                           const char *drive, const char *script, 
279                           const char *profile, const char *account_control,
280                           const char *user_sid, const char *group_sid,
281                           const char *user_domain,
282                           const BOOL badpw, const BOOL hours,
283                           time_t pwd_can_change, time_t pwd_must_change)
284 {
285         BOOL updated_autolock = False, updated_badpw = False;
286         struct samu *sam_pwent=NULL;
287         BOOL ret;
288         
289         if ( !(sam_pwent = samu_new( NULL )) ) {
290                 return 1;
291         }
292         
293         ret = NT_STATUS_IS_OK(in->getsampwnam (in, sam_pwent, username));
294         if (ret==False) {
295                 fprintf (stderr, "Username not found!\n");
296                 TALLOC_FREE(sam_pwent);
297                 return -1;
298         }
299
300         if (hours) {
301                 uint8 hours_array[MAX_HOURS_LEN];
302                 uint32 hours_len;
303                 
304                 hours_len = pdb_get_hours_len(sam_pwent);
305                 memset(hours_array, 0xff, hours_len);
306                 
307                 pdb_set_hours(sam_pwent, hours_array, PDB_CHANGED);
308         }
309
310         if (pwd_can_change != -1) {
311                 pdb_set_pass_can_change_time(sam_pwent, pwd_can_change, PDB_CHANGED);
312         }
313
314         if (pwd_must_change != -1) {
315                 pdb_set_pass_must_change_time(sam_pwent, pwd_must_change, PDB_CHANGED);
316         }
317
318         if (!pdb_update_autolock_flag(sam_pwent, &updated_autolock)) {
319                 DEBUG(2,("pdb_update_autolock_flag failed.\n"));
320         }
321
322         if (!pdb_update_bad_password_count(sam_pwent, &updated_badpw)) {
323                 DEBUG(2,("pdb_update_bad_password_count failed.\n"));
324         }
325
326         if (fullname)
327                 pdb_set_fullname(sam_pwent, fullname, PDB_CHANGED);
328         if (acct_desc)
329                 pdb_set_acct_desc(sam_pwent, acct_desc, PDB_CHANGED);
330         if (homedir)
331                 pdb_set_homedir(sam_pwent, homedir, PDB_CHANGED);
332         if (drive)
333                 pdb_set_dir_drive(sam_pwent,drive, PDB_CHANGED);
334         if (script)
335                 pdb_set_logon_script(sam_pwent, script, PDB_CHANGED);
336         if (profile)
337                 pdb_set_profile_path (sam_pwent, profile, PDB_CHANGED);
338         if (user_domain)
339                 pdb_set_domain(sam_pwent, user_domain, PDB_CHANGED);
340
341         if (account_control) {
342                 uint16 not_settable = ~(ACB_DISABLED|ACB_HOMDIRREQ|ACB_PWNOTREQ|
343                                         ACB_PWNOEXP|ACB_AUTOLOCK);
344
345                 uint16 newflag = pdb_decode_acct_ctrl(account_control);
346
347                 if (newflag & not_settable) {
348                         fprintf(stderr, "Can only set [NDHLX] flags\n");
349                         TALLOC_FREE(sam_pwent);
350                         return -1;
351                 }
352
353                 pdb_set_acct_ctrl(sam_pwent,
354                                   (pdb_get_acct_ctrl(sam_pwent) & not_settable) | newflag,
355                                   PDB_CHANGED);
356         }
357         if (user_sid) {
358                 DOM_SID u_sid;
359                 if (!string_to_sid(&u_sid, user_sid)) {
360                         /* not a complete sid, may be a RID, try building a SID */
361                         int u_rid;
362                         
363                         if (sscanf(user_sid, "%d", &u_rid) != 1) {
364                                 fprintf(stderr, "Error passed string is not a complete user SID or RID!\n");
365                                 return -1;
366                         }
367                         sid_copy(&u_sid, get_global_sam_sid());
368                         sid_append_rid(&u_sid, u_rid);
369                 }
370                 pdb_set_user_sid (sam_pwent, &u_sid, PDB_CHANGED);
371         }
372         if (group_sid) {
373                 DOM_SID g_sid;
374                 if (!string_to_sid(&g_sid, group_sid)) {
375                         /* not a complete sid, may be a RID, try building a SID */
376                         int g_rid;
377                         
378                         if (sscanf(group_sid, "%d", &g_rid) != 1) {
379                                 fprintf(stderr, "Error passed string is not a complete group SID or RID!\n");
380                                 return -1;
381                         }
382                         sid_copy(&g_sid, get_global_sam_sid());
383                         sid_append_rid(&g_sid, g_rid);
384                 }
385                 pdb_set_group_sid (sam_pwent, &g_sid, PDB_CHANGED);
386         }
387
388         if (badpw) {
389                 pdb_set_bad_password_count(sam_pwent, 0, PDB_CHANGED);
390                 pdb_set_bad_password_time(sam_pwent, 0, PDB_CHANGED);
391         }
392
393         if (NT_STATUS_IS_OK(in->update_sam_account (in, sam_pwent)))
394                 print_user_info (in, username, True, False);
395         else {
396                 fprintf (stderr, "Unable to modify entry!\n");
397                 TALLOC_FREE(sam_pwent);
398                 return -1;
399         }
400         TALLOC_FREE(sam_pwent);
401         return 0;
402 }
403
404 /*********************************************************
405  Add New User
406 **********************************************************/
407 static int new_user (struct pdb_methods *in, const char *username,
408                         const char *fullname, const char *homedir,
409                         const char *drive, const char *script,
410                         const char *profile, char *user_sid, char *group_sid,
411                         BOOL stdin_get)
412 {
413         struct samu *sam_pwent=NULL;
414
415         char *password1, *password2;
416         int rc_pwd_cmp;
417
418         get_global_sam_sid();
419
420         if (!NT_STATUS_IS_OK(pdb_init_sam_new(&sam_pwent, username))) {
421                 DEBUG(0, ("could not create account to add new user %s\n", username));
422                 return -1;
423         }
424
425         password1 = get_pass( "new password:", stdin_get);
426         password2 = get_pass( "retype new password:", stdin_get);
427         if ((rc_pwd_cmp = strcmp (password1, password2))) {
428                 fprintf (stderr, "Passwords do not match!\n");
429                 TALLOC_FREE(sam_pwent);
430         } else {
431                 pdb_set_plaintext_passwd(sam_pwent, password1);
432         }
433
434         memset(password1, 0, strlen(password1));
435         SAFE_FREE(password1);
436         memset(password2, 0, strlen(password2));
437         SAFE_FREE(password2);
438
439         /* pwds do _not_ match? */
440         if (rc_pwd_cmp)
441                 return -1;
442
443         if (fullname)
444                 pdb_set_fullname(sam_pwent, fullname, PDB_CHANGED);
445         if (homedir)
446                 pdb_set_homedir (sam_pwent, homedir, PDB_CHANGED);
447         if (drive)
448                 pdb_set_dir_drive (sam_pwent, drive, PDB_CHANGED);
449         if (script)
450                 pdb_set_logon_script(sam_pwent, script, PDB_CHANGED);
451         if (profile)
452                 pdb_set_profile_path (sam_pwent, profile, PDB_CHANGED);
453         if (user_sid) {
454                 DOM_SID u_sid;
455                 if (!string_to_sid(&u_sid, user_sid)) {
456                         /* not a complete sid, may be a RID, try building a SID */
457                         int u_rid;
458                         
459                         if (sscanf(user_sid, "%d", &u_rid) != 1) {
460                                 fprintf(stderr, "Error passed string is not a complete user SID or RID!\n");
461                                 return -1;
462                         }
463                         sid_copy(&u_sid, get_global_sam_sid());
464                         sid_append_rid(&u_sid, u_rid);
465                 }
466                 pdb_set_user_sid (sam_pwent, &u_sid, PDB_CHANGED);
467         }
468         if (group_sid) {
469                 DOM_SID g_sid;
470                 if (!string_to_sid(&g_sid, group_sid)) {
471                         /* not a complete sid, may be a RID, try building a SID */
472                         int g_rid;
473                         
474                         if (sscanf(group_sid, "%d", &g_rid) != 1) {
475                                 fprintf(stderr, "Error passed string is not a complete group SID or RID!\n");
476                                 return -1;
477                         }
478                         sid_copy(&g_sid, get_global_sam_sid());
479                         sid_append_rid(&g_sid, g_rid);
480                 }
481                 pdb_set_group_sid (sam_pwent, &g_sid, PDB_CHANGED);
482         }
483         
484         pdb_set_acct_ctrl (sam_pwent, ACB_NORMAL, PDB_CHANGED);
485         
486         if (NT_STATUS_IS_OK(in->add_sam_account (in, sam_pwent))) { 
487                 print_user_info (in, username, True, False);
488         } else {
489                 fprintf (stderr, "Unable to add user! (does it already exist?)\n");
490                 TALLOC_FREE(sam_pwent);
491                 return -1;
492         }
493         TALLOC_FREE(sam_pwent);
494         return 0;
495 }
496
497 /*********************************************************
498  Add New Machine
499 **********************************************************/
500
501 static int new_machine (struct pdb_methods *in, const char *machine_in)
502 {
503         struct samu *sam_pwent=NULL;
504         fstring machinename;
505         fstring machineaccount;
506         struct passwd  *pwd = NULL;
507         
508         get_global_sam_sid();
509
510         fstrcpy(machinename, machine_in); 
511         machinename[15]= '\0';
512
513         if (machinename[strlen (machinename) -1] == '$')
514                 machinename[strlen (machinename) -1] = '\0';
515         
516         strlower_m(machinename);
517         
518         fstrcpy(machineaccount, machinename);
519         fstrcat(machineaccount, "$");
520
521         if ((pwd = getpwnam_alloc(NULL, machineaccount))) {
522
523                 if ( !(sam_pwent = samu_new( NULL )) ) {
524                         fprintf(stderr, "Memory allocation error!\n");
525                         TALLOC_FREE(pwd);
526                         return -1;
527                 }
528
529                 if ( !NT_STATUS_IS_OK(samu_set_unix(sam_pwent, pwd)) ) {
530                         fprintf(stderr, "Could not init sam from pw\n");
531                         TALLOC_FREE(pwd);
532                         return -1;
533                 }
534
535                 TALLOC_FREE(pwd);
536         } else {
537                 if ( !(sam_pwent = samu_new( NULL )) ) {
538                         fprintf(stderr, "Could not init sam from pw\n");
539                         return -1;
540                 }
541         }
542
543         pdb_set_plaintext_passwd (sam_pwent, machinename);
544
545         pdb_set_username (sam_pwent, machineaccount, PDB_CHANGED);
546         
547         pdb_set_acct_ctrl (sam_pwent, ACB_WSTRUST, PDB_CHANGED);
548         
549         pdb_set_group_sid_from_rid(sam_pwent, DOMAIN_GROUP_RID_COMPUTERS, PDB_CHANGED);
550         
551         if (NT_STATUS_IS_OK(in->add_sam_account (in, sam_pwent))) {
552                 print_user_info (in, machineaccount, True, False);
553         } else {
554                 fprintf (stderr, "Unable to add machine! (does it already exist?)\n");
555                 TALLOC_FREE(sam_pwent);
556                 return -1;
557         }
558         TALLOC_FREE(sam_pwent);
559         return 0;
560 }
561
562 /*********************************************************
563  Delete user entry
564 **********************************************************/
565
566 static int delete_user_entry (struct pdb_methods *in, const char *username)
567 {
568         struct samu *samaccount = NULL;
569
570         if ( !(samaccount = samu_new( NULL )) ) {
571                 return -1;
572         }
573
574         if (!NT_STATUS_IS_OK(in->getsampwnam(in, samaccount, username))) {
575                 fprintf (stderr, "user %s does not exist in the passdb\n", username);
576                 return -1;
577         }
578
579         if (!NT_STATUS_IS_OK(in->delete_sam_account (in, samaccount))) {
580                 fprintf (stderr, "Unable to delete user %s\n", username);
581                 return -1;
582         }
583         return 0;
584 }
585
586 /*********************************************************
587  Delete machine entry
588 **********************************************************/
589
590 static int delete_machine_entry (struct pdb_methods *in, const char *machinename)
591 {
592         fstring name;
593         struct samu *samaccount = NULL;
594         
595         fstrcpy(name, machinename);
596         name[15] = '\0';
597         if (name[strlen(name)-1] != '$')
598                 fstrcat (name, "$");
599
600         if ( !(samaccount = samu_new( NULL )) ) {
601                 return -1;
602         }
603
604         if (!NT_STATUS_IS_OK(in->getsampwnam(in, samaccount, name))) {
605                 fprintf (stderr, "machine %s does not exist in the passdb\n", name);
606                 return -1;
607         }
608
609         if (!NT_STATUS_IS_OK(in->delete_sam_account (in, samaccount))) {
610                 fprintf (stderr, "Unable to delete machine %s\n", name);
611                 return -1;
612         }
613
614         return 0;
615 }
616
617 /*********************************************************
618  Start here.
619 **********************************************************/
620
621 int main (int argc, char **argv)
622 {
623         static BOOL list_users = False;
624         static BOOL verbose = False;
625         static BOOL spstyle = False;
626         static BOOL machine = False;
627         static BOOL add_user = False;
628         static BOOL delete_user = False;
629         static BOOL modify_user = False;
630         uint32  setparms, checkparms;
631         int opt;
632         static char *full_name = NULL;
633         static char *acct_desc = NULL;
634         static const char *user_name = NULL;
635         static char *home_dir = NULL;
636         static char *home_drive = NULL;
637         static char *backend = NULL;
638         static char *backend_in = NULL;
639         static char *backend_out = NULL;
640         static BOOL transfer_groups = False;
641         static BOOL transfer_account_policies = False;
642         static BOOL reset_account_policies = False;
643         static BOOL  force_initialised_password = False;
644         static char *logon_script = NULL;
645         static char *profile_path = NULL;
646         static char *user_domain = NULL;
647         static char *account_control = NULL;
648         static char *account_policy = NULL;
649         static char *user_sid = NULL;
650         static char *group_sid = NULL;
651         static long int account_policy_value = 0;
652         BOOL account_policy_value_set = False;
653         static BOOL badpw_reset = False;
654         static BOOL hours_reset = False;
655         static char *pwd_can_change_time = NULL;
656         static char *pwd_must_change_time = NULL;
657         static char *pwd_time_format = NULL;
658         BOOL pw_from_stdin = False;
659
660         struct pdb_methods *bdef = NULL;
661         poptContext pc;
662         struct poptOption long_options[] = {
663                 POPT_AUTOHELP
664                 {"list",        'L', POPT_ARG_NONE, &list_users, 0, "list all users", NULL},
665                 {"verbose",     'v', POPT_ARG_NONE, &verbose, 0, "be verbose", NULL },
666                 {"smbpasswd-style",     'w',POPT_ARG_NONE, &spstyle, 0, "give output in smbpasswd style", NULL},
667                 {"user",        'u', POPT_ARG_STRING, &user_name, 0, "use username", "USER" },
668                 {"account-desc",        'N', POPT_ARG_STRING, &acct_desc, 0, "set account description", NULL},
669                 {"fullname",    'f', POPT_ARG_STRING, &full_name, 0, "set full name", NULL},
670                 {"homedir",     'h', POPT_ARG_STRING, &home_dir, 0, "set home directory", NULL},
671                 {"drive",       'D', POPT_ARG_STRING, &home_drive, 0, "set home drive", NULL},
672                 {"script",      'S', POPT_ARG_STRING, &logon_script, 0, "set logon script", NULL},
673                 {"profile",     'p', POPT_ARG_STRING, &profile_path, 0, "set profile path", NULL},
674                 {"domain",      'I', POPT_ARG_STRING, &user_domain, 0, "set a users' domain", NULL},
675                 {"user SID",    'U', POPT_ARG_STRING, &user_sid, 0, "set user SID or RID", NULL},
676                 {"group SID",   'G', POPT_ARG_STRING, &group_sid, 0, "set group SID or RID", NULL},
677                 {"create",      'a', POPT_ARG_NONE, &add_user, 0, "create user", NULL},
678                 {"modify",      'r', POPT_ARG_NONE, &modify_user, 0, "modify user", NULL},
679                 {"machine",     'm', POPT_ARG_NONE, &machine, 0, "account is a machine account", NULL},
680                 {"delete",      'x', POPT_ARG_NONE, &delete_user, 0, "delete user", NULL},
681                 {"backend",     'b', POPT_ARG_STRING, &backend, 0, "use different passdb backend as default backend", NULL},
682                 {"import",      'i', POPT_ARG_STRING, &backend_in, 0, "import user accounts from this backend", NULL},
683                 {"export",      'e', POPT_ARG_STRING, &backend_out, 0, "export user accounts to this backend", NULL},
684                 {"group",       'g', POPT_ARG_NONE, &transfer_groups, 0, "use -i and -e for groups", NULL},
685                 {"policies",    'y', POPT_ARG_NONE, &transfer_account_policies, 0, "use -i and -e to move account policies between backends", NULL},
686                 {"policies-reset",      0, POPT_ARG_NONE, &reset_account_policies, 0, "restore default policies", NULL},
687                 {"account-policy",      'P', POPT_ARG_STRING, &account_policy, 0,"value of an account policy (like maximum password age)",NULL},
688                 {"value",       'C', POPT_ARG_LONG, &account_policy_value, 'C',"set the account policy to this value", NULL},
689                 {"account-control",     'c', POPT_ARG_STRING, &account_control, 0, "Values of account control", NULL},
690                 {"force-initialized-passwords", 0, POPT_ARG_NONE, &force_initialised_password, 0, "Force initialization of corrupt password strings in a passdb backend", NULL},
691                 {"bad-password-count-reset", 'z', POPT_ARG_NONE, &badpw_reset, 0, "reset bad password count", NULL},
692                 {"logon-hours-reset", 'Z', POPT_ARG_NONE, &hours_reset, 0, "reset logon hours", NULL},
693                 {"pwd-can-change-time", 0, POPT_ARG_STRING, &pwd_can_change_time, 0, "Set password can change time (unix time in seconds since 1970 if time format not provided)", NULL },
694                 {"pwd-must-change-time", 0, POPT_ARG_STRING, &pwd_must_change_time, 0, "Set password must change time (unix time in seconds since 1970 if time format not provided)", NULL },
695                 {"time-format", 0, POPT_ARG_STRING, &pwd_time_format, 0, "The time format for time parameters", NULL },
696                 {"password-from-stdin", 't', POPT_ARG_NONE, &pw_from_stdin, 0, "get password from standard in", NULL},
697                 POPT_COMMON_SAMBA
698                 POPT_TABLEEND
699         };
700         
701         load_case_tables();
702
703         setup_logging("pdbedit", True);
704         
705         pc = poptGetContext(NULL, argc, (const char **) argv, long_options,
706                             POPT_CONTEXT_KEEP_FIRST);
707         
708         while((opt = poptGetNextOpt(pc)) != -1) {
709                 switch (opt) {
710                 case 'C':
711                         account_policy_value_set = True;
712                         break;
713                 }
714         }
715
716         poptGetArg(pc); /* Drop argv[0], the program name */
717
718         if (user_name == NULL)
719                 user_name = poptGetArg(pc);
720
721         if (!lp_load(dyn_CONFIGFILE,True,False,False,True)) {
722                 fprintf(stderr, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE);
723                 exit(1);
724         }
725
726         if(!initialize_password_db(False))
727                 exit(1);
728
729         if (!init_names())
730                 exit(1);
731
732         setparms =      (backend ? BIT_BACKEND : 0) +
733                         (verbose ? BIT_VERBOSE : 0) +
734                         (spstyle ? BIT_SPSTYLE : 0) +
735                         (full_name ? BIT_FULLNAME : 0) +
736                         (home_dir ? BIT_HOMEDIR : 0) +
737                         (home_drive ? BIT_HDIRDRIVE : 0) +
738                         (logon_script ? BIT_LOGSCRIPT : 0) +
739                         (profile_path ? BIT_PROFILE : 0) +
740                         (user_domain ? BIT_USERDOMAIN : 0) +
741                         (machine ? BIT_MACHINE : 0) +
742                         (user_name ? BIT_USER : 0) +
743                         (list_users ? BIT_LIST : 0) +
744                         (force_initialised_password ? BIT_FIX_INIT : 0) +
745                         (user_sid ? BIT_USERSIDS : 0) +
746                         (group_sid ? BIT_USERSIDS : 0) +
747                         (modify_user ? BIT_MODIFY : 0) +
748                         (add_user ? BIT_CREATE : 0) +
749                         (delete_user ? BIT_DELETE : 0) +
750                         (account_control ? BIT_ACCTCTRL : 0) +
751                         (account_policy ? BIT_ACCPOLICY : 0) +
752                         (account_policy_value_set ? BIT_ACCPOLVAL : 0) +
753                         (backend_in ? BIT_IMPORT : 0) +
754                         (backend_out ? BIT_EXPORT : 0) +
755                         (badpw_reset ? BIT_BADPWRESET : 0) +
756                         (hours_reset ? BIT_LOGONHOURS : 0) +
757                         (pwd_can_change_time ? BIT_CAN_CHANGE: 0) +
758                         (pwd_must_change_time ? BIT_MUST_CHANGE: 0);
759
760         if (setparms & BIT_BACKEND) {
761                 if (!NT_STATUS_IS_OK(make_pdb_method_name( &bdef, backend ))) {
762                         fprintf(stderr, "Can't initialize passdb backend.\n");
763                         return 1;
764                 }
765         } else {
766                 if (!NT_STATUS_IS_OK(make_pdb_method_name(&bdef, lp_passdb_backend()))) {
767                         fprintf(stderr, "Can't initialize passdb backend.\n");
768                         return 1;
769                 }
770         }
771         
772         /* the lowest bit options are always accepted */
773         checkparms = setparms & ~MASK_ALWAYS_GOOD;
774
775         if (checkparms & BIT_FIX_INIT) {
776                 return fix_users_list(bdef);
777         }
778
779         /* account policy operations */
780         if ((checkparms & BIT_ACCPOLICY) && !(checkparms & ~(BIT_ACCPOLICY + BIT_ACCPOLVAL))) {
781                 uint32 value;
782                 int field = account_policy_name_to_fieldnum(account_policy);
783                 if (field == 0) {
784                         char *apn = account_policy_names_list();
785                         fprintf(stderr, "No account policy by that name\n");
786                         if (apn) {
787                                 fprintf(stderr, "Account policy names are :\n%s\n", apn);
788                         }
789                         SAFE_FREE(apn);
790                         exit(1);
791                 }
792                 if (!pdb_get_account_policy(field, &value)) {
793                         fprintf(stderr, "valid account policy, but unable to fetch value!\n");
794                         if (!account_policy_value_set)
795                                 exit(1);
796                 }
797                 printf("account policy \"%s\" description: %s\n", account_policy, account_policy_get_desc(field));
798                 if (account_policy_value_set) {
799                         printf("account policy \"%s\" value was: %u\n", account_policy, value);
800                         if (!pdb_set_account_policy(field, account_policy_value)) {
801                                 fprintf(stderr, "valid account policy, but unable to set value!\n");
802                                 exit(1);
803                         }
804                         printf("account policy \"%s\" value is now: %lu\n", account_policy, account_policy_value);
805                         exit(0);
806                 } else {
807                         printf("account policy \"%s\" value is: %u\n", account_policy, value);
808                         exit(0);
809                 }
810         }
811
812         if (reset_account_policies) {
813                 if (!reinit_account_policies()) {
814                         exit(1);
815                 }
816
817                 exit(0);
818         }
819
820         /* if BIT_USER is defined but nothing else then threat it as -l -u for compatibility */
821         /* fake up BIT_LIST if only BIT_USER is defined */
822         if ((checkparms & BIT_USER) && !(checkparms & ~BIT_USER)) {
823                 checkparms += BIT_LIST;
824         }
825         
826         /* modify flag is optional to maintain backwards compatibility */
827         /* fake up BIT_MODIFY if BIT_USER  and at least one of MASK_USER_GOOD is defined */
828         if (!((checkparms & ~MASK_USER_GOOD) & ~BIT_USER) && (checkparms & MASK_USER_GOOD)) {
829                 checkparms += BIT_MODIFY;
830         }
831
832         /* list users operations */
833         if (checkparms & BIT_LIST) {
834                 if (!(checkparms & ~BIT_LIST)) {
835                         return print_users_list (bdef, verbose, spstyle);
836                 }
837                 if (!(checkparms & ~(BIT_USER + BIT_LIST))) {
838                         return print_user_info (bdef, user_name, verbose, spstyle);
839                 }
840         }
841         
842         /* mask out users options */
843         checkparms &= ~MASK_USER_GOOD;
844
845         /* if bad password count is reset, we must be modifying */
846         if (checkparms & BIT_BADPWRESET) {
847                 checkparms |= BIT_MODIFY;
848                 checkparms &= ~BIT_BADPWRESET;
849         }
850
851         /* if logon hours is reset, must modify */
852         if (checkparms & BIT_LOGONHOURS) {
853                 checkparms |= BIT_MODIFY;
854                 checkparms &= ~BIT_LOGONHOURS;
855         }
856         
857         /* account operation */
858         if ((checkparms & BIT_CREATE) || (checkparms & BIT_MODIFY) || (checkparms & BIT_DELETE)) {
859                 /* check use of -u option */
860                 if (!(checkparms & BIT_USER)) {
861                         fprintf (stderr, "Username not specified! (use -u option)\n");
862                         return -1;
863                 }
864
865                 /* account creation operations */
866                 if (!(checkparms & ~(BIT_CREATE + BIT_USER + BIT_MACHINE))) {
867                         if (checkparms & BIT_MACHINE) {
868                                 return new_machine (bdef, user_name);
869                         } else {
870                                 return new_user (bdef, user_name, full_name, home_dir, 
871                                                  home_drive, logon_script, 
872                                                  profile_path, user_sid, group_sid,
873                                                  pw_from_stdin);
874                         }
875                 }
876
877                 /* account deletion operations */
878                 if (!(checkparms & ~(BIT_DELETE + BIT_USER + BIT_MACHINE))) {
879                         if (checkparms & BIT_MACHINE) {
880                                 return delete_machine_entry (bdef, user_name);
881                         } else {
882                                 return delete_user_entry (bdef, user_name);
883                         }
884                 }
885
886                 /* account modification operations */
887                 if (!(checkparms & ~(BIT_MODIFY + BIT_USER))) {
888                         time_t pwd_can_change = -1;
889                         time_t pwd_must_change = -1;
890                         const char *errstr;
891
892                         if (pwd_can_change_time) {
893                                 errstr = "can";
894                                 if (pwd_time_format) {
895                                         struct tm tm;
896                                         char *ret;
897
898                                         memset(&tm, 0, sizeof(struct tm));
899                                         ret = strptime(pwd_can_change_time, pwd_time_format, &tm);
900                                         if (ret == NULL || *ret != '\0') {
901                                                 goto error;
902                                         }
903
904                                         pwd_can_change = mktime(&tm);
905
906                                         if (pwd_can_change == -1) {
907                                                 goto error;
908                                         }
909                                 } else { /* assume it is unix time */
910                                         errno = 0;
911                                         pwd_can_change = strtol(pwd_can_change_time, NULL, 10);
912                                         if (errno) {
913                                                 goto error;
914                                         }
915                                 }       
916                         }
917                         if (pwd_must_change_time) {
918                                 errstr = "must";
919                                 if (pwd_time_format) {
920                                         struct tm tm;
921                                         char *ret;
922
923                                         memset(&tm, 0, sizeof(struct tm));
924                                         ret = strptime(pwd_must_change_time, pwd_time_format, &tm);
925                                         if (ret == NULL || *ret != '\0') {
926                                                 goto error;
927                                         }
928
929                                         pwd_must_change = mktime(&tm);
930
931                                         if (pwd_must_change == -1) {
932                                                 goto error;
933                                         }
934                                 } else { /* assume it is unix time */
935                                         errno = 0;
936                                         pwd_must_change = strtol(pwd_must_change_time, NULL, 10);
937                                         if (errno) {
938                                                 goto error;
939                                         }
940                                 }       
941                         }
942                         return set_user_info (bdef, user_name, full_name,
943                                               home_dir,
944                                               acct_desc,
945                                               home_drive,
946                                               logon_script,
947                                               profile_path, account_control,
948                                               user_sid, group_sid,
949                                               user_domain,
950                                               badpw_reset, hours_reset,
951                                               pwd_can_change, pwd_must_change);
952 error:
953                         fprintf (stderr, "Error parsing the time in pwd-%s-change-time!\n", errstr);
954                         return -1;
955                 }
956         }
957
958         if (setparms >= 0x20) {
959                 fprintf (stderr, "Incompatible or insufficient options on command line!\n");
960         }
961         poptPrintHelp(pc, stderr, 0);
962
963         return 1;
964 }