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

1.7     ! tedu        1: /*     $OpenBSD: pwd_check.c,v 1.6 2002/06/28 22:28:17 deraadt Exp $   */
1.1       provos      2: /*
                      3:  * Copyright 2000 Niels Provos <provos@citi.umich.edu>
                      4:  * All rights reserved.
                      5:  *
                      6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
                      9:  * 1. Redistributions of source code must retain the above copyright
                     10:  *    notice, this list of conditions and the following disclaimer.
                     11:  * 2. Redistributions in binary form must reproduce the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer in the
                     13:  *    documentation and/or other materials provided with the distribution.
                     14:  * 3. All advertising materials mentioning features or use of this software
                     15:  *    must display the following acknowledgement:
                     16:  *      This product includes software developed by Niels Provos.
                     17:  * 4. The name of the author may not be used to endorse or promote products
                     18:  *    derived from this software without specific prior written permission.
                     19:  *
                     20:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     21:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     22:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     23:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     24:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     25:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     26:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     27:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     28:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     29:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     30:  */
                     31:
                     32: #include <sys/types.h>
                     33: #include <sys/wait.h>
1.2       millert    34:
                     35: #include <stdio.h>
1.1       provos     36: #include <stdlib.h>
1.2       millert    37: #include <string.h>
1.1       provos     38: #include <unistd.h>
                     39: #include <limits.h>
1.2       millert    40: #include <errno.h>
1.3       millert    41: #include <err.h>
1.1       provos     42: #include <regex.h>
                     43: #include <grp.h>
                     44: #include <paths.h>
                     45: #include <pwd.h>
1.3       millert    46: #include <util.h>
1.4       millert    47: #include <login_cap.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.4       millert    84: pwd_check(struct passwd *pwd, login_cap_t *lc, char *password)
1.1       provos     85: {
                     86:        regex_t rgx;
1.4       millert    87:        int i, res, min_len;
                     88:        char *cp, option[LINE_MAX];
1.1       provos     89:        int pipefds[2];
1.7     ! tedu       90:        pid_t child;
1.6       deraadt    91:
1.4       millert    92:        min_len = (int) login_getcapnum(lc, "minpasswordlen", 6, 6);
                     93:        if (min_len > 0 && strlen(password) < min_len) {
1.1       provos     94:                printf("Please enter a longer password.\n");
                     95:                return (0);
                     96:        }
                     97:
                     98:        for (i = 0; i < sizeof(patterns)/sizeof(struct pattern); i++) {
                     99:                if (regcomp(&rgx, patterns[i].match, patterns[i].flags) != 0)
                    100:                        continue;
                    101:                res = regexec(&rgx, password, 0, NULL, 0);
                    102:                regfree(&rgx);
                    103:                if (!res) {
                    104:                        printf("%s\nUnusual capitalization, control characters or digits are suggested.\n", patterns[i].response);
                    105:                        return (0);
                    106:                }
                    107:        }
                    108:
                    109:        /* Okay, now pass control to an external program */
                    110:
1.4       millert   111:        /*
                    112:         * Check login.conf, falling back onto the deprecated passwd.conf
                    113:         */
                    114:        if ((cp = login_getcapstr(lc, "passwordcheck", NULL, NULL)) != NULL) {
                    115:                strlcpy(option, cp, sizeof(option));
                    116:                free(cp);
                    117:        } else {
                    118:                pw_getconf(option, LINE_MAX, pwd->pw_name, "pwdcheck");
                    119:
                    120:                /* Try to find an entry for the group */
                    121:                if (*option == 0) {
                    122:                        struct group *grp;
                    123:                        char grpkey[LINE_MAX];
                    124:
                    125:                        grp = getgrgid(pwd->pw_gid);
                    126:                        if (grp != NULL) {
1.6       deraadt   127:                                snprintf(grpkey, LINE_MAX, ":%s",
1.5       itojun    128:                                    grp->gr_name);
                    129:                                pw_getconf(option, LINE_MAX, grpkey,
                    130:                                    "pwdcheck");
                    131:                        }
                    132:                        if (grp != NULL && *option == 0 &&
                    133:                            strchr(pwd->pw_name, '.') == NULL) {
1.6       deraadt   134:                                snprintf(grpkey, LINE_MAX, ".%s",
1.4       millert   135:                                    grp->gr_name);
                    136:                                pw_getconf(option, LINE_MAX, grpkey,
                    137:                                    "pwdcheck");
                    138:                        }
                    139:                        if (*option == 0)
                    140:                                pw_getconf(option, LINE_MAX, "default",
                    141:                                    "pwdcheck");
1.1       provos    142:                }
                    143:        }
1.6       deraadt   144:
1.1       provos    145:        /* If no checker is specified, we accept the password */
                    146:        if (*option == 0)
                    147:                return (1);
                    148:
                    149:        if (pipe(pipefds) == -1) {
                    150:                warn("pipe");
                    151:                goto out;
                    152:        }
                    153:
1.7     ! tedu      154:        child = fork();
        !           155:        if (child == 0) {
1.1       provos    156:                char *argp[] = { "sh", "-c", NULL, NULL};
1.6       deraadt   157:
1.1       provos    158:                /* Drop privileges */
                    159:                seteuid(getuid());
                    160:                setuid(getuid());
                    161:
                    162:                if (dup2(pipefds[0], STDIN_FILENO) == -1)
                    163:                        exit(1);
                    164:
                    165:                close(pipefds[0]);
                    166:                close(pipefds[1]);
                    167:
                    168:                argp[2] = option;
                    169:                if (execv(_PATH_BSHELL, argp) == -1)
                    170:                        exit(1);
                    171:                /* NOT REACHED */
1.7     ! tedu      172:        } else if (child == -1) {
1.1       provos    173:                warn("fork");
                    174:                goto out;
                    175:        }
                    176:        close(pipefds[0]);
                    177:
                    178:        /* Send the password to STDIN of child */
                    179:        write(pipefds[1], password, strlen(password) + 1);
                    180:        close(pipefds[1]);
                    181:
                    182:        /* get the return value from the child */
1.7     ! tedu      183:        wait(&child);
        !           184:        if (WIFEXITED(child) && WEXITSTATUS(child) == 0)
1.1       provos    185:                return (1);
                    186:
                    187:  out:
1.6       deraadt   188:        printf("Please use a different password. Unusual capitalization,\n");
                    189:        printf("control characters, or digits are suggested.\n");
1.1       provos    190:        return (0);
                    191: }
                    192:
1.6       deraadt   193: int
1.7     ! tedu      194: pwd_gettries(struct passwd *pwd, login_cap_t *lc)
1.4       millert   195: {
1.1       provos    196:        char option[LINE_MAX];
1.6       deraadt   197:        char *ep = option;
1.4       millert   198:        quad_t ntries;
1.6       deraadt   199:        long lval;
1.4       millert   200:
                    201:        /*
                    202:         * Check login.conf, falling back onto the deprecated passwd.conf
                    203:         */
                    204:        if ((ntries = login_getcapnum(lc, "passwordtries", -1, -1)) != -1) {
                    205:                if (ntries > INT_MAX || ntries < 0) {
                    206:                        fprintf(stderr,
1.6       deraadt   207:                            "Warning: pwdtries out of range in /etc/login.conf");
1.4       millert   208:                        goto out;
                    209:                }
                    210:                return((int)ntries);
                    211:        }
1.1       provos    212:
                    213:        pw_getconf(option, LINE_MAX, pwd->pw_name, "pwdtries");
                    214:
                    215:        /* Try to find an entry for the group */
                    216:        if (*option == 0) {
1.4       millert   217:                struct group *grp;
                    218:                char grpkey[LINE_MAX];
1.1       provos    219:
1.4       millert   220:                grp = getgrgid(pwd->pw_gid);
                    221:                if (grp != NULL) {
1.6       deraadt   222:                        snprintf(grpkey, LINE_MAX, ":%s", grp->gr_name);
1.5       itojun    223:                        pw_getconf(option, LINE_MAX, grpkey, "pwdtries");
                    224:                }
                    225:                if (grp != NULL && *option == 0 &&
                    226:                    strchr(pwd->pw_name, '.') == NULL) {
1.6       deraadt   227:                        snprintf(grpkey, LINE_MAX, ".%s", grp->gr_name);
1.1       provos    228:                        pw_getconf(option, LINE_MAX, grpkey, "pwdtries");
                    229:                }
                    230:                if (*option == 0)
1.4       millert   231:                        pw_getconf(option, LINE_MAX, "default", "pwdtries");
1.1       provos    232:        }
1.6       deraadt   233:
1.1       provos    234:        if (*option == 0)
                    235:                goto out;
1.6       deraadt   236:
                    237:        errno = 0;
                    238:        lval = strtol(option, &ep, 10);
                    239:        if (option[0] == '\0' || *ep != '\0') {
                    240:                fprintf(stderr,
                    241:                    "Warning: Bad pwdtries line in /etc/passwd.conf");
                    242:                goto out;
                    243:        }
                    244:        if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) ||
                    245:            (lval > INT_MAX || lval < 0)) {
                    246:                fprintf(stderr,
                    247:                    "Warning: pwdtries out of range in /etc/passwd.conf");
                    248:                goto out;
1.1       provos    249:        }
1.6       deraadt   250:        return((int) lval);
1.1       provos    251:
1.6       deraadt   252:        /* If no amount of tries is specified, return a default of
1.1       provos    253:         * 3, meaning that after 3 attempts where the user is foiled
                    254:         * by the password checks, it will no longer be checked and
                    255:         * they can set it to whatever they like.
                    256:         */
                    257:        out:
                    258:                return (3);
                    259: }