Annotation of src/usr.bin/passwd/pwd_check.c, Revision 1.5
1.5 ! itojun 1: /* $OpenBSD: pwd_check.c,v 1.4 2001/06/18 21:09:23 millert 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: {
57: "^[0-9]*$",
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];
90:
1.4 millert 91: min_len = (int) login_getcapnum(lc, "minpasswordlen", 6, 6);
92: if (min_len > 0 && strlen(password) < min_len) {
1.1 provos 93: printf("Please enter a longer password.\n");
94: return (0);
95: }
96:
97: for (i = 0; i < sizeof(patterns)/sizeof(struct pattern); i++) {
98: if (regcomp(&rgx, patterns[i].match, patterns[i].flags) != 0)
99: continue;
100: res = regexec(&rgx, password, 0, NULL, 0);
101: regfree(&rgx);
102: if (!res) {
103: printf("%s\nUnusual capitalization, control characters or digits are suggested.\n", patterns[i].response);
104: return (0);
105: }
106: }
107:
108: /* Okay, now pass control to an external program */
109:
1.4 millert 110: /*
111: * Check login.conf, falling back onto the deprecated passwd.conf
112: */
113: if ((cp = login_getcapstr(lc, "passwordcheck", NULL, NULL)) != NULL) {
114: strlcpy(option, cp, sizeof(option));
115: free(cp);
116: } else {
117: pw_getconf(option, LINE_MAX, pwd->pw_name, "pwdcheck");
118:
119: /* Try to find an entry for the group */
120: if (*option == 0) {
121: struct group *grp;
122: char grpkey[LINE_MAX];
123:
124: grp = getgrgid(pwd->pw_gid);
125: if (grp != NULL) {
1.5 ! itojun 126: snprintf(grpkey, LINE_MAX-1, ":%s",
! 127: grp->gr_name);
! 128: grpkey[LINE_MAX-1] = 0;
! 129: pw_getconf(option, LINE_MAX, grpkey,
! 130: "pwdcheck");
! 131: }
! 132: if (grp != NULL && *option == 0 &&
! 133: strchr(pwd->pw_name, '.') == NULL) {
1.4 millert 134: snprintf(grpkey, LINE_MAX-1, ".%s",
135: grp->gr_name);
136: grpkey[LINE_MAX-1] = 0;
137: pw_getconf(option, LINE_MAX, grpkey,
138: "pwdcheck");
139: }
140: if (*option == 0)
141: pw_getconf(option, LINE_MAX, "default",
142: "pwdcheck");
1.1 provos 143: }
144: }
145:
146: /* If no checker is specified, we accept the password */
147: if (*option == 0)
148: return (1);
149:
150: if (pipe(pipefds) == -1) {
151: warn("pipe");
152: goto out;
153: }
154:
155: res = fork();
156: if (res == 0) {
157: char *argp[] = { "sh", "-c", NULL, NULL};
158:
159: /* Drop privileges */
160: seteuid(getuid());
161: setuid(getuid());
162:
163: if (dup2(pipefds[0], STDIN_FILENO) == -1)
164: exit(1);
165:
166: close(pipefds[0]);
167: close(pipefds[1]);
168:
169: argp[2] = option;
170: if (execv(_PATH_BSHELL, argp) == -1)
171: exit(1);
172: /* NOT REACHED */
173: } else if (res == -1) {
174: warn("fork");
175: goto out;
176: }
177: close(pipefds[0]);
178:
179: /* Send the password to STDIN of child */
180: write(pipefds[1], password, strlen(password) + 1);
181: close(pipefds[1]);
182:
183: /* get the return value from the child */
184: wait(&res);
185: if (WIFEXITED(res) && WEXITSTATUS(res) == 0)
186: return (1);
187:
188: out:
189: printf("Please use a different password.\nUnusual capitalization, control characters or digits are suggested.\n");
190: return (0);
191: }
192:
1.4 millert 193: int pwd_gettries( struct passwd *pwd, login_cap_t *lc )
194: {
1.1 provos 195: char option[LINE_MAX];
196: char *ep = option;
1.4 millert 197: quad_t ntries;
198:
199: /*
200: * Check login.conf, falling back onto the deprecated passwd.conf
201: */
202: if ((ntries = login_getcapnum(lc, "passwordtries", -1, -1)) != -1) {
203: if (ntries > INT_MAX || ntries < 0) {
204: fprintf(stderr,
205: "Warning: pwdtries out of range in /etc/login.conf");
206: goto out;
207: }
208: return((int)ntries);
209: }
1.1 provos 210:
211: pw_getconf(option, LINE_MAX, pwd->pw_name, "pwdtries");
212:
213: /* Try to find an entry for the group */
214: if (*option == 0) {
1.4 millert 215: struct group *grp;
216: char grpkey[LINE_MAX];
1.1 provos 217:
1.4 millert 218: grp = getgrgid(pwd->pw_gid);
219: if (grp != NULL) {
1.5 ! itojun 220: snprintf(grpkey, LINE_MAX-1, ":%s", grp->gr_name);
! 221: grpkey[LINE_MAX-1] = 0;
! 222: pw_getconf(option, LINE_MAX, grpkey, "pwdtries");
! 223: }
! 224: if (grp != NULL && *option == 0 &&
! 225: strchr(pwd->pw_name, '.') == NULL) {
1.4 millert 226: snprintf(grpkey, LINE_MAX-1, ".%s", grp->gr_name);
1.1 provos 227: grpkey[LINE_MAX-1] = 0;
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: }
233:
234: if (*option == 0)
235: goto out;
236: else {
237: long lval;
238: errno = 0;
239: lval = strtol(option, &ep, 10);
240: if (option[0] == '\0' || *ep != '\0') {
241: fprintf(stderr,
242: "Warning: Bad pwdtries line in /etc/passwd.conf");
243: goto out;
244: }
245: if ((errno == ERANGE && (lval == LONG_MAX
246: || lval == LONG_MIN)) ||
1.4 millert 247: (lval > INT_MAX || lval < 0)) {
1.1 provos 248: fprintf(stderr,
249: "Warning: pwdtries out of range in /etc/passwd.conf");
250: goto out;
251: }
252: return((int) lval);
253: }
254:
255: /* If no amount of tries is specified, return a default of
256: * 3, meaning that after 3 attempts where the user is foiled
257: * by the password checks, it will no longer be checked and
258: * they can set it to whatever they like.
259: */
260: out:
261: return (3);
262: }
263:
264: