1/* 2 * Unix SMB/CIFS implementation. 3 * Copyright (C) Jeremy Allison 1995-1998 4 * Copyright (C) Tim Potter 2001 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation; either version 2 of the License, or (at your 9 * option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 * more details. 15 * 16 * You should have received a copy of the GNU General Public License along with 17 * this program; if not, write to the Free Software Foundation, Inc., 675 18 * Mass Ave, Cambridge, MA 02139, USA. */ 19 20#include "includes.h" 21 22extern BOOL AllowDebugChange; 23 24/* 25 * Next two lines needed for SunOS and don't 26 * hurt anything else... 27 */ 28extern char *optarg; 29extern int optind; 30 31/* forced running in root-mode */ 32static BOOL got_username = False; 33static BOOL stdin_passwd_get = False; 34static fstring user_name; 35static char *new_passwd = NULL; 36static const char *remote_machine = NULL; 37 38static fstring ldap_secret; 39 40 41/********************************************************* 42 Print command usage on stderr and die. 43**********************************************************/ 44static void usage(void) 45{ 46 printf("When run by root:\n"); 47 printf(" smbpasswd [options] [username]\n"); 48 printf("otherwise:\n"); 49 printf(" smbpasswd [options]\n\n"); 50 51 printf("options:\n"); 52 printf(" -L local mode (must be first option)\n"); 53 printf(" -h print this usage message\n"); 54 printf(" -s use stdin for password prompt\n"); 55 printf(" -c smb.conf file Use the given path to the smb.conf file\n"); 56 printf(" -D LEVEL debug level\n"); 57 printf(" -r MACHINE remote machine\n"); 58 printf(" -U USER remote username\n"); 59 60 printf("extra options when run by root or in local mode:\n"); 61 printf(" -a add user\n"); 62 printf(" -d disable user\n"); 63 printf(" -e enable user\n"); 64 printf(" -i interdomain trust account\n"); 65 printf(" -m machine trust account\n"); 66 printf(" -n set no password\n"); 67 printf(" -w PASSWORD ldap admin password\n"); 68 printf(" -x delete user\n"); 69 printf(" -R ORDER name resolve order\n"); 70 71 exit(1); 72} 73 74static void set_line_buffering(FILE *f) 75{ 76 setvbuf(f, NULL, _IOLBF, 0); 77} 78 79/******************************************************************* 80 Process command line options 81 ******************************************************************/ 82 83static int process_options(int argc, char **argv, int local_flags) 84{ 85 int ch; 86 pstring configfile; 87 pstrcpy(configfile, dyn_CONFIGFILE); 88 89 local_flags |= LOCAL_SET_PASSWORD; 90 91 ZERO_STRUCT(user_name); 92 93 user_name[0] = '\0'; 94 95 while ((ch = getopt(argc, argv, "c:axdehminjr:sw:R:D:U:L")) != EOF) { 96 switch(ch) { 97 case 'L': 98 local_flags |= LOCAL_AM_ROOT; 99 break; 100 case 'c': 101 pstrcpy(configfile,optarg); 102 break; 103 case 'a': 104 local_flags |= LOCAL_ADD_USER; 105 break; 106 case 'x': 107 local_flags |= LOCAL_DELETE_USER; 108 local_flags &= ~LOCAL_SET_PASSWORD; 109 break; 110 case 'd': 111 local_flags |= LOCAL_DISABLE_USER; 112 local_flags &= ~LOCAL_SET_PASSWORD; 113 break; 114 case 'e': 115 local_flags |= LOCAL_ENABLE_USER; 116 local_flags &= ~LOCAL_SET_PASSWORD; 117 break; 118 case 'm': 119 local_flags |= LOCAL_TRUST_ACCOUNT; 120 break; 121 case 'i': 122 local_flags |= LOCAL_INTERDOM_ACCOUNT; 123 break; 124 case 'j': 125 d_printf("See 'net join' for this functionality\n"); 126 exit(1); 127 break; 128 case 'n': 129 local_flags |= LOCAL_SET_NO_PASSWORD; 130 local_flags &= ~LOCAL_SET_PASSWORD; 131 new_passwd = smb_xstrdup("NO PASSWORD"); 132 break; 133 case 'r': 134 remote_machine = optarg; 135 break; 136 case 's': 137 set_line_buffering(stdin); 138 set_line_buffering(stdout); 139 set_line_buffering(stderr); 140 stdin_passwd_get = True; 141 break; 142 case 'w': 143 local_flags |= LOCAL_SET_LDAP_ADMIN_PW; 144 fstrcpy(ldap_secret, optarg); 145 break; 146 case 'R': 147 lp_set_name_resolve_order(optarg); 148 break; 149 case 'D': 150 DEBUGLEVEL = atoi(optarg); 151 break; 152 case 'U': { 153 got_username = True; 154 fstrcpy(user_name, optarg); 155 break; 156 } 157 case 'h': 158 default: 159 usage(); 160 } 161 } 162 163 argc -= optind; 164 argv += optind; 165 166 switch(argc) { 167 case 0: 168 if (!got_username) 169 fstrcpy(user_name, ""); 170 break; 171 case 1: 172 if (!(local_flags & LOCAL_AM_ROOT)) { 173 usage(); 174 } else { 175 if (got_username) { 176 usage(); 177 } else { 178 fstrcpy(user_name, argv[0]); 179 } 180 } 181 break; 182 default: 183 usage(); 184 } 185 186 if (!lp_load(configfile,True,False,False)) { 187 fprintf(stderr, "Can't load %s - run testparm to debug it\n", 188 dyn_CONFIGFILE); 189 exit(1); 190 } 191 192 return local_flags; 193} 194 195/************************************************************* 196 Utility function to prompt for passwords from stdin. Each 197 password entered must end with a newline. 198*************************************************************/ 199static char *stdin_new_passwd(void) 200{ 201 static fstring new_pw; 202 size_t len; 203 204 ZERO_ARRAY(new_pw); 205 206 /* 207 * if no error is reported from fgets() and string at least contains 208 * the newline that ends the password, then replace the newline with 209 * a null terminator. 210 */ 211 if ( fgets(new_pw, sizeof(new_pw), stdin) != NULL) { 212 if ((len = strlen(new_pw)) > 0) { 213 if(new_pw[len-1] == '\n') 214 new_pw[len - 1] = 0; 215 } 216 } 217 return(new_pw); 218} 219 220 221/************************************************************* 222 Utility function to get passwords via tty or stdin 223 Used if the '-s' option is set to silently get passwords 224 to enable scripting. 225*************************************************************/ 226static char *get_pass( const char *prompt, BOOL stdin_get) 227{ 228 char *p; 229 if (stdin_get) { 230 p = stdin_new_passwd(); 231 } else { 232 p = getpass(prompt); 233 } 234 return smb_xstrdup(p); 235} 236 237/************************************************************* 238 Utility function to prompt for new password. 239*************************************************************/ 240static char *prompt_for_new_password(BOOL stdin_get) 241{ 242 char *p; 243 fstring new_pw; 244 245 ZERO_ARRAY(new_pw); 246 247 p = get_pass("New SMB password:", stdin_get); 248 249 fstrcpy(new_pw, p); 250 SAFE_FREE(p); 251 252 p = get_pass("Retype new SMB password:", stdin_get); 253 254 if (strcmp(p, new_pw)) { 255 fprintf(stderr, "Mismatch - password unchanged.\n"); 256 ZERO_ARRAY(new_pw); 257 SAFE_FREE(p); 258 return NULL; 259 } 260 261 return p; 262} 263 264 265/************************************************************* 266 Change a password either locally or remotely. 267*************************************************************/ 268 269static BOOL password_change(const char *remote_mach, char *username, 270 char *old_passwd, char *new_pw, int local_flags) 271{ 272 BOOL ret; 273 pstring err_str; 274 pstring msg_str; 275 276 if (remote_mach != NULL) { 277 if (local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER|LOCAL_DISABLE_USER|LOCAL_ENABLE_USER| 278 LOCAL_TRUST_ACCOUNT|LOCAL_SET_NO_PASSWORD)) { 279 /* these things can't be done remotely yet */ 280 return False; 281 } 282 ret = remote_password_change(remote_mach, username, 283 old_passwd, new_pw, err_str, sizeof(err_str)); 284 if(*err_str) 285 fprintf(stderr, err_str); 286 return ret; 287 } 288 289 ret = local_password_change(username, local_flags, new_pw, 290 err_str, sizeof(err_str), msg_str, sizeof(msg_str)); 291 292 if(*msg_str) 293 printf(msg_str); 294 if(*err_str) 295 fprintf(stderr, err_str); 296 297 return ret; 298} 299 300/******************************************************************* 301 Store the LDAP admin password in secrets.tdb 302 ******************************************************************/ 303static BOOL store_ldap_admin_pw (char* pw) 304{ 305 if (!pw) 306 return False; 307 308 if (!secrets_init()) 309 return False; 310 311 return secrets_store_ldap_pw(lp_ldap_admin_dn(), pw); 312} 313 314 315/************************************************************* 316 Handle password changing for root. 317*************************************************************/ 318 319static int process_root(int local_flags) 320{ 321 struct passwd *pwd; 322 int result = 0; 323 char *old_passwd = NULL; 324 325 if (local_flags & LOCAL_SET_LDAP_ADMIN_PW) { 326 printf("Setting stored password for \"%s\" in secrets.tdb\n", 327 lp_ldap_admin_dn()); 328 if (!store_ldap_admin_pw(ldap_secret)) 329 DEBUG(0,("ERROR: Failed to store the ldap admin password!\n")); 330 goto done; 331 } 332 333 /* Ensure passdb startup(). */ 334 if(!initialize_password_db(False)) { 335 DEBUG(0, ("Failed to open passdb!\n")); 336 exit(1); 337 } 338 339 /* Ensure we have a SAM sid. */ 340 get_global_sam_sid(); 341 342 /* 343 * Ensure both add/delete user are not set 344 * Ensure add/delete user and either remote machine or join domain are 345 * not both set. 346 */ 347 if(((local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER)) == (LOCAL_ADD_USER|LOCAL_DELETE_USER)) || 348 ((local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER)) && 349 (remote_machine != NULL))) { 350 usage(); 351 } 352 353 /* Only load interfaces if we are doing network operations. */ 354 355 if (remote_machine) { 356 load_interfaces(); 357 } 358 359 if (!user_name[0] && (pwd = getpwuid_alloc(geteuid()))) { 360 fstrcpy(user_name, pwd->pw_name); 361 passwd_free(&pwd); 362 } 363 364 if (!user_name[0]) { 365 fprintf(stderr,"You must specify a username\n"); 366 exit(1); 367 } 368 369 if (local_flags & LOCAL_TRUST_ACCOUNT) { 370 /* add the $ automatically */ 371 static fstring buf; 372 373 /* 374 * Remove any trailing '$' before we 375 * generate the initial machine password. 376 */ 377 378 if (user_name[strlen(user_name)-1] == '$') { 379 user_name[strlen(user_name)-1] = 0; 380 } 381 382 if (local_flags & LOCAL_ADD_USER) { 383 SAFE_FREE(new_passwd); 384 new_passwd = smb_xstrdup(user_name); 385 strlower_m(new_passwd); 386 } 387 388 /* 389 * Now ensure the username ends in '$' for 390 * the machine add. 391 */ 392 393 slprintf(buf, sizeof(buf)-1, "%s$", user_name); 394 fstrcpy(user_name, buf); 395 } else if (local_flags & LOCAL_INTERDOM_ACCOUNT) { 396 static fstring buf; 397 398 if ((local_flags & LOCAL_ADD_USER) && (new_passwd == NULL)) { 399 /* 400 * Prompt for trusting domain's account password 401 */ 402 new_passwd = prompt_for_new_password(stdin_passwd_get); 403 if(!new_passwd) { 404 fprintf(stderr, "Unable to get newpassword.\n"); 405 exit(1); 406 } 407 } 408 409 /* prepare uppercased and '$' terminated username */ 410 slprintf(buf, sizeof(buf) - 1, "%s$", user_name); 411 fstrcpy(user_name, buf); 412 413 } else { 414 415 if (remote_machine != NULL) { 416 old_passwd = get_pass("Old SMB password:",stdin_passwd_get); 417 } 418 419 if (!(local_flags & LOCAL_SET_PASSWORD)) { 420 421 /* 422 * If we are trying to enable a user, first we need to find out 423 * if they are using a modern version of the smbpasswd file that 424 * disables a user by just writing a flag into the file. If so 425 * then we can re-enable a user without prompting for a new 426 * password. If not (ie. they have a no stored password in the 427 * smbpasswd file) then we need to prompt for a new password. 428 */ 429 430 if(local_flags & LOCAL_ENABLE_USER) { 431 SAM_ACCOUNT *sampass = NULL; 432 BOOL ret; 433 434 pdb_init_sam(&sampass); 435 ret = pdb_getsampwnam(sampass, user_name); 436 if((ret) && 437 (pdb_get_lanman_passwd(sampass) == NULL)) { 438 local_flags |= LOCAL_SET_PASSWORD; 439 } 440 pdb_free_sam(&sampass); 441 } 442 } 443 444 if((local_flags & LOCAL_SET_PASSWORD) && (new_passwd == NULL)) { 445 new_passwd = prompt_for_new_password(stdin_passwd_get); 446 447 if(!new_passwd) { 448 fprintf(stderr, "Unable to get new password.\n"); 449 exit(1); 450 } 451 } 452 } 453 454 if (!password_change(remote_machine, user_name, old_passwd, new_passwd, local_flags)) { 455 fprintf(stderr,"Failed to modify password entry for user %s\n", user_name); 456 result = 1; 457 goto done; 458 } 459 460 if(remote_machine) { 461 printf("Password changed for user %s on %s.\n", user_name, remote_machine ); 462 } else if(!(local_flags & (LOCAL_ADD_USER|LOCAL_DISABLE_USER|LOCAL_ENABLE_USER|LOCAL_DELETE_USER|LOCAL_SET_NO_PASSWORD|LOCAL_SET_PASSWORD))) { 463 SAM_ACCOUNT *sampass = NULL; 464 BOOL ret; 465 466 pdb_init_sam(&sampass); 467 ret = pdb_getsampwnam(sampass, user_name); 468 469 printf("Password changed for user %s.", user_name ); 470 if( (ret != False) && (pdb_get_acct_ctrl(sampass)&ACB_DISABLED) ) 471 printf(" User has disabled flag set."); 472 if((ret != False) && (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ) ) 473 printf(" User has no password flag set."); 474 printf("\n"); 475 pdb_free_sam(&sampass); 476 } 477 478 done: 479 SAFE_FREE(new_passwd); 480 return result; 481} 482 483 484/************************************************************* 485 Handle password changing for non-root. 486*************************************************************/ 487 488static int process_nonroot(int local_flags) 489{ 490 struct passwd *pwd = NULL; 491 int result = 0; 492 char *old_pw = NULL; 493 char *new_pw = NULL; 494 495 if (local_flags & ~(LOCAL_AM_ROOT | LOCAL_SET_PASSWORD)) { 496 /* Extra flags that we can't honor non-root */ 497 usage(); 498 } 499 500 if (!user_name[0]) { 501 pwd = getpwuid_alloc(getuid()); 502 if (pwd) { 503 fstrcpy(user_name,pwd->pw_name); 504 passwd_free(&pwd); 505 } else { 506 fprintf(stderr, "smbpasswd: you don't exist - go away\n"); 507 exit(1); 508 } 509 } 510 511 /* 512 * A non-root user is always setting a password 513 * via a remote machine (even if that machine is 514 * localhost). 515 */ 516 517 load_interfaces(); /* Delayed from main() */ 518 519 if (remote_machine == NULL) { 520 remote_machine = "127.0.0.1"; 521 } 522 523 if (remote_machine != NULL) { 524 old_pw = get_pass("Old SMB password:",stdin_passwd_get); 525 } 526 527 if (!new_passwd) { 528 new_pw = prompt_for_new_password(stdin_passwd_get); 529 } 530 else 531 new_pw = smb_xstrdup(new_passwd); 532 533 if (!new_pw) { 534 fprintf(stderr, "Unable to get new password.\n"); 535 exit(1); 536 } 537 538 if (!password_change(remote_machine, user_name, old_pw, new_pw, 0)) { 539 fprintf(stderr,"Failed to change password for %s\n", user_name); 540 result = 1; 541 goto done; 542 } 543 544 printf("Password changed for user %s\n", user_name); 545 546 done: 547 SAFE_FREE(old_pw); 548 SAFE_FREE(new_pw); 549 550 return result; 551} 552 553 554 555/********************************************************* 556 Start here. 557**********************************************************/ 558int main(int argc, char **argv) 559{ 560 int local_flags = 0; 561 562 AllowDebugChange = False; 563 564#if defined(HAVE_SET_AUTH_PARAMETERS) 565 set_auth_parameters(argc, argv); 566#endif /* HAVE_SET_AUTH_PARAMETERS */ 567 568 if (getuid() == 0) { 569 local_flags = LOCAL_AM_ROOT; 570 } 571 572 local_flags = process_options(argc, argv, local_flags); 573 574 setup_logging("smbpasswd", True); 575 576 /* 577 * Set the machine NETBIOS name if not already 578 * set from the config file. 579 */ 580 581 if (!init_names()) 582 return 1; 583 584 /* Check the effective uid - make sure we are not setuid */ 585 if (is_setuid_root()) { 586 fprintf(stderr, "smbpasswd must *NOT* be setuid root.\n"); 587 exit(1); 588 } 589 590 if (local_flags & LOCAL_AM_ROOT) { 591 secrets_init(); 592 return process_root(local_flags); 593 } 594 595 return process_nonroot(local_flags); 596} 597