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

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/passwd/passwd.c
          +++ new/usr/src/cmd/passwd/passwd.c
↓ open down ↓ 22 lines elided ↑ open up ↑
  23   23   * Use is subject to license terms.
  24   24   */
  25   25  
  26   26  /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
  27   27  /*        All Rights Reserved   */
  28   28  
  29   29  /*      Copyright (c) 1987, 1988 Microsoft Corporation  */
  30   30  /*        All Rights Reserved   */
  31   31  
  32   32  /*
       33 + * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
       34 + */
       35 +/*
  33   36   * passwd is a program whose sole purpose is to manage
  34   37   * the password file, map, or table. It allows system administrator
  35   38   * to add, change and display password attributes.
  36   39   * Non privileged user can change password or display
  37   40   * password attributes which corresponds to their login name.
  38   41   */
  39   42  
  40   43  #include <stdio.h>
  41   44  #include <pwd.h>
  42   45  #include <sys/types.h>
↓ open down ↓ 34 lines elided ↑ open up ↑
  77   80  #define FFLAG 0x020             /* expire  user's password */
  78   81  #define AFLAG 0x040             /* display password attributes for all users */
  79   82  #define SAFLAG (SFLAG|AFLAG)    /* display password attributes for all users */
  80   83  #define WFLAG 0x100             /* warn user to change passwd */
  81   84  #define OFLAG 0x200             /* domain name */
  82   85  #define EFLAG 0x400             /* change shell */
  83   86  #define GFLAG 0x800             /* change gecos information */
  84   87  #define HFLAG 0x1000            /* change home directory */
  85   88  #define XFLAG 0x2000            /* no login */
  86   89  #define UFLAG 0x4000            /* unlock user's password */
       90 +#define STFLAG 0x6000           /* read the password from stdin */
  87   91  
  88   92  #define NONAGEFLAG      (EFLAG | GFLAG | HFLAG)
  89   93  #define AGEFLAG (LFLAG | FFLAG | MFLAG | NFLAG | WFLAG | XFLAG | UFLAG)
  90   94  #define MUTEXFLAG       (DFLAG | LFLAG | XFLAG | UFLAG | SAFLAG)
  91   95  
  92   96  
  93   97  /*
  94   98   * exit code
  95   99   */
  96  100  
↓ open down ↓ 74 lines elided ↑ open up ↑
 171  175  
 172  176  extern int      optind;
 173  177  
 174  178  static int              retval = SUCCESS;
 175  179  static int              pam_retval = PAM_SUCCESS;
 176  180  static uid_t            uid;
 177  181  static char             *prognamep;
 178  182  static long             maxdate;        /* password aging information */
 179  183  static int              passwd_conv(int, struct pam_message **,
 180  184                              struct pam_response **, void *);
      185 +static int              stdin_conv(int, struct pam_message **,
      186 +                            struct pam_response **, void *);
 181  187  static struct pam_conv  pam_conv = {passwd_conv, NULL};
 182  188  static pam_handle_t     *pamh;          /* Authentication handle */
 183  189  static char             *usrname;       /* user whose attribute we update */
 184  190  static adt_session_data_t *ah;  /* audit session handle */
 185  191  static adt_event_data_t *event = NULL; /* event to be generated */
 186  192  
 187  193  static pam_repository_t auth_rep;
 188  194  static pwu_repository_t repository;
 189  195  static pwu_repository_t __REPFILES = { "files", NULL, 0 };
 190  196  
