rlm_otp import from HEAD
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * Copyright 2000  The FreeRADIUS server project
21  * Copyright 2000  Miquel van Smoorenburg <miquels@cistron.nl>
22  * Copyright 2000  Jeff Carneal <jeff@apex.net>
23  */
24
25 static const char rcsid[] = "$Id$";
26
27 #include "autoconf.h"
28 #include "libradius.h"
29
30 #include <stdlib.h>
31 #include <string.h>
32 #include <ctype.h>
33
34 #ifdef HAVE_NETINET_IN_H
35 #       include <netinet/in.h>
36 #endif
37
38 #include "radiusd.h"
39 #include "modules.h"
40
41 /*
42  *      Return a short string showing the terminal server, port
43  *      and calling station ID.
44  */
45 char *auth_name(char *buf, size_t buflen, REQUEST *request, int do_cli) {
46         VALUE_PAIR      *cli;
47         VALUE_PAIR      *pair;
48         int             port = 0;
49
50         if ((cli = pairfind(request->packet->vps, PW_CALLING_STATION_ID)) == NULL)
51                 do_cli = 0;
52         if ((pair = pairfind(request->packet->vps, PW_NAS_PORT)) != NULL)
53                 port = pair->lvalue;
54
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 : ""));
58
59         return buf;
60 }
61
62
63 /*
64  *      Check if account has expired, and if user may login now.
65  */
66 static int check_expiration(REQUEST *request)
67 {
68         int result;
69         VALUE_PAIR *check_item = request->config_items;
70
71         result = 0;
72         while (result == 0 && check_item != NULL) {
73
74                 /*
75                  *      Check expiration date if we are doing password aging.
76                  */
77                 if (check_item->attribute == PW_EXPIRATION) {
78                         /*
79                          *      Has this user's password expired?
80                          *
81                          *      If so, remove ALL reply attributes,
82                          *      and add our own Reply-Message, saying
83                          *      why they're being rejected.
84                          */
85                         if (check_item->lvalue < (unsigned) time(NULL)) {
86                                 VALUE_PAIR *vp;
87
88                                 result = -1;
89                                 vp = pairmake("Reply-Message",
90                                                 "Password Has Expired\r\n",
91                                                 T_OP_ADD);
92                                 pairfree(&request->reply->vps);
93                                 request->reply->vps = vp;
94                                 break;
95                         }
96                 }
97                 check_item = check_item->next;
98         }
99         return result;
100 }
101
102
103 /*
104  * Make sure user/pass are clean
105  * and then log them
106  */
107 static int rad_authlog(const char *msg, REQUEST *request, int goodpass) {
108
109         char clean_password[1024];
110         char clean_username[1024];
111         char buf[1024];
112         VALUE_PAIR *username = NULL;
113
114         if (!mainconfig.log_auth) {
115                 return 0;
116         }
117
118         /*
119          * Get the correct username based on the configured value
120          */
121         if (log_stripped_names == 0) {
122                 username = pairfind(request->packet->vps, PW_USER_NAME);
123         } else {
124                 username = request->username;
125         }
126
127         /*
128          *      Clean up the username
129          */
130         if (username == NULL) {
131                 strcpy(clean_username, "<no User-Name attribute>");
132         } else {
133                 librad_safeprint((char *)username->strvalue,
134                                 username->length,
135                                 clean_username, sizeof(clean_username));
136         }
137
138         /*
139          *      Clean up the password
140          */
141         if (mainconfig.log_auth_badpass || mainconfig.log_auth_goodpass) {
142                 if (!request->password) {
143                         strcpy(clean_password, "<no User-Password attribute>");
144                 } else if (request->password->attribute == PW_CHAP_PASSWORD) {
145                         strcpy(clean_password, "<CHAP-Password>");
146                 } else {
147                         librad_safeprint((char *)request->password->strvalue,
148                                          request->password->length,
149                                          clean_password, sizeof(clean_password));
150                 }
151         }
152
153         if (goodpass) {
154                 radlog(L_AUTH, "%s: [%s%s%s] (%s)",
155                                 msg,
156                                 clean_username,
157                                 mainconfig.log_auth_goodpass ? "/" : "",
158                                 mainconfig.log_auth_goodpass ? clean_password : "",
159                                 auth_name(buf, sizeof(buf), request, 1));
160         } else {
161                 radlog(L_AUTH, "%s: [%s%s%s] (%s)",
162                                 msg,
163                                 clean_username,
164                                 mainconfig.log_auth_badpass ? "/" : "",
165                                 mainconfig.log_auth_badpass ? clean_password : "",
166                                 auth_name(buf, sizeof(buf), request, 1));
167         }
168
169         return 0;
170 }
171
172 /*
173  *      Check password.
174  *
175  *      Returns:        0  OK
176  *                      -1 Password fail
177  *                      -2 Rejected (Auth-Type = Reject, send Port-Message back)
178  *                      1  End check & return, don't reply
179  *
180  *      NOTE: NOT the same as the RLM_ values !
181  */
182 int rad_check_password(REQUEST *request)
183 {
184         VALUE_PAIR *auth_type_pair;
185         VALUE_PAIR *cur_config_item;
186         VALUE_PAIR *password_pair;
187         VALUE_PAIR *auth_item;
188         char string[MAX_STRING_LEN];
189         int auth_type = -1;
190         int result;
191         int auth_type_count = 0;
192         result = 0;
193
194         /*
195          *      Look for matching check items. We skip the whole lot
196          *      if the authentication type is PW_AUTHTYPE_ACCEPT or
197          *      PW_AUTHTYPE_REJECT.
198          */
199         cur_config_item = request->config_items;
200         while(((auth_type_pair = pairfind(cur_config_item, PW_AUTH_TYPE))) != NULL) {
201                 auth_type = auth_type_pair->lvalue;
202                 auth_type_count++;
203
204                 DEBUG2("  rad_check_password:  Found Auth-Type %s",
205                                 auth_type_pair->strvalue);
206                 cur_config_item = auth_type_pair->next;
207
208                 if (auth_type == PW_AUTHTYPE_REJECT) {
209                         DEBUG2("  rad_check_password: Auth-Type = Reject, rejecting user");
210                         return -2;
211                 }
212         }
213
214         if (( auth_type_count > 1) && (debug_flag)) {
215                 radlog(L_ERR, "Warning:  Found %d auth-types on request for user '%s'",
216                         auth_type_count, request->username->strvalue);
217         }
218
219         /*
220          *      This means we have a proxy reply or an accept
221          *  and it wasn't rejected in the above loop.  So
222          *  that means it is accepted and we do no further
223          *  authentication
224          */
225         if ((auth_type == PW_AUTHTYPE_ACCEPT) || (request->proxy)) {
226                 DEBUG2("  rad_check_password: Auth-Type = Accept, accepting the user");
227                 return 0;
228         }
229
230         /*
231          *      Find the password from the users file.
232          */
233         if ((password_pair = pairfind(request->config_items, PW_CRYPT_PASSWORD)) != NULL) {
234                 /*
235                  *      Re-write Auth-Type, but ONLY if it isn't already
236                  *      set.
237                  */
238                 if (auth_type == -1) auth_type = PW_AUTHTYPE_CRYPT;
239         } else {
240                 password_pair = pairfind(request->config_items, PW_PASSWORD);
241         }
242
243         if (auth_type < 0) {
244                 if (password_pair) {
245                         auth_type = PW_AUTHTYPE_LOCAL;
246                 } else {
247                         /*
248                         *       The admin hasn't told us how to
249                         *       authenticate the user, so we reject them!
250                         *
251                         *       This is fail-safe.
252                         */
253                         DEBUG2("auth: No authenticate method (Auth-Type) configuration found for the request: Rejecting the user");
254                         return -2;
255                 }
256         }
257
258         switch(auth_type) {
259                 case PW_AUTHTYPE_CRYPT:
260                         /*
261                          *      Find the password sent by the user. It
262                          *      SHOULD be there, if it's not
263                          *      authentication fails.
264                          */
265                         auth_item = request->password;
266                         if (auth_item == NULL) {
267                                 DEBUG2("auth: No User-Password or CHAP-Password attribute in the request");
268                                 return -1;
269                         }
270
271                         DEBUG2("auth: type Crypt");
272                         if (password_pair == NULL) {
273                                 DEBUG2("No Crypt-Password configured for the user");
274                                 rad_authlog("Login incorrect "
275                                         "(No Crypt-Password configured for the user)", request, 0);
276                                 return -1;
277                         }
278
279                         switch (lrad_crypt_check((char *)auth_item->strvalue,
280                                                                          (char *)password_pair->strvalue)) {
281                         case -1:
282                           rad_authlog("Login incorrect "
283                                                   "(system failed to supply an encrypted password for comparison)", request, 0);
284                         case 1:
285                           return -1;
286                         }
287                         break;
288                 case PW_AUTHTYPE_LOCAL:
289                         DEBUG2("auth: type Local");
290
291                         /*
292                          *      Find the password sent by the user. It
293                          *      SHOULD be there, if it's not
294                          *      authentication fails.
295                          */
296                         auth_item = request->password;
297                         if (auth_item == NULL) {
298                                 DEBUG2("auth: No User-Password or CHAP-Password attribute in the request");
299                                 return -1;
300                         }
301
302                         /*
303                          *      Plain text password.
304                          */
305                         if (password_pair == NULL) {
306                                 DEBUG2("auth: No password configured for the user");
307                                 rad_authlog("Login incorrect "
308                                         "(No password configured for the user)", request, 0);
309                                 return -1;
310                         }
311
312                         /*
313                          *      Local password is just plain text.
314                          */
315                         if (auth_item->attribute == PW_PASSWORD) {
316                                 if (strcmp((char *)password_pair->strvalue,
317                                            (char *)auth_item->strvalue) != 0) {
318                                         DEBUG2("auth: user supplied User-Password does NOT match local User-Password");
319                                         return -1;
320                                 }
321                                 DEBUG2("auth: user supplied User-Password matches local User-Password");
322                                 break;
323
324                         } else if (auth_item->attribute != PW_CHAP_PASSWORD) {
325                                 DEBUG2("The user did not supply a User-Password or a CHAP-Password attribute");
326                                 rad_authlog("Login incorrect "
327                                         "(no User-Password or CHAP-Password attribute)", request, 0);
328                                 return -1;
329                         }
330
331                         rad_chap_encode(request->packet, string,
332                                         auth_item->strvalue[0], password_pair);
333
334                         /*
335                          *      Compare them
336                          */
337                         if (memcmp(string + 1, auth_item->strvalue + 1,
338                                    CHAP_VALUE_LENGTH) != 0) {
339                                 DEBUG2("auth: user supplied CHAP-Password does NOT match local User-Password");
340                                 return -1;
341                         }
342                         DEBUG2("auth: user supplied CHAP-Password matches local User-Password");
343                         break;
344                 default:
345                         DEBUG2("auth: type \"%s\"",
346                                         dict_valbyattr(PW_AUTH_TYPE, auth_type)->name);
347                         /*
348                          *      See if there is a module that handles
349                          *      this type, and turn the RLM_ return
350                          *      status into the values as defined at
351                          *      the top of this function.
352                          */
353                         result = module_authenticate(auth_type, request);
354                         switch (result) {
355                                 /*
356                                  *      An authentication module FAIL
357                                  *      return code, or any return code that
358                                  *      is not expected from authentication,
359                                  *      is the same as an explicit REJECT!
360                                  */
361                                 case RLM_MODULE_FAIL:
362                                 case RLM_MODULE_REJECT:
363                                 case RLM_MODULE_USERLOCK:
364                                 case RLM_MODULE_INVALID:
365                                 case RLM_MODULE_NOTFOUND:
366                                 case RLM_MODULE_NOOP:
367                                 case RLM_MODULE_UPDATED:
368                                         result = -1;
369                                         break;
370                                 case RLM_MODULE_OK:
371                                         result = 0;
372                                         break;
373                                 case RLM_MODULE_HANDLED:
374                                         result = 1;
375                                         break;
376                         }
377                         break;
378         }
379
380         return result;
381 }
382
383 /*
384  *      Post-authentication step processes the response before it is
385  *      sent to the NAS. It can receive both Access-Accept and Access-Reject
386  *      replies.
387  */
388 int rad_postauth(REQUEST *request)
389 {
390         int     result;
391         int     postauth_type = 0;
392         VALUE_PAIR      *postauth_type_item = NULL;
393
394         /*
395          *      Do post-authentication calls. ignoring the return code.
396          */
397         postauth_type_item = pairfind(request->config_items, PW_POST_AUTH_TYPE);
398         if (postauth_type_item)
399                 postauth_type = postauth_type_item->lvalue;
400         result = module_post_auth(postauth_type, request);
401         switch (result) {
402         default:
403           break;
404
405           /*
406            *    The module failed, or said to reject the user: Do so.
407            */
408         case RLM_MODULE_FAIL:
409         case RLM_MODULE_REJECT:
410         case RLM_MODULE_USERLOCK:
411         case RLM_MODULE_INVALID:
412           request->reply->code = PW_AUTHENTICATION_REJECT;
413           result = RLM_MODULE_REJECT;
414           break;
415
416           /*
417            *    The module had a number of OK return codes.
418            */
419         case RLM_MODULE_NOTFOUND:
420         case RLM_MODULE_NOOP:
421         case RLM_MODULE_UPDATED:
422         case RLM_MODULE_OK:
423         case RLM_MODULE_HANDLED:
424           result = RLM_MODULE_OK;
425           break;
426         }
427         return result;
428 }
429
430 /*
431  *      Before sending an Access-Reject, call the modules in the
432  *      Post-Auth-Type REJECT stanza.
433  */
434 static int rad_postauth_reject(REQUEST *request)
435 {
436         int             result;
437         VALUE_PAIR      *tmp;
438         DICT_VALUE      *dval;
439
440         dval = dict_valbyname(PW_POST_AUTH_TYPE, "REJECT");
441         if (dval) {
442                 /* Overwrite the Post-Auth-Type with the value REJECT */
443                 pairdelete(&request->config_items, PW_POST_AUTH_TYPE);
444                 tmp = paircreate(PW_POST_AUTH_TYPE, PW_TYPE_INTEGER);
445                 tmp->lvalue = dval->value;
446                 pairadd(&request->config_items, tmp);
447                 result = rad_postauth(request);
448         } else {
449                 /* No REJECT stanza */
450                 result = RLM_MODULE_OK;
451         }
452         return result;
453 }
454
455 /*
456  *      Process and reply to an authentication request
457  *
458  *      The return value of this function isn't actually used right now, so
459  *      it's not entirely clear if it is returning the right things. --Pac.
460  */
461 int rad_authenticate(REQUEST *request)
462 {
463         VALUE_PAIR      *namepair;
464         VALUE_PAIR      *check_item;
465         VALUE_PAIR      *reply_item;
466         VALUE_PAIR      *auth_item;
467         VALUE_PAIR      *module_msg;
468         VALUE_PAIR      *tmp = NULL;
469         int             result, r;
470         char            umsg[MAX_STRING_LEN + 1];
471         const char      *user_msg = NULL;
472         const char      *password;
473         char            *exec_program;
474         int             exec_wait;
475         int             seen_callback_id;
476         char            buf[1024], logstr[1024];
477         char            autz_retry = 0;
478         int             autz_type = 0;
479
480         password = "";
481
482         /*
483          *      If this request got proxied to another server,
484          *      AND it was an authentication request, then we need
485          *      to add an initial Auth-Type: Auth-Accept for success,
486          *      Auth-Reject for fail. We also need to add the reply
487          *      pairs from the server to the initial reply.
488          *
489          *      Huh?  If the request wasn't an authentication request,
490          *      WTF are we doing here?
491          */
492         if ((request->proxy_reply) &&
493             (request->packet->code == PW_AUTHENTICATION_REQUEST)) {
494                 tmp = paircreate(PW_AUTH_TYPE, PW_TYPE_INTEGER);
495                 if (tmp == NULL) {
496                         radlog(L_ERR|L_CONS, "no memory");
497                         exit(1);
498                 }
499
500                 /*
501                  *      Challenges are punted back to the NAS
502                  *      without any further processing.
503                  */
504                 if (request->proxy_reply->code == PW_ACCESS_CHALLENGE) {
505                         request->reply->code = PW_ACCESS_CHALLENGE;
506                         return RLM_MODULE_HANDLED;
507                 }
508
509                 /*
510                  *      Reply of ACCEPT means accept, ALL other
511                  *      replies mean reject.  This is fail-safe.
512                  */
513                 if (request->proxy_reply->code == PW_AUTHENTICATION_ACK)
514                         tmp->lvalue = PW_AUTHTYPE_ACCEPT;
515                 else
516                         tmp->lvalue = PW_AUTHTYPE_REJECT;
517                 pairadd(&request->config_items, tmp);
518
519                 /*
520                  *      If it's an Access-Reject, then do NOT do any
521                  *      authorization or authentication.  They're being
522                  *      rejected, so we minimize the amount of work
523                  *      done by the server, by rejecting them here.
524                  */
525                 if ((request->proxy_reply->code != PW_AUTHENTICATION_ACK) &&
526                     (request->proxy_reply->code != PW_ACCESS_CHALLENGE)) {
527                         rad_authlog("Login incorrect (Home Server says so)", request, 0);
528                         request->reply->code = PW_AUTHENTICATION_REJECT;
529                         rad_postauth_reject(request);
530                         return RLM_MODULE_REJECT;
531                 }
532         }
533
534         /*
535          *      Get the username from the request.
536          *
537          *      Note that namepair MAY be NULL, in which case there
538          *      is no User-Name attribute in the request.
539          */
540         namepair = request->username;
541
542         /*
543          *      Look for, and cache, passwords.
544          */
545         if (!request->password) {
546                 request->password = pairfind(request->packet->vps,
547                                              PW_PASSWORD);
548         }
549
550         /*
551          *      Discover which password we want to use.
552          */
553         auth_item = request->password;
554         if (auth_item) {
555                 password = (const char *)auth_item->strvalue;
556
557         } else {
558                 /*
559                  *      Maybe there's a CHAP-Password?
560                  */
561                 if ((auth_item = pairfind(request->packet->vps,
562                                 PW_CHAP_PASSWORD)) != NULL) {
563                         password = "<CHAP-PASSWORD>";
564
565                 } else {
566                         /*
567                          *      No password we recognize.
568                          */
569                         password = "<NO-PASSWORD>";
570                 }
571         }
572         request->password = auth_item;
573
574         /*
575          *      Get the user's authorization information from the database
576          */
577 autz_redo:
578         r = module_authorize(autz_type, request);
579         if (r != RLM_MODULE_NOTFOUND &&
580             r != RLM_MODULE_NOOP &&
581             r != RLM_MODULE_OK &&
582             r != RLM_MODULE_UPDATED) {
583                 if (r != RLM_MODULE_FAIL && r != RLM_MODULE_HANDLED) {
584                         if ((module_msg = pairfind(request->packet->vps,
585                                         PW_MODULE_FAILURE_MESSAGE)) != NULL){
586                                 char msg[MAX_STRING_LEN+16];
587                                 snprintf(msg, sizeof(msg), "Invalid user (%s)",
588                                          module_msg->strvalue);
589                                 rad_authlog(msg,request,0);
590                         } else {
591                                 rad_authlog("Invalid user", request, 0);
592                         }
593                         request->reply->code = PW_AUTHENTICATION_REJECT;
594                 }
595                 return r;
596         }
597         if (!autz_retry){
598                 VALUE_PAIR      *autz_type_item = NULL;
599                 autz_type_item = pairfind(request->config_items, PW_AUTZ_TYPE);
600                 if (autz_type_item){
601                         autz_type = autz_type_item->lvalue;
602                         autz_retry = 1;
603                         goto autz_redo;
604                 }
605         }
606
607         /*
608          *      If we haven't already proxied the packet, then check
609          *      to see if we should.  Maybe one of the authorize
610          *      modules has decided that a proxy should be used. If
611          *      so, get out of here and send the packet.
612          */
613         if ((request->proxy == NULL) &&
614             ((tmp = pairfind(request->config_items, PW_PROXY_TO_REALM)) != NULL)) {
615                 REALM *realm;
616
617                 /*
618                  *      Catch users who set Proxy-To-Realm to a LOCAL
619                  *      realm (sigh).
620                  */
621                 realm = realm_find(tmp->strvalue, 0);
622                 if (realm && (realm->ipaddr == htonl(INADDR_NONE))) {
623                         DEBUG2("  WARNING: You set Proxy-To-Realm = %s, but it is a LOCAL realm!  Cancelling invalid proxy request.", realm->realm);
624                 } else {
625                         /*
626                          *      Don't authenticate, as the request is
627                          *      proxied.
628                          */
629                         return RLM_MODULE_OK;
630                 }
631         }
632
633         /*
634          *      Perhaps there is a Stripped-User-Name now.
635          */
636         namepair = request->username;
637
638         /*
639          *      Validate the user
640          */
641         do {
642                 if ((result = check_expiration(request)) < 0)
643                                 break;
644                 result = rad_check_password(request);
645                 if (result > 0) {
646                         /* don't reply! */
647                         return RLM_MODULE_HANDLED;
648                 }
649         } while(0);
650
651         /*
652          *      Failed to validate the user.
653          *
654          *      We PRESUME that the code which failed will clean up
655          *      request->reply->vps, to be ONLY the reply items it
656          *      wants to send back.
657          */
658         if (result < 0) {
659                 DEBUG2("auth: Failed to validate the user.");
660                 request->reply->code = PW_AUTHENTICATION_REJECT;
661
662                 if ((module_msg = pairfind(request->packet->vps,PW_MODULE_FAILURE_MESSAGE)) != NULL){
663                         char msg[MAX_STRING_LEN+19];
664
665                         snprintf(msg, sizeof(msg), "Login incorrect (%s)",
666                                  module_msg->strvalue);
667                         rad_authlog(msg, request, 0);
668                 } else {
669                         rad_authlog("Login incorrect", request, 0);
670                 }
671
672                 /* double check: maybe the secret is wrong? */
673                 if ((debug_flag > 1) && (auth_item != NULL) &&
674                                 (auth_item->attribute == PW_PASSWORD)) {
675                         u_char *p;
676
677                         p = auth_item->strvalue;
678                         while (*p != '\0') {
679                                 if (!isprint((int) *p)) {
680                                         log_debug("  WARNING: Unprintable characters in the password.\n\t  Double-check the shared secret on the server and the NAS!");
681                                         break;
682                                 }
683                                 p++;
684                         }
685                 }
686         }
687
688         if (result >= 0 &&
689             (check_item = pairfind(request->config_items, PW_SIMULTANEOUS_USE)) != NULL) {
690                 VALUE_PAIR      *session_type;
691                 int             sess_type = 0;
692
693                 session_type = pairfind(request->config_items, PW_SESSION_TYPE);
694                 if (session_type)
695                         sess_type = session_type->lvalue;
696
697                 /*
698                  *      User authenticated O.K. Now we have to check
699                  *      for the Simultaneous-Use parameter.
700                  */
701                 if (namepair &&
702                     (r = module_checksimul(sess_type,request, check_item->lvalue)) != 0) {
703                         char mpp_ok = 0;
704
705                         if (r == 2){
706                                 /* Multilink attempt. Check if port-limit > simultaneous-use */
707                                 VALUE_PAIR *port_limit;
708
709                                 if ((port_limit = pairfind(request->reply->vps, PW_PORT_LIMIT)) != NULL &&
710                                         port_limit->lvalue > check_item->lvalue){
711                                         DEBUG2("main auth: MPP is OK");
712                                         mpp_ok = 1;
713                                 }
714                         }
715                         if (!mpp_ok){
716                                 if (check_item->lvalue > 1) {
717                                 snprintf(umsg, sizeof(umsg),
718                                                         "\r\nYou are already logged in %d times  - access denied\r\n\n",
719                                                         (int)check_item->lvalue);
720                                         user_msg = umsg;
721                                 } else {
722                                         user_msg = "\r\nYou are already logged in - access denied\r\n\n";
723                                 }
724
725                                 request->reply->code = PW_AUTHENTICATION_REJECT;
726
727                                 /*
728                                  *      They're trying to log in too many times.
729                                  *      Remove ALL reply attributes.
730                                  */
731                                 pairfree(&request->reply->vps);
732                                 tmp = pairmake("Reply-Message", user_msg, T_OP_SET);
733                                 request->reply->vps = tmp;
734
735                                 snprintf(logstr, sizeof(logstr), "Multiple logins (max %d) %s",
736                                         check_item->lvalue,
737                                         r == 2 ? "[MPP attempt]" : "");
738                                 rad_authlog(logstr, request, 1);
739
740                                 result = -1;
741                         }
742                 }
743         }
744
745         if (result >= 0 &&
746             (check_item = pairfind(request->config_items, PW_LOGIN_TIME)) != NULL) {
747
748                 /*
749                  *      Authentication is OK. Now see if this
750                  *      user may login at this time of the day.
751                  */
752                 r = timestr_match((char *)check_item->strvalue,
753                                   request->timestamp);
754
755                 if (r == 0) {   /* unlimited */
756                         /*
757                          *      Do nothing: login-time is OK.
758                          */
759
760                         /*
761                          *      Session-Timeout needs to be at least
762                          *      60 seconds, some terminal servers
763                          *      ignore smaller values.
764                          */
765                 } else if (r < 60) {
766                         /*
767                          *      User called outside allowed time interval.
768                          */
769                         result = -1;
770                         user_msg = "You are calling outside your allowed timespan\r\n";
771
772                         request->reply->code = PW_AUTHENTICATION_REJECT;
773                         pairfree(&request->reply->vps);
774
775                         tmp = pairmake("Reply-Message", user_msg, T_OP_SET);
776                         request->reply->vps = tmp;
777
778                         snprintf(logstr, sizeof(logstr), "Outside allowed timespan (time allowed %s)",
779                                  check_item->strvalue);
780                         rad_authlog(logstr, request, 1);
781
782                 } else if (r > 0) {
783
784                         /*
785                          *      User is allowed, but set Session-Timeout.
786                          */
787                         if ((reply_item = pairfind(request->reply->vps,
788                                         PW_SESSION_TIMEOUT)) != NULL) {
789                                 if (reply_item->lvalue > (unsigned) r)
790                                         reply_item->lvalue = r;
791                         } else {
792                                 if ((reply_item = paircreate(
793                                                 PW_SESSION_TIMEOUT,
794                                                 PW_TYPE_INTEGER)) == NULL) {
795                                         radlog(L_ERR|L_CONS, "no memory");
796                                         exit(1);
797                                 }
798                                 reply_item->lvalue = r;
799                                 pairadd(&request->reply->vps, reply_item);
800                         }
801                 }
802         }
803
804         /*
805          *      Result should be >= 0 here - if not, it means the user
806          *      is rejected, so we just process post-auth and return.
807          */
808         if (result < 0) {
809                 rad_postauth_reject(request);
810                 return RLM_MODULE_REJECT;
811         }
812
813         /*
814          *      We might need this later.  The 'password' string
815          *      is NOT used anywhere below here, except for logging,
816          *      so it should be safe...
817          */
818         if ((auth_item != NULL) && (auth_item->attribute == PW_CHAP_PASSWORD)) {
819                 password = "CHAP-Password";
820         }
821
822         /*
823          *      Add the port number to the Framed-IP-Address if
824          *      vp->addport is set.
825          */
826         if (((tmp = pairfind(request->reply->vps,
827                              PW_FRAMED_IP_ADDRESS)) != NULL) &&
828             (tmp->flags.addport != 0)) {
829                 VALUE_PAIR *vpPortId;
830
831                 /*
832                  *  Find the NAS port ID.
833                  */
834                 if ((vpPortId = pairfind(request->packet->vps,
835                                          PW_NAS_PORT)) != NULL) {
836                   unsigned long tvalue = ntohl(tmp->lvalue);
837                   tmp->lvalue = htonl(tvalue + vpPortId->lvalue);
838                   tmp->flags.addport = 0;
839                   ip_ntoa(tmp->strvalue, tmp->lvalue);
840                 } else {
841                         DEBUG2("WARNING: No NAS-Port attribute in request.  CANNOT return a Framed-IP-Address + NAS-Port.\n");
842                         pairdelete(&request->reply->vps, PW_FRAMED_IP_ADDRESS);
843                 }
844         }
845
846         /*
847          *      See if we need to execute a program.
848          *      FIXME: somehow cache this info, and only execute the
849          *      program when we receive an Accounting-START packet.
850          *      Only at that time we know dynamic IP etc.
851          */
852         exec_program = NULL;
853         exec_wait = 0;
854         if ((auth_item = pairfind(request->reply->vps, PW_EXEC_PROGRAM)) != NULL) {
855                 exec_wait = 0;
856                 exec_program = strdup((char *)auth_item->strvalue);
857                 pairdelete(&request->reply->vps, PW_EXEC_PROGRAM);
858         }
859         if ((auth_item = pairfind(request->reply->vps, PW_EXEC_PROGRAM_WAIT)) != NULL) {
860                 exec_wait = 1;
861                 exec_program = strdup((char *)auth_item->strvalue);
862                 pairdelete(&request->reply->vps, PW_EXEC_PROGRAM_WAIT);
863         }
864
865         /*
866          *      Hack - allow % expansion in certain value strings.
867          *      This is nice for certain Exec-Program programs.
868          */
869         seen_callback_id = 0;
870         if ((auth_item = pairfind(request->reply->vps, PW_CALLBACK_ID)) != NULL) {
871                 seen_callback_id = 1;
872                 radius_xlat(buf, sizeof(auth_item->strvalue),
873                             (char *)auth_item->strvalue, request, NULL);
874                 strNcpy((char *)auth_item->strvalue, buf,
875                         sizeof(auth_item->strvalue));
876                 auth_item->length = strlen((char *)auth_item->strvalue);
877         }
878
879
880         /*
881          *      If we want to exec a program, but wait for it,
882          *      do it first before sending the reply.
883          */
884         if (exec_program && exec_wait) {
885                 r = radius_exec_program(exec_program, request,
886                                         exec_wait,
887                                         umsg, sizeof(umsg),
888                                         request->packet->vps, &tmp);
889                 free(exec_program);
890                 exec_program = NULL;
891
892                 /*
893                  *      Always add the value-pairs to the reply.
894                  */
895                 pairmove(&request->reply->vps, &tmp);
896                 pairfree(&tmp);
897
898                 if (r != 0) {
899                         /*
900                          *      Error. radius_exec_program() returns -1 on
901                          *      fork/exec errors, or >0 if the exec'ed program
902                          *      had a non-zero exit status.
903                          */
904                         if (umsg[0] == '\0') {
905                                 user_msg = "\r\nAccess denied (external check failed).";
906                         } else {
907                                 user_msg = &umsg[0];
908                         }
909
910                         request->reply->code = PW_AUTHENTICATION_REJECT;
911                         tmp = pairmake("Reply-Message", user_msg, T_OP_SET);
912
913                         pairadd(&request->reply->vps, tmp);
914                         rad_authlog("Login incorrect (external check failed)",
915                                         request, 0);
916
917                         rad_postauth_reject(request);
918
919                         return RLM_MODULE_REJECT;
920                 }
921         }
922
923         /*
924          *      Delete "normal" A/V pairs when using callback.
925          *
926          *      FIXME: This is stupid. The portmaster should accept
927          *      these settings instead of insisting on using a
928          *      dialout location.
929          *
930          *      FIXME2: Move this into the above exec thingy?
931          *      (if you knew how I use the exec_wait, you'd understand).
932          */
933         if (seen_callback_id) {
934                 pairdelete(&request->reply->vps, PW_FRAMED_PROTOCOL);
935                 pairdelete(&request->reply->vps, PW_FRAMED_IP_ADDRESS);
936                 pairdelete(&request->reply->vps, PW_FRAMED_IP_NETMASK);
937                 pairdelete(&request->reply->vps, PW_FRAMED_ROUTE);
938                 pairdelete(&request->reply->vps, PW_FRAMED_MTU);
939                 pairdelete(&request->reply->vps, PW_FRAMED_COMPRESSION);
940                 pairdelete(&request->reply->vps, PW_FILTER_ID);
941                 pairdelete(&request->reply->vps, PW_PORT_LIMIT);
942                 pairdelete(&request->reply->vps, PW_CALLBACK_NUMBER);
943         }
944
945         /*
946          *      Filter (possibly multiple) Reply-Message attributes
947          *      through radius_xlat, modifying them in place.
948          */
949         if (user_msg == NULL) {
950                 reply_item = pairfind(request->reply->vps, PW_REPLY_MESSAGE);
951                 while (reply_item) {
952                         radius_xlat(buf, sizeof(reply_item->strvalue),
953                                     (char *)reply_item->strvalue, request, NULL);
954                         strNcpy((char *)reply_item->strvalue, buf,
955                                 sizeof(reply_item->strvalue));
956                         reply_item->length = strlen((char *)reply_item->strvalue);
957                         user_msg = NULL;
958                         reply_item = pairfind(reply_item->next, PW_REPLY_MESSAGE);
959                 }
960         }
961
962         /*
963          *      Set the reply to Access-Accept, if it hasn't already
964          *      been set to something.  (i.e. Access-Challenge)
965          */
966         if (request->reply->code == 0)
967           request->reply->code = PW_AUTHENTICATION_ACK;
968
969         if ((module_msg = pairfind(request->packet->vps,PW_MODULE_SUCCESS_MESSAGE)) != NULL){
970                 char msg[MAX_STRING_LEN+12];
971
972                 snprintf(msg, sizeof(msg), "Login OK (%s)",
973                          module_msg->strvalue);
974                 rad_authlog(msg, request, 1);
975         } else {
976                 rad_authlog("Login OK", request, 1);
977         }
978
979         if (exec_program && !exec_wait) {
980                 /*
981                  *      No need to check the exit status here.
982                  */
983                 radius_exec_program(exec_program, request, exec_wait,
984                                     NULL, 0, request->packet->vps, NULL);
985         }
986
987         if (exec_program)
988                 free(exec_program);
989
990         result = rad_postauth(request);
991
992         return result;
993 }