Annotation of src/usr.bin/passwd/pwd_check.c, Revision 1.4
1.4 ! millert 1: /* $OpenBSD: pwd_check.c,v 1.3 2000/11/24 21:07:04 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) {
! 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 (*option == 0)
! 133: pw_getconf(option, LINE_MAX, "default",
! 134: "pwdcheck");
1.1 provos 135: }
136: }
137:
138: /* If no checker is specified, we accept the password */
139: if (*option == 0)
140: return (1);
141:
142: if (pipe(pipefds) == -1) {
143: warn("pipe");
144: goto out;
145: }
146:
147: res = fork();
148: if (res == 0) {
149: char *argp[] = { "sh", "-c", NULL, NULL};
150:
151: /* Drop privileges */
152: seteuid(getuid());
153: setuid(getuid());
154:
155: if (dup2(pipefds[0], STDIN_FILENO) == -1)
156: exit(1);
157:
158: close(pipefds[0]);
159: close(pipefds[1]);
160:
161: argp[2] = option;
162: if (execv(_PATH_BSHELL, argp) == -1)
163: exit(1);
164: /* NOT REACHED */
165: } else if (res == -1) {
166: warn("fork");
167: goto out;
168: }
169: close(pipefds[0]);
170:
171: /* Send the password to STDIN of child */
172: write(pipefds[1], password, strlen(password) + 1);
173: close(pipefds[1]);
174:
175: /* get the return value from the child */
176: wait(&res);
177: if (WIFEXITED(res) && WEXITSTATUS(res) == 0)
178: return (1);
179:
180: out:
181: printf("Please use a different password.\nUnusual capitalization, control characters or digits are suggested.\n");
182: return (0);
183: }
184:
1.4 ! millert 185: int pwd_gettries( struct passwd *pwd, login_cap_t *lc )
! 186: {
1.1 provos 187: char option[LINE_MAX];
188: char *ep = option;
1.4 ! millert 189: quad_t ntries;
! 190:
! 191: /*
! 192: * Check login.conf, falling back onto the deprecated passwd.conf
! 193: */
! 194: if ((ntries = login_getcapnum(lc, "passwordtries", -1, -1)) != -1) {
! 195: if (ntries > INT_MAX || ntries < 0) {
! 196: fprintf(stderr,
! 197: "Warning: pwdtries out of range in /etc/login.conf");
! 198: goto out;
! 199: }
! 200: return((int)ntries);
! 201: }
1.1 provos 202:
203: pw_getconf(option, LINE_MAX, pwd->pw_name, "pwdtries");
204:
205: /* Try to find an entry for the group */
206: if (*option == 0) {
1.4 ! millert 207: struct group *grp;
! 208: char grpkey[LINE_MAX];
1.1 provos 209:
1.4 ! millert 210: grp = getgrgid(pwd->pw_gid);
! 211: if (grp != NULL) {
! 212: snprintf(grpkey, LINE_MAX-1, ".%s", grp->gr_name);
1.1 provos 213: grpkey[LINE_MAX-1] = 0;
214: pw_getconf(option, LINE_MAX, grpkey, "pwdtries");
215: }
216: if (*option == 0)
1.4 ! millert 217: pw_getconf(option, LINE_MAX, "default", "pwdtries");
1.1 provos 218: }
219:
220: if (*option == 0)
221: goto out;
222: else {
223: long lval;
224: errno = 0;
225: lval = strtol(option, &ep, 10);
226: if (option[0] == '\0' || *ep != '\0') {
227: fprintf(stderr,
228: "Warning: Bad pwdtries line in /etc/passwd.conf");
229: goto out;
230: }
231: if ((errno == ERANGE && (lval == LONG_MAX
232: || lval == LONG_MIN)) ||
1.4 ! millert 233: (lval > INT_MAX || lval < 0)) {
1.1 provos 234: fprintf(stderr,
235: "Warning: pwdtries out of range in /etc/passwd.conf");
236: goto out;
237: }
238: return((int) lval);
239: }
240:
241: /* If no amount of tries is specified, return a default of
242: * 3, meaning that after 3 attempts where the user is foiled
243: * by the password checks, it will no longer be checked and
244: * they can set it to whatever they like.
245: */
246: out:
247: return (3);
248: }
249:
250: