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: }