Started a cleanup of smbpasswd related stuff. I've created a new file
[samba.git] / source3 / 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 accounts 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                 smbpasswd_sethexpwd(lm_passwd, 
93                                     pdb_get_lanman_passwd(sam_pwent), 
94                                     pdb_get_acct_ctrl(sam_pwent));
95                 smbpasswd_sethexpwd(nt_passwd, 
96                                     pdb_get_nt_passwd(sam_pwent), 
97                                     pdb_get_acct_ctrl(sam_pwent));
98                 
99                 printf("%s:%d:%s:%s:%s:LCT-%08x:\n",
100                        pdb_get_username(sam_pwent),
101                        pdb_get_uid(sam_pwent),
102                        lm_passwd,
103                        nt_passwd,
104                        smbpasswd_encode_acb_info(pdb_get_acct_ctrl(sam_pwent)),
105                        (uint32)pdb_get_pass_last_set_time(sam_pwent));
106         }
107         else
108         {
109                 printf ("%s:%d:%s\n", sam_pwent->username, sam_pwent->uid, sam_pwent->full_name);
110         }       
111         
112         return 0;       
113 }
114
115 /*********************************************************
116  Get an Print User Info
117 **********************************************************/
118 static int print_user_info (char *username, BOOL verbosity, BOOL smbpwdstyle)
119 {
120         SAM_ACCOUNT *sam_pwent=NULL;
121         BOOL ret;
122         
123         pdb_init_sam(&sam_pwent);
124         
125         ret = pdb_getsampwnam (sam_pwent, username);
126
127         if (ret==False) {
128                 fprintf (stderr, "Username not found!\n");
129                 pdb_free_sam(sam_pwent);
130                 return -1;
131         }
132         
133         ret=print_sam_info (sam_pwent, verbosity, smbpwdstyle);
134         pdb_free_sam(sam_pwent);
135         
136         return ret;
137 }
138         
139 /*********************************************************
140  List Users
141 **********************************************************/
142 static int print_users_list (BOOL verbosity, BOOL smbpwdstyle)
143 {
144         SAM_ACCOUNT *sam_pwent=NULL;
145         BOOL ret;
146         
147         pdb_init_sam(&sam_pwent);
148
149         ret = pdb_setsampwent(False);
150         if (ret && errno == ENOENT) {
151                 fprintf (stderr,"Password database not found!\n");
152                 pdb_free_sam(sam_pwent);
153                 exit(1);
154         }
155
156         while ((ret = pdb_getsampwent (sam_pwent)))
157         {
158                 if (verbosity) printf ("---------------\n");
159                 print_sam_info (sam_pwent, verbosity, smbpwdstyle);
160                 pdb_reset_sam(sam_pwent);
161         }
162         
163         pdb_endsampwent ();
164         pdb_free_sam(sam_pwent);
165         return 0;
166 }
167
168 /*********************************************************
169  Set User Info
170 **********************************************************/
171 static int set_user_info (char *username, char *fullname, char *homedir, char *drive, char *script, char *profile)
172 {
173         SAM_ACCOUNT *sam_pwent=NULL;
174         BOOL ret;
175         
176         pdb_init_sam(&sam_pwent);
177         
178         ret = pdb_getsampwnam (sam_pwent, username);
179         if (ret==False)
180         {
181                 fprintf (stderr, "Username not found!\n");
182                 pdb_free_sam(sam_pwent);
183                 return -1;
184         }
185         
186         if (fullname) pdb_set_fullname(sam_pwent, fullname);
187         if (homedir) pdb_set_homedir(sam_pwent, homedir);
188         if (drive) pdb_set_dir_drive(sam_pwent,drive);
189         if (script) pdb_set_logon_script(sam_pwent, script);
190         if (profile) pdb_set_profile_path (sam_pwent, profile);
191         
192         if (pdb_update_sam_account (sam_pwent, True)) print_user_info (username, True, False);
193         else
194         {
195                 fprintf (stderr, "Unable to modify entry!\n");
196                 pdb_free_sam(sam_pwent);
197                 return -1;
198         }
199         pdb_free_sam(sam_pwent);
200         return 0;
201 }
202
203 /*********************************************************
204  Add New User
205 **********************************************************/
206 static int new_user (char *username, char *fullname, char *homedir, char *drive, char *script, char *profile)
207 {
208         SAM_ACCOUNT sam_pwent;
209         struct passwd  *pwd = NULL;
210         uchar new_p16[16];
211         uchar new_nt_p16[16];
212         char *password1, *password2;
213         
214         ZERO_STRUCT(sam_pwent);
215
216         if (pdb_getsampwnam (&sam_pwent, username))
217         {
218                 fprintf (stderr, "Username already exist in database!\n");
219                 return -1;
220         }
221
222         if (!(pwd = sys_getpwnam(username)))
223         {
224                 fprintf (stderr, "User %s does not exist in system passwd!\n", username);
225                 return -1;
226         }
227         
228         password1 = getpass("new password:");
229         password2 = getpass("retype new password:");
230         if (strcmp (password1, password2))
231         {
232                  fprintf (stderr, "Passwords does not match!\n");
233                  return -1;
234         }
235         nt_lm_owf_gen (password1, new_nt_p16, new_p16);
236         
237         pdb_set_username(&sam_pwent, username);
238         if (fullname) pdb_set_fullname(&sam_pwent, fullname);
239         if (homedir) pdb_set_homedir (&sam_pwent, homedir);
240         if (drive) pdb_set_dir_drive (&sam_pwent, drive);
241         if (script) pdb_set_logon_script(&sam_pwent, script);
242         if (profile) pdb_set_profile_path (&sam_pwent, profile);
243         
244         /* TODO: Check uid not being in MACHINE UID range!! */
245         sam_pwent.uid = pwd->pw_uid;
246         sam_pwent.gid = pwd->pw_gid;
247         sam_pwent.user_rid = pdb_uid_to_user_rid (pwd->pw_uid);
248         sam_pwent.group_rid = pdb_gid_to_group_rid (pwd->pw_gid);
249         sam_pwent.lm_pw = new_p16;
250         sam_pwent.nt_pw = new_nt_p16;
251         sam_pwent.acct_ctrl = ACB_NORMAL;
252         
253         if (pdb_add_sam_account (&sam_pwent)) print_user_info (username, True, False);
254         else
255         {
256                 fprintf (stderr, "Unable to add user!\n");
257                 return -1;
258         }
259         return 0;
260 }
261
262 /*********************************************************
263  Add New Machine
264 **********************************************************/
265 static int new_machine (char *machinename)
266 {
267         SAM_ACCOUNT sam_pwent;
268         SAM_ACCOUNT sam_trust;
269         uchar new_p16[16];
270         uchar new_nt_p16[16];
271         char name[16];
272         char *password = NULL;
273         uid_t uid;
274
275         if (machinename[strlen (machinename) -1] == '$') machinename[strlen (machinename) -1] = '\0';
276         
277         safe_strcpy (name, machinename, 16);
278         safe_strcat (name, "$", 16);
279         
280         string_set (&password, machinename);
281         strlower(password);
282         nt_lm_owf_gen (password, new_nt_p16, new_p16);
283         
284         pdb_set_username(&sam_pwent, name);
285         
286         for (uid=BASE_MACHINE_UID; uid<=MAX_MACHINE_UID; uid++)
287                 if (!(pdb_getsampwuid (&sam_trust, uid)))
288                         break;
289
290         if (uid>MAX_MACHINE_UID) {
291                 fprintf (stderr, "No more free UIDs available to Machine accounts!\n");
292                 return -1;
293         }
294
295         sam_pwent.uid = uid;
296         sam_pwent.gid = BASE_MACHINE_UID; /* TODO: set there more appropriate value!! */
297         sam_pwent.user_rid = pdb_uid_to_user_rid (uid);
298         sam_pwent.group_rid = pdb_gid_to_group_rid (BASE_MACHINE_UID);
299         sam_pwent.lm_pw = new_p16;
300         sam_pwent.nt_pw = new_nt_p16;
301         sam_pwent.acct_ctrl = ACB_WSTRUST;
302         
303         if (pdb_add_sam_account (&sam_pwent))
304                 print_user_info (name, True, False);
305         else {
306                 fprintf (stderr, "Unable to add machine!\n");
307                 return -1;
308         }
309         return 0;
310 }
311
312 /*********************************************************
313  Delete user entry
314 **********************************************************/
315 static int delete_user_entry (char *username)
316 {
317         return pdb_delete_sam_account (username);
318 }
319
320 /*********************************************************
321  Delete machine entry
322 **********************************************************/
323 static int delete_machine_entry (char *machinename)
324 {
325         char name[16];
326         
327         safe_strcpy (name, machinename, 16);
328         if (name[strlen(name)] != '$')
329         {
330                 safe_strcat (name, "$", 16);
331         }
332         return pdb_delete_sam_account (name);
333 }
334
335 /*********************************************************
336  Import smbpasswd style file
337 **********************************************************/
338 static int import_users (char *filename)
339 {
340         FILE *fp = NULL;
341         SAM_ACCOUNT sam_pwent;
342         SAM_ACCOUNT sam_test;
343         static pstring  user_name;
344         static unsigned char smbpwd[16];
345         static unsigned char smbntpwd[16];
346         char linebuf[256];
347         size_t linebuf_len;
348         unsigned char c;
349         unsigned char *p;
350         long uidval;
351         int line = 0;
352         int good = 0;
353
354         if((fp = sys_fopen(filename, "rb")) == NULL)
355         {
356                 fprintf (stderr, "%s\n", strerror (ferror (fp)));
357                 return -1;
358         }
359         
360         while (!feof(fp))
361         {
362                 /*Get a new line*/
363                 linebuf[0] = '\0';
364                 fgets(linebuf, 256, fp);
365                 if (ferror(fp))
366                 {
367                         fprintf (stderr, "%s\n", strerror (ferror (fp)));
368                         return -1;
369                 }
370                 if ((linebuf_len = strlen(linebuf)) == 0)
371                 {
372                         line++;
373                         continue;
374                 }
375                 if (linebuf[linebuf_len - 1] != '\n')
376                 {
377                         c = '\0';
378                         while (!ferror(fp) && !feof(fp))
379                         {
380                                 c = fgetc(fp);
381                                 if (c == '\n') break;
382                         }
383                 }
384                 else linebuf[linebuf_len - 1] = '\0';
385                 linebuf[linebuf_len] = '\0';
386                 if ((linebuf[0] == 0) && feof(fp))
387                 {
388                         /*end of file!!*/
389                         return 0;
390                 }
391                 line++;
392                 if (linebuf[0] == '#' || linebuf[0] == '\0') continue;
393                 
394                 /*pdb_init_sam (&sam_pwent);*/
395                 sam_pwent.acct_ctrl = ACB_NORMAL;
396                 
397                 /* Get user name */
398                 p = (unsigned char *) strchr_m(linebuf, ':');
399                 if (p == NULL)
400                 {
401                         fprintf (stderr, "Error: malformed password entry at line %d !!\n", line);
402                         continue;
403                 }
404                 strncpy(user_name, linebuf, PTR_DIFF(p, linebuf));
405                 user_name[PTR_DIFF(p, linebuf)] = '\0';
406
407                 /* Get smb uid. */
408                 p++;
409                 if(*p == '-')
410                 {
411                         fprintf (stderr, "Error: negative uid at line %d\n", line);
412                         continue;
413                 }
414                 if (!isdigit(*p))
415                 {
416                         fprintf (stderr, "Error: malformed password entry at line %d (uid not number)\n", line);
417                         continue;
418                 }
419                 uidval = atoi((char *) p);
420                 while (*p && isdigit(*p)) p++;
421                 if (*p != ':')
422                 {
423                         fprintf (stderr, "Error: malformed password entry at line %d (no : after uid)\n", line);
424                         continue;
425                 }
426
427                 pdb_set_username(&sam_pwent, user_name);
428                 pdb_set_uid (&sam_pwent, uidval);
429                 
430                 /* Get passwords */
431                 p++;
432                 if (*p == '*' || *p == 'X')
433                 {
434                         /* Password deliberately invalid */
435                         fprintf (stderr, "Warning: entry invalidated for user %s\n", user_name);
436                         sam_pwent.lm_pw = NULL;
437                         sam_pwent.nt_pw = NULL;
438                         sam_pwent.acct_ctrl |= ACB_DISABLED;
439                 }
440                 else
441                 {
442                         if (linebuf_len < (PTR_DIFF(p, linebuf) + 33))
443                         {
444                                 fprintf (stderr, "Error: malformed password entry at line %d (password too short)\n",line);
445                                 continue;
446                         }
447                         if (p[32] != ':')
448                         {
449                                 fprintf (stderr, "Error: malformed password entry at line %d (no terminating :)\n",line);
450                                 continue;
451                         }
452                         if (!strncasecmp((char *) p, "NO PASSWORD", 11))
453                         {
454                                 sam_pwent.lm_pw = NULL;
455                                 sam_pwent.acct_ctrl |= ACB_PWNOTREQ;
456                         }
457                         else
458                         {
459                                 if (!smbpasswd_gethexpwd((char *)p, smbpwd))
460                                 {
461                                         fprintf (stderr, "Error: malformed Lanman password entry at line %d (non hex chars)\n", line);
462                                         continue;
463                                 }
464                                 sam_pwent.lm_pw = smbpwd;
465                         }
466                         /* NT password */
467                         sam_pwent.nt_pw = NULL;
468                         p += 33;
469                         if ((linebuf_len >= (PTR_DIFF(p, linebuf) + 33)) && (p[32] == ':'))
470                         {
471                                 if (*p != '*' && *p != 'X')
472                                 {
473                                         if (smbpasswd_gethexpwd((char *)p,smbntpwd))
474                                         {
475                                                 sam_pwent.nt_pw = smbntpwd;
476                                         }
477                                 }
478                                 p += 33;
479                         }
480                 }
481
482                 /* Get ACCT_CTRL field if any */
483                 if (*p == '[')
484                 {
485                         unsigned char *end_p = (unsigned char *)strchr_m((char *)p, ']');
486                         
487                         sam_pwent.acct_ctrl = smbpasswd_decode_acb_info((char*)p);
488                         if(sam_pwent.acct_ctrl == 0) sam_pwent.acct_ctrl = ACB_NORMAL;
489                         
490                         /* Get last change time */
491                         if(end_p) p = end_p + 1;
492                         if(*p == ':')
493                         {
494                                 p++;
495                                 if(*p && (StrnCaseCmp((char *)p, "LCT-", 4)==0))
496                                 {
497                                         int i;
498                                         
499                                         p += 4;
500                                         for(i = 0; i < 8; i++)
501                                         {
502                                                 if(p[i] == '\0' || !isxdigit(p[i])) break;
503                                         }
504                                         if(i == 8)
505                                         {
506                                                 sam_pwent.pass_last_set_time = (time_t)strtol((char *)p, NULL, 16);
507                                         }
508                                 }
509                         }
510                 }
511
512                 /* Test if workstation */
513                 else
514                 {
515                         if(sam_pwent.username[strlen(sam_pwent.username) - 1] == '$')
516                         {
517                                 sam_pwent.acct_ctrl &= ~ACB_NORMAL;
518                                 sam_pwent.acct_ctrl |= ACB_WSTRUST;
519                         }
520                 }
521                 if (sam_pwent.acct_ctrl & ACB_WSTRUST)
522                 {
523                         if (!(BASE_MACHINE_UID <= uidval <= MAX_MACHINE_UID))
524                         {
525                                 fprintf (stderr, "Warning: Machine UID out of normal range %d-%d\n",
526                                                  BASE_MACHINE_UID,
527                                                  MAX_MACHINE_UID);
528                         }
529                         sam_pwent.gid = BASE_MACHINE_UID;
530                 }
531         
532                 /* Test if user is valid */
533                 if (sam_pwent.acct_ctrl & ACB_NORMAL)
534                 {
535                         struct passwd  *pwd = NULL;
536
537                         if (pdb_getsampwnam (&sam_test,user_name))
538                         {
539                                 fprintf (stderr, "Error: Username already exist in database!\n");
540                                 continue;
541                         }
542                         if (!(pwd = sys_getpwnam(user_name)))
543                         {
544                                 fprintf (stderr, "Error: User %s does not exist in system passwd!\n", user_name);
545                                 continue;
546                         }
547                         sam_pwent.gid = pwd->pw_gid;
548                 }
549
550                 /* Fill in sam_pwent structure */
551                 sam_pwent.user_rid = pdb_uid_to_user_rid (sam_pwent.uid);
552                 sam_pwent.group_rid = pdb_gid_to_group_rid (sam_pwent.gid);
553                 /* TODO: set also full_name, home_dir, dir_drive, logon_script, profile_path, ecc...
554                  * when defaults will be available (after passdb redesign)
555                  * let them blank just now they are not used anyway
556                  */
557                                          
558                  /* Now ADD the entry */
559                 if (!(pdb_add_sam_account (&sam_pwent)))
560                 {
561                         fprintf (stderr, "Unable to add user entry!\n");
562                         continue;
563                 }
564                 printf ("%s imported!\n", user_name);
565                 good++;
566         }
567         printf ("%d lines read.\n%d entryes imported\n", line, good);
568         
569         return 0;
570 }
571
572 /*********************************************************
573  Start here.
574 **********************************************************/
575 int main (int argc, char **argv)
576 {
577         int ch;
578         static pstring servicesf = CONFIGFILE;
579         BOOL list_users = False;
580         BOOL verbose = False;
581         BOOL spstyle = False;
582         BOOL setparms = False;
583         BOOL machine = False;
584         BOOL add_user = False;
585         BOOL delete_user = False;
586         BOOL import = False;
587         char *user_name = NULL;
588         char *full_name = NULL;
589         char *home_dir = NULL;
590         char *home_drive = NULL;
591         char *logon_script = NULL;
592         char *profile_path = NULL;
593         char *smbpasswd = NULL;
594
595         TimeInit();
596         
597         setup_logging("tdbedit", True);
598
599         if (argc < 2)
600
601         {
602                 usage();
603                 return 0;
604         }
605         
606         if(!initialize_password_db(True)) {
607                 fprintf(stderr, "Can't setup password database vectors.\n");
608                 exit(1);
609         }
610         
611         if (!lp_load(servicesf,True,False,False)) {
612                 fprintf(stderr, "Can't load %s - run testparm to debug it\n", 
613                         servicesf);
614                 exit(1);
615         }
616         
617         while ((ch = getopt(argc, argv, "ad:f:h:i:lmp:s:u:vwx")) != EOF) {
618                 switch(ch) {
619                 case 'a':
620                         add_user = True;
621                         break;
622                 case 'm':
623                         machine = True;
624                         break;
625                 case 'l':
626                         list_users = True;
627                         break;
628                 case 'v':
629                         verbose = True;
630                         break;
631                 case 'w':
632                         spstyle = True;
633                         break;
634                 case 'u':
635                         user_name = optarg;
636                         break;
637                 case 'f':
638                         setparms = True;
639                         full_name = optarg;
640                         break;
641                 case 'h':
642                         setparms = True;
643                         home_dir = optarg;
644                         break;
645                 case 'd':
646                         setparms = True;
647                         home_drive = optarg;
648                         break;
649                 case 's':
650                         setparms = True;
651                         logon_script = optarg;
652                         break;
653                 case 'p':
654                         setparms = True;
655                         profile_path = optarg;
656                         break;
657                 case 'x':
658                         delete_user = True;
659                         break;
660                 case 'i':
661                         import = True;
662                         smbpasswd = optarg;
663                         break;
664                 default:
665                         usage();
666                 }
667         }
668         if (((add_user?1:0) + (delete_user?1:0) + (list_users?1:0) + (import?1:0) + (setparms?1:0)) > 1)
669         {
670                 fprintf (stderr, "Incompatible options on command line!\n");
671                 usage();
672                 exit(1);
673         }
674
675         if (add_user) 
676         {
677                 if (!user_name)
678                 {
679                         fprintf (stderr, "Username not specified! (use -u option)\n");
680                         return -1;
681                 }
682                 if (machine) return new_machine (user_name);
683                 else return new_user (user_name, full_name, home_dir, home_drive, logon_script, profile_path);
684         }
685
686         if (delete_user)
687         {
688                 if (!user_name)
689                 {
690                         fprintf (stderr, "Username not specified! (use -u option)\n");
691                         return -1;
692                 }
693                 if (machine) return delete_machine_entry (user_name);
694                 else return delete_user_entry (user_name);
695         }
696         
697         if (user_name) 
698         {
699                 if (setparms) set_user_info (   user_name,
700                                                 full_name,
701                                                 home_dir,
702                                                 home_drive,
703                                                 logon_script,
704                                                 profile_path);
705                                                 
706                 else return print_user_info (user_name, verbose, spstyle);
707                 
708                 return 0;
709         }
710
711         
712         if (list_users) 
713                 return print_users_list (verbose, spstyle);
714         
715         if (import) 
716                 return import_users (smbpasswd); 
717         
718         usage();
719
720         return 0;
721 }