a86ea2ef5f43f6ee8c4afa941803515cfd5249c4
[tprouty/samba.git] / source / utils / pdbedit.c
1 /*
2  * Unix SMB/Netbios implementation. Version 1.9. tdbedit module. Copyright
3  * (C) Simo Sorce 2000
4  * 
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License as published by the Free
7  * Software Foundation; either version 2 of the License, or (at your option)
8  * any later version.
9  * 
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13  * more details.
14  * 
15  * You should have received a copy of the GNU General Public License along with
16  * this program; if not, write to the Free Software Foundation, Inc., 675
17  * Mass Ave, Cambridge, MA 02139, USA.
18  */
19
20 /* base uid for trust accounts is set to 60000 ! 
21  * May be we should add the defines in smb.h to make it possible having 
22  * different values on different platforms?
23  */
24
25 #define BASE_MACHINE_UID 60000
26 #define MAX_MACHINE_UID 65500 /* 5500 trust acconts aren't enough? */
27
28 #include "includes.h"
29
30 extern pstring global_myname;
31 extern int DEBUGLEVEL;
32
33 /*
34  * Next two lines needed for SunOS and don't
35  * hurt anything else...
36  */
37 extern char *optarg;
38 extern int optind;
39
40 /*********************************************************
41  Print command usage on stderr and die.
42 **********************************************************/
43 static void usage(void)
44 {
45         if (getuid() == 0) {
46                 printf("tdbedit options\n");
47         } else {
48                 printf("You need to be root to use this tool!\n");
49         }
50         printf("(actually to add a user you need to use smbpasswd)\n");
51         printf("options:\n");
52         printf("  -l                   list usernames\n");
53         printf("     -v                verbose output\n");
54         printf("     -w                smbpasswd file style\n");
55         printf("  -u username          print user's info\n");
56         printf("     -f fullname       set Full Name\n");
57         printf("     -h homedir        set home directory\n");
58         printf("     -d drive          set home dir drive\n");
59         printf("     -s script         set logon script\n");
60         printf("     -p profile        set profile path\n");
61         printf("  -a                   create new account\n");
62         printf("     -m                it is a machine trust\n");
63         printf("  -x                   delete this user\n");
64         printf("  -i file              import account from file (smbpasswd style)\n");
65         exit(1);
66 }
67 /*********************************************************
68  Print info from sam structure
69 **********************************************************/
70 static int print_sam_info (SAM_ACCOUNT *sam_pwent, BOOL verbosity, BOOL smbpwdstyle)
71 {
72         /* TODO: chaeck if entry is a user or a workstation */
73         if (!sam_pwent) return -1;
74         
75         if (verbosity)
76         {
77                 printf ("username:       %s\n", sam_pwent->username);
78                 printf ("user ID/Group:  %d/%d\n", sam_pwent->uid,
79                                                   sam_pwent->gid);
80                 printf ("user RID/GRID:  %d/%d\n", sam_pwent->user_rid,
81                                                   sam_pwent->group_rid);
82                 printf ("Full Name:      %s\n", sam_pwent->full_name);
83                 printf ("Home Directory: %s\n", sam_pwent->home_dir);
84                 printf ("HomeDir Drive:  %s\n", sam_pwent->dir_drive);
85                 printf ("Logon Script:   %s\n", sam_pwent->logon_script);
86                 printf ("Profile Path:   %s\n", sam_pwent->profile_path);
87         }
88         else if (smbpwdstyle)
89         {
90                 char lm_passwd[33];
91                 char nt_passwd[33];
92                 pdb_sethexpwd(lm_passwd, pdb_get_lanman_passwd(sam_pwent), pdb_get_acct_ctrl(sam_pwent));
93                 pdb_sethexpwd(nt_passwd, pdb_get_nt_passwd(sam_pwent), pdb_get_acct_ctrl(sam_pwent));
94                 
95                 printf ("%s:%d:%s:%s:%s:LCT-%08x:\n",
96                         pdb_get_username(sam_pwent),
97                         pdb_get_uid(sam_pwent),
98                         lm_passwd,
99                         nt_passwd,
100                         pdb_encode_acct_ctrl(pdb_get_acct_ctrl(sam_pwent),NEW_PW_FORMAT_SPACE_PADDED_LEN),
101                         (uint32)pdb_get_pass_last_set_time(sam_pwent));
102         }
103         else
104         {
105                 printf ("%s:%d:%s\n", sam_pwent->username, sam_pwent->uid, sam_pwent->full_name);
106         }       
107         
108         return 0;       
109 }
110
111 /*********************************************************
112  Get an Print User Info
113 **********************************************************/
114 static int print_user_info (char *username, BOOL verbosity, BOOL smbpwdstyle)
115 {
116         SAM_ACCOUNT *sam_pwent;
117         
118         sam_pwent = pdb_getsampwnam (username);
119         if (sam_pwent) return print_sam_info (sam_pwent, verbosity, smbpwdstyle);
120         else fprintf (stderr, "Username not found!\n");
121         return -1;
122 }
123         
124 /*********************************************************
125  List Users
126 **********************************************************/
127 static int print_users_list (BOOL verbosity, BOOL smbpwdstyle)
128 {
129         SAM_ACCOUNT *sam_pwent;
130         BOOL ret;
131         
132         ret = pdb_setsampwent(False);
133         if (ret && errno == ENOENT) {
134                 fprintf (stderr,"Password database not found!\n");
135                 exit(1);
136         }
137
138         while ((sam_pwent = pdb_getsampwent ()))
139         {
140                 if (verbosity) printf ("---------------\n");
141                 print_sam_info (sam_pwent, verbosity, smbpwdstyle);
142         }
143         
144         pdb_endsampwent ();
145         return 0;
146 }
147
148 /*********************************************************
149  Set User Info
150 **********************************************************/
151 static int set_user_info (char *username, char *fullname, char *homedir, char *drive, char *script, char *profile)
152 {
153         SAM_ACCOUNT *sam_pwent;
154         
155         sam_pwent = pdb_getsampwnam (username);
156         if (!sam_pwent)
157         {
158                 fprintf (stderr, "Username not found!\n");
159                 return -1;
160         }
161         
162         if (fullname) sam_pwent->full_name = fullname;
163         if (homedir) sam_pwent->home_dir = homedir;
164         if (drive) sam_pwent->dir_drive = drive;
165         if (script) sam_pwent->logon_script = script;
166         if (profile) sam_pwent->profile_path = profile;
167         
168         if (pdb_update_sam_account (sam_pwent, TRUE)) print_user_info (username, TRUE, FALSE);
169         else
170         {
171                 fprintf (stderr, "Unable to modify entry!\n");
172                 return -1;
173         }
174         return 0;
175 }
176
177 /*********************************************************
178  Add New User
179 **********************************************************/
180 static int new_user (char *username, char *fullname, char *homedir, char *drive, char *script, char *profile)
181 {
182         SAM_ACCOUNT sam_pwent;
183         struct passwd  *pwd = NULL;
184         uchar new_p16[16];
185         uchar new_nt_p16[16];
186         char *password1, *password2;
187         
188         if (pdb_getsampwnam (username))
189         {
190                 fprintf (stderr, "Username already exist in database!\n");
191                 return -1;
192         }
193
194         if (!(pwd = sys_getpwnam(username)))
195         {
196                 fprintf (stderr, "User %s does not exist in system passwd!\n", username);
197                 return -1;
198         }
199         
200         password1 = getpass("new password:");
201         password2 = getpass("retype new password:");
202         if (strcmp (password1, password2))
203         {
204                  fprintf (stderr, "Passwords does not match!\n");
205                  return -1;
206         }
207         nt_lm_owf_gen (password1, new_nt_p16, new_p16);
208         
209         sam_pwent.username = username;
210         if (fullname) sam_pwent.full_name = fullname;
211         if (homedir) sam_pwent.home_dir = homedir;
212         if (drive) sam_pwent.dir_drive = drive;
213         if (script) sam_pwent.logon_script = script;
214         if (profile) sam_pwent.profile_path = profile;
215         
216         /* TODO: Check uid not being in MACHINE UID range!! */
217         sam_pwent.uid = pwd->pw_uid;
218         sam_pwent.gid = pwd->pw_gid;
219         sam_pwent.user_rid = pdb_uid_to_user_rid (pwd->pw_uid);
220         sam_pwent.group_rid = pdb_gid_to_group_rid (pwd->pw_gid);
221         sam_pwent.lm_pw = new_p16;
222         sam_pwent.nt_pw = new_nt_p16;
223         sam_pwent.acct_ctrl = ACB_NORMAL;
224         
225         if (pdb_add_sam_account (&sam_pwent)) print_user_info (username, TRUE, FALSE);
226         else
227         {
228                 fprintf (stderr, "Unable to add user!\n");
229                 return -1;
230         }
231         return 0;
232 }
233
234 /*********************************************************
235  Add New Machine
236 **********************************************************/
237 static int new_machine (char *machinename)
238 {
239         SAM_ACCOUNT sam_pwent;
240         uchar new_p16[16];
241         uchar new_nt_p16[16];
242         char name[16];
243         char *password = NULL;
244         uid_t uid;
245
246         if (machinename[strlen (machinename) -1] == '$') machinename[strlen (machinename) -1] = '\0';
247         
248         safe_strcpy (name, machinename, 16);
249         safe_strcat (name, "$", 16);
250         
251         string_set (&password, machinename);
252         strlower(password);
253         nt_lm_owf_gen (password, new_nt_p16, new_p16);
254         
255         sam_pwent.username = name;
256
257         for (uid=BASE_MACHINE_UID; uid<=MAX_MACHINE_UID; uid++) if (!(pdb_getsampwuid (uid))) break;
258         if (uid>MAX_MACHINE_UID)
259         {
260                 fprintf (stderr, "No more free UIDs available to Machine accounts!\n");
261                 return -1;
262         }
263         sam_pwent.uid = uid;
264         sam_pwent.gid = BASE_MACHINE_UID; /* TODO: set there more appropriate value!! */
265         sam_pwent.user_rid = pdb_uid_to_user_rid (uid);
266         sam_pwent.group_rid = pdb_gid_to_group_rid (BASE_MACHINE_UID);
267         sam_pwent.lm_pw = new_p16;
268         sam_pwent.nt_pw = new_nt_p16;
269         sam_pwent.acct_ctrl = ACB_WSTRUST;
270         
271         if (pdb_add_sam_account (&sam_pwent)) print_user_info (name, TRUE, FALSE);
272         else
273         {
274                 fprintf (stderr, "Unable to add machine!\n");
275                 return -1;
276         }
277         return 0;
278 }
279
280 /*********************************************************
281  Delete user entry
282 **********************************************************/
283 static int delete_user_entry (char *username)
284 {
285         return pdb_delete_sam_account (username);
286 }
287
288 /*********************************************************
289  Delete machine entry
290 **********************************************************/
291 static int delete_machine_entry (char *machinename)
292 {
293         char name[16];
294         
295         safe_strcpy (name, machinename, 16);
296         if (name[strlen(name)] != '$')
297         {
298                 safe_strcat (name, "$", 16);
299         }
300         return pdb_delete_sam_account (name);
301 }
302
303 /*********************************************************
304  Import smbpasswd style file
305 **********************************************************/
306 static int import_users (char *filename)
307 {
308         FILE *fp = NULL;
309         SAM_ACCOUNT sam_pwent;
310         static pstring  user_name;
311         static unsigned char smbpwd[16];
312         static unsigned char smbntpwd[16];
313         char linebuf[256];
314         size_t linebuf_len;
315         unsigned char c;
316         unsigned char *p;
317         long uidval;
318         int line = 0;
319         int good = 0;
320
321         if((fp = sys_fopen(filename, "rb")) == NULL)
322         {
323                 fprintf (stderr, "%s\n", strerror (ferror (fp)));
324                 return -1;
325         }
326         
327         while (!feof(fp))
328         {
329                 /*Get a new line*/
330                 linebuf[0] = '\0';
331                 fgets(linebuf, 256, fp);
332                 if (ferror(fp))
333                 {
334                         fprintf (stderr, "%s\n", strerror (ferror (fp)));
335                         return -1;
336                 }
337                 if ((linebuf_len = strlen(linebuf)) == 0)
338                 {
339                         line++;
340                         continue;
341                 }
342                 if (linebuf[linebuf_len - 1] != '\n')
343                 {
344                         c = '\0';
345                         while (!ferror(fp) && !feof(fp))
346                         {
347                                 c = fgetc(fp);
348                                 if (c == '\n') break;
349                         }
350                 }
351                 else linebuf[linebuf_len - 1] = '\0';
352                 linebuf[linebuf_len] = '\0';
353                 if ((linebuf[0] == 0) && feof(fp))
354                 {
355                         /*end of file!!*/
356                         return 0;
357                 }
358                 line++;
359                 if (linebuf[0] == '#' || linebuf[0] == '\0') continue;
360                 
361                 pdb_init_sam (&sam_pwent);
362                 sam_pwent.acct_ctrl = ACB_NORMAL;
363                 
364                 /* Get user name */
365                 p = (unsigned char *) strchr(linebuf, ':');
366                 if (p == NULL)
367                 {
368                         fprintf (stderr, "Error: malformed password entry at line %d !!\n", line);
369                         continue;
370                 }
371                 strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
372                 user_name[PTR_DIFF(p, linebuf)] = '\0';
373
374                 /* Get smb uid. */
375                 p++;
376                 if(*p == '-')
377                 {
378                         fprintf (stderr, "Error: negative uid at line %d\n", line);
379                         continue;
380                 }
381                 if (!isdigit(*p))
382                 {
383                         fprintf (stderr, "Error: malformed password entry at line %d (uid not number)\n", line);
384                         continue;
385                 }
386                 uidval = atoi((char *) p);
387                 while (*p && isdigit(*p)) p++;
388                 if (*p != ':')
389                 {
390                         fprintf (stderr, "Error: malformed password entry at line %d (no : after uid)\n", line);
391                         continue;
392                 }
393
394                 sam_pwent.username = user_name;
395                 sam_pwent.uid = uidval;
396                 
397                 /* Get passwords */
398                 p++;
399                 if (*p == '*' || *p == 'X')
400                 {
401                         /* Password deliberately invalid */
402                         fprintf (stderr, "Warning: entry invalidated for user %s\n", user_name);
403                         sam_pwent.lm_pw = NULL;
404                         sam_pwent.nt_pw = NULL;
405                         sam_pwent.acct_ctrl |= ACB_DISABLED;
406                 }
407                 else
408                 {
409                         if (linebuf_len < (PTR_DIFF(p, linebuf) + 33))
410                         {
411                                 fprintf (stderr, "Error: malformed password entry at line %d (password too short)\n",line);
412                                 continue;
413                         }
414                         if (p[32] != ':')
415                         {
416                                 fprintf (stderr, "Error: malformed password entry at line %d (no terminating :)\n",line);
417                                 continue;
418                         }
419                         if (!strncasecmp((char *) p, "NO PASSWORD", 11))
420                         {
421                                 sam_pwent.lm_pw = NULL;
422                                 sam_pwent.acct_ctrl |= ACB_PWNOTREQ;
423                         }
424                         else
425                         {
426                                 if (!pdb_gethexpwd((char *)p, smbpwd))
427                                 {
428                                         fprintf (stderr, "Error: malformed Lanman password entry at line %d (non hex chars)\n", line);
429                                         continue;
430                                 }
431                                 sam_pwent.lm_pw = smbpwd;
432                         }
433                         /* NT password */
434                         sam_pwent.nt_pw = NULL;
435                         p += 33;
436                         if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':'))
437                         {
438                                 if (*p != '*' && *p != 'X')
439                                 {
440                                         if (pdb_gethexpwd((char *)p,smbntpwd))
441                                         {
442                                                 sam_pwent.nt_pw = smbntpwd;
443                                         }
444                                 }
445                                 p += 33;
446                         }
447                 }
448
449                 /* Get ACCT_CTRL field if any */
450                 if (*p == '[')
451                 {
452                         unsigned char *end_p = (unsigned char *)strchr((char *)p, ']');
453                         
454                         sam_pwent.acct_ctrl = pdb_decode_acct_ctrl((char*)p);
455                         if(sam_pwent.acct_ctrl == 0) sam_pwent.acct_ctrl = ACB_NORMAL;
456                         
457                         /* Get last change time */
458                         if(end_p) p = end_p + 1;
459                         if(*p == ':')
460                         {
461                                 p++;
462                                 if(*p && (StrnCaseCmp((char *)p, "LCT-", 4)==0))
463                                 {
464                                         int i;
465                                         
466                                         p += 4;
467                                         for(i = 0; i < 8; i++)
468                                         {
469                                                 if(p[i] == '\0' || !isxdigit(p[i])) break;
470                                         }
471                                         if(i == 8)
472                                         {
473                                                 sam_pwent.pass_last_set_time = (time_t)strtol((char *)p, NULL, 16);
474                                         }
475                                 }
476                         }
477                 }
478
479                 /* Test if workstation */
480                 else
481                 {
482                         if(sam_pwent.username[strlen(sam_pwent.username) - 1] == '$')
483                         {
484                                 sam_pwent.acct_ctrl &= ~ACB_NORMAL;
485                                 sam_pwent.acct_ctrl |= ACB_WSTRUST;
486                         }
487                 }
488                 if (sam_pwent.acct_ctrl & ACB_WSTRUST)
489                 {
490                         if (!(BASE_MACHINE_UID <= uidval <= MAX_MACHINE_UID))
491                         {
492                                 fprintf (stderr, "Warning: Machine UID out of normal range %d-%d\n",
493                                                  BASE_MACHINE_UID,
494                                                  MAX_MACHINE_UID);
495                         }
496                         sam_pwent.gid = BASE_MACHINE_UID;
497                 }
498         
499                 /* Test if user is valid */
500                 if (sam_pwent.acct_ctrl & ACB_NORMAL)
501                 {
502                         struct passwd  *pwd = NULL;
503
504                         if (pdb_getsampwnam (user_name))
505                         {
506                                 fprintf (stderr, "Error: Username already exist in database!\n");
507                                 continue;
508                         }
509                         if (!(pwd = sys_getpwnam(user_name)))
510                         {
511                                 fprintf (stderr, "Error: User %s does not exist in system passwd!\n", user_name);
512                                 continue;
513                         }
514                         sam_pwent.gid = pwd->pw_gid;
515                 }
516
517                 /* Fill in sam_pwent structure */
518                 sam_pwent.user_rid = pdb_uid_to_user_rid (sam_pwent.uid);
519                 sam_pwent.group_rid = pdb_gid_to_group_rid (sam_pwent.gid);
520                 /* TODO: set also full_name, home_dir, dir_drive, logon_script, profile_path, ecc...
521                  * when defaults will be available (after passdb redesign)
522                  * let them blank just now they are not used anyway
523                  */
524                                          
525                  /* Now ADD the entry */
526                 if (!(pdb_add_sam_account (&sam_pwent)))
527                 {
528                         fprintf (stderr, "Unable to add user entry!\n");
529                         continue;
530                 }
531                 printf ("%s imported!\n", user_name);
532                 good++;
533         }
534         printf ("%d lines read.\n%d entryes imported\n", line, good);
535         
536         return 0;
537 }
538
539 /*********************************************************
540  Start here.
541 **********************************************************/
542 int main (int argc, char **argv)
543 {
544         int ch;
545         static pstring servicesf = CONFIGFILE;
546         BOOL list_users = FALSE;
547         BOOL verbose = FALSE;
548         BOOL spstyle = FALSE;
549         BOOL setparms = FALSE;
550         BOOL machine = FALSE;
551         BOOL add_user = FALSE;
552         BOOL delete_user = FALSE;
553         BOOL import = FALSE;
554         char *user_name = NULL;
555         char *full_name = NULL;
556         char *home_dir = NULL;
557         char *home_drive = NULL;
558         char *logon_script = NULL;
559         char *profile_path = NULL;
560         char *smbpasswd = NULL;
561
562         TimeInit();
563         
564         setup_logging("tdbedit", True);
565
566         charset_initialise();
567
568         if (argc < 2)
569
570         {
571                 usage();
572                 return 0;
573         }
574         
575         if(!initialize_password_db(True)) {
576                 fprintf(stderr, "Can't setup password database vectors.\n");
577                 exit(1);
578         }
579         
580         if (!lp_load(servicesf,True,False,False)) {
581                 fprintf(stderr, "Can't load %s - run testparm to debug it\n", 
582                         servicesf);
583                 exit(1);
584         }
585         
586         while ((ch = getopt(argc, argv, "ad:f:h:i:lmp:s:u:vwx")) != EOF) {
587                 switch(ch) {
588                 case 'a':
589                         add_user = TRUE;
590                         break;
591                 case 'm':
592                         machine = TRUE;
593                         break;
594                 case 'l':
595                         list_users = TRUE;
596                         break;
597                 case 'v':
598                         verbose = TRUE;
599                         break;
600                 case 'w':
601                         spstyle = TRUE;
602                         break;
603                 case 'u':
604                         user_name = optarg;
605                         break;
606                 case 'f':
607                         setparms = TRUE;
608                         full_name = optarg;
609                         break;
610                 case 'h':
611                         setparms = TRUE;
612                         home_dir = optarg;
613                         break;
614                 case 'd':
615                         setparms = TRUE;
616                         home_drive = optarg;
617                         break;
618                 case 's':
619                         setparms = TRUE;
620                         logon_script = optarg;
621                         break;
622                 case 'p':
623                         setparms = TRUE;
624                         profile_path = optarg;
625                         break;
626                 case 'x':
627                         delete_user = TRUE;
628                         break;
629                 case 'i':
630                         import = TRUE;
631                         smbpasswd = optarg;
632                         break;
633                 default:
634                         usage();
635                 }
636         }
637         if (((add_user?1:0) + (delete_user?1:0) + (list_users?1:0) + (import?1:0) + (setparms?1:0)) > 1)
638         {
639                 fprintf (stderr, "Incompatible options on command line!\n");
640                 usage();
641                 exit(1);
642         }
643
644         if (add_user) 
645         {
646                 if (!user_name)
647                 {
648                         fprintf (stderr, "Username not specified! (use -u option)\n");
649                         return -1;
650                 }
651                 if (machine) return new_machine (user_name);
652                 else return new_user (user_name, full_name, home_dir, home_drive, logon_script, profile_path);
653         }
654
655         if (delete_user)
656         {
657                 if (!user_name)
658                 {
659                         fprintf (stderr, "Username not specified! (use -u option)\n");
660                         return -1;
661                 }
662                 if (machine) return delete_machine_entry (user_name);
663                 else return delete_user_entry (user_name);
664         }
665         
666         if (user_name) 
667         {
668                 if (setparms) set_user_info (   user_name,
669                                                 full_name,
670                                                 home_dir,
671                                                 home_drive,
672                                                 logon_script,
673                                                 profile_path);
674                                                 
675                 else return print_user_info (user_name, verbose, spstyle);
676                 
677                 return 0;
678         }
679
680         
681         if (list_users) 
682                 return print_users_list (verbose, spstyle);
683         
684         if (import) 
685                 return import_users (smbpasswd); 
686         
687         usage();
688
689         return 0;
690 }
691
692