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 global_myname
;
23 extern int DEBUGLEVEL
;
26 * Next two lines needed for SunOS and don't
27 * hurt anything else...
32 /*********************************************************
34 **********************************************************/
35 static char *xstrdup(char *s
)
39 fprintf(stderr
,"out of memory\n");
46 /*********************************************************
47 Print command usage on stderr and die.
48 **********************************************************/
49 static void usage(void)
52 printf("smbpasswd [options] [username] [password]\n");
54 printf("smbpasswd [options] [password]\n");
57 printf(" -s use stdin for password prompt\n");
58 printf(" -D LEVEL debug level\n");
59 printf(" -U USER remote username\n");
60 printf(" -r MACHINE remote machine\n");
63 printf(" -R ORDER name resolve order\n");
64 printf(" -j DOMAIN join domain name\n");
65 printf(" -a add user\n");
66 printf(" -x delete 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 * Write the old machine account password.
103 if(!secrets_store_trust_account_password(domain
, orig_trust_passwd_hash
)) {
104 fprintf(stderr
, "Unable to write the machine account password for \
105 machine %s in domain %s.\n", global_myname
, domain
);
110 * If we are given a remote machine assume this is the PDC.
114 pstrcpy(remote_machine
, lp_passwordserver());
117 if(!*remote_machine
) {
118 fprintf(stderr
, "No password server list given in smb.conf - \
119 unable to join domain.\n");
123 ret
= change_trust_account_password( domain
, remote_machine
);
126 trust_password_delete(domain
);
127 fprintf(stderr
,"Unable to join domain %s.\n",domain
);
129 printf("Joined domain %s.\n",domain
);
136 static void set_line_buffering(FILE *f
)
138 setvbuf(f
, NULL
, _IOLBF
, 0);
141 /*************************************************************
142 Utility function to prompt for passwords from stdin. Each
143 password entered must end with a newline.
144 *************************************************************/
145 static char *stdin_new_passwd(void)
147 static fstring new_passwd
;
150 ZERO_ARRAY(new_passwd
);
153 * if no error is reported from fgets() and string at least contains
154 * the newline that ends the password, then replace the newline with
157 if ( fgets(new_passwd
, sizeof(new_passwd
), stdin
) != NULL
) {
158 if ((len
= strlen(new_passwd
)) > 0) {
159 if(new_passwd
[len
-1] == '\n')
160 new_passwd
[len
- 1] = 0;
167 /*************************************************************
168 Utility function to get passwords via tty or stdin
169 Used if the '-s' option is set to silently get passwords
171 *************************************************************/
172 static char *get_pass( char *prompt
, BOOL stdin_get
)
176 p
= stdin_new_passwd();
183 /*************************************************************
184 Utility function to prompt for new password.
185 *************************************************************/
186 static char *prompt_for_new_password(BOOL stdin_get
)
191 ZERO_ARRAY(new_passwd
);
193 p
= get_pass("New SMB password:", stdin_get
);
195 fstrcpy(new_passwd
, p
);
198 p
= get_pass("Retype new SMB password:", stdin_get
);
200 if (strcmp(p
, new_passwd
)) {
201 fprintf(stderr
, "Mismatch - password unchanged.\n");
202 ZERO_ARRAY(new_passwd
);
211 /*************************************************************
212 Change a password either locally or remotely.
213 *************************************************************/
215 static BOOL
password_change(const char *remote_machine
, char *user_name
,
216 char *old_passwd
, char *new_passwd
, int local_flags
)
222 if (remote_machine
!= NULL
) {
223 if (local_flags
& (LOCAL_ADD_USER
|LOCAL_DELETE_USER
|LOCAL_DISABLE_USER
|LOCAL_ENABLE_USER
|
224 LOCAL_TRUST_ACCOUNT
|LOCAL_SET_NO_PASSWORD
)) {
225 /* these things can't be done remotely yet */
228 ret
= remote_password_change(remote_machine
, user_name
,
229 old_passwd
, new_passwd
, err_str
, sizeof(err_str
));
231 fprintf(stderr
, err_str
);
235 ret
= local_password_change(user_name
, local_flags
, new_passwd
,
236 err_str
, sizeof(err_str
), msg_str
, sizeof(msg_str
));
241 fprintf(stderr
, err_str
);
247 /*************************************************************
248 Handle password changing for root.
249 *************************************************************/
251 static int process_root(int argc
, char *argv
[])
255 BOOL joining_domain
= False
;
257 BOOL stdin_passwd_get
= False
;
258 char *user_name
= NULL
;
259 char *new_domain
= NULL
;
260 char *new_passwd
= NULL
;
261 char *old_passwd
= NULL
;
262 char *remote_machine
= NULL
;
264 while ((ch
= getopt(argc
, argv
, "ax:d:e:mnj:r:sR:D:U:")) != EOF
) {
267 local_flags
|= LOCAL_ADD_USER
;
270 local_flags
|= LOCAL_DELETE_USER
;
272 new_passwd
= xstrdup("XXXXXX");
275 local_flags
|= LOCAL_DISABLE_USER
;
277 new_passwd
= xstrdup("XXXXXX");
280 local_flags
|= LOCAL_ENABLE_USER
;
284 local_flags
|= LOCAL_TRUST_ACCOUNT
;
287 local_flags
|= LOCAL_SET_NO_PASSWORD
;
288 new_passwd
= xstrdup("NO PASSWORD");
292 strupper(new_domain
);
293 joining_domain
= True
;
296 remote_machine
= optarg
;
299 set_line_buffering(stdin
);
300 set_line_buffering(stdout
);
301 set_line_buffering(stderr
);
302 stdin_passwd_get
= True
;
305 lp_set_name_resolve_order(optarg
);
308 DEBUGLEVEL
= atoi(optarg
);
322 * Ensure add/delete user and either remote machine or join domain are
325 if((local_flags
& (LOCAL_ADD_USER
|LOCAL_DELETE_USER
)) && ((remote_machine
!= NULL
) || joining_domain
)) {
329 /* Only load interfaces if we are doing network operations. */
331 if (joining_domain
|| remote_machine
) {
338 return join_domain(new_domain
, remote_machine
);
342 * Deal with root - can add a user, but only locally.
353 new_passwd
= xstrdup(argv
[1]);
359 if (!user_name
&& (pwd
= sys_getpwuid(0))) {
360 user_name
= xstrdup(pwd
->pw_name
);
364 fprintf(stderr
,"You must specify a username\n");
368 if (local_flags
& LOCAL_TRUST_ACCOUNT
) {
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;
381 if (local_flags
& LOCAL_ADD_USER
) {
382 safe_free(new_passwd
);
383 new_passwd
= xstrdup(user_name
);
384 strlower(new_passwd
);
388 * Now ensure the username ends in '$' for
392 slprintf(buf
, sizeof(buf
)-1, "%s$", user_name
);
396 if (remote_machine
!= NULL
) {
397 old_passwd
= get_pass("Old SMB password:",stdin_passwd_get
);
403 * If we are trying to enable a user, first we need to find out
404 * if they are using a modern version of the smbpasswd file that
405 * disables a user by just writing a flag into the file. If so
406 * then we can re-enable a user without prompting for a new
407 * password. If not (ie. they have a no stored password in the
408 * smbpasswd file) then we need to prompt for a new password.
411 if(local_flags
& LOCAL_ENABLE_USER
) {
412 struct smb_passwd
*smb_pass
= getsmbpwnam(user_name
);
413 if((smb_pass
!= NULL
) && (smb_pass
->smb_passwd
!= NULL
)) {
414 new_passwd
= xstrdup("XXXX"); /* Don't care. */
419 new_passwd
= prompt_for_new_password(stdin_passwd_get
);
422 fprintf(stderr
, "Unable to get new password.\n");
427 if (!password_change(remote_machine
, user_name
, old_passwd
, new_passwd
, local_flags
)) {
428 fprintf(stderr
,"Failed to modify password entry for user %s\n", user_name
);
433 if(!(local_flags
& (LOCAL_ADD_USER
|LOCAL_DISABLE_USER
|LOCAL_ENABLE_USER
|LOCAL_DELETE_USER
|LOCAL_SET_NO_PASSWORD
))) {
434 struct smb_passwd
*smb_pass
= getsmbpwnam(user_name
);
435 printf("Password changed for user %s.", user_name
);
436 if((smb_pass
!= NULL
) && (smb_pass
->acct_ctrl
& ACB_DISABLED
))
437 printf(" User has disabled flag set.");
438 if((smb_pass
!= NULL
) && (smb_pass
->acct_ctrl
& ACB_PWNOTREQ
))
439 printf(" User has no password flag set.");
444 safe_free(new_passwd
);
449 /*************************************************************
450 handle password changing for non-root
451 *************************************************************/
452 static int process_nonroot(int argc
, char *argv
[])
454 struct passwd
*pwd
= NULL
;
456 BOOL stdin_passwd_get
= False
;
457 char *old_passwd
= NULL
;
458 char *remote_machine
= NULL
;
459 char *user_name
= NULL
;
460 char *new_passwd
= NULL
;
462 while ((ch
= getopt(argc
, argv
, "hD:r:sU:")) != EOF
) {
465 DEBUGLEVEL
= atoi(optarg
);
468 remote_machine
= optarg
;
471 set_line_buffering(stdin
);
472 set_line_buffering(stdout
);
473 set_line_buffering(stderr
);
474 stdin_passwd_get
= True
;
492 new_passwd
= argv
[0];
496 pwd
= sys_getpwuid(getuid());
498 user_name
= xstrdup(pwd
->pw_name
);
500 fprintf(stderr
,"you don't exist - go away\n");
506 * A non-root user is always setting a password
507 * via a remote machine (even if that machine is
511 load_interfaces(); /* Delayed from main() */
513 if (remote_machine
== NULL
) {
514 remote_machine
= "127.0.0.1";
517 if (remote_machine
!= NULL
) {
518 old_passwd
= get_pass("Old SMB password:",stdin_passwd_get
);
522 new_passwd
= prompt_for_new_password(stdin_passwd_get
);
526 fprintf(stderr
, "Unable to get new password.\n");
530 if (!password_change(remote_machine
, user_name
, old_passwd
, new_passwd
, 0)) {
531 fprintf(stderr
,"Failed to change password for %s\n", user_name
);
536 printf("Password changed for user %s\n", user_name
);
539 safe_free(old_passwd
);
540 safe_free(new_passwd
);
547 /*********************************************************
549 **********************************************************/
550 int main(int argc
, char **argv
)
552 static pstring servicesf
= CONFIGFILE
;
554 #if defined(HAVE_SET_AUTH_PARAMETERS)
555 set_auth_parameters(argc
, argv
);
556 #endif /* HAVE_SET_AUTH_PARAMETERS */
560 setup_logging("smbpasswd", True
);
562 charset_initialise();
564 if(!initialize_password_db()) {
565 fprintf(stderr
, "Can't setup password database vectors.\n");
569 if (!lp_load(servicesf
,True
,False
,False
)) {
570 fprintf(stderr
, "Can't load %s - run testparm to debug it\n",
576 * Set the machine NETBIOS name if not already
577 * set from the config file.
580 if (!*global_myname
) {
582 fstrcpy(global_myname
, myhostname());
583 p
= strchr(global_myname
, '.' );
586 strupper(global_myname
);
588 codepage_initialise(lp_client_code_page());
592 /* Check the effective uid - make sure we are not setuid */
593 if ((geteuid() == (uid_t
)0) && (getuid() != (uid_t
)0)) {
594 fprintf(stderr
, "smbpasswd must *NOT* be setuid root.\n");
599 return process_root(argc
, argv
);
602 return process_nonroot(argc
, argv
);