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