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