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