Print this page
4107 Add passwd option to read passwords from stdin


  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  27 /*        All Rights Reserved   */
  28 
  29 /*      Copyright (c) 1987, 1988 Microsoft Corporation  */
  30 /*        All Rights Reserved   */
  31 
  32 /*



  33  * passwd is a program whose sole purpose is to manage
  34  * the password file, map, or table. It allows system administrator
  35  * to add, change and display password attributes.
  36  * Non privileged user can change password or display
  37  * password attributes which corresponds to their login name.
  38  */
  39 
  40 #include <stdio.h>
  41 #include <pwd.h>
  42 #include <sys/types.h>
  43 #include <errno.h>
  44 #include <unistd.h>
  45 #include <stdlib.h>
  46 #include <locale.h>
  47 #include <stdarg.h>
  48 #include <errno.h>
  49 #include <string.h>
  50 #include <security/pam_appl.h>
  51 #include <security/pam_modules.h>
  52 #include <security/pam_impl.h>


  67 /*
  68  * flags indicate password attributes to be modified
  69  */
  70 
  71 #define LFLAG 0x001             /* lock user's password  */
  72 #define DFLAG 0x002             /* delete user's  password */
  73 #define MFLAG 0x004             /* set max field -- # of days passwd is valid */
  74 #define NFLAG 0x008             /* set min field -- # of days between */
  75                                 /* password changes */
  76 #define SFLAG 0x010             /* display password attributes */
  77 #define FFLAG 0x020             /* expire  user's password */
  78 #define AFLAG 0x040             /* display password attributes for all users */
  79 #define SAFLAG (SFLAG|AFLAG)    /* display password attributes for all users */
  80 #define WFLAG 0x100             /* warn user to change passwd */
  81 #define OFLAG 0x200             /* domain name */
  82 #define EFLAG 0x400             /* change shell */
  83 #define GFLAG 0x800             /* change gecos information */
  84 #define HFLAG 0x1000            /* change home directory */
  85 #define XFLAG 0x2000            /* no login */
  86 #define UFLAG 0x4000            /* unlock user's password */

  87 
  88 #define NONAGEFLAG      (EFLAG | GFLAG | HFLAG)
  89 #define AGEFLAG (LFLAG | FFLAG | MFLAG | NFLAG | WFLAG | XFLAG | UFLAG)
  90 #define MUTEXFLAG       (DFLAG | LFLAG | XFLAG | UFLAG | SAFLAG)
  91 
  92 
  93 /*
  94  * exit code
  95  */
  96 
  97 #define SUCCESS 0       /* succeeded */
  98 #define NOPERM  1       /* No permission */
  99 #define BADOPT  2       /* Invalid combination of option */
 100 #define FMERR   3       /* File/table manipulation error */
 101 #define FATAL   4       /* Old file/table can not be recovered */
 102 #define FBUSY   5       /* Lock file/table busy */
 103 #define BADSYN  6       /* Incorrect syntax */
 104 #define BADAGE  7       /* Aging is disabled  */
 105 #define NOMEM   8       /* No memory */
 106 #define SYSERR  9       /* System error */


 161 #define DEF_ATTEMPTS    3
 162 
 163 /* Number of characters in that make up an encrypted password (for now) */
 164 #define NUMCP                   13
 165 
 166 #ifdef DEBUG
 167 #define dprintf1        printf
 168 #else
 169 #define dprintf1(w, x)
 170 #endif
 171 
 172 extern int      optind;
 173 
 174 static int              retval = SUCCESS;
 175 static int              pam_retval = PAM_SUCCESS;
 176 static uid_t            uid;
 177 static char             *prognamep;
 178 static long             maxdate;        /* password aging information */
 179 static int              passwd_conv(int, struct pam_message **,
 180                             struct pam_response **, void *);


 181 static struct pam_conv  pam_conv = {passwd_conv, NULL};
 182 static pam_handle_t     *pamh;          /* Authentication handle */
 183 static char             *usrname;       /* user whose attribute we update */
 184 static adt_session_data_t *ah;  /* audit session handle */
 185 static adt_event_data_t *event = NULL; /* event to be generated */
 186 
 187 static pam_repository_t auth_rep;
 188 static pwu_repository_t repository;
 189 static pwu_repository_t __REPFILES = { "files", NULL, 0 };
 190 
 191 /*
 192  * Function Declarations
 193  */
 194 
 195 extern  void            setusershell(void);
 196 extern  char            *getusershell(void);
 197 extern  void            endusershell(void);
 198 
 199 static  void            passwd_exit(int retcode) __NORETURN;
 200 static  void            rusage(void);


 217  *      The main routine will call ckarg() to parse the command line
 218  *      arguments and call the appropriate functions to perform the
 219  *      tasks specified by the arguments. It allows system
 220  *      administrator to add, change and display password attributes.
 221  *      Non privileged user can change password or display
 222  *      password attributes which corresponds to their login name.
 223  */
 224 
 225 int
 226 main(int argc, char *argv[])
 227 {
 228 
 229         int     flag;
 230         char    **namelist;
 231         int     num_user;
 232         int     i;
 233         attrlist *attributes = NULL;
 234         char    *input;
 235         int     tries = 1;
 236         int     updated_reps;


 237 
 238 
 239         if ((prognamep = strrchr(argv[0], '/')) != NULL)
 240                 ++prognamep;
 241         else
 242                 prognamep = argv[0];
 243 
 244         auth_rep.type = NULL;
 245         auth_rep.scope = NULL;
 246         repository.type = NULL;
 247         repository.scope = NULL;
 248         repository.scope_len = 0;
 249 
 250 
 251         /* initialization for variables, set locale and textdomain  */
 252         i = 0;
 253         flag = 0;
 254 
 255         uid = getuid();         /* get the user id */
 256         (void) setlocale(LC_ALL, "");
 257 
 258 #if !defined(TEXT_DOMAIN)       /* Should be defined by cc -D */


 277                         struct passwd *pass = getpwuid(uid);
 278                         if (pass != NULL)
 279                                 usrname = pass->pw_name;
 280                         else {
 281                                 rusage();
 282                                 exit(NOPERM);
 283                         }
 284                 } else if (flag == 0) {
 285                         /*
 286                          * If flag is zero, change passwd.
 287                          * Otherwise, it will display or
 288                          * modify password aging attributes
 289                          */
 290                         (void) fprintf(stderr, gettext(MSG_INFO), prognamep,
 291                             usrname);
 292                 }
 293         } else {
 294                 usrname = argv[optind];
 295         }
 296 










 297         if (pam_start("passwd", usrname, &pam_conv, &pamh) != PAM_SUCCESS) {
 298                 passwd_exit(NOPERM);
 299         }
 300 
 301         auth_rep.type = repository.type;
 302         auth_rep.scope = repository.scope;
 303         auth_rep.scope_len = repository.scope_len;
 304 
 305         if (auth_rep.type != NULL) {
 306                 if (pam_set_item(pamh, PAM_REPOSITORY, (void *)&auth_rep)
 307                     != PAM_SUCCESS) {
 308                         passwd_exit(NOPERM);
 309                 }
 310         }
 311 
 312         if (flag ==  SAFLAG) {  /* display password attributes for all users */
 313                 retval = get_namelist(repository, &namelist, &num_user);
 314                 if (retval != SUCCESS)
 315                         (void) passwd_exit(retval);
 316 


 345         case PAM_SUCCESS:
 346                 break;
 347         case PAM_USER_UNKNOWN:
 348                 (void) fprintf(stderr, gettext(MSG_UNKNOWN), prognamep,
 349                     usrname);
 350                 passwd_exit(NOPERM);
 351                 break;
 352         case PAM_PERM_DENIED:
 353                 passwd_exit(NOPERM);
 354                 break;
 355         case PAM_AUTH_ERR:
 356                 (void) fprintf(stderr, gettext(MSG_SORRY), prognamep);
 357                 passwd_exit(NOPERM);
 358                 break;
 359         default:
 360                 /* system error */
 361                 passwd_exit(FMERR);
 362                 break;
 363         }
 364 
 365         if (flag == 0) {                        /* changing user password */
 366                 int     chk_authtok = 0;        /* check password strength */
 367 
 368                 dprintf1("call pam_chauthtok() repository name =%s\n",
 369                     repository.type);
 370 
 371                 /* Set up for Audit */
 372                 if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
 373                         perror("adt_start_session");
 374                         passwd_exit(SYSERR);
 375                 }
 376                 if ((event = adt_alloc_event(ah, ADT_passwd)) == NULL) {
 377                         perror("adt_alloc_event");
 378                         passwd_exit(NOMEM);
 379                 }
 380 
 381                 /* Don't check account expiration when invoked by root */
 382                 if (ckuid() != SUCCESS) {
 383                         pam_retval = pam_acct_mgmt(pamh, PAM_SILENT);
 384                         switch (pam_retval) {
 385                         case PAM_ACCT_EXPIRED:


 671 }
 672 /*
 673  * ckarg():
 674  *      This function parses and verifies the
 675  *      arguments.  It takes three parameters:
 676  *      argc => # of arguments
 677  *      argv => pointer to an argument
 678  *      attrlist => pointer to list of password attributes
 679  */
 680 
 681 static int
 682 ckarg(int argc, char **argv, attrlist **attributes)
 683 {
 684         extern char     *optarg;
 685         char            *char_p;
 686         int     opt;
 687         int     flag;
 688 
 689         flag = 0;
 690 
 691         while ((opt = getopt(argc, argv, "r:aldefghsux:n:w:N")) != EOF) {
 692                 switch (opt) {
 693 
 694                 case 'r': /* Repository Specified */
 695                         /* repository: this option should be specified first */
 696 
 697                         if (repository.type != NULL) {
 698                                 (void) fprintf(stderr, gettext(
 699                         "Repository is already defined or specified.\n"));
 700                                 rusage();
 701                                 retval = BADSYN;
 702                                 return (FAIL);
 703                         }
 704                         if (strcmp(optarg, "nis") == 0) {
 705                                 repository.type = optarg;
 706                         } else if (strcmp(optarg, "ldap") == 0) {
 707                                 repository.type = optarg;
 708                         } else if (strcmp(optarg, "files") == 0) {
 709                                 repository.type = optarg;
 710                         } else {
 711                                 (void) fprintf(stderr,


 723                                 repository = __REPFILES;
 724 
 725                         /*
 726                          * Delete the password - only privileged processes
 727                          * can execute this for FILES or LDAP
 728                          */
 729                         if (IS_FILES(repository) == FALSE &&
 730                             IS_LDAP(repository) == FALSE) {
 731                                 (void) fprintf(stderr, gettext(
 732                                     "-d only applies to files "
 733                                     "or ldap repository\n"));
 734                                 rusage();       /* exit */
 735                                 retval = BADSYN;
 736                                 return (FAIL);
 737                         }
 738 
 739                         if (ckuid() != SUCCESS) {
 740                                 retval = NOPERM;
 741                                 return (FAIL);
 742                         }
 743                         if (flag & (LFLAG|SAFLAG|DFLAG|XFLAG|UFLAG)) {
 744                                 rusage();
 745                                 retval = BADOPT;
 746                                 return (FAIL);
 747                         }
 748                         flag |= DFLAG;
 749                         attrlist_add(attributes, ATTR_PASSWD, NULL);
 750                         break;
 751 
 752                 case 'N': /* set account to be "no login" */
 753 
 754                         /* if no repository the default for -N is files */
 755                         if (repository.type == NULL)
 756                                 repository = __REPFILES;
 757 
 758                         if (IS_FILES(repository) == FALSE &&
 759                             IS_LDAP(repository) == FALSE) {
 760                                 (void) fprintf(stderr, gettext(
 761                                     "-N only applies to files or ldap "
 762                                     "repository\n"));
 763                                 rusage();       /* exit */
 764                                 retval = BADOPT;
 765                                 return (FAIL);
 766                         }
 767 
 768                         /*
 769                          * Only privileged processes can execute this
 770                          * for FILES or LDAP
 771                          */
 772                         if ((IS_FILES(repository) || IS_LDAP(repository)) &&
 773                             ((retval = ckuid()) != SUCCESS))
 774                                 return (FAIL);
 775                         if (flag & (MUTEXFLAG|NONAGEFLAG)) {
 776                                 rusage();       /* exit */
 777                                 retval = BADOPT;
 778                                 return (FAIL);
 779                         }
 780                         flag |= XFLAG;
 781                         attrlist_add(attributes, ATTR_NOLOGIN_ACCOUNT, NULL);
 782                         break;
 783 
 784                 case 'l': /* lock the password */
 785 
 786                         /* if no repository the default for -l is files */
 787                         if (repository.type == NULL)
 788                                 repository = __REPFILES;
 789 
 790                         if (IS_FILES(repository) == FALSE &&
 791                             IS_LDAP(repository) == FALSE) {
 792                                 (void) fprintf(stderr, gettext(
 793                                     "-l only applies to files or ldap "
 794                                     "repository\n"));
 795                                 rusage();       /* exit */
 796                                 retval = BADOPT;
 797                                 return (FAIL);
 798                         }
 799 
 800                         /*
 801                          * Only privileged processes can execute this
 802                          * for FILES or LDAP
 803                          */
 804                         if ((IS_FILES(repository) || IS_LDAP(repository)) &&
 805                             ((retval = ckuid()) != SUCCESS))
 806                                 return (FAIL);
 807                         if (flag & (MUTEXFLAG|NONAGEFLAG)) {
 808                                 rusage();       /* exit */
 809                                 retval = BADOPT;
 810                                 return (FAIL);
 811                         }
 812                         flag |= LFLAG;
 813                         attrlist_add(attributes, ATTR_LOCK_ACCOUNT, NULL);
 814                         break;
 815 
 816                 case 'u': /* unlock the password */
 817 
 818                         /* if no repository the default for -u is files */
 819                         if (repository.type == NULL)
 820                                 repository = __REPFILES;
 821 
 822                         if (IS_FILES(repository) == FALSE &&
 823                             IS_LDAP(repository) == FALSE) {
 824                                 (void) fprintf(stderr, gettext(
 825                                     "-u only applies to files or ldap "
 826                                     "repository\n"));
 827                                 rusage();       /* exit */
 828                                 retval = BADOPT;
 829                                 return (FAIL);
 830                         }
 831 
 832                         /*
 833                          * Only privileged processes can execute this
 834                          * for FILES or LDAP
 835                          */
 836                         if ((IS_FILES(repository) || IS_LDAP(repository)) &&
 837                             ((retval = ckuid()) != SUCCESS))
 838                                 return (FAIL);
 839                         if (flag & (MUTEXFLAG|NONAGEFLAG)) {
 840                                 rusage();       /* exit */
 841                                 retval = BADOPT;
 842                                 return (FAIL);
 843                         }
 844                         flag |= UFLAG;
 845                         attrlist_add(attributes, ATTR_UNLOCK_ACCOUNT, NULL);
 846                         attrlist_add(attributes, ATTR_RST_FAILED_LOGINS, NULL);
 847                         break;
 848 
 849                 case 'x': /* set the max date */
 850 
 851                         /* if no repository the default for -x is files */
 852                         if (repository.type == NULL)
 853                                 repository = __REPFILES;
 854 
 855                         if (IS_FILES(repository) == FALSE &&
 856                             IS_LDAP(repository) == FALSE) {
 857                                 (void) fprintf(stderr, gettext(
 858                                     "-x only applies to files or ldap "
 859                                     "repository\n"));
 860                                 rusage();       /* exit */
 861                                 retval = BADSYN;
 862                                 return (FAIL);
 863                         }
 864 
 865                         /*
 866                          * Only privileged process can execute this
 867                          * for FILES or LDAP
 868                          */
 869                         if ((IS_FILES(repository) || IS_LDAP(repository)) &&
 870                             (ckuid() != SUCCESS)) {
 871                                 retval = NOPERM;
 872                                 return (FAIL);
 873                         }
 874                         if (flag & (SAFLAG|MFLAG|NONAGEFLAG)) {
 875                                 retval = BADOPT;
 876                                 return (FAIL);
 877                         }
 878                         flag |= MFLAG;
 879                         if ((int)strlen(optarg)  <= 0 ||
 880                             (maxdate = strtol(optarg, &char_p, 10)) < -1 ||
 881                             *char_p != '\0') {
 882                                 (void) fprintf(stderr, "%s: %s -x\n",
 883                                     prognamep, gettext(MSG_NV));
 884                                 retval = BADSYN;
 885                                 return (FAIL);
 886                         }
 887                         attrlist_add(attributes, ATTR_MAX, optarg);
 888                         break;
 889 
 890                 case 'n': /* set the min date */
 891 
 892                         /* if no repository the default for -n is files */
 893                         if (repository.type == NULL)
 894                                 repository = __REPFILES;
 895 
 896                         if (IS_FILES(repository) == FALSE &&
 897                             IS_LDAP(repository) == FALSE) {
 898                                 (void) fprintf(stderr, gettext(
 899                                     "-n only applies to files or ldap "
 900                                     "repository\n"));
 901                                 rusage();       /* exit */
 902                                 retval = BADSYN;
 903                                 return (FAIL);
 904                         }
 905 
 906                         /*
 907                          * Only privileged process can execute this
 908                          * for FILES or LDAP
 909                          */
 910                         if ((IS_FILES(repository) || IS_LDAP(repository)) &&
 911                             ((retval = ckuid()) != SUCCESS))
 912                                 return (FAIL);
 913                         if (flag & (SAFLAG|NFLAG|NONAGEFLAG)) {
 914                                 retval = BADOPT;
 915                                 return (FAIL);
 916                         }
 917                         flag |= NFLAG;
 918                         if ((int)strlen(optarg)  <= 0 ||
 919                             (strtol(optarg, &char_p, 10)) < 0 ||
 920                             *char_p != '\0') {
 921                                 (void) fprintf(stderr, "%s: %s -n\n",
 922                                     prognamep, gettext(MSG_NV));
 923                                 retval = BADSYN;
 924                                 return (FAIL);
 925                         }
 926                         attrlist_add(attributes, ATTR_MIN, optarg);
 927                         break;
 928 
 929                 case 'w': /* set the warning field */
 930 
 931                         /* if no repository the default for -w is files */
 932                         if (repository.type == NULL)
 933                                 repository = __REPFILES;
 934 
 935                         if (IS_FILES(repository) == FALSE &&
 936                             IS_LDAP(repository) == FALSE) {
 937                                 (void) fprintf(stderr, gettext(
 938                                     "-w only applies to files or ldap "
 939                                     "repository\n"));
 940                                 rusage();       /* exit */
 941                                 retval = BADSYN;
 942                                 return (FAIL);
 943                         }
 944 
 945                         /*
 946                          * Only privileged process can execute this
 947                          * for FILES or LDAP
 948                          */
 949                         if ((IS_FILES(repository) || IS_LDAP(repository)) &&
 950                             (ckuid() != SUCCESS)) {
 951                                 retval = NOPERM;
 952                                 return (FAIL);
 953                         }
 954                         if (flag & (SAFLAG|WFLAG|NONAGEFLAG)) {
 955                                 retval = BADOPT;
 956                                 return (FAIL);
 957                         }
 958                         flag |= WFLAG;
 959                         if ((int)strlen(optarg)  <= 0 ||
 960                             (strtol(optarg, &char_p, 10)) < 0 ||
 961                             *char_p != '\0') {
 962                                 (void) fprintf(stderr, "%s: %s -w\n",
 963                                     prognamep, gettext(MSG_NV));
 964                                 retval = BADSYN;
 965                                 return (FAIL);
 966                         }
 967                         attrlist_add(attributes, ATTR_WARN, optarg);
 968                         break;
 969 
 970                 case 's': /* display password attributes */
 971 
 972                         /* if no repository the default for -s is files */
 973                         if (repository.type == NULL)
 974                                 repository = __REPFILES;


1035                         if (repository.type == NULL)
1036                                 repository = __REPFILES;
1037 
1038                         if (IS_FILES(repository) == FALSE &&
1039                             IS_LDAP(repository) == FALSE) {
1040                                 (void) fprintf(stderr, gettext(
1041                                     "-f only applies to files or ldap "
1042                                     "repository\n"));
1043                                 rusage();       /* exit */
1044                                 retval = BADSYN;
1045                                 return (FAIL);
1046                         }
1047 
1048                         /*
1049                          * Only privileged process can execute this
1050                          * for FILES or LDAP
1051                          */
1052                         if ((IS_FILES(repository) || IS_LDAP(repository)) &&
1053                             ((retval = ckuid()) != SUCCESS))
1054                                 return (FAIL);
1055                         if (flag & (SAFLAG|FFLAG|NONAGEFLAG)) {
1056                                 retval = BADOPT;
1057                                 return (FAIL);
1058                         }
1059                         flag |= FFLAG;
1060                         attrlist_add(attributes, ATTR_EXPIRE_PASSWORD, NULL);
1061                         break;
1062 
1063                 case 'e': /* change login shell */
1064 
1065                         /* if no repository the default for -e is files */
1066                         if (repository.type == NULL)
1067                                 repository = __REPFILES;
1068 
1069                         if (flag & (EFLAG|SAFLAG|AGEFLAG)) {
1070                                 retval = BADOPT;
1071                                 return (FAIL);
1072                         }
1073                         flag |= EFLAG;
1074                         break;
1075 
1076                 case 'g': /* change gecos information */
1077 
1078                         /* if no repository the default for -g is files */
1079                         if (repository.type == NULL)
1080                                 repository = __REPFILES;
1081 
1082                         /*
1083                          * Only privileged process can execute this
1084                          * for FILES
1085                          */
1086                         if (IS_FILES(repository) && (ckuid() != SUCCESS)) {
1087                                 retval = NOPERM;
1088                                 return (FAIL);
1089                         }
1090                         if (flag & (GFLAG|SAFLAG|AGEFLAG)) {
1091                                 retval = BADOPT;
1092                                 return (FAIL);
1093                         }
1094                         flag |= GFLAG;
1095                         break;
1096 
1097                 case 'h': /* change home dir */
1098 
1099                         /* if no repository the default for -h is files */
1100                         if (repository.type == NULL)
1101                                 repository = __REPFILES;
1102                         /*
1103                          * Only privileged process can execute this
1104                          * for FILES
1105                          */
1106                         if (IS_FILES(repository) && (ckuid() != SUCCESS)) {
1107                                 retval = NOPERM;
1108                                 return (FAIL);
1109                         }
1110                         if (IS_NIS(repository)) {
1111                                 (void) fprintf(stderr, "%s\n",
1112                                     gettext(MSG_NIS_HOMEDIR));
1113                                 retval = BADSYN;
1114                                 return (FAIL);
1115                         }
1116 
1117                         if (flag & (HFLAG|SAFLAG|AGEFLAG)) {
1118                                 retval = BADOPT;
1119                                 return (FAIL);
1120                         }
1121                         flag |= HFLAG;
1122                         break;
1123 











1124                 case '?':
1125                         rusage();
1126                         retval = BADOPT;
1127                         return (FAIL);
1128                 }
1129         }
1130 
1131         argc -= optind;
1132         if (argc > 1) {
1133                 rusage();
1134                 retval = BADSYN;
1135                 return (FAIL);
1136         }
1137 
1138         /* Make sure (EXPIRE comes after (MAX comes after MIN)) */
1139         attrlist_reorder(attributes);
1140 
1141         /* If no options are specified or only the show option */
1142         /* is specified, return because no option error checking */
1143         /* is needed */


1656                         m++;
1657                         r++;
1658                         break;
1659                 case PAM_TEXT_INFO:
1660                         if (m->msg != NULL) {
1661                                 (void) fputs(m->msg, stdout);
1662                                 (void) fputs("\n", stdout);
1663                         }
1664                         m++;
1665                         r++;
1666                         break;
1667 
1668                 default:
1669                         break;
1670                 }
1671         }
1672         return (PAM_SUCCESS);
1673 }
1674 
1675 /*



















































1676  *              Utilities Functions
1677  */
1678 
1679 /*
1680  * int attrlist_add(attrlist **l, attrtype type, char *val)
1681  * add an item, with type "type" and value "val", at the tail of list l.
1682  * This functions exits the application on OutOfMem error.
1683  */
1684 void
1685 attrlist_add(attrlist **l, attrtype type, char *val)
1686 {
1687         attrlist **w;
1688 
1689         /* tail insert */
1690         for (w = l; *w != NULL; w = &(*w)->next)
1691                 ;
1692 
1693         if ((*w = malloc(sizeof (**w))) == NULL)
1694                 passwd_exit(NOMEM);
1695 


1758 void
1759 rusage(void)
1760 {
1761 
1762 #define MSG(a) (void) fprintf(stderr, gettext((a)));
1763 
1764         MSG("usage:\n");
1765         MSG("\tpasswd [-r files | -r nis | -r ldap] [name]\n");
1766         MSG("\tpasswd [-r files] [-egh] [name]\n");
1767         MSG("\tpasswd [-r files] -sa\n");
1768         MSG("\tpasswd [-r files] -s [name]\n");
1769         MSG("\tpasswd [-r files] [-d|-l|-N|-u] [-f] [-n min] [-w warn] "
1770             "[-x max] name\n");
1771         MSG("\tpasswd -r nis [-eg] [name]\n");
1772         MSG("\t\t[-x max] name\n");
1773         MSG("\tpasswd -r ldap [-egh] [name]\n");
1774         MSG("\tpasswd -r ldap -sa\n");
1775         MSG("\tpasswd -r ldap -s [name]\n");
1776         MSG("\tpasswd -r ldap [-l|-N|-u] [-f] [-n min] [-w warn] "
1777             "[-x max] name\n");

1778 #undef MSG
1779 }


  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  27 /*        All Rights Reserved   */
  28 
  29 /*      Copyright (c) 1987, 1988 Microsoft Corporation  */
  30 /*        All Rights Reserved   */
  31 
  32 /*
  33  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
  34  */
  35 /*
  36  * passwd is a program whose sole purpose is to manage
  37  * the password file, map, or table. It allows system administrator
  38  * to add, change and display password attributes.
  39  * Non privileged user can change password or display
  40  * password attributes which corresponds to their login name.
  41  */
  42 
  43 #include <stdio.h>
  44 #include <pwd.h>
  45 #include <sys/types.h>
  46 #include <errno.h>
  47 #include <unistd.h>
  48 #include <stdlib.h>
  49 #include <locale.h>
  50 #include <stdarg.h>
  51 #include <errno.h>
  52 #include <string.h>
  53 #include <security/pam_appl.h>
  54 #include <security/pam_modules.h>
  55 #include <security/pam_impl.h>


  70 /*
  71  * flags indicate password attributes to be modified
  72  */
  73 
  74 #define LFLAG 0x001             /* lock user's password  */
  75 #define DFLAG 0x002             /* delete user's  password */
  76 #define MFLAG 0x004             /* set max field -- # of days passwd is valid */
  77 #define NFLAG 0x008             /* set min field -- # of days between */
  78                                 /* password changes */
  79 #define SFLAG 0x010             /* display password attributes */
  80 #define FFLAG 0x020             /* expire  user's password */
  81 #define AFLAG 0x040             /* display password attributes for all users */
  82 #define SAFLAG (SFLAG|AFLAG)    /* display password attributes for all users */
  83 #define WFLAG 0x100             /* warn user to change passwd */
  84 #define OFLAG 0x200             /* domain name */
  85 #define EFLAG 0x400             /* change shell */
  86 #define GFLAG 0x800             /* change gecos information */
  87 #define HFLAG 0x1000            /* change home directory */
  88 #define XFLAG 0x2000            /* no login */
  89 #define UFLAG 0x4000            /* unlock user's password */
  90 #define STFLAG 0x6000           /* read the password from stdin */
  91 
  92 #define NONAGEFLAG      (EFLAG | GFLAG | HFLAG)
  93 #define AGEFLAG (LFLAG | FFLAG | MFLAG | NFLAG | WFLAG | XFLAG | UFLAG)
  94 #define MUTEXFLAG       (DFLAG | LFLAG | XFLAG | UFLAG | SAFLAG)
  95 
  96 
  97 /*
  98  * exit code
  99  */
 100 
 101 #define SUCCESS 0       /* succeeded */
 102 #define NOPERM  1       /* No permission */
 103 #define BADOPT  2       /* Invalid combination of option */
 104 #define FMERR   3       /* File/table manipulation error */
 105 #define FATAL   4       /* Old file/table can not be recovered */
 106 #define FBUSY   5       /* Lock file/table busy */
 107 #define BADSYN  6       /* Incorrect syntax */
 108 #define BADAGE  7       /* Aging is disabled  */
 109 #define NOMEM   8       /* No memory */
 110 #define SYSERR  9       /* System error */


 165 #define DEF_ATTEMPTS    3
 166 
 167 /* Number of characters in that make up an encrypted password (for now) */
 168 #define NUMCP                   13
 169 
 170 #ifdef DEBUG
 171 #define dprintf1        printf
 172 #else
 173 #define dprintf1(w, x)
 174 #endif
 175 
 176 extern int      optind;
 177 
 178 static int              retval = SUCCESS;
 179 static int              pam_retval = PAM_SUCCESS;
 180 static uid_t            uid;
 181 static char             *prognamep;
 182 static long             maxdate;        /* password aging information */
 183 static int              passwd_conv(int, struct pam_message **,
 184                             struct pam_response **, void *);
 185 static int              stdin_conv(int, struct pam_message **,
 186                             struct pam_response **, void *);
 187 static struct pam_conv  pam_conv = {passwd_conv, NULL};
 188 static pam_handle_t     *pamh;          /* Authentication handle */
 189 static char             *usrname;       /* user whose attribute we update */
 190 static adt_session_data_t *ah;  /* audit session handle */
 191 static adt_event_data_t *event = NULL; /* event to be generated */
 192 
 193 static pam_repository_t auth_rep;
 194 static pwu_repository_t repository;
 195 static pwu_repository_t __REPFILES = { "files", NULL, 0 };
 196 
 197 /*
 198  * Function Declarations
 199  */
 200 
 201 extern  void            setusershell(void);
 202 extern  char            *getusershell(void);
 203 extern  void            endusershell(void);
 204 
 205 static  void            passwd_exit(int retcode) __NORETURN;
 206 static  void            rusage(void);


 223  *      The main routine will call ckarg() to parse the command line
 224  *      arguments and call the appropriate functions to perform the
 225  *      tasks specified by the arguments. It allows system
 226  *      administrator to add, change and display password attributes.
 227  *      Non privileged user can change password or display
 228  *      password attributes which corresponds to their login name.
 229  */
 230 
 231 int
 232 main(int argc, char *argv[])
 233 {
 234 
 235         int     flag;
 236         char    **namelist;
 237         int     num_user;
 238         int     i;
 239         attrlist *attributes = NULL;
 240         char    *input;
 241         int     tries = 1;
 242         int     updated_reps;
 243         ssize_t s;
 244         char    st_pass[PASS_MAX];
 245 

 246         if ((prognamep = strrchr(argv[0], '/')) != NULL)
 247                 ++prognamep;
 248         else
 249                 prognamep = argv[0];
 250 
 251         auth_rep.type = NULL;
 252         auth_rep.scope = NULL;
 253         repository.type = NULL;
 254         repository.scope = NULL;
 255         repository.scope_len = 0;
 256 
 257 
 258         /* initialization for variables, set locale and textdomain  */
 259         i = 0;
 260         flag = 0;
 261 
 262         uid = getuid();         /* get the user id */
 263         (void) setlocale(LC_ALL, "");
 264 
 265 #if !defined(TEXT_DOMAIN)       /* Should be defined by cc -D */


 284                         struct passwd *pass = getpwuid(uid);
 285                         if (pass != NULL)
 286                                 usrname = pass->pw_name;
 287                         else {
 288                                 rusage();
 289                                 exit(NOPERM);
 290                         }
 291                 } else if (flag == 0) {
 292                         /*
 293                          * If flag is zero, change passwd.
 294                          * Otherwise, it will display or
 295                          * modify password aging attributes
 296                          */
 297                         (void) fprintf(stderr, gettext(MSG_INFO), prognamep,
 298                             usrname);
 299                 }
 300         } else {
 301                 usrname = argv[optind];
 302         }
 303 
 304         if (flag == STFLAG) {
 305                 if ((s = read(STDIN_FILENO, st_pass, sizeof (st_pass))) <= 0)
 306                         passwd_exit(FMERR);
 307 
 308                 st_pass[s - 1] = '\0';
 309                 if ((pam_conv.appdata_ptr = strdup(st_pass)) == NULL)
 310                         passwd_exit(FMERR);
 311                 pam_conv.conv = stdin_conv;
 312         }
 313 
 314         if (pam_start("passwd", usrname, &pam_conv, &pamh) != PAM_SUCCESS) {
 315                 passwd_exit(NOPERM);
 316         }
 317 
 318         auth_rep.type = repository.type;
 319         auth_rep.scope = repository.scope;
 320         auth_rep.scope_len = repository.scope_len;
 321 
 322         if (auth_rep.type != NULL) {
 323                 if (pam_set_item(pamh, PAM_REPOSITORY, (void *)&auth_rep)
 324                     != PAM_SUCCESS) {
 325                         passwd_exit(NOPERM);
 326                 }
 327         }
 328 
 329         if (flag ==  SAFLAG) {  /* display password attributes for all users */
 330                 retval = get_namelist(repository, &namelist, &num_user);
 331                 if (retval != SUCCESS)
 332                         (void) passwd_exit(retval);
 333 


 362         case PAM_SUCCESS:
 363                 break;
 364         case PAM_USER_UNKNOWN:
 365                 (void) fprintf(stderr, gettext(MSG_UNKNOWN), prognamep,
 366                     usrname);
 367                 passwd_exit(NOPERM);
 368                 break;
 369         case PAM_PERM_DENIED:
 370                 passwd_exit(NOPERM);
 371                 break;
 372         case PAM_AUTH_ERR:
 373                 (void) fprintf(stderr, gettext(MSG_SORRY), prognamep);
 374                 passwd_exit(NOPERM);
 375                 break;
 376         default:
 377                 /* system error */
 378                 passwd_exit(FMERR);
 379                 break;
 380         }
 381 
 382         if (flag == STFLAG || flag == 0) {      /* changing user password */
 383                 int     chk_authtok = 0;        /* check password strength */
 384 
 385                 dprintf1("call pam_chauthtok() repository name =%s\n",
 386                     repository.type);
 387 
 388                 /* Set up for Audit */
 389                 if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
 390                         perror("adt_start_session");
 391                         passwd_exit(SYSERR);
 392                 }
 393                 if ((event = adt_alloc_event(ah, ADT_passwd)) == NULL) {
 394                         perror("adt_alloc_event");
 395                         passwd_exit(NOMEM);
 396                 }
 397 
 398                 /* Don't check account expiration when invoked by root */
 399                 if (ckuid() != SUCCESS) {
 400                         pam_retval = pam_acct_mgmt(pamh, PAM_SILENT);
 401                         switch (pam_retval) {
 402                         case PAM_ACCT_EXPIRED:


 688 }
 689 /*
 690  * ckarg():
 691  *      This function parses and verifies the
 692  *      arguments.  It takes three parameters:
 693  *      argc => # of arguments
 694  *      argv => pointer to an argument
 695  *      attrlist => pointer to list of password attributes
 696  */
 697 
 698 static int
 699 ckarg(int argc, char **argv, attrlist **attributes)
 700 {
 701         extern char     *optarg;
 702         char            *char_p;
 703         int     opt;
 704         int     flag;
 705 
 706         flag = 0;
 707 
 708         while ((opt = getopt(argc, argv, "r:aldefghsux:n:w:N:S")) != EOF) {
 709                 switch (opt) {
 710 
 711                 case 'r': /* Repository Specified */
 712                         /* repository: this option should be specified first */
 713 
 714                         if (repository.type != NULL) {
 715                                 (void) fprintf(stderr, gettext(
 716                         "Repository is already defined or specified.\n"));
 717                                 rusage();
 718                                 retval = BADSYN;
 719                                 return (FAIL);
 720                         }
 721                         if (strcmp(optarg, "nis") == 0) {
 722                                 repository.type = optarg;
 723                         } else if (strcmp(optarg, "ldap") == 0) {
 724                                 repository.type = optarg;
 725                         } else if (strcmp(optarg, "files") == 0) {
 726                                 repository.type = optarg;
 727                         } else {
 728                                 (void) fprintf(stderr,


 740                                 repository = __REPFILES;
 741 
 742                         /*
 743                          * Delete the password - only privileged processes
 744                          * can execute this for FILES or LDAP
 745                          */
 746                         if (IS_FILES(repository) == FALSE &&
 747                             IS_LDAP(repository) == FALSE) {
 748                                 (void) fprintf(stderr, gettext(
 749                                     "-d only applies to files "
 750                                     "or ldap repository\n"));
 751                                 rusage();       /* exit */
 752                                 retval = BADSYN;
 753                                 return (FAIL);
 754                         }
 755 
 756                         if (ckuid() != SUCCESS) {
 757                                 retval = NOPERM;
 758                                 return (FAIL);
 759                         }
 760                         if (flag & (LFLAG|SAFLAG|DFLAG|XFLAG|UFLAG|STFLAG)) {
 761                                 rusage();
 762                                 retval = BADOPT;
 763                                 return (FAIL);
 764                         }
 765                         flag |= DFLAG;
 766                         attrlist_add(attributes, ATTR_PASSWD, NULL);
 767                         break;
 768 
 769                 case 'N': /* set account to be "no login" */
 770 
 771                         /* if no repository the default for -N is files */
 772                         if (repository.type == NULL)
 773                                 repository = __REPFILES;
 774 
 775                         if (IS_FILES(repository) == FALSE &&
 776                             IS_LDAP(repository) == FALSE) {
 777                                 (void) fprintf(stderr, gettext(
 778                                     "-N only applies to files or ldap "
 779                                     "repository\n"));
 780                                 rusage();       /* exit */
 781                                 retval = BADOPT;
 782                                 return (FAIL);
 783                         }
 784 
 785                         /*
 786                          * Only privileged processes can execute this
 787                          * for FILES or LDAP
 788                          */
 789                         if ((IS_FILES(repository) || IS_LDAP(repository)) &&
 790                             ((retval = ckuid()) != SUCCESS))
 791                                 return (FAIL);
 792                         if (flag & (MUTEXFLAG|NONAGEFLAG|STFLAG)) {
 793                                 rusage();       /* exit */
 794                                 retval = BADOPT;
 795                                 return (FAIL);
 796                         }
 797                         flag |= XFLAG;
 798                         attrlist_add(attributes, ATTR_NOLOGIN_ACCOUNT, NULL);
 799                         break;
 800 
 801                 case 'l': /* lock the password */
 802 
 803                         /* if no repository the default for -l is files */
 804                         if (repository.type == NULL)
 805                                 repository = __REPFILES;
 806 
 807                         if (IS_FILES(repository) == FALSE &&
 808                             IS_LDAP(repository) == FALSE) {
 809                                 (void) fprintf(stderr, gettext(
 810                                     "-l only applies to files or ldap "
 811                                     "repository\n"));
 812                                 rusage();       /* exit */
 813                                 retval = BADOPT;
 814                                 return (FAIL);
 815                         }
 816 
 817                         /*
 818                          * Only privileged processes can execute this
 819                          * for FILES or LDAP
 820                          */
 821                         if ((IS_FILES(repository) || IS_LDAP(repository)) &&
 822                             ((retval = ckuid()) != SUCCESS))
 823                                 return (FAIL);
 824                         if (flag & (MUTEXFLAG|NONAGEFLAG|STFLAG)) {
 825                                 rusage();       /* exit */
 826                                 retval = BADOPT;
 827                                 return (FAIL);
 828                         }
 829                         flag |= LFLAG;
 830                         attrlist_add(attributes, ATTR_LOCK_ACCOUNT, NULL);
 831                         break;
 832 
 833                 case 'u': /* unlock the password */
 834 
 835                         /* if no repository the default for -u is files */
 836                         if (repository.type == NULL)
 837                                 repository = __REPFILES;
 838 
 839                         if (IS_FILES(repository) == FALSE &&
 840                             IS_LDAP(repository) == FALSE) {
 841                                 (void) fprintf(stderr, gettext(
 842                                     "-u only applies to files or ldap "
 843                                     "repository\n"));
 844                                 rusage();       /* exit */
 845                                 retval = BADOPT;
 846                                 return (FAIL);
 847                         }
 848 
 849                         /*
 850                          * Only privileged processes can execute this
 851                          * for FILES or LDAP
 852                          */
 853                         if ((IS_FILES(repository) || IS_LDAP(repository)) &&
 854                             ((retval = ckuid()) != SUCCESS))
 855                                 return (FAIL);
 856                         if (flag & (MUTEXFLAG|NONAGEFLAG|STFLAG)) {
 857                                 rusage();       /* exit */
 858                                 retval = BADOPT;
 859                                 return (FAIL);
 860                         }
 861                         flag |= UFLAG;
 862                         attrlist_add(attributes, ATTR_UNLOCK_ACCOUNT, NULL);
 863                         attrlist_add(attributes, ATTR_RST_FAILED_LOGINS, NULL);
 864                         break;
 865 
 866                 case 'x': /* set the max date */
 867 
 868                         /* if no repository the default for -x is files */
 869                         if (repository.type == NULL)
 870                                 repository = __REPFILES;
 871 
 872                         if (IS_FILES(repository) == FALSE &&
 873                             IS_LDAP(repository) == FALSE) {
 874                                 (void) fprintf(stderr, gettext(
 875                                     "-x only applies to files or ldap "
 876                                     "repository\n"));
 877                                 rusage();       /* exit */
 878                                 retval = BADSYN;
 879                                 return (FAIL);
 880                         }
 881 
 882                         /*
 883                          * Only privileged process can execute this
 884                          * for FILES or LDAP
 885                          */
 886                         if ((IS_FILES(repository) || IS_LDAP(repository)) &&
 887                             (ckuid() != SUCCESS)) {
 888                                 retval = NOPERM;
 889                                 return (FAIL);
 890                         }
 891                         if (flag & (SAFLAG|MFLAG|NONAGEFLAG|STFLAG)) {
 892                                 retval = BADOPT;
 893                                 return (FAIL);
 894                         }
 895                         flag |= MFLAG;
 896                         if ((int)strlen(optarg)  <= 0 ||
 897                             (maxdate = strtol(optarg, &char_p, 10)) < -1 ||
 898                             *char_p != '\0') {
 899                                 (void) fprintf(stderr, "%s: %s -x\n",
 900                                     prognamep, gettext(MSG_NV));
 901                                 retval = BADSYN;
 902                                 return (FAIL);
 903                         }
 904                         attrlist_add(attributes, ATTR_MAX, optarg);
 905                         break;
 906 
 907                 case 'n': /* set the min date */
 908 
 909                         /* if no repository the default for -n is files */
 910                         if (repository.type == NULL)
 911                                 repository = __REPFILES;
 912 
 913                         if (IS_FILES(repository) == FALSE &&
 914                             IS_LDAP(repository) == FALSE) {
 915                                 (void) fprintf(stderr, gettext(
 916                                     "-n only applies to files or ldap "
 917                                     "repository\n"));
 918                                 rusage();       /* exit */
 919                                 retval = BADSYN;
 920                                 return (FAIL);
 921                         }
 922 
 923                         /*
 924                          * Only privileged process can execute this
 925                          * for FILES or LDAP
 926                          */
 927                         if ((IS_FILES(repository) || IS_LDAP(repository)) &&
 928                             ((retval = ckuid()) != SUCCESS))
 929                                 return (FAIL);
 930                         if (flag & (SAFLAG|NFLAG|NONAGEFLAG|STFLAG)) {
 931                                 retval = BADOPT;
 932                                 return (FAIL);
 933                         }
 934                         flag |= NFLAG;
 935                         if ((int)strlen(optarg)  <= 0 ||
 936                             (strtol(optarg, &char_p, 10)) < 0 ||
 937                             *char_p != '\0') {
 938                                 (void) fprintf(stderr, "%s: %s -n\n",
 939                                     prognamep, gettext(MSG_NV));
 940                                 retval = BADSYN;
 941                                 return (FAIL);
 942                         }
 943                         attrlist_add(attributes, ATTR_MIN, optarg);
 944                         break;
 945 
 946                 case 'w': /* set the warning field */
 947 
 948                         /* if no repository the default for -w is files */
 949                         if (repository.type == NULL)
 950                                 repository = __REPFILES;
 951 
 952                         if (IS_FILES(repository) == FALSE &&
 953                             IS_LDAP(repository) == FALSE) {
 954                                 (void) fprintf(stderr, gettext(
 955                                     "-w only applies to files or ldap "
 956                                     "repository\n"));
 957                                 rusage();       /* exit */
 958                                 retval = BADSYN;
 959                                 return (FAIL);
 960                         }
 961 
 962                         /*
 963                          * Only privileged process can execute this
 964                          * for FILES or LDAP
 965                          */
 966                         if ((IS_FILES(repository) || IS_LDAP(repository)) &&
 967                             (ckuid() != SUCCESS)) {
 968                                 retval = NOPERM;
 969                                 return (FAIL);
 970                         }
 971                         if (flag & (SAFLAG|WFLAG|NONAGEFLAG|STFLAG)) {
 972                                 retval = BADOPT;
 973                                 return (FAIL);
 974                         }
 975                         flag |= WFLAG;
 976                         if ((int)strlen(optarg)  <= 0 ||
 977                             (strtol(optarg, &char_p, 10)) < 0 ||
 978                             *char_p != '\0') {
 979                                 (void) fprintf(stderr, "%s: %s -w\n",
 980                                     prognamep, gettext(MSG_NV));
 981                                 retval = BADSYN;
 982                                 return (FAIL);
 983                         }
 984                         attrlist_add(attributes, ATTR_WARN, optarg);
 985                         break;
 986 
 987                 case 's': /* display password attributes */
 988 
 989                         /* if no repository the default for -s is files */
 990                         if (repository.type == NULL)
 991                                 repository = __REPFILES;


1052                         if (repository.type == NULL)
1053                                 repository = __REPFILES;
1054 
1055                         if (IS_FILES(repository) == FALSE &&
1056                             IS_LDAP(repository) == FALSE) {
1057                                 (void) fprintf(stderr, gettext(
1058                                     "-f only applies to files or ldap "
1059                                     "repository\n"));
1060                                 rusage();       /* exit */
1061                                 retval = BADSYN;
1062                                 return (FAIL);
1063                         }
1064 
1065                         /*
1066                          * Only privileged process can execute this
1067                          * for FILES or LDAP
1068                          */
1069                         if ((IS_FILES(repository) || IS_LDAP(repository)) &&
1070                             ((retval = ckuid()) != SUCCESS))
1071                                 return (FAIL);
1072                         if (flag & (SAFLAG|FFLAG|NONAGEFLAG|STFLAG)) {
1073                                 retval = BADOPT;
1074                                 return (FAIL);
1075                         }
1076                         flag |= FFLAG;
1077                         attrlist_add(attributes, ATTR_EXPIRE_PASSWORD, NULL);
1078                         break;
1079 
1080                 case 'e': /* change login shell */
1081 
1082                         /* if no repository the default for -e is files */
1083                         if (repository.type == NULL)
1084                                 repository = __REPFILES;
1085 
1086                         if (flag & (EFLAG|SAFLAG|AGEFLAG|STFLAG)) {
1087                                 retval = BADOPT;
1088                                 return (FAIL);
1089                         }
1090                         flag |= EFLAG;
1091                         break;
1092 
1093                 case 'g': /* change gecos information */
1094 
1095                         /* if no repository the default for -g is files */
1096                         if (repository.type == NULL)
1097                                 repository = __REPFILES;
1098 
1099                         /*
1100                          * Only privileged process can execute this
1101                          * for FILES
1102                          */
1103                         if (IS_FILES(repository) && (ckuid() != SUCCESS)) {
1104                                 retval = NOPERM;
1105                                 return (FAIL);
1106                         }
1107                         if (flag & (GFLAG|SAFLAG|AGEFLAG|STFLAG)) {
1108                                 retval = BADOPT;
1109                                 return (FAIL);
1110                         }
1111                         flag |= GFLAG;
1112                         break;
1113 
1114                 case 'h': /* change home dir */
1115 
1116                         /* if no repository the default for -h is files */
1117                         if (repository.type == NULL)
1118                                 repository = __REPFILES;
1119                         /*
1120                          * Only privileged process can execute this
1121                          * for FILES
1122                          */
1123                         if (IS_FILES(repository) && (ckuid() != SUCCESS)) {
1124                                 retval = NOPERM;
1125                                 return (FAIL);
1126                         }
1127                         if (IS_NIS(repository)) {
1128                                 (void) fprintf(stderr, "%s\n",
1129                                     gettext(MSG_NIS_HOMEDIR));
1130                                 retval = BADSYN;
1131                                 return (FAIL);
1132                         }
1133 
1134                         if (flag & (HFLAG|SAFLAG|AGEFLAG|STFLAG)) {
1135                                 retval = BADOPT;
1136                                 return (FAIL);
1137                         }
1138                         flag |= HFLAG;
1139                         break;
1140                 case 'S':
1141                         if (ckuid() != SUCCESS) {
1142                                 retval = NOPERM;
1143                                 return (FAIL);
1144                         }
1145                         if (flag & (MUTEXFLAG|NONAGEFLAG|AGEFLAG)) {
1146                                 rusage();       /* exit */
1147                                 retval = BADOPT;
1148                                 return (FAIL);
1149                         }
1150                         flag |= STFLAG;
1151                         break;
1152                 case '?':
1153                         rusage();
1154                         retval = BADOPT;
1155                         return (FAIL);
1156                 }
1157         }
1158 
1159         argc -= optind;
1160         if (argc > 1) {
1161                 rusage();
1162                 retval = BADSYN;
1163                 return (FAIL);
1164         }
1165 
1166         /* Make sure (EXPIRE comes after (MAX comes after MIN)) */
1167         attrlist_reorder(attributes);
1168 
1169         /* If no options are specified or only the show option */
1170         /* is specified, return because no option error checking */
1171         /* is needed */


1684                         m++;
1685                         r++;
1686                         break;
1687                 case PAM_TEXT_INFO:
1688                         if (m->msg != NULL) {
1689                                 (void) fputs(m->msg, stdout);
1690                                 (void) fputs("\n", stdout);
1691                         }
1692                         m++;
1693                         r++;
1694                         break;
1695 
1696                 default:
1697                         break;
1698                 }
1699         }
1700         return (PAM_SUCCESS);
1701 }
1702 
1703 /*
1704  *
1705  * stdin_conv():
1706  *      This is the conv function called for reading
1707  *      the password from standard input.
1708  *
1709  */
1710 /*ARGSUSED*/
1711 static int
1712 stdin_conv(int num_msg, struct pam_message **msg,
1713             struct pam_response **response, void *appdata_ptr)
1714 {
1715         struct pam_response *reply = NULL;
1716         int                     replies = 0;
1717 
1718         if (num_msg <= 0)
1719                 return (PAM_CONV_ERR);
1720 
1721         reply = calloc(num_msg, sizeof (struct pam_response));
1722         if (reply == NULL)
1723                 return (PAM_BUF_ERR);
1724 
1725         for (replies = 0; replies < num_msg; replies ++) {
1726                 reply[replies].resp = NULL;
1727                 reply[replies].resp_retcode = PAM_SUCCESS;
1728                 switch (msg[replies]->msg_style) {
1729                 case PAM_PROMPT_ECHO_OFF:
1730                         reply[replies].resp = strdup(appdata_ptr);
1731                         if (reply[replies].resp == NULL)
1732                                 goto err;
1733                         break;
1734                 case PAM_PROMPT_ECHO_ON:
1735                 case PAM_ERROR_MSG:
1736                 case PAM_TEXT_INFO:
1737                         reply[replies].resp = strdup("");
1738                         if (reply[replies].resp == NULL)
1739                                 goto err;
1740                         break;
1741                 default:
1742                         free(reply);
1743                         return (PAM_CONV_ERR);
1744                 }
1745         }
1746         *response = reply;
1747         return (PAM_SUCCESS);
1748 
1749 err:
1750         free(reply);
1751         return (PAM_BUF_ERR);
1752 }
1753 
1754 /*
1755  *              Utilities Functions
1756  */
1757 
1758 /*
1759  * int attrlist_add(attrlist **l, attrtype type, char *val)
1760  * add an item, with type "type" and value "val", at the tail of list l.
1761  * This functions exits the application on OutOfMem error.
1762  */
1763 void
1764 attrlist_add(attrlist **l, attrtype type, char *val)
1765 {
1766         attrlist **w;
1767 
1768         /* tail insert */
1769         for (w = l; *w != NULL; w = &(*w)->next)
1770                 ;
1771 
1772         if ((*w = malloc(sizeof (**w))) == NULL)
1773                 passwd_exit(NOMEM);
1774 


1837 void
1838 rusage(void)
1839 {
1840 
1841 #define MSG(a) (void) fprintf(stderr, gettext((a)));
1842 
1843         MSG("usage:\n");
1844         MSG("\tpasswd [-r files | -r nis | -r ldap] [name]\n");
1845         MSG("\tpasswd [-r files] [-egh] [name]\n");
1846         MSG("\tpasswd [-r files] -sa\n");
1847         MSG("\tpasswd [-r files] -s [name]\n");
1848         MSG("\tpasswd [-r files] [-d|-l|-N|-u] [-f] [-n min] [-w warn] "
1849             "[-x max] name\n");
1850         MSG("\tpasswd -r nis [-eg] [name]\n");
1851         MSG("\t\t[-x max] name\n");
1852         MSG("\tpasswd -r ldap [-egh] [name]\n");
1853         MSG("\tpasswd -r ldap -sa\n");
1854         MSG("\tpasswd -r ldap -s [name]\n");
1855         MSG("\tpasswd -r ldap [-l|-N|-u] [-f] [-n min] [-w warn] "
1856             "[-x max] name\n");
1857         MSG("\tpasswd -S [name]\n");
1858 #undef MSG
1859 }