1 /*
2 * ProFTPD: mod_radius -- a module for RADIUS authentication and accounting
3 * Copyright (c) 2001-2021 TJ Saunders
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 *
19 * As a special exemption, TJ Saunders gives permission to link this program
20 * with OpenSSL, and distribute the resulting executable, without including
21 * the source code for OpenSSL in the source distribution.
22 *
23 * This is mod_radius, contrib software for proftpd 1.2 and above.
24 * For more information contact TJ Saunders <tj@castaglia.org>.
25 *
26 * This module is based in part on code in Alan DeKok's (aland@freeradius.org)
27 * mod_auth_radius for Apache, in part on the FreeRADIUS project's code.
28 */
29
30 #define MOD_RADIUS_VERSION "mod_radius/0.9.3"
31
32 #include "conf.h"
33 #include "privs.h"
34
35 /* RADIUS information */
36
37 /* From RFC2865, RFC2866 */
38 #define RADIUS_AUTH_PORT 1812
39 #define RADIUS_ACCT_PORT 1813
40
41 #define RADIUS_PASSWD_LEN 16
42 #define RADIUS_VECTOR_LEN 16
43
44 /* From RFC2138 */
45 #define RADIUS_STRING_LEN 254
46
47 /* RADIUS attribute structures */
48 typedef struct {
49 unsigned char type;
50 unsigned char length;
51 unsigned char data[1];
52 } radius_attrib_t;
53
54 /* RADIUS packet header */
55 typedef struct {
56 unsigned char code;
57 unsigned char id;
58 unsigned short length;
59 unsigned char digest[RADIUS_VECTOR_LEN];
60 unsigned char data[2];
61
62 char _pad[PR_TUNABLE_BUFFER_SIZE];
63 } radius_packet_t;
64
65 #define RADIUS_HEADER_LEN 20
66
67 /* RADIUS ID Definitions (see RFC 2865, 2866) */
68 #define RADIUS_AUTH_REQUEST 1
69 #define RADIUS_AUTH_ACCEPT 2
70 #define RADIUS_AUTH_REJECT 3
71 #define RADIUS_ACCT_REQUEST 4
72 #define RADIUS_ACCT_RESPONSE 5
73 #define RADIUS_ACCT_STATUS 6
74 #define RADIUS_AUTH_CHALLENGE 11
75
76 /* RADIUS Attribute Definitions (see RFC 2865, 2866) */
77 #define RADIUS_USER_NAME 1
78 #define RADIUS_PASSWORD 2
79 #define RADIUS_NAS_IP_ADDRESS 4
80 #define RADIUS_NAS_PORT 5
81 #define RADIUS_SERVICE_TYPE 6
82 #define RADIUS_OLD_PASSWORD 17
83 #define RADIUS_REPLY_MESSAGE 18
84 #define RADIUS_STATE 24
85 #define RADIUS_CLASS 25
86 #define RADIUS_VENDOR_SPECIFIC 26
87 #define RADIUS_SESSION_TIMEOUT 27
88 #define RADIUS_IDLE_TIMEOUT 28
89 #define RADIUS_CALLING_STATION_ID 31
90 #define RADIUS_NAS_IDENTIFIER 32
91 #define RADIUS_ACCT_STATUS_TYPE 40
92 #define RADIUS_ACCT_INPUT_OCTETS 42
93 #define RADIUS_ACCT_OUTPUT_OCTETS 43
94 #define RADIUS_ACCT_SESSION_ID 44
95 #define RADIUS_ACCT_AUTHENTIC 45
96 #define RADIUS_ACCT_SESSION_TIME 46
97 #define RADIUS_ACCT_TERMINATE_CAUSE 49
98 #define RADIUS_ACCT_EVENT_TS 55
99 #define RADIUS_NAS_PORT_TYPE 61
100 #define RADIUS_MESSAGE_AUTHENTICATOR 80
101 #define RADIUS_NAS_IPV6_ADDRESS 95
102
103 /* RADIUS service types */
104 #define RADIUS_SVC_LOGIN 1
105 #define RADIUS_SVC_AUTHENTICATE_ONLY 8
106
107 /* RADIUS status types */
108 #define RADIUS_ACCT_STATUS_START 1
109 #define RADIUS_ACCT_STATUS_STOP 2
110 #define RADIUS_ACCT_STATUS_ALIVE 3
111
112 /* RADIUS NAS port types */
113 #define RADIUS_NAS_PORT_TYPE_VIRTUAL 5
114
115 /* RADIUS authentication types */
116 #define RADIUS_AUTH_NONE 0
117 #define RADIUS_AUTH_RADIUS 1
118 #define RADIUS_AUTH_LOCAL 2
119
120 /* RADIUS Acct-Terminate-Cause types */
121 #define RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST 1
122 #define RADIUS_ACCT_TERMINATE_CAUSE_LOST_SERVICE 3
123 #define RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT 4
124 #define RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT 5
125 #define RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_RESET 6
126 #define RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT 7
127 #define RADIUS_ACCT_TERMINATE_CAUSE_SERVICE_UNAVAIL 15
128 #define RADIUS_ACCT_TERMINATE_CAUSE_USER_ERROR 16
129
130 /* The RFC says 4096 octets max, and most packets are less than 256.
131 * However, this number is just larger than the maximum MTU of just
132 * most types of networks, except maybe for gigabit ethernet.
133 */
134 #define RADIUS_PACKET_LEN 1600
135
136 /* Miscellaneous default values */
137 #define DEFAULT_RADIUS_TIMEOUT 10
138
139 #define RADIUS_ATTRIB_LEN(attr) ((attr)->length)
140
141 /* Adjust the VSA length (I'm not sure why this is necessary, but a reading
142 * of the FreeRADIUS sources show it to be. Weird.)
143 */
144 #define RADIUS_VSA_ATTRIB_LEN(attr) ((attr)->length - 2)
145
146 typedef struct radius_server_obj {
147
148 /* Next server in line */
149 struct radius_server_obj *next;
150
151 /* Memory pool for this object */
152 pool *pool;
153
154 /* RADIUS server IP address */
155 const pr_netaddr_t *addr;
156
157 /* RADIUS server port */
158 unsigned short port;
159
160 /* RADIUS server shared secret */
161 unsigned char *secret;
162 size_t secret_len;
163
164 /* How long to wait for RADIUS responses */
165 unsigned int timeout;
166
167 } radius_server_t;
168
169 module radius_module;
170
171 static pool *radius_pool = NULL;
172 static int radius_engine = FALSE;
173 static radius_server_t *radius_acct_server = NULL;
174 static radius_server_t *radius_auth_server = NULL;
175 static int radius_logfd = -1;
176
177 /* mod_radius option flags */
178 #define RADIUS_OPT_IGNORE_REPLY_MESSAGE_ATTR 0x0001
179 #define RADIUS_OPT_IGNORE_CLASS_ATTR 0x0002
180 #define RADIUS_OPT_IGNORE_SESSION_TIMEOUT_ATTR 0x0004
181 #define RADIUS_OPT_IGNORE_IDLE_TIMEOUT_ATTR 0x0008
182 #define RADIUS_OPT_REQUIRE_MAC 0x0010
183
184 static unsigned long radius_opts = 0UL;
185
186 static struct sockaddr radius_local_sock, radius_remote_sock;
187
188 /* For tracking various values not stored in the session struct */
189 static const char *radius_nas_identifier_config = NULL;
190 static char *radius_realm = NULL;
191 static time_t radius_session_start = 0;
192 static int radius_session_authtype = RADIUS_AUTH_LOCAL;
193 static unsigned char radius_auth_ok = FALSE;
194 static unsigned char radius_auth_reject = FALSE;
195
196 /* For tracking the Class attribute, for sending in accounting requests. */
197 static char *radius_acct_class = NULL;
198 static size_t radius_acct_classlen = 0;
199 static char *radius_acct_user = NULL;
200 static size_t radius_acct_userlen = 0;
201
202 /* "Fake" user/group information for RADIUS users. */
203 static unsigned char radius_have_user_info = FALSE;
204 static struct passwd radius_passwd;
205
206 static unsigned char radius_have_group_info = FALSE;
207 static char *radius_prime_group_name = NULL;
208 static unsigned int radius_addl_group_count = 0;
209 static char **radius_addl_group_names = NULL;
210 static char *radius_addl_group_names_str = NULL;
211 static gid_t *radius_addl_group_ids = NULL;
212 static char *radius_addl_group_ids_str = NULL;
213
214 /* Quota info */
215 static unsigned char radius_have_quota_info = FALSE;
216 static char *radius_quota_per_sess = NULL;
217 static char *radius_quota_limit_type = NULL;
218 static char *radius_quota_bytes_in = NULL;
219 static char *radius_quota_bytes_out = NULL;
220 static char *radius_quota_bytes_xfer = NULL;
221 static char *radius_quota_files_in = NULL;
222 static char *radius_quota_files_out = NULL;
223 static char *radius_quota_files_xfer = NULL;
224
225 /* Other info */
226 static unsigned char radius_have_other_info = FALSE;
227
228 /* Vendor information, defaults to Unix (Vendor-Id of 4) */
229 static const char *radius_vendor_name = "Unix";
230 static unsigned int radius_vendor_id = 4;
231
232 /* Custom VSA IDs that may be used for server-supplied RadiusUserInfo
233 * parameters.
234 */
235 static int radius_uid_attr_id = 0;
236 static int radius_gid_attr_id = 0;
237 static int radius_home_attr_id = 0;
238 static int radius_shell_attr_id = 0;
239
240 /* Custom VSA IDs that may be used for server-supplied RadiusGroupInfo
241 * parameters.
242 */
243 static int radius_prime_group_name_attr_id = 0;
244 static int radius_addl_group_names_attr_id = 0;
245 static int radius_addl_group_ids_attr_id = 0;
246
247 /* Custom VSA IDs that may be used for server-supplied QuotaLimitTable
248 * parameters.
249 */
250 static int radius_quota_per_sess_attr_id = 0;
251 static int radius_quota_limit_type_attr_id = 0;
252 static int radius_quota_bytes_in_attr_id = 0;
253 static int radius_quota_bytes_out_attr_id = 0;
254 static int radius_quota_bytes_xfer_attr_id = 0;
255 static int radius_quota_files_in_attr_id = 0;
256 static int radius_quota_files_out_attr_id = 0;
257 static int radius_quota_files_xfer_attr_id = 0;
258
259 /* For tracking the ID of the last accounting packet (to prevent the
260 * same ID from being reused).
261 */
262 static unsigned char radius_last_acct_pkt_id = 0;
263
264 static const char *trace_channel = "radius";
265
266 /* Convenience macros. */
267 #define RADIUS_IS_VAR(str) \
268 ((str[0] == '$') && (str[1] == '(') && (str[strlen(str)-1] == ')'))
269
270 /* Function prototypes. */
271 static radius_attrib_t *radius_add_attrib(radius_packet_t *, unsigned char,
272 const unsigned char *, size_t);
273 static void radius_add_passwd(radius_packet_t *, unsigned char,
274 const unsigned char *, unsigned char *, size_t);
275 static void radius_build_packet(radius_packet_t *, const unsigned char *,
276 const unsigned char *, unsigned char *, size_t);
277 static unsigned char radius_have_var(char *);
278 static radius_attrib_t *radius_get_attrib(radius_packet_t *, unsigned char);
279 static radius_attrib_t *radius_get_next_attrib(radius_packet_t *,
280 unsigned char, unsigned int *, radius_attrib_t *);
281 static void radius_get_rnd_digest(radius_packet_t *);
282 static radius_attrib_t *radius_get_vendor_attrib(radius_packet_t *,
283 unsigned char);
284 static void radius_set_acct_digest(radius_packet_t *, const unsigned char *,
285 size_t);
286 static void radius_set_auth_mac(radius_packet_t *, const unsigned char *,
287 size_t);
288 static radius_server_t *radius_make_server(pool *);
289 static int radius_openlog(void);
290 static int radius_open_socket(void);
291 static unsigned char radius_parse_gids_str(pool *, char *, gid_t **,
292 unsigned int *);
293 static unsigned char radius_parse_groups_str(pool *, char *, char ***,
294 unsigned int *);
295 static int radius_parse_var(char *, int *, char **);
296 static int radius_process_accept_packet(radius_packet_t *,
297 const unsigned char *, size_t);
298 static int radius_process_reject_packet(radius_packet_t *,
299 const unsigned char *, size_t);
300 static void radius_process_group_info(config_rec *);
301 static void radius_process_quota_info(config_rec *);
302 static void radius_process_user_info(config_rec *);
303 static radius_packet_t *radius_recv_packet(int, unsigned int);
304 static int radius_send_packet(int, radius_packet_t *, radius_server_t *);
305 static int radius_start_accting(void);
306 static int radius_stop_accting(void);
307 static int radius_verify_auth_mac(radius_packet_t *, const char *,
308 const unsigned char *, size_t);
309 static int radius_verify_packet(radius_packet_t *, radius_packet_t *,
310 const unsigned char *, size_t);
311 static int radius_sess_init(void);
312
313 /* Support functions
314 */
315
radius_argsep(char ** arg)316 static char *radius_argsep(char **arg) {
317 char *ret = NULL, *dst = NULL;
318 char quote_mode = 0;
319
320 if (!arg || !*arg || !**arg)
321 return NULL;
322
323 while (**arg && PR_ISSPACE(**arg)) {
324 (*arg)++;
325 }
326
327 if (!**arg)
328 return NULL;
329
330 ret = dst = *arg;
331
332 if (**arg == '\"') {
333 quote_mode++;
334 (*arg)++;
335 }
336
337 while (**arg && **arg != ',' &&
338 (quote_mode ? (**arg != '\"') : (!PR_ISSPACE(**arg)))) {
339
340 if (**arg == '\\' && quote_mode) {
341
342 /* escaped char */
343 if (*((*arg) + 1))
344 *dst = *(++(*arg));
345 }
346
347 *dst++ = **arg;
348 ++(*arg);
349 }
350
351 if (**arg)
352 (*arg)++;
353
354 *dst = '\0';
355 return ret;
356 }
357
358 /* Check a "$(attribute-id:default)" string for validity. */
radius_have_var(char * var)359 static unsigned char radius_have_var(char *var) {
360 int id = 0;
361 char *ptr = NULL;
362 size_t varlen;
363
364 varlen = strlen(var);
365
366 /* Must be at least six characters. */
367 if (varlen < 7) {
368 return FALSE;
369 }
370
371 /* Must start with '$(', and end with ')'. */
372 if (RADIUS_IS_VAR(var) == FALSE) {
373 return FALSE;
374 }
375
376 /* Must have a ':'. */
377 ptr = strchr(var, ':');
378 if (ptr == NULL) {
379 return FALSE;
380 }
381
382 /* ':' must be between '(' and ')'. */
383 if (ptr < (var + 3) ||
384 ptr > &var[varlen-2]) {
385 return FALSE;
386 }
387
388 /* Parse out the component int/string. */
389 radius_parse_var(var, &id, NULL);
390
391 /* Int must be greater than zero. */
392 if (id < 1) {
393 return FALSE;
394 }
395
396 return TRUE;
397 }
398
399 /* Separate the given "$(attribute-id:default)" string into its constituent
400 * custom attribute ID (int) and default (string) components.
401 */
radius_parse_var(char * var,int * attr_id,char ** attr_default)402 static int radius_parse_var(char *var, int *attr_id, char **attr_default) {
403 pool *tmp_pool;
404 char *var_cpy, *ptr = NULL;
405 size_t var_len, var_cpylen;
406
407 if (var == NULL) {
408 errno = EINVAL;
409 return -1;
410 }
411
412 var_len = var_cpylen = strlen(var);
413 if (var_len == 0) {
414 /* Empty string; nothing to do. */
415 return 0;
416 }
417
418 tmp_pool = make_sub_pool(radius_pool);
419 var_cpy = pstrdup(tmp_pool, var);
420
421 /* First, strip off the "$()" variable characters. */
422 var_cpy[var_cpylen-1] = '\0';
423 var_cpy += 2;
424
425 /* Find the delimiting ':' */
426 ptr = strchr(var_cpy, ':');
427 if (ptr != NULL) {
428 *ptr++ = '\0';
429 }
430
431 if (attr_id) {
432 *attr_id = atoi(var_cpy);
433 }
434
435 if (attr_default) {
436 ptr = strchr(var, ':');
437
438 /* Note: this works because the calling of this function by
439 * radius_have_var(), which occurs during the parsing process, uses
440 * a NULL for this portion, so that the string stored in the config_rec
441 * is not actually manipulated, as is done here.
442 */
443 if (var_len > 0) {
444 var[var_len-1] = '\0';
445 }
446
447 if (ptr != NULL) {
448 *attr_default = ++ptr;
449 }
450 }
451
452 /* Clean up. */
453 destroy_pool(tmp_pool);
454 return 0;
455 }
456
radius_parse_gids_str(pool * p,char * gids_str,gid_t ** gids,unsigned int * ngids)457 static unsigned char radius_parse_gids_str(pool *p, char *gids_str,
458 gid_t **gids, unsigned int *ngids) {
459 char *val = NULL;
460 array_header *group_ids = make_array(p, 0, sizeof(gid_t));
461
462 /* Add each GID to the array. */
463 while ((val = radius_argsep(&gids_str)) != NULL) {
464 gid_t gid;
465 char *endp = NULL;
466
467 pr_signals_handle();
468
469 /* Make sure the given ID is a valid number. */
470 gid = strtoul(val, &endp, 10);
471
472 if (endp && *endp) {
473 pr_log_pri(PR_LOG_NOTICE, "RadiusGroupInfo badly formed group ID: %s",
474 val);
475 return FALSE;
476 }
477
478 /* Push the ID into the ID array. */
479 *((gid_t *) push_array(group_ids)) = gid;
480 }
481
482 *gids = (gid_t *) group_ids->elts;
483 *ngids = group_ids->nelts;
484
485 return TRUE;
486 }
487
radius_parse_groups_str(pool * p,char * groups_str,char *** groups,unsigned int * ngroups)488 static unsigned char radius_parse_groups_str(pool *p, char *groups_str,
489 char ***groups, unsigned int *ngroups) {
490 char *name = NULL;
491 array_header *group_names = make_array(p, 0, sizeof(char *));
492
493 /* Add each name to the array. */
494 while ((name = radius_argsep(&groups_str)) != NULL) {
495 char *tmp;
496
497 pr_signals_handle();
498 tmp = pstrdup(p, name);
499
500 /* Push the name into the name array. */
501 *((char **) push_array(group_names)) = tmp;
502 }
503
504 *groups = (char **) group_names->elts;
505 *ngroups = group_names->nelts;
506
507 return TRUE;
508 }
509
radius_process_standard_attribs(radius_packet_t * pkt,const unsigned char * secret,size_t secret_len)510 static int radius_process_standard_attribs(radius_packet_t *pkt,
511 const unsigned char *secret, size_t secret_len) {
512 int attrib_count = 0;
513 radius_attrib_t *attrib = NULL;
514 unsigned char attrib_len;
515
516 pr_trace_msg(trace_channel, 2, "parsing packet for standard attribute IDs");
517
518 if (radius_verify_auth_mac(pkt, "Access-Accept", secret, secret_len) < 0) {
519 return -1;
520 }
521
522 /* TODO: Should we handle the Service-Type attribute here, make sure that it
523 * is a) a service type we implement, and b) the service type that we
524 * requested?
525 */
526
527 /* Handle any CLASS attribute. */
528 if (!(radius_opts & RADIUS_OPT_IGNORE_CLASS_ATTR)) {
529 attrib = radius_get_attrib(pkt, RADIUS_CLASS);
530 if (attrib != NULL) {
531 attrib_len = RADIUS_ATTRIB_LEN(attrib);
532 if (attrib_len > 0) {
533 char *class = NULL;
534
535 class = pstrndup(radius_pool, (char *) attrib->data, attrib_len);
536 pr_trace_msg(trace_channel, 7,
537 "found Class attribute in Access-Accept message: %s", class);
538 radius_acct_class = class;
539 radius_acct_classlen = attrib_len;
540 }
541
542 attrib_count++;
543
544 } else {
545 pr_trace_msg(trace_channel, 6,
546 "Access-Accept packet lacks Class attribute (%d)", RADIUS_CLASS);
547 }
548 }
549
550 /* Handle any User-Name attribute, per RFC 2865, Section 5.1. */
551 attrib = radius_get_attrib(pkt, RADIUS_USER_NAME);
552 if (attrib != NULL) {
553 attrib_len = RADIUS_ATTRIB_LEN(attrib);
554 if (attrib_len > 0) {
555 char *user_name = NULL;
556
557 user_name = pstrndup(radius_pool, (char *) attrib->data, attrib_len);
558 pr_trace_msg(trace_channel, 7,
559 "found User-Name attribute in Access-Accept message: %s", user_name);
560 radius_acct_user = user_name;
561 radius_acct_userlen = attrib_len;
562 }
563
564 attrib_count++;
565
566 } else {
567 pr_trace_msg(trace_channel, 6,
568 "Access-Accept packet lacks User-Name attribute (%d)", RADIUS_USER_NAME);
569 }
570
571 /* Handle any REPLY_MESSAGE attributes. */
572 if (!(radius_opts & RADIUS_OPT_IGNORE_REPLY_MESSAGE_ATTR)) {
573 unsigned int pkt_len = 0;
574
575 attrib = radius_get_next_attrib(pkt, RADIUS_REPLY_MESSAGE, &pkt_len, NULL);
576 while (attrib != NULL) {
577 pr_signals_handle();
578
579 attrib_len = RADIUS_ATTRIB_LEN(attrib);
580 if (attrib_len > 0) {
581 char *reply_msg = NULL;
582
583 reply_msg = pstrndup(radius_pool, (char *) attrib->data, attrib_len);
584 pr_trace_msg(trace_channel, 7,
585 "found REPLY_MESSAGE attribute in Access-Accept message: '%s'",
586 reply_msg);
587 pr_response_add(R_DUP, "%s", reply_msg);
588 }
589
590 attrib_count++;
591
592 if (pkt_len == 0) {
593 break;
594 }
595
596 attrib = radius_get_next_attrib(pkt, RADIUS_REPLY_MESSAGE, &pkt_len,
597 attrib);
598 }
599
600 if (attrib_count == 0) {
601 pr_trace_msg(trace_channel, 6,
602 "Access-Accept packet lacks Reply-Message attribute (%d)",
603 RADIUS_REPLY_MESSAGE);
604 }
605 }
606
607 /* Handle any IDLE_TIMEOUT attribute. */
608 if (!(radius_opts & RADIUS_OPT_IGNORE_IDLE_TIMEOUT_ATTR)) {
609 attrib = radius_get_attrib(pkt, RADIUS_IDLE_TIMEOUT);
610 if (attrib != NULL) {
611 attrib_len = RADIUS_ATTRIB_LEN(attrib);
612 if (attrib_len > 0) {
613 int timeout = -1;
614
615 if (attrib_len > sizeof(timeout)) {
616 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
617 "invalid attribute length (%u) for Idle-Timeout, truncating",
618 attrib_len);
619 attrib_len = sizeof(timeout);
620 }
621
622 memcpy(&timeout, attrib->data, attrib_len);
623 timeout = ntohl(timeout);
624
625 if (timeout < 0) {
626 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
627 "packet includes Idle-Timeout attribute %d for illegal timeout: %d",
628 RADIUS_IDLE_TIMEOUT, timeout);
629
630 } else {
631 config_rec *c;
632
633 pr_trace_msg(trace_channel, 2,
634 "packet includes Idle-Timeout attribute %d for timeout: %d",
635 RADIUS_IDLE_TIMEOUT, timeout);
636 remove_config(main_server->conf, "TimeoutIdle", TRUE);
637
638 c = pr_config_add_set(&main_server->conf, "TimeoutIdle",
639 PR_CONFIG_FL_INSERT_HEAD);
640 c->config_type = CONF_PARAM;
641 c->argc = 1;
642 c->argv[0] = palloc(c->pool, sizeof(int));
643 *((int *) c->argv[0]) = timeout;
644
645 attrib_count++;
646 }
647 }
648
649 } else {
650 pr_trace_msg(trace_channel, 6,
651 "Access-Accept packet lacks Idle-Timeout attribute (%d)",
652 RADIUS_IDLE_TIMEOUT);
653 }
654 }
655
656 /* Handle any SESSION_TIMEOUT attribute. */
657 if (!(radius_opts & RADIUS_OPT_IGNORE_SESSION_TIMEOUT_ATTR)) {
658 attrib = radius_get_attrib(pkt, RADIUS_SESSION_TIMEOUT);
659 if (attrib != NULL) {
660 attrib_len = RADIUS_ATTRIB_LEN(attrib);
661 if (attrib_len > 0) {
662 int timeout = -1;
663
664 if (attrib_len > sizeof(timeout)) {
665 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
666 "invalid attribute length (%u) for Session-Timeout, truncating",
667 attrib_len);
668 attrib_len = sizeof(timeout);
669 }
670
671 memcpy(&timeout, attrib->data, attrib_len);
672 timeout = ntohl(timeout);
673
674 if (timeout < 0) {
675 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
676 "packet includes Session-Timeout attribute %d for illegal "
677 "timeout: %d", RADIUS_SESSION_TIMEOUT, timeout);
678
679 } else {
680 config_rec *c;
681
682 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
683 "packet includes Session-Timeout attribute %d for timeout: %d",
684 RADIUS_SESSION_TIMEOUT, timeout);
685 remove_config(main_server->conf, "TimeoutSession", TRUE);
686
687 c = pr_config_add_set(&main_server->conf, "TimeoutSession",
688 PR_CONFIG_FL_INSERT_HEAD);
689 c->config_type = CONF_PARAM;
690 c->argc = 2;
691 c->argv[0] = palloc(c->pool, sizeof(int));
692 *((int *) c->argv[0]) = timeout;
693 c->argv[1] = palloc(c->pool, sizeof(unsigned int));
694 *((unsigned int *) c->argv[1]) = 0;
695
696 attrib_count++;
697 }
698 }
699
700 } else {
701 pr_trace_msg(trace_channel, 6,
702 "Access-Accept packet lacks Session-Timeout attribute (%d)",
703 RADIUS_SESSION_TIMEOUT);
704 }
705 }
706
707 return attrib_count;
708 }
709
radius_process_user_info_attribs(radius_packet_t * pkt)710 static int radius_process_user_info_attribs(radius_packet_t *pkt) {
711 int attrib_count = 0;
712
713 if (radius_uid_attr_id || radius_gid_attr_id ||
714 radius_home_attr_id || radius_shell_attr_id) {
715 pr_trace_msg(trace_channel, 2,
716 "parsing packet for RadiusUserInfo attributes");
717
718 /* These custom values will been supplied in the configuration file, and
719 * set when the RadiusUserInfo config_rec is retrieved, during
720 * session initialization.
721 */
722
723 if (radius_uid_attr_id) {
724 radius_attrib_t *attrib;
725
726 attrib = radius_get_vendor_attrib(pkt, radius_uid_attr_id);
727 if (attrib) {
728 unsigned char attrib_len;
729 int uid = -1;
730
731 attrib_len = RADIUS_VSA_ATTRIB_LEN(attrib);
732
733 /* Parse the attribute value into an int, then cast it into the
734 * radius_passwd.pw_uid field. Make sure it's a sane UID
735 * (ie non-negative).
736 */
737
738 if (attrib_len > sizeof(uid)) {
739 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
740 "invalid attribute length (%u) for user ID, truncating",
741 attrib_len);
742 attrib_len = sizeof(uid);
743 }
744
745 memcpy(&uid, attrib->data, attrib_len);
746 uid = ntohl(uid);
747
748 if (uid < 0) {
749 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
750 "packet includes '%s' Vendor-Specific Attribute %d for illegal "
751 "user ID: %d", radius_vendor_name, radius_uid_attr_id, uid);
752
753 } else {
754 radius_passwd.pw_uid = uid;
755
756 pr_trace_msg(trace_channel, 3,
757 "packet includes '%s' Vendor-Specific Attribute %d for user ID: %d",
758 radius_vendor_name, radius_uid_attr_id,
759 radius_passwd.pw_uid);
760 attrib_count++;
761 }
762
763 } else {
764 pr_trace_msg(trace_channel, 6,
765 "Access-Accept packet lacks '%s' Vendor-Specific Attribute %d "
766 "for user ID; defaulting to '%u'", radius_vendor_name,
767 radius_uid_attr_id, radius_passwd.pw_uid);
768 }
769 }
770
771 if (radius_gid_attr_id) {
772 radius_attrib_t *attrib;
773
774 attrib = radius_get_vendor_attrib(pkt, radius_gid_attr_id);
775 if (attrib) {
776 unsigned char attrib_len;
777 int gid = -1;
778
779 attrib_len = RADIUS_VSA_ATTRIB_LEN(attrib);
780
781 /* Parse the attribute value into an int, then cast it into the
782 * radius_passwd.pw_gid field. Make sure it's a sane GID
783 * (ie non-negative).
784 */
785
786 if (attrib_len > sizeof(gid)) {
787 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
788 "invalid attribute length (%u) for group ID, truncating",
789 attrib_len);
790 attrib_len = sizeof(gid);
791 }
792
793 memcpy(&gid, attrib->data, attrib_len);
794 gid = ntohl(gid);
795
796 if (gid < 0) {
797 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
798 "packet includes '%s' Vendor-Specific Attribute %d for illegal "
799 "group ID: %d", radius_vendor_name, radius_gid_attr_id, gid);
800
801 } else {
802 radius_passwd.pw_gid = gid;
803
804 pr_trace_msg(trace_channel, 3,
805 "packet includes '%s' Vendor-Specific Attribute %d for group "
806 "ID: %d", radius_vendor_name, radius_gid_attr_id,
807 radius_passwd.pw_gid);
808 attrib_count++;
809 }
810
811 } else {
812 pr_trace_msg(trace_channel, 6,
813 "Access-Accept packet lacks '%s' Vendor-Specific Attribute %d "
814 "for group ID; defaulting to '%u'", radius_vendor_name,
815 radius_gid_attr_id, radius_passwd.pw_gid);
816 }
817 }
818
819 if (radius_home_attr_id) {
820 radius_attrib_t *attrib;
821
822 attrib = radius_get_vendor_attrib(pkt, radius_home_attr_id);
823 if (attrib) {
824 unsigned char attrib_len;
825 char *home;
826
827 attrib_len = RADIUS_VSA_ATTRIB_LEN(attrib);
828
829 home = pstrndup(radius_pool, (char *) attrib->data, attrib_len);
830 if (*home != '/') {
831 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
832 "packet includes '%s' Vendor-Specific Attribute %d for illegal "
833 "home: '%s'", radius_vendor_name, radius_home_attr_id, home);
834
835 } else {
836 radius_passwd.pw_dir = home;
837
838 pr_trace_msg(trace_channel, 3,
839 "packet includes '%s' Vendor-Specific Attribute %d for home "
840 "directory: '%s'", radius_vendor_name, radius_home_attr_id,
841 radius_passwd.pw_dir);
842 attrib_count++;
843 }
844
845 } else {
846 pr_trace_msg(trace_channel, 6,
847 "Access-Accept packet lacks '%s' Vendor-Specific Attribute %d for "
848 "home directory; defaulting to '%s'", radius_vendor_name,
849 radius_home_attr_id, radius_passwd.pw_dir);
850 }
851 }
852
853 if (radius_shell_attr_id) {
854 radius_attrib_t *attrib;
855
856 attrib = radius_get_vendor_attrib(pkt, radius_shell_attr_id);
857 if (attrib) {
858 unsigned char attrib_len;
859 char *shell;
860
861 attrib_len = RADIUS_VSA_ATTRIB_LEN(attrib);
862
863 shell = pstrndup(radius_pool, (char *) attrib->data, attrib_len);
864 if (*shell != '/') {
865 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
866 "packet includes '%s' Vendor-Specific Attribute %d for illegal "
867 "shell: '%s'", radius_vendor_name, radius_shell_attr_id, shell);
868
869 } else {
870 radius_passwd.pw_shell = shell;
871
872 pr_trace_msg(trace_channel, 3,
873 "packet includes '%s' Vendor-Specific Attribute %d for "
874 "shell: '%s'", radius_vendor_name, radius_shell_attr_id,
875 radius_passwd.pw_shell);
876 attrib_count++;
877 }
878
879 } else {
880 pr_trace_msg(trace_channel, 6,
881 "Access-Accept packet lacks '%s' Vendor-Specific Attribute %d for "
882 "shell; defaulting to '%s'", radius_vendor_name, radius_shell_attr_id,
883 radius_passwd.pw_shell);
884 }
885 }
886 }
887
888 return attrib_count;
889 }
890
radius_process_group_info_attribs(radius_packet_t * pkt)891 static int radius_process_group_info_attribs(radius_packet_t *pkt) {
892 int attrib_count = 0;
893
894 if (radius_prime_group_name_attr_id ||
895 radius_addl_group_names_attr_id ||
896 radius_addl_group_ids_attr_id) {
897 unsigned int ngroups = 0, ngids = 0;
898 char **groups = NULL;
899 gid_t *gids = NULL;
900
901 pr_trace_msg(trace_channel, 2,
902 "parsing packet for RadiusGroupInfo attributes");
903
904 if (radius_prime_group_name_attr_id) {
905 radius_attrib_t *attrib;
906
907 attrib = radius_get_vendor_attrib(pkt, radius_prime_group_name_attr_id);
908 if (attrib) {
909 unsigned char attrib_len;
910 char *group_name;
911
912 attrib_len = RADIUS_VSA_ATTRIB_LEN(attrib);
913
914 group_name = pstrndup(radius_pool, (char *) attrib->data, attrib_len);
915 radius_prime_group_name = pstrdup(radius_pool, group_name);
916
917 pr_trace_msg(trace_channel, 3,
918 "packet includes '%s' Vendor-Specific Attribute %d for primary "
919 "group name: '%s'", radius_vendor_name,
920 radius_prime_group_name_attr_id, radius_prime_group_name);
921 attrib_count++;
922
923 } else {
924 pr_trace_msg(trace_channel, 6,
925 "Access-Accept packet lacks '%s' Vendor-Specific Attribute %d for "
926 "prime group name; defaulting to '%s'", radius_vendor_name,
927 radius_prime_group_name_attr_id, radius_prime_group_name);
928 }
929 }
930
931 if (radius_addl_group_names_attr_id) {
932 radius_attrib_t *attrib;
933
934 attrib = radius_get_vendor_attrib(pkt, radius_addl_group_names_attr_id);
935 if (attrib) {
936 unsigned char attrib_len;
937 char *group_names, *group_names_str;
938
939 attrib_len = RADIUS_VSA_ATTRIB_LEN(attrib);
940 group_names = pstrndup(radius_pool, (char *) attrib->data, attrib_len);
941
942 /* Make a copy of the string, for parsing purposes. The parsing
943 * of this string will consume it.
944 */
945 group_names_str = pstrdup(radius_pool, group_names);
946
947 if (!radius_parse_groups_str(radius_pool, group_names_str, &groups,
948 &ngroups)) {
949 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
950 "packet includes '%s' Vendor-Specific Attribute %d for illegal "
951 "additional group names: '%s'", radius_vendor_name,
952 radius_addl_group_names_attr_id, group_names);
953
954 } else {
955 pr_trace_msg(trace_channel, 3,
956 "packet includes '%s' Vendor-Specific Attribute %d for "
957 "additional group names: '%s'", radius_vendor_name,
958 radius_addl_group_names_attr_id, group_names);
959 }
960
961 attrib_count++;
962
963 } else {
964 pr_trace_msg(trace_channel, 6,
965 "Access-Accept packet lacks '%s' Vendor-Specific Attribute %d for "
966 "additional group names; defaulting to '%s'", radius_vendor_name,
967 radius_addl_group_names_attr_id, radius_addl_group_names_str);
968 }
969 }
970
971 if (radius_addl_group_ids_attr_id) {
972 radius_attrib_t *attrib;
973
974 attrib = radius_get_vendor_attrib(pkt, radius_addl_group_ids_attr_id);
975 if (attrib) {
976 unsigned char attrib_len;
977 char *group_ids, *group_ids_str;
978
979 attrib_len = RADIUS_VSA_ATTRIB_LEN(attrib);
980 group_ids = pstrndup(radius_pool, (char *) attrib->data, attrib_len);
981
982 /* Make a copy of the string, for parsing purposes. The parsing
983 * of this string will consume it.
984 */
985 group_ids_str = pstrdup(radius_pool, group_ids);
986
987 if (!radius_parse_gids_str(radius_pool, group_ids_str, &gids, &ngids)) {
988 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
989 "packet includes '%s' Vendor-Specific Attribute %d for illegal "
990 "additional group IDs: '%s'", radius_vendor_name,
991 radius_addl_group_ids_attr_id, group_ids);
992
993 } else {
994 pr_trace_msg(trace_channel, 3,
995 "packet includes '%s' Vendor-Specific Attribute %d for additional "
996 "group IDs: '%s'", radius_vendor_name,
997 radius_addl_group_ids_attr_id, group_ids);
998 }
999
1000 attrib_count++;
1001
1002 } else {
1003 pr_trace_msg(trace_channel, 6,
1004 "Access-Accept packet lacks '%s' Vendor-Specific Attribute %d for "
1005 "additional group IDs; defaulting to '%s'", radius_vendor_name,
1006 radius_addl_group_ids_attr_id, radius_addl_group_ids_str);
1007 }
1008 }
1009
1010 /* One last RadiusGroupInfo check: does the number of returned group
1011 * names match the number of returned group IDs?
1012 */
1013 if (ngroups == ngids) {
1014 radius_have_group_info = TRUE;
1015 radius_addl_group_count = ngroups;
1016 radius_addl_group_names = groups;
1017 radius_addl_group_ids = gids;
1018
1019 } else {
1020 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1021 "server provided mismatched number of group names (%u) and group "
1022 "IDs (%u), ignoring them", ngroups, ngids);
1023 }
1024 }
1025
1026 return attrib_count;
1027 }
1028
radius_process_quota_info_attribs(radius_packet_t * pkt)1029 static int radius_process_quota_info_attribs(radius_packet_t *pkt) {
1030 int attrib_count = 0;
1031
1032 if (radius_quota_per_sess_attr_id ||
1033 radius_quota_limit_type_attr_id ||
1034 radius_quota_bytes_in_attr_id ||
1035 radius_quota_bytes_out_attr_id ||
1036 radius_quota_bytes_xfer_attr_id ||
1037 radius_quota_files_in_attr_id ||
1038 radius_quota_files_out_attr_id ||
1039 radius_quota_files_xfer_attr_id) {
1040
1041 pr_trace_msg(trace_channel, 2,
1042 "parsing packet for RadiusQuotaInfo attributes");
1043
1044 if (radius_quota_per_sess_attr_id) {
1045 radius_attrib_t *attrib;
1046
1047 attrib = radius_get_vendor_attrib(pkt, radius_quota_per_sess_attr_id);
1048 if (attrib) {
1049 unsigned char attrib_len;
1050 char *per_sess;
1051
1052 attrib_len = RADIUS_VSA_ATTRIB_LEN(attrib);
1053 per_sess = pstrndup(radius_pool, (char *) attrib->data, attrib_len);
1054
1055 radius_quota_per_sess = per_sess;
1056
1057 pr_trace_msg(trace_channel, 2,
1058 "packet includes '%s' Vendor-Specific Attribute %d for quota "
1059 "per-session: '%s'", radius_vendor_name,
1060 radius_quota_per_sess_attr_id, radius_quota_per_sess);
1061 attrib_count++;
1062
1063 } else {
1064 pr_trace_msg(trace_channel, 6,
1065 "Access-Accept packet lacks '%s' Vendor-Specific Attribute %d for "
1066 "quota per-session; defaulting to '%s'", radius_vendor_name,
1067 radius_quota_per_sess_attr_id, radius_quota_per_sess);
1068 }
1069 }
1070
1071 if (radius_quota_limit_type_attr_id) {
1072 radius_attrib_t *attrib;
1073
1074 attrib = radius_get_vendor_attrib(pkt, radius_quota_limit_type_attr_id);
1075 if (attrib) {
1076 unsigned char attrib_len;
1077 char *limit_type;
1078
1079 attrib_len = RADIUS_VSA_ATTRIB_LEN(attrib);
1080 limit_type = pstrndup(radius_pool, (char *) attrib->data, attrib_len);
1081 radius_quota_limit_type = limit_type;
1082
1083 pr_trace_msg(trace_channel, 2,
1084 "packet includes '%s' Vendor-Specific Attribute %d for quota limit "
1085 "type: '%s'", radius_vendor_name, radius_quota_limit_type_attr_id,
1086 radius_quota_limit_type);
1087 attrib_count++;
1088
1089 } else {
1090 pr_trace_msg(trace_channel, 6,
1091 "Access-Accept packet lacks '%s' Vendor-Specific Attribute %d for "
1092 "quota limit type; defaulting to '%s'", radius_vendor_name,
1093 radius_quota_limit_type_attr_id, radius_quota_limit_type);
1094 }
1095 }
1096
1097 if (radius_quota_bytes_in_attr_id) {
1098 radius_attrib_t *attrib;
1099
1100 attrib = radius_get_vendor_attrib(pkt, radius_quota_bytes_in_attr_id);
1101 if (attrib) {
1102 unsigned char attrib_len;
1103 char *bytes_in;
1104
1105 attrib_len = RADIUS_VSA_ATTRIB_LEN(attrib);
1106 bytes_in = pstrndup(radius_pool, (char *) attrib->data, attrib_len);
1107 radius_quota_bytes_in = bytes_in;
1108
1109 pr_trace_msg(trace_channel, 3,
1110 "packet includes '%s' Vendor-Specific Attribute %d for quota bytes "
1111 "in available: '%s'", radius_vendor_name,
1112 radius_quota_bytes_in_attr_id, radius_quota_bytes_in);
1113 attrib_count++;
1114
1115 } else {
1116 pr_trace_msg(trace_channel, 6,
1117 "Access-Accept packet lacks '%s' Vendor-Specific Attribute %d for "
1118 "quota bytes in available; defaulting to '%s'", radius_vendor_name,
1119 radius_quota_bytes_in_attr_id, radius_quota_bytes_in);
1120 }
1121 }
1122
1123 if (radius_quota_bytes_out_attr_id) {
1124 radius_attrib_t *attrib;
1125
1126 attrib = radius_get_vendor_attrib(pkt, radius_quota_bytes_out_attr_id);
1127 if (attrib) {
1128 unsigned char attrib_len;
1129 char *bytes_out;
1130
1131 attrib_len = RADIUS_VSA_ATTRIB_LEN(attrib);
1132 bytes_out = pstrndup(radius_pool, (char *) attrib->data, attrib_len);
1133 radius_quota_bytes_out = bytes_out;
1134
1135 pr_trace_msg(trace_channel, 3,
1136 "packet includes '%s' Vendor-Specific Attribute %d for quota bytes "
1137 "out available: '%s'", radius_vendor_name,
1138 radius_quota_bytes_out_attr_id, radius_quota_bytes_out);
1139 attrib_count++;
1140
1141 } else {
1142 pr_trace_msg(trace_channel, 6,
1143 "Access-Accept packet lacks '%s' Vendor-Specific Attribute %d for "
1144 "quota bytes out available; defaulting to '%s'", radius_vendor_name,
1145 radius_quota_bytes_out_attr_id, radius_quota_bytes_out);
1146 }
1147 }
1148
1149 if (radius_quota_bytes_xfer_attr_id) {
1150 radius_attrib_t *attrib;
1151
1152 attrib = radius_get_vendor_attrib(pkt, radius_quota_bytes_xfer_attr_id);
1153 if (attrib) {
1154 unsigned char attrib_len;
1155 char *bytes_xfer;
1156
1157 attrib_len = RADIUS_VSA_ATTRIB_LEN(attrib);
1158 bytes_xfer = pstrndup(radius_pool, (char *) attrib->data, attrib_len);
1159 radius_quota_bytes_xfer = bytes_xfer;
1160
1161 pr_trace_msg(trace_channel, 3,
1162 "packet includes '%s' Vendor-Specific Attribute %d for quota bytes "
1163 "xfer available: '%s'", radius_vendor_name,
1164 radius_quota_bytes_xfer_attr_id, radius_quota_bytes_xfer);
1165 attrib_count++;
1166
1167 } else {
1168 pr_trace_msg(trace_channel, 6,
1169 "Access-Accept packet lacks '%s' Vendor-Specific Attribute %d for "
1170 "quota bytes xfer available; defaulting to '%s'", radius_vendor_name,
1171 radius_quota_bytes_xfer_attr_id, radius_quota_bytes_xfer);
1172 }
1173 }
1174
1175 if (radius_quota_files_in_attr_id) {
1176 radius_attrib_t *attrib;
1177
1178 attrib = radius_get_vendor_attrib(pkt, radius_quota_files_in_attr_id);
1179 if (attrib) {
1180 unsigned char attrib_len;
1181 char *files_in;
1182
1183 attrib_len = RADIUS_VSA_ATTRIB_LEN(attrib);
1184 files_in = pstrndup(radius_pool, (char *) attrib->data, attrib_len);
1185 radius_quota_files_in = files_in;
1186
1187 pr_trace_msg(trace_channel, 3,
1188 "packet includes '%s' Vendor-Specific Attribute %d for quota files "
1189 "in available: '%s'", radius_vendor_name,
1190 radius_quota_files_in_attr_id, radius_quota_files_in);
1191 attrib_count++;
1192
1193 } else {
1194 pr_trace_msg(trace_channel, 6,
1195 "Access-Accept packet lacks '%s' Vendor-Specific Attribute %d for "
1196 "quota files in available; defaulting to '%s'", radius_vendor_name,
1197 radius_quota_files_in_attr_id, radius_quota_files_in);
1198 }
1199 }
1200
1201 if (radius_quota_files_out_attr_id) {
1202 radius_attrib_t *attrib;
1203
1204 attrib = radius_get_vendor_attrib(pkt, radius_quota_files_out_attr_id);
1205 if (attrib) {
1206 unsigned char attrib_len;
1207 char *files_out;
1208
1209 attrib_len = RADIUS_VSA_ATTRIB_LEN(attrib);
1210 files_out = pstrndup(radius_pool, (char *) attrib->data, attrib_len);
1211 radius_quota_files_out = files_out;
1212
1213 pr_trace_msg(trace_channel, 3,
1214 "packet includes '%s' Vendor-Specific Attribute %d for quota files "
1215 "out available: '%s'", radius_vendor_name,
1216 radius_quota_files_out_attr_id, radius_quota_files_out);
1217 attrib_count++;
1218
1219 } else {
1220 pr_trace_msg(trace_channel, 6,
1221 "Access-Accept packet lacks '%s' Vendor-Specific Attribute %d for "
1222 "quota files out available; defaulting to '%s'", radius_vendor_name,
1223 radius_quota_files_out_attr_id, radius_quota_files_out);
1224 }
1225 }
1226
1227 if (radius_quota_files_xfer_attr_id) {
1228 radius_attrib_t *attrib;
1229
1230 attrib = radius_get_vendor_attrib(pkt, radius_quota_files_xfer_attr_id);
1231 if (attrib) {
1232 unsigned char attrib_len;
1233 char *files_xfer;
1234
1235 attrib_len = RADIUS_VSA_ATTRIB_LEN(attrib);
1236 files_xfer = pstrndup(radius_pool, (char *) attrib->data, attrib_len);
1237 radius_quota_files_xfer = files_xfer;
1238
1239 pr_trace_msg(trace_channel, 3,
1240 "packet includes '%s' Vendor-Specific Attribute %d for quota files "
1241 "xfer available: '%s'", radius_vendor_name,
1242 radius_quota_files_xfer_attr_id, radius_quota_files_xfer);
1243 attrib_count++;
1244
1245 } else {
1246 pr_trace_msg(trace_channel, 6,
1247 "Access-Accept packet lacks '%s' Vendor-Specific Attribute %d for "
1248 "quota files xfer available; defaulting to '%s'", radius_vendor_name,
1249 radius_quota_files_xfer_attr_id, radius_quota_files_xfer);
1250 }
1251 }
1252 }
1253
1254 return attrib_count;
1255 }
1256
radius_process_accept_packet(radius_packet_t * pkt,const unsigned char * secret,size_t secret_len)1257 static int radius_process_accept_packet(radius_packet_t *pkt,
1258 const unsigned char *secret, size_t secret_len) {
1259 int attrib_count = 0, res;;
1260
1261 res = radius_process_standard_attribs(pkt, secret, secret_len);
1262 if (res < 0) {
1263 return -1;
1264 }
1265
1266 attrib_count += res;
1267
1268 /* Now, parse the packet for any server-supplied RadiusUserInfo attributes,
1269 * if RadiusUserInfo is indeed in effect.
1270 */
1271
1272 if (radius_have_user_info == FALSE &&
1273 radius_have_group_info == FALSE &&
1274 radius_have_quota_info == FALSE) {
1275 /* Return now if there's no reason for doing extra work. */
1276 return attrib_count;
1277 }
1278
1279 attrib_count += radius_process_user_info_attribs(pkt);
1280 attrib_count += radius_process_group_info_attribs(pkt);
1281 attrib_count += radius_process_quota_info_attribs(pkt);
1282
1283 return attrib_count;
1284 }
1285
radius_process_reject_packet(radius_packet_t * pkt,const unsigned char * secret,size_t secret_len)1286 static int radius_process_reject_packet(radius_packet_t *pkt,
1287 const unsigned char *secret, size_t secret_len) {
1288 int attrib_count = 0;
1289
1290 if (radius_verify_auth_mac(pkt, "Access-Reject", secret, secret_len) < 0) {
1291 return -1;
1292 }
1293
1294 /* Handle any REPLY_MESSAGE attributes. */
1295 if (!(radius_opts & RADIUS_OPT_IGNORE_REPLY_MESSAGE_ATTR)) {
1296 radius_attrib_t *attrib = NULL;
1297 unsigned int pkt_len = 0;
1298
1299 attrib = radius_get_next_attrib(pkt, RADIUS_REPLY_MESSAGE, &pkt_len,
1300 NULL);
1301 while (attrib != NULL) {
1302 unsigned char attrib_len;
1303
1304 pr_signals_handle();
1305
1306 attrib_len = RADIUS_ATTRIB_LEN(attrib);
1307 if (attrib_len > 0) {
1308 char *reply_msg = NULL;
1309
1310 reply_msg = pstrndup(radius_pool, (char *) attrib->data, attrib_len);
1311
1312 pr_trace_msg(trace_channel, 7,
1313 "found REPLY_MESSAGE attribute in Access-Reject message: '%s'",
1314 reply_msg);
1315 pr_response_add_err(R_DUP, "%s", reply_msg);
1316 }
1317
1318 attrib_count++;
1319
1320 if (pkt_len == 0) {
1321 break;
1322 }
1323
1324 attrib = radius_get_next_attrib(pkt, RADIUS_REPLY_MESSAGE, &pkt_len,
1325 attrib);
1326 }
1327 }
1328
1329 return attrib_count;
1330 }
1331
radius_process_group_info(config_rec * c)1332 static void radius_process_group_info(config_rec *c) {
1333 char *param = NULL;
1334 unsigned char have_illegal_value = FALSE;
1335 unsigned int ngroups = 0, ngids = 0;
1336 char **groups = NULL;
1337 gid_t *gids = NULL;
1338
1339 /* Parse out any configured attribute/defaults here. The stored strings will
1340 * already have been sanitized by the configuration handler, so I don't
1341 * need to worry about that here.
1342 */
1343
1344 param = (char *) c->argv[0];
1345 if (RADIUS_IS_VAR(param) == TRUE) {
1346 radius_parse_var(param, &radius_prime_group_name_attr_id,
1347 &radius_prime_group_name);
1348
1349 } else {
1350 radius_prime_group_name = param;
1351 }
1352
1353 /* If the group name count is zero, then I know that the data will be
1354 * contained in a VSA. Otherwise, the group names have already been parsed.
1355 */
1356 if (*((unsigned int *) c->argv[1]) == 0) {
1357 param = (char *) c->argv[2];
1358
1359 radius_parse_var(param, &radius_addl_group_names_attr_id,
1360 &radius_addl_group_names_str);
1361
1362 /* Now, parse the default value provided. */
1363 if (!radius_parse_groups_str(c->pool, radius_addl_group_names_str,
1364 &groups, &ngroups)) {
1365 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1366 "badly formatted RadiusGroupInfo default additional group names");
1367 have_illegal_value = TRUE;
1368 }
1369
1370 } else {
1371 ngroups = *((unsigned int *) c->argv[1]);
1372 groups = (char **) c->argv[2];
1373 }
1374
1375 if (*((unsigned int *) c->argv[3]) == 0) {
1376 param = (char *) c->argv[4];
1377
1378 radius_parse_var(param, &radius_addl_group_ids_attr_id,
1379 &radius_addl_group_ids_str);
1380
1381 /* Similarly, parse the default value provided. */
1382 if (!radius_parse_gids_str(c->pool, radius_addl_group_ids_str,
1383 &gids, &ngids)) {
1384 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1385 "badly formatted RadiusGroupInfo default additional group IDs");
1386 have_illegal_value = TRUE;
1387 }
1388
1389 } else {
1390 ngids = *((unsigned int *) c->argv[3]);
1391 gids = (gid_t *) c->argv[4];
1392 }
1393
1394 if (!have_illegal_value &&
1395 ngroups != ngids) {
1396 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1397 "mismatched number of RadiusGroupInfo default additional group "
1398 "names (%u) and IDs (%u)", ngroups, ngids);
1399 have_illegal_value = TRUE;
1400 }
1401
1402 if (!have_illegal_value) {
1403 radius_have_group_info = TRUE;
1404 radius_addl_group_count = ngroups;
1405 radius_addl_group_names = groups;
1406 radius_addl_group_ids = gids;
1407
1408 } else {
1409 radius_have_group_info = FALSE;
1410 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1411 "error with RadiusGroupInfo parameters, ignoring them");
1412 }
1413 }
1414
radius_process_quota_info(config_rec * c)1415 static void radius_process_quota_info(config_rec *c) {
1416 char *param = NULL;
1417 unsigned char have_illegal_value = FALSE;
1418
1419 /* Parse out any configured attribute/defaults here. The stored strings will
1420 * already have been sanitized by the configuration handler, so I don't
1421 * need to worry about that here.
1422 */
1423
1424 param = (char *) c->argv[0];
1425 if (RADIUS_IS_VAR(param) == TRUE) {
1426 radius_parse_var(param, &radius_quota_per_sess_attr_id,
1427 &radius_quota_per_sess);
1428
1429 } else {
1430 radius_quota_per_sess = param;
1431
1432 if (strcasecmp(param, "false") != 0 &&
1433 strcasecmp(param, "true") != 0) {
1434 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1435 "illegal RadiusQuotaInfo per-session value: '%s'", param);
1436 have_illegal_value = TRUE;
1437
1438 } else {
1439 pr_trace_msg(trace_channel, 17,
1440 "found RadiusQuotaInfo per-session value: %s", param);
1441 }
1442 }
1443
1444 param = (char *) c->argv[1];
1445 if (RADIUS_IS_VAR(param) == TRUE) {
1446 radius_parse_var(param, &radius_quota_limit_type_attr_id,
1447 &radius_quota_limit_type);
1448
1449 } else {
1450 radius_quota_limit_type = param;
1451
1452 if (strcasecmp(param, "hard") != 0 &&
1453 strcasecmp(param, "soft") != 0) {
1454 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1455 "illegal RadiusQuotaInfo limit type value: '%s'", param);
1456 have_illegal_value = TRUE;
1457
1458 } else {
1459 pr_trace_msg(trace_channel, 17,
1460 "found RadiusQuotaInfo limit type value: %s", param);
1461 }
1462 }
1463
1464 param = (char *) c->argv[2];
1465 if (RADIUS_IS_VAR(param) == TRUE) {
1466 radius_parse_var(param, &radius_quota_bytes_in_attr_id,
1467 &radius_quota_bytes_in);
1468
1469 } else {
1470 char *endp = NULL;
1471
1472 if (strtod(param, &endp) < 0) {
1473 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1474 "illegal RadiusQuotaInfo bytes in value: negative number");
1475 have_illegal_value = TRUE;
1476 }
1477
1478 if (endp && *endp) {
1479 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1480 "illegal RadiusQuotaInfo bytes in value: '%s' not a number", param);
1481 have_illegal_value = TRUE;
1482
1483 } else {
1484 pr_trace_msg(trace_channel, 17,
1485 "found RadiusQuotaInfo bytes in value: %s", param);
1486 }
1487
1488 radius_quota_bytes_in = param;
1489 }
1490
1491 param = (char *) c->argv[3];
1492 if (RADIUS_IS_VAR(param) == TRUE) {
1493 radius_parse_var(param, &radius_quota_bytes_out_attr_id,
1494 &radius_quota_bytes_out);
1495
1496 } else {
1497 char *endp = NULL;
1498
1499 if (strtod(param, &endp) < 0) {
1500 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1501 "illegal RadiusQuotaInfo bytes out value: negative number");
1502 have_illegal_value = TRUE;
1503 }
1504
1505 if (endp && *endp) {
1506 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1507 "illegal RadiusQuotaInfo bytes out value: '%s' not a number", param);
1508 have_illegal_value = TRUE;
1509
1510 } else {
1511 pr_trace_msg(trace_channel, 17,
1512 "found RadiusQuotaInfo bytes out value: %s", param);
1513 }
1514
1515 radius_quota_bytes_out = param;
1516 }
1517
1518 param = (char *) c->argv[4];
1519 if (RADIUS_IS_VAR(param) == TRUE) {
1520 radius_parse_var(param, &radius_quota_bytes_xfer_attr_id,
1521 &radius_quota_bytes_xfer);
1522
1523 } else {
1524 char *endp = NULL;
1525
1526 if (strtod(param, &endp) < 0) {
1527 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1528 "illegal RadiusQuotaInfo bytes xfer value: negative number");
1529 have_illegal_value = TRUE;
1530 }
1531
1532 if (endp && *endp) {
1533 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1534 "illegal RadiusQuotaInfo bytes xfer value: '%s' not a number", param);
1535 have_illegal_value = TRUE;
1536
1537 } else {
1538 pr_trace_msg(trace_channel, 17,
1539 "found RadiusQuotaInfo bytes xfer value: %s", param);
1540 }
1541
1542 radius_quota_bytes_xfer = param;
1543 }
1544
1545 param = (char *) c->argv[5];
1546 if (RADIUS_IS_VAR(param) == TRUE) {
1547 radius_parse_var(param, &radius_quota_files_in_attr_id,
1548 &radius_quota_files_in);
1549
1550 } else {
1551 char *endp = NULL;
1552 unsigned long res;
1553
1554 res = strtoul(param, &endp, 10);
1555 if (endp && *endp) {
1556 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1557 "illegal RadiusQuotaInfo files in value: '%s' not a number",
1558 param);
1559 have_illegal_value = TRUE;
1560
1561 } else {
1562 pr_trace_msg(trace_channel, 17,
1563 "found RadiusQuotaInfo files in value: %lu", res);
1564 }
1565
1566 radius_quota_files_in = param;
1567 }
1568
1569 param = (char *) c->argv[6];
1570 if (RADIUS_IS_VAR(param) == TRUE) {
1571 radius_parse_var(param, &radius_quota_files_out_attr_id,
1572 &radius_quota_files_out);
1573
1574 } else {
1575 char *endp = NULL;
1576 unsigned long res;
1577
1578 res = strtoul(param, &endp, 10);
1579 if (endp && *endp) {
1580 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1581 "illegal RadiusQuotaInfo files out value: '%s' not a number", param);
1582 have_illegal_value = TRUE;
1583
1584 } else {
1585 pr_trace_msg(trace_channel, 17,
1586 "found RadiusQuotaInfo files out value: %lu", res);
1587 }
1588
1589 radius_quota_files_out = param;
1590 }
1591
1592 param = (char *) c->argv[7];
1593 if (RADIUS_IS_VAR(param) == TRUE) {
1594 radius_parse_var(param, &radius_quota_files_xfer_attr_id,
1595 &radius_quota_files_xfer);
1596
1597 } else {
1598 char *endp = NULL;
1599 unsigned long res;
1600
1601 res = strtoul(param, &endp, 10);
1602 if (endp && *endp) {
1603 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1604 "illegal RadiusQuotaInfo files xfer value: '%s' not a number", param);
1605 have_illegal_value = TRUE;
1606
1607 } else {
1608 pr_trace_msg(trace_channel, 17,
1609 "found RadiusQuotaInfo files xfer value: %lu", res);
1610 }
1611
1612 radius_quota_files_xfer = param;
1613 }
1614
1615 if (!have_illegal_value) {
1616 radius_have_quota_info = TRUE;
1617
1618 } else {
1619 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1620 "error with RadiusQuotaInfo parameters, ignoring them");
1621 }
1622 }
1623
radius_process_user_info(config_rec * c)1624 static void radius_process_user_info(config_rec *c) {
1625 char *param = NULL;
1626 unsigned char have_illegal_value = FALSE;
1627
1628 /* radius_passwd.pw_name will be filled in later, after successful
1629 * authentication. radius_passwd.pw_gecos will always be NULL, as there
1630 * is no practical need for this information.
1631 */
1632
1633 radius_passwd.pw_passwd = NULL;
1634 radius_passwd.pw_gecos = NULL;
1635
1636 /* Parse out any configured attribute/defaults here. The stored strings will
1637 * already have been sanitized by the configuration handler, so I don't
1638 * need to worry about that here.
1639 */
1640
1641 /* Process the UID string. */
1642 param = (char *) c->argv[0];
1643
1644 if (RADIUS_IS_VAR(param) == TRUE) {
1645 char *endp = NULL, *value = NULL;
1646
1647 radius_parse_var(param, &radius_uid_attr_id, &value);
1648 radius_passwd.pw_uid = (uid_t) strtoul(value, &endp, 10);
1649
1650 if (radius_passwd.pw_uid == (uid_t) -1) {
1651 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1652 "illegal RadiusUserInfo default UID value: -1 not allowed");
1653 have_illegal_value = TRUE;
1654 }
1655
1656 if (endp && *endp) {
1657 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1658 "illegal RadiusUserInfo default UID value: '%s' not a number", value);
1659 have_illegal_value = TRUE;
1660 }
1661
1662 } else {
1663
1664 char *endp = NULL;
1665 radius_passwd.pw_uid = (uid_t) strtoul(param, &endp, 10);
1666
1667 if (radius_passwd.pw_uid == (uid_t) -1) {
1668 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1669 "illegal RadiusUserInfo UID value: -1 not allowed");
1670 have_illegal_value = TRUE;
1671 }
1672
1673 if (endp && *endp) {
1674 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1675 "illegal RadiusUserInfo UID value: '%s' not a number", param);
1676 have_illegal_value = TRUE;
1677 }
1678 }
1679
1680 /* Process the GID string. */
1681 param = (char *) c->argv[1];
1682
1683 if (RADIUS_IS_VAR(param) == TRUE) {
1684 char *endp = NULL, *value = NULL;
1685
1686 radius_parse_var(param, &radius_gid_attr_id, &value);
1687 radius_passwd.pw_gid = (gid_t) strtoul(value, &endp, 10);
1688
1689 if (radius_passwd.pw_gid == (gid_t) -1) {
1690 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1691 "illegal RadiusUserInfo default GID value: -1 not allowed");
1692 have_illegal_value = TRUE;
1693 }
1694
1695 if (endp && *endp) {
1696 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1697 "illegal RadiusUserInfo default GID value: '%s' not a number", value);
1698 have_illegal_value = TRUE;
1699 }
1700
1701 } else {
1702
1703 char *endp = NULL;
1704 radius_passwd.pw_gid = (gid_t) strtoul(param, &endp, 10);
1705
1706 if (radius_passwd.pw_gid == (gid_t) -1) {
1707 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1708 "illegal RadiusUserInfo GID value: -1 not allowed");
1709 have_illegal_value = TRUE;
1710 }
1711
1712 if (endp && *endp) {
1713 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1714 "illegal RadiusUserInfo GID value: '%s' not a number", param);
1715 have_illegal_value = TRUE;
1716 }
1717 }
1718
1719 /* Parse the home directory string. */
1720 param = (char *) c->argv[2];
1721
1722 if (RADIUS_IS_VAR(param) == TRUE) {
1723 radius_parse_var(param, &radius_home_attr_id, &radius_passwd.pw_dir);
1724
1725 if (*radius_passwd.pw_dir != '/') {
1726 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1727 "illegal RadiusUserInfo default home value: '%s' not an absolute path",
1728 radius_passwd.pw_dir);
1729 have_illegal_value = TRUE;
1730 }
1731
1732 } else {
1733
1734 /* Param already checked in this case. */
1735 radius_passwd.pw_dir = param;
1736 }
1737
1738 /* Process the shell string. */
1739 param = (char *) c->argv[3];
1740
1741 if (RADIUS_IS_VAR(param) == TRUE) {
1742 radius_parse_var(param, &radius_shell_attr_id, &radius_passwd.pw_shell);
1743
1744 if (*radius_passwd.pw_shell != '/') {
1745 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1746 "illegal RadiusUserInfo default shell value: '%s' not an absolute path",
1747 radius_passwd.pw_shell);
1748 have_illegal_value = TRUE;
1749 }
1750
1751 } else {
1752
1753 /* Param already checked in this case. */
1754 radius_passwd.pw_shell = param;
1755 }
1756
1757 if (have_illegal_value == FALSE) {
1758 radius_have_user_info = TRUE;
1759
1760 } else {
1761 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
1762 "error with RadiusUserInfo parameters, ignoring them");
1763 }
1764 }
1765
radius_reset(void)1766 static void radius_reset(void) {
1767 /* Clear/reset user info */
1768 radius_have_user_info = FALSE;
1769
1770 /* Clear/reset group info */
1771 radius_have_group_info = FALSE;
1772 radius_prime_group_name = NULL;
1773 radius_addl_group_count = 0;
1774 radius_addl_group_names = NULL;
1775 radius_addl_group_names_str = NULL;
1776 radius_addl_group_ids = NULL;
1777 radius_addl_group_ids_str = NULL;
1778
1779 /* Clear/reset quota info */
1780 radius_have_quota_info = FALSE;
1781 radius_quota_per_sess = NULL;
1782 radius_quota_limit_type = NULL;
1783 radius_quota_bytes_in = NULL;
1784 radius_quota_bytes_out = NULL;
1785 radius_quota_bytes_xfer = NULL;
1786 radius_quota_files_in = NULL;
1787 radius_quota_files_out = NULL;
1788
1789 /* Clear/reset quota info */
1790 radius_have_quota_info = FALSE;
1791 radius_quota_per_sess = NULL;
1792 radius_quota_limit_type = NULL;
1793 radius_quota_bytes_in = NULL;
1794 radius_quota_bytes_out = NULL;
1795 radius_quota_bytes_xfer = NULL;
1796 radius_quota_files_in = NULL;
1797 radius_quota_files_out = NULL;
1798 radius_quota_files_xfer = NULL;
1799
1800 /* Clear/reset other info */
1801 radius_have_other_info = FALSE;
1802 }
1803
radius_xor(unsigned char * p,unsigned char * q,size_t len)1804 static unsigned char *radius_xor(unsigned char *p, unsigned char *q,
1805 size_t len) {
1806 register size_t i = 0;
1807 unsigned char *tmp = p;
1808
1809 for (i = 0; i < len; i++) {
1810 *(p++) ^= *(q++);
1811 }
1812
1813 return tmp;
1814 }
1815
1816 #if defined(PR_USE_OPENSSL)
1817 # include <openssl/err.h>
1818 # include <openssl/md5.h>
1819 # include <openssl/hmac.h>
1820
1821 #else
1822 /* Built-in MD5 */
1823
1824 /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991.
1825 * All rights reserved.
1826 *
1827 * License to copy and use this software is granted provided that it
1828 * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
1829 * Algorithm" in all material mentioning or referencing this software
1830 * or this function.
1831 *
1832 * License is also granted to make and use derivative works provided
1833 * that such works are identified as "derived from the RSA Data
1834 * Security, Inc. MD5 Message-Digest Algorithm" in all material
1835 * mentioning or referencing the derived work.
1836 *
1837 * RSA Data Security, Inc. makes no representations concerning either
1838 * the merchantability of this software or the suitability of this
1839 * software for any particular purpose. It is provided "as is"
1840 * without express or implied warranty of any kind.
1841 *
1842 * These notices must be retained in any copies of any part of this
1843 * documentation and/or software.
1844 */
1845
1846 /* MD5 context */
1847 typedef struct {
1848
1849 /* state (ABCD) */
1850 uint32_t state[4];
1851
1852 /* number of bits, module 2^64 (LSB first) */
1853 uint32_t count[2];
1854
1855 /* input buffer */
1856 unsigned char buffer[64];
1857 } MD5_CTX;
1858
1859 static void MD5_Init(MD5_CTX *);
1860 static void MD5_Update(MD5_CTX *, unsigned char *, size_t);
1861 static void MD5_Final(unsigned char *, MD5_CTX *);
1862
1863 /* Note: these MD5 routines are taken from RFC 1321 */
1864
1865 #ifdef HAVE_MEMCPY
1866 # define MD5_memcpy(a, b, c) memcpy((a), (b), (c))
1867 # define MD5_memset(a, b, c) memset((a), (b), (c))
1868 #endif
1869
1870 /* Constants for MD5Transform routine.
1871 */
1872
1873 #define S11 7
1874 #define S12 12
1875 #define S13 17
1876 #define S14 22
1877 #define S21 5
1878 #define S22 9
1879 #define S23 14
1880 #define S24 20
1881 #define S31 4
1882 #define S32 11
1883 #define S33 16
1884 #define S34 23
1885 #define S41 6
1886 #define S42 10
1887 #define S43 15
1888 #define S44 21
1889
1890 static void MD5Transform(uint32_t *, unsigned char[64]);
1891 static void Encode(unsigned char *, uint32_t *, unsigned int);
1892 static void Decode(uint32_t *, unsigned char *, unsigned int);
1893
1894 #ifndef HAVE_MEMCPY
1895 static void MD5_memcpy(unsigned char *, unsigned char *, unsigned int);
1896 static void MD5_memset(unsigned char *, int, unsigned int);
1897 #endif
1898
1899 static unsigned char PADDING[64] = {
1900 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1901 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1902 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1903 };
1904
1905 /* F, G, H and I are basic MD5 functions.
1906 */
1907 #define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
1908 #define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
1909 #define H(x, y, z) ((x) ^ (y) ^ (z))
1910 #define I(x, y, z) ((y) ^ ((x) | (~z)))
1911
1912 /* ROTATE_LEFT rotates x left n bits.
1913 */
1914 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
1915
1916 /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
1917 * Rotation is separate from addition to prevent recomputation.
1918 */
1919 #define FF(a, b, c, d, x, s, ac) { \
1920 (a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); \
1921 (a) = ROTATE_LEFT ((a), (s)); \
1922 (a) += (b); \
1923 }
1924 #define GG(a, b, c, d, x, s, ac) { \
1925 (a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); \
1926 (a) = ROTATE_LEFT ((a), (s)); \
1927 (a) += (b); \
1928 }
1929 #define HH(a, b, c, d, x, s, ac) { \
1930 (a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); \
1931 (a) = ROTATE_LEFT ((a), (s)); \
1932 (a) += (b); \
1933 }
1934 #define II(a, b, c, d, x, s, ac) { \
1935 (a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); \
1936 (a) = ROTATE_LEFT ((a), (s)); \
1937 (a) += (b); \
1938 }
1939
1940 /* MD5 initialization. Begins an MD5 operation, writing a new context.
1941 */
MD5_Init(MD5_CTX * context)1942 static void MD5_Init(MD5_CTX *context) {
1943 context->count[0] = context->count[1] = 0;
1944
1945 /* Load magic initialization constants.
1946 */
1947 context->state[0] = 0x67452301;
1948 context->state[1] = 0xefcdab89;
1949 context->state[2] = 0x98badcfe;
1950 context->state[3] = 0x10325476;
1951 }
1952
1953 /* MD5 block update operation. Continues an MD5 message-digest
1954 * operation, processing another message block, and updating the
1955 * context.
1956 */
MD5_Update(MD5_CTX * context,unsigned char * input,size_t inputLen)1957 static void MD5_Update(MD5_CTX *context, unsigned char *input,
1958 size_t inputLen) {
1959 unsigned int i, index, partLen;
1960
1961 /* Compute number of bytes mod 64 */
1962 index = (unsigned int)((context->count[0] >> 3) & 0x3F);
1963
1964 /* Update number of bits */
1965 if ((context->count[0] += ((uint32_t)inputLen << 3))
1966 < ((uint32_t)inputLen << 3))
1967 context->count[1]++;
1968 context->count[1] += ((uint32_t)inputLen >> 29);
1969
1970 partLen = 64 - index;
1971
1972 /* Transform as many times as possible */
1973 if (inputLen >= partLen) {
1974 MD5_memcpy((unsigned char *) &context->buffer[index],
1975 (unsigned char *) input, partLen);
1976 MD5Transform(context->state, context->buffer);
1977
1978 for (i = partLen; i + 63 < inputLen; i += 64)
1979 MD5Transform(context->state, &input[i]);
1980
1981 index = 0;
1982
1983 } else
1984 i = 0;
1985
1986 /* Buffer remaining input */
1987 MD5_memcpy((unsigned char *) &context->buffer[index],
1988 (unsigned char *) &input[i], inputLen-i);
1989 }
1990
1991 /* MD5 finalization. Ends an MD5 message-digest operation, writing the
1992 * the message digest and zeroizing the context.
1993 */
MD5_Final(unsigned char digest[16],MD5_CTX * context)1994 static void MD5_Final(unsigned char digest[16], MD5_CTX *context) {
1995 unsigned char bits[8];
1996 unsigned int index;
1997 size_t padLen;
1998
1999 /* Save number of bits */
2000 Encode (bits, context->count, 8);
2001
2002 /* Pad out to 56 mod 64.
2003 */
2004 index = (unsigned int) ((context->count[0] >> 3) & 0x3f);
2005 padLen = (index < 56) ? (56 - index) : (120 - index);
2006 MD5_Update(context, PADDING, padLen);
2007
2008 /* Append length (before padding) */
2009 MD5_Update(context, bits, 8);
2010
2011 /* Store state in digest */
2012 Encode(digest, context->state, 16);
2013
2014 /* Zeroize sensitive information.
2015 */
2016 MD5_memset((unsigned char *) context, 0, sizeof(*context));
2017 }
2018
2019 /* MD5 basic transformation. Transforms state based on block.
2020 */
MD5Transform(uint32_t state[4],unsigned char block[64])2021 static void MD5Transform(uint32_t state[4], unsigned char block[64]) {
2022 uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
2023
2024 Decode(x, block, 64);
2025
2026 /* Round 1 */
2027 FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
2028 FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
2029 FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
2030 FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
2031 FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
2032 FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
2033 FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
2034 FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
2035 FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
2036 FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
2037 FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
2038 FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
2039 FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
2040 FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
2041 FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
2042 FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
2043
2044 /* Round 2 */
2045 GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
2046 GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
2047 GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
2048 GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
2049 GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
2050 GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
2051 GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
2052 GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
2053 GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
2054 GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
2055 GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
2056
2057 GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
2058 GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
2059 GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
2060 GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
2061 GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
2062
2063 /* Round 3 */
2064 HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
2065 HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
2066 HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
2067 HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
2068 HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
2069 HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
2070 HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
2071 HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
2072 HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
2073 HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
2074 HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
2075 HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
2076 HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
2077 HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
2078 HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
2079 HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
2080
2081 /* Round 4 */
2082 II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
2083 II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
2084 II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
2085 II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
2086 II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
2087 II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
2088 II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
2089 II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
2090 II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
2091 II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
2092 II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
2093 II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
2094 II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
2095 II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
2096 II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
2097 II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
2098
2099 state[0] += a;
2100 state[1] += b;
2101 state[2] += c;
2102 state[3] += d;
2103
2104 /* Zeroize sensitive information.
2105 */
2106 MD5_memset((unsigned char *) x, 0, sizeof(x));
2107 }
2108
2109 /* Encodes input (unsigned long) into output (unsigned char). Assumes len is
2110 * a multiple of 4.
2111 */
Encode(unsigned char * output,uint32_t * input,unsigned int len)2112 static void Encode(unsigned char *output, uint32_t *input, unsigned int len) {
2113 unsigned int i, j;
2114
2115 for (i = 0, j = 0; j < len; i++, j += 4) {
2116 output[j] = (unsigned char)(input[i] & 0xff);
2117 output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
2118 output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
2119 output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
2120 }
2121 }
2122
2123 /* Decodes input (unsigned char) into output (unsigned long). Assumes len is
2124 * a multiple of 4.
2125 */
Decode(uint32_t * output,unsigned char * input,unsigned int len)2126 static void Decode(uint32_t *output, unsigned char *input, unsigned int len) {
2127 unsigned int i, j;
2128
2129 for (i = 0, j = 0; j < len; i++, j += 4)
2130 output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j+1]) << 8) |
2131 (((uint32_t)input[j+2]) << 16) | (((uint32_t)input[j+3]) << 24);
2132 }
2133
2134 #ifndef HAVE_MEMCPY
2135 /* Note: Replace "for loop" with standard memcpy if possible. */
MD5_memcpy(unsigned char * output,unsigned char * input,unsigned int len)2136 static void MD5_memcpy(unsigned char *output, unsigned char *input,
2137 unsigned int len) {
2138 unsigned int i;
2139
2140 for (i = 0; i < len; i++) {
2141 output[i] = input[i];
2142 }
2143 }
2144
2145 /* Note: Replace "for loop" with standard memset if possible. */
MD5_memset(unsigned char * output,int value,unsigned int len)2146 static void MD5_memset(unsigned char *output, int value, unsigned int len) {
2147 unsigned int i;
2148
2149 for (i = 0; i < len; i++) {
2150 ((char *) output)[i] = (char) value;
2151 }
2152 }
2153 #endif
2154 #endif /* !PR_USE_OPENSSL */
2155
radius_openlog(void)2156 static int radius_openlog(void) {
2157 int res = 0, xerrno = 0;
2158 config_rec *c;
2159 const char *path;
2160
2161 c = find_config(main_server->conf, CONF_PARAM, "RadiusLog", FALSE);
2162 if (c == NULL) {
2163 return 0;
2164 }
2165
2166 path = c->argv[0];
2167 if (strcasecmp(path, "none") == 0) {
2168 return 0;
2169 }
2170
2171 pr_signals_block();
2172 PRIVS_ROOT
2173 res = pr_log_openfile(path, &radius_logfd, PR_LOG_SYSTEM_MODE);
2174 xerrno = errno;
2175 PRIVS_RELINQUISH
2176 pr_signals_unblock();
2177
2178 errno = xerrno;
2179 return res;
2180 }
2181
2182 /* RADIUS routines */
2183
2184 /* Add an attribute to a RADIUS packet. Returns the added attribute. */
radius_add_attrib(radius_packet_t * packet,unsigned char type,const unsigned char * data,size_t datalen)2185 static radius_attrib_t *radius_add_attrib(radius_packet_t *packet,
2186 unsigned char type, const unsigned char *data, size_t datalen) {
2187 radius_attrib_t *attrib = NULL;
2188
2189 attrib = (radius_attrib_t *) ((unsigned char *) packet +
2190 ntohs(packet->length));
2191 attrib->type = type;
2192
2193 /* Total size of the attribute. The "+ 2" takes into account the size
2194 * of the attribute identifier.
2195 */
2196 attrib->length = datalen + 2;
2197
2198 /* Increment the size of the given packet. */
2199 packet->length = htons(ntohs(packet->length) + attrib->length);
2200
2201 memcpy(attrib->data, data, datalen);
2202
2203 return attrib;
2204 }
2205
2206 /* Add a RADIUS message authenticator attribute to the packet. */
radius_set_auth_mac(radius_packet_t * pkt,const unsigned char * secret,size_t secret_len)2207 static void radius_set_auth_mac(radius_packet_t *pkt,
2208 const unsigned char *secret, size_t secret_len) {
2209 #ifdef PR_USE_OPENSSL
2210 const EVP_MD *md;
2211 unsigned char digest[EVP_MAX_MD_SIZE];
2212 unsigned int digest_len = 0, mac_len = 16;
2213 radius_attrib_t *attrib = NULL;
2214
2215 /* First, add the Message-Authenticator attribute, with a value of all zeroes,
2216 * per RFC 3579, Section 3.2.
2217 */
2218 memset(digest, '\0', sizeof(digest));
2219 attrib = radius_add_attrib(pkt, RADIUS_MESSAGE_AUTHENTICATOR,
2220 (const unsigned char *) digest, mac_len);
2221
2222 /* Now, calculate the HMAC-MD5 of the packet. */
2223
2224 md = EVP_md5();
2225 if (HMAC(md, secret, secret_len, (unsigned char *) pkt, ntohs(pkt->length),
2226 digest, &digest_len) == NULL) {
2227 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
2228 "error generating Message-Authenticator: %s",
2229 ERR_error_string(ERR_get_error(), NULL));
2230
2231 } else {
2232 /* Finally, overwrite the all-zeroes Message-Authenticator value with our
2233 * calculated value.
2234 */
2235 memcpy(attrib->data, digest, mac_len);
2236 }
2237 #endif /* PR_USE_OPENSSL */
2238 }
2239
radius_verify_auth_mac(radius_packet_t * pkt,const char * pkt_type,const unsigned char * secret,size_t secret_len)2240 static int radius_verify_auth_mac(radius_packet_t *pkt, const char *pkt_type,
2241 const unsigned char *secret, size_t secret_len) {
2242 int res = 0;
2243 radius_attrib_t *attrib = NULL;
2244
2245 /* Handle any Message-Authenticator attribute, per RFC 2869, Section 5.14. */
2246 attrib = radius_get_attrib(pkt, RADIUS_MESSAGE_AUTHENTICATOR);
2247 if (attrib != NULL) {
2248 unsigned char attrib_len;
2249 unsigned int expected_len = 16;
2250
2251 attrib_len = RADIUS_ATTRIB_LEN(attrib);
2252 if (attrib_len != expected_len) {
2253 #ifdef PR_USE_OPENSSL
2254 const EVP_MD *md;
2255 unsigned char digest[EVP_MAX_MD_SIZE], replied[EVP_MAX_MD_SIZE];
2256 unsigned int digest_len = 0;
2257
2258 /* First, make a copy of the packet's Message-Authenticator value, for
2259 * comparison with what we will calculate.
2260 */
2261 memset(replied, '\0', sizeof(replied));
2262 memcpy(replied, attrib->data, attrib_len);
2263
2264 /* Next, zero out the value so that we can calculate it ourselves. */
2265 memset(attrib->data, '\0', attrib_len);
2266
2267 memset(digest, '\0', sizeof(digest));
2268 md = EVP_md5();
2269 if (HMAC(md, secret, secret_len, (unsigned char *) pkt,
2270 ntohs(pkt->length), digest, &digest_len) == NULL) {
2271 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
2272 "error generating Message-Authenticator: %s",
2273 ERR_error_string(ERR_get_error(), NULL));
2274 return 0;
2275 }
2276
2277 if (memcmp(replied, digest, expected_len) != 0) {
2278 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
2279 "packet Message-Authenticator verification failed: mismatched MACs");
2280 errno = EINVAL;
2281 return -1;
2282 }
2283
2284 res = 0;
2285
2286 #endif /* PR_USE_OPENSSL */
2287 } else {
2288 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
2289 "%s packet has incorrect Message-Authenticator attribute length "
2290 "(%u != %u), rejecting", pkt_type, attrib_len, expected_len);
2291 errno = EINVAL;
2292 return -1;
2293 }
2294
2295 } else {
2296 pr_trace_msg(trace_channel, 6,
2297 "%s packet lacks Message-Authenticator attribute (%d)", pkt_type,
2298 RADIUS_MESSAGE_AUTHENTICATOR);
2299
2300 if (radius_opts & RADIUS_OPT_REQUIRE_MAC) {
2301 errno = EPERM;
2302 return -1;
2303 }
2304 }
2305
2306 return res;
2307 }
2308
2309 /* Add a RADIUS password attribute to the packet. */
radius_add_passwd(radius_packet_t * packet,unsigned char type,const unsigned char * passwd,unsigned char * secret,size_t secret_len)2310 static void radius_add_passwd(radius_packet_t *packet, unsigned char type,
2311 const unsigned char *passwd, unsigned char *secret, size_t secret_len) {
2312 MD5_CTX ctx, secret_ctx;
2313 radius_attrib_t *attrib = NULL;
2314 unsigned char calculated[RADIUS_VECTOR_LEN];
2315 unsigned char pwhash[PR_TUNABLE_BUFFER_SIZE];
2316 unsigned char *digest = NULL;
2317 register unsigned int i = 0;
2318 size_t pwlen;
2319
2320 pwlen = strlen((const char *) passwd);
2321
2322 /* Clear the buffers. */
2323 memset(pwhash, '\0', sizeof(pwhash));
2324
2325 if (pwlen == 0) {
2326 pwlen = RADIUS_PASSWD_LEN;
2327
2328 } else if ((pwlen & (RADIUS_PASSWD_LEN - 1)) != 0) {
2329 /* pwlen is not a multiple of RADIUS_PASSWD_LEN, need to prepare a proper
2330 * buffer.
2331 */
2332 memcpy(pwhash, passwd, pwlen);
2333
2334 /* Round up the length. */
2335 pwlen += (RADIUS_PASSWD_LEN - 1);
2336
2337 /* Truncate the length, as necessary. */
2338 pwlen &= ~(RADIUS_PASSWD_LEN - 1);
2339
2340 } else {
2341 /* pwlen is a multiple of RADIUS_PASSWD_LEN, we can just use it. */
2342 memcpy(pwhash, passwd, pwlen);
2343 }
2344
2345 /* Find the password attribute. */
2346 attrib = radius_get_attrib(packet, RADIUS_PASSWORD);
2347
2348 if (type == RADIUS_PASSWORD) {
2349 digest = packet->digest;
2350
2351 } else {
2352 digest = attrib->data;
2353 }
2354
2355 /* Encrypt the password. Password: c[0] = p[0] ^ MD5(secret + digest) */
2356 MD5_Init(&secret_ctx);
2357 MD5_Update(&secret_ctx, secret, secret_len);
2358
2359 /* Save this hash for later. */
2360 ctx = secret_ctx;
2361
2362 MD5_Update(&ctx, digest, RADIUS_VECTOR_LEN);
2363
2364 /* Set the calculated digest. */
2365 MD5_Final(calculated, &ctx);
2366
2367 /* XOR the results. */
2368 radius_xor(pwhash, calculated, RADIUS_PASSWD_LEN);
2369
2370 /* For each step through: e[i] = p[i] ^ MD5(secret + e[i-1]) */
2371 for (i = 1; i < (pwlen >> 4); i++) {
2372
2373 /* Start with the old value of the MD5 sum. */
2374 ctx = secret_ctx;
2375
2376 MD5_Update(&ctx, &pwhash[(i-1) * RADIUS_PASSWD_LEN], RADIUS_PASSWD_LEN);
2377
2378 /* Set the calculated digest. */
2379 MD5_Final(calculated, &ctx);
2380
2381 /* XOR the results. */
2382 radius_xor(&pwhash[i * RADIUS_PASSWD_LEN], calculated, RADIUS_PASSWD_LEN);
2383 }
2384
2385 if (type == RADIUS_OLD_PASSWORD) {
2386 attrib = radius_get_attrib(packet, RADIUS_OLD_PASSWORD);
2387 }
2388
2389 if (attrib == NULL) {
2390 radius_add_attrib(packet, type, pwhash, pwlen);
2391
2392 } else {
2393 /* Overwrite the packet data. */
2394 memcpy(attrib->data, pwhash, pwlen);
2395 }
2396
2397 pr_memscrub(pwhash, sizeof(pwhash));
2398 }
2399
radius_set_acct_digest(radius_packet_t * packet,const unsigned char * secret,size_t secret_len)2400 static void radius_set_acct_digest(radius_packet_t *packet,
2401 const unsigned char *secret, size_t secret_len) {
2402 MD5_CTX ctx;
2403
2404 /* Clear the current digest (not needed yet for accounting packets) */
2405 memset(packet->digest, 0, RADIUS_VECTOR_LEN);
2406
2407 MD5_Init(&ctx);
2408
2409 /* Add the packet data to the mix. */
2410 MD5_Update(&ctx, (unsigned char *) packet, ntohs(packet->length));
2411
2412 /* Add the secret to the mix. */
2413 MD5_Update(&ctx, secret, secret_len);
2414
2415 /* Set the calculated digest in place in the packet. */
2416 MD5_Final(packet->digest, &ctx);
2417 }
2418
2419 /* Obtain a random digest. */
radius_get_rnd_digest(radius_packet_t * packet)2420 static void radius_get_rnd_digest(radius_packet_t *packet) {
2421 MD5_CTX ctx;
2422 struct timeval tv;
2423 struct timezone tz;
2424
2425 /* Use the time of day with the best resolution the system can give us,
2426 * often close to microsecond accuracy.
2427 */
2428 gettimeofday(&tv, &tz);
2429
2430 /* Add in some (possibly) hard to guess information. */
2431 tv.tv_sec ^= (long) (getpid() * getppid());
2432
2433 /* Use MD5 to obtain (hopefully) cryptographically strong pseudo-random
2434 * numbers
2435 */
2436 MD5_Init(&ctx);
2437 MD5_Update(&ctx, (unsigned char *) &tv, sizeof(tv));
2438 MD5_Update(&ctx, (unsigned char *) &tz, sizeof(tz));
2439
2440 /* Set the calculated digest in the space provided. */
2441 MD5_Final(packet->digest, &ctx);
2442 }
2443
2444 /* RADIUS packet manipulation functions.
2445 */
2446
2447 /* For iterating through all of the attributes in a packet, callers can
2448 * provide a pointer to the previous attribute returned, or NULL.
2449 */
radius_get_next_attrib(radius_packet_t * packet,unsigned char attrib_type,unsigned int * packet_len,radius_attrib_t * prev_attrib)2450 static radius_attrib_t *radius_get_next_attrib(radius_packet_t *packet,
2451 unsigned char attrib_type, unsigned int *packet_len,
2452 radius_attrib_t *prev_attrib) {
2453 radius_attrib_t *attrib = NULL;
2454 unsigned int len;
2455
2456 if (packet_len == NULL) {
2457 len = ntohs(packet->length) - RADIUS_HEADER_LEN;
2458
2459 } else {
2460 len = *packet_len;
2461 }
2462
2463 if (prev_attrib == NULL) {
2464 attrib = (radius_attrib_t *) &packet->data;
2465
2466 } else {
2467 attrib = prev_attrib;
2468 }
2469
2470 while (attrib->type != attrib_type) {
2471 if (attrib->length == 0 ||
2472 (len -= attrib->length) <= 0) {
2473
2474 /* Requested attribute not found. */
2475 if (packet_len != NULL) {
2476 *packet_len = 0;
2477 }
2478
2479 return NULL;
2480 }
2481
2482 /* Examine the next attribute in the packet. */
2483 attrib = (radius_attrib_t *) ((char *) attrib + attrib->length);
2484 }
2485
2486 if (packet_len != NULL) {
2487 *packet_len = len;
2488 }
2489
2490 return attrib;
2491 }
2492
radius_get_attrib(radius_packet_t * packet,unsigned char attrib_type)2493 static radius_attrib_t *radius_get_attrib(radius_packet_t *packet,
2494 unsigned char attrib_type) {
2495 return radius_get_next_attrib(packet, attrib_type, NULL, NULL);
2496 }
2497
2498 /* Find a Vendor-Specific Attribute (VSA) in a RADIUS packet. Note that
2499 * the packet length is always kept in network byte order.
2500 */
radius_get_vendor_attrib(radius_packet_t * packet,unsigned char type)2501 static radius_attrib_t *radius_get_vendor_attrib(radius_packet_t *packet,
2502 unsigned char type) {
2503 radius_attrib_t *attrib = (radius_attrib_t *) &packet->data;
2504 int len = ntohs(packet->length) - RADIUS_HEADER_LEN;
2505
2506 while (attrib) {
2507 unsigned int vendor_id = 0;
2508
2509 pr_signals_handle();
2510
2511 if (attrib->length == 0) {
2512 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
2513 "packet includes invalid length (%u) for attribute type %u, rejecting",
2514 attrib->length, attrib->type);
2515 return NULL;
2516 }
2517
2518 if (attrib->type != RADIUS_VENDOR_SPECIFIC) {
2519 len -= attrib->length;
2520 attrib = (radius_attrib_t *) ((char *) attrib + attrib->length);
2521 continue;
2522 }
2523
2524 /* The first four octets (bytes) of data will contain the Vendor-Id. */
2525 if (attrib->length >= 4) {
2526 memcpy(&vendor_id, attrib->data, 4);
2527 vendor_id = ntohl(vendor_id);
2528 }
2529
2530 if (vendor_id != radius_vendor_id) {
2531 len -= attrib->length;
2532 attrib = (radius_attrib_t *) ((char *) attrib + attrib->length);
2533 continue;
2534 }
2535
2536 /* Parse the data value for this attribute into a VSA structure. */
2537 if (attrib->length > 4) {
2538 radius_attrib_t *vsa = NULL;
2539
2540 vsa = (radius_attrib_t *) ((char *) attrib->data + sizeof(int));
2541
2542 /* Does this VSA have the type requested? */
2543 if (vsa->type != type) {
2544 len -= attrib->length;
2545 attrib = (radius_attrib_t *) ((char *) attrib + attrib->length);
2546 continue;
2547 }
2548
2549 return vsa;
2550 }
2551 }
2552
2553 return NULL;
2554 }
2555
2556 /* Build a RADIUS packet, initializing some of the header and adding
2557 * common attributes.
2558 */
radius_build_packet(radius_packet_t * packet,const unsigned char * user,const unsigned char * passwd,unsigned char * secret,size_t secret_len)2559 static void radius_build_packet(radius_packet_t *packet,
2560 const unsigned char *user, const unsigned char *passwd,
2561 unsigned char *secret, size_t secret_len) {
2562 unsigned int nas_port_type = htonl(RADIUS_NAS_PORT_TYPE_VIRTUAL);
2563 int nas_port = htonl(main_server->ServerPort);
2564 char *caller_id = NULL;
2565 const char *nas_identifier = NULL;
2566 size_t userlen;
2567
2568 /* Set the packet length. */
2569 packet->length = htons(RADIUS_HEADER_LEN);
2570
2571 /* Obtain a random digest. */
2572 radius_get_rnd_digest(packet);
2573
2574 /* Set the ID for the packet. */
2575 packet->id = packet->digest[0];
2576
2577 /* Add the user attribute. */
2578 userlen = strlen((const char *) user);
2579 radius_add_attrib(packet, RADIUS_USER_NAME, user, userlen);
2580
2581 /* Add the password attribute, if given. */
2582 if (passwd) {
2583 radius_add_passwd(packet, RADIUS_PASSWORD, passwd, secret, secret_len);
2584
2585 } else if (packet->code != RADIUS_ACCT_REQUEST) {
2586 /* Add a NULL password if necessary. */
2587 radius_add_passwd(packet, RADIUS_PASSWORD, (const unsigned char *) "",
2588 secret, 1);
2589 }
2590
2591 /* Add a NAS identifier attribute of the service name, e.g. 'ftp'. */
2592
2593 nas_identifier = pr_session_get_protocol(0);
2594 if (radius_nas_identifier_config != NULL) {
2595 nas_identifier = radius_nas_identifier_config;
2596 }
2597
2598 radius_add_attrib(packet, RADIUS_NAS_IDENTIFIER,
2599 (const unsigned char *) nas_identifier,
2600 strlen((const char *) nas_identifier));
2601
2602 #ifdef PR_USE_IPV6
2603 if (pr_netaddr_use_ipv6()) {
2604 const pr_netaddr_t *local_addr;
2605 int family;
2606
2607 local_addr = pr_netaddr_get_sess_local_addr();
2608 family = pr_netaddr_get_family(local_addr);
2609
2610 switch (family) {
2611 case AF_INET: {
2612 struct in_addr *inaddr;
2613
2614 inaddr = pr_netaddr_get_inaddr(local_addr);
2615
2616 /* Add a NAS-IP-Address attribute. */
2617 radius_add_attrib(packet, RADIUS_NAS_IP_ADDRESS,
2618 (unsigned char *) &(inaddr->s_addr), sizeof(inaddr->s_addr));
2619 break;
2620 }
2621
2622 case AF_INET6: {
2623 if (pr_netaddr_is_v4mappedv6(local_addr)) {
2624 pr_netaddr_t *v4_addr;
2625
2626 /* Note: in the future, switch to using a per-packet pool. */
2627 v4_addr = pr_netaddr_v6tov4(radius_pool, local_addr);
2628 if (v4_addr != NULL) {
2629 struct in_addr *inaddr;
2630
2631 inaddr = pr_netaddr_get_inaddr(v4_addr);
2632
2633 /* Add a NAS-IP-Address attribute. */
2634 radius_add_attrib(packet, RADIUS_NAS_IP_ADDRESS,
2635 (unsigned char *) &(inaddr->s_addr), sizeof(inaddr->s_addr));
2636
2637 } else {
2638 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
2639 "error converting '%s' to IPv4 address: %s",
2640 pr_netaddr_get_ipstr(local_addr), strerror(errno));
2641 }
2642
2643 } else {
2644 struct in6_addr *inaddr;
2645 uint32_t ipv6_addr[4];
2646
2647 inaddr = pr_netaddr_get_inaddr(pr_netaddr_get_sess_local_addr());
2648
2649 /* Ideally we would use the inaddr->s6_addr32 to get to the 128-bit
2650 * IPv6 address. But `s6_addr32' turns out to be a macro that is not
2651 * available on all systems (FreeBSD, for example, does not provide
2652 * this macro unless you're building its kernel).
2653 *
2654 * As a workaround, try using the (hopefully) more portable s6_addr
2655 * macro.
2656 */
2657 memcpy(ipv6_addr, inaddr->s6_addr, sizeof(ipv6_addr));
2658
2659 /* Add a NAS-IPv6-Address attribute. */
2660 radius_add_attrib(packet, RADIUS_NAS_IPV6_ADDRESS,
2661 (unsigned char *) ipv6_addr, sizeof(ipv6_addr));
2662 }
2663
2664 break;
2665 }
2666 }
2667
2668 } else {
2669 #else
2670 if (TRUE) {
2671 #endif /* PR_USE_IPV6 */
2672 struct in_addr *inaddr;
2673
2674 inaddr = pr_netaddr_get_inaddr(pr_netaddr_get_sess_local_addr());
2675
2676 /* Add a NAS-IP-Address attribute. */
2677 radius_add_attrib(packet, RADIUS_NAS_IP_ADDRESS,
2678 (unsigned char *) &(inaddr->s_addr), sizeof(inaddr->s_addr));
2679 }
2680
2681 /* Add a NAS port attribute. */
2682 radius_add_attrib(packet, RADIUS_NAS_PORT, (unsigned char *) &nas_port,
2683 sizeof(int));
2684
2685 /* Add a NAS port type attribute. */
2686 radius_add_attrib(packet, RADIUS_NAS_PORT_TYPE,
2687 (unsigned char *) &nas_port_type, sizeof(int));
2688
2689 /* Add the calling station ID attribute (this is the IP of the connecting
2690 * client).
2691 */
2692 caller_id = (char *) pr_netaddr_get_ipstr(pr_netaddr_get_sess_remote_addr());
2693
2694 radius_add_attrib(packet, RADIUS_CALLING_STATION_ID,
2695 (const unsigned char *) caller_id, strlen(caller_id));
2696 }
2697
2698 static radius_server_t *radius_make_server(pool *parent_pool) {
2699 pool *server_pool = NULL;
2700 radius_server_t *server = NULL;
2701
2702 /* sanity check */
2703 if (!parent_pool)
2704 return NULL;
2705
2706 /* allocate a subpool for the new rec */
2707 server_pool = make_sub_pool(parent_pool);
2708
2709 /* allocate the rec from the subpool */
2710 server = (radius_server_t *) pcalloc(server_pool,
2711 sizeof(radius_server_t));
2712
2713 /* set the members to sane default values */
2714 server->pool = server_pool;
2715 server->addr = NULL;
2716 server->port = RADIUS_AUTH_PORT;
2717 server->secret = NULL;
2718 server->secret_len = 0;
2719 server->timeout = DEFAULT_RADIUS_TIMEOUT;
2720 server->next = NULL;
2721
2722 return server;
2723 }
2724
2725 static int radius_open_socket(void) {
2726 int sockfd = -1;
2727 struct sockaddr_in *radius_sockaddr_in = NULL;
2728 unsigned short local_port = 0;
2729
2730 /* Obtain a socket descriptor. */
2731 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
2732 if (sockfd < 0) {
2733 int xerrno = errno;
2734
2735 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
2736 "notice: unable to open socket for communication: %s",
2737 strerror(xerrno));
2738
2739 errno = xerrno;
2740 return -1;
2741 }
2742
2743 /* Set the members appropriately to bind to the descriptor. */
2744 memset((void *) &radius_local_sock, 0, sizeof(radius_local_sock));
2745 radius_sockaddr_in = (struct sockaddr_in *) &radius_local_sock;
2746 radius_sockaddr_in->sin_family = AF_INET;
2747 radius_sockaddr_in->sin_addr.s_addr = INADDR_ANY;
2748
2749 /* Use our process ID as a local port for RADIUS.
2750 */
2751 local_port = (getpid() & 0x7fff) + 1024;
2752 do {
2753 pr_signals_handle();
2754
2755 local_port++;
2756 radius_sockaddr_in->sin_port = htons(local_port);
2757
2758 } while ((bind(sockfd, &radius_local_sock, sizeof(radius_local_sock)) < 0) &&
2759 (local_port < USHRT_MAX));
2760
2761 if (local_port >= USHRT_MAX) {
2762 (void) close(sockfd);
2763 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
2764 "notice: unable to bind to socket: no open local ports");
2765 errno = EPERM;
2766 return -1;
2767 }
2768
2769 /* Done */
2770 return sockfd;
2771 }
2772
2773 static radius_packet_t *radius_recv_packet(int sockfd, unsigned int timeout) {
2774 static unsigned char recvbuf[RADIUS_PACKET_LEN];
2775 radius_packet_t *packet = NULL;
2776 int res = 0, recvlen = -1;
2777 socklen_t sockaddrlen = sizeof(struct sockaddr);
2778 struct timeval tv;
2779 fd_set rset;
2780
2781 /* receive the response, waiting as necessary */
2782 memset(recvbuf, '\0', sizeof(recvbuf));
2783
2784 tv.tv_sec = timeout;
2785 tv.tv_usec = 0;
2786
2787 FD_ZERO(&rset);
2788 FD_SET(sockfd, &rset);
2789
2790 res = select(sockfd + 1, &rset, NULL, NULL, &tv);
2791 if (res == 0) {
2792 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
2793 "server failed to respond in %u seconds", timeout);
2794 return NULL;
2795
2796 } else if (res < 0) {
2797 int xerrno = errno;
2798
2799 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
2800 "error: unable to receive response: %s", strerror(xerrno));
2801
2802 errno = xerrno;
2803 return NULL;
2804 }
2805
2806 recvlen = recvfrom(sockfd, (char *) recvbuf, RADIUS_PACKET_LEN, 0,
2807 &radius_remote_sock, &sockaddrlen);
2808 if (recvlen < 0) {
2809 int xerrno = errno;
2810
2811 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
2812 "error reading packet: %s", strerror(xerrno));
2813
2814 errno = xerrno;
2815 return NULL;
2816 }
2817
2818 packet = (radius_packet_t *) recvbuf;
2819
2820 /* Make sure the packet is of valid length. */
2821 if (ntohs(packet->length) != recvlen ||
2822 ntohs(packet->length) > RADIUS_PACKET_LEN) {
2823 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
2824 "received corrupted packet");
2825 return NULL;
2826 }
2827
2828 return packet;
2829 }
2830
2831 static int radius_send_packet(int sockfd, radius_packet_t *packet,
2832 radius_server_t *server) {
2833 int res;
2834 struct sockaddr_in *radius_sockaddr_in =
2835 (struct sockaddr_in *) &radius_remote_sock;
2836
2837 /* Set the members appropriately to send to the descriptor. */
2838 memset((void *) &radius_remote_sock, '\0', sizeof(radius_remote_sock));
2839 radius_sockaddr_in->sin_family = AF_INET;
2840 radius_sockaddr_in->sin_addr.s_addr = pr_netaddr_get_addrno(server->addr);
2841 radius_sockaddr_in->sin_port = htons(server->port);
2842
2843 res = sendto(sockfd, (char *) packet, ntohs(packet->length), 0,
2844 &radius_remote_sock, sizeof(struct sockaddr_in));
2845 if (res < 0) {
2846 int xerrno = errno;
2847
2848 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
2849 "error: unable to send packet: %s", strerror(xerrno));
2850
2851 errno = xerrno;
2852 return -1;
2853 }
2854
2855 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
2856 "sending packet to %s:%u", inet_ntoa(radius_sockaddr_in->sin_addr),
2857 ntohs(radius_sockaddr_in->sin_port));
2858
2859 return 0;
2860 }
2861
2862 static int radius_start_accting(void) {
2863 int sockfd = -1, acct_status = 0, acct_authentic = 0, now = 0, pid_len = 0;
2864 radius_packet_t *request = NULL, *response = NULL;
2865 radius_server_t *acct_server = NULL;
2866 unsigned char recvd_response = FALSE, *authenticated = NULL;
2867 char pid_str[16];
2868
2869 /* Check to see if RADIUS accounting should be done. */
2870 if (radius_engine == FALSE ||
2871 radius_acct_server == NULL) {
2872 return 0;
2873 }
2874
2875 /* Only do accounting for authenticated users. */
2876 authenticated = get_param_ptr(main_server->conf, "authenticated", FALSE);
2877 if (authenticated == NULL ||
2878 *authenticated == FALSE) {
2879 return 0;
2880 }
2881
2882 /* Open a RADIUS socket */
2883 sockfd = radius_open_socket();
2884 if (sockfd < 0) {
2885 int xerrno = errno;
2886
2887 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
2888 "socket open failed: %s", strerror(xerrno));
2889
2890 errno = xerrno;
2891 return -1;
2892 }
2893
2894 /* Allocate a packet. */
2895 request = (radius_packet_t *) pcalloc(radius_pool, sizeof(radius_packet_t));
2896
2897 now = htonl(time(NULL));
2898
2899 memset(pid_str, '\0', sizeof(pid_str));
2900 pid_len = pr_snprintf(pid_str, sizeof(pid_str), "%08u",
2901 (unsigned int) session.pid);
2902
2903 /* Loop through the list of servers, trying each one until the packet is
2904 * successfully sent.
2905 */
2906 acct_server = radius_acct_server;
2907
2908 while (acct_server) {
2909 pr_signals_handle();
2910
2911 /* Clear the packet. */
2912 memset(request, '\0', sizeof(radius_packet_t));
2913
2914 /* Build the packet. */
2915 request->code = RADIUS_ACCT_REQUEST;
2916 radius_build_packet(request,
2917 radius_realm ?
2918 (const unsigned char *) pstrcat(radius_pool, session.user,
2919 radius_realm, NULL) :
2920 (const unsigned char *) session.user, NULL, acct_server->secret,
2921 acct_server->secret_len);
2922
2923 radius_last_acct_pkt_id = request->id;
2924
2925 /* Add accounting attributes. */
2926 acct_status = htonl(RADIUS_ACCT_STATUS_START);
2927 radius_add_attrib(request, RADIUS_ACCT_STATUS_TYPE,
2928 (unsigned char *) &acct_status, sizeof(int));
2929
2930 radius_add_attrib(request, RADIUS_ACCT_SESSION_ID,
2931 (const unsigned char *) pid_str, pid_len);
2932
2933 acct_authentic = htonl(RADIUS_AUTH_LOCAL);
2934 radius_add_attrib(request, RADIUS_ACCT_AUTHENTIC,
2935 (unsigned char *) &acct_authentic, sizeof(int));
2936
2937 radius_add_attrib(request, RADIUS_ACCT_EVENT_TS, (unsigned char *) &now,
2938 sizeof(int));
2939
2940 if (radius_acct_user != NULL) {
2941 /* See RFC 2865, Section 5.1. */
2942 radius_add_attrib(request, RADIUS_USER_NAME,
2943 (const unsigned char *) radius_acct_user, radius_acct_userlen);
2944 }
2945
2946 if (radius_acct_class != NULL) {
2947 radius_add_attrib(request, RADIUS_CLASS,
2948 (const unsigned char *) radius_acct_class, radius_acct_classlen);
2949 }
2950
2951 /* Calculate the signature. */
2952 radius_set_acct_digest(request, acct_server->secret,
2953 acct_server->secret_len);
2954
2955 /* Send the request. */
2956 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
2957 "sending start acct request packet");
2958 if (radius_send_packet(sockfd, request, acct_server) < 0) {
2959 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
2960 "packet send failed");
2961 acct_server = acct_server->next;
2962 continue;
2963 }
2964
2965 /* Receive the response. */
2966 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
2967 "receiving acct response packet");
2968 response = radius_recv_packet(sockfd, acct_server->timeout);
2969 if (response == NULL) {
2970 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
2971 "packet receive failed");
2972 acct_server = acct_server->next;
2973 continue;
2974 }
2975
2976 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
2977 "packet receive succeeded");
2978 recvd_response = TRUE;
2979 break;
2980 }
2981
2982 /* Close the socket. */
2983 (void) close(sockfd);
2984
2985 if (recvd_response) {
2986
2987 /* Verify the response. */
2988 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
2989 "verifying packet");
2990 if (radius_verify_packet(request, response, acct_server->secret,
2991 acct_server->secret_len) < 0) {
2992 return -1;
2993 }
2994
2995 /* Handle the response. */
2996 switch (response->code) {
2997 case RADIUS_ACCT_RESPONSE:
2998 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
2999 "accounting started for user '%s'", session.user);
3000 return 0;
3001
3002 default:
3003 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3004 "notice: server returned unknown response code: %02x",
3005 response->code);
3006 return -1;
3007 }
3008
3009 } else {
3010 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3011 "error: no acct servers responded");
3012 }
3013
3014 /* Default return value. */
3015 return -1;
3016 }
3017
3018 /* Maps the ProFTPD disconnect reason code to the RADIUS Acct-Terminate-Cause
3019 * attribute values.
3020 */
3021 static unsigned int radius_get_terminate_cause(void) {
3022 unsigned int cause = RADIUS_ACCT_TERMINATE_CAUSE_SERVICE_UNAVAIL;
3023
3024 switch (session.disconnect_reason) {
3025 case PR_SESS_DISCONNECT_CLIENT_QUIT:
3026 cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
3027 break;
3028
3029 case PR_SESS_DISCONNECT_CLIENT_EOF:
3030 cause = RADIUS_ACCT_TERMINATE_CAUSE_LOST_SERVICE;
3031 break;
3032
3033 case PR_SESS_DISCONNECT_SIGNAL:
3034 cause = RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_RESET;
3035 break;
3036
3037 case PR_SESS_DISCONNECT_SERVER_SHUTDOWN:
3038 cause = RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT;
3039 break;
3040
3041 case PR_SESS_DISCONNECT_TIMEOUT: {
3042 const char *details = NULL;
3043
3044 pr_session_get_disconnect_reason(&details);
3045 if (details != NULL) {
3046 if (strcasecmp(details, "TimeoutIdle") == 0) {
3047 cause = RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
3048
3049 } else if (strcasecmp(details, "TimeoutSession") == 0) {
3050 cause = RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT;
3051 }
3052 }
3053
3054 break;
3055 }
3056 }
3057
3058 return cause;
3059 }
3060
3061 static int radius_stop_accting(void) {
3062 int sockfd = -1, acct_status = 0, acct_authentic = 0, event_ts = 0,
3063 now = 0, pid_len = 0, session_duration = 0;
3064 unsigned int terminate_cause = 0;
3065 radius_packet_t *request = NULL, *response = NULL;
3066 radius_server_t *acct_server = NULL;
3067 unsigned char recvd_response = FALSE, *authenticated = NULL;
3068 off_t radius_session_bytes_in = 0;
3069 off_t radius_session_bytes_out = 0;
3070 char pid_str[16];
3071
3072 /* Check to see if RADIUS accounting should be done. */
3073 if (radius_engine == FALSE ||
3074 radius_acct_server == NULL) {
3075 return 0;
3076 }
3077
3078 /* Only do accounting for authenticated users. */
3079 authenticated = get_param_ptr(main_server->conf, "authenticated", FALSE);
3080 if (authenticated == NULL ||
3081 *authenticated == FALSE) {
3082 return 0;
3083 }
3084
3085 /* Open a RADIUS socket */
3086 sockfd = radius_open_socket();
3087 if (sockfd < 0) {
3088 int xerrno = errno;
3089
3090 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3091 "socket open failed: %s", strerror(xerrno));
3092
3093 errno = xerrno;
3094 return -1;
3095 }
3096
3097 /* Allocate a packet. */
3098 request = (radius_packet_t *) pcalloc(radius_pool, sizeof(radius_packet_t));
3099
3100 now = time(NULL);
3101 event_ts = htonl(now);
3102 session_duration = htonl(now - radius_session_start);
3103 terminate_cause = htonl(radius_get_terminate_cause());
3104
3105 memset(pid_str, '\0', sizeof(pid_str));
3106 pid_len = pr_snprintf(pid_str, sizeof(pid_str)-1, "%08u",
3107 (unsigned int) session.pid);
3108
3109 /* Loop through the list of servers, trying each one until the packet is
3110 * successfully sent.
3111 */
3112 acct_server = radius_acct_server;
3113
3114 while (acct_server) {
3115 const char *ip_str;
3116
3117 pr_signals_handle();
3118
3119 /* Clear the packet. */
3120 memset(request, '\0', sizeof(radius_packet_t));
3121
3122 /* Build the packet. */
3123 request->code = RADIUS_ACCT_REQUEST;
3124 radius_build_packet(request,
3125 radius_realm ?
3126 (const unsigned char *) pstrcat(radius_pool, session.user,
3127 radius_realm, NULL) :
3128 (const unsigned char *) session.user, NULL, acct_server->secret,
3129 acct_server->secret_len);
3130
3131 /* Use the ID of the last accounting packet sent, plus one. Be sure
3132 * to handle the datatype overflow case.
3133 */
3134 request->id = radius_last_acct_pkt_id + 1;
3135 if (request->id == 0) {
3136 request->id = 1;
3137 }
3138
3139 /* Add accounting attributes. */
3140 acct_status = htonl(RADIUS_ACCT_STATUS_STOP);
3141 radius_add_attrib(request, RADIUS_ACCT_STATUS_TYPE,
3142 (unsigned char *) &acct_status, sizeof(int));
3143
3144 radius_add_attrib(request, RADIUS_ACCT_SESSION_ID,
3145 (const unsigned char *) pid_str, pid_len);
3146
3147 acct_authentic = htonl(RADIUS_AUTH_LOCAL);
3148 radius_add_attrib(request, RADIUS_ACCT_AUTHENTIC,
3149 (unsigned char *) &acct_authentic, sizeof(int));
3150
3151 radius_add_attrib(request, RADIUS_ACCT_SESSION_TIME,
3152 (unsigned char *) &session_duration, sizeof(int));
3153
3154 radius_session_bytes_in = htonl(session.total_bytes_in);
3155 radius_add_attrib(request, RADIUS_ACCT_INPUT_OCTETS,
3156 (unsigned char *) &radius_session_bytes_in, sizeof(int));
3157
3158 radius_session_bytes_out = htonl(session.total_bytes_out);
3159 radius_add_attrib(request, RADIUS_ACCT_OUTPUT_OCTETS,
3160 (unsigned char *) &radius_session_bytes_out, sizeof(int));
3161
3162 radius_add_attrib(request, RADIUS_ACCT_TERMINATE_CAUSE,
3163 (unsigned char *) &terminate_cause, sizeof(int));
3164
3165 radius_add_attrib(request, RADIUS_ACCT_EVENT_TS,
3166 (unsigned char *) &event_ts, sizeof(int));
3167
3168 if (radius_acct_user != NULL) {
3169 /* See RFC 2865, Section 5.1. */
3170 radius_add_attrib(request, RADIUS_USER_NAME,
3171 (const unsigned char *) radius_acct_user, radius_acct_userlen);
3172 }
3173
3174 if (radius_acct_class != NULL) {
3175 radius_add_attrib(request, RADIUS_CLASS,
3176 (const unsigned char *) radius_acct_class, radius_acct_classlen);
3177 }
3178
3179 /* Calculate the signature. */
3180 radius_set_acct_digest(request, acct_server->secret,
3181 acct_server->secret_len);
3182
3183 /* Send the request. */
3184 ip_str = pr_netaddr_get_ipstr(acct_server->addr);
3185 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3186 "sending stop acct request packet to %s#%u", ip_str, acct_server->port);
3187 if (radius_send_packet(sockfd, request, acct_server) < 0) {
3188 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3189 "packet send failed to %s#%u", ip_str, acct_server->port);
3190 acct_server = acct_server->next;
3191 continue;
3192 }
3193
3194 /* Receive the response. */
3195 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3196 "receiving acct response packet");
3197 response = radius_recv_packet(sockfd, acct_server->timeout);
3198 if (response == NULL) {
3199 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3200 "packet receive failed from %s#%u", ip_str, acct_server->port);
3201 acct_server = acct_server->next;
3202 continue;
3203 }
3204
3205 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3206 "packet receive succeeded succeeded from %s#%u", ip_str,
3207 acct_server->port);
3208 recvd_response = TRUE;
3209 break;
3210 }
3211
3212 /* Close the socket. */
3213 (void) close(sockfd);
3214
3215 if (recvd_response) {
3216
3217 /* Verify the response. */
3218 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3219 "verifying packet");
3220 if (radius_verify_packet(request, response, acct_server->secret,
3221 acct_server->secret_len) < 0) {
3222 return -1;
3223 }
3224
3225 /* Handle the response. */
3226 switch (response->code) {
3227 case RADIUS_ACCT_RESPONSE:
3228 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3229 "accounting ended for user '%s'", session.user);
3230 return 0;
3231
3232 default:
3233 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3234 "notice: server returned unknown response code: %02x",
3235 response->code);
3236 return -1;
3237 }
3238
3239 } else {
3240 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3241 "error: no accounting servers responded");
3242 }
3243
3244 /* Default return value. */
3245 return -1;
3246 }
3247
3248 /* Verify the response packet from the server. */
3249 static int radius_verify_packet(radius_packet_t *req_packet,
3250 radius_packet_t *resp_packet, const unsigned char *secret,
3251 size_t secret_len) {
3252 MD5_CTX ctx;
3253 unsigned char calculated[RADIUS_VECTOR_LEN], replied[RADIUS_VECTOR_LEN];
3254
3255 /* sanity check */
3256 if (req_packet == NULL ||
3257 resp_packet == NULL ||
3258 secret == NULL) {
3259 errno = EINVAL;
3260 return -1;
3261 }
3262
3263 /* NOTE: add checks for too-big, too-small packets, invalid packet->length
3264 * values, etc.
3265 */
3266
3267 /* Check that the packet IDs match. */
3268 if (resp_packet->id != req_packet->id) {
3269 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3270 "packet verification failed: response packet ID %d does not "
3271 "match the request packet ID %d", resp_packet->id, req_packet->id);
3272 return -1;
3273 }
3274
3275 /* Make sure the buffers are void of junk values. */
3276 memset(calculated, '\0', sizeof(calculated));
3277 memset(replied, '\0', sizeof(replied));
3278
3279 /* Save a copy of the response's digest. */
3280 memcpy(replied, resp_packet->digest, RADIUS_VECTOR_LEN);
3281
3282 /* Copy in the digest sent in the request. */
3283 memcpy(resp_packet->digest, req_packet->digest, RADIUS_VECTOR_LEN);
3284
3285 /* Re-calculate a digest from the given packet, and compare it against
3286 * the provided response digest:
3287 * MD5(response packet header + digest + response packet data + secret)
3288 */
3289 MD5_Init(&ctx);
3290 MD5_Update(&ctx, (unsigned char *) resp_packet, ntohs(resp_packet->length));
3291
3292 if (*secret) {
3293 MD5_Update(&ctx, secret, secret_len);
3294 }
3295
3296 /* Set the calculated digest. */
3297 MD5_Final(calculated, &ctx);
3298
3299 /* Do the digests match properly? */
3300 if (memcmp(calculated, replied, RADIUS_VECTOR_LEN) != 0) {
3301 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3302 "packet verification failed: mismatched digests");
3303 errno = EINVAL;
3304 return -1;
3305 }
3306
3307 return 0;
3308 }
3309
3310 /* Authentication handlers
3311 */
3312
3313 MODRET radius_auth(cmd_rec *cmd) {
3314
3315 /* This authentication check has already been performed; I just need
3316 * to report the results of that check now.
3317 */
3318 if (radius_auth_ok) {
3319 session.auth_mech = "mod_radius.c";
3320 return PR_HANDLED(cmd);
3321
3322 } else if (radius_auth_reject) {
3323 return PR_ERROR_INT(cmd, PR_AUTH_BADPWD);
3324 }
3325
3326 /* Default return value. */
3327 return PR_DECLINED(cmd);
3328 }
3329
3330 MODRET radius_check(cmd_rec *cmd) {
3331 return PR_DECLINED(cmd);
3332 }
3333
3334 MODRET radius_name2uid(cmd_rec *cmd) {
3335 return PR_DECLINED(cmd);
3336 }
3337
3338 MODRET radius_name2gid(cmd_rec *cmd) {
3339 return PR_DECLINED(cmd);
3340 }
3341
3342 MODRET radius_uid2name(cmd_rec *cmd) {
3343 return PR_DECLINED(cmd);
3344 }
3345
3346 MODRET radius_gid2name(cmd_rec *cmd) {
3347 return PR_DECLINED(cmd);
3348 }
3349
3350 MODRET radius_endgrent(cmd_rec *cmd) {
3351 return PR_DECLINED(cmd);
3352 }
3353
3354 MODRET radius_getgrnam(cmd_rec *cmd) {
3355 return PR_DECLINED(cmd);
3356 }
3357
3358 MODRET radius_getgrent(cmd_rec *cmd) {
3359 return PR_DECLINED(cmd);
3360 }
3361
3362 MODRET radius_getgrgid(cmd_rec *cmd) {
3363 return PR_DECLINED(cmd);
3364 }
3365
3366 MODRET radius_getgroups(cmd_rec *cmd) {
3367
3368 if (radius_have_group_info) {
3369 array_header *gids = NULL, *groups = NULL;
3370 register unsigned int i = 0;
3371
3372 /* Return the faked group information. */
3373
3374 /* Don't forget to include the primary GID (with accompanying name!)
3375 * in the returned info -- if provided. Otherwise, well...the user
3376 * is out of luck.
3377 */
3378
3379 /* Check for NULL values */
3380 if (cmd->argv[1]) {
3381 gids = (array_header *) cmd->argv[1];
3382
3383 if (radius_have_user_info) {
3384 *((gid_t *) push_array(gids)) = radius_passwd.pw_gid;
3385 }
3386
3387 for (i = 0; i < radius_addl_group_count; i++) {
3388 *((gid_t *) push_array(gids)) = radius_addl_group_ids[i];
3389 }
3390 }
3391
3392 if (cmd->argv[2]) {
3393 groups = (array_header *) cmd->argv[2];
3394
3395 if (radius_have_user_info) {
3396 *((char **) push_array(groups)) = radius_prime_group_name;
3397 }
3398
3399 for (i = 0; i < radius_addl_group_count; i++) {
3400 *((char **) push_array(groups)) = radius_addl_group_names[i];
3401 }
3402 }
3403
3404 /* Increment this count, for the sake of proper reporting back to the
3405 * getgroups() caller.
3406 */
3407 if (radius_have_user_info) {
3408 radius_addl_group_count++;
3409 }
3410
3411 return mod_create_data(cmd, (void *) &radius_addl_group_count);
3412 }
3413
3414 return PR_DECLINED(cmd);
3415 }
3416
3417 MODRET radius_setgrent(cmd_rec *cmd) {
3418 return PR_DECLINED(cmd);
3419 }
3420
3421 MODRET radius_endpwent(cmd_rec *cmd) {
3422 return PR_DECLINED(cmd);
3423 }
3424
3425 MODRET radius_getpwnam(cmd_rec *cmd) {
3426
3427 if (radius_have_user_info) {
3428
3429 if (radius_passwd.pw_name == NULL) {
3430 radius_passwd.pw_name = pstrdup(radius_pool, cmd->argv[0]);
3431 }
3432
3433 if (strcmp(cmd->argv[0], radius_passwd.pw_name) == 0) {
3434
3435 /* Return the faked user information. */
3436 return mod_create_data(cmd, &radius_passwd);
3437 }
3438 }
3439
3440 /* Default response */
3441 return PR_DECLINED(cmd);
3442 }
3443
3444 MODRET radius_getpwent(cmd_rec *cmd) {
3445
3446 if (radius_have_user_info) {
3447
3448 /* Return the faked user information. */
3449 return mod_create_data(cmd, &radius_passwd);
3450 }
3451
3452 /* Default response */
3453 return PR_DECLINED(cmd);
3454 }
3455
3456 MODRET radius_getpwuid(cmd_rec *cmd) {
3457
3458 if (radius_have_user_info) {
3459
3460 /* Check that given UID matches faked UID before returning. */
3461 if (*((uid_t *) cmd->argv[0]) == radius_passwd.pw_uid) {
3462
3463 /* Return the faked user information. */
3464 return mod_create_data(cmd, &radius_passwd);
3465 }
3466 }
3467
3468 /* Default response */
3469 return PR_DECLINED(cmd);
3470 }
3471
3472 MODRET radius_setpwent(cmd_rec *cmd) {
3473 return PR_DECLINED(cmd);
3474 }
3475
3476 /* Command handlers
3477 */
3478
3479 /* Handle retrieval of quota-related VSAs from response packets.
3480 */
3481 MODRET radius_quota_lookup(cmd_rec *cmd) {
3482
3483 if (radius_have_quota_info) {
3484 array_header *quota = make_array(session.pool, 9, sizeof(char *));
3485 *((char **) push_array(quota)) = cmd->argv[0];
3486 *((char **) push_array(quota)) = radius_quota_per_sess;
3487 *((char **) push_array(quota)) = radius_quota_limit_type;
3488 *((char **) push_array(quota)) = radius_quota_bytes_in;
3489 *((char **) push_array(quota)) = radius_quota_bytes_out;
3490 *((char **) push_array(quota)) = radius_quota_bytes_xfer;
3491 *((char **) push_array(quota)) = radius_quota_files_in;
3492 *((char **) push_array(quota)) = radius_quota_files_out;
3493 *((char **) push_array(quota)) = radius_quota_files_xfer;
3494
3495 return mod_create_data(cmd, quota);
3496 }
3497
3498 return PR_DECLINED(cmd);
3499 }
3500
3501 /* Perform the check with the RADIUS auth server(s) now, prior to the
3502 * actual handling of the PASS command by mod_auth, so that any of the
3503 * RadiusUserInfo parameters can be supplied by the RADIUS server.
3504 *
3505 * NOTE: first draft, does not honor UserAlias'd names (eg it uses the
3506 * username as supplied by the client.
3507 */
3508 MODRET radius_pre_pass(cmd_rec *cmd) {
3509 int pid_len = 0, sockfd = -1;
3510 radius_packet_t *request = NULL, *response = NULL;
3511 radius_server_t *auth_server = NULL;
3512 unsigned char recvd_response = FALSE;
3513 unsigned int service;
3514 const char *user;
3515 char pid_str[16];
3516
3517 /* Check to see whether RADIUS authentication should even be done. */
3518 if (radius_engine == FALSE ||
3519 radius_auth_server == NULL) {
3520 return PR_DECLINED(cmd);
3521 }
3522
3523 user = pr_table_get(session.notes, "mod_auth.orig-user", NULL);
3524 if (user == NULL) {
3525 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3526 "missing prerequisite USER command, declining to handle PASS");
3527 pr_response_add_err(R_503, _("Login with USER first"));
3528 return PR_ERROR(cmd);
3529 }
3530
3531 /* Open a RADIUS socket */
3532 sockfd = radius_open_socket();
3533 if (sockfd < 0) {
3534 int xerrno = errno;
3535 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3536 "socket open failed: %s", strerror(xerrno));
3537 errno = xerrno;
3538 return PR_DECLINED(cmd);
3539 }
3540
3541 /* Allocate a packet. */
3542 request = (radius_packet_t *) pcalloc(cmd->tmp_pool,
3543 sizeof(radius_packet_t));
3544
3545 /* Clear the OK flag. */
3546 radius_auth_ok = FALSE;
3547
3548 memset(pid_str, '\0', sizeof(pid_str));
3549 pid_len = pr_snprintf(pid_str, sizeof(pid_str)-1, "%08u",
3550 (unsigned int) session.pid);
3551
3552 /* If mod_radius expects to find VSAs in the returned packet, it needs
3553 * to send a service type of Login, otherwise, use the Authenticate-Only
3554 * service type.
3555 */
3556 if (radius_have_user_info == TRUE ||
3557 radius_have_group_info == TRUE ||
3558 radius_have_quota_info == TRUE ||
3559 radius_have_other_info == TRUE) {
3560 service = (unsigned int) htonl(RADIUS_SVC_LOGIN);
3561
3562 } else {
3563 service = (unsigned int) htonl(RADIUS_SVC_AUTHENTICATE_ONLY);
3564 }
3565
3566 /* Loop through the list of servers, trying each one until the packet is
3567 * successfully sent.
3568 */
3569 auth_server = radius_auth_server;
3570 while (auth_server != NULL) {
3571 const char *ip_str;
3572
3573 pr_signals_handle();
3574
3575 /* Clear the packet. */
3576 memset(request, '\0', sizeof(radius_packet_t));
3577
3578 /* Build the packet. */
3579 request->code = RADIUS_AUTH_REQUEST;
3580 radius_build_packet(request, radius_realm ?
3581 (const unsigned char *) pstrcat(radius_pool, user, radius_realm, NULL) :
3582 (const unsigned char *) user, (const unsigned char *) cmd->arg,
3583 auth_server->secret, auth_server->secret_len);
3584
3585 radius_add_attrib(request, RADIUS_SERVICE_TYPE, (unsigned char *) &service,
3586 sizeof(service));
3587
3588 radius_add_attrib(request, RADIUS_ACCT_SESSION_ID,
3589 (const unsigned char *) pid_str, pid_len);
3590
3591 /* Calculate the signature. */
3592 radius_set_auth_mac(request, auth_server->secret, auth_server->secret_len);
3593
3594 /* Send the request. */
3595 ip_str = pr_netaddr_get_ipstr(auth_server->addr);
3596 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3597 "sending auth request packet to %s#%d", ip_str, auth_server->port);
3598 if (radius_send_packet(sockfd, request, auth_server) < 0) {
3599 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3600 "packet send failed to %s#%d", ip_str, auth_server->port);
3601 auth_server = auth_server->next;
3602 continue;
3603 }
3604
3605 /* Receive the response. */
3606 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3607 "receiving auth response packet from %s#%d", ip_str, auth_server->port);
3608 response = radius_recv_packet(sockfd, auth_server->timeout);
3609 if (response == NULL) {
3610 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3611 "packet receive failed from %s#%d", ip_str, auth_server->port);
3612 auth_server = auth_server->next;
3613 continue;
3614 }
3615
3616 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3617 "packet receive succeeded from %s#%d", ip_str, auth_server->port);
3618 recvd_response = TRUE;
3619 break;
3620 }
3621
3622 /* Close the socket. */
3623 (void) close(sockfd);
3624
3625 if (recvd_response) {
3626 int res;
3627
3628 /* Verify the response. */
3629 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3630 "verifying packet");
3631 res = radius_verify_packet(request, response, auth_server->secret,
3632 auth_server->secret_len);
3633 if (res < 0) {
3634 return PR_DECLINED(cmd);
3635 }
3636
3637 /* Handle the response */
3638 switch (response->code) {
3639 case RADIUS_AUTH_ACCEPT:
3640 /* Process the packet for custom attributes */
3641 res = radius_process_accept_packet(response, auth_server->secret,
3642 auth_server->secret_len);
3643 if (res < 0) {
3644 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3645 "DISCARDING Access-Accept packet for user '%s' due to failed "
3646 "Message-Authenticator check; is the shared secret correct?",
3647 user);
3648 pr_log_pri(PR_LOG_NOTICE, MOD_RADIUS_VERSION
3649 ": DISCARDING Access-Accept packet for user '%s' due to failed "
3650 "Message-Authenticator check; is the shared secret correct?", user);
3651
3652 } else {
3653 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3654 "authentication successful for user '%s'", user);
3655 pr_trace_msg(trace_channel, 9,
3656 "processed %d %s in Access-Accept packet", res,
3657 res != 1 ? "attributes" : "attribute");
3658
3659 radius_auth_ok = TRUE;
3660 radius_session_authtype = htonl(RADIUS_AUTH_RADIUS);
3661 }
3662 break;
3663
3664 case RADIUS_AUTH_REJECT:
3665 /* Process the packet for custom attributes */
3666 res = radius_process_reject_packet(response, auth_server->secret,
3667 auth_server->secret_len);
3668 if (res < 0) {
3669 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3670 "DISCARDING Access-Reject packet for user '%s' due to failed "
3671 "Message-Authenticator check; is the shared secret correct?",
3672 user);
3673 pr_log_pri(PR_LOG_NOTICE, MOD_RADIUS_VERSION
3674 ": DISCARDING Access-Reject packet for user '%s' due to failed "
3675 "Message-Authenticator check; is the shared secret correct?", user);
3676
3677 } else {
3678 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3679 "authentication failed for user '%s'", user);
3680 pr_trace_msg(trace_channel, 9,
3681 "processed %d %s in Access-Reject packet", res,
3682 res != 1 ? "attributes" : "attribute");
3683
3684 radius_auth_ok = FALSE;
3685 radius_auth_reject = TRUE;
3686 radius_reset();
3687 }
3688 break;
3689
3690 case RADIUS_AUTH_CHALLENGE:
3691 /* Just log this case for now. */
3692 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3693 "authentication challenged for user '%s'", user);
3694 radius_reset();
3695 break;
3696
3697 default:
3698 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3699 "notice: server returned unknown response code: %02x",
3700 response->code);
3701 radius_reset();
3702 break;
3703 }
3704
3705 } else {
3706 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3707 "error: no auth servers responded");
3708 }
3709
3710 return PR_DECLINED(cmd);
3711 }
3712
3713 MODRET radius_post_pass(cmd_rec *cmd) {
3714
3715 /* Check to see if RADIUS accounting should be done. */
3716 if (!radius_engine || !radius_acct_server) {
3717 return PR_DECLINED(cmd);
3718 }
3719
3720 /* Fill in the username in the faked user info, if need be. */
3721 if (radius_have_user_info) {
3722 radius_passwd.pw_name = (char *) session.user;
3723 }
3724
3725 if (radius_start_accting() < 0) {
3726 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
3727 "error: unable to start accounting: %s", strerror(errno));
3728 }
3729
3730 return PR_DECLINED(cmd);
3731 }
3732
3733 MODRET radius_post_pass_err(cmd_rec *cmd) {
3734 radius_reset();
3735 return PR_DECLINED(cmd);
3736 }
3737
3738 /* Configuration handlers
3739 */
3740
3741 /* usage: RadiusAcctServer server[:port] shared-secret [timeout] */
3742 MODRET set_radiusacctserver(cmd_rec *cmd) {
3743 config_rec *c = NULL;
3744 radius_server_t *radius_server = NULL;
3745 unsigned short server_port = 0;
3746 char *port = NULL;
3747
3748 if (cmd->argc-1 < 2 ||
3749 cmd->argc-1 > 3) {
3750 CONF_ERROR(cmd, "missing parameters");
3751 }
3752
3753 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
3754
3755 /* Check to see if there's a port specified in the server name */
3756 port = strchr(cmd->argv[1], ':');
3757 if (port != NULL) {
3758
3759 /* Separate the server name from the port */
3760 *(port++) = '\0';
3761
3762 server_port = (unsigned short) atoi(port);
3763 if (server_port < 1024) {
3764 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "port number must be greater "
3765 "than 1023", NULL));
3766 }
3767 }
3768
3769 if (pr_netaddr_get_addr(cmd->tmp_pool, cmd->argv[1], NULL) == NULL) {
3770 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unable to resolve server address: ",
3771 cmd->argv[1], NULL));
3772 }
3773
3774 /* Allocate a RADIUS server rec and populate the members */
3775 radius_server = radius_make_server(radius_pool);
3776
3777 radius_server->addr = pr_netaddr_get_addr(radius_server->pool, cmd->argv[1],
3778 NULL);
3779 radius_server->port = (server_port ? server_port : RADIUS_ACCT_PORT);
3780 radius_server->secret = (unsigned char *) pstrdup(radius_server->pool,
3781 cmd->argv[2]);
3782 radius_server->secret_len = strlen((char *) radius_server->secret);
3783
3784 if (cmd->argc-1 == 3) {
3785 int timeout = -1;
3786
3787 if (pr_str_get_duration(cmd->argv[3], &timeout) < 0) {
3788 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "error parsing timeout value '",
3789 cmd->argv[1], "': ", strerror(errno), NULL));
3790 }
3791
3792 radius_server->timeout = timeout;
3793 }
3794
3795 c = add_config_param(cmd->argv[0], 1, NULL);
3796 c->argv[0] = pcalloc(c->pool, sizeof(radius_server_t *));
3797 *((radius_server_t **) c->argv[0]) = radius_server;
3798
3799 return PR_HANDLED(cmd);
3800 }
3801
3802 /* usage: RadiusAuthServer server[:port] <shared-secret> [timeout] */
3803 MODRET set_radiusauthserver(cmd_rec *cmd) {
3804 config_rec *c = NULL;
3805 radius_server_t *radius_server = NULL;
3806 unsigned short server_port = 0;
3807 char *port = NULL;
3808
3809 if (cmd->argc-1 < 2 ||
3810 cmd->argc-1 > 3) {
3811 CONF_ERROR(cmd, "missing parameters");
3812 }
3813
3814 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
3815
3816 /* Check to see if there's a port specified in the server name */
3817 if ((port = strchr(cmd->argv[1], ':')) != NULL) {
3818
3819 /* Separate the server name from the port */
3820 *(port++) = '\0';
3821
3822 server_port = (unsigned short) atoi(port);
3823 if (server_port < 1024) {
3824 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "port number must be greater "
3825 "than 1023", NULL));
3826 }
3827 }
3828
3829 if (pr_netaddr_get_addr(cmd->tmp_pool, cmd->argv[1], NULL) == NULL) {
3830 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unable resolve server address: ",
3831 cmd->argv[1], NULL));
3832 }
3833
3834 /* OK, allocate a RADIUS server rec and populate the members */
3835 radius_server = radius_make_server(radius_pool);
3836
3837 radius_server->addr = pr_netaddr_get_addr(radius_server->pool, cmd->argv[1],
3838 NULL);
3839 radius_server->port = (server_port ? server_port : RADIUS_AUTH_PORT);
3840 radius_server->secret = (unsigned char *) pstrdup(radius_server->pool,
3841 cmd->argv[2]);
3842 radius_server->secret_len = strlen((char *) radius_server->secret);
3843
3844 if (cmd->argc-1 == 3) {
3845 int timeout = -1;
3846
3847 if (pr_str_get_duration(cmd->argv[3], &timeout) < 0) {
3848 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "error parsing timeout value '",
3849 cmd->argv[1], "': ", strerror(errno), NULL));
3850 }
3851
3852 radius_server->timeout = timeout;
3853 }
3854
3855 c = add_config_param(cmd->argv[0], 1, NULL);
3856 c->argv[0] = pcalloc(c->pool, sizeof(radius_server_t *));
3857 *((radius_server_t **) c->argv[0]) = radius_server;
3858
3859 return PR_HANDLED(cmd);
3860 }
3861
3862 /* usage: RadiusEngine on|off */
3863 MODRET set_radiusengine(cmd_rec *cmd) {
3864 int engine = -1;
3865 config_rec *c = NULL;
3866
3867 CHECK_ARGS(cmd, 1);
3868 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
3869
3870 engine = get_boolean(cmd, 1);
3871 if (engine == -1) {
3872 CONF_ERROR(cmd, "expected Boolean parameter");
3873 }
3874
3875 c = add_config_param(cmd->argv[0], 1, NULL);
3876 c->argv[0] = pcalloc(c->pool, sizeof(int));
3877 *((int *) c->argv[0]) = engine;
3878
3879 return PR_HANDLED(cmd);
3880 }
3881
3882 /* usage: RadiusGroupInfo primary-name addl-names add-ids */
3883 MODRET set_radiusgroupinfo(cmd_rec *cmd) {
3884 config_rec *c = NULL;
3885 unsigned char group_names_vsa = FALSE;
3886 unsigned char group_ids_vsa = FALSE;
3887 unsigned int ngroups = 0, ngids = 0;
3888
3889 CHECK_ARGS(cmd, 3);
3890 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
3891
3892 group_names_vsa = radius_have_var(cmd->argv[2]);
3893 group_ids_vsa = radius_have_var(cmd->argv[3]);
3894
3895 /* There will be five parameters to this config_rec:
3896 *
3897 * primary-group-name
3898 * addl-group-name-count
3899 * addl-group-names
3900 * addl-group-id-count
3901 * addl-group-ids
3902 */
3903
3904 c = add_config_param(cmd->argv[0], 5, NULL, NULL, NULL, NULL, NULL);
3905 c->argv[0] = pstrdup(c->pool, cmd->argv[1]);
3906 c->argv[1] = pcalloc(c->pool, sizeof(unsigned int));
3907 c->argv[3] = pcalloc(c->pool, sizeof(unsigned int));
3908
3909 if (group_names_vsa) {
3910 /* As VSA variables, the group names won't be resolved until session time,
3911 * so just store the variable strings as is.
3912 */
3913 c->argv[2] = pstrdup(c->pool, cmd->argv[2]);
3914
3915 } else {
3916 char **groups = NULL;
3917
3918 if (!radius_parse_groups_str(c->pool, cmd->argv[2], &groups, &ngroups))
3919 CONF_ERROR(cmd, "badly formatted group names");
3920
3921 *((unsigned int *) c->argv[1]) = ngroups;
3922 c->argv[2] = (void *) groups;
3923 }
3924
3925 if (group_ids_vsa) {
3926 /* As VSA variables, the group IDs won't be resolved until session time,
3927 * so just store the variable strings as is.
3928 */
3929 c->argv[4] = pstrdup(c->pool, cmd->argv[3]);
3930
3931 } else {
3932 gid_t *gids = NULL;
3933
3934 if (!radius_parse_gids_str(c->pool, cmd->argv[3], &gids, &ngids))
3935 CONF_ERROR(cmd, "badly formatted group IDs");
3936
3937 *((unsigned int *) c->argv[3]) = ngids;
3938 c->argv[4] = (void *) gids;
3939 }
3940
3941 if (ngroups > 0 &&
3942 ngids > 0 &&
3943 ngroups != ngids) {
3944 char ngroups_str[32], ngids_str[32];
3945
3946 memset(ngroups_str, '\0', sizeof(ngroups_str));
3947 pr_snprintf(ngroups_str, sizeof(ngroups_str)-1, "%u", ngroups);
3948
3949 memset(ngids_str, '\0', sizeof(ngids_str));
3950 pr_snprintf(ngids_str, sizeof(ngids_str)-1, "%u", ngids);
3951
3952 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "mismatched number of group names (",
3953 ngroups_str, ") and group IDs (", ngids_str, ")", NULL));
3954 }
3955
3956 return PR_HANDLED(cmd);
3957 }
3958
3959 /* usage: RadiusLog file|"none" */
3960 MODRET set_radiuslog(cmd_rec *cmd) {
3961 if (cmd->argc-1 != 1)
3962 CONF_ERROR(cmd, "wrong number of parameters");
3963 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
3964
3965 add_config_param_str(cmd->argv[0], 1, cmd->argv[1]);
3966 return PR_HANDLED(cmd);
3967 }
3968
3969 /* usage: RadiusNASIdentifier string */
3970 MODRET set_radiusnasidentifier(cmd_rec *cmd) {
3971 CHECK_ARGS(cmd, 1);
3972 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
3973
3974 add_config_param_str(cmd->argv[0], 1, cmd->argv[1]);
3975 return PR_HANDLED(cmd);
3976 }
3977
3978 /* usage: RadiusOptions opt1 ... */
3979 MODRET set_radiusoptions(cmd_rec *cmd) {
3980 config_rec *c = NULL;
3981 register unsigned int i = 0;
3982 unsigned long opts = 0UL;
3983
3984 if (cmd->argc-1 == 0)
3985 CONF_ERROR(cmd, "wrong number of parameters");
3986
3987 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
3988
3989 c = add_config_param(cmd->argv[0], 1, NULL);
3990
3991 for (i = 1; i < cmd->argc; i++) {
3992 if (strcmp(cmd->argv[i], "IgnoreReplyMessage") == 0) {
3993 opts |= RADIUS_OPT_IGNORE_REPLY_MESSAGE_ATTR;
3994
3995 } else if (strcmp(cmd->argv[i], "IgnoreClass") == 0) {
3996 opts |= RADIUS_OPT_IGNORE_CLASS_ATTR;
3997
3998 } else if (strcmp(cmd->argv[i], "IgnoreIdleTimeout") == 0) {
3999 opts |= RADIUS_OPT_IGNORE_IDLE_TIMEOUT_ATTR;
4000
4001 } else if (strcmp(cmd->argv[i], "IgnoreSessionTimeout") == 0) {
4002 opts |= RADIUS_OPT_IGNORE_SESSION_TIMEOUT_ATTR;
4003
4004 } else if (strcmp(cmd->argv[i], "RequireMAC") == 0) {
4005 opts |= RADIUS_OPT_REQUIRE_MAC;
4006
4007 } else {
4008 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": unknown TLSOption '",
4009 cmd->argv[i], "'", NULL));
4010 }
4011 }
4012
4013 c->argv[0] = pcalloc(c->pool, sizeof(unsigned long));
4014 *((unsigned long *) c->argv[0]) = opts;
4015
4016 return PR_HANDLED(cmd);
4017 }
4018
4019 /* usage: RadiusQuotaInfo per-sess limit-type bytes-in bytes-out bytes-xfer
4020 * files-in files-out files-xfer
4021 */
4022 MODRET set_radiusquotainfo(cmd_rec *cmd) {
4023 CHECK_ARGS(cmd, 8);
4024 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
4025
4026 if (!radius_have_var(cmd->argv[1])) {
4027 if (strcasecmp(cmd->argv[1], "false") != 0 &&
4028 strcasecmp(cmd->argv[1], "true") != 0)
4029 CONF_ERROR(cmd, "invalid per-session value");
4030 }
4031
4032 if (!radius_have_var(cmd->argv[2])) {
4033 if (strcasecmp(cmd->argv[2], "hard") != 0 &&
4034 strcasecmp(cmd->argv[2], "soft") != 0) {
4035 CONF_ERROR(cmd, "invalid limit type value");
4036 }
4037 }
4038
4039 if (!radius_have_var(cmd->argv[3])) {
4040 char *endp = NULL;
4041
4042 /* Make sure it's a number, at least. */
4043 if (strtod(cmd->argv[3], &endp) < 0) {
4044 CONF_ERROR(cmd, "negative bytes value not allowed");
4045 }
4046
4047 if (endp && *endp) {
4048 CONF_ERROR(cmd, "invalid bytes parameter: not a number");
4049 }
4050 }
4051
4052 if (!radius_have_var(cmd->argv[4])) {
4053 char *endp = NULL;
4054
4055 /* Make sure it's a number, at least. */
4056 if (strtod(cmd->argv[4], &endp) < 0) {
4057 CONF_ERROR(cmd, "negative bytes value not allowed");
4058 }
4059
4060 if (endp && *endp) {
4061 CONF_ERROR(cmd, "invalid bytes parameter: not a number");
4062 }
4063 }
4064
4065 if (!radius_have_var(cmd->argv[5])) {
4066 char *endp = NULL;
4067
4068 /* Make sure it's a number, at least. */
4069 if (strtod(cmd->argv[5], &endp) < 0) {
4070 CONF_ERROR(cmd, "negative bytes value not allowed");
4071 }
4072
4073 if (endp && *endp) {
4074 CONF_ERROR(cmd, "invalid bytes parameter: not a number");
4075 }
4076 }
4077
4078 if (!radius_have_var(cmd->argv[6])) {
4079 char *endp = NULL;
4080
4081 /* Make sure it's a number, at least. */
4082 (void) strtoul(cmd->argv[6], &endp, 10);
4083 if (endp && *endp) {
4084 CONF_ERROR(cmd, "invalid files parameter: not a number");
4085 }
4086 }
4087
4088 if (!radius_have_var(cmd->argv[7])) {
4089 char *endp = NULL;
4090
4091 /* Make sure it's a number, at least. */
4092 (void) strtoul(cmd->argv[7], &endp, 10);
4093 if (endp && *endp) {
4094 CONF_ERROR(cmd, "invalid files parameter: not a number");
4095 }
4096 }
4097
4098 if (!radius_have_var(cmd->argv[8])) {
4099 char *endp = NULL;
4100
4101 /* Make sure it's a number, at least. */
4102 (void) strtoul(cmd->argv[8], &endp, 10);
4103 if (endp && *endp) {
4104 CONF_ERROR(cmd, "invalid files parameter: not a number");
4105 }
4106 }
4107
4108 add_config_param_str(cmd->argv[0], 8, cmd->argv[1], cmd->argv[2],
4109 cmd->argv[3], cmd->argv[4], cmd->argv[5], cmd->argv[6],
4110 cmd->argv[7], cmd->argv[8]);
4111
4112 return PR_HANDLED(cmd);
4113 }
4114
4115 /* usage: RadiusRealm string */
4116 MODRET set_radiusrealm(cmd_rec *cmd) {
4117 CHECK_ARGS(cmd, 1);
4118 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
4119
4120 add_config_param_str(cmd->argv[0], 1, cmd->argv[1]);
4121 return PR_HANDLED(cmd);
4122 }
4123
4124 /* usage: RadiusUserInfo uid gid home shell */
4125 MODRET set_radiususerinfo(cmd_rec *cmd) {
4126 CHECK_ARGS(cmd, 4);
4127 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
4128
4129 if (!radius_have_var(cmd->argv[1])) {
4130 char *endp = NULL;
4131
4132 /* Make sure it's a number, at least. */
4133 (void) strtoul(cmd->argv[1], &endp, 10);
4134 if (endp && *endp) {
4135 CONF_ERROR(cmd, "invalid UID parameter: not a number");
4136 }
4137 }
4138
4139 if (!radius_have_var(cmd->argv[2])) {
4140 char *endp = NULL;
4141
4142 /* Make sure it's a number, at least. */
4143 (void) strtoul(cmd->argv[2], &endp, 10);
4144 if (endp && *endp)
4145 CONF_ERROR(cmd, "invalid GID parameter: not a number");
4146 }
4147
4148 if (!radius_have_var(cmd->argv[3])) {
4149 char *path;
4150
4151 path = cmd->argv[3];
4152 /* Make sure the path is absolute, at least. */
4153 if (*path != '/') {
4154 CONF_ERROR(cmd, "home relative path not allowed");
4155 }
4156 }
4157
4158 if (!radius_have_var(cmd->argv[4])) {
4159 char *path;
4160
4161 path = cmd->argv[4];
4162 /* Make sure the path is absolute, at least. */
4163 if (*path != '/') {
4164 CONF_ERROR(cmd, "shell relative path not allowed");
4165 }
4166 }
4167
4168 add_config_param_str(cmd->argv[0], 4, cmd->argv[1], cmd->argv[2],
4169 cmd->argv[3], cmd->argv[4]);
4170 return PR_HANDLED(cmd);
4171 }
4172
4173 /* usage: RadiusVendor name id */
4174 MODRET set_radiusvendor(cmd_rec *cmd) {
4175 config_rec *c = NULL;
4176 long id = 0;
4177 char *tmp = NULL;
4178
4179 CHECK_ARGS(cmd, 2);
4180 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
4181
4182 /* Make sure that the given vendor ID number is valid. */
4183 id = strtol(cmd->argv[2], &tmp, 10);
4184
4185 if (tmp && *tmp) {
4186 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": vendor id '", cmd->argv[2],
4187 "' is not a valid number", NULL));
4188 }
4189
4190 if (id < 0) {
4191 CONF_ERROR(cmd, "vendor id must be a positive number");
4192 }
4193
4194 c = add_config_param(cmd->argv[0], 2, NULL, NULL);
4195 c->argv[0] = pstrdup(c->pool, cmd->argv[1]);
4196 c->argv[1] = pcalloc(c->pool, sizeof(unsigned int));
4197 *((unsigned int *) c->argv[1]) = id;
4198
4199 return PR_HANDLED(cmd);
4200 }
4201
4202 /* Event handlers
4203 */
4204
4205 static void radius_exit_ev(const void *event_data, void *user_data) {
4206 if (radius_stop_accting() < 0) {
4207 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
4208 "error: unable to stop accounting: %s", strerror(errno));
4209 }
4210
4211 (void) close(radius_logfd);
4212 radius_logfd = -1;
4213 }
4214
4215 #if defined(PR_SHARED_MODULE)
4216 static void radius_mod_unload_ev(const void *event_data, void *user_data) {
4217 if (strcmp("mod_radius.c", (const char *) event_data) == 0) {
4218 pr_event_unregister(&radius_module, NULL, NULL);
4219
4220 if (radius_pool) {
4221 destroy_pool(radius_pool);
4222 radius_pool = NULL;
4223 }
4224
4225 close(radius_logfd);
4226 radius_logfd = -1;
4227 }
4228 }
4229 #endif /* PR_SHARED_MODULE */
4230
4231 static void radius_restart_ev(const void *event_data, void *user_data) {
4232
4233 /* Re-allocate the pool used by this module. */
4234 if (radius_pool) {
4235 destroy_pool(radius_pool);
4236 }
4237
4238 radius_pool = make_sub_pool(permanent_pool);
4239 pr_pool_tag(radius_pool, MOD_RADIUS_VERSION);
4240
4241 return;
4242 }
4243
4244 static void radius_sess_reinit_ev(const void *event_data, void *user_data) {
4245 int res;
4246
4247 /* A HOST command changed the main_server pointer; reinitialize ourselves. */
4248
4249 pr_event_unregister(&radius_module, "core.exit", radius_exit_ev);
4250 pr_event_unregister(&radius_module, "core.session-reinit",
4251 radius_sess_reinit_ev);
4252
4253 /* Reset defaults. */
4254 radius_engine = FALSE;
4255 radius_acct_server = NULL;
4256 radius_auth_server = NULL;
4257 (void) close(radius_logfd);
4258 radius_logfd = -1;
4259 radius_opts = 0UL;
4260 radius_nas_identifier_config = NULL;
4261 radius_vendor_name = "Unix";
4262 radius_vendor_id = 4;
4263 radius_realm = NULL;
4264
4265 radius_have_user_info = FALSE;
4266 radius_uid_attr_id = 0;
4267 radius_gid_attr_id = 0;
4268 radius_home_attr_id = 0;
4269 radius_shell_attr_id = 0;
4270
4271 radius_have_group_info = FALSE;
4272 radius_prime_group_name_attr_id = 0;
4273 radius_addl_group_names_attr_id = 0;
4274 radius_addl_group_ids_attr_id = 0;
4275 radius_prime_group_name = NULL;
4276 radius_addl_group_count = 0;
4277 radius_addl_group_names = 0;
4278 radius_addl_group_names_str = NULL;
4279 radius_addl_group_ids = NULL;
4280 radius_addl_group_ids_str = NULL;
4281
4282 radius_have_quota_info = FALSE;
4283 radius_quota_per_sess_attr_id = 0;
4284 radius_quota_limit_type_attr_id = 0;
4285 radius_quota_bytes_in_attr_id = 0;
4286 radius_quota_bytes_out_attr_id = 0;
4287 radius_quota_bytes_xfer_attr_id = 0;
4288 radius_quota_files_in_attr_id = 0;
4289 radius_quota_files_out_attr_id = 0;
4290 radius_quota_files_xfer_attr_id = 0;
4291 radius_quota_per_sess = NULL;
4292 radius_quota_limit_type = NULL;
4293 radius_quota_bytes_in = NULL;
4294 radius_quota_bytes_out = NULL;
4295 radius_quota_bytes_xfer = NULL;
4296 radius_quota_files_in = NULL;
4297 radius_quota_files_out = NULL;
4298 radius_quota_files_xfer = NULL;
4299
4300 radius_have_other_info = FALSE;
4301
4302 /* Note that we deliberately leave the radius_session_start time_t alone;
4303 * it is initialized at the start of the session, regardless of vhost.
4304 */
4305
4306 res = radius_sess_init();
4307 if (res < 0) {
4308 pr_session_disconnect(&radius_module,
4309 PR_SESS_DISCONNECT_SESSION_INIT_FAILED, NULL);
4310 }
4311 }
4312
4313 /* Initialization routines
4314 */
4315
4316 static int radius_sess_init(void) {
4317 int res = 0;
4318 config_rec *c = NULL;
4319 radius_server_t **current_server = NULL;
4320
4321 pr_event_register(&radius_module, "core.session-reinit",
4322 radius_sess_reinit_ev, NULL);
4323
4324 /* Is RadiusEngine on? */
4325 c = find_config(main_server->conf, CONF_PARAM, "RadiusEngine", FALSE);
4326 if (c != NULL) {
4327 radius_engine = *((int *) c->argv[0]);
4328 }
4329
4330 if (radius_engine == FALSE) {
4331 return 0;
4332 }
4333
4334 res = radius_openlog();
4335 if (res < 0) {
4336 if (res == -1) {
4337 pr_log_pri(PR_LOG_NOTICE, MOD_RADIUS_VERSION
4338 ": notice: unable to open RadiusLog: %s", strerror(errno));
4339
4340 } else if (res == PR_LOG_WRITABLE_DIR) {
4341 pr_log_pri(PR_LOG_WARNING, MOD_RADIUS_VERSION
4342 ": notice: unable to open RadiusLog: parent directory is "
4343 "world-writable");
4344
4345 } else if (res == PR_LOG_SYMLINK) {
4346 pr_log_pri(PR_LOG_WARNING, MOD_RADIUS_VERSION
4347 ": notice: unable to open RadiusLog: cannot log to a symbolic link");
4348 }
4349 }
4350
4351 /* Initialize session variables */
4352 time(&radius_session_start);
4353
4354 c = find_config(main_server->conf, CONF_PARAM, "RadiusOptions", FALSE);
4355 while (c != NULL) {
4356 unsigned long opts = 0;
4357
4358 pr_signals_handle();
4359
4360 opts = *((unsigned long *) c->argv[0]);
4361 radius_opts |= opts;
4362
4363 c = find_config_next(c, c->next, CONF_PARAM, "RadiusOptions", FALSE);
4364 }
4365
4366 c = find_config(main_server->conf, CONF_PARAM, "RadiusNASIdentifier", FALSE);
4367 if (c != NULL) {
4368 radius_nas_identifier_config = c->argv[0];
4369
4370 pr_trace_msg(trace_channel, 3,
4371 "RadiusNASIdentifier '%s' configured", radius_nas_identifier_config);
4372 }
4373
4374 c = find_config(main_server->conf, CONF_PARAM, "RadiusVendor", FALSE);
4375 if (c != NULL) {
4376 radius_vendor_name = c->argv[0];
4377 radius_vendor_id = *((unsigned int *) c->argv[1]);
4378
4379 pr_trace_msg(trace_channel, 3,
4380 "RadiusVendor '%s' (Vendor-Id %u) configured", radius_vendor_name,
4381 radius_vendor_id);
4382 }
4383
4384 /* Find any configured RADIUS servers for this session */
4385 c = find_config(main_server->conf, CONF_PARAM, "RadiusAcctServer", FALSE);
4386
4387 /* Point to the start of the accounting server list. */
4388 current_server = &radius_acct_server;
4389
4390 while (c != NULL) {
4391 pr_signals_handle();
4392
4393 *current_server = *((radius_server_t **) c->argv[0]);
4394 current_server = &(*current_server)->next;
4395
4396 c = find_config_next(c, c->next, CONF_PARAM, "RadiusAcctServer", FALSE);
4397 }
4398
4399 if (radius_acct_server == NULL) {
4400 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
4401 "notice: no configured RadiusAcctServers, no accounting");
4402 }
4403
4404 c = find_config(main_server->conf, CONF_PARAM, "RadiusAuthServer", FALSE);
4405
4406 /* Point to the start of the authentication server list. */
4407 current_server = &radius_auth_server;
4408
4409 while (c != NULL) {
4410 pr_signals_handle();
4411
4412 *current_server = *((radius_server_t **) c->argv[0]);
4413 current_server = &(*current_server)->next;
4414
4415 c = find_config_next(c, c->next, CONF_PARAM, "RadiusAuthServer", FALSE);
4416 }
4417
4418 if (radius_auth_server == NULL) {
4419 (void) pr_log_writefile(radius_logfd, MOD_RADIUS_VERSION,
4420 "notice: no configured RadiusAuthServers, no authentication");
4421 }
4422
4423 /* Prepare any configured fake user information. */
4424 c = find_config(main_server->conf, CONF_PARAM, "RadiusUserInfo", FALSE);
4425 if (c != NULL) {
4426
4427 /* Process the parameter string stored in the found config_rec. */
4428 radius_process_user_info(c);
4429
4430 /* Only use the faked information if authentication via RADIUS is
4431 * possible. The radius_have_user_info flag will be set to
4432 * TRUE by radius_process_user_info(), unless there was some
4433 * illegal value.
4434 */
4435 if (radius_auth_server == NULL) {
4436 radius_have_user_info = FALSE;
4437 }
4438 }
4439
4440 /* If the RadiusUserInfo directive has not been set (or if it has been
4441 * set, but it was not well-formed), then we will be acting in a
4442 * "yes/no" style of authentication, similar to PAM.
4443 *
4444 * The Auth API tries to use the same module for authenticating a user
4445 * as the one which provided information for that user. If we are not
4446 * providing user information, then we won't get a chance to authenticate
4447 * the user -- unless we disable that Auth API behavior.
4448 */
4449 if (radius_have_user_info == FALSE) {
4450 if (pr_auth_add_auth_only_module("mod_radius.c") < 0) {
4451 pr_log_debug(DEBUG2, "error adding 'mod_radius.c' to auth-only module "
4452 "list: %s", strerror(errno));
4453 }
4454 }
4455
4456 /* Prepare any configured fake group information. */
4457 c = find_config(main_server->conf, CONF_PARAM, "RadiusGroupInfo", FALSE);
4458 if (c != NULL) {
4459
4460 /* Process the parameter string stored in the found config_rec. */
4461 radius_process_group_info(c);
4462
4463 /* Only use the faked information if authentication via RADIUS is
4464 * possible. The radius_have_group_info flag will be set to
4465 * TRUE by radius_process_group_info(), unless there was some
4466 * illegal value.
4467 */
4468 if (radius_auth_server == NULL) {
4469 radius_have_group_info = FALSE;
4470 }
4471 }
4472
4473 /* Prepare any configure quota information. */
4474 c = find_config(main_server->conf, CONF_PARAM, "RadiusQuotaInfo", FALSE);
4475 if (c != NULL) {
4476 radius_process_quota_info(c);
4477
4478 if (radius_auth_server == NULL) {
4479 radius_have_quota_info = FALSE;
4480 }
4481 }
4482
4483 /* Check for a configured RadiusRealm. If present, use username + realm
4484 * in RADIUS packets as the user name, else just use the username.
4485 */
4486 radius_realm = get_param_ptr(main_server->conf, "RadiusRealm", FALSE);
4487 if (radius_realm) {
4488 pr_trace_msg(trace_channel, 3,
4489 "using RadiusRealm '%s'", radius_realm);
4490 }
4491
4492 pr_event_register(&radius_module, "core.exit", radius_exit_ev, NULL);
4493 return 0;
4494 }
4495
4496 static int radius_init(void) {
4497
4498 /* Allocate a pool for this module's use. */
4499 radius_pool = make_sub_pool(permanent_pool);
4500 pr_pool_tag(radius_pool, MOD_RADIUS_VERSION);
4501
4502 #if defined(PR_SHARED_MODULE)
4503 pr_event_register(&radius_module, "core.module-unload",
4504 radius_mod_unload_ev, NULL);
4505 #endif /* PR_SHARED_MODULE */
4506
4507 /* Register a restart handler, to cleanup the pool. */
4508 pr_event_register(&radius_module, "core.restart", radius_restart_ev, NULL);
4509
4510 return 0;
4511 }
4512
4513 /* Module API tables
4514 */
4515
4516 static conftable radius_conftab[] = {
4517 { "RadiusAcctServer", set_radiusacctserver, NULL },
4518 { "RadiusAuthServer", set_radiusauthserver, NULL },
4519 { "RadiusEngine", set_radiusengine, NULL },
4520 { "RadiusGroupInfo", set_radiusgroupinfo, NULL },
4521 { "RadiusLog", set_radiuslog, NULL },
4522 { "RadiusNASIdentifier", set_radiusnasidentifier,NULL },
4523 { "RadiusOptions", set_radiusoptions, NULL },
4524 { "RadiusQuotaInfo", set_radiusquotainfo, NULL },
4525 { "RadiusRealm", set_radiusrealm, NULL },
4526 { "RadiusUserInfo", set_radiususerinfo, NULL },
4527 { "RadiusVendor", set_radiusvendor, NULL },
4528 { NULL }
4529 };
4530
4531 static cmdtable radius_cmdtab[] = {
4532 { HOOK, "radius_quota_lookup", G_NONE,
4533 radius_quota_lookup, FALSE, FALSE },
4534
4535 { PRE_CMD, C_PASS, G_NONE, radius_pre_pass, FALSE, FALSE, CL_AUTH },
4536 { POST_CMD, C_PASS, G_NONE, radius_post_pass, FALSE, FALSE, CL_AUTH },
4537 { POST_CMD_ERR, C_PASS, G_NONE, radius_post_pass_err, FALSE, FALSE, CL_AUTH },
4538 { 0, NULL }
4539 };
4540
4541 static authtable radius_authtab[] = {
4542 { 0, "setpwent", radius_setpwent },
4543 { 0, "setgrent", radius_setgrent },
4544 { 0, "endpwent", radius_endpwent },
4545 { 0, "endgrent", radius_endgrent },
4546 { 0, "getpwent", radius_getpwent },
4547 { 0, "getgrent", radius_getgrent },
4548 { 0, "getpwnam", radius_getpwnam },
4549 { 0, "getgrnam", radius_getgrnam },
4550 { 0, "getpwuid", radius_getpwuid },
4551 { 0, "getgrgid", radius_getgrgid },
4552 { 0, "getgroups", radius_getgroups },
4553 { 0, "auth", radius_auth },
4554 { 0, "check", radius_check },
4555 { 0, "uid2name", radius_uid2name },
4556 { 0, "gid2name", radius_gid2name },
4557 { 0, "name2uid", radius_name2uid },
4558 { 0, "name2gid", radius_name2gid },
4559 { 0, NULL }
4560 };
4561
4562 module radius_module = {
4563
4564 /* Always NULL */
4565 NULL, NULL,
4566
4567 /* Module API version 2.0 */
4568 0x20,
4569
4570 /* Module name */
4571 "radius",
4572
4573 /* Module configuration handler table */
4574 radius_conftab,
4575
4576 /* Module command handler table */
4577 radius_cmdtab,
4578
4579 /* Module authentication handler table */
4580 radius_authtab,
4581
4582 /* Module initialization function */
4583 radius_init,
4584
4585 /* Module session initialization function */
4586 radius_sess_init,
4587
4588 /* Module version */
4589 MOD_RADIUS_VERSION
4590 };
4591