Annotate logit to provide transitive format string checks.diff -r1.14 -r1.15 src/lib/libpam/modules/pam_lastlog/pam_lastlog.c
(joerg)
--- src/lib/libpam/modules/pam_lastlog/pam_lastlog.c 2012/01/03 19:02:55 1.14
+++ src/lib/libpam/modules/pam_lastlog/pam_lastlog.c 2014/01/07 02:07:43 1.15
@@ -1,386 +1,387 @@ | @@ -1,386 +1,387 @@ | |||
1 | /* $NetBSD: pam_lastlog.c,v 1.14 2012/01/03 19:02:55 christos Exp $ */ | 1 | /* $NetBSD: pam_lastlog.c,v 1.15 2014/01/07 02:07:43 joerg Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994 | 4 | * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * Copyright (c) 2001 Mark R V Murray | 6 | * Copyright (c) 2001 Mark R V Murray | |
7 | * All rights reserved. | 7 | * All rights reserved. | |
8 | * Copyright (c) 2001 Networks Associates Technology, Inc. | 8 | * Copyright (c) 2001 Networks Associates Technology, Inc. | |
9 | * All rights reserved. | 9 | * All rights reserved. | |
10 | * Copyright (c) 2004 Joe R. Doupnik | 10 | * Copyright (c) 2004 Joe R. Doupnik | |
11 | * All rights reserved. | 11 | * All rights reserved. | |
12 | * | 12 | * | |
13 | * Portions of this software were developed for the FreeBSD Project by | 13 | * Portions of this software were developed for the FreeBSD Project by | |
14 | * ThinkSec AS and NAI Labs, the Security Research Division of Network | 14 | * ThinkSec AS and NAI Labs, the Security Research Division of Network | |
15 | * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 | 15 | * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 | |
16 | * ("CBOSS"), as part of the DARPA CHATS research program. | 16 | * ("CBOSS"), as part of the DARPA CHATS research program. | |
17 | * | 17 | * | |
18 | * Redistribution and use in source and binary forms, with or without | 18 | * Redistribution and use in source and binary forms, with or without | |
19 | * modification, are permitted provided that the following conditions | 19 | * modification, are permitted provided that the following conditions | |
20 | * are met: | 20 | * are met: | |
21 | * 1. Redistributions of source code must retain the above copyright | 21 | * 1. Redistributions of source code must retain the above copyright | |
22 | * notice, this list of conditions and the following disclaimer. | 22 | * notice, this list of conditions and the following disclaimer. | |
23 | * 2. Redistributions in binary form must reproduce the above copyright | 23 | * 2. Redistributions in binary form must reproduce the above copyright | |
24 | * notice, this list of conditions and the following disclaimer in the | 24 | * notice, this list of conditions and the following disclaimer in the | |
25 | * documentation and/or other materials provided with the distribution. | 25 | * documentation and/or other materials provided with the distribution. | |
26 | * 3. The name of the author may not be used to endorse or promote | 26 | * 3. The name of the author may not be used to endorse or promote | |
27 | * products derived from this software without specific prior written | 27 | * products derived from this software without specific prior written | |
28 | * permission. | 28 | * permission. | |
29 | * 4. Neither the name of the University nor the names of its contributors | 29 | * 4. Neither the name of the University nor the names of its contributors | |
30 | * may be used to endorse or promote products derived from this software | 30 | * may be used to endorse or promote products derived from this software | |
31 | * without specific prior written permission. | 31 | * without specific prior written permission. | |
32 | * | 32 | * | |
33 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | 33 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
34 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 34 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
35 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 35 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
36 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | 36 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
37 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 37 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
38 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 38 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
39 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 39 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
40 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 40 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
41 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 41 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
42 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 42 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
43 | * SUCH DAMAGE. | 43 | * SUCH DAMAGE. | |
44 | */ | 44 | */ | |
45 | 45 | |||
46 | #include <sys/cdefs.h> | 46 | #include <sys/cdefs.h> | |
47 | #ifdef __FreeBSD__ | 47 | #ifdef __FreeBSD__ | |
48 | __FBSDID("$FreeBSD: src/lib/libpam/modules/pam_lastlog/pam_lastlog.c,v 1.20 2004/01/26 19:28:37 des Exp $"); | 48 | __FBSDID("$FreeBSD: src/lib/libpam/modules/pam_lastlog/pam_lastlog.c,v 1.20 2004/01/26 19:28:37 des Exp $"); | |
49 | #else | 49 | #else | |
50 | __RCSID("$NetBSD: pam_lastlog.c,v 1.14 2012/01/03 19:02:55 christos Exp $"); | 50 | __RCSID("$NetBSD: pam_lastlog.c,v 1.15 2014/01/07 02:07:43 joerg Exp $"); | |
51 | #endif | 51 | #endif | |
52 | 52 | |||
53 | #include <sys/param.h> | 53 | #include <sys/param.h> | |
54 | 54 | |||
55 | #include <fcntl.h> | 55 | #include <fcntl.h> | |
56 | #include <util.h> | 56 | #include <util.h> | |
57 | #include <paths.h> | 57 | #include <paths.h> | |
58 | #include <pwd.h> | 58 | #include <pwd.h> | |
59 | #include <stdio.h> | 59 | #include <stdio.h> | |
60 | #include <stdlib.h> | 60 | #include <stdlib.h> | |
61 | #include <string.h> | 61 | #include <string.h> | |
62 | #include <syslog.h> | 62 | #include <syslog.h> | |
63 | #include <errno.h> | 63 | #include <errno.h> | |
64 | #include <time.h> | 64 | #include <time.h> | |
65 | #include <unistd.h> | 65 | #include <unistd.h> | |
66 | #include <stdarg.h> | 66 | #include <stdarg.h> | |
67 | #ifdef LOGIN_CAP | 67 | #ifdef LOGIN_CAP | |
68 | #include <login_cap.h> | 68 | #include <login_cap.h> | |
69 | #endif | 69 | #endif | |
70 | 70 | |||
71 | #define PAM_SM_SESSION | 71 | #define PAM_SM_SESSION | |
72 | 72 | |||
73 | #include <security/pam_appl.h> | 73 | #include <security/pam_appl.h> | |
74 | #include <security/pam_modules.h> | 74 | #include <security/pam_modules.h> | |
75 | #include <security/pam_mod_misc.h> | 75 | #include <security/pam_mod_misc.h> | |
76 | 76 | |||
77 | #ifdef SUPPORT_UTMP | 77 | #ifdef SUPPORT_UTMP | |
78 | #include <utmp.h> | 78 | #include <utmp.h> | |
79 | static void doutmp(const char *, const char *, const char *, | 79 | static void doutmp(const char *, const char *, const char *, | |
80 | const struct timeval *); | 80 | const struct timeval *); | |
81 | static void dolastlog(pam_handle_t *, int, const struct passwd *, const char *, | 81 | static void dolastlog(pam_handle_t *, int, const struct passwd *, const char *, | |
82 | const char *, const struct timeval *); | 82 | const char *, const struct timeval *); | |
83 | #endif | 83 | #endif | |
84 | 84 | |||
85 | #ifdef SUPPORT_UTMPX | 85 | #ifdef SUPPORT_UTMPX | |
86 | #include <utmpx.h> | 86 | #include <utmpx.h> | |
87 | static void doutmpx(const char *, const char *, const char *, | 87 | static void doutmpx(const char *, const char *, const char *, | |
88 | const struct sockaddr_storage *ss, const struct timeval *); | 88 | const struct sockaddr_storage *ss, const struct timeval *); | |
89 | static void dolastlogx(pam_handle_t *, int, const struct passwd *, const char *, | 89 | static void dolastlogx(pam_handle_t *, int, const struct passwd *, const char *, | |
90 | const char *, const struct sockaddr_storage *ss, const struct timeval *); | 90 | const char *, const struct sockaddr_storage *ss, const struct timeval *); | |
91 | #endif | 91 | #endif | |
92 | 92 | |||
93 | #if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP) | 93 | #if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP) | |
94 | static void domsg(pam_handle_t *, time_t, const char *, size_t, const char *, | 94 | static void domsg(pam_handle_t *, time_t, const char *, size_t, const char *, | |
95 | size_t); | 95 | size_t); | |
96 | #endif | 96 | #endif | |
97 | 97 | |||
98 | __printflike(2, 3) | |||
98 | static void | 99 | static void | |
99 | logit(int level, const char *fmt, ...) | 100 | logit(int level, const char *fmt, ...) | |
100 | { | 101 | { | |
101 | va_list ap; | 102 | va_list ap; | |
102 | struct syslog_data data = SYSLOG_DATA_INIT; | 103 | struct syslog_data data = SYSLOG_DATA_INIT; | |
103 | 104 | |||
104 | openlog_r("pam_lastlog", LOG_PID, LOG_AUTHPRIV, &data); | 105 | openlog_r("pam_lastlog", LOG_PID, LOG_AUTHPRIV, &data); | |
105 | va_start(ap, fmt); | 106 | va_start(ap, fmt); | |
106 | vsyslog_r(level, &data, fmt, ap); | 107 | vsyslog_r(level, &data, fmt, ap); | |
107 | va_end(ap); | 108 | va_end(ap); | |
108 | closelog_r(&data); | 109 | closelog_r(&data); | |
109 | } | 110 | } | |
110 | 111 | |||
111 | 112 | |||
112 | PAM_EXTERN int | 113 | PAM_EXTERN int | |
113 | pam_sm_open_session(pam_handle_t *pamh, int flags, | 114 | pam_sm_open_session(pam_handle_t *pamh, int flags, | |
114 | int argc __unused, const char *argv[] __unused) | 115 | int argc __unused, const char *argv[] __unused) | |
115 | { | 116 | { | |
116 | struct passwd *pwd, pwres; | 117 | struct passwd *pwd, pwres; | |
117 | struct timeval now; | 118 | struct timeval now; | |
118 | const char *user, *rhost, *tty, *nuser; | 119 | const char *user, *rhost, *tty, *nuser; | |
119 | const void *vrhost, *vtty, *vss, *vnuser; | 120 | const void *vrhost, *vtty, *vss, *vnuser; | |
120 | const struct sockaddr_storage *ss; | 121 | const struct sockaddr_storage *ss; | |
121 | int pam_err; | 122 | int pam_err; | |
122 | char pwbuf[1024]; | 123 | char pwbuf[1024]; | |
123 | #ifdef LOGIN_CAP | 124 | #ifdef LOGIN_CAP | |
124 | login_cap_t *lc; | 125 | login_cap_t *lc; | |
125 | #endif | 126 | #endif | |
126 | 127 | |||
127 | pam_err = pam_get_user(pamh, &user, NULL); | 128 | pam_err = pam_get_user(pamh, &user, NULL); | |
128 | if (pam_err != PAM_SUCCESS) | 129 | if (pam_err != PAM_SUCCESS) | |
129 | return pam_err; | 130 | return pam_err; | |
130 | 131 | |||
131 | if (user == NULL || | 132 | if (user == NULL || | |
132 | getpwnam_r(user, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 || | 133 | getpwnam_r(user, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 || | |
133 | pwd == NULL) | 134 | pwd == NULL) | |
134 | return PAM_SERVICE_ERR; | 135 | return PAM_SERVICE_ERR; | |
135 | 136 | |||
136 | PAM_LOG("Got user: %s", user); | 137 | PAM_LOG("Got user: %s", user); | |
137 | 138 | |||
138 | pam_err = pam_get_item(pamh, PAM_RHOST, &vrhost); | 139 | pam_err = pam_get_item(pamh, PAM_RHOST, &vrhost); | |
139 | if (pam_err != PAM_SUCCESS) | 140 | if (pam_err != PAM_SUCCESS) | |
140 | goto err; | 141 | goto err; | |
141 | rhost = (const char *)vrhost; | 142 | rhost = (const char *)vrhost; | |
142 | 143 | |||
143 | pam_err = pam_get_item(pamh, PAM_SOCKADDR, &vss); | 144 | pam_err = pam_get_item(pamh, PAM_SOCKADDR, &vss); | |
144 | if (pam_err != PAM_SUCCESS) | 145 | if (pam_err != PAM_SUCCESS) | |
145 | goto err; | 146 | goto err; | |
146 | ss = (const struct sockaddr_storage *)vss; | 147 | ss = (const struct sockaddr_storage *)vss; | |
147 | 148 | |||
148 | pam_err = pam_get_item(pamh, PAM_TTY, &vtty); | 149 | pam_err = pam_get_item(pamh, PAM_TTY, &vtty); | |
149 | if (pam_err != PAM_SUCCESS) | 150 | if (pam_err != PAM_SUCCESS) | |
150 | goto err; | 151 | goto err; | |
151 | tty = (const char *)vtty; | 152 | tty = (const char *)vtty; | |
152 | 153 | |||
153 | if (tty == NULL) { | 154 | if (tty == NULL) { | |
154 | pam_err = PAM_SERVICE_ERR; | 155 | pam_err = PAM_SERVICE_ERR; | |
155 | goto err; | 156 | goto err; | |
156 | } | 157 | } | |
157 | 158 | |||
158 | if (pam_get_item(pamh, PAM_NUSER, &vnuser) != PAM_SUCCESS) | 159 | if (pam_get_item(pamh, PAM_NUSER, &vnuser) != PAM_SUCCESS) | |
159 | nuser = NULL; | 160 | nuser = NULL; | |
160 | else | 161 | else | |
161 | nuser = (const char *)vnuser; | 162 | nuser = (const char *)vnuser; | |
162 | 163 | |||
163 | if (strncmp(tty, _PATH_DEV, strlen(_PATH_DEV)) == 0) | 164 | if (strncmp(tty, _PATH_DEV, strlen(_PATH_DEV)) == 0) | |
164 | tty = tty + strlen(_PATH_DEV); | 165 | tty = tty + strlen(_PATH_DEV); | |
165 | 166 | |||
166 | if (*tty == '\0') { | 167 | if (*tty == '\0') { | |
167 | pam_err = PAM_SERVICE_ERR; | 168 | pam_err = PAM_SERVICE_ERR; | |
168 | goto err; | 169 | goto err; | |
169 | } | 170 | } | |
170 | 171 | |||
171 | (void)gettimeofday(&now, NULL); | 172 | (void)gettimeofday(&now, NULL); | |
172 | 173 | |||
173 | if (openpam_get_option(pamh, "no_nested") == NULL || nuser == NULL) { | 174 | if (openpam_get_option(pamh, "no_nested") == NULL || nuser == NULL) { | |
174 | int quiet; | 175 | int quiet; | |
175 | if ((flags & PAM_SILENT) != 0) | 176 | if ((flags & PAM_SILENT) != 0) | |
176 | quiet = 1; | 177 | quiet = 1; | |
177 | else { | 178 | else { | |
178 | #ifdef LOGIN_CAP | 179 | #ifdef LOGIN_CAP | |
179 | lc = login_getpwclass(pwd); | 180 | lc = login_getpwclass(pwd); | |
180 | quiet = login_getcapbool(lc, "hushlogin", 0); | 181 | quiet = login_getcapbool(lc, "hushlogin", 0); | |
181 | login_close(lc); | 182 | login_close(lc); | |
182 | #else | 183 | #else | |
183 | quiet = 0; | 184 | quiet = 0; | |
184 | #endif | 185 | #endif | |
185 | } | 186 | } | |
186 | #ifdef SUPPORT_UTMPX | 187 | #ifdef SUPPORT_UTMPX | |
187 | doutmpx(user, rhost, tty, ss, &now); | 188 | doutmpx(user, rhost, tty, ss, &now); | |
188 | dolastlogx(pamh, quiet, pwd, rhost, tty, ss, &now); | 189 | dolastlogx(pamh, quiet, pwd, rhost, tty, ss, &now); | |
189 | quiet = 1; | 190 | quiet = 1; | |
190 | #endif | 191 | #endif | |
191 | #ifdef SUPPORT_UTMP | 192 | #ifdef SUPPORT_UTMP | |
192 | doutmp(user, rhost, tty, &now); | 193 | doutmp(user, rhost, tty, &now); | |
193 | dolastlog(pamh, quiet, pwd, rhost, tty, &now); | 194 | dolastlog(pamh, quiet, pwd, rhost, tty, &now); | |
194 | #endif | 195 | #endif | |
195 | } | 196 | } | |
196 | err: | 197 | err: | |
197 | if (openpam_get_option(pamh, "no_fail")) | 198 | if (openpam_get_option(pamh, "no_fail")) | |
198 | return PAM_SUCCESS; | 199 | return PAM_SUCCESS; | |
199 | return pam_err; | 200 | return pam_err; | |
200 | } | 201 | } | |
201 | 202 | |||
202 | PAM_EXTERN int | 203 | PAM_EXTERN int | |
203 | pam_sm_close_session(pam_handle_t *pamh __unused, int flags __unused, | 204 | pam_sm_close_session(pam_handle_t *pamh __unused, int flags __unused, | |
204 | int argc __unused, const char *argv[] __unused) | 205 | int argc __unused, const char *argv[] __unused) | |
205 | { | 206 | { | |
206 | const void *vtty, *vnuser; | 207 | const void *vtty, *vnuser; | |
207 | const char *tty, *nuser; | 208 | const char *tty, *nuser; | |
208 | 209 | |||
209 | if (pam_get_item(pamh, PAM_NUSER, &vnuser) != PAM_SUCCESS) | 210 | if (pam_get_item(pamh, PAM_NUSER, &vnuser) != PAM_SUCCESS) | |
210 | nuser = NULL; | 211 | nuser = NULL; | |
211 | else | 212 | else | |
212 | nuser = (const char *)vnuser; | 213 | nuser = (const char *)vnuser; | |
213 | 214 | |||
214 | pam_get_item(pamh, PAM_TTY, &vtty); | 215 | pam_get_item(pamh, PAM_TTY, &vtty); | |
215 | if (vtty == NULL) | 216 | if (vtty == NULL) | |
216 | return PAM_SERVICE_ERR; | 217 | return PAM_SERVICE_ERR; | |
217 | tty = (const char *)vtty; | 218 | tty = (const char *)vtty; | |
218 | 219 | |||
219 | if (strncmp(tty, _PATH_DEV, strlen(_PATH_DEV)) == 0) | 220 | if (strncmp(tty, _PATH_DEV, strlen(_PATH_DEV)) == 0) | |
220 | tty = tty + strlen(_PATH_DEV); | 221 | tty = tty + strlen(_PATH_DEV); | |
221 | 222 | |||
222 | if (*tty == '\0') | 223 | if (*tty == '\0') | |
223 | return PAM_SERVICE_ERR; | 224 | return PAM_SERVICE_ERR; | |
224 | 225 | |||
225 | if (openpam_get_option(pamh, "no_nested") == NULL || nuser == NULL) { | 226 | if (openpam_get_option(pamh, "no_nested") == NULL || nuser == NULL) { | |
226 | 227 | |||
227 | #ifdef SUPPORT_UTMPX | 228 | #ifdef SUPPORT_UTMPX | |
228 | if (logoutx(tty, 0, DEAD_PROCESS)) | 229 | if (logoutx(tty, 0, DEAD_PROCESS)) | |
229 | logwtmpx(tty, "", "", 0, DEAD_PROCESS); | 230 | logwtmpx(tty, "", "", 0, DEAD_PROCESS); | |
230 | else | 231 | else | |
231 | logit(LOG_NOTICE, "%s(): no utmpx record for %s", | 232 | logit(LOG_NOTICE, "%s(): no utmpx record for %s", | |
232 | __func__, tty); | 233 | __func__, tty); | |
233 | #endif | 234 | #endif | |
234 | 235 | |||
235 | #ifdef SUPPORT_UTMP | 236 | #ifdef SUPPORT_UTMP | |
236 | if (logout(tty)) | 237 | if (logout(tty)) | |
237 | logwtmp(tty, "", ""); | 238 | logwtmp(tty, "", ""); | |
238 | else | 239 | else | |
239 | logit(LOG_NOTICE, "%s(): no utmp record for %s", | 240 | logit(LOG_NOTICE, "%s(): no utmp record for %s", | |
240 | __func__, tty); | 241 | __func__, tty); | |
241 | #endif | 242 | #endif | |
242 | } | 243 | } | |
243 | return PAM_SUCCESS; | 244 | return PAM_SUCCESS; | |
244 | } | 245 | } | |
245 | 246 | |||
246 | #if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP) | 247 | #if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP) | |
247 | static void | 248 | static void | |
248 | domsg(pam_handle_t *pamh, time_t t, const char *host, size_t hsize, | 249 | domsg(pam_handle_t *pamh, time_t t, const char *host, size_t hsize, | |
249 | const char *line, size_t lsize) | 250 | const char *line, size_t lsize) | |
250 | { | 251 | { | |
251 | char buf[MAXHOSTNAMELEN + 32], *promptresp = NULL; | 252 | char buf[MAXHOSTNAMELEN + 32], *promptresp = NULL; | |
252 | int pam_err; | 253 | int pam_err; | |
253 | 254 | |||
254 | if (*host) { | 255 | if (*host) { | |
255 | (void)snprintf(buf, sizeof(buf), "from %.*s ", | 256 | (void)snprintf(buf, sizeof(buf), "from %.*s ", | |
256 | (int)hsize, host); | 257 | (int)hsize, host); | |
257 | host = buf; | 258 | host = buf; | |
258 | } | 259 | } | |
259 | 260 | |||
260 | pam_err = pam_prompt(pamh, PAM_TEXT_INFO, &promptresp, | 261 | pam_err = pam_prompt(pamh, PAM_TEXT_INFO, &promptresp, | |
261 | "Last login: %.24s %son %.*s\n", ctime(&t), host, (int)lsize, line); | 262 | "Last login: %.24s %son %.*s\n", ctime(&t), host, (int)lsize, line); | |
262 | 263 | |||
263 | if (pam_err == PAM_SUCCESS && promptresp) | 264 | if (pam_err == PAM_SUCCESS && promptresp) | |
264 | free(promptresp); | 265 | free(promptresp); | |
265 | } | 266 | } | |
266 | #endif | 267 | #endif | |
267 | 268 | |||
268 | #ifdef SUPPORT_UTMPX | 269 | #ifdef SUPPORT_UTMPX | |
269 | static void | 270 | static void | |
270 | doutmpx(const char *username, const char *hostname, const char *tty, | 271 | doutmpx(const char *username, const char *hostname, const char *tty, | |
271 | const struct sockaddr_storage *ss, const struct timeval *now) | 272 | const struct sockaddr_storage *ss, const struct timeval *now) | |
272 | { | 273 | { | |
273 | struct utmpx utmpx; | 274 | struct utmpx utmpx; | |
274 | const char *t; | 275 | const char *t; | |
275 | 276 | |||
276 | memset((void *)&utmpx, 0, sizeof(utmpx)); | 277 | memset((void *)&utmpx, 0, sizeof(utmpx)); | |
277 | utmpx.ut_tv = *now; | 278 | utmpx.ut_tv = *now; | |
278 | (void)strncpy(utmpx.ut_name, username, sizeof(utmpx.ut_name)); | 279 | (void)strncpy(utmpx.ut_name, username, sizeof(utmpx.ut_name)); | |
279 | if (hostname) { | 280 | if (hostname) { | |
280 | (void)strncpy(utmpx.ut_host, hostname, sizeof(utmpx.ut_host)); | 281 | (void)strncpy(utmpx.ut_host, hostname, sizeof(utmpx.ut_host)); | |
281 | if (ss) | 282 | if (ss) | |
282 | utmpx.ut_ss = *ss; | 283 | utmpx.ut_ss = *ss; | |
283 | } | 284 | } | |
284 | (void)strncpy(utmpx.ut_line, tty, sizeof(utmpx.ut_line)); | 285 | (void)strncpy(utmpx.ut_line, tty, sizeof(utmpx.ut_line)); | |
285 | utmpx.ut_type = USER_PROCESS; | 286 | utmpx.ut_type = USER_PROCESS; | |
286 | utmpx.ut_pid = getpid(); | 287 | utmpx.ut_pid = getpid(); | |
287 | t = tty + strlen(tty); | 288 | t = tty + strlen(tty); | |
288 | if ((size_t)(t - tty) >= sizeof(utmpx.ut_id)) { | 289 | if ((size_t)(t - tty) >= sizeof(utmpx.ut_id)) { | |
289 | (void)strncpy(utmpx.ut_id, t - sizeof(utmpx.ut_id), | 290 | (void)strncpy(utmpx.ut_id, t - sizeof(utmpx.ut_id), | |
290 | sizeof(utmpx.ut_id)); | 291 | sizeof(utmpx.ut_id)); | |
291 | } else { | 292 | } else { | |
292 | (void)strncpy(utmpx.ut_id, tty, sizeof(utmpx.ut_id)); | 293 | (void)strncpy(utmpx.ut_id, tty, sizeof(utmpx.ut_id)); | |
293 | } | 294 | } | |
294 | if (pututxline(&utmpx) == NULL) | 295 | if (pututxline(&utmpx) == NULL) | |
295 | logit(LOG_NOTICE, "Cannot update utmpx: %s", strerror(errno)); | 296 | logit(LOG_NOTICE, "Cannot update utmpx: %s", strerror(errno)); | |
296 | endutxent(); | 297 | endutxent(); | |
297 | if (updwtmpx(_PATH_WTMPX, &utmpx) != 0) | 298 | if (updwtmpx(_PATH_WTMPX, &utmpx) != 0) | |
298 | logit(LOG_NOTICE, "Cannot update wtmpx: %s", strerror(errno)); | 299 | logit(LOG_NOTICE, "Cannot update wtmpx: %s", strerror(errno)); | |
299 | } | 300 | } | |
300 | 301 | |||
301 | static void | 302 | static void | |
302 | dolastlogx(pam_handle_t *pamh, int quiet, const struct passwd *pwd, | 303 | dolastlogx(pam_handle_t *pamh, int quiet, const struct passwd *pwd, | |
303 | const char *hostname, const char *tty, const struct sockaddr_storage *ss, | 304 | const char *hostname, const char *tty, const struct sockaddr_storage *ss, | |
304 | const struct timeval *now) | 305 | const struct timeval *now) | |
305 | { | 306 | { | |
306 | struct lastlogx ll; | 307 | struct lastlogx ll; | |
307 | if (!quiet) { | 308 | if (!quiet) { | |
308 | if (getlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != NULL) | 309 | if (getlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != NULL) | |
309 | domsg(pamh, (time_t)ll.ll_tv.tv_sec, ll.ll_host, | 310 | domsg(pamh, (time_t)ll.ll_tv.tv_sec, ll.ll_host, | |
310 | sizeof(ll.ll_host), ll.ll_line, | 311 | sizeof(ll.ll_host), ll.ll_line, | |
311 | sizeof(ll.ll_line)); | 312 | sizeof(ll.ll_line)); | |
312 | } | 313 | } | |
313 | ll.ll_tv = *now; | 314 | ll.ll_tv = *now; | |
314 | (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); | 315 | (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); | |
315 | 316 | |||
316 | if (hostname) | 317 | if (hostname) | |
317 | (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); | 318 | (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); | |
318 | else | 319 | else | |
319 | (void)memset(ll.ll_host, 0, sizeof(ll.ll_host)); | 320 | (void)memset(ll.ll_host, 0, sizeof(ll.ll_host)); | |
320 | 321 | |||
321 | if (ss) | 322 | if (ss) | |
322 | ll.ll_ss = *ss; | 323 | ll.ll_ss = *ss; | |
323 | else | 324 | else | |
324 | (void)memset(&ll.ll_ss, 0, sizeof(ll.ll_ss)); | 325 | (void)memset(&ll.ll_ss, 0, sizeof(ll.ll_ss)); | |
325 | 326 | |||
326 | if (updlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != 0) | 327 | if (updlastlogx(_PATH_LASTLOGX, pwd->pw_uid, &ll) != 0) | |
327 | logit(LOG_NOTICE, "Cannot update lastlogx: %s", strerror(errno)); | 328 | logit(LOG_NOTICE, "Cannot update lastlogx: %s", strerror(errno)); | |
328 | PAM_LOG("Login recorded in %s", _PATH_LASTLOGX); | 329 | PAM_LOG("Login recorded in %s", _PATH_LASTLOGX); | |
329 | } | 330 | } | |
330 | #endif | 331 | #endif | |
331 | 332 | |||
332 | #ifdef SUPPORT_UTMP | 333 | #ifdef SUPPORT_UTMP | |
333 | static void | 334 | static void | |
334 | doutmp(const char *username, const char *hostname, const char *tty, | 335 | doutmp(const char *username, const char *hostname, const char *tty, | |
335 | const struct timeval *now) | 336 | const struct timeval *now) | |
336 | { | 337 | { | |
337 | struct utmp utmp; | 338 | struct utmp utmp; | |
338 | 339 | |||
339 | (void)memset((void *)&utmp, 0, sizeof(utmp)); | 340 | (void)memset((void *)&utmp, 0, sizeof(utmp)); | |
340 | utmp.ut_time = now->tv_sec; | 341 | utmp.ut_time = now->tv_sec; | |
341 | (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); | 342 | (void)strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); | |
342 | if (hostname) | 343 | if (hostname) | |
343 | (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); | 344 | (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); | |
344 | (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); | 345 | (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); | |
345 | login(&utmp); | 346 | login(&utmp); | |
346 | } | 347 | } | |
347 | 348 | |||
348 | static void | 349 | static void | |
349 | dolastlog(pam_handle_t *pamh, int quiet, const struct passwd *pwd, | 350 | dolastlog(pam_handle_t *pamh, int quiet, const struct passwd *pwd, | |
350 | const char *hostname, const char *tty, const struct timeval *now) | 351 | const char *hostname, const char *tty, const struct timeval *now) | |
351 | { | 352 | { | |
352 | struct lastlog ll; | 353 | struct lastlog ll; | |
353 | int fd; | 354 | int fd; | |
354 | 355 | |||
355 | if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) == -1) { | 356 | if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) == -1) { | |
356 | logit(LOG_NOTICE, "Cannot open `%s': %s", _PATH_LASTLOG, | 357 | logit(LOG_NOTICE, "Cannot open `%s': %s", _PATH_LASTLOG, | |
357 | strerror(errno)); | 358 | strerror(errno)); | |
358 | return; | 359 | return; | |
359 | } | 360 | } | |
360 | (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET); | 361 | (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET); | |
361 | 362 | |||
362 | if (!quiet) { | 363 | if (!quiet) { | |
363 | if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && | 364 | if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && | |
364 | ll.ll_time != 0) | 365 | ll.ll_time != 0) | |
365 | domsg(pamh, ll.ll_time, ll.ll_host, | 366 | domsg(pamh, ll.ll_time, ll.ll_host, | |
366 | sizeof(ll.ll_host), ll.ll_line, | 367 | sizeof(ll.ll_host), ll.ll_line, | |
367 | sizeof(ll.ll_line)); | 368 | sizeof(ll.ll_line)); | |
368 | (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET); | 369 | (void)lseek(fd, (off_t)(pwd->pw_uid * sizeof(ll)), SEEK_SET); | |
369 | } | 370 | } | |
370 | 371 | |||
371 | ll.ll_time = now->tv_sec; | 372 | ll.ll_time = now->tv_sec; | |
372 | (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); | 373 | (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); | |
373 | 374 | |||
374 | if (hostname) | 375 | if (hostname) | |
375 | (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); | 376 | (void)strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); | |
376 | else | 377 | else | |
377 | (void)memset(ll.ll_host, 0, sizeof(ll.ll_host)); | 378 | (void)memset(ll.ll_host, 0, sizeof(ll.ll_host)); | |
378 | 379 | |||
379 | (void)write(fd, &ll, sizeof(ll)); | 380 | (void)write(fd, &ll, sizeof(ll)); | |
380 | (void)close(fd); | 381 | (void)close(fd); | |
381 | 382 | |||
382 | PAM_LOG("Login recorded in %s", _PATH_LASTLOG); | 383 | PAM_LOG("Login recorded in %s", _PATH_LASTLOG); | |
383 | } | 384 | } | |
384 | #endif | 385 | #endif | |
385 | 386 | |||
386 | PAM_MODULE_ENTRY("pam_lastlog"); | 387 | PAM_MODULE_ENTRY("pam_lastlog"); |
--- src/lib/libpam/modules/pam_login_access/login_access.c 2013/12/29 22:54:58 1.7
+++ src/lib/libpam/modules/pam_login_access/login_access.c 2014/01/07 02:07:43 1.8
@@ -1,253 +1,254 @@ | @@ -1,253 +1,254 @@ | |||
1 | /* $NetBSD: login_access.c,v 1.7 2013/12/29 22:54:58 christos Exp $ */ | 1 | /* $NetBSD: login_access.c,v 1.8 2014/01/07 02:07:43 joerg Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * This module implements a simple but effective form of login access | 4 | * This module implements a simple but effective form of login access | |
5 | * control based on login names and on host (or domain) names, internet | 5 | * control based on login names and on host (or domain) names, internet | |
6 | * addresses (or network numbers), or on terminal line names in case of | 6 | * addresses (or network numbers), or on terminal line names in case of | |
7 | * non-networked logins. Diagnostics are reported through syslog(3). | 7 | * non-networked logins. Diagnostics are reported through syslog(3). | |
8 | * | 8 | * | |
9 | * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. | 9 | * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands. | |
10 | */ | 10 | */ | |
11 | 11 | |||
12 | #if 0 | 12 | #if 0 | |
13 | #ifndef lint | 13 | #ifndef lint | |
14 | static char sccsid[] = "%Z% %M% %I% %E% %U%"; | 14 | static char sccsid[] = "%Z% %M% %I% %E% %U%"; | |
15 | #endif | 15 | #endif | |
16 | #endif | 16 | #endif | |
17 | 17 | |||
18 | #include <sys/cdefs.h> | 18 | #include <sys/cdefs.h> | |
19 | #ifdef __FreeBSD__ | 19 | #ifdef __FreeBSD__ | |
20 | __FBSDID("$FreeBSD: src/lib/libpam/modules/pam_login_access/login_access.c,v 1.12 2004/03/05 08:10:18 markm Exp $"); | 20 | __FBSDID("$FreeBSD: src/lib/libpam/modules/pam_login_access/login_access.c,v 1.12 2004/03/05 08:10:18 markm Exp $"); | |
21 | #else | 21 | #else | |
22 | __RCSID("$NetBSD: login_access.c,v 1.7 2013/12/29 22:54:58 christos Exp $"); | 22 | __RCSID("$NetBSD: login_access.c,v 1.8 2014/01/07 02:07:43 joerg Exp $"); | |
23 | #endif | 23 | #endif | |
24 | 24 | |||
25 | #include <sys/types.h> | 25 | #include <sys/types.h> | |
26 | #include <ctype.h> | 26 | #include <ctype.h> | |
27 | #include <errno.h> | 27 | #include <errno.h> | |
28 | #include <grp.h> | 28 | #include <grp.h> | |
29 | #include <stdio.h> | 29 | #include <stdio.h> | |
30 | #include <stdlib.h> | 30 | #include <stdlib.h> | |
31 | #include <string.h> | 31 | #include <string.h> | |
32 | #include <syslog.h> | 32 | #include <syslog.h> | |
33 | #include <unistd.h> | 33 | #include <unistd.h> | |
34 | #include <stdarg.h> | 34 | #include <stdarg.h> | |
35 | 35 | |||
36 | #include "pam_login_access.h" | 36 | #include "pam_login_access.h" | |
37 | 37 | |||
38 | #define _PATH_LOGACCESS "/etc/login.access" | 38 | #define _PATH_LOGACCESS "/etc/login.access" | |
39 | 39 | |||
40 | /* Delimiters for fields and for lists of users, ttys or hosts. */ | 40 | /* Delimiters for fields and for lists of users, ttys or hosts. */ | |
41 | 41 | |||
42 | static char fs[] = ":"; /* field separator */ | 42 | static char fs[] = ":"; /* field separator */ | |
43 | static char sep[] = ", \t"; /* list-element separator */ | 43 | static char sep[] = ", \t"; /* list-element separator */ | |
44 | 44 | |||
45 | /* Constants to be used in assignments only, not in comparisons... */ | 45 | /* Constants to be used in assignments only, not in comparisons... */ | |
46 | 46 | |||
47 | #define YES 1 | 47 | #define YES 1 | |
48 | #define NO 0 | 48 | #define NO 0 | |
49 | 49 | |||
50 | static int from_match(const char *, const char *); | 50 | static int from_match(const char *, const char *); | |
51 | static int list_match(char *, const char *, | 51 | static int list_match(char *, const char *, | |
52 | int (*)(const char *, const char *)); | 52 | int (*)(const char *, const char *)); | |
53 | static int netgroup_match(const char *, const char *, const char *); | 53 | static int netgroup_match(const char *, const char *, const char *); | |
54 | static int string_match(const char *, const char *); | 54 | static int string_match(const char *, const char *); | |
55 | static int user_match(const char *, const char *); | 55 | static int user_match(const char *, const char *); | |
56 | 56 | |||
57 | /* login_access - match username/group and host/tty with access control file */ | 57 | /* login_access - match username/group and host/tty with access control file */ | |
58 | 58 | |||
59 | __printflike(2, 3) | |||
59 | static void | 60 | static void | |
60 | logit(int level, const char *fmt, ...) | 61 | logit(int level, const char *fmt, ...) | |
61 | { | 62 | { | |
62 | va_list ap; | 63 | va_list ap; | |
63 | struct syslog_data data = SYSLOG_DATA_INIT; | 64 | struct syslog_data data = SYSLOG_DATA_INIT; | |
64 | 65 | |||
65 | openlog_r("pam_login_access", LOG_PID, LOG_AUTHPRIV, &data); | 66 | openlog_r("pam_login_access", LOG_PID, LOG_AUTHPRIV, &data); | |
66 | va_start(ap, fmt); | 67 | va_start(ap, fmt); | |
67 | vsyslog_r(level, &data, fmt, ap); | 68 | vsyslog_r(level, &data, fmt, ap); | |
68 | va_end(ap); | 69 | va_end(ap); | |
69 | closelog_r(&data); | 70 | closelog_r(&data); | |
70 | } | 71 | } | |
71 | 72 | |||
72 | int | 73 | int | |
73 | login_access(const char *user, const char *from) | 74 | login_access(const char *user, const char *from) | |
74 | { | 75 | { | |
75 | FILE *fp; | 76 | FILE *fp; | |
76 | char line[BUFSIZ]; | 77 | char line[BUFSIZ]; | |
77 | char *perm; /* becomes permission field */ | 78 | char *perm; /* becomes permission field */ | |
78 | char *users; /* becomes list of login names */ | 79 | char *users; /* becomes list of login names */ | |
79 | char *froms; /* becomes list of terminals or hosts */ | 80 | char *froms; /* becomes list of terminals or hosts */ | |
80 | int match = NO; | 81 | int match = NO; | |
81 | size_t end; | 82 | size_t end; | |
82 | int lineno = 0; /* for diagnostics */ | 83 | int lineno = 0; /* for diagnostics */ | |
83 | 84 | |||
84 | /* | 85 | /* | |
85 | * Process the table one line at a time and stop at the first match. | 86 | * Process the table one line at a time and stop at the first match. | |
86 | * Blank lines and lines that begin with a '#' character are ignored. | 87 | * Blank lines and lines that begin with a '#' character are ignored. | |
87 | * Non-comment lines are broken at the ':' character. All fields are | 88 | * Non-comment lines are broken at the ':' character. All fields are | |
88 | * mandatory. The first field should be a "+" or "-" character. A | 89 | * mandatory. The first field should be a "+" or "-" character. A | |
89 | * non-existing table means no access control. | 90 | * non-existing table means no access control. | |
90 | */ | 91 | */ | |
91 | 92 | |||
92 | if ((fp = fopen(_PATH_LOGACCESS, "r")) != NULL) { | 93 | if ((fp = fopen(_PATH_LOGACCESS, "r")) != NULL) { | |
93 | while (!match && fgets(line, sizeof(line), fp)) { | 94 | while (!match && fgets(line, sizeof(line), fp)) { | |
94 | lineno++; | 95 | lineno++; | |
95 | if ((end = strlen(line)) == 0 || line[end - 1] != '\n') { | 96 | if ((end = strlen(line)) == 0 || line[end - 1] != '\n') { | |
96 | logit(LOG_ERR, "%s: line %d: missing newline or line too long", | 97 | logit(LOG_ERR, "%s: line %d: missing newline or line too long", | |
97 | _PATH_LOGACCESS, lineno); | 98 | _PATH_LOGACCESS, lineno); | |
98 | continue; | 99 | continue; | |
99 | } | 100 | } | |
100 | if (line[0] == '#') | 101 | if (line[0] == '#') | |
101 | continue; /* comment line */ | 102 | continue; /* comment line */ | |
102 | while (end > 0 && isspace((unsigned char)line[end - 1])) | 103 | while (end > 0 && isspace((unsigned char)line[end - 1])) | |
103 | end--; | 104 | end--; | |
104 | line[end] = 0; /* strip trailing whitespace */ | 105 | line[end] = 0; /* strip trailing whitespace */ | |
105 | if (line[0] == 0) /* skip blank lines */ | 106 | if (line[0] == 0) /* skip blank lines */ | |
106 | continue; | 107 | continue; | |
107 | if (!(perm = strtok(line, fs)) | 108 | if (!(perm = strtok(line, fs)) | |
108 | || !(users = strtok((char *) 0, fs)) | 109 | || !(users = strtok((char *) 0, fs)) | |
109 | || !(froms = strtok((char *) 0, fs)) | 110 | || !(froms = strtok((char *) 0, fs)) | |
110 | || strtok((char *) 0, fs)) { | 111 | || strtok((char *) 0, fs)) { | |
111 | logit(LOG_ERR, "%s: line %d: bad field count", _PATH_LOGACCESS, | 112 | logit(LOG_ERR, "%s: line %d: bad field count", _PATH_LOGACCESS, | |
112 | lineno); | 113 | lineno); | |
113 | continue; | 114 | continue; | |
114 | } | 115 | } | |
115 | if (perm[0] != '+' && perm[0] != '-') { | 116 | if (perm[0] != '+' && perm[0] != '-') { | |
116 | logit(LOG_ERR, "%s: line %d: bad first field", _PATH_LOGACCESS, | 117 | logit(LOG_ERR, "%s: line %d: bad first field", _PATH_LOGACCESS, | |
117 | lineno); | 118 | lineno); | |
118 | continue; | 119 | continue; | |
119 | } | 120 | } | |
120 | match = (list_match(froms, from, from_match) | 121 | match = (list_match(froms, from, from_match) | |
121 | && list_match(users, user, user_match)); | 122 | && list_match(users, user, user_match)); | |
122 | } | 123 | } | |
123 | (void) fclose(fp); | 124 | (void) fclose(fp); | |
124 | } else if (errno != ENOENT) { | 125 | } else if (errno != ENOENT) { | |
125 | logit(LOG_ERR, "cannot open %s: %s", _PATH_LOGACCESS, strerror(errno)); | 126 | logit(LOG_ERR, "cannot open %s: %s", _PATH_LOGACCESS, strerror(errno)); | |
126 | } | 127 | } | |
127 | return (match == 0 || (line[0] == '+')); | 128 | return (match == 0 || (line[0] == '+')); | |
128 | } | 129 | } | |
129 | 130 | |||
130 | /* list_match - match an item against a list of tokens with exceptions */ | 131 | /* list_match - match an item against a list of tokens with exceptions */ | |
131 | 132 | |||
132 | static int | 133 | static int | |
133 | list_match(char *list, const char *item, | 134 | list_match(char *list, const char *item, | |
134 | int (*match_fn)(const char *, const char *)) | 135 | int (*match_fn)(const char *, const char *)) | |
135 | { | 136 | { | |
136 | char *tok; | 137 | char *tok; | |
137 | int match = NO; | 138 | int match = NO; | |
138 | 139 | |||
139 | /* | 140 | /* | |
140 | * Process tokens one at a time. We have exhausted all possible matches | 141 | * Process tokens one at a time. We have exhausted all possible matches | |
141 | * when we reach an "EXCEPT" token or the end of the list. If we do find | 142 | * when we reach an "EXCEPT" token or the end of the list. If we do find | |
142 | * a match, look for an "EXCEPT" list and recurse to determine whether | 143 | * a match, look for an "EXCEPT" list and recurse to determine whether | |
143 | * the match is affected by any exceptions. | 144 | * the match is affected by any exceptions. | |
144 | */ | 145 | */ | |
145 | 146 | |||
146 | for (tok = strtok(list, sep); tok != 0; tok = strtok((char *) 0, sep)) { | 147 | for (tok = strtok(list, sep); tok != 0; tok = strtok((char *) 0, sep)) { | |
147 | if (strcasecmp(tok, "EXCEPT") == 0) /* EXCEPT: give up */ | 148 | if (strcasecmp(tok, "EXCEPT") == 0) /* EXCEPT: give up */ | |
148 | break; | 149 | break; | |
149 | if ((match = (*match_fn)(tok, item)) != 0) /* YES */ | 150 | if ((match = (*match_fn)(tok, item)) != 0) /* YES */ | |
150 | break; | 151 | break; | |
151 | } | 152 | } | |
152 | /* Process exceptions to matches. */ | 153 | /* Process exceptions to matches. */ | |
153 | 154 | |||
154 | if (match != NO) { | 155 | if (match != NO) { | |
155 | while ((tok = strtok((char *) 0, sep)) && strcasecmp(tok, "EXCEPT")) | 156 | while ((tok = strtok((char *) 0, sep)) && strcasecmp(tok, "EXCEPT")) | |
156 | /* VOID */ ; | 157 | /* VOID */ ; | |
157 | if (tok == 0 || list_match((char *) 0, item, match_fn) == NO) | 158 | if (tok == 0 || list_match((char *) 0, item, match_fn) == NO) | |
158 | return (match); | 159 | return (match); | |
159 | } | 160 | } | |
160 | return (NO); | 161 | return (NO); | |
161 | } | 162 | } | |
162 | 163 | |||
163 | /* netgroup_match - match group against machine or user */ | 164 | /* netgroup_match - match group against machine or user */ | |
164 | 165 | |||
165 | static int | 166 | static int | |
166 | netgroup_match(const char *group __unused, | 167 | netgroup_match(const char *group __unused, | |
167 | const char *machine __unused, const char *user __unused) | 168 | const char *machine __unused, const char *user __unused) | |
168 | { | 169 | { | |
169 | logit(LOG_ERR, "NIS netgroup support not configured"); | 170 | logit(LOG_ERR, "NIS netgroup support not configured"); | |
170 | return 0; | 171 | return 0; | |
171 | } | 172 | } | |
172 | 173 | |||
173 | /* user_match - match a username against one token */ | 174 | /* user_match - match a username against one token */ | |
174 | 175 | |||
175 | static int | 176 | static int | |
176 | user_match(const char *tok, const char *string) | 177 | user_match(const char *tok, const char *string) | |
177 | { | 178 | { | |
178 | struct group grres, *group; | 179 | struct group grres, *group; | |
179 | char grbuf[1024]; | 180 | char grbuf[1024]; | |
180 | int i; | 181 | int i; | |
181 | 182 | |||
182 | /* | 183 | /* | |
183 | * If a token has the magic value "ALL" the match always succeeds. | 184 | * If a token has the magic value "ALL" the match always succeeds. | |
184 | * Otherwise, return YES if the token fully matches the username, or if | 185 | * Otherwise, return YES if the token fully matches the username, or if | |
185 | * the token is a group that contains the username. | 186 | * the token is a group that contains the username. | |
186 | */ | 187 | */ | |
187 | 188 | |||
188 | if (tok[0] == '@') { /* netgroup */ | 189 | if (tok[0] == '@') { /* netgroup */ | |
189 | return (netgroup_match(tok + 1, (char *) 0, string)); | 190 | return (netgroup_match(tok + 1, (char *) 0, string)); | |
190 | } else if (string_match(tok, string)) { /* ALL or exact match */ | 191 | } else if (string_match(tok, string)) { /* ALL or exact match */ | |
191 | return (YES); | 192 | return (YES); | |
192 | } else if (getgrnam_r(tok, &grres, grbuf, sizeof(grbuf), &group) == 0 && | 193 | } else if (getgrnam_r(tok, &grres, grbuf, sizeof(grbuf), &group) == 0 && | |
193 | group != NULL) {/* try group membership */ | 194 | group != NULL) {/* try group membership */ | |
194 | for (i = 0; group->gr_mem[i]; i++) | 195 | for (i = 0; group->gr_mem[i]; i++) | |
195 | if (strcasecmp(string, group->gr_mem[i]) == 0) | 196 | if (strcasecmp(string, group->gr_mem[i]) == 0) | |
196 | return (YES); | 197 | return (YES); | |
197 | } | 198 | } | |
198 | return (NO); | 199 | return (NO); | |
199 | } | 200 | } | |
200 | 201 | |||
201 | /* from_match - match a host or tty against a list of tokens */ | 202 | /* from_match - match a host or tty against a list of tokens */ | |
202 | 203 | |||
203 | static int | 204 | static int | |
204 | from_match(const char *tok, const char *string) | 205 | from_match(const char *tok, const char *string) | |
205 | { | 206 | { | |
206 | size_t tok_len; | 207 | size_t tok_len; | |
207 | size_t str_len; | 208 | size_t str_len; | |
208 | 209 | |||
209 | /* | 210 | /* | |
210 | * If a token has the magic value "ALL" the match always succeeds. Return | 211 | * If a token has the magic value "ALL" the match always succeeds. Return | |
211 | * YES if the token fully matches the string. If the token is a domain | 212 | * YES if the token fully matches the string. If the token is a domain | |
212 | * name, return YES if it matches the last fields of the string. If the | 213 | * name, return YES if it matches the last fields of the string. If the | |
213 | * token has the magic value "LOCAL", return YES if the string does not | 214 | * token has the magic value "LOCAL", return YES if the string does not | |
214 | * contain a "." character. If the token is a network number, return YES | 215 | * contain a "." character. If the token is a network number, return YES | |
215 | * if it matches the head of the string. | 216 | * if it matches the head of the string. | |
216 | */ | 217 | */ | |
217 | 218 | |||
218 | if (tok[0] == '@') { /* netgroup */ | 219 | if (tok[0] == '@') { /* netgroup */ | |
219 | return (netgroup_match(tok + 1, string, (char *) 0)); | 220 | return (netgroup_match(tok + 1, string, (char *) 0)); | |
220 | } else if (string_match(tok, string)) { /* ALL or exact match */ | 221 | } else if (string_match(tok, string)) { /* ALL or exact match */ | |
221 | return (YES); | 222 | return (YES); | |
222 | } else if (tok[0] == '.') { /* domain: match last fields */ | 223 | } else if (tok[0] == '.') { /* domain: match last fields */ | |
223 | if ((str_len = strlen(string)) > (tok_len = strlen(tok)) | 224 | if ((str_len = strlen(string)) > (tok_len = strlen(tok)) | |
224 | && strcasecmp(tok, string + str_len - tok_len) == 0) | 225 | && strcasecmp(tok, string + str_len - tok_len) == 0) | |
225 | return (YES); | 226 | return (YES); | |
226 | } else if (strcasecmp(tok, "LOCAL") == 0) { /* local: no dots */ | 227 | } else if (strcasecmp(tok, "LOCAL") == 0) { /* local: no dots */ | |
227 | if (strchr(string, '.') == 0) | 228 | if (strchr(string, '.') == 0) | |
228 | return (YES); | 229 | return (YES); | |
229 | } else if (tok[(tok_len = strlen(tok)) - 1] == '.' /* network */ | 230 | } else if (tok[(tok_len = strlen(tok)) - 1] == '.' /* network */ | |
230 | && strncmp(tok, string, tok_len) == 0) { | 231 | && strncmp(tok, string, tok_len) == 0) { | |
231 | return (YES); | 232 | return (YES); | |
232 | } | 233 | } | |
233 | return (NO); | 234 | return (NO); | |
234 | } | 235 | } | |
235 | 236 | |||
236 | /* string_match - match a string against one token */ | 237 | /* string_match - match a string against one token */ | |
237 | 238 | |||
238 | static int | 239 | static int | |
239 | string_match(const char *tok, const char *string) | 240 | string_match(const char *tok, const char *string) | |
240 | { | 241 | { | |
241 | 242 | |||
242 | /* | 243 | /* | |
243 | * If the token has the magic value "ALL" the match always succeeds. | 244 | * If the token has the magic value "ALL" the match always succeeds. | |
244 | * Otherwise, return YES if the token fully matches the string. | 245 | * Otherwise, return YES if the token fully matches the string. | |
245 | */ | 246 | */ | |
246 | 247 | |||
247 | if (strcasecmp(tok, "ALL") == 0) { /* all: always matches */ | 248 | if (strcasecmp(tok, "ALL") == 0) { /* all: always matches */ | |
248 | return (YES); | 249 | return (YES); | |
249 | } else if (strcasecmp(tok, string) == 0) { /* try exact match */ | 250 | } else if (strcasecmp(tok, string) == 0) { /* try exact match */ | |
250 | return (YES); | 251 | return (YES); | |
251 | } | 252 | } | |
252 | return (NO); | 253 | return (NO); | |
253 | } | 254 | } |
--- src/lib/libpam/modules/pam_radius/pam_radius.c 2006/11/03 18:55:40 1.7
+++ src/lib/libpam/modules/pam_radius/pam_radius.c 2014/01/07 02:07:43 1.8
@@ -1,388 +1,389 @@ | @@ -1,388 +1,389 @@ | |||
1 | /* $NetBSD: pam_radius.c,v 1.7 2006/11/03 18:55:40 christos Exp $ */ | 1 | /* $NetBSD: pam_radius.c,v 1.8 2014/01/07 02:07:43 joerg Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright 1998 Juniper Networks, Inc. | 4 | * Copyright 1998 Juniper Networks, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * Copyright (c) 2001-2003 Networks Associates Technology, Inc. | 6 | * Copyright (c) 2001-2003 Networks Associates Technology, Inc. | |
7 | * All rights reserved. | 7 | * All rights reserved. | |
8 | * | 8 | * | |
9 | * Portions of this software were developed for the FreeBSD Project by | 9 | * Portions of this software were developed for the FreeBSD Project by | |
10 | * ThinkSec AS and NAI Labs, the Security Research Division of Network | 10 | * ThinkSec AS and NAI Labs, the Security Research Division of Network | |
11 | * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 | 11 | * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 | |
12 | * ("CBOSS"), as part of the DARPA CHATS research program. | 12 | * ("CBOSS"), as part of the DARPA CHATS research program. | |
13 | * | 13 | * | |
14 | * Redistribution and use in source and binary forms, with or without | 14 | * Redistribution and use in source and binary forms, with or without | |
15 | * modification, are permitted provided that the following conditions | 15 | * modification, are permitted provided that the following conditions | |
16 | * are met: | 16 | * are met: | |
17 | * 1. Redistributions of source code must retain the above copyright | 17 | * 1. Redistributions of source code must retain the above copyright | |
18 | * notice, this list of conditions and the following disclaimer. | 18 | * notice, this list of conditions and the following disclaimer. | |
19 | * 2. Redistributions in binary form must reproduce the above copyright | 19 | * 2. Redistributions in binary form must reproduce the above copyright | |
20 | * notice, this list of conditions and the following disclaimer in the | 20 | * notice, this list of conditions and the following disclaimer in the | |
21 | * documentation and/or other materials provided with the distribution. | 21 | * documentation and/or other materials provided with the distribution. | |
22 | * 3. The name of the author may not be used to endorse or promote | 22 | * 3. The name of the author may not be used to endorse or promote | |
23 | * products derived from this software without specific prior written | 23 | * products derived from this software without specific prior written | |
24 | * permission. | 24 | * permission. | |
25 | * | 25 | * | |
26 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | 26 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
27 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 27 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | 29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
30 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 30 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
31 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 31 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
32 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 32 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
33 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 33 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
34 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 34 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
35 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 35 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
36 | * SUCH DAMAGE. | 36 | * SUCH DAMAGE. | |
37 | */ | 37 | */ | |
38 | 38 | |||
39 | #include <sys/cdefs.h> | 39 | #include <sys/cdefs.h> | |
40 | #ifdef __FreeBSD__ | 40 | #ifdef __FreeBSD__ | |
41 | __FBSDID("$FreeBSD: src/lib/libpam/modules/pam_radius/pam_radius.c,v 1.22 2004/06/25 12:32:45 kan Exp $"); | 41 | __FBSDID("$FreeBSD: src/lib/libpam/modules/pam_radius/pam_radius.c,v 1.22 2004/06/25 12:32:45 kan Exp $"); | |
42 | #else | 42 | #else | |
43 | __RCSID("$NetBSD: pam_radius.c,v 1.7 2006/11/03 18:55:40 christos Exp $"); | 43 | __RCSID("$NetBSD: pam_radius.c,v 1.8 2014/01/07 02:07:43 joerg Exp $"); | |
44 | #endif | 44 | #endif | |
45 | 45 | |||
46 | #include <sys/param.h> | 46 | #include <sys/param.h> | |
47 | #include <sys/types.h> | 47 | #include <sys/types.h> | |
48 | #include <sys/socket.h> | 48 | #include <sys/socket.h> | |
49 | #include <netdb.h> | 49 | #include <netdb.h> | |
50 | #include <pwd.h> | 50 | #include <pwd.h> | |
51 | #include <radlib.h> | 51 | #include <radlib.h> | |
52 | #include <stdlib.h> | 52 | #include <stdlib.h> | |
53 | #include <string.h> | 53 | #include <string.h> | |
54 | #include <syslog.h> | 54 | #include <syslog.h> | |
55 | #include <unistd.h> | 55 | #include <unistd.h> | |
56 | #include <stdarg.h> | 56 | #include <stdarg.h> | |
57 | 57 | |||
58 | #define PAM_SM_AUTH | 58 | #define PAM_SM_AUTH | |
59 | 59 | |||
60 | #include <security/pam_appl.h> | 60 | #include <security/pam_appl.h> | |
61 | #include <security/pam_modules.h> | 61 | #include <security/pam_modules.h> | |
62 | #include <security/pam_mod_misc.h> | 62 | #include <security/pam_mod_misc.h> | |
63 | 63 | |||
64 | #define PAM_OPT_CONF "conf" | 64 | #define PAM_OPT_CONF "conf" | |
65 | #define PAM_OPT_TEMPLATE_USER "template_user" | 65 | #define PAM_OPT_TEMPLATE_USER "template_user" | |
66 | #define PAM_OPT_NAS_ID "nas_id" | 66 | #define PAM_OPT_NAS_ID "nas_id" | |
67 | #define PAM_OPT_NAS_IPADDR "nas_ipaddr" | 67 | #define PAM_OPT_NAS_IPADDR "nas_ipaddr" | |
68 | 68 | |||
69 | #define MAX_CHALLENGE_MSGS 10 | 69 | #define MAX_CHALLENGE_MSGS 10 | |
70 | #define PASSWORD_PROMPT "RADIUS Password:" | 70 | #define PASSWORD_PROMPT "RADIUS Password:" | |
71 | 71 | |||
72 | static int build_access_request(struct rad_handle *, const char *, | 72 | static int build_access_request(struct rad_handle *, const char *, | |
73 | const char *, const char *, const char *, const void *, | 73 | const char *, const char *, const char *, const void *, | |
74 | size_t); | 74 | size_t); | |
75 | static int do_accept(pam_handle_t *, struct rad_handle *); | 75 | static int do_accept(pam_handle_t *, struct rad_handle *); | |
76 | static int do_challenge(pam_handle_t *, struct rad_handle *, | 76 | static int do_challenge(pam_handle_t *, struct rad_handle *, | |
77 | const char *); | 77 | const char *); | |
78 | 78 | |||
79 | __printflike(2, 3) | |||
79 | static void | 80 | static void | |
80 | logit(int level, const char *fmt, ...) | 81 | logit(int level, const char *fmt, ...) | |
81 | { | 82 | { | |
82 | va_list ap; | 83 | va_list ap; | |
83 | struct syslog_data data = SYSLOG_DATA_INIT; | 84 | struct syslog_data data = SYSLOG_DATA_INIT; | |
84 | 85 | |||
85 | openlog_r("pam_radius", LOG_PID, LOG_AUTHPRIV, &data); | 86 | openlog_r("pam_radius", LOG_PID, LOG_AUTHPRIV, &data); | |
86 | va_start(ap, fmt); | 87 | va_start(ap, fmt); | |
87 | vsyslog_r(level, &data, fmt, ap); | 88 | vsyslog_r(level, &data, fmt, ap); | |
88 | va_end(ap); | 89 | va_end(ap); | |
89 | closelog_r(&data); | 90 | closelog_r(&data); | |
90 | } | 91 | } | |
91 | 92 | |||
92 | /* | 93 | /* | |
93 | * Construct an access request, but don't send it. Returns 0 on success, | 94 | * Construct an access request, but don't send it. Returns 0 on success, | |
94 | * -1 on failure. | 95 | * -1 on failure. | |
95 | */ | 96 | */ | |
96 | static int | 97 | static int | |
97 | build_access_request(struct rad_handle *radh, const char *user, | 98 | build_access_request(struct rad_handle *radh, const char *user, | |
98 | const char *pass, const char *nas_id, const char *nas_ipaddr, | 99 | const char *pass, const char *nas_id, const char *nas_ipaddr, | |
99 | const void *state, size_t state_len) | 100 | const void *state, size_t state_len) | |
100 | { | 101 | { | |
101 | int error; | 102 | int error; | |
102 | char host[MAXHOSTNAMELEN]; | 103 | char host[MAXHOSTNAMELEN]; | |
103 | struct sockaddr_in *haddr; | 104 | struct sockaddr_in *haddr; | |
104 | struct addrinfo hints; | 105 | struct addrinfo hints; | |
105 | struct addrinfo *res; | 106 | struct addrinfo *res; | |
106 | 107 | |||
107 | if (rad_create_request(radh, RAD_ACCESS_REQUEST) == -1) { | 108 | if (rad_create_request(radh, RAD_ACCESS_REQUEST) == -1) { | |
108 | logit(LOG_CRIT, "rad_create_request: %s", rad_strerror(radh)); | 109 | logit(LOG_CRIT, "rad_create_request: %s", rad_strerror(radh)); | |
109 | return (-1); | 110 | return (-1); | |
110 | } | 111 | } | |
111 | if (nas_id == NULL || | 112 | if (nas_id == NULL || | |
112 | (nas_ipaddr != NULL && strlen(nas_ipaddr) == 0)) { | 113 | (nas_ipaddr != NULL && strlen(nas_ipaddr) == 0)) { | |
113 | if (gethostname(host, sizeof host) != -1) { | 114 | if (gethostname(host, sizeof host) != -1) { | |
114 | if (nas_id == NULL) | 115 | if (nas_id == NULL) | |
115 | nas_id = host; | 116 | nas_id = host; | |
116 | if (nas_ipaddr != NULL && strlen(nas_ipaddr) == 0) | 117 | if (nas_ipaddr != NULL && strlen(nas_ipaddr) == 0) | |
117 | nas_ipaddr = host; | 118 | nas_ipaddr = host; | |
118 | } | 119 | } | |
119 | } | 120 | } | |
120 | if ((user != NULL && | 121 | if ((user != NULL && | |
121 | rad_put_string(radh, RAD_USER_NAME, user) == -1) || | 122 | rad_put_string(radh, RAD_USER_NAME, user) == -1) || | |
122 | (pass != NULL && | 123 | (pass != NULL && | |
123 | rad_put_string(radh, RAD_USER_PASSWORD, pass) == -1) || | 124 | rad_put_string(radh, RAD_USER_PASSWORD, pass) == -1) || | |
124 | (nas_id != NULL && | 125 | (nas_id != NULL && | |
125 | rad_put_string(radh, RAD_NAS_IDENTIFIER, nas_id) == -1)) { | 126 | rad_put_string(radh, RAD_NAS_IDENTIFIER, nas_id) == -1)) { | |
126 | logit(LOG_CRIT, "rad_put_string: %s", rad_strerror(radh)); | 127 | logit(LOG_CRIT, "rad_put_string: %s", rad_strerror(radh)); | |
127 | return (-1); | 128 | return (-1); | |
128 | } | 129 | } | |
129 | if (nas_ipaddr != NULL) { | 130 | if (nas_ipaddr != NULL) { | |
130 | memset(&hints, 0, sizeof(hints)); | 131 | memset(&hints, 0, sizeof(hints)); | |
131 | hints.ai_family = PF_INET; | 132 | hints.ai_family = PF_INET; | |
132 | if (getaddrinfo(nas_ipaddr, NULL, &hints, &res) == 0 && | 133 | if (getaddrinfo(nas_ipaddr, NULL, &hints, &res) == 0 && | |
133 | res != NULL) { | 134 | res != NULL) { | |
134 | haddr = (struct sockaddr_in *)res->ai_addr; | 135 | haddr = (struct sockaddr_in *)res->ai_addr; | |
135 | error = rad_put_addr(radh, RAD_NAS_IP_ADDRESS, | 136 | error = rad_put_addr(radh, RAD_NAS_IP_ADDRESS, | |
136 | haddr->sin_addr); | 137 | haddr->sin_addr); | |
137 | freeaddrinfo(res); | 138 | freeaddrinfo(res); | |
138 | if (error == -1) { | 139 | if (error == -1) { | |
139 | logit(LOG_CRIT, "rad_put_addr: %s", | 140 | logit(LOG_CRIT, "rad_put_addr: %s", | |
140 | rad_strerror(radh)); | 141 | rad_strerror(radh)); | |
141 | return (-1); | 142 | return (-1); | |
142 | } | 143 | } | |
143 | } | 144 | } | |
144 | } | 145 | } | |
145 | if (state != NULL && rad_put_attr(radh, RAD_STATE, state, | 146 | if (state != NULL && rad_put_attr(radh, RAD_STATE, state, | |
146 | state_len) == -1) { | 147 | state_len) == -1) { | |
147 | logit(LOG_CRIT, "rad_put_attr: %s", rad_strerror(radh)); | 148 | logit(LOG_CRIT, "rad_put_attr: %s", rad_strerror(radh)); | |
148 | return (-1); | 149 | return (-1); | |
149 | } | 150 | } | |
150 | if (rad_put_int(radh, RAD_SERVICE_TYPE, RAD_AUTHENTICATE_ONLY) == -1) { | 151 | if (rad_put_int(radh, RAD_SERVICE_TYPE, RAD_AUTHENTICATE_ONLY) == -1) { | |
151 | logit(LOG_CRIT, "rad_put_int: %s", rad_strerror(radh)); | 152 | logit(LOG_CRIT, "rad_put_int: %s", rad_strerror(radh)); | |
152 | return (-1); | 153 | return (-1); | |
153 | } | 154 | } | |
154 | return (0); | 155 | return (0); | |
155 | } | 156 | } | |
156 | 157 | |||
157 | static int | 158 | static int | |
158 | do_accept(pam_handle_t *pamh, struct rad_handle *radh) | 159 | do_accept(pam_handle_t *pamh, struct rad_handle *radh) | |
159 | { | 160 | { | |
160 | int attrtype; | 161 | int attrtype; | |
161 | const void *attrval; | 162 | const void *attrval; | |
162 | size_t attrlen; | 163 | size_t attrlen; | |
163 | char *s; | 164 | char *s; | |
164 | 165 | |||
165 | while ((attrtype = rad_get_attr(radh, &attrval, &attrlen)) > 0) { | 166 | while ((attrtype = rad_get_attr(radh, &attrval, &attrlen)) > 0) { | |
166 | if (attrtype == RAD_USER_NAME) { | 167 | if (attrtype == RAD_USER_NAME) { | |
167 | s = rad_cvt_string(attrval, attrlen); | 168 | s = rad_cvt_string(attrval, attrlen); | |
168 | if (s == NULL) { | 169 | if (s == NULL) { | |
169 | logit(LOG_CRIT, | 170 | logit(LOG_CRIT, | |
170 | "rad_cvt_string: out of memory"); | 171 | "rad_cvt_string: out of memory"); | |
171 | return (-1); | 172 | return (-1); | |
172 | } | 173 | } | |
173 | pam_set_item(pamh, PAM_USER, s); | 174 | pam_set_item(pamh, PAM_USER, s); | |
174 | free(s); | 175 | free(s); | |
175 | } | 176 | } | |
176 | } | 177 | } | |
177 | if (attrtype == -1) { | 178 | if (attrtype == -1) { | |
178 | logit(LOG_CRIT, "rad_get_attr: %s", rad_strerror(radh)); | 179 | logit(LOG_CRIT, "rad_get_attr: %s", rad_strerror(radh)); | |
179 | return (-1); | 180 | return (-1); | |
180 | } | 181 | } | |
181 | return (0); | 182 | return (0); | |
182 | } | 183 | } | |
183 | 184 | |||
184 | static int | 185 | static int | |
185 | do_challenge(pam_handle_t *pamh, struct rad_handle *radh, const char *user) | 186 | do_challenge(pam_handle_t *pamh, struct rad_handle *radh, const char *user) | |
186 | { | 187 | { | |
187 | int retval; | 188 | int retval; | |
188 | int attrtype; | 189 | int attrtype; | |
189 | const void *attrval; | 190 | const void *attrval; | |
190 | size_t attrlen; | 191 | size_t attrlen; | |
191 | const void *state; | 192 | const void *state; | |
192 | size_t statelen; | 193 | size_t statelen; | |
193 | struct pam_message msgs[MAX_CHALLENGE_MSGS]; | 194 | struct pam_message msgs[MAX_CHALLENGE_MSGS]; | |
194 | const struct pam_message *msg_ptrs[MAX_CHALLENGE_MSGS]; | 195 | const struct pam_message *msg_ptrs[MAX_CHALLENGE_MSGS]; | |
195 | struct pam_response *resp; | 196 | struct pam_response *resp; | |
196 | int num_msgs; | 197 | int num_msgs; | |
197 | const void *item; | 198 | const void *item; | |
198 | const struct pam_conv *conv; | 199 | const struct pam_conv *conv; | |
199 | 200 | |||
200 | state = NULL; | 201 | state = NULL; | |
201 | statelen = 0; | 202 | statelen = 0; | |
202 | num_msgs = 0; | 203 | num_msgs = 0; | |
203 | while ((attrtype = rad_get_attr(radh, &attrval, &attrlen)) > 0) { | 204 | while ((attrtype = rad_get_attr(radh, &attrval, &attrlen)) > 0) { | |
204 | switch (attrtype) { | 205 | switch (attrtype) { | |
205 | 206 | |||
206 | case RAD_STATE: | 207 | case RAD_STATE: | |
207 | state = attrval; | 208 | state = attrval; | |
208 | statelen = attrlen; | 209 | statelen = attrlen; | |
209 | break; | 210 | break; | |
210 | 211 | |||
211 | case RAD_REPLY_MESSAGE: | 212 | case RAD_REPLY_MESSAGE: | |
212 | if (num_msgs >= MAX_CHALLENGE_MSGS) { | 213 | if (num_msgs >= MAX_CHALLENGE_MSGS) { | |
213 | logit(LOG_CRIT, | 214 | logit(LOG_CRIT, | |
214 | "Too many RADIUS challenge messages"); | 215 | "Too many RADIUS challenge messages"); | |
215 | return (PAM_SERVICE_ERR); | 216 | return (PAM_SERVICE_ERR); | |
216 | } | 217 | } | |
217 | msgs[num_msgs].msg = rad_cvt_string(attrval, attrlen); | 218 | msgs[num_msgs].msg = rad_cvt_string(attrval, attrlen); | |
218 | if (msgs[num_msgs].msg == NULL) { | 219 | if (msgs[num_msgs].msg == NULL) { | |
219 | logit(LOG_CRIT, | 220 | logit(LOG_CRIT, | |
220 | "rad_cvt_string: out of memory"); | 221 | "rad_cvt_string: out of memory"); | |
221 | return (PAM_SERVICE_ERR); | 222 | return (PAM_SERVICE_ERR); | |
222 | } | 223 | } | |
223 | msgs[num_msgs].msg_style = PAM_TEXT_INFO; | 224 | msgs[num_msgs].msg_style = PAM_TEXT_INFO; | |
224 | msg_ptrs[num_msgs] = &msgs[num_msgs]; | 225 | msg_ptrs[num_msgs] = &msgs[num_msgs]; | |
225 | num_msgs++; | 226 | num_msgs++; | |
226 | break; | 227 | break; | |
227 | } | 228 | } | |
228 | } | 229 | } | |
229 | if (attrtype == -1) { | 230 | if (attrtype == -1) { | |
230 | logit(LOG_CRIT, "rad_get_attr: %s", rad_strerror(radh)); | 231 | logit(LOG_CRIT, "rad_get_attr: %s", rad_strerror(radh)); | |
231 | return (PAM_SERVICE_ERR); | 232 | return (PAM_SERVICE_ERR); | |
232 | } | 233 | } | |
233 | if (num_msgs == 0) { | 234 | if (num_msgs == 0) { | |
234 | msgs[num_msgs].msg = strdup("(null RADIUS challenge): "); | 235 | msgs[num_msgs].msg = strdup("(null RADIUS challenge): "); | |
235 | if (msgs[num_msgs].msg == NULL) { | 236 | if (msgs[num_msgs].msg == NULL) { | |
236 | logit(LOG_CRIT, "Out of memory"); | 237 | logit(LOG_CRIT, "Out of memory"); | |
237 | return (PAM_SERVICE_ERR); | 238 | return (PAM_SERVICE_ERR); | |
238 | } | 239 | } | |
239 | msgs[num_msgs].msg_style = PAM_TEXT_INFO; | 240 | msgs[num_msgs].msg_style = PAM_TEXT_INFO; | |
240 | msg_ptrs[num_msgs] = &msgs[num_msgs]; | 241 | msg_ptrs[num_msgs] = &msgs[num_msgs]; | |
241 | num_msgs++; | 242 | num_msgs++; | |
242 | } | 243 | } | |
243 | msgs[num_msgs-1].msg_style = PAM_PROMPT_ECHO_ON; | 244 | msgs[num_msgs-1].msg_style = PAM_PROMPT_ECHO_ON; | |
244 | if ((retval = pam_get_item(pamh, PAM_CONV, &item)) != PAM_SUCCESS) { | 245 | if ((retval = pam_get_item(pamh, PAM_CONV, &item)) != PAM_SUCCESS) { | |
245 | logit(LOG_CRIT, "do_challenge: cannot get PAM_CONV"); | 246 | logit(LOG_CRIT, "do_challenge: cannot get PAM_CONV"); | |
246 | return (retval); | 247 | return (retval); | |
247 | } | 248 | } | |
248 | conv = (const struct pam_conv *)item; | 249 | conv = (const struct pam_conv *)item; | |
249 | if ((retval = conv->conv(num_msgs, msg_ptrs, &resp, | 250 | if ((retval = conv->conv(num_msgs, msg_ptrs, &resp, | |
250 | conv->appdata_ptr)) != PAM_SUCCESS) | 251 | conv->appdata_ptr)) != PAM_SUCCESS) | |
251 | return (retval); | 252 | return (retval); | |
252 | if (build_access_request(radh, user, resp[num_msgs-1].resp, NULL, | 253 | if (build_access_request(radh, user, resp[num_msgs-1].resp, NULL, | |
253 | NULL, state, statelen) == -1) | 254 | NULL, state, statelen) == -1) | |
254 | return (PAM_SERVICE_ERR); | 255 | return (PAM_SERVICE_ERR); | |
255 | memset(resp[num_msgs-1].resp, 0, strlen(resp[num_msgs-1].resp)); | 256 | memset(resp[num_msgs-1].resp, 0, strlen(resp[num_msgs-1].resp)); | |
256 | free(resp[num_msgs-1].resp); | 257 | free(resp[num_msgs-1].resp); | |
257 | free(resp); | 258 | free(resp); | |
258 | while (num_msgs > 0) | 259 | while (num_msgs > 0) | |
259 | free(msgs[--num_msgs].msg); | 260 | free(msgs[--num_msgs].msg); | |
260 | return (PAM_SUCCESS); | 261 | return (PAM_SUCCESS); | |
261 | } | 262 | } | |
262 | 263 | |||
263 | PAM_EXTERN int | 264 | PAM_EXTERN int | |
264 | pam_sm_authenticate(pam_handle_t *pamh, int flags __unused, | 265 | pam_sm_authenticate(pam_handle_t *pamh, int flags __unused, | |
265 | int argc __unused, const char *argv[] __unused) | 266 | int argc __unused, const char *argv[] __unused) | |
266 | { | 267 | { | |
267 | struct rad_handle *radh; | 268 | struct rad_handle *radh; | |
268 | const char *user, *pass; | 269 | const char *user, *pass; | |
269 | const void *tmpuser; | 270 | const void *tmpuser; | |
270 | struct passwd *pwd, pwres; | 271 | struct passwd *pwd, pwres; | |
271 | char pwbuf[1024]; | 272 | char pwbuf[1024]; | |
272 | const char *conf_file, *template_user, *nas_id, *nas_ipaddr; | 273 | const char *conf_file, *template_user, *nas_id, *nas_ipaddr; | |
273 | int retval; | 274 | int retval; | |
274 | int e; | 275 | int e; | |
275 | 276 | |||
276 | conf_file = openpam_get_option(pamh, PAM_OPT_CONF); | 277 | conf_file = openpam_get_option(pamh, PAM_OPT_CONF); | |
277 | template_user = openpam_get_option(pamh, PAM_OPT_TEMPLATE_USER); | 278 | template_user = openpam_get_option(pamh, PAM_OPT_TEMPLATE_USER); | |
278 | nas_id = openpam_get_option(pamh, PAM_OPT_NAS_ID); | 279 | nas_id = openpam_get_option(pamh, PAM_OPT_NAS_ID); | |
279 | nas_ipaddr = openpam_get_option(pamh, PAM_OPT_NAS_IPADDR); | 280 | nas_ipaddr = openpam_get_option(pamh, PAM_OPT_NAS_IPADDR); | |
280 | 281 | |||
281 | retval = pam_get_user(pamh, &user, NULL); | 282 | retval = pam_get_user(pamh, &user, NULL); | |
282 | if (retval != PAM_SUCCESS) | 283 | if (retval != PAM_SUCCESS) | |
283 | return (retval); | 284 | return (retval); | |
284 | 285 | |||
285 | PAM_LOG("Got user: %s", user); | 286 | PAM_LOG("Got user: %s", user); | |
286 | 287 | |||
287 | retval = pam_get_authtok(pamh, PAM_AUTHTOK, &pass, PASSWORD_PROMPT); | 288 | retval = pam_get_authtok(pamh, PAM_AUTHTOK, &pass, PASSWORD_PROMPT); | |
288 | if (retval != PAM_SUCCESS) | 289 | if (retval != PAM_SUCCESS) | |
289 | return (retval); | 290 | return (retval); | |
290 | 291 | |||
291 | PAM_LOG("Got password"); | 292 | PAM_LOG("Got password"); | |
292 | 293 | |||
293 | radh = rad_open(); | 294 | radh = rad_open(); | |
294 | if (radh == NULL) { | 295 | if (radh == NULL) { | |
295 | logit(LOG_CRIT, "rad_open failed"); | 296 | logit(LOG_CRIT, "rad_open failed"); | |
296 | return (PAM_SERVICE_ERR); | 297 | return (PAM_SERVICE_ERR); | |
297 | } | 298 | } | |
298 | 299 | |||
299 | PAM_LOG("Radius opened"); | 300 | PAM_LOG("Radius opened"); | |
300 | 301 | |||
301 | if (rad_config(radh, conf_file) == -1) { | 302 | if (rad_config(radh, conf_file) == -1) { | |
302 | logit(LOG_ALERT, "rad_config: %s", rad_strerror(radh)); | 303 | logit(LOG_ALERT, "rad_config: %s", rad_strerror(radh)); | |
303 | rad_close(radh); | 304 | rad_close(radh); | |
304 | return (PAM_SERVICE_ERR); | 305 | return (PAM_SERVICE_ERR); | |
305 | } | 306 | } | |
306 | 307 | |||
307 | PAM_LOG("Radius config file read"); | 308 | PAM_LOG("Radius config file read"); | |
308 | 309 | |||
309 | if (build_access_request(radh, user, pass, nas_id, nas_ipaddr, NULL, | 310 | if (build_access_request(radh, user, pass, nas_id, nas_ipaddr, NULL, | |
310 | 0) == -1) { | 311 | 0) == -1) { | |
311 | rad_close(radh); | 312 | rad_close(radh); | |
312 | return (PAM_SERVICE_ERR); | 313 | return (PAM_SERVICE_ERR); | |
313 | } | 314 | } | |
314 | 315 | |||
315 | PAM_LOG("Radius build access done"); | 316 | PAM_LOG("Radius build access done"); | |
316 | 317 | |||
317 | for (;;) { | 318 | for (;;) { | |
318 | switch (rad_send_request(radh)) { | 319 | switch (rad_send_request(radh)) { | |
319 | 320 | |||
320 | case RAD_ACCESS_ACCEPT: | 321 | case RAD_ACCESS_ACCEPT: | |
321 | e = do_accept(pamh, radh); | 322 | e = do_accept(pamh, radh); | |
322 | rad_close(radh); | 323 | rad_close(radh); | |
323 | if (e == -1) | 324 | if (e == -1) | |
324 | return (PAM_SERVICE_ERR); | 325 | return (PAM_SERVICE_ERR); | |
325 | if (template_user != NULL) { | 326 | if (template_user != NULL) { | |
326 | 327 | |||
327 | PAM_LOG("Trying template user: %s", | 328 | PAM_LOG("Trying template user: %s", | |
328 | template_user); | 329 | template_user); | |
329 | 330 | |||
330 | /* | 331 | /* | |
331 | * If the given user name doesn't exist in | 332 | * If the given user name doesn't exist in | |
332 | * the local password database, change it | 333 | * the local password database, change it | |
333 | * to the value given in the "template_user" | 334 | * to the value given in the "template_user" | |
334 | * option. | 335 | * option. | |
335 | */ | 336 | */ | |
336 | retval = pam_get_item(pamh, PAM_USER, &tmpuser); | 337 | retval = pam_get_item(pamh, PAM_USER, &tmpuser); | |
337 | if (retval != PAM_SUCCESS) | 338 | if (retval != PAM_SUCCESS) | |
338 | return (retval); | 339 | return (retval); | |
339 | if (getpwnam_r(tmpuser, &pwres, pwbuf, | 340 | if (getpwnam_r(tmpuser, &pwres, pwbuf, | |
340 | sizeof(pwbuf), &pwd) != 0 || | 341 | sizeof(pwbuf), &pwd) != 0 || | |
341 | pwd == NULL) { | 342 | pwd == NULL) { | |
342 | pam_set_item(pamh, PAM_USER, | 343 | pam_set_item(pamh, PAM_USER, | |
343 | template_user); | 344 | template_user); | |
344 | PAM_LOG("Using template user"); | 345 | PAM_LOG("Using template user"); | |
345 | } | 346 | } | |
346 | 347 | |||
347 | } | 348 | } | |
348 | return (PAM_SUCCESS); | 349 | return (PAM_SUCCESS); | |
349 | 350 | |||
350 | case RAD_ACCESS_REJECT: | 351 | case RAD_ACCESS_REJECT: | |
351 | rad_close(radh); | 352 | rad_close(radh); | |
352 | PAM_VERBOSE_ERROR("Radius rejection"); | 353 | PAM_VERBOSE_ERROR("Radius rejection"); | |
353 | return (PAM_AUTH_ERR); | 354 | return (PAM_AUTH_ERR); | |
354 | 355 | |||
355 | case RAD_ACCESS_CHALLENGE: | 356 | case RAD_ACCESS_CHALLENGE: | |
356 | retval = do_challenge(pamh, radh, user); | 357 | retval = do_challenge(pamh, radh, user); | |
357 | if (retval != PAM_SUCCESS) { | 358 | if (retval != PAM_SUCCESS) { | |
358 | rad_close(radh); | 359 | rad_close(radh); | |
359 | return (retval); | 360 | return (retval); | |
360 | } | 361 | } | |
361 | break; | 362 | break; | |
362 | 363 | |||
363 | case -1: | 364 | case -1: | |
364 | logit(LOG_CRIT, "rad_send_request: %s", | 365 | logit(LOG_CRIT, "rad_send_request: %s", | |
365 | rad_strerror(radh)); | 366 | rad_strerror(radh)); | |
366 | rad_close(radh); | 367 | rad_close(radh); | |
367 | PAM_VERBOSE_ERROR("Radius failure"); | 368 | PAM_VERBOSE_ERROR("Radius failure"); | |
368 | return (PAM_AUTHINFO_UNAVAIL); | 369 | return (PAM_AUTHINFO_UNAVAIL); | |
369 | 370 | |||
370 | default: | 371 | default: | |
371 | logit(LOG_CRIT, | 372 | logit(LOG_CRIT, | |
372 | "rad_send_request: unexpected return value"); | 373 | "rad_send_request: unexpected return value"); | |
373 | rad_close(radh); | 374 | rad_close(radh); | |
374 | PAM_VERBOSE_ERROR("Radius error"); | 375 | PAM_VERBOSE_ERROR("Radius error"); | |
375 | return (PAM_SERVICE_ERR); | 376 | return (PAM_SERVICE_ERR); | |
376 | } | 377 | } | |
377 | } | 378 | } | |
378 | } | 379 | } | |
379 | 380 | |||
380 | PAM_EXTERN int | 381 | PAM_EXTERN int | |
381 | pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused, | 382 | pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused, | |
382 | int argc __unused, const char *argv[] __unused) | 383 | int argc __unused, const char *argv[] __unused) | |
383 | { | 384 | { | |
384 | 385 | |||
385 | return (PAM_SUCCESS); | 386 | return (PAM_SUCCESS); | |
386 | } | 387 | } | |
387 | 388 | |||
388 | PAM_MODULE_ENTRY("pam_radius"); | 389 | PAM_MODULE_ENTRY("pam_radius"); |