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