[BACK]Return to pwd_check.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / passwd

Annotation of src/usr.bin/passwd/pwd_check.c, Revision 1.18

1.18    ! tobias      1: /*     $OpenBSD: pwd_check.c,v 1.17 2021/08/28 06:46:49 robert Exp $   */
1.9       millert     2:
1.1       provos      3: /*
                      4:  * Copyright 2000 Niels Provos <provos@citi.umich.edu>
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. All advertising materials mentioning features or use of this software
                     16:  *    must display the following acknowledgement:
                     17:  *      This product includes software developed by Niels Provos.
                     18:  * 4. The name of the author may not be used to endorse or promote products
                     19:  *    derived from this software without specific prior written permission.
                     20:  *
                     21:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     22:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     23:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     24:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     25:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     26:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     27:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     28:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     29:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     30:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     31:  */
                     32:
                     33: #include <sys/types.h>
                     34: #include <sys/wait.h>
1.2       millert    35:
                     36: #include <stdio.h>
1.1       provos     37: #include <stdlib.h>
1.2       millert    38: #include <string.h>
1.1       provos     39: #include <unistd.h>
                     40: #include <limits.h>
1.2       millert    41: #include <errno.h>
1.3       millert    42: #include <err.h>
1.1       provos     43: #include <regex.h>
                     44: #include <grp.h>
                     45: #include <paths.h>
1.4       millert    46: #include <login_cap.h>
1.11      djm        47: #include <signal.h>
1.12      djm        48:
                     49: int pwd_check(login_cap_t *, char *);
                     50: int pwd_gettries(login_cap_t *);
1.1       provos     51:
                     52: struct pattern {
                     53:        char *match;
                     54:        int flags;
                     55:        char *response;
                     56: };
                     57:
                     58: struct pattern patterns[] = {
                     59:        {
1.6       deraadt    60:                "^[0-9]*$",
1.1       provos     61:                REG_EXTENDED|REG_NOSUB,
                     62:                "Please don't use all-digit passwords."
                     63:        },
                     64:        {
                     65:                "^[a-z]{1,9}$",
                     66:                REG_EXTENDED|REG_NOSUB,
                     67:                "Please don't use an all-lower case password."
                     68:        },
                     69:        {
                     70:                "^[a-z]{1,6}[0-9]+$",
                     71:                REG_EXTENDED|REG_NOSUB|REG_ICASE,
                     72:                "Please use a more complicated password."
                     73:        },
                     74:        {
                     75:                "^([a-z][0-9]){1,4}$",
                     76:                REG_EXTENDED|REG_NOSUB|REG_ICASE,
                     77:                "Please use a more complicated password."
                     78:        },
                     79:        {
                     80:                "^([0-9][a-z]){1,4}$",
                     81:                REG_EXTENDED|REG_NOSUB|REG_ICASE,
                     82:                "Please use a more complicated password."
                     83:        }
                     84: };
                     85:
                     86: int
