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

1.11    ! djm         1: /*     $OpenBSD: pwd_check.c,v 1.10 2005/03/04 15:36:03 moritz 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.1       provos     48:
                     49: struct pattern {
                     50:        char *match;
                     51:        int flags;
                     52:        char *response;
                     53: };
                     54:
                     55: struct pattern patterns[] = {
                     56:        {
1.6       deraadt    57:                "^[0-9]*$",
1.1       provos     58:                REG_EXTENDED|REG_NOSUB,
                     59:                "Please don't use all-digit passwords."
                     60:        },
                     61:        {
                     62:                "^[a-z]{1,9}$",
                     63:                REG_EXTENDED|REG_NOSUB,
                     64:                "Please don't use an all-lower case password."
                     65:        },
                     66:        {
                     67:                "^[a-z]{1,6}[0-9]+$",
                     68:                REG_EXTENDED|REG_NOSUB|REG_ICASE,
                     69:                "Please use a more complicated password."
                     70:        },
                     71:        {
                     72:                "^([a-z][0-9]){1,4}$",
                     73:                REG_EXTENDED|REG_NOSUB|REG_ICASE,
                     74:                "Please use a more complicated password."
                     75:        },
                     76:        {
                     77:                "^([0-9][a-z]){1,4}$",
                     78:                REG_EXTENDED|REG_NOSUB|REG_ICASE,
                     79:                "Please use a more complicated password."
                     80:        }
                     81: };
                     82:
                     83: int
1.8       millert    84: pwd_check(login_cap_t *lc, char *password)
1.1       provos     85: {
                     86:        regex_t rgx;
1.4       millert    87:        int i, res, min_len;
1.9       millert    88:        char *checker;
1.11    ! djm        89:        char *argp[] = { "sh", "-c", NULL, NULL};
1.1       provos     90:        int pipefds[2];
1.7       tedu       91:        pid_t child;
1.11    ! djm        92:        uid_t uid;
        !            93:        gid_t gid;
1.6       deraadt    94:
1.9       millert    95:        min_len = (int)login_getcapnum(lc, "minpasswordlen", 6, 6);
1.4       millert    96:        if (min_len > 0 && strlen(password) < min_len) {
1.1       provos     97:                printf("Please enter a longer password.\n");
                     98:                return (0);
                     99:        }
                    100:
1.11    ! djm       101:        /* External password check program */
1.9       millert   102:        checker = login_getcapstr(lc, "passwordcheck", NULL, NULL);
1.1       provos    103:
1.11    ! djm       104:        /* Pipes are only used for external checker */
        !           105:        if (checker != NULL && pipe(pipefds) == -1) {
1.1       provos    106:                warn("pipe");
                    107:                goto out;
                    108:        }
                    109:
1.11    ! djm       110:        /* Check password in low-privileged child */
        !           111:        switch (child = fork()) {
        !           112:        case -1:
        !           113:                warn("fork");
        !           114:                goto out;
        !           115:        case 0:
        !           116:                (void)signal(SIGINT, SIG_DFL);
        !           117:                (void)signal(SIGQUIT, SIG_DFL);
        !           118:                uid = getuid();
        !           119:                gid = getgid();
        !           120:                if (setresgid(gid, gid, gid) == -1) {
        !           121:                        warn("setresgid");
        !           122:                        exit(1);
        !           123:                }
        !           124:                if (setgroups(1, &gid) == -1) {
        !           125:                        warn("setgroups");
        !           126:                        exit(1);
        !           127:                }
        !           128:                if (setresuid(uid, uid, uid) == -1) {
        !           129:                        warn("setresuid");
        !           130:                        exit(1);
        !           131:                }
        !           132:
        !           133:                for (i = 0; i < sizeof(patterns) / sizeof(*patterns); i++) {
        !           134:                        if (regcomp(&rgx, patterns[i].match,
        !           135:                            patterns[i].flags) != 0)
        !           136:                                continue;
        !           137:                        res = regexec(&rgx, password, 0, NULL, 0);
        !           138:                        regfree(&rgx);
        !           139:                        if (res == 0) {
        !           140:                                printf("%s\n", patterns[i].response);
        !           141:                                exit(1);
        !           142:                        }
        !           143:                }
        !           144:
        !           145:                /* If no external checker in use, accept the password */
        !           146:                if (checker == NULL)
        !           147:                        exit(0);
1.1       provos    148:
1.11    ! djm       149:                /* Otherwise, pass control to checker program */
        !           150:                argp[2] = checker;
        !           151:                if (dup2(pipefds[0], STDIN_FILENO) == -1) {
        !           152:                        warn("dup2");
1.1       provos    153:                        exit(1);
1.11    ! djm       154:                }
1.1       provos    155:                close(pipefds[0]);
                    156:                close(pipefds[1]);
                    157:
1.11    ! djm       158:                if (execv(_PATH_BSHELL, argp) == -1) {
        !           159:                        warn("exec");
1.1       provos    160:                        exit(1);
1.11    ! djm       161:                }
        !           162:                /* NOTREACHED */
        !           163:        default:
        !           164:                break; /* parent continues below */
1.1       provos    165:        }
                    166:
1.11    ! djm       167:        if (checker != NULL) {
        !           168:                /* Send the password to STDIN of child */
        !           169:                close(pipefds[0]);
        !           170:                write(pipefds[1], password, strlen(password) + 1);
        !           171:                close(pipefds[1]);
        !           172:        }
1.1       provos    173:
                    174:        /* get the return value from the child */
1.7       tedu      175:        wait(&child);
1.9       millert   176:        if (WIFEXITED(child) && WEXITSTATUS(child) == 0) {
1.11    ! djm       177:                if (checker != NULL)
        !           178:                        free(checker);
1.1       provos    179:                return (1);
1.9       millert   180:        }
1.1       provos    181:
                    182:  out:
1.11    ! djm       183:        if (checker != NULL)
        !           184:                free(checker);
1.6       deraadt   185:        printf("Please use a different password. Unusual capitalization,\n");
                    186:        printf("control characters, or digits are suggested.\n");
1.11    ! djm       187:
1.1       provos    188:        return (0);
                    189: }
                    190:
1.6       deraadt   191: int
1.8       millert   192: pwd_gettries(login_cap_t *lc)
1.4       millert   193: {
                    194:        quad_t ntries;
                    195:
                    196:        if ((ntries = login_getcapnum(lc, "passwordtries", -1, -1)) != -1) {
1.10      moritz    197:                if (ntries >= 0 && ntries <= INT_MAX)
1.9       millert   198:                        return((int)ntries);
                    199:                fprintf(stderr,
                    200:                    "Warning: pwdtries out of range in /etc/login.conf");
1.4       millert   201:        }
1.1       provos    202:
1.8       millert   203:        /*
1.9       millert   204:         * If no amount of tries is specified, return a default of 3,
                    205:         * meaning that after 3 attempts where the user is foiled by the
                    206:         * password checks, it will no longer be checked and they can set
                    207:         * it to whatever they like.  This is the historic BSD behavior.
1.1       provos    208:         */
1.9       millert   209:        return (3);
1.1       provos    210: }