Parionia to ensure people don't install libsmb based programs setuid root.
[gd/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 = LOCAL_SET_PASSWORD;
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                         local_flags &= ~LOCAL_SET_PASSWORD;
563                         break;
564                 case 'd':
565                         local_flags |= LOCAL_DISABLE_USER;
566                         local_flags &= ~LOCAL_SET_PASSWORD;
567                         break;
568                 case 'e':
569                         local_flags |= LOCAL_ENABLE_USER;
570                         local_flags &= ~LOCAL_SET_PASSWORD;
571                         break;
572                 case 'm':
573                         local_flags |= LOCAL_TRUST_ACCOUNT;
574                         break;
575                 case 'n':
576                         local_flags |= LOCAL_SET_NO_PASSWORD;
577                         local_flags &= ~LOCAL_SET_PASSWORD;
578                         break;
579                 case 'j':
580                         new_domain = optarg;
581                         strupper(new_domain);
582                         joining_domain = True;
583                         break;
584                 case 'r':
585                         remote_machine = optarg;
586                         break;
587                 case 's':
588                         set_line_buffering(stdin);
589                         set_line_buffering(stdout);
590                         set_line_buffering(stderr);
591                         stdin_passwd_get = True;
592                         break;
593                 case 'R':
594                         lp_set_name_resolve_order(optarg);
595                         break;
596                 case 'D':
597                         DEBUGLEVEL = atoi(optarg);
598                         break;
599                 case 'U': {
600                         char *lp;
601
602                         got_username = True;
603                         fstrcpy(user_name, optarg);
604
605                         if ((lp = strchr_m(user_name, '%'))) {
606                                 *lp = 0;
607                                 fstrcpy(user_password, lp + 1);
608                                 got_pass = True;
609                                 memset(strchr_m(optarg, '%') + 1, 'X',
610                                        strlen(user_password));
611                         }
612
613                         break;
614                 }
615                 case 'h':
616                 default:
617                         usage();
618                 }
619         }
620         
621         argc -= optind;
622         argv += optind;
623
624         /*
625          * Ensure both add/delete user are not set
626          * Ensure add/delete user and either remote machine or join domain are
627          * not both set.
628          */     
629         if(((local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER)) == (LOCAL_ADD_USER|LOCAL_DELETE_USER)) || 
630            ((local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER)) && 
631                 ((remote_machine != NULL) || joining_domain))) {
632                 usage();
633         }
634         
635         /* Only load interfaces if we are doing network operations. */
636
637         if (joining_domain || remote_machine) {
638                 load_interfaces();
639         }
640
641         /* Join a domain */
642
643         if (joining_domain) {
644
645                 if (argc != 0)
646                         usage();
647
648                 /* Are we joining by specifing an admin username and
649                    password? */
650
651                 if (user_name[0]) {
652
653                         /* Get administrator password if not specified */
654
655                         if (!got_pass) {
656                                 char *pass = getpass("Password: ");
657
658                                 if (pass)
659                                         pstrcpy(user_password, pass);
660                         }
661                                 
662                         return join_domain_byuser(new_domain, remote_machine,
663                                                   user_name, user_password);
664                 } else {
665
666                         /* Or just with the server manager? */
667
668                         return join_domain(new_domain, remote_machine);
669                 }
670         }
671
672         /*
673          * Deal with root - can add a user, but only locally.
674          */
675
676         switch(argc) {
677         case 0:
678                 if (!got_username)
679                         fstrcpy(user_name, "");
680                 break;
681         case 1:
682                 if (got_username)
683                         usage();
684                 fstrcpy(user_name, argv[0]);
685                 break;
686         case 2:
687                 if (got_username || got_pass)
688                         usage();
689                 fstrcpy(user_name, argv[0]);
690                 new_passwd = xstrdup(argv[1]);
691                 break;
692         default:
693                 usage();
694         }
695
696         if (!user_name[0] && (pwd = sys_getpwuid(geteuid()))) {
697                 fstrcpy(user_name, pwd->pw_name);
698         } 
699
700         if (!user_name[0]) {
701                 fprintf(stderr,"You must specify a username\n");
702                 exit(1);
703         }
704
705         if (local_flags & LOCAL_TRUST_ACCOUNT) {
706                 /* add the $ automatically */
707                 static fstring buf;
708
709                 /*
710                  * Remove any trailing '$' before we
711                  * generate the initial machine password.
712                  */
713
714                 if (user_name[strlen(user_name)-1] == '$') {
715                         user_name[strlen(user_name)-1] = 0;
716                 }
717
718                 if (local_flags & LOCAL_ADD_USER) {
719                         SAFE_FREE(new_passwd);
720                         new_passwd = xstrdup(user_name);
721                         strlower(new_passwd);
722                 }
723
724                 /*
725                  * Now ensure the username ends in '$' for
726                  * the machine add.
727                  */
728
729                 slprintf(buf, sizeof(buf)-1, "%s$", user_name);
730                 fstrcpy(user_name, buf);
731         }
732
733         if (remote_machine != NULL) {
734                 old_passwd = get_pass("Old SMB password:",stdin_passwd_get);
735         }
736         
737         if (!(local_flags & LOCAL_SET_PASSWORD)) {
738
739                 /*
740                  * If we are trying to enable a user, first we need to find out
741                  * if they are using a modern version of the smbpasswd file that
742                  * disables a user by just writing a flag into the file. If so
743                  * then we can re-enable a user without prompting for a new
744                  * password. If not (ie. they have a no stored password in the
745                  * smbpasswd file) then we need to prompt for a new password.
746                  */
747
748                 if(local_flags & LOCAL_ENABLE_USER) {
749                         SAM_ACCOUNT *sampass = NULL;
750                         BOOL ret;
751                         
752                         pdb_init_sam(&sampass);
753                         ret = pdb_getsampwnam(sampass, user_name);
754                         if((sampass != False) && (pdb_get_lanman_passwd(sampass) == NULL)) {
755                                 local_flags |= LOCAL_SET_PASSWORD;
756                         }
757                         pdb_free_sam(&sampass);
758                 }
759         }
760
761         if(local_flags & LOCAL_SET_PASSWORD) {
762                 new_passwd = prompt_for_new_password(stdin_passwd_get);
763                 
764                 if(!new_passwd) {
765                         fprintf(stderr, "Unable to get new password.\n");
766                         exit(1);
767                 }
768         }
769         
770         if (!password_change(remote_machine, user_name, old_passwd, new_passwd, local_flags)) {
771                 fprintf(stderr,"Failed to modify password entry for user %s\n", user_name);
772                 result = 1;
773                 goto done;
774         } 
775
776         if(!(local_flags & (LOCAL_ADD_USER|LOCAL_DISABLE_USER|LOCAL_ENABLE_USER|LOCAL_DELETE_USER|LOCAL_SET_NO_PASSWORD|LOCAL_SET_PASSWORD))) {
777                 SAM_ACCOUNT *sampass = NULL;
778                 BOOL ret;
779                 
780                 pdb_init_sam(&sampass);
781                 ret = pdb_getsampwnam(sampass, user_name);
782
783                 printf("Password changed for user %s.", user_name );
784                 if( (ret != False) && (pdb_get_acct_ctrl(sampass)&ACB_DISABLED) )
785                         printf(" User has disabled flag set.");
786                 if((ret != False) && (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ) )
787                         printf(" User has no password flag set.");
788                 printf("\n");
789                 pdb_free_sam(&sampass);
790         }
791
792  done:
793         SAFE_FREE(new_passwd);
794         return result;
795 }
796
797
798 /*************************************************************
799 handle password changing for non-root
800 *************************************************************/
801 static int process_nonroot(int argc, char *argv[])
802 {
803         struct passwd  *pwd = NULL;
804         int result = 0, ch;
805         BOOL stdin_passwd_get = False;
806         char *old_passwd = NULL;
807         char *remote_machine = NULL;
808         char *user_name = NULL;
809         char *new_passwd = NULL;
810
811         while ((ch = getopt(argc, argv, "hD:r:sU:")) != EOF) {
812                 switch(ch) {
813                 case 'D':
814                         DEBUGLEVEL = atoi(optarg);
815                         break;
816                 case 'r':
817                         remote_machine = optarg;
818                         break;
819                 case 's':
820                         set_line_buffering(stdin);
821                         set_line_buffering(stdout);
822                         set_line_buffering(stderr);
823                         stdin_passwd_get = True;
824                         break;
825                 case 'U':
826                         user_name = optarg;
827                         break;
828                 default:
829                         usage();
830                 }
831         }
832         
833         argc -= optind;
834         argv += optind;
835
836         if(argc > 1) {
837                 usage();
838         }
839         
840         if (argc == 1) {
841                 new_passwd = argv[0];
842         }
843         
844         if (!user_name) {
845                 pwd = sys_getpwuid(getuid());
846                 if (pwd) {
847                         user_name = xstrdup(pwd->pw_name);
848                 } else {
849                         fprintf(stderr,"you don't exist - go away\n");
850                         exit(1);
851                 }
852         }
853         
854         /*
855          * A non-root user is always setting a password
856          * via a remote machine (even if that machine is
857          * localhost).
858          */     
859
860         load_interfaces(); /* Delayed from main() */
861
862         if (remote_machine == NULL) {
863                 remote_machine = "127.0.0.1";
864         }
865
866         if (remote_machine != NULL) {
867                 old_passwd = get_pass("Old SMB password:",stdin_passwd_get);
868         }
869         
870         if (!new_passwd) {
871                 new_passwd = prompt_for_new_password(stdin_passwd_get);
872         }
873         
874         if (!new_passwd) {
875                 fprintf(stderr, "Unable to get new password.\n");
876                 exit(1);
877         }
878
879         if (!password_change(remote_machine, user_name, old_passwd, new_passwd, 0)) {
880                 fprintf(stderr,"Failed to change password for %s\n", user_name);
881                 result = 1;
882                 goto done;
883         }
884
885         printf("Password changed for user %s\n", user_name);
886
887  done:
888         SAFE_FREE(old_passwd);
889         SAFE_FREE(new_passwd);
890
891         return result;
892 }
893
894
895
896 /*********************************************************
897  Start here.
898 **********************************************************/
899 int main(int argc, char **argv)
900 {       
901         static pstring servicesf = CONFIGFILE;
902
903 #if defined(HAVE_SET_AUTH_PARAMETERS)
904         set_auth_parameters(argc, argv);
905 #endif /* HAVE_SET_AUTH_PARAMETERS */
906
907         TimeInit();
908         
909         setup_logging("smbpasswd", True);
910         
911         if(!initialize_password_db(True)) {
912                 fprintf(stderr, "Can't setup password database vectors.\n");
913                 exit(1);
914         }
915
916         if (!lp_load(servicesf,True,False,False)) {
917                 fprintf(stderr, "Can't load %s - run testparm to debug it\n", 
918                         servicesf);
919                 exit(1);
920         }
921
922         /*
923          * Set the machine NETBIOS name if not already
924          * set from the config file. 
925          */ 
926     
927         if (!*global_myname) {   
928                 char *p;
929                 fstrcpy(global_myname, myhostname());
930                 p = strchr_m(global_myname, '.' );
931                 if (p) *p = 0;
932         }           
933         strupper(global_myname);
934
935         /* Check the effective uid - make sure we are not setuid */
936         if (is_setuid_root()) {
937                 fprintf(stderr, "smbpasswd must *NOT* be setuid root.\n");
938                 exit(1);
939         }
940
941         /* pre-check for local mode option as first option. We can't
942            do this via normal getopt as getopt can't be called
943            twice. */
944         if (argc > 1 && strcmp(argv[1], "-L") == 0) {
945                 local_mode = True;
946         }
947
948         if (local_mode || getuid() == 0) {
949                 secrets_init();
950                 return process_root(argc, argv);
951         } 
952
953         return process_nonroot(argc, argv);
954 }