↓ open down ↓ 36 lines elided ↑ open up ↑
 227  233  {
 228  234  
 229  235          int     flag;
 230  236          char    **namelist;
 231  237          int     num_user;
 232  238          int     i;
 233  239          attrlist *attributes = NULL;
 234  240          char    *input;
 235  241          int     tries = 1;
 236  242          int     updated_reps;
      243 +        ssize_t s;
      244 +        char    st_pass[PASS_MAX];
 237  245  
 238      -
 239  246          if ((prognamep = strrchr(argv[0], '/')) != NULL)
 240  247                  ++prognamep;
 241  248          else
 242  249                  prognamep = argv[0];
 243  250  
 244  251          auth_rep.type = NULL;
 245  252          auth_rep.scope = NULL;
 246  253          repository.type = NULL;
 247  254          repository.scope = NULL;
 248  255          repository.scope_len = 0;
↓ open down ↓ 38 lines elided ↑ open up ↑
 287  294                           * Otherwise, it will display or
 288  295                           * modify password aging attributes
 289  296                           */
 290  297                          (void) fprintf(stderr, gettext(MSG_INFO), prognamep,
 291  298                              usrname);
 292  299                  }
 293  300          } else {
 294  301                  usrname = argv[optind];
 295  302          }
 296  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 +
 297  314          if (pam_start("passwd", usrname, &pam_conv, &pamh) != PAM_SUCCESS) {
 298  315                  passwd_exit(NOPERM);
 299  316          }
 300  317  
 301  318          auth_rep.type = repository.type;
 302  319          auth_rep.scope = repository.scope;
 303  320          auth_rep.scope_len = repository.scope_len;
 304  321  
 305  322          if (auth_rep.type != NULL) {
 306  323                  if (pam_set_item(pamh, PAM_REPOSITORY, (void *)&auth_rep)
↓ open down ↓ 48 lines elided ↑ open up ↑
 355  372          case PAM_AUTH_ERR:
 356  373                  (void) fprintf(stderr, gettext(MSG_SORRY), prognamep);
 357  374                  passwd_exit(NOPERM);
 358  375                  break;
 359  376          default:
 360  377                  /* system error */
 361  378                  passwd_exit(FMERR);
 362  379                  break;
 363  380          }
 364  381  
 365      -        if (flag == 0) {                        /* changing user password */
      382 +        if (flag == STFLAG || flag == 0) {      /* changing user password */
 366  383                  int     chk_authtok = 0;        /* check password strength */
 367  384  
 368  385                  dprintf1("call pam_chauthtok() repository name =%s\n",
 369  386                      repository.type);
 370  387  
 371  388                  /* Set up for Audit */
 372  389                  if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
 373  390                          perror("adt_start_session");
 374  391                          passwd_exit(SYSERR);
 375  392                  }
↓ open down ↓ 305 lines elided ↑ open up ↑
 681  698  static int
 682  699  ckarg(int argc, char **argv, attrlist **attributes)
 683  700  {
 684  701          extern char     *optarg;
 685  702          char            *char_p;
 686  703          int     opt;
 687  704          int     flag;
 688  705  
 689  706          flag = 0;
 690  707  
 691      -        while ((opt = getopt(argc, argv, "r:aldefghsux:n:w:N")) != EOF) {
      708 +        while ((opt = getopt(argc, argv, "r:aldefghsux:n:w:N:S")) != EOF) {
 692  709                  switch (opt) {
 693  710  
 694  711                  case 'r': /* Repository Specified */
 695  712                          /* repository: this option should be specified first */
 696  713  
 697  714                          if (repository.type != NULL) {
 698  715                                  (void) fprintf(stderr, gettext(
 699  716                          "Repository is already defined or specified.\n"));
 700  717                                  rusage();
 701  718                                  retval = BADSYN;
↓ open down ↓ 31 lines elided ↑ open up ↑
 733  750                                      "or ldap repository\n"));
 734  751                                  rusage();       /* exit */
 735  752                                  retval = BADSYN;
 736  753                                  return (FAIL);
 737  754                          }
 738  755  
 739  756                          if (ckuid() != SUCCESS) {
 740  757                                  retval = NOPERM;
 741  758                                  return (FAIL);
 742  759                          }
 743      -                        if (flag & (LFLAG|SAFLAG|DFLAG|XFLAG|UFLAG)) {
      760 +                        if (flag & (LFLAG|SAFLAG|DFLAG|XFLAG|UFLAG|STFLAG)) {
 744  761                                  rusage();
 745  762                                  retval = BADOPT;
 746  763                                  return (FAIL);
 747  764                          }
 748  765                          flag |= DFLAG;
 749  766                          attrlist_add(attributes, ATTR_PASSWD, NULL);
 750  767                          break;
 751  768  
 752  769                  case 'N': /* set account to be "no login" */
 753  770  
↓ open down ↓ 11 lines elided ↑ open up ↑
 765  782                                  return (FAIL);
 766  783                          }
 767  784  
 768  785                          /*
 769  786                           * Only privileged processes can execute this
 770  787                           * for FILES or LDAP
 771  788                           */
 772  789                          if ((IS_FILES(repository) || IS_LDAP(repository)) &&
 773  790                              ((retval = ckuid()) != SUCCESS))
 774  791                                  return (FAIL);
 775      -                        if (flag & (MUTEXFLAG|NONAGEFLAG)) {
      792 +                        if (flag & (MUTEXFLAG|NONAGEFLAG|STFLAG)) {
 776  793                                  rusage();       /* exit */
 777  794                                  retval = BADOPT;
 778  795                                  return (FAIL);
 779  796                          }
 780  797                          flag |= XFLAG;
 781  798                          attrlist_add(attributes, ATTR_NOLOGIN_ACCOUNT, NULL);
 782  799                          break;
 783  800  
 784  801                  case 'l': /* lock the password */
 785  802  
↓ open down ↓ 11 lines elided ↑ open up ↑
 797  814                                  return (FAIL);
 798  815                          }
 799  816  
 800  817                          /*
 801  818                           * Only privileged processes can execute this
 802  819                           * for FILES or LDAP
 803  820                           */
 804  821                          if ((IS_FILES(repository) || IS_LDAP(repository)) &&
 805  822                              ((retval = ckuid()) != SUCCESS))
 806  823                                  return (FAIL);
 807      -                        if (flag & (MUTEXFLAG|NONAGEFLAG)) {
      824 +                        if (flag & (MUTEXFLAG|NONAGEFLAG|STFLAG)) {
 808  825                                  rusage();       /* exit */
 809  826                                  retval = BADOPT;
 810  827                                  return (FAIL);
 811  828                          }
 812  829                          flag |= LFLAG;
 813  830                          attrlist_add(attributes, ATTR_LOCK_ACCOUNT, NULL);
 814  831                          break;
 815  832  
 816  833                  case 'u': /* unlock the password */
 817  834  
↓ open down ↓ 11 lines elided ↑ open up ↑
 829  846                                  return (FAIL);
 830  847                          }
 831  848  
 832  849                          /*
 833  850                           * Only privileged processes can execute this
 834  851                           * for FILES or LDAP
 835  852                           */
 836  853                          if ((IS_FILES(repository) || IS_LDAP(repository)) &&
 837  854                              ((retval = ckuid()) != SUCCESS))
 838  855                                  return (FAIL);
 839      -                        if (flag & (MUTEXFLAG|NONAGEFLAG)) {
      856 +                        if (flag & (MUTEXFLAG|NONAGEFLAG|STFLAG)) {
 840  857                                  rusage();       /* exit */
 841  858                                  retval = BADOPT;
 842  859                                  return (FAIL);
 843  860                          }
 844  861                          flag |= UFLAG;
 845  862                          attrlist_add(attributes, ATTR_UNLOCK_ACCOUNT, NULL);
 846  863                          attrlist_add(attributes, ATTR_RST_FAILED_LOGINS, NULL);
 847  864                          break;
 848  865  
 849  866                  case 'x': /* set the max date */
↓ open down ↓ 14 lines elided ↑ open up ↑
 864  881  
 865  882                          /*
 866  883                           * Only privileged process can execute this
 867  884                           * for FILES or LDAP
 868  885                           */
 869  886                          if ((IS_FILES(repository) || IS_LDAP(repository)) &&
 870  887                              (ckuid() != SUCCESS)) {
 871  888                                  retval = NOPERM;
 872  889                                  return (FAIL);
 873  890                          }
 874      -                        if (flag & (SAFLAG|MFLAG|NONAGEFLAG)) {
      891 +                        if (flag & (SAFLAG|MFLAG|NONAGEFLAG|STFLAG)) {
 875  892                                  retval = BADOPT;
 876  893                                  return (FAIL);
 877  894                          }
 878  895                          flag |= MFLAG;
 879  896                          if ((int)strlen(optarg)  <= 0 ||
 880  897                              (maxdate = strtol(optarg, &char_p, 10)) < -1 ||
 881  898                              *char_p != '\0') {
 882  899                                  (void) fprintf(stderr, "%s: %s -x\n",
 883  900                                      prognamep, gettext(MSG_NV));
 884  901                                  retval = BADSYN;
↓ open down ↓ 18 lines elided ↑ open up ↑
 903  920                                  return (FAIL);
 904  921                          }
 905  922  
 906  923                          /*
 907  924                           * Only privileged process can execute this
 908  925                           * for FILES or LDAP
 909  926                           */
 910  927                          if ((IS_FILES(repository) || IS_LDAP(repository)) &&
 911  928                              ((retval = ckuid()) != SUCCESS))
 912  929                                  return (FAIL);
 913      -                        if (flag & (SAFLAG|NFLAG|NONAGEFLAG)) {
      930 +                        if (flag & (SAFLAG|NFLAG|NONAGEFLAG|STFLAG)) {
 914  931                                  retval = BADOPT;
 915  932                                  return (FAIL);
 916  933                          }
 917  934                          flag |= NFLAG;
 918  935                          if ((int)strlen(optarg)  <= 0 ||
 919  936                              (strtol(optarg, &char_p, 10)) < 0 ||
 920  937                              *char_p != '\0') {
 921  938                                  (void) fprintf(stderr, "%s: %s -n\n",
 922  939                                      prognamep, gettext(MSG_NV));
 923  940                                  retval = BADSYN;
↓ open down ↓ 20 lines elided ↑ open up ↑
 944  961  
 945  962                          /*
 946  963                           * Only privileged process can execute this
 947  964                           * for FILES or LDAP
 948  965                           */
 949  966                          if ((IS_FILES(repository) || IS_LDAP(repository)) &&
 950  967                              (ckuid() != SUCCESS)) {
 951  968                                  retval = NOPERM;
 952  969                                  return (FAIL);
 953  970                          }
 954      -                        if (flag & (SAFLAG|WFLAG|NONAGEFLAG)) {
      971 +                        if (flag & (SAFLAG|WFLAG|NONAGEFLAG|STFLAG)) {
 955  972                                  retval = BADOPT;
 956  973                                  return (FAIL);
 957  974                          }
 958  975                          flag |= WFLAG;
 959  976                          if ((int)strlen(optarg)  <= 0 ||
 960  977                              (strtol(optarg, &char_p, 10)) < 0 ||
 961  978                              *char_p != '\0') {
 962  979                                  (void) fprintf(stderr, "%s: %s -w\n",
 963  980                                      prognamep, gettext(MSG_NV));
 964  981                                  retval = BADSYN;
↓ open down ↓ 80 lines elided ↑ open up ↑
1045 1062                                  return (FAIL);
1046 1063                          }
1047 1064  
1048 1065                          /*
1049 1066                           * Only privileged process can execute this
1050 1067                           * for FILES or LDAP
1051 1068                           */
1052 1069                          if ((IS_FILES(repository) || IS_LDAP(repository)) &&
1053 1070                              ((retval = ckuid()) != SUCCESS))
1054 1071                                  return (FAIL);
1055      -                        if (flag & (SAFLAG|FFLAG|NONAGEFLAG)) {
     1072 +                        if (flag & (SAFLAG|FFLAG|NONAGEFLAG|STFLAG)) {
1056 1073                                  retval = BADOPT;
1057 1074                                  return (FAIL);
1058 1075                          }
1059 1076                          flag |= FFLAG;
1060 1077                          attrlist_add(attributes, ATTR_EXPIRE_PASSWORD, NULL);
1061 1078                          break;
1062 1079  
1063 1080                  case 'e': /* change login shell */
1064 1081  
1065 1082                          /* if no repository the default for -e is files */
1066 1083                          if (repository.type == NULL)
1067 1084                                  repository = __REPFILES;
1068 1085  
1069      -                        if (flag & (EFLAG|SAFLAG|AGEFLAG)) {
     1086 +                        if (flag & (EFLAG|SAFLAG|AGEFLAG|STFLAG)) {
1070 1087                                  retval = BADOPT;
1071 1088                                  return (FAIL);
1072 1089                          }
1073 1090                          flag |= EFLAG;
1074 1091                          break;
1075 1092  
1076 1093                  case 'g': /* change gecos information */
1077 1094  
1078 1095                          /* if no repository the default for -g is files */
1079 1096                          if (repository.type == NULL)
1080 1097                                  repository = __REPFILES;
1081 1098  
1082 1099                          /*
1083 1100                           * Only privileged process can execute this
1084 1101                           * for FILES
1085 1102                           */
1086 1103                          if (IS_FILES(repository) && (ckuid() != SUCCESS)) {
1087 1104                                  retval = NOPERM;
1088 1105                                  return (FAIL);
1089 1106                          }
1090      -                        if (flag & (GFLAG|SAFLAG|AGEFLAG)) {
     1107 +                        if (flag & (GFLAG|SAFLAG|AGEFLAG|STFLAG)) {
1091 1108                                  retval = BADOPT;
1092 1109                                  return (FAIL);
1093 1110                          }
1094 1111                          flag |= GFLAG;
1095 1112                          break;
1096 1113  
1097 1114                  case 'h': /* change home dir */
1098 1115  
1099 1116                          /* if no repository the default for -h is files */
1100 1117                          if (repository.type == NULL)
↓ open down ↓ 6 lines elided ↑ open up ↑
1107 1124                                  retval = NOPERM;
1108 1125                                  return (FAIL);
1109 1126                          }
1110 1127                          if (IS_NIS(repository)) {
1111 1128                                  (void) fprintf(stderr, "%s\n",
1112 1129                                      gettext(MSG_NIS_HOMEDIR));
1113 1130                                  retval = BADSYN;
1114 1131                                  return (FAIL);
1115 1132                          }
1116 1133  
1117      -                        if (flag & (HFLAG|SAFLAG|AGEFLAG)) {
     1134 +                        if (flag & (HFLAG|SAFLAG|AGEFLAG|STFLAG)) {
1118 1135                                  retval = BADOPT;
1119 1136                                  return (FAIL);
1120 1137                          }
1121 1138                          flag |= HFLAG;
1122 1139                          break;
1123      -
     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;
1124 1152                  case '?':
1125 1153                          rusage();
1126 1154                          retval = BADOPT;
1127 1155                          return (FAIL);
1128 1156                  }
1129 1157          }
1130 1158  
1131 1159          argc -= optind;
1132 1160          if (argc > 1) {
1133 1161                  rusage();
↓ open down ↓ 532 lines elided ↑ open up ↑
1666 1694                          break;
1667 1695  
1668 1696                  default:
1669 1697                          break;
1670 1698                  }
1671 1699          }
1672 1700          return (PAM_SUCCESS);
1673 1701  }
1674 1702  
1675 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 +/*
1676 1755   *              Utilities Functions
1677 1756   */
1678 1757  
1679 1758  /*
1680 1759   * int attrlist_add(attrlist **l, attrtype type, char *val)
1681 1760   * add an item, with type "type" and value "val", at the tail of list l.
1682 1761   * This functions exits the application on OutOfMem error.
1683 1762   */
1684 1763  void
1685 1764  attrlist_add(attrlist **l, attrtype type, char *val)
↓ open down ↓ 82 lines elided ↑ open up ↑
1768 1847          MSG("\tpasswd [-r files] -s [name]\n");
1769 1848          MSG("\tpasswd [-r files] [-d|-l|-N|-u] [-f] [-n min] [-w warn] "
1770 1849              "[-x max] name\n");
1771 1850          MSG("\tpasswd -r nis [-eg] [name]\n");
1772 1851          MSG("\t\t[-x max] name\n");
1773 1852          MSG("\tpasswd -r ldap [-egh] [name]\n");
1774 1853          MSG("\tpasswd -r ldap -sa\n");
1775 1854          MSG("\tpasswd -r ldap -s [name]\n");
1776 1855          MSG("\tpasswd -r ldap [-l|-N|-u] [-f] [-n min] [-w warn] "
1777 1856              "[-x max] name\n");
     1857 +        MSG("\tpasswd -S [name]\n");
1778 1858  #undef MSG
1779 1859  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX