[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.15

1.15    ! mmcc        1: /*     $OpenBSD: pwd_check.c,v 1.14 2015/11/26 19:01:47 deraadt 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.1       provos    100:                printf("Please enter a longer password.\n");
                    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");
                    117:                goto out;
                    118:        case 0:
                    119:                (void)signal(SIGINT, SIG_DFL);
                    120:                (void)signal(SIGQUIT, SIG_DFL);
                    121:                uid = getuid();
                    122:                gid = getgid();
                    123:                if (setresgid(gid, gid, gid) == -1) {
                    124:                        warn("setresgid");
                    125:                        exit(1);
                    126:                }
                    127:                if (setgroups(1, &gid) == -1) {
                    128:                        warn("setgroups");
                    129:                        exit(1);
                    130:                }
                    131:                if (setresuid(uid, uid, uid) == -1) {
                    132:                        warn("setresuid");
                    133:                        exit(1);
                    134:                }
                    135:
1.13      ajacouto  136:                if (checker == NULL) {
1.14      deraadt   137:                        if (pledge("stdio", NULL) == -1)
                    138:                                err(1, "pledge");
                    139:
1.13      ajacouto  140:                        for (i = 0; i < sizeof(patterns) / sizeof(*patterns); i++) {
                    141:                                if (regcomp(&rgx, patterns[i].match,
                    142:                                    patterns[i].flags) != 0)
                    143:                                        continue;
                    144:                                res = regexec(&rgx, password, 0, NULL, 0);
                    145:                                regfree(&rgx);
                    146:                                if (res == 0) {
                    147:                                        printf("%s\n", patterns[i].response);
                    148:                                        exit(1);
                    149:                                }
1.11      djm       150:                        }
1.13      ajacouto  151:                        /* no external checker in use, accept the password */
                    152:                        exit(0);
1.11      djm       153:                }
1.14      deraadt   154:
                    155:                if (pledge("stdio exec", NULL) == -1)
                    156:                        err(1, "pledge");
1.1       provos    157:
1.11      djm       158:                /* Otherwise, pass control to checker program */
                    159:                argp[2] = checker;
                    160:                if (dup2(pipefds[0], STDIN_FILENO) == -1) {
                    161:                        warn("dup2");
1.1       provos    162:                        exit(1);
1.11      djm       163:                }
1.1       provos    164:                close(pipefds[0]);
                    165:                close(pipefds[1]);
                    166:
1.11      djm       167:                if (execv(_PATH_BSHELL, argp) == -1) {
                    168:                        warn("exec");
1.1       provos    169:                        exit(1);
1.11      djm       170:                }
                    171:                /* NOTREACHED */
                    172:        default:
                    173:                break; /* parent continues below */
1.1       provos    174:        }
                    175:
1.11      djm       176:        if (checker != NULL) {
                    177:                /* Send the password to STDIN of child */
                    178:                close(pipefds[0]);
                    179:                write(pipefds[1], password, strlen(password) + 1);
                    180:                close(pipefds[1]);
                    181:        }
1.1       provos    182:
                    183:        /* get the return value from the child */
1.7       tedu      184:        wait(&child);
1.9       millert   185:        if (WIFEXITED(child) && WEXITSTATUS(child) == 0) {
1.15    ! mmcc      186:                free(checker);
1.1       provos    187:                return (1);
1.9       millert   188:        }
1.1       provos    189:
                    190:  out:
1.15    ! mmcc      191:        free(checker);
1.6       deraadt   192:        printf("Please use a different password. Unusual capitalization,\n");
                    193:        printf("control characters, or digits are suggested.\n");
1.11      djm       194:
1.1       provos    195:        return (0);
                    196: }
                    197:
1.6       deraadt   198: int
1.8       millert   199: pwd_gettries(login_cap_t *lc)
1.4       millert   200: {
                    201:        quad_t ntries;
                    202:
                    203:        if ((ntries = login_getcapnum(lc, "passwordtries", -1, -1)) != -1) {
1.10      moritz    204:                if (ntries >= 0 && ntries <= INT_MAX)
1.9       millert   205:                        return((int)ntries);
                    206:                fprintf(stderr,
                    207:                    "Warning: pwdtries out of range in /etc/login.conf");
1.4       millert   208:        }
1.1       provos    209:
1.8       millert   210:        /*
1.9       millert   211:         * If no amount of tries is specified, return a default of 3,
                    212:         * meaning that after 3 attempts where the user is foiled by the
                    213:         * password checks, it will no longer be checked and they can set
                    214:         * it to whatever they like.  This is the historic BSD behavior.
1.1       provos    215:         */
1.9       millert   216:        return (3);
1.1       provos    217: }