Tue Jan 7 02:07:43 2014 UTC ()
Annotate logit to provide transitive format string checks.


(joerg)
diff -r1.14 -r1.15 src/lib/libpam/modules/pam_lastlog/pam_lastlog.c
diff -r1.7 -r1.8 src/lib/libpam/modules/pam_login_access/login_access.c
diff -r1.7 -r1.8 src/lib/libpam/modules/pam_radius/pam_radius.c

cvs diff -r1.14 -r1.15 src/lib/libpam/modules/pam_lastlog/pam_lastlog.c (switch to unified diff)

--- 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>
79static void doutmp(const char *, const char *, const char *, 79static void doutmp(const char *, const char *, const char *,
80 const struct timeval *); 80 const struct timeval *);
81static void dolastlog(pam_handle_t *, int, const struct passwd *, const char *, 81static 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>
87static void doutmpx(const char *, const char *, const char *, 87static 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 *);
89static void dolastlogx(pam_handle_t *, int, const struct passwd *, const char *, 89static 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)
94static void domsg(pam_handle_t *, time_t, const char *, size_t, const char *, 94static 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)
98static void 99static void
99logit(int level, const char *fmt, ...) 100logit(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
112PAM_EXTERN int 113PAM_EXTERN int
113pam_sm_open_session(pam_handle_t *pamh, int flags, 114pam_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 }
196err: 197err:
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
202PAM_EXTERN int 203PAM_EXTERN int
203pam_sm_close_session(pam_handle_t *pamh __unused, int flags __unused, 204pam_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)
247static void 248static void
248domsg(pam_handle_t *pamh, time_t t, const char *host, size_t hsize, 249domsg(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
269static void 270static void
270doutmpx(const char *username, const char *hostname, const char *tty, 271doutmpx(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
301static void 302static void
302dolastlogx(pam_handle_t *pamh, int quiet, const struct passwd *pwd, 303dolastlogx(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
333static void 334static void
334doutmp(const char *username, const char *hostname, const char *tty, 335doutmp(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
348static void 349static void
349dolastlog(pam_handle_t *pamh, int quiet, const struct passwd *pwd, 350dolastlog(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
386PAM_MODULE_ENTRY("pam_lastlog"); 387PAM_MODULE_ENTRY("pam_lastlog");

cvs diff -r1.7 -r1.8 src/lib/libpam/modules/pam_login_access/login_access.c (switch to unified diff)

--- 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
14static char sccsid[] = "%Z% %M% %I% %E% %U%"; 14static 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
42static char fs[] = ":"; /* field separator */ 42static char fs[] = ":"; /* field separator */
43static char sep[] = ", \t"; /* list-element separator */ 43static 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
50static int from_match(const char *, const char *); 50static int from_match(const char *, const char *);
51static int list_match(char *, const char *, 51static int list_match(char *, const char *,
52 int (*)(const char *, const char *)); 52 int (*)(const char *, const char *));
53static int netgroup_match(const char *, const char *, const char *); 53static int netgroup_match(const char *, const char *, const char *);
54static int string_match(const char *, const char *); 54static int string_match(const char *, const char *);
55static int user_match(const char *, const char *); 55static 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)
59static void 60static void
60logit(int level, const char *fmt, ...) 61logit(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
72int 73int
73login_access(const char *user, const char *from) 74login_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
132static int 133static int
133list_match(char *list, const char *item, 134list_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
165static int 166static int
166netgroup_match(const char *group __unused, 167netgroup_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
175static int 176static int
176user_match(const char *tok, const char *string) 177user_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
203static int 204static int
204from_match(const char *tok, const char *string) 205from_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
238static int 239static int
239string_match(const char *tok, const char *string) 240string_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}

cvs diff -r1.7 -r1.8 src/lib/libpam/modules/pam_radius/pam_radius.c (switch to unified diff)

--- 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
72static int build_access_request(struct rad_handle *, const char *, 72static 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);
75static int do_accept(pam_handle_t *, struct rad_handle *); 75static int do_accept(pam_handle_t *, struct rad_handle *);
76static int do_challenge(pam_handle_t *, struct rad_handle *, 76static int do_challenge(pam_handle_t *, struct rad_handle *,
77 const char *); 77 const char *);
78 78
 79__printflike(2, 3)
79static void 80static void
80logit(int level, const char *fmt, ...) 81logit(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 */
96static int 97static int
97build_access_request(struct rad_handle *radh, const char *user, 98build_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
157static int 158static int
158do_accept(pam_handle_t *pamh, struct rad_handle *radh) 159do_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
184static int 185static int
185do_challenge(pam_handle_t *pamh, struct rad_handle *radh, const char *user) 186do_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
263PAM_EXTERN int 264PAM_EXTERN int
264pam_sm_authenticate(pam_handle_t *pamh, int flags __unused, 265pam_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
380PAM_EXTERN int 381PAM_EXTERN int
381pam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused, 382pam_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
388PAM_MODULE_ENTRY("pam_radius"); 389PAM_MODULE_ENTRY("pam_radius");