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$";
27 #include <freeradius-devel/autoconf.h>
33 #ifdef HAVE_NETINET_IN_H
34 # include <netinet/in.h>
37 #include <freeradius-devel/radiusd.h>
38 #include <freeradius-devel/modules.h>
39 #include <freeradius-devel/rad_assert.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_old(&request->packet->src_ipaddr), port,
57 (do_cli ? " cli " : ""), (do_cli ? (char *)cli->vp_strvalue : ""));
65 * Make sure user/pass are clean
68 static int rad_authlog(const char *msg, REQUEST *request, int goodpass) {
70 char clean_password[1024];
71 char clean_username[1024];
73 VALUE_PAIR *username = NULL;
75 if (!mainconfig.log_auth) {
80 * Get the correct username based on the configured value
82 if (log_stripped_names == 0) {
83 username = pairfind(request->packet->vps, PW_USER_NAME);
85 username = request->username;
89 * Clean up the username
91 if (username == NULL) {
92 strcpy(clean_username, "<no User-Name attribute>");
94 librad_safeprint((char *)username->vp_strvalue,
96 clean_username, sizeof(clean_username));
100 * Clean up the password
102 if (mainconfig.log_auth_badpass || mainconfig.log_auth_goodpass) {
103 if (!request->password) {
104 VALUE_PAIR *auth_type;
106 auth_type = pairfind(request->config_items,
108 if (auth_type && (auth_type->vp_strvalue[0] != '\0')) {
109 snprintf(clean_password, sizeof(clean_password),
110 "<via Auth-Type = %s>",
111 auth_type->vp_strvalue);
113 strcpy(clean_password, "<no User-Password attribute>");
115 } else if (request->password->attribute == PW_CHAP_PASSWORD) {
116 strcpy(clean_password, "<CHAP-Password>");
118 librad_safeprint((char *)request->password->vp_strvalue,
119 request->password->length,
120 clean_password, sizeof(clean_password));
125 radlog(L_AUTH, "%s: [%s%s%s] (%s)",
128 mainconfig.log_auth_goodpass ? "/" : "",
129 mainconfig.log_auth_goodpass ? clean_password : "",
130 auth_name(buf, sizeof(buf), request, 1));
132 radlog(L_AUTH, "%s: [%s%s%s] (%s)",
135 mainconfig.log_auth_badpass ? "/" : "",
136 mainconfig.log_auth_badpass ? clean_password : "",
137 auth_name(buf, sizeof(buf), request, 1));
148 * -2 Rejected (Auth-Type = Reject, send Port-Message back)
149 * 1 End check & return, don't reply
151 * NOTE: NOT the same as the RLM_ values !
153 static int rad_check_password(REQUEST *request)
155 VALUE_PAIR *auth_type_pair;
156 VALUE_PAIR *cur_config_item;
157 VALUE_PAIR *password_pair;
158 VALUE_PAIR *auth_item;
159 char string[MAX_STRING_LEN];
162 int auth_type_count = 0;
166 * Look for matching check items. We skip the whole lot
167 * if the authentication type is PW_AUTHTYPE_ACCEPT or
168 * PW_AUTHTYPE_REJECT.
170 cur_config_item = request->config_items;
171 while(((auth_type_pair = pairfind(cur_config_item, PW_AUTH_TYPE))) != NULL) {
172 auth_type = auth_type_pair->lvalue;
175 DEBUG2(" rad_check_password: Found Auth-Type %s",
176 auth_type_pair->vp_strvalue);
177 cur_config_item = auth_type_pair->next;
179 if (auth_type == PW_AUTHTYPE_REJECT) {
180 DEBUG2(" rad_check_password: Auth-Type = Reject, rejecting user");
185 if (( auth_type_count > 1) && (debug_flag)) {
186 radlog(L_ERR, "Warning: Found %d auth-types on request for user '%s'",
187 auth_type_count, request->username->vp_strvalue);
191 * This means we have a proxy reply or an accept
192 * and it wasn't rejected in the above loop. So
193 * that means it is accepted and we do no further
196 if ((auth_type == PW_AUTHTYPE_ACCEPT) || (request->proxy)) {
197 DEBUG2(" rad_check_password: Auth-Type = Accept, accepting the user");
202 * Find the password from the users file.
204 if ((password_pair = pairfind(request->config_items, PW_CRYPT_PASSWORD)) != NULL) {
206 * Re-write Auth-Type, but ONLY if it isn't already
209 if (auth_type == -1) auth_type = PW_AUTHTYPE_CRYPT;
211 password_pair = pairfind(request->config_items, PW_PASSWORD);
216 auth_type = PW_AUTHTYPE_LOCAL;
219 * The admin hasn't told us how to
220 * authenticate the user, so we reject them!
224 DEBUG2("auth: No authenticate method (Auth-Type) configuration found for the request: Rejecting the user");
232 case PW_AUTHTYPE_CRYPT:
234 * Find the password sent by the user. It
235 * SHOULD be there, if it's not
236 * authentication fails.
238 auth_item = request->password;
239 if (auth_item == NULL) {
240 DEBUG2("auth: No User-Password or CHAP-Password attribute in the request");
244 DEBUG2("auth: type Crypt");
245 if (password_pair == NULL) {
246 DEBUG2("No Crypt-Password configured for the user");
247 rad_authlog("Login incorrect "
248 "(No Crypt-Password configured for the user)", request, 0);
252 switch (lrad_crypt_check((char *)auth_item->vp_strvalue,
253 (char *)password_pair->vp_strvalue)) {
255 rad_authlog("Login incorrect "
256 "(system failed to supply an encrypted password for comparison)", request, 0);
261 case PW_AUTHTYPE_LOCAL:
262 DEBUG2("auth: type Local");
265 * Find the password sent by the user. It
266 * SHOULD be there, if it's not
267 * authentication fails.
269 auth_item = request->password;
270 if (auth_item == NULL) {
271 DEBUG2("auth: No User-Password or CHAP-Password attribute in the request");
276 * Plain text password.
278 if (password_pair == NULL) {
279 DEBUG2("auth: No password configured for the user");
280 rad_authlog("Login incorrect "
281 "(No password configured for the user)", request, 0);
286 * Local password is just plain text.
288 if (auth_item->attribute == PW_PASSWORD) {
289 if (strcmp((char *)password_pair->vp_strvalue,
290 (char *)auth_item->vp_strvalue) != 0) {
291 DEBUG2("auth: user supplied User-Password does NOT match local User-Password");
294 DEBUG2("auth: user supplied User-Password matches local User-Password");
297 } else if (auth_item->attribute != PW_CHAP_PASSWORD) {
298 DEBUG2("The user did not supply a User-Password or a CHAP-Password attribute");
299 rad_authlog("Login incorrect "
300 "(no User-Password or CHAP-Password attribute)", request, 0);
304 rad_chap_encode(request->packet, string,
305 auth_item->vp_strvalue[0], password_pair);
310 if (memcmp(string + 1, auth_item->vp_strvalue + 1,
311 CHAP_VALUE_LENGTH) != 0) {
312 DEBUG2("auth: user supplied CHAP-Password does NOT match local User-Password");
315 DEBUG2("auth: user supplied CHAP-Password matches local User-Password");
318 dval = dict_valbyattr(PW_AUTH_TYPE, auth_type);
320 DEBUG2("auth: type \"%s\"", dval->name);
322 DEBUG2("auth: type UNKNOWN-%d", auth_type);
326 * See if there is a module that handles
327 * this type, and turn the RLM_ return
328 * status into the values as defined at
329 * the top of this function.
331 result = module_authenticate(auth_type, request);
334 * An authentication module FAIL
335 * return code, or any return code that
336 * is not expected from authentication,
337 * is the same as an explicit REJECT!
339 case RLM_MODULE_FAIL:
340 case RLM_MODULE_INVALID:
341 case RLM_MODULE_NOOP:
342 case RLM_MODULE_NOTFOUND:
343 case RLM_MODULE_REJECT:
344 case RLM_MODULE_UPDATED:
345 case RLM_MODULE_USERLOCK:
352 case RLM_MODULE_HANDLED:
363 * Post-authentication step processes the response before it is
364 * sent to the NAS. It can receive both Access-Accept and Access-Reject
367 int rad_postauth(REQUEST *request)
370 int postauth_type = 0;
374 * Do post-authentication calls. ignoring the return code.
376 vp = pairfind(request->config_items, PW_POST_AUTH_TYPE);
378 DEBUG2(" Found Post-Auth-Type %s", vp->vp_strvalue);
379 postauth_type = vp->lvalue;
381 result = module_post_auth(postauth_type, request);
384 * The module failed, or said to reject the user: Do so.
386 case RLM_MODULE_FAIL:
387 case RLM_MODULE_INVALID:
388 case RLM_MODULE_REJECT:
389 case RLM_MODULE_USERLOCK:
391 request->reply->code = PW_AUTHENTICATION_REJECT;
392 result = RLM_MODULE_REJECT;
395 * The module handled the request, cancel the reply.
397 case RLM_MODULE_HANDLED:
401 * The module had a number of OK return codes.
403 case RLM_MODULE_NOOP:
404 case RLM_MODULE_NOTFOUND:
406 case RLM_MODULE_UPDATED:
407 result = RLM_MODULE_OK;
414 * Before sending an Access-Reject, call the modules in the
415 * Post-Auth-Type REJECT stanza.
417 static int rad_postauth_reject(REQUEST *request)
423 dval = dict_valbyname(PW_POST_AUTH_TYPE, "REJECT");
425 /* Overwrite the Post-Auth-Type with the value REJECT */
426 pairdelete(&request->config_items, PW_POST_AUTH_TYPE);
427 tmp = paircreate(PW_POST_AUTH_TYPE, PW_TYPE_INTEGER);
428 tmp->lvalue = dval->value;
429 pairadd(&request->config_items, tmp);
430 result = rad_postauth(request);
432 /* No REJECT stanza */
433 result = RLM_MODULE_OK;
439 * Process and reply to an authentication request
441 * The return value of this function isn't actually used right now, so
442 * it's not entirely clear if it is returning the right things. --Pac.
444 int rad_authenticate(REQUEST *request)
446 VALUE_PAIR *namepair;
447 VALUE_PAIR *check_item;
448 VALUE_PAIR *auth_item;
449 VALUE_PAIR *module_msg;
450 VALUE_PAIR *tmp = NULL;
452 char umsg[MAX_STRING_LEN + 1];
453 const char *user_msg = NULL;
454 const char *password;
462 * If this request got proxied to another server, we need
463 * to check whether it authenticated the request or not.
465 if (request->proxy_reply) {
466 switch (request->proxy_reply->code) {
468 * Reply of ACCEPT means accept, thus set Auth-Type
471 case PW_AUTHENTICATION_ACK:
472 tmp = paircreate(PW_AUTH_TYPE, PW_TYPE_INTEGER);
474 radlog(L_ERR|L_CONS, "Not enough memory");
477 tmp->lvalue = PW_AUTHTYPE_ACCEPT;
478 pairadd(&request->config_items, tmp);
481 * Challenges are punted back to the NAS without any
482 * further processing.
484 case PW_ACCESS_CHALLENGE:
485 request->reply->code = PW_ACCESS_CHALLENGE;
486 return RLM_MODULE_OK;
488 * ALL other replies mean reject. (this is fail-safe)
490 * Do NOT do any authorization or authentication. They
491 * are being rejected, so we minimize the amount of work
492 * done by the server, by rejecting them here.
494 case PW_AUTHENTICATION_REJECT:
496 rad_authlog("Login incorrect (Home Server says so)",
498 request->reply->code = PW_AUTHENTICATION_REJECT;
499 rad_postauth_reject(request);
500 return RLM_MODULE_REJECT;
505 * Get the username from the request.
507 * Note that namepair MAY be NULL, in which case there
508 * is no User-Name attribute in the request.
510 namepair = request->username;
513 * Look for, and cache, passwords.
515 if (!request->password) {
516 request->password = pairfind(request->packet->vps,
521 * Discover which password we want to use.
523 auth_item = request->password;
525 password = (const char *)auth_item->vp_strvalue;
529 * Maybe there's a CHAP-Password?
531 if ((auth_item = pairfind(request->packet->vps,
532 PW_CHAP_PASSWORD)) != NULL) {
533 password = "<CHAP-PASSWORD>";
537 * No password we recognize.
539 password = "<NO-PASSWORD>";
542 request->password = auth_item;
545 * Get the user's authorization information from the database
548 result = module_authorize(autz_type, request);
550 case RLM_MODULE_NOOP:
551 case RLM_MODULE_NOTFOUND:
553 case RLM_MODULE_UPDATED:
555 case RLM_MODULE_FAIL:
556 case RLM_MODULE_HANDLED:
558 case RLM_MODULE_INVALID:
559 case RLM_MODULE_REJECT:
560 case RLM_MODULE_USERLOCK:
562 if ((module_msg = pairfind(request->packet->vps,
563 PW_MODULE_FAILURE_MESSAGE)) != NULL) {
564 char msg[MAX_STRING_LEN + 16];
565 snprintf(msg, sizeof(msg), "Invalid user (%s)",
566 module_msg->vp_strvalue);
567 rad_authlog(msg,request,0);
569 rad_authlog("Invalid user", request, 0);
571 request->reply->code = PW_AUTHENTICATION_REJECT;
575 tmp = pairfind(request->config_items, PW_AUTZ_TYPE);
577 DEBUG2(" Found Autz-Type %s", tmp->vp_strvalue);
578 autz_type = tmp->lvalue;
585 * If we haven't already proxied the packet, then check
586 * to see if we should. Maybe one of the authorize
587 * modules has decided that a proxy should be used. If
588 * so, get out of here and send the packet.
590 if ((request->proxy == NULL) &&
591 ((tmp = pairfind(request->config_items, PW_PROXY_TO_REALM)) != NULL)) {
595 * Catch users who set Proxy-To-Realm to a LOCAL
598 realm = realm_find(tmp->vp_strvalue, 0);
599 rad_assert((realm == NULL) || (realm->ipaddr.af == AF_INET));
600 if (realm && (realm->ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_NONE))) {
601 DEBUG2(" WARNING: You set Proxy-To-Realm = %s, but it is a LOCAL realm! Cancelling invalid proxy request.", realm->realm);
604 * Don't authenticate, as the request is
607 return RLM_MODULE_OK;
612 * Perhaps there is a Stripped-User-Name now.
614 namepair = request->username;
620 result = rad_check_password(request);
623 return RLM_MODULE_HANDLED;
628 * Failed to validate the user.
630 * We PRESUME that the code which failed will clean up
631 * request->reply->vps, to be ONLY the reply items it
632 * wants to send back.
635 DEBUG2("auth: Failed to validate the user.");
636 request->reply->code = PW_AUTHENTICATION_REJECT;
638 if ((module_msg = pairfind(request->packet->vps,PW_MODULE_FAILURE_MESSAGE)) != NULL){
639 char msg[MAX_STRING_LEN+19];
641 snprintf(msg, sizeof(msg), "Login incorrect (%s)",
642 module_msg->vp_strvalue);
643 rad_authlog(msg, request, 0);
645 rad_authlog("Login incorrect", request, 0);
648 /* double check: maybe the secret is wrong? */
649 if ((debug_flag > 1) && (auth_item != NULL) &&
650 (auth_item->attribute == PW_PASSWORD)) {
653 p = auth_item->vp_strvalue;
655 if (!isprint((int) *p)) {
656 log_debug(" WARNING: Unprintable characters in the password.\n\t Double-check the shared secret on the server and the NAS!");
665 (check_item = pairfind(request->config_items, PW_SIMULTANEOUS_USE)) != NULL) {
666 int r, session_type = 0;
668 tmp = pairfind(request->config_items, PW_SESSION_TYPE);
670 DEBUG2(" Found Session-Type %s", tmp->vp_strvalue);
671 session_type = tmp->lvalue;
675 * User authenticated O.K. Now we have to check
676 * for the Simultaneous-Use parameter.
679 (r = module_checksimul(session_type, request, check_item->lvalue)) != 0) {
683 /* Multilink attempt. Check if port-limit > simultaneous-use */
684 VALUE_PAIR *port_limit;
686 if ((port_limit = pairfind(request->reply->vps, PW_PORT_LIMIT)) != NULL &&
687 port_limit->lvalue > check_item->lvalue){
688 DEBUG2("main auth: MPP is OK");
693 if (check_item->lvalue > 1) {
694 snprintf(umsg, sizeof(umsg),
695 "\r\nYou are already logged in %d times - access denied\r\n\n",
696 (int)check_item->lvalue);
699 user_msg = "\r\nYou are already logged in - access denied\r\n\n";
702 request->reply->code = PW_AUTHENTICATION_REJECT;
705 * They're trying to log in too many times.
706 * Remove ALL reply attributes.
708 pairfree(&request->reply->vps);
709 tmp = pairmake("Reply-Message", user_msg, T_OP_SET);
710 request->reply->vps = tmp;
712 snprintf(logstr, sizeof(logstr), "Multiple logins (max %d) %s",
714 r == 2 ? "[MPP attempt]" : "");
715 rad_authlog(logstr, request, 1);
723 * Result should be >= 0 here - if not, it means the user
724 * is rejected, so we just process post-auth and return.
727 rad_postauth_reject(request);
728 return RLM_MODULE_REJECT;
732 * We might need this later. The 'password' string
733 * is NOT used anywhere below here, except for logging,
734 * so it should be safe...
736 if ((auth_item != NULL) && (auth_item->attribute == PW_CHAP_PASSWORD)) {
737 password = "CHAP-Password";
741 * Add the port number to the Framed-IP-Address if
742 * vp->addport is set.
744 if (((tmp = pairfind(request->reply->vps,
745 PW_FRAMED_IP_ADDRESS)) != NULL) &&
746 (tmp->flags.addport != 0)) {
747 VALUE_PAIR *vpPortId;
750 * Find the NAS port ID.
752 if ((vpPortId = pairfind(request->packet->vps,
753 PW_NAS_PORT)) != NULL) {
754 unsigned long tvalue = ntohl(tmp->lvalue);
755 tmp->lvalue = htonl(tvalue + vpPortId->lvalue);
756 tmp->flags.addport = 0;
757 ip_ntoa(tmp->vp_strvalue, tmp->lvalue);
759 DEBUG2("WARNING: No NAS-Port attribute in request. CANNOT return a Framed-IP-Address + NAS-Port.\n");
760 pairdelete(&request->reply->vps, PW_FRAMED_IP_ADDRESS);
765 * Set the reply to Access-Accept, if it hasn't already
766 * been set to something. (i.e. Access-Challenge)
768 if (request->reply->code == 0)
769 request->reply->code = PW_AUTHENTICATION_ACK;
771 if ((module_msg = pairfind(request->packet->vps,PW_MODULE_SUCCESS_MESSAGE)) != NULL){
772 char msg[MAX_STRING_LEN+12];
774 snprintf(msg, sizeof(msg), "Login OK (%s)",
775 module_msg->vp_strvalue);
776 rad_authlog(msg, request, 1);
778 rad_authlog("Login OK", request, 1);
782 * Run the modules in the 'post-auth' section.
784 result = rad_postauth(request);