1 /* This file is part of GNU Radius
2 Copyright (C) 2000,2001,2002,2003,2004,
3 2006,2007,2008 Free Software Foundation, Inc.
4
5 Written by Sergey Poznyakoff
6
7 GNU Radius is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 GNU Radius is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Radius; if not, write to the Free Software Foundation,
19 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24
25 #include <sys/types.h>
26 #include <sys/time.h>
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <ctype.h>
31 #include <pwd.h>
32 #include <time.h>
33 #include <unistd.h>
34 #include <signal.h>
35 #include <errno.h>
36 #include <sys/wait.h>
37
38 #if defined(HAVE_CRYPT_H)
39 # include <crypt.h>
40 #endif
41
42 #if defined(PWD_SHADOW)
43 # if PWD_SHADOW == SHADOW
44 # include <shadow.h>
45 # define STRUCT_SHADOW_PASSWD struct spwd
46 # define SHADOW_PASSWD_ENCRYPTED(s) ((s)->sp_pwdp)
47 # define GETSPNAM getspnam
48 # if defined(HAVE_STRUCT_SPWD_SP_EXPIRE)
49 # define SHADOW_PASSWD_EXPIRE(s) ((s)->sp_expire)
50 # endif
51 # else /*OSFC2*/
52 # include <sys/security.h>
53 # include <prot.h>
54 # define STRUCT_SHADOW_PASSWD struct pr_passwd
55 # define SHADOW_PASSWD_ENCRYPTED(s) ((s)->ufld.fd_encrypt)
56 # define GETSPNAM getprpwnam
57 # ifdef HAVE_STRUCT_PR_PASSWD_UFLG_FG_LOCK
58 # define SHADOW_PASSWD_LOCK(s) ((s)->->uflg.fg_lock)
59 # endif
60 # endif
61 #else
62 # define STRUCT_SHADOW_PASSWD struct passwd
63 # define GETSPNAM(n) NULL
64 # define SHADOW_PASSWD_ENCRYPTED(s) NULL
65 #endif
66
67 #include <radiusd.h>
68 #include <timestr.h>
69 #include <rewrite.h>
70
71 char *username_valid_chars;
72
73 /* Check if the username is valid. Valid usernames consist of
74 alphanumeric characters and symbols from username_valid_chars[]
75 array */
76 int
check_user_name(char * p)77 check_user_name(char *p)
78 {
79 for (; *p && (isalnum(*p) || strchr(username_valid_chars, *p)); p++)
80 ;
81 return *p;
82 }
83
84 LOCK_DECLARE(lock)
85
86 #ifdef EMBEDDED_EXPIRATION_INFO
87 static char base64[] = /* 0 ... 63 => ascii - 64 */
88 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
89
90 static int
from_base64(u_char * data,int len,unsigned int * value)91 from_base64(u_char *data, int len, unsigned int *value)
92 {
93 int i;
94
95 *value = 0;
96 for (i = len-1; i >= 0; i--) {
97 char *p = strchr(base64, data[i]);
98 if (!p)
99 return 1;
100 *value <<= 6;
101 *value += p - base64;
102 }
103 return 0;
104 }
105
106 static int
decode_aging_info(char * p,u_int * maxweeks,u_int * minweeks,u_int * lastchange)107 decode_aging_info(char *p, u_int *maxweeks, u_int *minweeks, u_int *lastchange)
108 {
109 if (from_base64(p, 1, maxweeks))
110 return 1;
111 p++;
112 if (from_base64(p, 1, minweeks))
113 return 1;
114 p++;
115 if (from_base64(p, 2, lastchange))
116 return 1;
117 if (p[2])
118 return 1;
119 return 0;
120 }
121 #endif
122
123 static enum auth_status
unix_expiration(char * name,time_t * exp)124 unix_expiration(char *name, time_t *exp)
125 {
126 enum auth_status status = auth_ok;
127 #ifdef SHADOW_PASSWD_EXPIRE
128 STRUCT_SHADOW_PASSWD *spwd = GETSPNAM(name);
129
130 if (spwd && SHADOW_PASSWD_EXPIRE(spwd) > 0) {
131 time_t t = time(NULL);
132 if (t > SHADOW_PASSWD_EXPIRE(spwd) * SECONDS_PER_DAY)
133 status = auth_account_expired;
134 else {
135 *exp = SHADOW_PASSWD_EXPIRE(spwd) * SECONDS_PER_DAY - t;
136 status = auth_valid;
137 }
138 }
139 #elif defined(HAVE_STRUCT_PASSWD_PW_EXPIRE)
140 struct passwd *pwd;
141 struct timeval tv;
142 time_t t = 0;
143
144 if (pwd = getpwnam(name)) {
145 gettimeofday(&tv, NULL);
146 if (pwd->pw_expire) {
147 if (tv.tv_sec >= pwd->pw_expire)
148 status = auth_account_expired;
149 else {
150 t = pwd->pw_change - tv.tv_sec;
151 status = auth_valid;
152 }
153 }
154 # if defined(HAVE_STRUCT_PASSWD_PW_CHANGE)
155 if (pwd->pw_change) {
156 if (tv.tv_sec >= pwd->pw_change)
157 status = auth_password_expired;
158 else if (status == auth_ok
159 || pwd->pw_change - tv.tv_sec < t) {
160 t = pwd->pw_change - tv.tv_sec;
161 status = auth_valid;
162 }
163 }
164 *exp = t;
165 # endif
166 }
167 #endif
168 #ifdef EMBEDDED_EXPIRATION_INFO
169 if (status == auth_ok) {
170 struct passwd *pwd;
171 char *p;
172 #define SECS_IN_WEEK 604800
173
174 if (pwd = getpwnam(name)) {
175 p = strchr(pwd->pw_passwd, ',');
176 if (p) {
177 u_int maxweeks, minweeks, lastchange;
178
179 if (decode_aging_info(p+1,
180 &maxweeks,
181 &minweeks,
182 &lastchange) == 0) {
183 time_t now = time(NULL);
184 time_t nweeks = now / SECS_IN_WEEK
185 - lastchange;
186
187 if (maxweeks == minweeks)
188 return auth_password_expired;
189
190 if (nweeks >= minweeks
191 && nweeks >= maxweeks)
192 return auth_password_expired;
193
194 *exp = (maxweeks - nweeks)
195 * SECS_IN_WEEK
196 + now % SECS_IN_WEEK;
197 status = auth_valid;
198 } else { /* Invalid password data? */
199 grad_log(GRAD_LOG_NOTICE,
200 _("Invalid password aging information for user '%s'"), name);
201 status = auth_fail;
202 }
203 }
204 }
205 }
206 #endif
207 return status;
208 }
209
210 static int
unix_pass(char * name,char * passwd)211 unix_pass(char *name, char *passwd)
212 {
213 int rc;
214 char *encpw;
215 int pwlen;
216 char *encrypted_pass = NULL;
217 STRUCT_SHADOW_PASSWD *spwd;
218
219 LOCK_SET(lock);
220 if (spwd = GETSPNAM(name))
221 encrypted_pass = SHADOW_PASSWD_ENCRYPTED(spwd);
222 else { /* Try to get encrypted password from password file */
223 struct passwd *pwd;
224
225 if (pwd = getpwnam(name))
226 encrypted_pass = pwd->pw_passwd;
227 }
228
229 #ifdef SHADOW_PASSWD_LOCK
230 if (encrypted_pass) {
231 /* Check if the account is locked. */
232 if (SHADOW_PASSWD_LOCK(spwd) != 1) {
233 grad_log(GRAD_LOG_NOTICE,
234 "unix_pass: [%s]: %s",
235 name, _("account locked"));
236 encrypted_pass = NULL;
237 }
238 }
239 #endif
240
241 if (encrypted_pass) {
242 if (encrypted_pass[0] == 0)
243 encrypted_pass = NULL;
244 else
245 encrypted_pass = grad_estrdup(encrypted_pass);
246 }
247
248 LOCK_RELEASE(lock);
249
250 if (!encrypted_pass)
251 return -1;
252
253 /*
254 * Check encrypted password.
255 */
256 pwlen = strlen(encrypted_pass);
257 encpw = grad_emalloc(pwlen+1);
258 #ifdef EMBEDDED_EXPIRATION_INFO
259 {
260 /* Some systems append expiration data to the encrypted password */
261 char *p = strchr(encrypted_pass, ',');
262 if (p)
263 pwlen = p - encrypted_pass;
264 }
265 #endif
266 rc = grad_md5crypt(passwd, encrypted_pass, encpw, pwlen+1) == NULL
267 || strlen (encpw) != pwlen
268 || memcmp(encpw, encrypted_pass, pwlen);
269 grad_free(encpw);
270 grad_free(encrypted_pass);
271 if (rc)
272 return -1;
273
274 return 0;
275 }
276
277 int
rad_auth_check_username(radiusd_request_t * radreq,int activefd)278 rad_auth_check_username(radiusd_request_t *radreq, int activefd)
279 {
280 grad_avp_t *namepair = grad_avl_find(radreq->request->avlist,
281 DA_USER_NAME);
282
283 log_open(GRAD_LOG_AUTH);
284
285 if (grad_avp_null_string_p(namepair))
286 grad_log_req(GRAD_LOG_ERR, radreq->request, _("No username"));
287 else if (check_user_name(namepair->avp_strvalue))
288 grad_log_req(GRAD_LOG_ERR, radreq->request, _("Malformed username"));
289 else
290 return 0;
291
292 /* Process a malformed request */
293 if (auth_reject_malformed_names)
294 radius_send_reply(RT_ACCESS_REJECT, radreq,
295 NULL,
296 message_text[MSG_ACCESS_DENIED],
297 activefd);
298 else
299 stat_inc(auth, radreq->request->ipaddr, num_bad_req);
300 return -1;
301 }
302
303 /* Initial step of authentication. */
304 int
rad_auth_init(radiusd_request_t * radreq,int activefd)305 rad_auth_init(radiusd_request_t *radreq, int activefd)
306 {
307 grad_locus_t loc;
308
309 log_open(GRAD_LOG_AUTH);
310
311 if (auth_detail)
312 write_detail(radreq, REQ_AUTH_ZERO, R_AUTH);
313
314 /*
315 * See if the user has access to this huntgroup.
316 */
317 if (!huntgroup_access(radreq, &loc)) {
318 grad_log_req(GRAD_LOG_NOTICE, radreq->request,
319 _("Access denied by huntgroup %s:%d"),
320 loc.file, loc.line);
321 radius_send_reply(RT_ACCESS_REJECT, radreq,
322 radreq->request->avlist, NULL, activefd);
323 return -1;
324 }
325
326 return 0;
327 }
328
329 /* ****************************************************************************
330 * Authentication state machine.
331 */
332
333 enum auth_state {
334 as_init,
335 as_validate,
336 as_disable,
337 as_realmuse,
338 as_simuse,
339 as_time,
340 as_scheme,
341 as_ipaddr,
342 as_exec_wait,
343 as_cleanup_cbkid,
344 as_menu_challenge,
345 as_ack,
346 as_exec_nowait,
347 as_stop,
348 as_reject,
349 as_reject_cleanup,
350 AS_COUNT
351 };
352
353 enum list_id {
354 L_null,
355 L_req,
356 L_reply,
357 L_check
358 };
359
360 typedef struct auth_mach {
361 radiusd_request_t *req;
362 grad_avp_t *user_check;
363 grad_avp_t *user_reply;
364 int activefd;
365
366 grad_avp_t *namepair;
367 grad_avp_t *check_pair;
368 char userpass[GRAD_STRING_LENGTH+1];
369
370 char *user_msg;
371 struct obstack msg_stack;
372
373 enum auth_state state;
374 } AUTH_MACH;
375
376 static void sfn_init(AUTH_MACH*);
377 static void sfn_validate(AUTH_MACH*);
378 static void sfn_scheme(AUTH_MACH*);
379 static void sfn_disable(AUTH_MACH*);
380 static void sfn_realmuse(AUTH_MACH*);
381 static void sfn_simuse(AUTH_MACH*);
382 static void sfn_time(AUTH_MACH*);
383 static void sfn_ipaddr(AUTH_MACH*);
384 static void sfn_exec_wait(AUTH_MACH*);
385 static void sfn_cleanup_cbkid(AUTH_MACH*);
386 static void sfn_menu_challenge(AUTH_MACH*);
387 static void sfn_ack(AUTH_MACH*);
388 static void sfn_exec_nowait(AUTH_MACH*);
389 static void sfn_reject(AUTH_MACH*);
390 static void sfn_reject_cleanup(AUTH_MACH *m);
391 static int check_expiration(AUTH_MACH *m);
392
393
394 struct auth_state_s {
395 enum auth_state this;
396 enum auth_state next;
397 int attr;
398 enum list_id list;
399 void (*sfn)(AUTH_MACH*);
400 };
401
402 struct auth_state_s states[] = {
403 { as_init, as_validate,
404 0, L_null, sfn_init },
405
406 { as_validate, as_disable,
407 0, L_null, sfn_validate },
408
409 { as_disable, as_realmuse,
410 0, L_null, sfn_disable },
411
412 { as_realmuse, as_simuse,
413 0, L_null, sfn_realmuse },
414
415 { as_simuse, as_time,
416 DA_SIMULTANEOUS_USE, L_check, sfn_simuse },
417
418 { as_time, as_scheme,
419 DA_LOGIN_TIME, L_check, sfn_time },
420
421 { as_scheme, as_ipaddr,
422 DA_SCHEME_PROCEDURE, L_reply, sfn_scheme },
423
424 { as_ipaddr, as_exec_wait,
425 0, L_null, sfn_ipaddr },
426
427 { as_exec_wait, as_cleanup_cbkid,
428 DA_EXEC_PROGRAM_WAIT, L_reply, sfn_exec_wait },
429
430 { as_cleanup_cbkid,as_menu_challenge,
431 DA_CALLBACK_ID, L_reply, sfn_cleanup_cbkid },
432
433 { as_menu_challenge, as_ack,
434 DA_MENU, L_reply, sfn_menu_challenge },
435
436 { as_ack, as_exec_nowait,
437 0, L_null, sfn_ack },
438
439 { as_exec_nowait, as_stop,
440 DA_EXEC_PROGRAM, L_reply, sfn_exec_nowait },
441
442 { as_stop, as_stop,
443 0, L_null, NULL },
444
445 { as_reject, as_stop,
446 0, L_null, sfn_reject },
447
448 { as_reject_cleanup, as_reject,
449 0, L_null, sfn_reject_cleanup },
450 };
451
452 static int is_log_mode(AUTH_MACH *m, int mask);
453 static void auth_format_msg(AUTH_MACH *m, int msg_id);
454 static char *auth_finish_msg(AUTH_MACH *m);
455
456 static void
auth_log(AUTH_MACH * m,const char * diag,const char * pass,const char * reason,const char * addstr)457 auth_log(AUTH_MACH *m, const char *diag, const char *pass,
458 const char *reason, const char *addstr)
459 {
460 if (reason)
461 grad_log_req(GRAD_LOG_NOTICE, m->req->request,
462 "%s [%s%s%s]: %s%s",
463 diag,
464 m->namepair->avp_strvalue,
465 pass ? "/" : "",
466 pass ? pass : "",
467 reason,
468 addstr ? addstr : "");
469 else
470 grad_log_req(GRAD_LOG_NOTICE, m->req->request,
471 "%s [%s%s%s]",
472 diag,
473 m->namepair->avp_strvalue,
474 pass ? "/" : "",
475 pass ? pass : "");
476 }
477
478 int
is_log_mode(AUTH_MACH * m,int mask)479 is_log_mode(AUTH_MACH *m, int mask)
480 {
481 int mode = log_mode;
482 int xmask = 0;
483 #ifdef DA_LOG_MODE_MASK
484 grad_avp_t *p;
485
486 for (p = grad_avl_find(m->user_check, DA_LOG_MODE_MASK);
487 p;
488 p = p->next ? grad_avl_find(p->next, DA_LOG_MODE_MASK) : NULL)
489 xmask |= p->avp_lvalue;
490 for (p = grad_avl_find(m->req->request->avlist, DA_LOG_MODE_MASK);
491 p;
492 p = p->next ? grad_avl_find(p->next, DA_LOG_MODE_MASK) : NULL)
493 xmask |= p->avp_lvalue;
494 #endif
495 return (mode & ~xmask) & mask;
496 }
497
498 void
auth_format_msg(AUTH_MACH * m,int msg_id)499 auth_format_msg(AUTH_MACH *m, int msg_id)
500 {
501 int len = strlen(message_text[msg_id]);
502 obstack_grow(&m->msg_stack, message_text[msg_id], len);
503 }
504
505 char *
auth_finish_msg(AUTH_MACH * m)506 auth_finish_msg(AUTH_MACH *m)
507 {
508 if (m->user_msg)
509 obstack_grow(&m->msg_stack, m->user_msg, strlen(m->user_msg));
510 obstack_1grow(&m->msg_stack, 0);
511 return radius_xlate(&m->msg_stack, obstack_finish(&m->msg_stack),
512 m->req->request, m->user_reply);
513 }
514
515 /* Check password. */
516 static enum auth_status
rad_check_password(radiusd_request_t * radreq,AUTH_MACH * m,time_t * exp)517 rad_check_password(radiusd_request_t *radreq, AUTH_MACH *m, time_t *exp)
518 {
519 char *ptr;
520 char *real_password = NULL;
521 char name[GRAD_STRING_LENGTH];
522 grad_avp_t *auth_item;
523 grad_avp_t *tmp;
524 int auth_type = -1;
525 int length;
526 enum auth_status result = auth_ok;
527 char *authdata = NULL;
528 char pw_digest[GRAD_AUTHENTICATOR_LENGTH];
529 int pwlen;
530 char *pwbuf;
531 char *challenge;
532 int challenge_len;
533
534 m->userpass[0] = 0;
535
536 /* Process immediate authentication types */
537 if ((tmp = grad_avl_find(m->user_check, DA_AUTH_TYPE)) != NULL)
538 auth_type = tmp->avp_lvalue;
539
540 switch (auth_type) {
541 case DV_AUTH_TYPE_ACCEPT:
542 return auth_ok;
543
544 case DV_AUTH_TYPE_REJECT:
545 return auth_reject;
546
547 case DV_AUTH_TYPE_IGNORE:
548 return auth_ignore;
549 }
550
551 /* Find the password sent by the user. If it's not present,
552 authentication fails. */
553
554 if (auth_item = grad_avl_find(radreq->request->avlist, DA_CHAP_PASSWORD))
555 auth_type = DV_AUTH_TYPE_LOCAL;
556 else
557 auth_item = grad_avl_find(radreq->request->avlist, DA_USER_PASSWORD);
558
559 /* Decrypt the password. */
560 if (auth_item) {
561 if (auth_item->avp_strlength == 0)
562 m->userpass[0] = 0;
563 else
564 req_decrypt_password(m->userpass, radreq->request,
565 auth_item);
566 } else /* if (auth_item == NULL) */
567 return auth_fail;
568
569 /* Set up authentication data */
570 if ((tmp = grad_avl_find(m->user_check, DA_AUTH_DATA)) != NULL)
571 authdata = tmp->avp_strvalue;
572
573 /* Find the 'real' password */
574 tmp = grad_avl_find(m->user_check, DA_USER_PASSWORD);
575 if (tmp)
576 real_password = grad_estrdup(tmp->avp_strvalue);
577 else if (tmp = grad_avl_find(m->user_check, DA_PASSWORD_LOCATION)) {
578 switch (tmp->avp_lvalue) {
579 case DV_PASSWORD_LOCATION_SQL:
580 #ifdef USE_SQL
581 real_password = radiusd_sql_pass(radreq, authdata);
582 if (!real_password)
583 return auth_nouser;
584 grad_avl_add_pair(&m->user_check,
585 grad_avp_create_string(DA_USER_PASSWORD, real_password));
586 break;
587 #endif
588 /* NOTE: add any new location types here */
589 default:
590 grad_log(GRAD_LOG_ERR,
591 _("unknown Password-Location value: %ld"),
592 tmp->avp_lvalue);
593 return auth_fail;
594 }
595 }
596
597 /* Process any prefixes/suffixes. */
598 strip_username(1, m->namepair->avp_strvalue, m->user_check, name);
599
600 GRAD_DEBUG4(1, "auth_type=%d, userpass=%s, name=%s, password=%s",
601 auth_type, m->userpass, name,
602 real_password ? real_password : "NONE");
603
604 switch (auth_type) {
605 case DV_AUTH_TYPE_SYSTEM:
606 GRAD_DEBUG(1, "auth: System");
607 if (unix_pass(name, m->userpass) != 0)
608 result = auth_fail;
609 else
610 result = unix_expiration(name, exp);
611 break;
612
613 case DV_AUTH_TYPE_PAM:
614 #ifdef USE_PAM
615 GRAD_DEBUG(1, "auth: Pam");
616 /* Provide defaults for authdata */
617 if (authdata == NULL &&
618 (tmp = grad_avl_find(m->user_check, DA_PAM_AUTH)) != NULL) {
619 authdata = tmp->avp_strvalue;
620 }
621 authdata = authdata ? authdata : PAM_DEFAULT_TYPE;
622 if (pam_pass(name, m->userpass, authdata, &m->user_msg) != 0)
623 result = auth_fail;
624 #else
625 grad_log_req(GRAD_LOG_ERR, radreq->request,
626 _("PAM authentication not available"));
627 result = auth_nouser;
628 #endif
629 break;
630
631 case DV_AUTH_TYPE_CRYPT_LOCAL:
632 GRAD_DEBUG(1, "auth: Crypt");
633 if (real_password == NULL) {
634 result = auth_fail;
635 break;
636 }
637 pwlen = strlen(real_password)+1;
638 pwbuf = grad_emalloc(pwlen);
639 if (!grad_md5crypt(m->userpass, real_password, pwbuf, pwlen))
640 result = auth_fail;
641 else if (strcmp(real_password, pwbuf) != 0)
642 result = auth_fail;
643 GRAD_DEBUG1(1, "pwbuf: %s", pwbuf);
644 grad_free(pwbuf);
645 break;
646
647 case DV_AUTH_TYPE_LOCAL:
648 GRAD_DEBUG(1, "auth: Local");
649 /* Local password is just plain text. */
650 if (auth_item->attribute != DA_CHAP_PASSWORD) {
651 if (real_password == NULL ||
652 strcmp(real_password, m->userpass) != 0)
653 result = auth_fail;
654 break;
655 }
656
657 /* CHAP: RFC 2865, page 7
658 The RADIUS server looks up a password based on the
659 User-Name, encrypts the challenge using MD5 on the
660 CHAP ID octet, that password, and the CHAP challenge
661 (from the CHAP-Challenge attribute if present,
662 otherwise from the Request Authenticator), and compares
663 that result to the CHAP-Password. If they match, the
664 server sends back an Access-Accept, otherwise it sends
665 back an Access-Reject. */
666
667 /* Provide some userpass in case authentication fails */
668 strcpy(m->userpass, "{chap-password}");
669
670 if (real_password == NULL) {
671 result = auth_fail;
672 break;
673 }
674
675 /* Compute the length of the password buffer and
676 allocate it */
677 length = strlen(real_password);
678
679 if (tmp = grad_avl_find(radreq->request->avlist,
680 DA_CHAP_CHALLENGE)) {
681 challenge = tmp->avp_strvalue;
682 challenge_len = tmp->avp_strlength;
683 } else {
684 challenge = radreq->request->authenticator;
685 challenge_len = GRAD_AUTHENTICATOR_LENGTH;
686 }
687
688 pwlen = 1 + length + challenge_len;
689 pwbuf = grad_emalloc(pwlen);
690
691 ptr = pwbuf;
692 *ptr++ = *auth_item->avp_strvalue;
693 memcpy(ptr, real_password, length);
694 ptr += length;
695 memcpy(ptr, challenge, challenge_len);
696
697 /* Compute the MD5 hash */
698 grad_md5_calc(pw_digest, (u_char*) pwbuf, pwlen);
699 grad_free(pwbuf);
700
701 /* Compare them */
702 if (memcmp(pw_digest, auth_item->avp_strvalue + 1,
703 GRAD_CHAP_VALUE_LENGTH) != 0)
704 result = auth_fail;
705 else
706 strcpy(m->userpass, real_password);
707 break;
708
709 default:
710 /* Try loadable modules. */
711 result = scheme_try_auth(auth_type, radreq,
712 m->user_check,
713 &m->user_reply) ? auth_fail : auth_ok;
714 break;
715 }
716
717 if (real_password) {
718 /* just in case: */
719 memset(real_password, 0, strlen(real_password));
720 grad_free(real_password);
721 }
722 return result;
723 }
724
725 /* Check if account has expired, and if user may login now. */
726 enum auth_status
radius_check_expiration(AUTH_MACH * m,time_t * exp)727 radius_check_expiration(AUTH_MACH *m, time_t *exp)
728 {
729 grad_avp_t *pair;
730
731 if (pair = grad_avl_find(m->user_check, DA_EXPIRATION)) {
732 struct timeval tv;
733 gettimeofday(&tv, NULL);
734 if (tv.tv_sec > pair->avp_lvalue)
735 return auth_account_expired;
736 *exp = pair->avp_lvalue - tv.tv_sec;
737 return auth_valid;
738 }
739 return auth_ok;
740 }
741
742
743 int
rad_authenticate(radiusd_request_t * radreq,int activefd)744 rad_authenticate(radiusd_request_t *radreq, int activefd)
745 {
746 enum auth_state oldstate;
747 struct auth_state_s *sp;
748 struct auth_mach m;
749
750 log_open(GRAD_LOG_AUTH);
751 m.req = radreq;
752 m.activefd = activefd;
753 m.user_check = NULL;
754 m.user_reply = NULL;
755 m.check_pair = NULL;
756 m.user_msg = NULL;
757 obstack_init(&m.msg_stack);
758
759 m.namepair = grad_avl_find(m.req->request->avlist, DA_USER_NAME);
760
761 GRAD_DEBUG1(1, "auth: %s", m.namepair->avp_strvalue);
762 m.state = as_init;
763
764 while (m.state != as_stop) {
765 sp = &states[m.state];
766 oldstate = m.state;
767 if (sp->attr) {
768 grad_avp_t *p;
769
770 switch (sp->list) {
771 case L_req:
772 p = m.req->request->avlist;
773 break;
774 case L_check:
775 p = m.user_check;
776 break;
777 case L_reply:
778 p = m.user_reply;
779 break;
780 default:
781 abort();
782 }
783 if (p = grad_avl_find(p, sp->attr))
784 m.check_pair = p;
785 else {
786 m.state = sp->next;
787 continue;
788 }
789 }
790 (*sp->sfn)(&m);
791 /* default action: */
792 if (oldstate == m.state)
793 m.state = sp->next;
794 }
795
796 /* Cleanup */
797 grad_avl_free(m.user_check);
798 grad_avl_free(m.user_reply);
799 if (m.user_msg)
800 free(m.user_msg);
801 obstack_free(&m.msg_stack, NULL);
802 memset(m.userpass, 0, sizeof(m.userpass));
803 return 0;
804 }
805
806 #if RADIUS_DEBUG
807 # define newstate(s) do {\
808 GRAD_DEBUG2(2, "%d -> %d", m->state, s);\
809 m->state = s;\
810 } while (0)
811 #else
812 # define newstate(s) m->state = s
813 #endif
814
815
816 void
sfn_init(AUTH_MACH * m)817 sfn_init(AUTH_MACH *m)
818 {
819 radiusd_request_t *radreq = m->req;
820 grad_avp_t *pair_ptr;
821
822 switch (radreq->server_code) {
823 case RT_ACCESS_REJECT:
824 m->user_check = grad_avp_create_integer(DA_AUTH_TYPE,
825 DV_AUTH_TYPE_REJECT);
826 break;
827
828 case RT_ACCESS_ACCEPT:
829 m->user_check = grad_avp_create_integer(DA_AUTH_TYPE,
830 DV_AUTH_TYPE_ACCEPT);
831 break;
832
833 case 0:
834 break;
835
836 default:
837 radius_send_reply(radreq->server_code,
838 radreq,
839 radreq->server_reply,
840 NULL,
841 m->activefd);
842 newstate(as_stop);
843 return;
844 }
845
846 #ifdef USE_LIVINGSTON_MENUS
847 /*
848 * If the request is processing a menu, service it here.
849 */
850 if (radreq->server_code == 0
851 && (pair_ptr = grad_avl_find(m->req->request->avlist, DA_STATE)) != NULL
852 && strncmp(pair_ptr->avp_strvalue, "MENU=", 5) == 0) {
853 menu_reply(m->req, m->activefd);
854 newstate(as_stop);
855 return;
856 }
857 #endif
858
859 /* If this request was proxied to another server, we need
860 to add the reply pairs from the server to the initial reply.
861 We need to scan and decrypt them first. It could have been
862 done in proxy_receive, but this would mean that their plaintext
863 values would hang around in queue, which is not acceptable. */
864
865 if (radreq->server_reply) {
866 m->user_reply =
867 radius_decrypt_request_pairs(radreq,
868 radreq->server_reply);
869 radreq->server_reply = NULL;
870 }
871
872 /*
873 * Get the user from the database
874 */
875 if (user_find(m->namepair->avp_strvalue, radreq,
876 &m->user_check, &m->user_reply) != 0
877 && !radreq->server_code) {
878
879 if (is_log_mode(m, RLOG_AUTH))
880 auth_log(m, _("No such user"), NULL, NULL, NULL);
881
882 auth_format_msg(m, MSG_ACCESS_DENIED);
883 /* Send reject packet with proxy-pairs as a reply */
884 newstate(as_reject_cleanup);
885 }
886 }
887
888 void
sfn_scheme(AUTH_MACH * m)889 sfn_scheme(AUTH_MACH *m)
890 {
891 grad_avp_t *p;
892 grad_avp_t *tmp = NULL;
893
894 grad_avl_move_attr(&tmp, &m->user_reply, DA_SCHEME_PROCEDURE);
895 if (scheme_eval_avl (m->req, m->user_check, tmp, &m->user_reply, &p)) {
896 if (p) {
897 auth_log(m,
898 _("Login rejected"),
899 NULL,
900 _("denied by Scheme procedure "),
901 p->avp_strvalue);
902 newstate(as_reject);
903 } else { /* Empty P means that Guile auth is not available */
904 newstate(as_reject_cleanup);
905 }
906 }
907 grad_avl_free(tmp);
908 }
909
910 /* Execute an Authentication Failure Trigger, if the one is specified */
911 static void
auth_failure(AUTH_MACH * m)912 auth_failure(AUTH_MACH *m)
913 {
914 grad_avp_t *pair;
915 char *cmd;
916
917 pair = grad_avl_find(m->user_reply, DA_AUTH_FAILURE_TRIGGER);
918 if (!pair)
919 return;
920
921 cmd = util_xlate(&m->msg_stack, pair->avp_strvalue, m->req->request);
922 switch (cmd[0]) {
923 case '(':
924 scheme_eval_unspecified_expr(cmd);
925 break;
926
927 case '/':
928 radius_exec_command(cmd);
929 break;
930
931 default:
932 grad_log_req(GRAD_LOG_ERR,
933 m->req->request,
934 _("Invalid Auth-Failure-Trigger value: %s"),
935 cmd);
936 grad_log(GRAD_LOG_INFO,
937 _("The value of Auth-Failure-Trigger attribute must begin with '/' or '('."));
938 }
939 }
940
941 void
sfn_validate(AUTH_MACH * m)942 sfn_validate(AUTH_MACH *m)
943 {
944 radiusd_request_t *radreq = m->req;
945 enum auth_status rc;
946 time_t exp;
947 grad_avp_t *pair;
948
949 rc = rad_check_password(radreq, m, &exp);
950
951 if (rc == auth_ok) {
952 radiusd_sql_auth_result_query(m->req, 0);
953 rc = radius_check_expiration(m, &exp);
954 } else if (rc == auth_fail) {
955 radiusd_sql_auth_result_query(m->req, 1);
956 auth_failure(m);
957 }
958
959 switch (rc) {
960 case auth_ok:
961 break;
962
963 case auth_valid:
964 exp /= SECONDS_PER_DAY;
965 if (warning_seconds != 0 && exp < warning_seconds) {
966 pair = grad_avp_create_integer(DA_PASSWORD_EXPIRE_DAYS,
967 exp);
968 grad_avl_add_pair(&m->user_reply, pair);
969 auth_format_msg(m, MSG_PASSWORD_EXPIRE_WARNING);
970 }
971 break;
972
973 case auth_reject:
974 if (is_log_mode(m, RLOG_AUTH))
975 auth_log(m, _("Rejected"),
976 NULL, NULL, NULL);
977 newstate(as_reject);
978 auth_format_msg(m, MSG_ACCESS_DENIED);
979 break;
980
981 case auth_ignore:
982 if (is_log_mode(m, RLOG_AUTH))
983 auth_log(m, _("Ignored"),
984 NULL, NULL, NULL);
985 newstate(as_stop);
986 break;
987
988 case auth_nouser:
989 if (is_log_mode(m, RLOG_AUTH))
990 auth_log(m, _("No such user"),
991 NULL, NULL, NULL);
992 newstate(as_reject_cleanup);
993 auth_format_msg(m, MSG_ACCESS_DENIED);
994 break;
995
996 case auth_fail:
997 if (is_log_mode(m, RLOG_AUTH))
998 auth_log(m,
999 _("Login incorrect"),
1000 is_log_mode(m, RLOG_FAILED_PASS) ?
1001 m->userpass : NULL,
1002 NULL, NULL);
1003 newstate(as_reject_cleanup);
1004 auth_format_msg(m, MSG_ACCESS_DENIED);
1005 break;
1006
1007 case auth_account_expired:
1008 auth_format_msg(m, MSG_PASSWORD_EXPIRED);
1009 newstate(as_reject_cleanup);
1010 if (is_log_mode(m, RLOG_AUTH)) {
1011 auth_log(m,
1012 _("Login incorrect"),
1013 NULL,
1014 _("Account expired"), NULL);
1015 }
1016 break;
1017
1018 case auth_password_expired:
1019 auth_format_msg(m, MSG_PASSWORD_EXPIRED);
1020 newstate(as_reject_cleanup);
1021 if (is_log_mode(m, RLOG_AUTH)) {
1022 auth_log(m,
1023 _("Login incorrect"),
1024 NULL,
1025 _("Password expired"), NULL);
1026 }
1027 break;
1028
1029 default:
1030 grad_insist_fail("sfn_validate");
1031 }
1032 return;
1033 }
1034
1035 void
sfn_disable(AUTH_MACH * m)1036 sfn_disable(AUTH_MACH *m)
1037 {
1038 if (get_deny(m->namepair->avp_strvalue)) {
1039 auth_format_msg(m, MSG_ACCOUNT_CLOSED);
1040 auth_log(m, _("Account disabled"), NULL, NULL, NULL);
1041 newstate(as_reject_cleanup);
1042 }
1043 }
1044
1045 void
sfn_realmuse(AUTH_MACH * m)1046 sfn_realmuse(AUTH_MACH *m)
1047 {
1048 if (!m->req->realm)
1049 return;
1050
1051 if (radius_mlc_realm(m->req) == 0)
1052 return;
1053 auth_format_msg(m, MSG_REALM_QUOTA);
1054 auth_log(m, _("Login failed"), NULL,
1055 _("realm quota exceeded for "), m->req->realm->realm);
1056 newstate(as_reject_cleanup);
1057 }
1058
1059 void
sfn_simuse(AUTH_MACH * m)1060 sfn_simuse(AUTH_MACH *m)
1061 {
1062 char name[GRAD_STRING_LENGTH];
1063 int rc;
1064 int count;
1065
1066 strip_username(strip_names,
1067 m->namepair->avp_strvalue, m->user_check, name);
1068 rc = radius_mlc_user(name, m->req,
1069 m->check_pair->avp_lvalue, &count);
1070 grad_avl_add_pair(&m->user_reply,
1071 grad_avp_create_integer(DA_SIMULTANEOUS_USE, count));
1072 if (!rc)
1073 return;
1074
1075 auth_format_msg(m,
1076 (m->check_pair->avp_lvalue > 1) ?
1077 MSG_MULTIPLE_LOGIN : MSG_SECOND_LOGIN);
1078
1079 grad_log_req(GRAD_LOG_WARN, m->req->request,
1080 _("Multiple logins: [%s] max. %ld%s"),
1081 m->namepair->avp_strvalue,
1082 m->check_pair->avp_lvalue,
1083 rc == 2 ? _(" [MPP attempt]") : "");
1084 newstate(as_reject_cleanup);
1085 }
1086
1087 static grad_uint32_t
set_session_timeout(AUTH_MACH * m,grad_uint32_t val)1088 set_session_timeout(AUTH_MACH *m, grad_uint32_t val)
1089 {
1090 grad_avp_t *p;
1091
1092 if (!(p = grad_avl_find(m->user_reply, DA_SESSION_TIMEOUT))) {
1093 p = grad_avp_create_integer(DA_SESSION_TIMEOUT, val);
1094 grad_avl_add_pair(&m->user_reply, p);
1095 } else if (p->avp_lvalue > val)
1096 p->avp_lvalue = val;
1097 return p->avp_lvalue;
1098 }
1099
1100 void
sfn_time(AUTH_MACH * m)1101 sfn_time(AUTH_MACH *m)
1102 {
1103 int rc;
1104 time_t t;
1105 unsigned rest;
1106
1107 time(&t);
1108 rc = ts_check(m->check_pair->avp_strvalue, &t, &rest, NULL);
1109 if (rc == 1) {
1110 /*
1111 * User called outside allowed time interval.
1112 */
1113 auth_format_msg(m, MSG_TIMESPAN_VIOLATION);
1114 grad_log_req(GRAD_LOG_ERR,
1115 m->req->request,
1116 _("Outside allowed timespan (%s)"),
1117 m->check_pair->avp_strvalue);
1118 newstate(as_reject_cleanup);
1119 } else if (rc == 0) {
1120 /*
1121 * User is allowed, but set Session-Timeout.
1122 */
1123 grad_uint32_t to = set_session_timeout(m, rest);
1124 GRAD_DEBUG4(2, "user %s, span %s, timeout %d, real timeout %d",
1125 m->namepair->avp_strvalue,
1126 m->check_pair->avp_strvalue,
1127 rest,
1128 to);
1129 }
1130 }
1131
1132 void
sfn_ipaddr(AUTH_MACH * m)1133 sfn_ipaddr(AUTH_MACH *m)
1134 {
1135 grad_avp_t *p, *tmp, *pp;
1136
1137 /* Assign an IP if necessary */
1138 if (!grad_avl_find(m->user_reply, DA_FRAMED_IP_ADDRESS)) {
1139 if (p = grad_avl_find(m->req->request->avlist,
1140 DA_FRAMED_IP_ADDRESS)) {
1141 /* termserver hint */
1142 grad_avl_add_pair(&m->user_reply, grad_avp_dup(p));
1143 }
1144 }
1145
1146 }
1147
1148 void
sfn_exec_wait(AUTH_MACH * m)1149 sfn_exec_wait(AUTH_MACH *m)
1150 {
1151 int rc;
1152 grad_avp_t *p;
1153 grad_avp_t *reply = NULL;
1154
1155 rc = exec_program_wait (m->req, m->check_pair, &reply, &p);
1156
1157 if (rc != 0) {
1158 newstate(as_reject);
1159
1160 if (is_log_mode(m, RLOG_AUTH)) {
1161 auth_log(m, _("Login incorrect"),
1162 NULL,
1163 _("external check failed: "),
1164 p->avp_strvalue);
1165 }
1166
1167 grad_avl_free(m->user_reply);
1168 m->user_reply = reply;
1169 if (!grad_avl_find(m->user_reply, DA_REPLY_MESSAGE))
1170 auth_format_msg(m, MSG_ACCESS_DENIED);
1171 } else {
1172 grad_avl_merge(&m->user_reply, &reply);
1173 grad_avl_free(reply);
1174 }
1175 }
1176
1177 void
sfn_exec_nowait(AUTH_MACH * m)1178 sfn_exec_nowait(AUTH_MACH *m)
1179 {
1180 grad_avp_t *p;
1181
1182 for (p = m->check_pair;
1183 p;
1184 p = grad_avl_find(p->next, DA_EXEC_PROGRAM)) {
1185 radius_eval_avp(m->req, p, NULL, 1);
1186 radius_exec_program(p->avp_strvalue, m->req, NULL, 0);
1187 }
1188 }
1189
1190 void
sfn_cleanup_cbkid(AUTH_MACH * m)1191 sfn_cleanup_cbkid(AUTH_MACH *m)
1192 {
1193 static int delete_pairs[] = {
1194 DA_FRAMED_PROTOCOL,
1195 DA_FRAMED_IP_ADDRESS,
1196 DA_FRAMED_IP_NETMASK,
1197 DA_FRAMED_ROUTE,
1198 DA_FRAMED_MTU,
1199 DA_FRAMED_COMPRESSION,
1200 DA_FILTER_ID,
1201 DA_PORT_LIMIT,
1202 DA_CALLBACK_NUMBER,
1203 0
1204 };
1205 int *ip;
1206
1207 for (ip = delete_pairs; *ip; ip++)
1208 grad_avl_delete(&m->user_reply, *ip);
1209 }
1210
1211 void
sfn_menu_challenge(AUTH_MACH * m)1212 sfn_menu_challenge(AUTH_MACH *m)
1213 {
1214 #ifdef USE_LIVINGSTON_MENUS
1215 char *msg;
1216 char state_value[MAX_STATE_VALUE];
1217
1218 msg = menu_read_text(m->check_pair->avp_strvalue);
1219 snprintf(state_value, sizeof(state_value),
1220 "MENU=%s", m->check_pair->avp_strvalue);
1221 radius_send_challenge(m->req, msg, state_value, m->activefd);
1222 grad_free(msg);
1223
1224 GRAD_DEBUG2(1, "sending challenge (menu %s) to %s",
1225 m->check_pair->avp_strvalue, m->namepair->avp_strvalue);
1226 newstate(as_stop);
1227 #endif
1228 }
1229
1230 void
sfn_ack(AUTH_MACH * m)1231 sfn_ack(AUTH_MACH *m)
1232 {
1233 GRAD_DEBUG1(1, "ACK: %s", m->namepair->avp_strvalue);
1234
1235 radius_eval_avl(m->req, m->user_reply);
1236
1237 radius_send_reply(RT_ACCESS_ACCEPT,
1238 m->req,
1239 m->user_reply,
1240 auth_finish_msg(m),
1241 m->activefd);
1242
1243 if (is_log_mode(m, RLOG_AUTH)) {
1244 auth_log(m, _("Login OK"),
1245 is_log_mode(m, RLOG_AUTH_PASS) ? m->userpass : NULL,
1246 NULL, NULL);
1247 }
1248 }
1249
1250 void
sfn_reject_cleanup(AUTH_MACH * m)1251 sfn_reject_cleanup(AUTH_MACH *m)
1252 {
1253 grad_avl_free(m->user_reply);
1254 m->user_reply = NULL;
1255 newstate(as_reject);
1256 }
1257
1258 void
sfn_reject(AUTH_MACH * m)1259 sfn_reject(AUTH_MACH *m)
1260 {
1261 GRAD_DEBUG1(1, "REJECT: %s", m->namepair->avp_strvalue);
1262 radius_eval_avl(m->req, m->user_reply);
1263 radius_send_reply(RT_ACCESS_REJECT,
1264 m->req,
1265 m->user_reply,
1266 auth_finish_msg(m),
1267 m->activefd);
1268 }
1269
1270 void
req_decrypt_password(char * password,grad_request_t * req,grad_avp_t * pair)1271 req_decrypt_password(char *password, grad_request_t *req, grad_avp_t *pair)
1272 {
1273 grad_nas_t *nas;
1274 char *s;
1275
1276 if (!pair) {
1277 pair = grad_avl_find(req->avlist, DA_USER_PASSWORD);
1278 if (!pair)
1279 return;
1280 }
1281
1282 if (pair->prop & GRAD_AP_ENCRYPT_RFC2138) {
1283 /* Determine whether we need to use broken decoding */
1284 nas = grad_nas_request_to_nas(req);
1285 if (nas
1286 && (s = grad_envar_lookup(nas->args, "broken_pass")) != NULL
1287 && s[0] == '1')
1288 grad_decrypt_password_broken(password, pair,
1289 req->authenticator,
1290 req->secret);
1291 else
1292 grad_decrypt_password(password, pair,
1293 req->authenticator,
1294 req->secret);
1295 } else if (pair->prop & GRAD_AP_ENCRYPT_RFC2868) {
1296 u_char tag; /* FIXME: not accessible for user */
1297 grad_decrypt_tunnel_password(password,
1298 &tag, pair,
1299 req->authenticator,
1300 req->secret);
1301 }
1302 }
1303