1c8b503b4d68522a6f35c93647e58c2463ffa030
[bbaumbach/samba-autobuild/.git] / source3 / utils / smbpasswd.c
1 /*
2  * Unix SMB/CIFS implementation. 
3  * Copyright (C) Jeremy Allison 1995-1998
4  * Copyright (C) Tim Potter     2001
5  * 
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation; either version 3 of the License, or (at your
9  * option) any later version.
10  * 
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with
17  * this program; if not, write to the Free Software Foundation, Inc., 675
18  * Mass Ave, Cambridge, MA 02139, USA.  */
19
20 #include "includes.h"
21
22 extern BOOL AllowDebugChange;
23
24 /*
25  * Next two lines needed for SunOS and don't
26  * hurt anything else...
27  */
28 extern char *optarg;
29 extern int optind;
30
31 /* forced running in root-mode */
32 static BOOL got_username = False;
33 static BOOL stdin_passwd_get = False;
34 static fstring user_name;
35 static char *new_passwd = NULL;
36 static const char *remote_machine = NULL;
37
38 static fstring ldap_secret;
39
40
41 /*********************************************************
42  Print command usage on stderr and die.
43 **********************************************************/
44 static void usage(void)
45 {
46         printf("When run by root:\n");
47         printf("    smbpasswd [options] [username]\n");
48         printf("otherwise:\n");
49         printf("    smbpasswd [options]\n\n");
50
51         printf("options:\n");
52         printf("  -L                   local mode (must be first option)\n");
53         printf("  -h                   print this usage message\n");
54         printf("  -s                   use stdin for password prompt\n");
55         printf("  -c smb.conf file     Use the given path to the smb.conf file\n");
56         printf("  -D LEVEL             debug level\n");
57         printf("  -r MACHINE           remote machine\n");
58         printf("  -U USER              remote username\n");
59
60         printf("extra options when run by root or in local mode:\n");
61         printf("  -a                   add user\n");
62         printf("  -d                   disable user\n");
63         printf("  -e                   enable user\n");
64         printf("  -i                   interdomain trust account\n");
65         printf("  -m                   machine trust account\n");
66         printf("  -n                   set no password\n");
67         printf("  -W                   use stdin ldap admin password\n");
68         printf("  -w PASSWORD          ldap admin password\n");
69         printf("  -x                   delete user\n");
70         printf("  -R ORDER             name resolve order\n");
71
72         exit(1);
73 }
74
75 static void set_line_buffering(FILE *f)
76 {
77         setvbuf(f, NULL, _IOLBF, 0);
78 }
79
80 /*******************************************************************
81  Process command line options
82  ******************************************************************/
83
84 static int process_options(int argc, char **argv, int local_flags)
85 {
86         int ch;
87         pstring configfile;
88         pstrcpy(configfile, dyn_CONFIGFILE);
89
90         local_flags |= LOCAL_SET_PASSWORD;
91
92         ZERO_STRUCT(user_name);
93
94         user_name[0] = '\0';
95
96         while ((ch = getopt(argc, argv, "c:axdehminjr:sw:R:D:U:LW")) != EOF) {
97                 switch(ch) {
98                 case 'L':
99                         local_flags |= LOCAL_AM_ROOT;
100                         break;
101                 case 'c':
102                         pstrcpy(configfile,optarg);
103                         break;
104                 case 'a':
105                         local_flags |= LOCAL_ADD_USER;
106                         break;
107                 case 'x':
108                         local_flags |= LOCAL_DELETE_USER;
109                         local_flags &= ~LOCAL_SET_PASSWORD;
110                         break;
111                 case 'd':
112                         local_flags |= LOCAL_DISABLE_USER;
113                         local_flags &= ~LOCAL_SET_PASSWORD;
114                         break;
115                 case 'e':
116                         local_flags |= LOCAL_ENABLE_USER;
117                         local_flags &= ~LOCAL_SET_PASSWORD;
118                         break;
119                 case 'm':
120                         local_flags |= LOCAL_TRUST_ACCOUNT;
121                         break;
122                 case 'i':
123                         local_flags |= LOCAL_INTERDOM_ACCOUNT;
124                         break;
125                 case 'j':
126                         d_printf("See 'net join' for this functionality\n");
127                         exit(1);
128                         break;
129                 case 'n':
130                         local_flags |= LOCAL_SET_NO_PASSWORD;
131                         local_flags &= ~LOCAL_SET_PASSWORD;
132                         new_passwd = smb_xstrdup("NO PASSWORD");
133                         break;
134                 case 'r':
135                         remote_machine = optarg;
136                         break;
137                 case 's':
138                         set_line_buffering(stdin);
139                         set_line_buffering(stdout);
140                         set_line_buffering(stderr);
141                         stdin_passwd_get = True;
142                         break;
143                 case 'w':
144                         local_flags |= LOCAL_SET_LDAP_ADMIN_PW;
145                         fstrcpy(ldap_secret, optarg);
146                         break;
147                 case 'R':
148                         lp_set_name_resolve_order(optarg);
149                         break;
150                 case 'D':
151                         DEBUGLEVEL = atoi(optarg);
152                         break;
153                 case 'U': {
154                         got_username = True;
155                         fstrcpy(user_name, optarg);
156                         break;
157                 case 'W':
158                         local_flags |= LOCAL_SET_LDAP_ADMIN_PW;
159                         *ldap_secret = '\0';
160                         break;
161                 }
162                 case 'h':
163                 default:
164                         usage();
165                 }
166         }
167         
168         argc -= optind;
169         argv += optind;
170
171         switch(argc) {
172         case 0:
173                 if (!got_username)
174                         fstrcpy(user_name, "");
175                 break;
176         case 1:
177                 if (!(local_flags & LOCAL_AM_ROOT)) {
178                         usage();
179                 } else {
180                         if (got_username) {
181                                 usage();
182                         } else {
183                                 fstrcpy(user_name, argv[0]);
184                         }
185                 }
186                 break;
187         default:
188                 usage();
189         }
190
191         if (!lp_load(configfile,True,False,False,True)) {
192                 fprintf(stderr, "Can't load %s - run testparm to debug it\n", 
193                         configfile);
194                 exit(1);
195         }
196
197         return local_flags;
198 }
199
200 /*************************************************************
201  Utility function to prompt for new password.
202 *************************************************************/
203 static char *prompt_for_new_password(BOOL stdin_get)
204 {
205         char *p;
206         fstring new_pw;
207
208         ZERO_ARRAY(new_pw);
209  
210         p = get_pass("New SMB password:", stdin_get);
211
212         fstrcpy(new_pw, p);
213         SAFE_FREE(p);
214
215         p = get_pass("Retype new SMB password:", stdin_get);
216
217         if (strcmp(p, new_pw)) {
218                 fprintf(stderr, "Mismatch - password unchanged.\n");
219                 ZERO_ARRAY(new_pw);
220                 SAFE_FREE(p);
221                 return NULL;
222         }
223
224         return p;
225 }
226
227
228 /*************************************************************
229  Change a password either locally or remotely.
230 *************************************************************/
231
232 static NTSTATUS password_change(const char *remote_mach, char *username, 
233                                 char *old_passwd, char *new_pw,
234                                 int local_flags)
235 {
236         NTSTATUS ret;
237         pstring err_str;
238         pstring msg_str;
239
240         if (remote_mach != NULL) {
241                 if (local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER|LOCAL_DISABLE_USER|LOCAL_ENABLE_USER|
242                                                         LOCAL_TRUST_ACCOUNT|LOCAL_SET_NO_PASSWORD)) {
243                         /* these things can't be done remotely yet */
244                         return NT_STATUS_UNSUCCESSFUL;
245                 }
246                 ret = remote_password_change(remote_mach, username, 
247                                              old_passwd, new_pw, err_str, sizeof(err_str));
248                 if(*err_str)
249                         fprintf(stderr, "%s", err_str);
250                 return ret;
251         }
252         
253         ret = local_password_change(username, local_flags, new_pw, 
254                                      err_str, sizeof(err_str), msg_str, sizeof(msg_str));
255
256         if(*msg_str)
257                 printf("%s", msg_str);
258         if(*err_str)
259                 fprintf(stderr, "%s", err_str);
260
261         return ret;
262 }
263
264 /*******************************************************************
265  Store the LDAP admin password in secrets.tdb
266  ******************************************************************/
267 static BOOL store_ldap_admin_pw (char* pw)
268 {       
269         if (!pw) 
270                 return False;
271
272         if (!secrets_init())
273                 return False;
274         
275         return secrets_store_ldap_pw(lp_ldap_admin_dn(), pw);
276 }
277
278
279 /*************************************************************
280  Handle password changing for root.
281 *************************************************************/
282
283 static int process_root(int local_flags)
284 {
285         struct passwd  *pwd;
286         int result = 0;
287         char *old_passwd = NULL;
288
289         if (local_flags & LOCAL_SET_LDAP_ADMIN_PW) {
290                 char *ldap_admin_dn = lp_ldap_admin_dn();
291                 if ( ! *ldap_admin_dn ) {
292                         DEBUG(0,("ERROR: 'ldap admin dn' not defined! Please check your smb.conf\n"));
293                         goto done;
294                 }
295
296                 printf("Setting stored password for \"%s\" in secrets.tdb\n", ldap_admin_dn);
297                 if ( ! *ldap_secret ) {
298                         new_passwd = prompt_for_new_password(stdin_passwd_get);
299                         fstrcpy(ldap_secret, new_passwd);
300                 }
301                 if (!store_ldap_admin_pw(ldap_secret)) {
302                         DEBUG(0,("ERROR: Failed to store the ldap admin password!\n"));
303                 }
304                 goto done;
305         }
306
307         /* Ensure passdb startup(). */
308         if(!initialize_password_db(False, NULL)) {
309                 DEBUG(0, ("Failed to open passdb!\n"));
310                 exit(1);
311         }
312                 
313         /* Ensure we have a SAM sid. */
314         get_global_sam_sid();
315
316         /*
317          * Ensure both add/delete user are not set
318          * Ensure add/delete user and either remote machine or join domain are
319          * not both set.
320          */     
321         if(((local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER)) == (LOCAL_ADD_USER|LOCAL_DELETE_USER)) || 
322            ((local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER)) && 
323                 (remote_machine != NULL))) {
324                 usage();
325         }
326         
327         /* Only load interfaces if we are doing network operations. */
328
329         if (remote_machine) {
330                 load_interfaces();
331         }
332
333         if (!user_name[0] && (pwd = getpwuid_alloc(NULL, geteuid()))) {
334                 fstrcpy(user_name, pwd->pw_name);
335                 TALLOC_FREE(pwd);
336         } 
337
338         if (!user_name[0]) {
339                 fprintf(stderr,"You must specify a username\n");
340                 exit(1);
341         }
342
343         if (local_flags & LOCAL_TRUST_ACCOUNT) {
344                 /* add the $ automatically */
345                 static fstring buf;
346
347                 /*
348                  * Remove any trailing '$' before we
349                  * generate the initial machine password.
350                  */
351
352                 if (user_name[strlen(user_name)-1] == '$') {
353                         user_name[strlen(user_name)-1] = 0;
354                 }
355
356                 if (local_flags & LOCAL_ADD_USER) {
357                         SAFE_FREE(new_passwd);
358                         new_passwd = smb_xstrdup(user_name);
359                         strlower_m(new_passwd);
360                 }
361
362                 /*
363                  * Now ensure the username ends in '$' for
364                  * the machine add.
365                  */
366
367                 slprintf(buf, sizeof(buf)-1, "%s$", user_name);
368                 fstrcpy(user_name, buf);
369         } else if (local_flags & LOCAL_INTERDOM_ACCOUNT) {
370                 static fstring buf;
371
372                 if ((local_flags & LOCAL_ADD_USER) && (new_passwd == NULL)) {
373                         /*
374                          * Prompt for trusting domain's account password
375                          */
376                         new_passwd = prompt_for_new_password(stdin_passwd_get);
377                         if(!new_passwd) {
378                                 fprintf(stderr, "Unable to get newpassword.\n");
379                                 exit(1);
380                         }
381                 }
382                 
383                 /* prepare uppercased and '$' terminated username */
384                 slprintf(buf, sizeof(buf) - 1, "%s$", user_name);
385                 fstrcpy(user_name, buf);
386                 
387         } else {
388                 
389                 if (remote_machine != NULL) {
390                         old_passwd = get_pass("Old SMB password:",stdin_passwd_get);
391                 }
392                 
393                 if (!(local_flags & LOCAL_SET_PASSWORD)) {
394                         
395                         /*
396                          * If we are trying to enable a user, first we need to find out
397                          * if they are using a modern version of the smbpasswd file that
398                          * disables a user by just writing a flag into the file. If so
399                          * then we can re-enable a user without prompting for a new
400                          * password. If not (ie. they have a no stored password in the
401                          * smbpasswd file) then we need to prompt for a new password.
402                          */
403                         
404                         if(local_flags & LOCAL_ENABLE_USER) {
405                                 struct samu *sampass = NULL;
406                                 
407                                 sampass = samu_new( NULL );
408                                 if (!sampass) {
409                                         fprintf(stderr, "talloc fail for struct samu.\n");
410                                         exit(1);
411                                 }
412                                 if (!pdb_getsampwnam(sampass, user_name)) {
413                                         fprintf(stderr, "Failed to find user %s in passdb backend.\n",
414                                                 user_name );
415                                         exit(1);
416                                 }
417
418                                 if(pdb_get_nt_passwd(sampass) == NULL) {
419                                         local_flags |= LOCAL_SET_PASSWORD;
420                                 }
421                                 TALLOC_FREE(sampass);
422                         }
423                 }
424                 
425                 if((local_flags & LOCAL_SET_PASSWORD) && (new_passwd == NULL)) {
426                         new_passwd = prompt_for_new_password(stdin_passwd_get);
427                         
428                         if(!new_passwd) {
429                                 fprintf(stderr, "Unable to get new password.\n");
430                                 exit(1);
431                         }
432                 }
433         }
434
435         if (!NT_STATUS_IS_OK(password_change(remote_machine, user_name,
436                                              old_passwd, new_passwd,
437                                              local_flags))) {
438                 fprintf(stderr,"Failed to modify password entry for user %s\n", user_name);
439                 result = 1;
440                 goto done;
441         } 
442
443         if(remote_machine) {
444                 printf("Password changed for user %s on %s.\n", user_name, remote_machine );
445         } else if(!(local_flags & (LOCAL_ADD_USER|LOCAL_DISABLE_USER|LOCAL_ENABLE_USER|LOCAL_DELETE_USER|LOCAL_SET_NO_PASSWORD|LOCAL_SET_PASSWORD))) {
446                 struct samu *sampass = NULL;
447                 
448                 sampass = samu_new( NULL );
449                 if (!sampass) {
450                         fprintf(stderr, "talloc fail for struct samu.\n");
451                         exit(1);
452                 }
453
454                 if (!pdb_getsampwnam(sampass, user_name)) {
455                         fprintf(stderr, "Failed to find user %s in passdb backend.\n",
456                                 user_name );
457                         exit(1);
458                 }
459
460                 printf("Password changed for user %s.", user_name );
461                 if(pdb_get_acct_ctrl(sampass)&ACB_DISABLED) {
462                         printf(" User has disabled flag set.");
463                 }
464                 if(pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ) {
465                         printf(" User has no password flag set.");
466                 }
467                 printf("\n");
468                 TALLOC_FREE(sampass);
469         }
470
471  done:
472         SAFE_FREE(new_passwd);
473         return result;
474 }
475
476
477 /*************************************************************
478  Handle password changing for non-root.
479 *************************************************************/
480
481 static int process_nonroot(int local_flags)
482 {
483         struct passwd  *pwd = NULL;
484         int result = 0;
485         char *old_pw = NULL;
486         char *new_pw = NULL;
487
488         if (local_flags & ~(LOCAL_AM_ROOT | LOCAL_SET_PASSWORD)) {
489                 /* Extra flags that we can't honor non-root */
490                 usage();
491         }
492
493         if (!user_name[0]) {
494                 pwd = getpwuid_alloc(NULL, getuid());
495                 if (pwd) {
496                         fstrcpy(user_name,pwd->pw_name);
497                         TALLOC_FREE(pwd);
498                 } else {
499                         fprintf(stderr, "smbpasswd: cannot lookup user name for uid %u\n", (unsigned int)getuid());
500                         exit(1);
501                 }
502         }
503         
504         /*
505          * A non-root user is always setting a password
506          * via a remote machine (even if that machine is
507          * localhost).
508          */     
509
510         load_interfaces(); /* Delayed from main() */
511
512         if (remote_machine == NULL) {
513                 remote_machine = "127.0.0.1";
514         }
515
516         if (remote_machine != NULL) {
517                 old_pw = get_pass("Old SMB password:",stdin_passwd_get);
518         }
519         
520         if (!new_passwd) {
521                 new_pw = prompt_for_new_password(stdin_passwd_get);
522         }
523         else
524                 new_pw = smb_xstrdup(new_passwd);
525         
526         if (!new_pw) {
527                 fprintf(stderr, "Unable to get new password.\n");
528                 exit(1);
529         }
530
531         if (!NT_STATUS_IS_OK(password_change(remote_machine, user_name, old_pw,
532                                              new_pw, 0))) {
533                 fprintf(stderr,"Failed to change password for %s\n", user_name);
534                 result = 1;
535                 goto done;
536         }
537
538         printf("Password changed for user %s\n", user_name);
539
540  done:
541         SAFE_FREE(old_pw);
542         SAFE_FREE(new_pw);
543
544         return result;
545 }
546
547
548
549 /*********************************************************
550  Start here.
551 **********************************************************/
552 int main(int argc, char **argv)
553 {       
554         int local_flags = 0;
555         
556         AllowDebugChange = False;
557
558 #if defined(HAVE_SET_AUTH_PARAMETERS)
559         set_auth_parameters(argc, argv);
560 #endif /* HAVE_SET_AUTH_PARAMETERS */
561
562         if (getuid() == 0) {
563                 local_flags = LOCAL_AM_ROOT;
564         }
565
566         load_case_tables();
567
568         local_flags = process_options(argc, argv, local_flags);
569
570         setup_logging("smbpasswd", True);
571         
572         /*
573          * Set the machine NETBIOS name if not already
574          * set from the config file. 
575          */ 
576     
577         if (!init_names())
578                 return 1;
579
580         /* Check the effective uid - make sure we are not setuid */
581         if (is_setuid_root()) {
582                 fprintf(stderr, "smbpasswd must *NOT* be setuid root.\n");
583                 exit(1);
584         }
585
586         if (local_flags & LOCAL_AM_ROOT) {
587                 secrets_init();
588                 return process_root(local_flags);
589         } 
590
591         return process_nonroot(local_flags);
592 }