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