2 * Unix SMB/Netbios implementation. Version 1.9. smbpasswd module. Copyright
3 * (C) Jeremy Allison 1995-1998
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 675
17 * Mass Ave, Cambridge, MA 02139, USA.
22 extern pstring myhostname;
23 extern pstring global_myname;
24 extern int DEBUGLEVEL;
27 * Next two lines needed for SunOS and don't
28 * hurt anything else...
33 /*********************************************************
35 **********************************************************/
36 static char *xstrdup(char *s)
40 fprintf(stderr,"out of memory\n");
47 /*********************************************************
48 Print command usage on stderr and die.
49 **********************************************************/
50 static void usage(void)
53 printf("smbpasswd [options] [username] [password]\n");
55 printf("smbpasswd [options] [password]\n");
58 printf(" -s use stdin for password prompt\n");
59 printf(" -D LEVEL debug level\n");
60 printf(" -U USER remote username\n");
61 printf(" -r MACHINE remote machine\n");
64 printf(" -R ORDER name resolve order\n");
65 printf(" -j DOMAIN join domain name\n");
66 printf(" -a add user\n");
67 printf(" -d disable user\n");
68 printf(" -e enable user\n");
69 printf(" -n set no password\n");
70 printf(" -m machine trust account\n");
75 /*********************************************************
77 **********************************************************/
78 static int join_domain(char *domain, char *remote)
80 pstring remote_machine;
82 unsigned char orig_trust_passwd_hash[16];
85 pstrcpy(remote_machine, remote ? remote : "");
86 fstrcpy(trust_passwd, global_myname);
87 strlower(trust_passwd);
88 E_md4hash( (uchar *)trust_passwd, orig_trust_passwd_hash);
90 /* Ensure that we are not trying to join a
91 domain if we are locally set up as a domain
94 if(strequal(remote, global_myname)) {
95 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);
100 * Create the machine account password file.
102 if(!trust_password_lock( domain, global_myname, True)) {
103 fprintf(stderr, "unable to open the machine account password file for \
104 machine %s in domain %s.\n", global_myname, domain);
109 * Write the old machine account password.
112 if(!set_trust_account_password( orig_trust_passwd_hash)) {
113 fprintf(stderr, "unable to write the machine account password for \
114 machine %s in domain %s.\n", global_myname, domain);
115 trust_password_unlock();
120 * If we are given a remote machine assume this is the PDC.
124 pstrcpy(remote_machine, lp_passwordserver());
127 if(!*remote_machine) {
128 fprintf(stderr, "No password server list given in smb.conf - \
129 unable to join domain.\n");
130 trust_password_unlock();
134 ret = change_trust_account_password( domain, remote_machine);
135 trust_password_unlock();
138 trust_password_delete( domain, global_myname);
139 fprintf(stderr,"Unable to join domain %s.\n",domain);
141 printf("Joined domain %s.\n",domain);
148 static void set_line_buffering(FILE *f)
150 setvbuf(f, NULL, _IOLBF, 0);
153 /*************************************************************
154 Utility function to prompt for passwords from stdin. Each
155 password entered must end with a newline.
156 *************************************************************/
157 static char *stdin_new_passwd(void)
159 static fstring new_passwd;
162 ZERO_ARRAY(new_passwd);
165 * if no error is reported from fgets() and string at least contains
166 * the newline that ends the password, then replace the newline with
169 if ( fgets(new_passwd, sizeof(new_passwd), stdin) != NULL) {
170 if ((len = strlen(new_passwd)) > 0) {
171 if(new_passwd[len-1] == '\n')
172 new_passwd[len - 1] = 0;
179 /*************************************************************
180 Utility function to get passwords via tty or stdin
181 Used if the '-s' option is set to silently get passwords
183 *************************************************************/
184 static char *get_pass( char *prompt, BOOL stdin_get)
188 p = stdin_new_passwd();
195 /*************************************************************
196 Utility function to prompt for new password.
197 *************************************************************/
198 static char *prompt_for_new_password(BOOL stdin_get)
203 ZERO_ARRAY(new_passwd);
205 p = get_pass("New SMB password:", stdin_get);
207 fstrcpy(new_passwd, p);
209 p = get_pass("Retype new SMB password:", stdin_get);
211 if (strcmp(p, new_passwd)) {
212 fprintf(stderr, "Mismatch - password unchanged.\n");
220 /*************************************************************
221 change a password either locally or remotely
222 *************************************************************/
223 static BOOL password_change(const char *remote_machine, char *user_name,
224 char *old_passwd, char *new_passwd,
225 BOOL add_user, BOOL enable_user,
226 BOOL disable_user, BOOL set_no_password,
233 if (remote_machine != NULL) {
234 if (add_user || enable_user || disable_user || set_no_password || trust_account) {
235 /* these things can't be done remotely yet */
238 ret = remote_password_change(remote_machine, user_name,
239 old_passwd, new_passwd, err_str, sizeof(err_str));
241 fprintf(stderr, err_str);
245 ret = local_password_change(user_name, trust_account, add_user, enable_user,
246 disable_user, set_no_password, new_passwd,
247 err_str, sizeof(err_str), msg_str, sizeof(msg_str));
252 fprintf(stderr, err_str);
258 /*************************************************************
259 handle password changing for root
260 *************************************************************/
261 static int process_root(int argc, char *argv[])
265 BOOL joining_domain = False;
266 BOOL trust_account = False;
267 BOOL add_user = False;
268 BOOL disable_user = False;
269 BOOL enable_user = False;
270 BOOL set_no_password = False;
271 BOOL stdin_passwd_get = False;
272 char *user_name = NULL;
273 char *new_domain = NULL;
274 char *new_passwd = NULL;
275 char *old_passwd = NULL;
276 char *remote_machine = NULL;
278 while ((ch = getopt(argc, argv, "adehmnj:r:sR:D:U:")) != EOF) {
285 new_passwd = "XXXXXX";
291 DEBUGLEVEL = atoi(optarg);
294 set_no_password = True;
295 new_passwd = "NO PASSWORD";
297 remote_machine = optarg;
300 set_line_buffering(stdin);
301 set_line_buffering(stdout);
302 set_line_buffering(stderr);
303 stdin_passwd_get = True;
306 lp_set_name_resolve_order(optarg);
309 trust_account = True;
313 strupper(new_domain);
314 joining_domain = True;
329 * Ensure add_user and either remote machine or join domain are
332 if(add_user && ((remote_machine != NULL) || joining_domain)) {
337 if (argc != 0) usage();
338 return join_domain(new_domain, remote_machine);
342 * Deal with root - can add a user, but only locally.
353 new_passwd = argv[1];
359 if (!user_name && (pwd = getpwuid(0))) {
360 user_name = xstrdup(pwd->pw_name);
364 fprintf(stderr,"You must specify a username\n");
369 /* add the $ automatically */
373 * Remove any trailing '$' before we
374 * generate the initial machine password.
377 if (user_name[strlen(user_name)-1] == '$') {
378 user_name[strlen(user_name)-1] = 0;
382 new_passwd = xstrdup(user_name);
383 strlower(new_passwd);
387 * Now ensure the username ends in '$' for
391 slprintf(buf, sizeof(buf)-1, "%s$", user_name);
395 if (!remote_machine && !Get_Pwnam(user_name, True)) {
396 fprintf(stderr, "User \"%s\" was not found in system password file.\n",
401 if (remote_machine != NULL) {
402 old_passwd = get_pass("Old SMB password:",stdin_passwd_get);
408 * If we are trying to enable a user, first we need to find out
409 * if they are using a modern version of the smbpasswd file that
410 * disables a user by just writing a flag into the file. If so
411 * then we can re-enable a user without prompting for a new
412 * password. If not (ie. they have a no stored password in the
413 * smbpasswd file) then we need to prompt for a new password.
417 struct smb_passwd *smb_pass = getsmbpwnam(user_name);
418 if((smb_pass != NULL) && (smb_pass->smb_passwd != NULL)) {
419 new_passwd = "XXXX"; /* Don't care. */
424 new_passwd = prompt_for_new_password(stdin_passwd_get);
427 if (!password_change(remote_machine, user_name, old_passwd, new_passwd,
428 add_user, enable_user, disable_user, set_no_password,
430 fprintf(stderr,"Failed to change password entry for %s\n", user_name);
435 printf("User %s disabled.\n", user_name);
436 } else if(enable_user) {
437 printf("User %s enabled.\n", user_name);
438 } else if (set_no_password) {
439 printf("User %s - set to no password.\n", user_name);
441 printf("Password changed for user %s\n", user_name);
447 /*************************************************************
448 handle password changing for non-root
449 *************************************************************/
450 static int process_nonroot(int argc, char *argv[])
452 struct passwd *pwd = NULL;
454 BOOL stdin_passwd_get = False;
455 char *old_passwd = NULL;
456 char *remote_machine = NULL;
457 char *user_name = NULL;
458 char *new_passwd = NULL;
460 while ((ch = getopt(argc, argv, "hD:r:sU:")) != EOF) {
463 DEBUGLEVEL = atoi(optarg);
466 remote_machine = optarg;
469 set_line_buffering(stdin);
470 set_line_buffering(stdout);
471 set_line_buffering(stderr);
472 stdin_passwd_get = True;
490 new_passwd = argv[0];
494 pwd = getpwuid(getuid());
496 user_name = xstrdup(pwd->pw_name);
498 fprintf(stderr,"you don't exist - go away\n");
504 * A non-root user is always setting a password
505 * via a remote machine (even if that machine is
508 if (remote_machine == NULL) {
509 remote_machine = "127.0.0.1";
513 if (remote_machine != NULL) {
514 old_passwd = get_pass("Old SMB password:",stdin_passwd_get);
518 new_passwd = prompt_for_new_password(stdin_passwd_get);
522 printf("unable to get new password\n");
526 if (!password_change(remote_machine, user_name, old_passwd, new_passwd,
527 False, False, False, False, False)) {
528 fprintf(stderr,"Failed to change password for %s\n", user_name);
532 printf("Password changed for user %s\n", user_name);
538 /*********************************************************
540 **********************************************************/
541 int main(int argc, char **argv)
543 static pstring servicesf = CONFIGFILE;
547 setup_logging("smbpasswd", True);
549 charset_initialise();
551 if(!initialise_password_db()) {
552 fprintf(stderr, "Can't setup password database vectors.\n");
556 if (!lp_load(servicesf,True,False,False)) {
557 fprintf(stderr, "Can't load %s - run testparm to debug it\n",
562 if(!get_myname(myhostname,NULL)) {
563 fprintf(stderr, "unable to get my hostname.\n");
568 * Set the machine NETBIOS name if not already
569 * set from the config file.
572 if (!*global_myname) {
574 fstrcpy(global_myname, myhostname);
575 p = strchr(global_myname, '.' );
578 strupper(global_myname);
580 codepage_initialise(lp_client_code_page());
582 /* Check the effective uid - make sure we are not setuid */
583 if ((geteuid() == (uid_t)0) && (getuid() != (uid_t)0)) {
584 fprintf(stderr, "smbpasswd must *NOT* be setuid root.\n");
589 return process_root(argc, argv);
592 return process_nonroot(argc, argv);