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