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