2 * auth.c User authentication.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Copyright 2000 The FreeRADIUS server project
21 * Copyright 2000 Miquel van Smoorenburg <miquels@cistron.nl>
22 * Copyright 2000 Jeff Carneal <jeff@apex.net>
25 static const char rcsid[] = "$Id$";
28 #include "libradius.h"
34 #ifdef HAVE_NETINET_IN_H
35 # include <netinet/in.h>
42 * Return a short string showing the terminal server, port
43 * and calling station ID.
45 char *auth_name(char *buf, size_t buflen, REQUEST *request, int do_cli) {
50 if ((cli = pairfind(request->packet->vps, PW_CALLING_STATION_ID)) == NULL)
52 if ((pair = pairfind(request->packet->vps, PW_NAS_PORT)) != NULL)
55 snprintf(buf, buflen, "from client %.128s port %u%s%.128s",
56 client_name(request->packet->src_ipaddr), port,
57 (do_cli ? " cli " : ""), (do_cli ? (char *)cli->strvalue : ""));
64 * Check if account has expired, and if user may login now.
66 static int check_expiration(REQUEST *request)
68 VALUE_PAIR *check_item;
71 check_item = pairfind(request->config_items, PW_EXPIRATION);
73 if (!check_item) return 0;
76 * Has this user's password expired?
78 * If so, remove ALL reply attributes,
79 * and add our own Reply-Message, saying
80 * why they're being rejected.
82 if (((time_t) check_item->lvalue) <= request->timestamp) {
83 vp = pairmake("Reply-Message",
84 "Password Has Expired\r\n",
86 pairfree(&request->reply->vps);
87 request->reply->vps = vp;
91 #define EXP_TIMEOUT ((uint32_t) (((time_t) check_item->lvalue) - request->timestamp))
93 * Otherwise, set the Session-Timeout based on expiration.
95 vp = pairfind(request->reply->vps, PW_SESSION_TIMEOUT);
97 vp = pairmake("Session-Timeout", "0", T_OP_SET);
98 if (!vp) return -1; /* out of memory */
100 vp->lvalue = EXP_TIMEOUT;
101 pairadd(&request->reply->vps, vp);
102 } else if (vp->lvalue > EXP_TIMEOUT) {
103 vp->lvalue = EXP_TIMEOUT;
104 } /* else Session-Timeout is smaller than Expiration, leave it alone */
111 * Make sure user/pass are clean
114 static int rad_authlog(const char *msg, REQUEST *request, int goodpass) {
116 char clean_password[1024];
117 char clean_username[1024];
119 VALUE_PAIR *username = NULL;
121 if (!mainconfig.log_auth) {
126 * Get the correct username based on the configured value
128 if (log_stripped_names == 0) {
129 username = pairfind(request->packet->vps, PW_USER_NAME);
131 username = request->username;
135 * Clean up the username
137 if (username == NULL) {
138 strcpy(clean_username, "<no User-Name attribute>");
140 librad_safeprint((char *)username->strvalue,
142 clean_username, sizeof(clean_username));
146 * Clean up the password
148 if (mainconfig.log_auth_badpass || mainconfig.log_auth_goodpass) {
149 if (!request->password) {
150 strcpy(clean_password, "<no User-Password attribute>");
151 } else if (request->password->attribute == PW_CHAP_PASSWORD) {
152 strcpy(clean_password, "<CHAP-Password>");
154 librad_safeprint((char *)request->password->strvalue,
155 request->password->length,
156 clean_password, sizeof(clean_password));
161 radlog(L_AUTH, "%s: [%s%s%s] (%s)",
164 mainconfig.log_auth_goodpass ? "/" : "",
165 mainconfig.log_auth_goodpass ? clean_password : "",
166 auth_name(buf, sizeof(buf), request, 1));
168 radlog(L_AUTH, "%s: [%s%s%s] (%s)",
171 mainconfig.log_auth_badpass ? "/" : "",
172 mainconfig.log_auth_badpass ? clean_password : "",
173 auth_name(buf, sizeof(buf), request, 1));
184 * -2 Rejected (Auth-Type = Reject, send Port-Message back)
185 * 1 End check & return, don't reply
187 * NOTE: NOT the same as the RLM_ values !
189 int rad_check_password(REQUEST *request)
191 VALUE_PAIR *auth_type_pair;
192 VALUE_PAIR *cur_config_item;
193 VALUE_PAIR *password_pair;
194 VALUE_PAIR *auth_item;
195 char string[MAX_STRING_LEN];
198 int auth_type_count = 0;
202 * Look for matching check items. We skip the whole lot
203 * if the authentication type is PW_AUTHTYPE_ACCEPT or
204 * PW_AUTHTYPE_REJECT.
206 cur_config_item = request->config_items;
207 while(((auth_type_pair = pairfind(cur_config_item, PW_AUTH_TYPE))) != NULL) {
208 auth_type = auth_type_pair->lvalue;
211 DEBUG2(" rad_check_password: Found Auth-Type %s",
212 auth_type_pair->strvalue);
213 cur_config_item = auth_type_pair->next;
215 if (auth_type == PW_AUTHTYPE_REJECT) {
216 DEBUG2(" rad_check_password: Auth-Type = Reject, rejecting user");
221 if (( auth_type_count > 1) && (debug_flag)) {
222 radlog(L_ERR, "Warning: Found %d auth-types on request for user '%s'",
223 auth_type_count, request->username->strvalue);
227 * This means we have a proxy reply or an accept
228 * and it wasn't rejected in the above loop. So
229 * that means it is accepted and we do no further
232 if ((auth_type == PW_AUTHTYPE_ACCEPT) || (request->proxy)) {
233 DEBUG2(" rad_check_password: Auth-Type = Accept, accepting the user");
238 * Find the password from the users file.
240 if ((password_pair = pairfind(request->config_items, PW_CRYPT_PASSWORD)) != NULL) {
242 * Re-write Auth-Type, but ONLY if it isn't already
245 if (auth_type == -1) auth_type = PW_AUTHTYPE_CRYPT;
247 password_pair = pairfind(request->config_items, PW_PASSWORD);
248 if (!password_pair) {
249 password_pair = pairfind(request->config_items,
250 PW_CLEARTEXT_PASSWORD);
254 old = pairmake("User-Password",
255 password_pair->strvalue,
257 if (old) pairadd(&request->config_items, old);
265 auth_type = PW_AUTHTYPE_LOCAL;
268 * The admin hasn't told us how to
269 * authenticate the user, so we reject them!
273 DEBUG2("auth: No authenticate method (Auth-Type) configuration found for the request: Rejecting the user");
281 case PW_AUTHTYPE_CRYPT:
283 * Find the password sent by the user. It
284 * SHOULD be there, if it's not
285 * authentication fails.
287 auth_item = request->password;
288 if (auth_item == NULL) {
289 DEBUG2("auth: No User-Password or CHAP-Password attribute in the request");
293 DEBUG2("auth: type Crypt");
294 if (password_pair == NULL) {
295 DEBUG2("No Crypt-Password configured for the user");
296 rad_authlog("Login incorrect "
297 "(No Crypt-Password configured for the user)", request, 0);
301 switch (lrad_crypt_check((char *)auth_item->strvalue,
302 (char *)password_pair->strvalue)) {
304 rad_authlog("Login incorrect "
305 "(system failed to supply an encrypted password for comparison)", request, 0);
310 case PW_AUTHTYPE_LOCAL:
311 DEBUG2("auth: type Local");
314 * Find the password sent by the user. It
315 * SHOULD be there, if it's not
316 * authentication fails.
318 auth_item = request->password;
319 if (auth_item == NULL) {
320 DEBUG2("auth: No User-Password or CHAP-Password attribute in the request");
325 * Plain text password.
327 if (password_pair == NULL) {
328 DEBUG2("auth: No password configured for the user");
329 rad_authlog("Login incorrect "
330 "(No password configured for the user)", request, 0);
335 * Local password is just plain text.
337 if (auth_item->attribute == PW_PASSWORD) {
338 if (strcmp((char *)password_pair->strvalue,
339 (char *)auth_item->strvalue) != 0) {
340 DEBUG2("auth: user supplied User-Password does NOT match local User-Password");
343 DEBUG2("auth: user supplied User-Password matches local User-Password");
346 } else if (auth_item->attribute != PW_CHAP_PASSWORD) {
347 DEBUG2("The user did not supply a User-Password or a CHAP-Password attribute");
348 rad_authlog("Login incorrect "
349 "(no User-Password or CHAP-Password attribute)", request, 0);
353 rad_chap_encode(request->packet, string,
354 auth_item->strvalue[0], password_pair);
359 if (memcmp(string + 1, auth_item->strvalue + 1,
360 CHAP_VALUE_LENGTH) != 0) {
361 DEBUG2("auth: user supplied CHAP-Password does NOT match local User-Password");
364 DEBUG2("auth: user supplied CHAP-Password matches local User-Password");
367 dval = dict_valbyattr(PW_AUTH_TYPE, auth_type);
369 DEBUG2("auth: type \"%s\"", dval->name);
371 DEBUG2("auth: type UNKNOWN-%d", auth_type);
375 * See if there is a module that handles
376 * this type, and turn the RLM_ return
377 * status into the values as defined at
378 * the top of this function.
380 result = module_authenticate(auth_type, request);
383 * An authentication module FAIL
384 * return code, or any return code that
385 * is not expected from authentication,
386 * is the same as an explicit REJECT!
388 case RLM_MODULE_FAIL:
389 case RLM_MODULE_INVALID:
390 case RLM_MODULE_NOOP:
391 case RLM_MODULE_NOTFOUND:
392 case RLM_MODULE_REJECT:
393 case RLM_MODULE_UPDATED:
394 case RLM_MODULE_USERLOCK:
401 case RLM_MODULE_HANDLED:
412 * Post-authentication step processes the response before it is
413 * sent to the NAS. It can receive both Access-Accept and Access-Reject
416 int rad_postauth(REQUEST *request)
419 int postauth_type = 0;
423 * Do post-authentication calls. ignoring the return code.
425 vp = pairfind(request->config_items, PW_POST_AUTH_TYPE);
427 DEBUG2(" Found Post-Auth-Type %s", vp->strvalue);
428 postauth_type = vp->lvalue;
430 result = module_post_auth(postauth_type, request);
433 * The module failed, or said to reject the user: Do so.
435 case RLM_MODULE_FAIL:
436 case RLM_MODULE_INVALID:
437 case RLM_MODULE_REJECT:
438 case RLM_MODULE_USERLOCK:
440 request->reply->code = PW_AUTHENTICATION_REJECT;
441 result = RLM_MODULE_REJECT;
444 * The module handled the request, cancel the reply.
446 case RLM_MODULE_HANDLED:
448 result = RLM_MODULE_OK;
451 * The module had a number of OK return codes.
453 case RLM_MODULE_NOOP:
454 case RLM_MODULE_NOTFOUND:
456 case RLM_MODULE_UPDATED:
457 result = RLM_MODULE_OK;
464 * Before sending an Access-Reject, call the modules in the
465 * Post-Auth-Type REJECT stanza.
467 static int rad_postauth_reject(REQUEST *request)
473 dval = dict_valbyname(PW_POST_AUTH_TYPE, "REJECT");
475 /* Overwrite the Post-Auth-Type with the value REJECT */
476 pairdelete(&request->config_items, PW_POST_AUTH_TYPE);
477 tmp = paircreate(PW_POST_AUTH_TYPE, PW_TYPE_INTEGER);
478 tmp->lvalue = dval->value;
479 pairadd(&request->config_items, tmp);
480 result = rad_postauth(request);
482 /* No REJECT stanza */
483 result = RLM_MODULE_OK;
489 * Process and reply to an authentication request
491 * The return value of this function isn't actually used right now, so
492 * it's not entirely clear if it is returning the right things. --Pac.
494 int rad_authenticate(REQUEST *request)
496 VALUE_PAIR *namepair;
497 VALUE_PAIR *check_item;
498 VALUE_PAIR *reply_item;
499 VALUE_PAIR *auth_item;
500 VALUE_PAIR *module_msg;
501 VALUE_PAIR *tmp = NULL;
503 char umsg[MAX_STRING_LEN + 1];
504 const char *user_msg = NULL;
505 const char *password;
508 int seen_callback_id;
509 char buf[1024], logstr[1024];
516 * If this request got proxied to another server, we need
517 * to check whether it authenticated the request or not.
519 if (request->proxy_reply) {
520 switch (request->proxy_reply->code) {
522 * Reply of ACCEPT means accept, thus set Auth-Type
525 case PW_AUTHENTICATION_ACK:
526 tmp = paircreate(PW_AUTH_TYPE, PW_TYPE_INTEGER);
528 radlog(L_ERR|L_CONS, "Not enough memory");
531 tmp->lvalue = PW_AUTHTYPE_ACCEPT;
532 pairadd(&request->config_items, tmp);
535 * Challenges are punted back to the NAS without any
536 * further processing.
538 case PW_ACCESS_CHALLENGE:
539 request->reply->code = PW_ACCESS_CHALLENGE;
540 return RLM_MODULE_OK;
542 * ALL other replies mean reject. (this is fail-safe)
544 * Do NOT do any authorization or authentication. They
545 * are being rejected, so we minimize the amount of work
546 * done by the server, by rejecting them here.
548 case PW_AUTHENTICATION_REJECT:
550 rad_authlog("Login incorrect (Home Server says so)",
552 request->reply->code = PW_AUTHENTICATION_REJECT;
553 rad_postauth_reject(request);
554 return RLM_MODULE_REJECT;
559 * Get the username from the request.
561 * Note that namepair MAY be NULL, in which case there
562 * is no User-Name attribute in the request.
564 namepair = request->username;
567 * Look for, and cache, passwords.
569 if (!request->password) {
570 request->password = pairfind(request->packet->vps,
575 * Discover which password we want to use.
577 auth_item = request->password;
579 password = (const char *)auth_item->strvalue;
583 * Maybe there's a CHAP-Password?
585 if ((auth_item = pairfind(request->packet->vps,
586 PW_CHAP_PASSWORD)) != NULL) {
587 password = "<CHAP-PASSWORD>";
591 * No password we recognize.
593 password = "<NO-PASSWORD>";
596 request->password = auth_item;
599 * Get the user's authorization information from the database
602 result = module_authorize(autz_type, request);
604 case RLM_MODULE_NOOP:
605 case RLM_MODULE_NOTFOUND:
607 case RLM_MODULE_UPDATED:
609 case RLM_MODULE_FAIL:
610 case RLM_MODULE_HANDLED:
612 case RLM_MODULE_INVALID:
613 case RLM_MODULE_REJECT:
614 case RLM_MODULE_USERLOCK:
616 if ((module_msg = pairfind(request->packet->vps,
617 PW_MODULE_FAILURE_MESSAGE)) != NULL) {
618 char msg[MAX_STRING_LEN + 16];
619 snprintf(msg, sizeof(msg), "Invalid user (%s)",
620 module_msg->strvalue);
621 rad_authlog(msg,request,0);
623 rad_authlog("Invalid user", request, 0);
625 request->reply->code = PW_AUTHENTICATION_REJECT;
629 tmp = pairfind(request->config_items, PW_AUTZ_TYPE);
631 DEBUG2(" Found Autz-Type %s", tmp->strvalue);
632 autz_type = tmp->lvalue;
639 * If we haven't already proxied the packet, then check
640 * to see if we should. Maybe one of the authorize
641 * modules has decided that a proxy should be used. If
642 * so, get out of here and send the packet.
644 if ((request->proxy == NULL) &&
645 ((tmp = pairfind(request->config_items, PW_PROXY_TO_REALM)) != NULL)) {
649 * Catch users who set Proxy-To-Realm to a LOCAL
652 realm = realm_find(tmp->strvalue, 0);
653 if (realm && (realm->ipaddr == htonl(INADDR_NONE))) {
654 DEBUG2(" WARNING: You set Proxy-To-Realm = %s, but it is a LOCAL realm! Cancelling invalid proxy request.", realm->realm);
657 * Don't authenticate, as the request is
660 return RLM_MODULE_OK;
665 * Perhaps there is a Stripped-User-Name now.
667 namepair = request->username;
673 if ((result = check_expiration(request)) < 0)
675 result = rad_check_password(request);
678 return RLM_MODULE_HANDLED;
683 * Failed to validate the user.
685 * We PRESUME that the code which failed will clean up
686 * request->reply->vps, to be ONLY the reply items it
687 * wants to send back.
690 DEBUG2("auth: Failed to validate the user.");
691 request->reply->code = PW_AUTHENTICATION_REJECT;
693 if ((module_msg = pairfind(request->packet->vps,PW_MODULE_FAILURE_MESSAGE)) != NULL){
694 char msg[MAX_STRING_LEN+19];
696 snprintf(msg, sizeof(msg), "Login incorrect (%s)",
697 module_msg->strvalue);
698 rad_authlog(msg, request, 0);
700 rad_authlog("Login incorrect", request, 0);
703 /* double check: maybe the secret is wrong? */
704 if ((debug_flag > 1) && (auth_item != NULL) &&
705 (auth_item->attribute == PW_PASSWORD)) {
708 p = auth_item->strvalue;
710 if (!isprint((int) *p)) {
711 log_debug(" WARNING: Unprintable characters in the password.\n\t Double-check the shared secret on the server and the NAS!");
720 (check_item = pairfind(request->config_items, PW_SIMULTANEOUS_USE)) != NULL) {
721 int session_type = 0;
723 tmp = pairfind(request->config_items, PW_SESSION_TYPE);
725 DEBUG2(" Found Session-Type %s", tmp->strvalue);
726 session_type = tmp->lvalue;
730 * User authenticated O.K. Now we have to check
731 * for the Simultaneous-Use parameter.
734 (r = module_checksimul(session_type, request, check_item->lvalue)) != 0) {
738 /* Multilink attempt. Check if port-limit > simultaneous-use */
739 VALUE_PAIR *port_limit;
741 if ((port_limit = pairfind(request->reply->vps, PW_PORT_LIMIT)) != NULL &&
742 port_limit->lvalue > check_item->lvalue){
743 DEBUG2("main auth: MPP is OK");
748 if (check_item->lvalue > 1) {
749 snprintf(umsg, sizeof(umsg),
750 "\r\nYou are already logged in %d times - access denied\r\n\n",
751 (int)check_item->lvalue);
754 user_msg = "\r\nYou are already logged in - access denied\r\n\n";
757 request->reply->code = PW_AUTHENTICATION_REJECT;
760 * They're trying to log in too many times.
761 * Remove ALL reply attributes.
763 pairfree(&request->reply->vps);
764 tmp = pairmake("Reply-Message", user_msg, T_OP_SET);
765 request->reply->vps = tmp;
767 snprintf(logstr, sizeof(logstr), "Multiple logins (max %d) %s",
769 r == 2 ? "[MPP attempt]" : "");
770 rad_authlog(logstr, request, 1);
778 (check_item = pairfind(request->config_items, PW_LOGIN_TIME)) != NULL) {
781 * Authentication is OK. Now see if this
782 * user may login at this time of the day.
784 r = timestr_match((char *)check_item->strvalue,
787 if (r == 0) { /* unlimited */
789 * Do nothing: login-time is OK.
793 * Session-Timeout needs to be at least
794 * 60 seconds, some terminal servers
795 * ignore smaller values.
799 * User called outside allowed time interval.
802 user_msg = "You are calling outside your allowed timespan\r\n";
804 request->reply->code = PW_AUTHENTICATION_REJECT;
805 pairfree(&request->reply->vps);
807 tmp = pairmake("Reply-Message", user_msg, T_OP_SET);
808 request->reply->vps = tmp;
810 snprintf(logstr, sizeof(logstr), "Outside allowed timespan (time allowed %s)",
811 check_item->strvalue);
812 rad_authlog(logstr, request, 1);
817 * User is allowed, but set Session-Timeout.
819 if ((reply_item = pairfind(request->reply->vps,
820 PW_SESSION_TIMEOUT)) != NULL) {
821 if (reply_item->lvalue > (unsigned) r)
822 reply_item->lvalue = r;
824 if ((reply_item = paircreate(
826 PW_TYPE_INTEGER)) == NULL) {
827 radlog(L_ERR|L_CONS, "no memory");
830 reply_item->lvalue = r;
831 pairadd(&request->reply->vps, reply_item);
837 * Result should be >= 0 here - if not, it means the user
838 * is rejected, so we just process post-auth and return.
841 rad_postauth_reject(request);
842 return RLM_MODULE_REJECT;
846 * We might need this later. The 'password' string
847 * is NOT used anywhere below here, except for logging,
848 * so it should be safe...
850 if ((auth_item != NULL) && (auth_item->attribute == PW_CHAP_PASSWORD)) {
851 password = "CHAP-Password";
855 * Add the port number to the Framed-IP-Address if
856 * vp->addport is set.
858 if (((tmp = pairfind(request->reply->vps,
859 PW_FRAMED_IP_ADDRESS)) != NULL) &&
860 (tmp->flags.addport != 0)) {
861 VALUE_PAIR *vpPortId;
864 * Find the NAS port ID.
866 if ((vpPortId = pairfind(request->packet->vps,
867 PW_NAS_PORT)) != NULL) {
868 unsigned long tvalue = ntohl(tmp->lvalue);
869 tmp->lvalue = htonl(tvalue + vpPortId->lvalue);
870 tmp->flags.addport = 0;
871 ip_ntoa(tmp->strvalue, tmp->lvalue);
873 DEBUG2("WARNING: No NAS-Port attribute in request. CANNOT return a Framed-IP-Address + NAS-Port.\n");
874 pairdelete(&request->reply->vps, PW_FRAMED_IP_ADDRESS);
879 * See if we need to execute a program.
880 * FIXME: somehow cache this info, and only execute the
881 * program when we receive an Accounting-START packet.
882 * Only at that time we know dynamic IP etc.
886 if ((auth_item = pairfind(request->reply->vps, PW_EXEC_PROGRAM)) != NULL) {
888 exec_program = strdup((char *)auth_item->strvalue);
889 pairdelete(&request->reply->vps, PW_EXEC_PROGRAM);
891 if ((auth_item = pairfind(request->reply->vps, PW_EXEC_PROGRAM_WAIT)) != NULL) {
894 exec_program = strdup((char *)auth_item->strvalue);
895 pairdelete(&request->reply->vps, PW_EXEC_PROGRAM_WAIT);
899 * Hack - allow % expansion in certain value strings.
900 * This is nice for certain Exec-Program programs.
902 seen_callback_id = 0;
903 if ((auth_item = pairfind(request->reply->vps, PW_CALLBACK_ID)) != NULL) {
904 seen_callback_id = 1;
905 radius_xlat(buf, sizeof(auth_item->strvalue),
906 (char *)auth_item->strvalue, request, NULL);
907 strNcpy((char *)auth_item->strvalue, buf,
908 sizeof(auth_item->strvalue));
909 auth_item->length = strlen((char *)auth_item->strvalue);
914 * If we want to exec a program, but wait for it,
915 * do it first before sending the reply.
917 if (exec_program && exec_wait) {
918 r = radius_exec_program(exec_program, request,
921 request->packet->vps, &tmp);
926 * Always add the value-pairs to the reply.
928 pairmove(&request->reply->vps, &tmp);
933 * Error. radius_exec_program() returns -1 on
936 user_msg = "Access denied (external check failed)";
937 tmp = pairmake("Reply-Message", user_msg, T_OP_SET);
938 pairadd(&request->reply->vps, tmp);
940 request->reply->code = PW_AUTHENTICATION_REJECT;
941 rad_authlog("Login incorrect (external check failed)",
943 rad_postauth_reject(request);
945 return RLM_MODULE_REJECT;
949 * Reject. radius_exec_program() returns >0
950 * if the exec'ed program had a non-zero
953 request->reply->code = PW_AUTHENTICATION_REJECT;
954 rad_authlog("Login incorrect (external check said so)",
956 rad_postauth_reject(request);
958 return RLM_MODULE_REJECT;
963 * Delete "normal" A/V pairs when using callback.
965 * FIXME: This is stupid. The portmaster should accept
966 * these settings instead of insisting on using a
969 * FIXME2: Move this into the above exec thingy?
970 * (if you knew how I use the exec_wait, you'd understand).
972 if (seen_callback_id) {
973 pairdelete(&request->reply->vps, PW_FRAMED_PROTOCOL);
974 pairdelete(&request->reply->vps, PW_FRAMED_IP_ADDRESS);
975 pairdelete(&request->reply->vps, PW_FRAMED_IP_NETMASK);
976 pairdelete(&request->reply->vps, PW_FRAMED_ROUTE);
977 pairdelete(&request->reply->vps, PW_FRAMED_MTU);
978 pairdelete(&request->reply->vps, PW_FRAMED_COMPRESSION);
979 pairdelete(&request->reply->vps, PW_FILTER_ID);
980 pairdelete(&request->reply->vps, PW_PORT_LIMIT);
981 pairdelete(&request->reply->vps, PW_CALLBACK_NUMBER);
985 * Filter (possibly multiple) Reply-Message attributes
986 * through radius_xlat, modifying them in place.
988 if (user_msg == NULL) {
989 reply_item = pairfind(request->reply->vps, PW_REPLY_MESSAGE);
991 radius_xlat(buf, sizeof(reply_item->strvalue),
992 (char *)reply_item->strvalue, request, NULL);
993 strNcpy((char *)reply_item->strvalue, buf,
994 sizeof(reply_item->strvalue));
995 reply_item->length = strlen((char *)reply_item->strvalue);
997 reply_item = pairfind(reply_item->next, PW_REPLY_MESSAGE);
1002 * Set the reply to Access-Accept, if it hasn't already
1003 * been set to something. (i.e. Access-Challenge)
1005 if (request->reply->code == 0)
1006 request->reply->code = PW_AUTHENTICATION_ACK;
1008 if ((module_msg = pairfind(request->packet->vps,PW_MODULE_SUCCESS_MESSAGE)) != NULL){
1009 char msg[MAX_STRING_LEN+12];
1011 snprintf(msg, sizeof(msg), "Login OK (%s)",
1012 module_msg->strvalue);
1013 rad_authlog(msg, request, 1);
1015 rad_authlog("Login OK", request, 1);
1018 if (exec_program && !exec_wait) {
1020 * No need to check the exit status here.
1022 radius_exec_program(exec_program, request, exec_wait,
1023 NULL, 0, request->packet->vps, NULL);
1029 result = rad_postauth(request);