0ceb4fcafa71340d397b92cebbf23963487c09bc
[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 static 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  *      Process and reply to an authentication request
432  *
433  *      The return value of this function isn't actually used right now, so
434  *      it's not entirely clear if it is returning the right things. --Pac.
435  */
436 int rad_authenticate(REQUEST *request)
437 {
438         VALUE_PAIR      *namepair;
439         VALUE_PAIR      *check_item;
440         VALUE_PAIR      *reply_item;
441         VALUE_PAIR      *auth_item;
442         VALUE_PAIR      *module_msg;
443         VALUE_PAIR      *tmp = NULL;
444         int             result, r;
445         char            umsg[MAX_STRING_LEN + 1];
446         const char      *user_msg = NULL;
447         const char      *password;
448         char            *exec_program;
449         int             exec_wait;
450         int             seen_callback_id;
451         char            buf[1024], logstr[1024];
452         char            autz_retry = 0;
453         int             autz_type = 0;
454
455         password = "";
456
457         /*
458          *      If this request got proxied to another server,
459          *      AND it was an authentication request, then we need
460          *      to add an initial Auth-Type: Auth-Accept for success,
461          *      Auth-Reject for fail. We also need to add the reply
462          *      pairs from the server to the initial reply.
463          */
464         if ((request->proxy_reply) &&
465             (request->packet->code == PW_AUTHENTICATION_REQUEST)) {
466                 tmp = paircreate(PW_AUTH_TYPE, PW_TYPE_INTEGER);
467                 if (tmp == NULL) {
468                         radlog(L_ERR|L_CONS, "no memory");
469                         exit(1);
470                 }
471
472                 /*
473                  *      Challenges are punted back to the NAS
474                  *      without any further processing.
475                  */
476                 if (request->proxy_reply->code == PW_ACCESS_CHALLENGE) {
477                         request->reply->code = PW_ACCESS_CHALLENGE;
478                         return RLM_MODULE_HANDLED;
479                 }
480
481                 /*
482                  *      Reply of ACCEPT means accept, ALL other
483                  *      replies mean reject.  This is fail-safe.
484                  */
485                 if (request->proxy_reply->code == PW_AUTHENTICATION_ACK)
486                         tmp->lvalue = PW_AUTHTYPE_ACCEPT;
487                 else
488                         tmp->lvalue = PW_AUTHTYPE_REJECT;
489                 pairadd(&request->config_items, tmp);
490
491                 /*
492                  *      If it's an Access-Reject, then do NOT do any
493                  *      authorization or authentication.  They're being
494                  *      rejected, so we minimize the amount of work
495                  *      done by the server, by rejecting them here.
496                  */
497                 if ((request->proxy_reply->code != PW_AUTHENTICATION_ACK) &&
498                     (request->proxy_reply->code != PW_ACCESS_CHALLENGE)) {
499                         rad_authlog("Login incorrect (Home Server says so)", request, 0);
500                         request->reply->code = PW_AUTHENTICATION_REJECT;
501                         return RLM_MODULE_REJECT;
502                 }
503         }
504
505         /*
506          *      Get the username from the request.
507          *
508          *      Note that namepair MAY be NULL, in which case there
509          *      is no User-Name attribute in the request.
510          */
511         namepair = request->username;
512
513         /*
514          *      Look for, and cache, passwords.
515          */
516         if (!request->password) {
517                 request->password = pairfind(request->packet->vps,
518                                              PW_PASSWORD);
519         }
520           
521         /*
522          *      Discover which password we want to use.
523          */
524         auth_item = request->password;
525         if (auth_item) {
526                 password = (const char *)auth_item->strvalue;
527
528         } else {
529                 /*
530                  *      Maybe there's a CHAP-Password?
531                  */
532                 if ((auth_item = pairfind(request->packet->vps, 
533                                 PW_CHAP_PASSWORD)) != NULL) {
534                         password = "<CHAP-PASSWORD>";
535                 
536                 } else {
537                         /*
538                          *      No password we recognize.
539                          */
540                         password = "<NO-PASSWORD>";
541                 }
542         }
543         request->password = auth_item;
544         
545         /*
546          *      Get the user's authorization information from the database
547          */
548 autz_redo:
549         r = module_authorize(autz_type, request);
550         if (r != RLM_MODULE_NOTFOUND &&
551             r != RLM_MODULE_NOOP &&
552             r != RLM_MODULE_OK &&
553             r != RLM_MODULE_UPDATED) {
554                 if (r != RLM_MODULE_FAIL && r != RLM_MODULE_HANDLED) {
555                         if ((module_msg = pairfind(request->packet->vps,
556                                         PW_MODULE_FAILURE_MESSAGE)) != NULL){
557                                 char msg[MAX_STRING_LEN+16];
558                                 snprintf(msg, sizeof(msg), "Invalid user (%s)",
559                                          module_msg->strvalue);
560                                 rad_authlog(msg,request,0);
561                         } else {
562                                 rad_authlog("Invalid user", request, 0);
563                         }
564                         request->reply->code = PW_AUTHENTICATION_REJECT;
565                 }
566                 return r;
567         }
568         if (!autz_retry){
569                 VALUE_PAIR      *autz_type_item = NULL;
570                 autz_type_item = pairfind(request->config_items, PW_AUTZ_TYPE);
571                 if (autz_type_item){
572                         autz_type = autz_type_item->lvalue;
573                         autz_retry = 1;
574                         goto autz_redo;
575                 }
576         }
577
578         /*
579          *      If we haven't already proxied the packet, then check
580          *      to see if we should.  Maybe one of the authorize
581          *      modules has decided that a proxy should be used. If
582          *      so, get out of here and send the packet.
583          */
584         if ((request->proxy == NULL) &&
585             ((tmp = pairfind(request->config_items, PW_PROXY_TO_REALM)) != NULL)) {
586                 REALM *realm;
587
588                 /*
589                  *      Catch users who set Proxy-To-Realm to a LOCAL
590                  *      realm (sigh).
591                  */
592                 realm = realm_find(tmp->strvalue, 0);
593                 if (realm && (realm->ipaddr == htonl(INADDR_NONE))) {
594                         DEBUG2("  WARNING: You set Proxy-To-Realm = %s, but it is a LOCAL realm!  Cancelling invalid proxy request.", realm->realm);
595                 } else {
596                         /*
597                          *      Don't authenticate, as the request is
598                          *      proxied.
599                          */
600                         return RLM_MODULE_OK;
601                 }
602         }
603
604         /*
605          *      Perhaps there is a Stripped-User-Name now.
606          */
607         namepair = request->username;
608
609         /*
610          *      Validate the user
611          */
612         do {
613                 if ((result = check_expiration(request)) < 0)
614                                 break;
615                 result = rad_check_password(request);
616                 if (result > 0) {
617                         /* don't reply! */
618                         return RLM_MODULE_HANDLED;
619                 }
620         } while(0);
621         
622         /*
623          *      Failed to validate the user.
624          *
625          *      We PRESUME that the code which failed will clean up
626          *      request->reply->vps, to be ONLY the reply items it
627          *      wants to send back.
628          */
629         if (result < 0) {
630                 DEBUG2("auth: Failed to validate the user.");
631                 request->reply->code = PW_AUTHENTICATION_REJECT;
632
633                 if ((module_msg = pairfind(request->packet->vps,PW_MODULE_FAILURE_MESSAGE)) != NULL){
634                         char msg[MAX_STRING_LEN+19];
635
636                         snprintf(msg, sizeof(msg), "Login incorrect (%s)",
637                                  module_msg->strvalue);
638                         rad_authlog(msg, request, 0);
639                 } else {
640                         rad_authlog("Login incorrect", request, 0);
641                 }
642
643                 /* double check: maybe the secret is wrong? */
644                 if ((debug_flag > 1) && (auth_item != NULL) &&
645                                 (auth_item->attribute == PW_PASSWORD)) {
646                         u_char *p;
647
648                         p = auth_item->strvalue;
649                         while (*p != '\0') {
650                                 if (!isprint((int) *p)) {
651                                         log_debug("  WARNING: Unprintable characters in the password.\n\t  Double-check the shared secret on the server and the NAS!");
652                                         break;
653                                 }
654                                 p++;
655                         }
656                 }
657         }
658
659         if (result >= 0 &&
660             (check_item = pairfind(request->config_items, PW_SIMULTANEOUS_USE)) != NULL) {
661                 VALUE_PAIR      *session_type;
662                 int             sess_type = 0;
663
664                 session_type = pairfind(request->config_items, PW_SESSION_TYPE);
665                 if (session_type)
666                         sess_type = session_type->lvalue;
667
668                 /*
669                  *      User authenticated O.K. Now we have to check
670                  *      for the Simultaneous-Use parameter.
671                  */
672                 if (namepair &&
673                     (r = module_checksimul(sess_type,request, check_item->lvalue)) != 0) {
674                         char mpp_ok = 0;
675
676                         if (r == 2){
677                                 /* Multilink attempt. Check if port-limit > simultaneous-use */
678                                 VALUE_PAIR *port_limit;
679
680                                 if ((port_limit = pairfind(request->reply->vps, PW_PORT_LIMIT)) != NULL &&
681                                         port_limit->lvalue > check_item->lvalue){
682                                         DEBUG2("main auth: MPP is OK");
683                                         mpp_ok = 1;
684                                 }
685                         }
686                         if (!mpp_ok){
687                                 if (check_item->lvalue > 1) {
688                                 snprintf(umsg, sizeof(umsg), 
689                                                         "\r\nYou are already logged in %d times  - access denied\r\n\n",
690                                                         (int)check_item->lvalue);
691                                         user_msg = umsg;
692                                 } else {
693                                         user_msg = "\r\nYou are already logged in - access denied\r\n\n";
694                                 }
695
696                                 request->reply->code = PW_AUTHENTICATION_REJECT;
697
698                                 /*
699                                  *      They're trying to log in too many times.
700                                  *      Remove ALL reply attributes.
701                                  */
702                                 pairfree(&request->reply->vps);
703                                 tmp = pairmake("Reply-Message", user_msg, T_OP_SET);
704                                 request->reply->vps = tmp;
705
706                                 snprintf(logstr, sizeof(logstr), "Multiple logins (max %d) %s",
707                                         check_item->lvalue,
708                                         r == 2 ? "[MPP attempt]" : "");
709                                 rad_authlog(logstr, request, 1);
710
711                                 result = -1;
712                         }
713                 }
714         }
715
716         if (result >= 0 &&
717             (check_item = pairfind(request->config_items, PW_LOGIN_TIME)) != NULL) {
718
719                 /*
720                  *      Authentication is OK. Now see if this
721                  *      user may login at this time of the day.
722                  */
723                 r = timestr_match((char *)check_item->strvalue,
724                                   request->timestamp);
725
726                 if (r == 0) {   /* unlimited */
727                         /*
728                          *      Do nothing: login-time is OK.
729                          */
730
731                         /*
732                          *      Session-Timeout needs to be at least
733                          *      60 seconds, some terminal servers
734                          *      ignore smaller values.
735                          */
736                 } else if (r < 60) {
737                         /*
738                          *      User called outside allowed time interval.
739                          */
740                         result = -1;
741                         user_msg = "You are calling outside your allowed timespan\r\n";
742
743                         request->reply->code = PW_AUTHENTICATION_REJECT;
744                         pairfree(&request->reply->vps);
745
746                         tmp = pairmake("Reply-Message", user_msg, T_OP_SET);
747                         request->reply->vps = tmp;
748
749                         snprintf(logstr, sizeof(logstr), "Outside allowed timespan (time allowed %s)", 
750                                  check_item->strvalue);
751                         rad_authlog(logstr, request, 1);
752
753                 } else if (r > 0) {
754
755                         /*
756                          *      User is allowed, but set Session-Timeout.
757                          */
758                         if ((reply_item = pairfind(request->reply->vps,
759                                         PW_SESSION_TIMEOUT)) != NULL) {
760                                 if (reply_item->lvalue > (unsigned) r)
761                                         reply_item->lvalue = r;
762                         } else {
763                                 if ((reply_item = paircreate(
764                                                 PW_SESSION_TIMEOUT,
765                                                 PW_TYPE_INTEGER)) == NULL) {
766                                         radlog(L_ERR|L_CONS, "no memory");
767                                         exit(1);
768                                 }
769                                 reply_item->lvalue = r;
770                                 pairadd(&request->reply->vps, reply_item);
771                         }
772                 }
773         }
774
775         /*
776          *      Result should be >= 0 here - if not, it means the user
777          *      is rejected, so we overwrite the Post-Auth-Type with
778          *      the value REJECT and cal the post-authentication
779          *      step.
780          */
781         if (result < 0) {
782                 DICT_VALUE *dval;
783
784                 dval = dict_valbyname(PW_POST_AUTH_TYPE, "REJECT");
785                 if (dval) {
786                         pairdelete(&request->config_items, PW_POST_AUTH_TYPE);
787                         tmp = paircreate(PW_POST_AUTH_TYPE, PW_TYPE_INTEGER);
788                         tmp->lvalue = dval->value;
789                         pairadd(&request->config_items, tmp);
790                         rad_postauth(request);
791                 }
792                 return RLM_MODULE_OK;
793         }
794
795         /*
796          *      We might need this later.  The 'password' string
797          *      is NOT used anywhere below here, except for logging,
798          *      so it should be safe...
799          */
800         if ((auth_item != NULL) && (auth_item->attribute == PW_CHAP_PASSWORD)) {
801                 password = "CHAP-Password";
802         }
803
804         /*
805          *      Add the port number to the Framed-IP-Address if
806          *      vp->addport is set.
807          */
808         if (((tmp = pairfind(request->reply->vps, 
809                              PW_FRAMED_IP_ADDRESS)) != NULL) &&
810             (tmp->flags.addport != 0)) {
811                 VALUE_PAIR *vpPortId;
812                 
813                 /*
814                  *  Find the NAS port ID.
815                  */
816                 if ((vpPortId = pairfind(request->packet->vps,
817                                          PW_NAS_PORT)) != NULL) {
818                   unsigned long tvalue = ntohl(tmp->lvalue);
819                   tmp->lvalue = htonl(tvalue + vpPortId->lvalue);
820                   tmp->flags.addport = 0;
821                   ip_ntoa(tmp->strvalue, tmp->lvalue);
822                 } else {
823                         DEBUG2("WARNING: No NAS-Port attribute in request.  CANNOT return a Framed-IP-Address + NAS-Port.\n");
824                         pairdelete(&request->reply->vps, PW_FRAMED_IP_ADDRESS);
825                 }
826         }
827
828         /*
829          *      See if we need to execute a program.
830          *      FIXME: somehow cache this info, and only execute the
831          *      program when we receive an Accounting-START packet.
832          *      Only at that time we know dynamic IP etc.
833          */
834         exec_program = NULL;
835         exec_wait = 0;
836         if ((auth_item = pairfind(request->reply->vps, PW_EXEC_PROGRAM)) != NULL) {
837                 exec_wait = 0;
838                 exec_program = strdup((char *)auth_item->strvalue);
839                 pairdelete(&request->reply->vps, PW_EXEC_PROGRAM);
840         }
841         if ((auth_item = pairfind(request->reply->vps, PW_EXEC_PROGRAM_WAIT)) != NULL) {
842                 exec_wait = 1;
843                 exec_program = strdup((char *)auth_item->strvalue);
844                 pairdelete(&request->reply->vps, PW_EXEC_PROGRAM_WAIT);
845         }
846
847         /*
848          *      Hack - allow % expansion in certain value strings.
849          *      This is nice for certain Exec-Program programs.
850          */
851         seen_callback_id = 0;
852         if ((auth_item = pairfind(request->reply->vps, PW_CALLBACK_ID)) != NULL) {
853                 seen_callback_id = 1;
854                 radius_xlat(buf, sizeof(auth_item->strvalue),
855                             (char *)auth_item->strvalue, request, NULL);
856                 strNcpy((char *)auth_item->strvalue, buf,
857                         sizeof(auth_item->strvalue));
858                 auth_item->length = strlen((char *)auth_item->strvalue);
859         }
860
861
862         /*
863          *      If we want to exec a program, but wait for it,
864          *      do it first before sending the reply.
865          */
866         if (exec_program && exec_wait) {
867                 r = radius_exec_program(exec_program, request,
868                                         exec_wait,
869                                         umsg, sizeof(umsg),
870                                         request->packet->vps, &tmp);
871                 free(exec_program);
872                 exec_program = NULL;
873
874                 /*
875                  *      Always add the value-pairs to the reply.
876                  */
877                 pairmove(&request->reply->vps, &tmp);
878                 pairfree(&tmp);
879
880                 if (r != 0) {
881                         /*
882                          *      Error. radius_exec_program() returns -1 on
883                          *      fork/exec errors, or >0 if the exec'ed program
884                          *      had a non-zero exit status.
885                          */
886                         if (umsg[0] == '\0') {
887                                 user_msg = "\r\nAccess denied (external check failed).";
888                         } else {
889                                 user_msg = &umsg[0];
890                         }
891
892                         request->reply->code = PW_AUTHENTICATION_REJECT;
893                         tmp = pairmake("Reply-Message", user_msg, T_OP_SET);
894
895                         pairadd(&request->reply->vps, tmp);
896                         rad_authlog("Login incorrect (external check failed)", 
897                                         request, 0);
898
899                         return RLM_MODULE_REJECT;
900                 }
901         }
902
903         /*
904          *      Delete "normal" A/V pairs when using callback.
905          *
906          *      FIXME: This is stupid. The portmaster should accept
907          *      these settings instead of insisting on using a
908          *      dialout location.
909          *
910          *      FIXME2: Move this into the above exec thingy?
911          *      (if you knew how I use the exec_wait, you'd understand).
912          */
913         if (seen_callback_id) {
914                 pairdelete(&request->reply->vps, PW_FRAMED_PROTOCOL);
915                 pairdelete(&request->reply->vps, PW_FRAMED_IP_ADDRESS);
916                 pairdelete(&request->reply->vps, PW_FRAMED_IP_NETMASK);
917                 pairdelete(&request->reply->vps, PW_FRAMED_ROUTE);
918                 pairdelete(&request->reply->vps, PW_FRAMED_MTU);
919                 pairdelete(&request->reply->vps, PW_FRAMED_COMPRESSION);
920                 pairdelete(&request->reply->vps, PW_FILTER_ID);
921                 pairdelete(&request->reply->vps, PW_PORT_LIMIT);
922                 pairdelete(&request->reply->vps, PW_CALLBACK_NUMBER);
923         }
924
925         /*
926          *      Filter (possibly multiple) Reply-Message attributes
927          *      through radius_xlat, modifying them in place.
928          */
929         if (user_msg == NULL) {
930                 reply_item = pairfind(request->reply->vps, PW_REPLY_MESSAGE);
931                 while (reply_item) {
932                         radius_xlat(buf, sizeof(reply_item->strvalue),
933                                     (char *)reply_item->strvalue, request, NULL);
934                         strNcpy((char *)reply_item->strvalue, buf,
935                                 sizeof(reply_item->strvalue));
936                         reply_item->length = strlen((char *)reply_item->strvalue);
937                         user_msg = NULL;
938                         reply_item = pairfind(reply_item->next, PW_REPLY_MESSAGE);
939                 }
940         }
941
942         /*
943          *      Set the reply to Access-Accept, if it hasn't already
944          *      been set to something.  (i.e. Access-Challenge)
945          */
946         if (request->reply->code == 0)
947           request->reply->code = PW_AUTHENTICATION_ACK;
948
949         if ((module_msg = pairfind(request->packet->vps,PW_MODULE_SUCCESS_MESSAGE)) != NULL){
950                 char msg[MAX_STRING_LEN+12];
951
952                 snprintf(msg, sizeof(msg), "Login OK (%s)",
953                          module_msg->strvalue);
954                 rad_authlog(msg, request, 1);
955         } else {
956                 rad_authlog("Login OK", request, 1);
957         }
958
959         if (exec_program && !exec_wait) {
960                 /*
961                  *      No need to check the exit status here.
962                  */
963                 radius_exec_program(exec_program, request, exec_wait,
964                                     NULL, 0, request->packet->vps, NULL);
965         }
966
967         if (exec_program) 
968                 free(exec_program);
969
970         result = rad_postauth(request);
971
972         return result;
973 }