/[ \t]+$//
[freeradius.git] / src / main / auth.c
1 /*
2  * auth.c       User authentication.
3  *
4  * Version:     $Id$
5  *
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.
10  *
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.
15  *
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000,2006  The FreeRADIUS server project
21  * Copyright 2000  Miquel van Smoorenburg <miquels@cistron.nl>
22  * Copyright 2000  Jeff Carneal <jeff@apex.net>
23  */
24 RCSID("$Id$")
25
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/modules.h>
28 #include <freeradius-devel/rad_assert.h>
29
30 #include <ctype.h>
31
32 /*
33  *      Return a short string showing the terminal server, port
34  *      and calling station ID.
35  */
36 char *auth_name(char *buf, size_t buflen, REQUEST *request, int do_cli)
37 {
38         VALUE_PAIR      *cli;
39         VALUE_PAIR      *pair;
40         int             port = 0;
41         char const      *tls = "";
42
43         if ((cli = pairfind(request->packet->vps, PW_CALLING_STATION_ID, 0, TAG_ANY)) == NULL)
44                 do_cli = 0;
45         if ((pair = pairfind(request->packet->vps, PW_NAS_PORT, 0, TAG_ANY)) != NULL)
46                 port = pair->vp_integer;
47
48         if (request->packet->dst_port == 0) {
49                 if (pairfind(request->packet->vps, PW_FREERADIUS_PROXIED_TO, 0, TAG_ANY)) {
50                         tls = " via TLS tunnel";
51                 } else {
52                         tls = " via proxy to virtual server";
53                 }
54         }
55
56         snprintf(buf, buflen, "from client %.128s port %u%s%.128s%s",
57                         request->client->shortname, port,
58                  (do_cli ? " cli " : ""), (do_cli ? cli->vp_strvalue : ""),
59                  tls);
60
61         return buf;
62 }
63
64
65
66 /*
67  * Make sure user/pass are clean
68  * and then log them
69  */
70 static int rad_authlog(char const *msg, REQUEST *request, int goodpass)
71 {
72         int logit;
73         char const *extra_msg = NULL;
74         char clean_password[1024];
75         char clean_username[1024];
76         char buf[1024];
77         char extra[1024];
78         char *p;
79         VALUE_PAIR *username = NULL;
80
81         if (!request->root->log_auth) {
82                 return 0;
83         }
84
85         /*
86          * Get the correct username based on the configured value
87          */
88         if (log_stripped_names == 0) {
89                 username = pairfind(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
90         } else {
91                 username = request->username;
92         }
93
94         /*
95          *      Clean up the username
96          */
97         if (username == NULL) {
98                 strcpy(clean_username, "<no User-Name attribute>");
99         } else {
100                 fr_print_string(username->vp_strvalue,
101                                 username->length,
102                                 clean_username, sizeof(clean_username));
103         }
104
105         /*
106          *      Clean up the password
107          */
108         if (request->root->log_auth_badpass || request->root->log_auth_goodpass) {
109                 if (!request->password) {
110                         VALUE_PAIR *auth_type;
111
112                         auth_type = pairfind(request->config_items, PW_AUTH_TYPE, 0, TAG_ANY);
113                         if (auth_type) {
114                                 snprintf(clean_password, sizeof(clean_password),
115                                          "<via Auth-Type = %s>",
116                                          dict_valnamebyattr(PW_AUTH_TYPE, 0,
117                                                             auth_type->vp_integer));
118                         } else {
119                                 strcpy(clean_password, "<no User-Password attribute>");
120                         }
121                 } else if (pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) {
122                         strcpy(clean_password, "<CHAP-Password>");
123                 } else {
124                         fr_print_string(request->password->vp_strvalue,
125                                          request->password->length,
126                                          clean_password, sizeof(clean_password));
127                 }
128         }
129
130         if (goodpass) {
131                 logit = request->root->log_auth_goodpass;
132                 extra_msg = request->root->auth_goodpass_msg;
133         } else {
134                 logit = request->root->log_auth_badpass;
135                 extra_msg = request->root->auth_badpass_msg;
136         }
137
138         if (extra_msg) {
139                 extra[0] = ' ';
140                 p = extra + 1;
141                 if (radius_xlat(p, sizeof(extra) - 1, request, extra_msg, NULL, NULL) < 0) {
142                         return -1;
143                 }
144         } else {
145                 *extra = '\0';
146         }
147
148         RAUTH("%s: [%s%s%s] (%s)%s",
149                        msg,
150                        clean_username,
151                        logit ? "/" : "",
152                        logit ? clean_password : "",
153                        auth_name(buf, sizeof(buf), request, 1),
154                        extra);
155
156         return 0;
157 }
158
159 /*
160  *      Check password.
161  *
162  *      Returns:        0  OK
163  *                      -1 Password fail
164  *                      -2 Rejected (Auth-Type = Reject, send Port-Message back)
165  *                      1  End check & return, don't reply
166  *
167  *      NOTE: NOT the same as the RLM_ values !
168  */
169 static int rad_check_password(REQUEST *request)
170 {
171         vp_cursor_t cursor;
172         VALUE_PAIR *auth_type_pair;
173         int auth_type = -1;
174         int result;
175         int auth_type_count = 0;
176         result = 0;
177
178         /*
179          *      Look for matching check items. We skip the whole lot
180          *      if the authentication type is PW_AUTHTYPE_ACCEPT or
181          *      PW_AUTHTYPE_REJECT.
182          */
183         paircursor(&cursor, &request->config_items);
184         while ((auth_type_pair = pairfindnext(&cursor, PW_AUTH_TYPE, 0, TAG_ANY))) {
185                 auth_type = auth_type_pair->vp_integer;
186                 auth_type_count++;
187
188                 RDEBUG2("Found Auth-Type = %s", dict_valnamebyattr(PW_AUTH_TYPE, 0, auth_type));
189                 if (auth_type == PW_AUTHTYPE_REJECT) {
190                         RDEBUG2("Auth-Type = Reject, rejecting user");
191
192                         return -2;
193                 }
194         }
195
196         /*
197          *      Warn if more than one Auth-Type was found, because only the last
198          *      one found will actually be used.
199          */
200         if ((auth_type_count > 1) && (debug_flag)) {
201                 RERROR("Warning:  Found %d auth-types on request for user '%s'",
202                         auth_type_count, request->username->vp_strvalue);
203         }
204
205         /*
206          *      This means we have a proxy reply or an accept and it wasn't
207          *      rejected in the above loop. So that means it is accepted and we
208          *      do no further authentication.
209          */
210         if ((auth_type == PW_AUTHTYPE_ACCEPT)
211 #ifdef WITH_PROXY
212             || (request->proxy)
213 #endif
214             ) {
215                 RDEBUG2("Auth-Type = Accept, accepting the user");
216                 return 0;
217         }
218
219         /*
220          *      Check that Auth-Type has been set, and reject if not.
221          *
222          *      Do quick checks to see if Cleartext-Password or Crypt-Password have
223          *      been set, and complain if so.
224          */
225         if (auth_type < 0) {
226                 if (pairfind(request->config_items, PW_CRYPT_PASSWORD, 0, TAG_ANY) != NULL) {
227                         RWDEBUG2("Please update your configuration, and remove 'Auth-Type = Crypt'");
228                         RWDEBUG2("Use the PAP module instead.");
229                 }
230                 else if (pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY) != NULL) {
231                         RWDEBUG2("Please update your configuration, and remove 'Auth-Type = Local'");
232                         RWDEBUG2("Use the PAP or CHAP modules instead.");
233                 }
234
235                 /*
236                  *      The admin hasn't told us how to
237                  *      authenticate the user, so we reject them!
238                  *
239                  *      This is fail-safe.
240                  */
241
242                 REDEBUG2("No Auth-Type found: rejecting the user via Post-Auth-Type = Reject");
243                 return -2;
244         }
245
246         /*
247          *      See if there is a module that handles
248          *      this Auth-Type, and turn the RLM_ return
249          *      status into the values as defined at
250          *      the top of this function.
251          */
252         result = process_authenticate(auth_type, request);
253         switch (result) {
254                 /*
255                  *      An authentication module FAIL
256                  *      return code, or any return code that
257                  *      is not expected from authentication,
258                  *      is the same as an explicit REJECT!
259                  */
260                 case RLM_MODULE_FAIL:
261                 case RLM_MODULE_INVALID:
262                 case RLM_MODULE_NOOP:
263                 case RLM_MODULE_NOTFOUND:
264                 case RLM_MODULE_REJECT:
265                 case RLM_MODULE_UPDATED:
266                 case RLM_MODULE_USERLOCK:
267                 default:
268                         result = -1;
269                         break;
270                 case RLM_MODULE_OK:
271                         result = 0;
272                         break;
273                 case RLM_MODULE_HANDLED:
274                         result = 1;
275                         break;
276         }
277
278         return result;
279 }
280
281 /*
282  *      Post-authentication step processes the response before it is
283  *      sent to the NAS. It can receive both Access-Accept and Access-Reject
284  *      replies.
285  */
286 int rad_postauth(REQUEST *request)
287 {
288         int     result;
289         int     postauth_type = 0;
290         VALUE_PAIR *vp;
291
292         /*
293          *      Do post-authentication calls. ignoring the return code.
294          */
295         vp = pairfind(request->config_items, PW_POST_AUTH_TYPE, 0, TAG_ANY);
296         if (vp) {
297                 postauth_type = vp->vp_integer;
298                 RDEBUG2("Using Post-Auth-Type %s",
299                         dict_valnamebyattr(PW_POST_AUTH_TYPE, 0, postauth_type));
300         }
301         result = process_post_auth(postauth_type, request);
302         switch (result) {
303                 /*
304                  *      The module failed, or said to reject the user: Do so.
305                  */
306                 case RLM_MODULE_FAIL:
307                 case RLM_MODULE_INVALID:
308                 case RLM_MODULE_REJECT:
309                 case RLM_MODULE_USERLOCK:
310                 default:
311                         request->reply->code = PW_AUTHENTICATION_REJECT;
312                         result = RLM_MODULE_REJECT;
313                         break;
314                 /*
315                  *      The module handled the request, cancel the reply.
316                  */
317                 case RLM_MODULE_HANDLED:
318                         /* FIXME */
319                         break;
320                 /*
321                  *      The module had a number of OK return codes.
322                  */
323                 case RLM_MODULE_NOOP:
324                 case RLM_MODULE_NOTFOUND:
325                 case RLM_MODULE_OK:
326                 case RLM_MODULE_UPDATED:
327                         result = RLM_MODULE_OK;
328                         break;
329         }
330         return result;
331 }
332
333 /*
334  *      Process and reply to an authentication request
335  *
336  *      The return value of this function isn't actually used right now, so
337  *      it's not entirely clear if it is returning the right things. --Pac.
338  */
339 int rad_authenticate(REQUEST *request)
340 {
341         VALUE_PAIR      *namepair;
342 #ifdef WITH_SESSION_MGMT
343         VALUE_PAIR      *check_item;
344 #endif
345         VALUE_PAIR      *auth_item = NULL;
346         VALUE_PAIR      *module_msg;
347         VALUE_PAIR      *tmp = NULL;
348         int             result;
349         char            autz_retry = 0;
350         int             autz_type = 0;
351
352 #ifdef WITH_PROXY
353         /*
354          *      If this request got proxied to another server, we need
355          *      to check whether it authenticated the request or not.
356          */
357         if (request->proxy_reply) {
358                 switch (request->proxy_reply->code) {
359                 /*
360                  *      Reply of ACCEPT means accept, thus set Auth-Type
361                  *      accordingly.
362                  */
363                 case PW_AUTHENTICATION_ACK:
364                         tmp = radius_paircreate(request,
365                                                 &request->config_items,
366                                                 PW_AUTH_TYPE, 0);
367                         if (tmp) tmp->vp_integer = PW_AUTHTYPE_ACCEPT;
368                         goto authenticate;
369
370                 /*
371                  *      Challenges are punted back to the NAS without any
372                  *      further processing.
373                  */
374                 case PW_ACCESS_CHALLENGE:
375                         request->reply->code = PW_ACCESS_CHALLENGE;
376                         return RLM_MODULE_OK;
377                 /*
378                  *      ALL other replies mean reject. (this is fail-safe)
379                  *
380                  *      Do NOT do any authorization or authentication. They
381                  *      are being rejected, so we minimize the amount of work
382                  *      done by the server, by rejecting them here.
383                  */
384                 case PW_AUTHENTICATION_REJECT:
385                         rad_authlog("Login incorrect (Home Server says so)",
386                                     request, 0);
387                         request->reply->code = PW_AUTHENTICATION_REJECT;
388                         return RLM_MODULE_REJECT;
389
390                 default:
391                         rad_authlog("Login incorrect (Home Server failed to respond)",
392                                     request, 0);
393                         return RLM_MODULE_REJECT;
394                 }
395         }
396 #endif
397
398         /*
399          *      Get the username from the request.
400          *
401          *      Note that namepair MAY be NULL, in which case there
402          *      is no User-Name attribute in the request.
403          */
404         namepair = request->username;
405
406         /*
407          *      Look for, and cache, passwords.
408          */
409         if (!request->password) {
410                 request->password = pairfind(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
411         }
412
413         /*
414          *      Discover which password we want to use.
415          */
416         auth_item = request->password;
417         if (!auth_item) {
418                 auth_item = pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY);
419         }
420         request->password = auth_item;
421
422         /*
423          *      Get the user's authorization information from the database
424          */
425 autz_redo:
426         result = process_authorize(autz_type, request);
427         switch (result) {
428                 case RLM_MODULE_NOOP:
429                 case RLM_MODULE_NOTFOUND:
430                 case RLM_MODULE_OK:
431                 case RLM_MODULE_UPDATED:
432                         break;
433                 case RLM_MODULE_HANDLED:
434                         return result;
435                 case RLM_MODULE_FAIL:
436                 case RLM_MODULE_INVALID:
437                 case RLM_MODULE_REJECT:
438                 case RLM_MODULE_USERLOCK:
439                 default:
440                         if ((module_msg = pairfind(request->packet->vps, PW_MODULE_FAILURE_MESSAGE, 0, TAG_ANY)) != NULL) {
441                                 char msg[MAX_STRING_LEN + 16];
442                                 snprintf(msg, sizeof(msg), "Invalid user (%s)",
443                                          module_msg->vp_strvalue);
444                                 rad_authlog(msg,request,0);
445                         } else {
446                                 rad_authlog("Invalid user", request, 0);
447                         }
448                         request->reply->code = PW_AUTHENTICATION_REJECT;
449                         return result;
450         }
451         if (!autz_retry) {
452                 tmp = pairfind(request->config_items, PW_AUTZ_TYPE, 0, TAG_ANY);
453                 if (tmp) {
454                         autz_type = tmp->vp_integer;
455                         RDEBUG2("Using Autz-Type %s",
456                                 dict_valnamebyattr(PW_AUTZ_TYPE, 0, autz_type));
457                         autz_retry = 1;
458                         goto autz_redo;
459                 }
460         }
461
462         /*
463          *      If we haven't already proxied the packet, then check
464          *      to see if we should.  Maybe one of the authorize
465          *      modules has decided that a proxy should be used. If
466          *      so, get out of here and send the packet.
467          */
468         if (
469 #ifdef WITH_PROXY
470             (request->proxy == NULL) &&
471 #endif
472             ((tmp = pairfind(request->config_items, PW_PROXY_TO_REALM, 0, TAG_ANY)) != NULL)) {
473                 REALM *realm;
474
475                 realm = realm_find2(tmp->vp_strvalue);
476
477                 /*
478                  *      Don't authenticate, as the request is going to
479                  *      be proxied.
480                  */
481                 if (realm && realm->auth_pool) {
482                         return RLM_MODULE_OK;
483                 }
484
485                 /*
486                  *      Catch users who set Proxy-To-Realm to a LOCAL
487                  *      realm (sigh).  But don't complain if it is
488                  *      *the* LOCAL realm.
489                  */
490                 if (realm &&(strcmp(realm->name, "LOCAL") != 0)) {
491                         RWDEBUG2("You set Proxy-To-Realm = %s, but it is a LOCAL realm!  Cancelling proxy request.", realm->name);
492                 }
493
494                 if (!realm) {
495                         RWDEBUG2("You set Proxy-To-Realm = %s, but the realm does not exist!  Cancelling invalid proxy request.", tmp->vp_strvalue);
496                 }
497         }
498
499 #ifdef WITH_PROXY
500  authenticate:
501 #endif
502
503         /*
504          *      Perhaps there is a Stripped-User-Name now.
505          */
506         namepair = request->username;
507
508         /*
509          *      Validate the user
510          */
511         do {
512                 result = rad_check_password(request);
513                 if (result > 0) {
514                         /* don't reply! */
515                         return RLM_MODULE_HANDLED;
516                 }
517         } while(0);
518
519         /*
520          *      Failed to validate the user.
521          *
522          *      We PRESUME that the code which failed will clean up
523          *      request->reply->vps, to be ONLY the reply items it
524          *      wants to send back.
525          */
526         if (result < 0) {
527                 RDEBUG2("Failed to authenticate the user.");
528                 request->reply->code = PW_AUTHENTICATION_REJECT;
529
530                 if ((module_msg = pairfind(request->packet->vps, PW_MODULE_FAILURE_MESSAGE, 0, TAG_ANY)) != NULL){
531                         char msg[MAX_STRING_LEN+19];
532
533                         snprintf(msg, sizeof(msg), "Login incorrect (%s)",
534                                  module_msg->vp_strvalue);
535                         rad_authlog(msg, request, 0);
536                 } else {
537                         rad_authlog("Login incorrect", request, 0);
538                 }
539
540                 /* double check: maybe the secret is wrong? */
541                 if ((debug_flag > 1) && (auth_item != NULL) &&
542                                 (auth_item->da->attr == PW_USER_PASSWORD)) {
543                         uint8_t const *p;
544
545                         p = (uint8_t const *) auth_item->vp_strvalue;
546                         while (*p) {
547                                 int size;
548
549                                 size = fr_utf8_char(p);
550                                 if (!size) {
551                                         RWDEBUG("Unprintable characters in the password.  Double-check the shared secret on the server and the NAS!");
552                                         break;
553                                 }
554                                 p += size;
555                         }
556                 }
557         }
558
559 #ifdef WITH_SESSION_MGMT
560         if (result >= 0 &&
561             (check_item = pairfind(request->config_items, PW_SIMULTANEOUS_USE, 0, TAG_ANY)) != NULL) {
562                 int r, session_type = 0;
563                 char            logstr[1024];
564                 char            umsg[MAX_STRING_LEN + 1];
565                 char const      *user_msg = NULL;
566
567                 tmp = pairfind(request->config_items, PW_SESSION_TYPE, 0, TAG_ANY);
568                 if (tmp) {
569                         session_type = tmp->vp_integer;
570                         RDEBUG2("Using Session-Type %s",
571                                 dict_valnamebyattr(PW_SESSION_TYPE, 0, session_type));
572                 }
573
574                 /*
575                  *      User authenticated O.K. Now we have to check
576                  *      for the Simultaneous-Use parameter.
577                  */
578                 if (namepair &&
579                     (r = process_checksimul(session_type, request, check_item->vp_integer)) != 0) {
580                         char mpp_ok = 0;
581
582                         if (r == 2){
583                                 /* Multilink attempt. Check if port-limit > simultaneous-use */
584                                 VALUE_PAIR *port_limit;
585
586                                 if ((port_limit = pairfind(request->reply->vps, PW_PORT_LIMIT, 0, TAG_ANY)) != NULL &&
587                                         port_limit->vp_integer > check_item->vp_integer){
588                                         RDEBUG2("MPP is OK");
589                                         mpp_ok = 1;
590                                 }
591                         }
592                         if (!mpp_ok){
593                                 if (check_item->vp_integer > 1) {
594                                 snprintf(umsg, sizeof(umsg),
595                                                         "\r\nYou are already logged in %d times  - access denied\r\n\n",
596                                                         (int)check_item->vp_integer);
597                                         user_msg = umsg;
598                                 } else {
599                                         user_msg = "\r\nYou are already logged in - access denied\r\n\n";
600                                 }
601
602                                 request->reply->code = PW_AUTHENTICATION_REJECT;
603
604                                 /*
605                                  *      They're trying to log in too many times.
606                                  *      Remove ALL reply attributes.
607                                  */
608                                 pairfree(&request->reply->vps);
609                                 pairmake_reply("Reply-Message",
610                                                user_msg, T_OP_SET);
611
612                                 snprintf(logstr, sizeof(logstr), "Multiple logins (max %d) %s",
613                                         check_item->vp_integer,
614                                         r == 2 ? "[MPP attempt]" : "");
615                                 rad_authlog(logstr, request, 1);
616
617                                 result = -1;
618                         }
619                 }
620         }
621 #endif
622
623         /*
624          *      Result should be >= 0 here - if not, it means the user
625          *      is rejected, so we just process post-auth and return.
626          */
627         if (result < 0) {
628                 return RLM_MODULE_REJECT;
629         }
630
631         /*
632          *      Set the reply to Access-Accept, if it hasn't already
633          *      been set to something.  (i.e. Access-Challenge)
634          */
635         if (request->reply->code == 0)
636           request->reply->code = PW_AUTHENTICATION_ACK;
637
638         if ((module_msg = pairfind(request->packet->vps, PW_MODULE_SUCCESS_MESSAGE, 0, TAG_ANY)) != NULL){
639                 char msg[MAX_STRING_LEN+12];
640
641                 snprintf(msg, sizeof(msg), "Login OK (%s)",
642                          module_msg->vp_strvalue);
643                 rad_authlog(msg, request, 1);
644         } else {
645                 rad_authlog("Login OK", request, 1);
646         }
647
648         return result;
649 }
650
651 /*
652  *      Run a virtual server auth and postauth
653  *
654  */
655 int rad_virtual_server(REQUEST *request)
656 {
657         VALUE_PAIR *vp;
658         int result;
659
660         /*
661          *      We currently only handle AUTH packets here.
662          *      This could be expanded to handle other packets as well if required.
663          */
664         rad_assert(request->packet->code == PW_AUTHENTICATION_REQUEST);
665
666         result = rad_authenticate(request);
667
668         if (request->reply->code == PW_AUTHENTICATION_REJECT) {
669                 pairdelete(&request->config_items, PW_POST_AUTH_TYPE, 0, TAG_ANY);
670                 vp = pairmake_config("Post-Auth-Type", "Reject", T_OP_SET);
671                 if (vp) rad_postauth(request);
672         }
673
674         if (request->reply->code == PW_AUTHENTICATION_ACK) {
675                 rad_postauth(request);
676         }
677
678         return result;
679 }
680