Deleted Added
full compact
1/*-
2 * Copyright 1998 Juniper Networks, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/lib/libpam/modules/pam_radius/pam_radius.c 41228 1998-11-18 01:44:37Z jdp $
26 * $FreeBSD: head/lib/libpam/modules/pam_radius/pam_radius.c 42917 1999-01-20 21:55:30Z jdp $
27 */
28
29#include <sys/param.h>
30#include <pwd.h>
31#include <radlib.h>
32#include <stdlib.h>
33#include <string.h>
34#include <syslog.h>
35#include <unistd.h>
36
37#define PAM_SM_AUTH
38#include <security/pam_modules.h>
39
40#include "pam_mod_misc.h"
41
42#define MAX_CHALLENGE_MSGS 10
43#define PASSWORD_PROMPT "RADIUS password:"
44
45/* Option names, including the "=" sign. */
46#define OPT_CONF "conf="
47#define OPT_TMPL "template_user="
48
49static int build_access_request(struct rad_handle *, const char *,
50 const char *, const void *, size_t);
51static int do_accept(pam_handle_t *, struct rad_handle *);
52static int do_challenge(pam_handle_t *, struct rad_handle *,
53 const char *);
54
55/*
56 * Construct an access request, but don't send it. Returns 0 on success,
57 * -1 on failure.
58 */
59static int
60build_access_request(struct rad_handle *radh, const char *user,
61 const char *pass, const void *state, size_t state_len)
62{
63 char host[MAXHOSTNAMELEN];
64
65 if (rad_create_request(radh, RAD_ACCESS_REQUEST) == -1) {
66 syslog(LOG_CRIT, "rad_create_request: %s", rad_strerror(radh));
67 return -1;
68 }
69 if ((user != NULL &&
70 rad_put_string(radh, RAD_USER_NAME, user) == -1) ||
71 (pass != NULL &&
72 rad_put_string(radh, RAD_USER_PASSWORD, pass) == -1) ||
73 (gethostname(host, sizeof host) != -1 &&
74 rad_put_string(radh, RAD_NAS_IDENTIFIER, host) == -1)) {
75 syslog(LOG_CRIT, "rad_put_string: %s", rad_strerror(radh));
76 return -1;
77 }
78 if (state != NULL && rad_put_attr(radh, RAD_STATE, state,
79 state_len) == -1) {
80 syslog(LOG_CRIT, "rad_put_attr: %s", rad_strerror(radh));
81 return -1;
82 }
83 if (rad_put_int(radh, RAD_SERVICE_TYPE, RAD_AUTHENTICATE_ONLY) == -1) {
84 syslog(LOG_CRIT, "rad_put_int: %s", rad_strerror(radh));
85 return -1;
86 }
87 return 0;
88}
89
90static int
91do_accept(pam_handle_t *pamh, struct rad_handle *radh)
92{
93 int attrtype;
94 const void *attrval;
95 size_t attrlen;
96 char *s;
97
98 while ((attrtype = rad_get_attr(radh, &attrval, &attrlen)) > 0) {
99 if (attrtype == RAD_USER_NAME) {
100 s = rad_cvt_string(attrval, attrlen);
101 if (s == NULL) {
102 syslog(LOG_CRIT,
103 "rad_cvt_string: out of memory");
104 return -1;
105 }
106 pam_set_item(pamh, PAM_USER, s);
107 free(s);
108 }
109 }
110 if (attrtype == -1) {
111 syslog(LOG_CRIT, "rad_get_attr: %s", rad_strerror(radh));
112 return -1;
113 }
114 return 0;
115}
116
117static int
118do_challenge(pam_handle_t *pamh, struct rad_handle *radh, const char *user)
119{
120 int retval;
121 int attrtype;
122 const void *attrval;
123 size_t attrlen;
124 const void *state;
125 size_t statelen;
126 struct pam_message msgs[MAX_CHALLENGE_MSGS];
127 const struct pam_message *msg_ptrs[MAX_CHALLENGE_MSGS];
128 struct pam_response *resp;
129 int num_msgs;
130 const void *item;
131 const struct pam_conv *conv;
132
133 state = NULL;
134 statelen = 0;
135 num_msgs = 0;
136 while ((attrtype = rad_get_attr(radh, &attrval, &attrlen)) > 0) {
137 switch (attrtype) {
138
139 case RAD_STATE:
140 state = attrval;
141 statelen = attrlen;
142 break;
143
144 case RAD_REPLY_MESSAGE:
145 if (num_msgs >= MAX_CHALLENGE_MSGS) {
146 syslog(LOG_CRIT,
147 "Too many RADIUS challenge messages");
148 return PAM_SERVICE_ERR;
149 }
150 msgs[num_msgs].msg = rad_cvt_string(attrval, attrlen);
151 if (msgs[num_msgs].msg == NULL) {
152 syslog(LOG_CRIT,
153 "rad_cvt_string: out of memory");
154 return PAM_SERVICE_ERR;
155 }
156 msgs[num_msgs].msg_style = PAM_TEXT_INFO;
157 msg_ptrs[num_msgs] = &msgs[num_msgs];
158 num_msgs++;
159 break;
160 }
161 }
162 if (attrtype == -1) {
163 syslog(LOG_CRIT, "rad_get_attr: %s", rad_strerror(radh));
164 return PAM_SERVICE_ERR;
165 }
166 if (num_msgs == 0) {
167 msgs[num_msgs].msg = strdup("(null RADIUS challenge): ");
168 if (msgs[num_msgs].msg == NULL) {
169 syslog(LOG_CRIT, "Out of memory");
170 return PAM_SERVICE_ERR;
171 }
172 msgs[num_msgs].msg_style = PAM_TEXT_INFO;
173 msg_ptrs[num_msgs] = &msgs[num_msgs];
174 num_msgs++;
175 }
176 msgs[num_msgs-1].msg_style = PAM_PROMPT_ECHO_ON;
177 if ((retval = pam_get_item(pamh, PAM_CONV, &item)) != PAM_SUCCESS) {
178 syslog(LOG_CRIT, "do_challenge: cannot get PAM_CONV");
179 return retval;
180 }
181 conv = (const struct pam_conv *)item;
182 if ((retval = conv->conv(num_msgs, msg_ptrs, &resp,
183 conv->appdata_ptr)) != PAM_SUCCESS)
184 return retval;
185 if (build_access_request(radh, user, resp[num_msgs-1].resp, state,
186 statelen) == -1)
187 return PAM_SERVICE_ERR;
188 memset(resp[num_msgs-1].resp, 0, strlen(resp[num_msgs-1].resp));
189 free(resp[num_msgs-1].resp);
190 free(resp);
191 while (num_msgs > 0)
192 free((void *)msgs[--num_msgs].msg);
193 return PAM_SUCCESS;
194}
195
196PAM_EXTERN int
197pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
198 const char **argv)
199{
200 struct rad_handle *radh;
201 const char *user;
202 const char *pass;
203 const char *conf_file = NULL;
204 const char *template_user = NULL;
205 int options = 0;
206 int retval;
207 int i;
208 int e;
209
210 for (i = 0; i < argc; i++) {
211 size_t len;
212
213 pam_std_option(&options, argv[i]);
214 if (strncmp(argv[i], OPT_CONF, (len = strlen(OPT_CONF))) == 0)
215 conf_file = argv[i] + len;
216 else if (strncmp(argv[i], OPT_TMPL,
217 (len = strlen(OPT_TMPL))) == 0)
218 template_user = argv[i] + len;
219 }
220 if ((retval = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS)
221 return retval;
222 if ((retval = pam_get_pass(pamh, &pass, PASSWORD_PROMPT,
223 options)) != PAM_SUCCESS)
224 return retval;
225
226 if ((radh = rad_open()) == NULL) {
227 syslog(LOG_CRIT, "rad_open failed");
228 return PAM_SERVICE_ERR;
229 }
230 if (rad_config(radh, conf_file) == -1) {
231 syslog(LOG_ALERT, "rad_config: %s", rad_strerror(radh));
232 rad_close(radh);
233 return PAM_SERVICE_ERR;
234 }
235 if (build_access_request(radh, user, pass, NULL, 0) == -1) {
236 rad_close(radh);
237 return PAM_SERVICE_ERR;
238 }
239 for ( ; ; ) {
240 switch (rad_send_request(radh)) {
241
242 case RAD_ACCESS_ACCEPT:
243 e = do_accept(pamh, radh);
244 rad_close(radh);
245 if (e == -1)
246 return PAM_SERVICE_ERR;
247 if (template_user != NULL) {
248 const void *item;
249 const char *user;
250
251 /*
252 * If the given user name doesn't exist in
253 * the local password database, change it
254 * to the value given in the "template_user"
255 * option.
256 */
257 retval = pam_get_item(pamh, PAM_USER, &item);
258 if (retval != PAM_SUCCESS)
259 return retval;
260 user = (const char *)item;
261 if (getpwnam(user) == NULL)
262 pam_set_item(pamh, PAM_USER,
263 template_user);
264 }
265 return PAM_SUCCESS;
266
267 case RAD_ACCESS_REJECT:
268 rad_close(radh);
269 return PAM_AUTH_ERR;
270
271 case RAD_ACCESS_CHALLENGE:
272 if ((retval = do_challenge(pamh, radh, user)) !=
273 PAM_SUCCESS) {
274 rad_close(radh);
275 return retval;
276 }
277 break;
278
279 case -1:
280 syslog(LOG_CRIT, "rad_send_request: %s",
281 rad_strerror(radh));
282 rad_close(radh);
283 return PAM_AUTHINFO_UNAVAIL;
284
285 default:
286 syslog(LOG_CRIT,
287 "rad_send_request: unexpected return value");
288 rad_close(radh);
289 return PAM_SERVICE_ERR;
290 }
291 }
292}
293
294PAM_EXTERN int
295pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
296{
297 return PAM_SUCCESS;
298}
299
300PAM_MODULE_ENTRY("pam_radius");