1.8       millert    87: pwd_check(login_cap_t *lc, char *password)
1.1       provos     88: {
                     89:        regex_t rgx;
1.4       millert    90:        int i, res, min_len;
1.9       millert    91:        char *checker;
1.11      djm        92:        char *argp[] = { "sh", "-c", NULL, NULL};
1.1       provos     93:        int pipefds[2];
1.7       tedu       94:        pid_t child;
1.11      djm        95:        uid_t uid;
                     96:        gid_t gid;
1.6       deraadt    97:
1.9       millert    98:        min_len = (int)login_getcapnum(lc, "minpasswordlen", 6, 6);
1.4       millert    99:        if (min_len > 0 && strlen(password) < min_len) {
1.17      robert    100:                fprintf(stderr, "Please enter a longer password.\n");
1.1       provos    101:                return (0);
                    102:        }
                    103:
1.11      djm       104:        /* External password check program */
1.9       millert   105:        checker = login_getcapstr(lc, "passwordcheck", NULL, NULL);
1.1       provos    106:
1.11      djm       107:        /* Pipes are only used for external checker */
                    108:        if (checker != NULL && pipe(pipefds) == -1) {
1.1       provos    109:                warn("pipe");
                    110:                goto out;
                    111:        }
                    112:
1.11      djm       113:        /* Check password in low-privileged child */
                    114:        switch (child = fork()) {
                    115:        case -1:
                    116:                warn("fork");
1.18    ! tobias    117:                close(pipefds[0]);
        !           118:                close(pipefds[1]);
1.11      djm       119:                goto out;
                    120:        case 0:
                    121:                (void)signal(SIGINT, SIG_DFL);
                    122:                (void)signal(SIGQUIT, SIG_DFL);
                    123:                uid = getuid();
                    124:                gid = getgid();
                    125:                if (setresgid(gid, gid, gid) == -1) {
                    126:                        warn("setresgid");
                    127:                        exit(1);
                    128:                }
                    129:                if (setgroups(1, &gid) == -1) {
                    130:                        warn("setgroups");
                    131:                        exit(1);
                    132:                }
                    133:                if (setresuid(uid, uid, uid) == -1) {
                    134:                        warn("setresuid");
                    135:                        exit(1);
                    136:                }
                    137:
1.13      ajacouto  138:                if (checker == NULL) {
1.14      deraadt   139:                        if (pledge("stdio", NULL) == -1)
                    140:                                err(1, "pledge");
                    141:
1.13      ajacouto  142:                        for (i = 0; i < sizeof(patterns) / sizeof(*patterns); i++) {
1.16      deraadt   143:                                int ret;
                    144:
1.13      ajacouto  145:                                if (regcomp(&rgx, patterns[i].match,
                    146:                                    patterns[i].flags) != 0)
                    147:                                        continue;
1.16      deraadt   148:                                ret = regexec(&rgx, password, 0, NULL, 0);
1.13      ajacouto  149:                                regfree(&rgx);
1.16      deraadt   150:                                if (ret == 0) {
1.17      robert    151:                                        fprintf(stderr, "%s\n", patterns[i].response);
1.13      ajacouto  152:                                        exit(1);
                    153:                                }
1.11      djm       154:                        }
1.13      ajacouto  155:                        /* no external checker in use, accept the password */
                    156:                        exit(0);
1.11      djm       157:                }
1.14      deraadt   158:
                    159:                if (pledge("stdio exec", NULL) == -1)
                    160:                        err(1, "pledge");
1.1       provos    161:
1.11      djm       162:                /* Otherwise, pass control to checker program */
                    163:                argp[2] = checker;
                    164:                if (dup2(pipefds[0], STDIN_FILENO) == -1) {
                    165:                        warn("dup2");
1.1       provos    166:                        exit(1);
1.11      djm       167:                }
1.1       provos    168:                close(pipefds[0]);
                    169:                close(pipefds[1]);
                    170:
1.11      djm       171:                if (execv(_PATH_BSHELL, argp) == -1) {
                    172:                        warn("exec");
1.1       provos    173:                        exit(1);
1.11      djm       174:                }
                    175:                /* NOTREACHED */
                    176:        default:
                    177:                break; /* parent continues below */
1.1       provos    178:        }
                    179:
1.11      djm       180:        if (checker != NULL) {
                    181:                /* Send the password to STDIN of child */
                    182:                close(pipefds[0]);
                    183:                write(pipefds[1], password, strlen(password) + 1);
                    184:                close(pipefds[1]);
                    185:        }
1.1       provos    186:
                    187:        /* get the return value from the child */
1.16      deraadt   188:        while (waitpid(child, &res, 0) == -1) {
1.18    ! tobias    189:                if (errno != EINTR) {
        !           190:                        warn("waitpid");
        !           191:                        goto out;
        !           192:                }
1.16      deraadt   193:        }
                    194:        if (WIFEXITED(res) && WEXITSTATUS(res) == 0) {
1.15      mmcc      195:                free(checker);
1.1       provos    196:                return (1);
1.9       millert   197:        }
1.1       provos    198:
                    199:  out:
1.15      mmcc      200:        free(checker);
1.17      robert    201:        fprintf(stderr, "Please use a different password. Unusual capitalization,\n");
                    202:        fprintf(stderr, "control characters, or digits are suggested.\n");
1.11      djm       203:
1.1       provos    204:        return (0);
                    205: }
                    206:
1.6       deraadt   207: int
1.8       millert   208: pwd_gettries(login_cap_t *lc)
1.4       millert   209: {
                    210:        quad_t ntries;
                    211:
                    212:        if ((ntries = login_getcapnum(lc, "passwordtries", -1, -1)) != -1) {
1.10      moritz    213:                if (ntries >= 0 && ntries <= INT_MAX)
1.9       millert   214:                        return((int)ntries);
                    215:                fprintf(stderr,
                    216:                    "Warning: pwdtries out of range in /etc/login.conf");
1.4       millert   217:        }
1.1       provos    218:
1.8       millert   219:        /*
1.9       millert   220:         * If no amount of tries is specified, return a default of 3,
                    221:         * meaning that after 3 attempts where the user is foiled by the
                    222:         * password checks, it will no longer be checked and they can set
                    223:         * it to whatever they like.  This is the historic BSD behavior.
1.1       provos    224:         */
1.9       millert   225:        return (3);
1.1       provos    226: }