Make the smbpasswd options/usage message a little less bizarre: it now
[ira/wip.git] / source3 / utils / smbpasswd.c
1 /*
2  * Unix SMB/Netbios 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 2 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 pstring global_myname;
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 local_mode;
33
34 /**
35  * Print command usage on stderr and die.
36  **/
37 static void usage(void)
38 {
39         printf("When run by root:\n");
40         printf("    smbpasswd [options] [username] [password]\n");
41         printf("otherwise:\n");
42         printf("    smbpasswd [options] [password]\n\n");
43
44         printf("options:\n");
45         printf("  -s                   use stdin for password prompt\n");
46         printf("  -D LEVEL             debug level\n");
47         printf("  -U USER              remote username\n");
48         printf("  -r MACHINE           remote machine\n");
49
50         printf("extra options when run by root or in local mode:\n");
51         printf("  -L                   local mode (must be first option)\n");
52         printf("  -R ORDER             name resolve order\n");
53         printf("  -j DOMAIN            join domain name\n");
54         printf("  -a                   add user\n");
55         printf("  -x                   delete user\n");
56         printf("  -d                   disable user\n");
57         printf("  -e                   enable user\n");
58         printf("  -n                   set no password\n");
59         printf("  -m                   machine trust account\n");
60
61         exit(1);
62 }
63
64 /*********************************************************
65 Join a domain.
66 **********************************************************/
67 static int join_domain(char *domain, char *remote)
68 {
69         pstring remote_machine;
70         fstring trust_passwd;
71         unsigned char orig_trust_passwd_hash[16];
72         BOOL ret;
73
74         pstrcpy(remote_machine, remote ? remote : "");
75         fstrcpy(trust_passwd, global_myname);
76         strlower(trust_passwd);
77         E_md4hash( (uchar *)trust_passwd, orig_trust_passwd_hash);
78
79         /* Ensure that we are not trying to join a
80            domain if we are locally set up as a domain
81            controller. */
82
83         if(strequal(remote, global_myname)) {
84                 fprintf(stderr, "Cannot join domain %s as the domain controller name is our own. We cannot be a domain controller for a domain and also be a domain member.\n", domain);
85                 return 1;
86         }
87
88         /*
89          * Write the old machine account password.
90          */
91         
92         if(!secrets_store_trust_account_password(domain,  orig_trust_passwd_hash)) {              
93                 fprintf(stderr, "Unable to write the machine account password for \
94 machine %s in domain %s.\n", global_myname, domain);
95                 return 1;
96         }
97         
98         /*
99          * If we are given a remote machine assume this is the PDC.
100          */
101         
102         if(remote == NULL) {
103                 pstrcpy(remote_machine, lp_passwordserver());
104         }
105
106         if(!*remote_machine) {
107                 fprintf(stderr, "No password server list given in smb.conf - \
108 unable to join domain.\n");
109                 return 1;
110         }
111
112         ret = change_trust_account_password( domain, remote_machine);
113         
114         if(!ret) {
115                 trust_password_delete(domain);
116                 fprintf(stderr,"Unable to join domain %s.\n",domain);
117         } else {
118                 printf("Joined domain %s.\n",domain);
119         }
120         
121         return (int)ret;
122 }
123
124 /* Initialise client credentials for authenticated pipe access */
125
126 void init_rpcclient_creds(struct ntuser_creds *creds, char* username,
127                           char* domain, char* password)
128 {
129         ZERO_STRUCTP(creds);
130         
131         if (lp_encrypted_passwords()) {
132                 pwd_make_lm_nt_16(&creds->pwd, password);
133         } else {
134                 pwd_set_cleartext(&creds->pwd, password);
135         }
136
137         fstrcpy(creds->user_name, username);
138         fstrcpy(creds->domain, domain);
139 }
140
141 /*********************************************************
142 Join a domain using the administrator username and password
143 **********************************************************/
144
145 /* Macro for checking RPC error codes to make things more readable */
146
147 #define CHECK_RPC_ERR(rpc, msg) \
148         if (!NT_STATUS_IS_OK(result = rpc)) { \
149                 DEBUG(0, (msg ": %s\n", get_nt_error_msg(result))); \
150                 goto done; \
151         }
152
153 #define CHECK_RPC_ERR_DEBUG(rpc, debug_args) \
154         if (!NT_STATUS_IS_OK(result = rpc)) { \
155                 DEBUG(0, debug_args); \
156                 goto done; \
157         }
158
159 static int join_domain_byuser(char *domain, char *remote_machine,
160                               char *username, char *password)
161 {
162         /* libsmb variables */
163
164         struct nmb_name calling, called;
165         struct ntuser_creds creds;
166         struct cli_state cli;
167         fstring dest_host, acct_name;
168         struct in_addr dest_ip;
169         TALLOC_CTX *mem_ctx;
170         uint32 acb_info;
171
172         /* rpc variables */
173
174         POLICY_HND lsa_pol, sam_pol, domain_pol, user_pol;
175         DOM_SID domain_sid;
176         uint32 user_rid;
177
178         /* Password stuff */
179
180         char *machine_pwd;
181         int plen = 0;
182         uchar pwbuf[516], ntpw[16], sess_key[16];
183         SAM_USERINFO_CTR ctr;
184         SAM_USER_INFO_24 p24;
185         SAM_USER_INFO_10 p10;
186
187         /* Misc */
188
189         NTSTATUS result;
190         int retval = 1;
191
192         /* Connect to remote machine */
193
194         ZERO_STRUCT(cli);
195         ZERO_STRUCT(creds);
196
197         if (!(mem_ctx = talloc_init())) {
198                 DEBUG(0, ("Could not initialise talloc context\n"));
199                 goto done;
200         }
201
202         if (!cli_initialise(&cli)) {
203                 DEBUG(0, ("Could not initialise client structure\n"));
204                 goto done;
205         }
206
207         init_rpcclient_creds(&creds, username, domain, password);
208         cli_init_creds(&cli, &creds);
209
210         if (!resolve_srv_name(remote_machine, dest_host, &dest_ip)) {
211                 DEBUG(0, ("Could not resolve name %s\n", remote_machine));
212                 goto done;
213         }
214
215         make_nmb_name(&called, dns_to_netbios_name(dest_host), 0x20);
216         make_nmb_name(&calling, dns_to_netbios_name(global_myname), 0);
217
218         if (!cli_establish_connection(&cli, dest_host, &dest_ip, &calling, 
219                                       &called, "IPC$", "IPC", False, True)) {
220                 DEBUG(0, ("Error connecting to %s\n", dest_host));
221                 goto done;
222         }
223
224         /* Fetch domain sid */
225
226         if (!cli_nt_session_open(&cli, PIPE_LSARPC)) {
227                 DEBUG(0, ("Error connecting to SAM pipe\n"));
228                 goto done;
229         }
230
231
232         CHECK_RPC_ERR(cli_lsa_open_policy(&cli, mem_ctx, True,
233                                           SEC_RIGHTS_MAXIMUM_ALLOWED,
234                                           &lsa_pol),
235                       "error opening lsa policy handle");
236
237         CHECK_RPC_ERR(cli_lsa_query_info_policy(&cli, mem_ctx, &lsa_pol,
238                                                 5, domain, &domain_sid),
239                       "error querying info policy");
240
241         cli_lsa_close(&cli, mem_ctx, &lsa_pol);
242
243         cli_nt_session_close(&cli); /* Done with this pipe */
244
245         /* Create domain user */
246
247         if (!cli_nt_session_open(&cli, PIPE_SAMR)) {
248                 DEBUG(0, ("Error connecting to SAM pipe\n"));
249                 goto done;
250         }
251
252         CHECK_RPC_ERR(cli_samr_connect(&cli, mem_ctx, 
253                                        SEC_RIGHTS_MAXIMUM_ALLOWED,
254                                        &sam_pol),
255                       "could not connect to SAM database");
256
257         
258         CHECK_RPC_ERR(cli_samr_open_domain(&cli, mem_ctx, &sam_pol,
259                                            SEC_RIGHTS_MAXIMUM_ALLOWED,
260                                            &domain_sid, &domain_pol),
261                       "could not open domain");
262
263         /* Create domain user */
264
265         fstrcpy(acct_name, global_myname);
266         fstrcat(acct_name, "$");
267
268         strlower(acct_name);
269
270         acb_info = (lp_server_role() == ROLE_DOMAIN_BDC) ? ACB_SVRTRUST :
271                 ACB_WSTRUST;
272
273         {
274                 uint32 unknown = 0xe005000b;
275
276                 result = cli_samr_create_dom_user(&cli, mem_ctx, &domain_pol,
277                                                   acct_name, acb_info,
278                                                   unknown, &user_pol, 
279                                                   &user_rid);
280
281                 /* We *must* do this.... don't ask... */
282
283                 CHECK_RPC_ERR_DEBUG(cli_samr_close(&cli, mem_ctx, &user_pol), ("error closing user policy"));
284                 result = NT_STATUS_USER_EXISTS;
285         }       
286
287         if (NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_USER_EXISTS)) {
288                 uint32 num_rids, *name_types, *user_rids;
289                 uint32 flags = 0x3e8;
290                 char *names;
291                 
292                 /* Look up existing rid */
293                 
294                 names = (char *)&acct_name[0];
295
296                 CHECK_RPC_ERR_DEBUG(
297                         cli_samr_lookup_names(&cli, mem_ctx,
298                                               &domain_pol, flags,
299                                               1, &names, &num_rids,
300                                               &user_rids, &name_types),
301                         ("error looking up rid for user %s: %s\n",
302                          acct_name, get_nt_error_msg(result)));
303
304                 if (name_types[0] != SID_NAME_USER) {
305                         DEBUG(0, ("%s is not a user account\n", acct_name));
306                         goto done;
307                 }
308
309                 user_rid = user_rids[0];
310                 
311                 /* Open handle on user */
312
313                 CHECK_RPC_ERR_DEBUG(
314                         cli_samr_open_user(&cli, mem_ctx, &domain_pol,
315                                            SEC_RIGHTS_MAXIMUM_ALLOWED,
316                                            user_rid, &user_pol),
317                         ("could not re-open existing user %s: %s\n",
318                          acct_name, get_nt_error_msg(result)));
319                 
320         } else if (!NT_STATUS_IS_OK(result)) {
321                 DEBUG(0, ("error creating domain user: %s\n",
322                           get_nt_error_msg(result)));
323                 goto done;
324         }
325
326         /* Create a random machine account password */
327
328         {
329                 UNISTR2 upw;    /* Unicode password */
330
331                 upw.buffer = (uint16 *)talloc_zero(mem_ctx, 0xc * 
332                                                    sizeof(uint16));
333
334                 upw.uni_str_len = 0xc;
335                 upw.uni_max_len = 0xc;
336
337                 machine_pwd = (char *)upw.buffer;
338                 plen = upw.uni_str_len * 2;
339                 generate_random_buffer((unsigned char *)machine_pwd, plen, True);
340
341                 encode_pw_buffer((char *)pwbuf, machine_pwd, plen, False);
342
343                 nt_owf_genW(&upw, ntpw);
344         }
345
346         /* Set password on machine account */
347
348         ZERO_STRUCT(ctr);
349         ZERO_STRUCT(p24);
350
351         init_sam_user_info24(&p24, (char *)pwbuf,24);
352
353         ctr.switch_value = 24;
354         ctr.info.id24 = &p24;
355
356         /* I don't think this is quite the right place for this
357            calculation.  It should be moved somewhere where the credentials
358            are calculated. )-: */
359
360         mdfour(sess_key, cli.pwd.smb_nt_pwd, 16);
361
362         CHECK_RPC_ERR(cli_samr_set_userinfo(&cli, mem_ctx, &user_pol, 24, 
363                                             sess_key, &ctr),
364                       "error setting trust account password");
365
366         /* Why do we have to try to (re-)set the ACB to be the same as what
367            we passed in the samr_create_dom_user() call?  When a NT
368            workstation is joined to a domain by an administrator the
369            acb_info is set to 0x80.  For a normal user with "Add
370            workstations to the domain" rights the acb_info is 0x84.  I'm
371            not sure whether it is supposed to make a difference or not.  NT
372            seems to cope with either value so don't bomb out if the set
373            userinfo2 level 0x10 fails.  -tpot */
374
375         ZERO_STRUCT(ctr);
376         ctr.switch_value = 0x10;
377         ctr.info.id10 = &p10;
378
379         init_sam_user_info10(&p10, acb_info);
380
381         /* Ignoring the return value is necessary for joining a domain
382            as a normal user with "Add workstation to domain" privilege. */
383
384         result = cli_samr_set_userinfo2(&cli, mem_ctx, &user_pol, 0x10, 
385                                         sess_key, &ctr);
386
387         /* Now store the secret in the secrets database */
388
389         strupper(domain);
390
391         if (!secrets_store_domain_sid(domain, &domain_sid) ||
392             !secrets_store_trust_account_password(domain, ntpw)) {
393                 DEBUG(0, ("error storing domain secrets\n"));
394                 goto done;
395         }
396
397         retval = 0;             /* Success! */
398
399  done:
400         /* Close down pipe - this will clean up open policy handles */
401
402         if (cli.nt_pipe_fnum)
403                 cli_nt_session_close(&cli);
404
405         /* Display success or failure */
406
407         if (retval != 0) {
408                 trust_password_delete(domain);
409                 fprintf(stderr,"Unable to join domain %s.\n",domain);
410         } else {
411                 printf("Joined domain %s.\n",domain);
412         }
413         
414         return retval;
415 }
416
417 static void set_line_buffering(FILE *f)
418 {
419         setvbuf(f, NULL, _IOLBF, 0);
420 }
421
422 /*************************************************************
423  Utility function to prompt for passwords from stdin. Each
424  password entered must end with a newline.
425 *************************************************************/
426 static char *stdin_new_passwd(void)
427 {
428         static fstring new_passwd;
429         size_t len;
430
431         ZERO_ARRAY(new_passwd);
432
433         /*
434          * if no error is reported from fgets() and string at least contains
435          * the newline that ends the password, then replace the newline with
436          * a null terminator.
437          */
438         if ( fgets(new_passwd, sizeof(new_passwd), stdin) != NULL) {
439                 if ((len = strlen(new_passwd)) > 0) {
440                         if(new_passwd[len-1] == '\n')
441                                 new_passwd[len - 1] = 0; 
442                 }
443         }
444         return(new_passwd);
445 }
446
447
448 /*************************************************************
449  Utility function to get passwords via tty or stdin
450  Used if the '-s' option is set to silently get passwords
451  to enable scripting.
452 *************************************************************/
453 static char *get_pass( char *prompt, BOOL stdin_get)
454 {
455         char *p;
456         if (stdin_get) {
457                 p = stdin_new_passwd();
458         } else {
459                 p = getpass(prompt);
460         }
461         return xstrdup(p);
462 }
463
464 /*************************************************************
465  Utility function to prompt for new password.
466 *************************************************************/
467 static char *prompt_for_new_password(BOOL stdin_get)
468 {
469         char *p;
470         fstring new_passwd;
471
472         ZERO_ARRAY(new_passwd);
473  
474         p = get_pass("New SMB password:", stdin_get);
475
476         fstrcpy(new_passwd, p);
477         SAFE_FREE(p);
478
479         p = get_pass("Retype new SMB password:", stdin_get);
480
481         if (strcmp(p, new_passwd)) {
482                 fprintf(stderr, "Mismatch - password unchanged.\n");
483                 ZERO_ARRAY(new_passwd);
484                 SAFE_FREE(p);
485                 return NULL;
486         }
487
488         return p;
489 }
490
491
492 /*************************************************************
493  Change a password either locally or remotely.
494 *************************************************************/
495
496 static BOOL password_change(const char *remote_machine, char *user_name, 
497                             char *old_passwd, char *new_passwd, int local_flags)
498 {
499         BOOL ret;
500         pstring err_str;
501         pstring msg_str;
502
503         if (remote_machine != NULL) {
504                 if (local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER|LOCAL_DISABLE_USER|LOCAL_ENABLE_USER|
505                                                         LOCAL_TRUST_ACCOUNT|LOCAL_SET_NO_PASSWORD)) {
506                         /* these things can't be done remotely yet */
507                         return False;
508                 }
509                 ret = remote_password_change(remote_machine, user_name, 
510                                              old_passwd, new_passwd, err_str, sizeof(err_str));
511                 if(*err_str)
512                         fprintf(stderr, err_str);
513                 return ret;
514         }
515         
516         ret = local_password_change(user_name, local_flags, new_passwd, 
517                                      err_str, sizeof(err_str), msg_str, sizeof(msg_str));
518
519         if(*msg_str)
520                 printf(msg_str);
521         if(*err_str)
522                 fprintf(stderr, err_str);
523
524         return ret;
525 }
526
527
528 /*************************************************************
529  Handle password changing for root.
530 *************************************************************/
531
532 static int process_root(int argc, char *argv[])
533 {
534         struct passwd  *pwd;
535         int result = 0, ch;
536         BOOL joining_domain = False, got_pass = False, got_username = False;
537         int local_flags = LOCAL_SET_PASSWORD;
538         BOOL stdin_passwd_get = False;
539         fstring user_name, user_password;
540         char *new_domain = NULL;
541         char *new_passwd = NULL;
542         char *old_passwd = NULL;
543         char *remote_machine = NULL;
544
545         ZERO_STRUCT(user_name);
546         ZERO_STRUCT(user_password);
547
548         user_name[0] = '\0';
549
550         while ((ch = getopt(argc, argv, "axdehmnj:r:sR:D:U:L")) != EOF) {
551                 switch(ch) {
552                 case 'L':
553                         local_mode = True;
554                         break;
555                 case 'a':
556                         local_flags |= LOCAL_ADD_USER;
557                         break;
558                 case 'x':
559                         local_flags |= LOCAL_DELETE_USER;
560                         local_flags &= ~LOCAL_SET_PASSWORD;
561                         break;
562                 case 'd':
563                         local_flags |= LOCAL_DISABLE_USER;
564                         local_flags &= ~LOCAL_SET_PASSWORD;
565                         break;
566                 case 'e':
567                         local_flags |= LOCAL_ENABLE_USER;
568                         local_flags &= ~LOCAL_SET_PASSWORD;
569                         break;
570                 case 'm':
571                         local_flags |= LOCAL_TRUST_ACCOUNT;
572                         break;
573                 case 'n':
574                         local_flags |= LOCAL_SET_NO_PASSWORD;
575                         local_flags &= ~LOCAL_SET_PASSWORD;
576                         break;
577                 case 'j':
578                         new_domain = optarg;
579                         strupper(new_domain);
580                         joining_domain = True;
581                         break;
582                 case 'r':
583                         remote_machine = optarg;
584                         break;
585                 case 's':
586                         set_line_buffering(stdin);
587                         set_line_buffering(stdout);
588                         set_line_buffering(stderr);
589                         stdin_passwd_get = True;
590                         break;
591                 case 'R':
592                         lp_set_name_resolve_order(optarg);
593                         break;
594                 case 'D':
595                         DEBUGLEVEL = atoi(optarg);
596                         break;
597                 case 'U': {
598                         char *lp;
599
600                         got_username = True;
601                         fstrcpy(user_name, optarg);
602
603                         if ((lp = strchr_m(user_name, '%'))) {
604                                 *lp = 0;
605                                 fstrcpy(user_password, lp + 1);
606                                 got_pass = True;
607                                 memset(strchr_m(optarg, '%') + 1, 'X',
608                                        strlen(user_password));
609                         }
610
611                         break;
612                 }
613                 case 'h':
614                 default:
615                         usage();
616                 }
617         }
618         
619         argc -= optind;
620         argv += optind;
621
622         /*
623          * Ensure both add/delete user are not set
624          * Ensure add/delete user and either remote machine or join domain are
625          * not both set.
626          */     
627         if(((local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER)) == (LOCAL_ADD_USER|LOCAL_DELETE_USER)) || 
628            ((local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER)) && 
629                 ((remote_machine != NULL) || joining_domain))) {
630                 usage();
631         }
632         
633         /* Only load interfaces if we are doing network operations. */
634
635         if (joining_domain || remote_machine) {
636                 load_interfaces();
637         }
638
639         /* Join a domain */
640
641         if (joining_domain) {
642
643                 if (argc != 0)
644                         usage();
645
646                 /* Are we joining by specifing an admin username and
647                    password? */
648
649                 if (user_name[0]) {
650
651                         /* Get administrator password if not specified */
652
653                         if (!got_pass) {
654                                 char *pass = getpass("Password: ");
655
656                                 if (pass)
657                                         pstrcpy(user_password, pass);
658                         }
659                                 
660                         return join_domain_byuser(new_domain, remote_machine,
661                                                   user_name, user_password);
662                 } else {
663
664                         /* Or just with the server manager? */
665
666                         return join_domain(new_domain, remote_machine);
667                 }
668         }
669
670         /*
671          * Deal with root - can add a user, but only locally.
672          */
673
674         switch(argc) {
675         case 0:
676                 if (!got_username)
677                         fstrcpy(user_name, "");
678                 break;
679         case 1:
680                 if (got_username)
681                         usage();
682                 fstrcpy(user_name, argv[0]);
683                 break;
684         case 2:
685                 if (got_username || got_pass)
686                         usage();
687                 fstrcpy(user_name, argv[0]);
688                 new_passwd = xstrdup(argv[1]);
689                 break;
690         default:
691                 usage();
692         }
693
694         if (!user_name[0] && (pwd = sys_getpwuid(geteuid()))) {
695                 fstrcpy(user_name, pwd->pw_name);
696         } 
697
698         if (!user_name[0]) {
699                 fprintf(stderr,"You must specify a username\n");
700                 exit(1);
701         }
702
703         if (local_flags & LOCAL_TRUST_ACCOUNT) {
704                 /* add the $ automatically */
705                 static fstring buf;
706
707                 /*
708                  * Remove any trailing '$' before we
709                  * generate the initial machine password.
710                  */
711
712                 if (user_name[strlen(user_name)-1] == '$') {
713                         user_name[strlen(user_name)-1] = 0;
714                 }
715
716                 if (local_flags & LOCAL_ADD_USER) {
717                         SAFE_FREE(new_passwd);
718                         new_passwd = xstrdup(user_name);
719                         strlower(new_passwd);
720                 }
721
722                 /*
723                  * Now ensure the username ends in '$' for
724                  * the machine add.
725                  */
726
727                 slprintf(buf, sizeof(buf)-1, "%s$", user_name);
728                 fstrcpy(user_name, buf);
729         }
730
731         if (remote_machine != NULL) {
732                 old_passwd = get_pass("Old SMB password:",stdin_passwd_get);
733         }
734         
735         if (!(local_flags & LOCAL_SET_PASSWORD)) {
736
737                 /*
738                  * If we are trying to enable a user, first we need to find out
739                  * if they are using a modern version of the smbpasswd file that
740                  * disables a user by just writing a flag into the file. If so
741                  * then we can re-enable a user without prompting for a new
742                  * password. If not (ie. they have a no stored password in the
743                  * smbpasswd file) then we need to prompt for a new password.
744                  */
745
746                 if(local_flags & LOCAL_ENABLE_USER) {
747                         SAM_ACCOUNT *sampass = NULL;
748                         BOOL ret;
749                         
750                         pdb_init_sam(&sampass);
751                         ret = pdb_getsampwnam(sampass, user_name);
752                         if((sampass != False) && (pdb_get_lanman_passwd(sampass) == NULL)) {
753                                 local_flags |= LOCAL_SET_PASSWORD;
754                         }
755                         pdb_free_sam(&sampass);
756                 }
757         }
758
759         if(local_flags & LOCAL_SET_PASSWORD) {
760                 new_passwd = prompt_for_new_password(stdin_passwd_get);
761                 
762                 if(!new_passwd) {
763                         fprintf(stderr, "Unable to get new password.\n");
764                         exit(1);
765                 }
766         }
767         
768         if (!password_change(remote_machine, user_name, old_passwd, new_passwd, local_flags)) {
769                 fprintf(stderr,"Failed to modify password entry for user %s\n", user_name);
770                 result = 1;
771                 goto done;
772         } 
773
774         if(!(local_flags & (LOCAL_ADD_USER|LOCAL_DISABLE_USER|LOCAL_ENABLE_USER|LOCAL_DELETE_USER|LOCAL_SET_NO_PASSWORD|LOCAL_SET_PASSWORD))) {
775                 SAM_ACCOUNT *sampass = NULL;
776                 BOOL ret;
777                 
778                 pdb_init_sam(&sampass);
779                 ret = pdb_getsampwnam(sampass, user_name);
780
781                 printf("Password changed for user %s.", user_name );
782                 if( (ret != False) && (pdb_get_acct_ctrl(sampass)&ACB_DISABLED) )
783                         printf(" User has disabled flag set.");
784                 if((ret != False) && (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ) )
785                         printf(" User has no password flag set.");
786                 printf("\n");
787                 pdb_free_sam(&sampass);
788         }
789
790  done:
791         SAFE_FREE(new_passwd);
792         return result;
793 }
794
795
796 /*************************************************************
797 handle password changing for non-root
798 *************************************************************/
799 static int process_nonroot(int argc, char *argv[])
800 {
801         struct passwd  *pwd = NULL;
802         int result = 0, ch;
803         BOOL stdin_passwd_get = False;
804         char *old_passwd = NULL;
805         char *remote_machine = NULL;
806         char *user_name = NULL;
807         char *new_passwd = NULL;
808
809         while ((ch = getopt(argc, argv, "hD:r:sU:")) != EOF) {
810                 switch(ch) {
811                 case 'D':
812                         DEBUGLEVEL = atoi(optarg);
813                         break;
814                 case 'r':
815                         remote_machine = optarg;
816                         break;
817                 case 's':
818                         set_line_buffering(stdin);
819                         set_line_buffering(stdout);
820                         set_line_buffering(stderr);
821                         stdin_passwd_get = True;
822                         break;
823                 case 'U':
824                         user_name = optarg;
825                         break;
826                 default:
827                         usage();
828                 }
829         }
830         
831         argc -= optind;
832         argv += optind;
833
834         if(argc > 1) {
835                 usage();
836         }
837         
838         if (argc == 1) {
839                 new_passwd = argv[0];
840         }
841         
842         if (!user_name) {
843                 pwd = sys_getpwuid(getuid());
844                 if (pwd) {
845                         user_name = xstrdup(pwd->pw_name);
846                 } else {
847                         fprintf(stderr,"you don't exist - go away\n");
848                         exit(1);
849                 }
850         }
851         
852         /*
853          * A non-root user is always setting a password
854          * via a remote machine (even if that machine is
855          * localhost).
856          */     
857
858         load_interfaces(); /* Delayed from main() */
859
860         if (remote_machine == NULL) {
861                 remote_machine = "127.0.0.1";
862         }
863
864         if (remote_machine != NULL) {
865                 old_passwd = get_pass("Old SMB password:",stdin_passwd_get);
866         }
867         
868         if (!new_passwd) {
869                 new_passwd = prompt_for_new_password(stdin_passwd_get);
870         }
871         
872         if (!new_passwd) {
873                 fprintf(stderr, "Unable to get new password.\n");
874                 exit(1);
875         }
876
877         if (!password_change(remote_machine, user_name, old_passwd, new_passwd, 0)) {
878                 fprintf(stderr,"Failed to change password for %s\n", user_name);
879                 result = 1;
880                 goto done;
881         }
882
883         printf("Password changed for user %s\n", user_name);
884
885  done:
886         SAFE_FREE(old_passwd);
887         SAFE_FREE(new_passwd);
888
889         return result;
890 }
891
892
893
894 /*********************************************************
895  Start here.
896 **********************************************************/
897 int main(int argc, char **argv)
898 {       
899 #if defined(HAVE_SET_AUTH_PARAMETERS)
900         set_auth_parameters(argc, argv);
901 #endif /* HAVE_SET_AUTH_PARAMETERS */
902
903         TimeInit();
904         
905         setup_logging("smbpasswd", True);
906         
907         if(!initialize_password_db(True)) {
908                 fprintf(stderr, "Can't setup password database vectors.\n");
909                 exit(1);
910         }
911
912         if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
913                 fprintf(stderr, "Can't load %s - run testparm to debug it\n", 
914                         dyn_CONFIGFILE);
915                 exit(1);
916         }
917
918         /*
919          * Set the machine NETBIOS name if not already
920          * set from the config file. 
921          */ 
922     
923         if (!*global_myname) {   
924                 char *p;
925                 fstrcpy(global_myname, myhostname());
926                 p = strchr_m(global_myname, '.' );
927                 if (p) *p = 0;
928         }           
929         strupper(global_myname);
930
931         /* Check the effective uid - make sure we are not setuid */
932         if (is_setuid_root()) {
933                 fprintf(stderr, "smbpasswd must *NOT* be setuid root.\n");
934                 exit(1);
935         }
936
937         /* pre-check for local mode option as first option. We can't
938            do this via normal getopt as getopt can't be called
939            twice. */
940         if (argc > 1 && strcmp(argv[1], "-L") == 0) {
941                 local_mode = True;
942         }
943
944         if (local_mode || getuid() == 0) {
945                 secrets_init();
946                 return process_root(argc, argv);
947         } 
948
949         return process_nonroot(argc, argv);
950 }