root/source3/utils/smbpasswd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. usage
  2. set_line_buffering
  3. process_options
  4. prompt_for_new_password
  5. password_change
  6. store_ldap_admin_pw
  7. process_root
  8. process_nonroot
  9. main

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

/* [<][>][^][v][top][bottom][index][help] */