0c9692e3bf531bbd2fa13bb7c0744b181caa17a9
[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 <freeradius-devel/autoconf.h>
28
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32
33 #ifdef HAVE_NETINET_IN_H
34 #       include <netinet/in.h>
35 #endif
36
37 #include <freeradius-devel/radiusd.h>
38 #include <freeradius-devel/modules.h>
39 #include <freeradius-devel/rad_assert.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_old(&request->packet->src_ipaddr), port,
57                         (do_cli ? " cli " : ""), (do_cli ? (char *)cli->vp_strvalue : ""));
58
59         return buf;
60 }
61
62
63
64 /*
65  * Make sure user/pass are clean
66  * and then log them
67  */
68 static int rad_authlog(const char *msg, REQUEST *request, int goodpass) {
69
70         char clean_password[1024];
71         char clean_username[1024];
72         char buf[1024];
73         VALUE_PAIR *username = NULL;
74
75         if (!mainconfig.log_auth) {
76                 return 0;
77         }
78
79         /*
80          * Get the correct username based on the configured value
81          */
82         if (log_stripped_names == 0) {
83                 username = pairfind(request->packet->vps, PW_USER_NAME);
84         } else {
85                 username = request->username;
86         }
87
88         /*
89          *      Clean up the username
90          */
91         if (username == NULL) {
92                 strcpy(clean_username, "<no User-Name attribute>");
93         } else {
94                 librad_safeprint((char *)username->vp_strvalue,
95                                 username->length,
96                                 clean_username, sizeof(clean_username));
97         }
98
99         /*
100          *      Clean up the password
101          */
102         if (mainconfig.log_auth_badpass || mainconfig.log_auth_goodpass) {
103                 if (!request->password) {
104                         VALUE_PAIR *auth_type;
105
106                         auth_type = pairfind(request->config_items,
107                                              PW_AUTH_TYPE);
108                         if (auth_type && (auth_type->vp_strvalue[0] != '\0')) {
109                                 snprintf(clean_password, sizeof(clean_password),
110                                          "<via Auth-Type = %s>",
111                                          auth_type->vp_strvalue);
112                         } else {
113                                 strcpy(clean_password, "<no User-Password attribute>");
114                         }
115                 } else if (request->password->attribute == PW_CHAP_PASSWORD) {
116                         strcpy(clean_password, "<CHAP-Password>");
117                 } else {
118                         librad_safeprint((char *)request->password->vp_strvalue,
119                                          request->password->length,
120                                          clean_password, sizeof(clean_password));
121                 }
122         }
123
124         if (goodpass) {
125                 radlog(L_AUTH, "%s: [%s%s%s] (%s)",
126                                 msg,
127                                 clean_username,
128                                 mainconfig.log_auth_goodpass ? "/" : "",
129                                 mainconfig.log_auth_goodpass ? clean_password : "",
130                                 auth_name(buf, sizeof(buf), request, 1));
131         } else {
132                 radlog(L_AUTH, "%s: [%s%s%s] (%s)",
133                                 msg,
134                                 clean_username,
135                                 mainconfig.log_auth_badpass ? "/" : "",
136                                 mainconfig.log_auth_badpass ? clean_password : "",
137                                 auth_name(buf, sizeof(buf), request, 1));
138         }
139
140         return 0;
141 }
142
143 /*
144  *      Check password.
145  *
146  *      Returns:        0  OK
147  *                      -1 Password fail
148  *                      -2 Rejected (Auth-Type = Reject, send Port-Message back)
149  *                      1  End check & return, don't reply
150  *
151  *      NOTE: NOT the same as the RLM_ values !
152  */
153 static int rad_check_password(REQUEST *request)
154 {
155         VALUE_PAIR *auth_type_pair;
156         VALUE_PAIR *cur_config_item;
157         VALUE_PAIR *password_pair;
158         VALUE_PAIR *auth_item;
159         char string[MAX_STRING_LEN];
160         int auth_type = -1;
161         int result;
162         int auth_type_count = 0;
163         result = 0;
164
165         /*
166          *      Look for matching check items. We skip the whole lot
167          *      if the authentication type is PW_AUTHTYPE_ACCEPT or
168          *      PW_AUTHTYPE_REJECT.
169          */
170         cur_config_item = request->config_items;
171         while(((auth_type_pair = pairfind(cur_config_item, PW_AUTH_TYPE))) != NULL) {
172                 auth_type = auth_type_pair->lvalue;
173                 auth_type_count++;
174
175                 DEBUG2("  rad_check_password:  Found Auth-Type %s",
176                                 auth_type_pair->vp_strvalue);
177                 cur_config_item = auth_type_pair->next;
178
179                 if (auth_type == PW_AUTHTYPE_REJECT) {
180                         DEBUG2("  rad_check_password: Auth-Type = Reject, rejecting user");
181                         return -2;
182                 }
183         }
184
185         if (( auth_type_count > 1) && (debug_flag)) {
186                 radlog(L_ERR, "Warning:  Found %d auth-types on request for user '%s'",
187                         auth_type_count, request->username->vp_strvalue);
188         }
189
190         /*
191          *      This means we have a proxy reply or an accept
192          *  and it wasn't rejected in the above loop.  So
193          *  that means it is accepted and we do no further
194          *  authentication
195          */
196         if ((auth_type == PW_AUTHTYPE_ACCEPT) || (request->proxy)) {
197                 DEBUG2("  rad_check_password: Auth-Type = Accept, accepting the user");
198                 return 0;
199         }
200
201         /*
202          *      Find the password from the users file.
203          */
204         if ((password_pair = pairfind(request->config_items, PW_CRYPT_PASSWORD)) != NULL) {
205                 /*
206                  *      Re-write Auth-Type, but ONLY if it isn't already
207                  *      set.
208                  */
209                 if (auth_type == -1) auth_type = PW_AUTHTYPE_CRYPT;
210         } else {
211                 password_pair = pairfind(request->config_items, PW_PASSWORD);
212         }
213
214         if (auth_type < 0) {
215                 if (password_pair) {
216                         auth_type = PW_AUTHTYPE_LOCAL;
217                 } else {
218                         /*
219                         *       The admin hasn't told us how to
220                         *       authenticate the user, so we reject them!
221                         *
222                         *       This is fail-safe.
223                         */
224                         DEBUG2("auth: No authenticate method (Auth-Type) configuration found for the request: Rejecting the user");
225                         return -2;
226                 }
227         }
228
229         switch(auth_type) {
230                 DICT_VALUE *dval;
231
232                 case PW_AUTHTYPE_CRYPT:
233                         /*
234                          *      Find the password sent by the user. It
235                          *      SHOULD be there, if it's not
236                          *      authentication fails.
237                          */
238                         auth_item = request->password;
239                         if (auth_item == NULL) {
240                                 DEBUG2("auth: No User-Password or CHAP-Password attribute in the request");
241                                 return -1;
242                         }
243
244                         DEBUG2("auth: type Crypt");
245                         if (password_pair == NULL) {
246                                 DEBUG2("No Crypt-Password configured for the user");
247                                 rad_authlog("Login incorrect "
248                                         "(No Crypt-Password configured for the user)", request, 0);
249                                 return -1;
250                         }
251
252                         switch (lrad_crypt_check((char *)auth_item->vp_strvalue,
253                                                                          (char *)password_pair->vp_strvalue)) {
254                         case -1:
255                           rad_authlog("Login incorrect "
256                                                   "(system failed to supply an encrypted password for comparison)", request, 0);
257                         case 1:
258                           return -1;
259                         }
260                         break;
261                 case PW_AUTHTYPE_LOCAL:
262                         DEBUG2("auth: type Local");
263
264                         /*
265                          *      Find the password sent by the user. It
266                          *      SHOULD be there, if it's not
267                          *      authentication fails.
268                          */
269                         auth_item = request->password;
270                         if (auth_item == NULL) {
271                                 DEBUG2("auth: No User-Password or CHAP-Password attribute in the request");
272                                 return -1;
273                         }
274
275                         /*
276                          *      Plain text password.
277                          */
278                         if (password_pair == NULL) {
279                                 DEBUG2("auth: No password configured for the user");
280                                 rad_authlog("Login incorrect "
281                                         "(No password configured for the user)", request, 0);
282                                 return -1;
283                         }
284
285                         /*
286                          *      Local password is just plain text.
287                          */
288                         if (auth_item->attribute == PW_PASSWORD) {
289                                 if (strcmp((char *)password_pair->vp_strvalue,
290                                            (char *)auth_item->vp_strvalue) != 0) {
291                                         DEBUG2("auth: user supplied User-Password does NOT match local User-Password");
292                                         return -1;
293                                 }
294                                 DEBUG2("auth: user supplied User-Password matches local User-Password");
295                                 break;
296
297                         } else if (auth_item->attribute != PW_CHAP_PASSWORD) {
298                                 DEBUG2("The user did not supply a User-Password or a CHAP-Password attribute");
299                                 rad_authlog("Login incorrect "
300                                         "(no User-Password or CHAP-Password attribute)", request, 0);
301                                 return -1;
302                         }
303
304                         rad_chap_encode(request->packet, string,
305                                         auth_item->vp_strvalue[0], password_pair);
306
307                         /*
308                          *      Compare them
309                          */
310                         if (memcmp(string + 1, auth_item->vp_strvalue + 1,
311                                    CHAP_VALUE_LENGTH) != 0) {
312                                 DEBUG2("auth: user supplied CHAP-Password does NOT match local User-Password");
313                                 return -1;
314                         }
315                         DEBUG2("auth: user supplied CHAP-Password matches local User-Password");
316                         break;
317                 default:
318                         dval = dict_valbyattr(PW_AUTH_TYPE, auth_type);
319                         if (dval) {
320                                 DEBUG2("auth: type \"%s\"", dval->name);
321                         } else {
322                                 DEBUG2("auth: type UNKNOWN-%d", auth_type);
323                         }
324
325                         /*
326                          *      See if there is a module that handles
327                          *      this type, and turn the RLM_ return
328                          *      status into the values as defined at
329                          *      the top of this function.
330                          */
331                         result = module_authenticate(auth_type, request);
332                         switch (result) {
333                                 /*
334                                  *      An authentication module FAIL
335                                  *      return code, or any return code that
336                                  *      is not expected from authentication,
337                                  *      is the same as an explicit REJECT!
338                                  */
339                                 case RLM_MODULE_FAIL:
340                                 case RLM_MODULE_INVALID:
341                                 case RLM_MODULE_NOOP:
342                                 case RLM_MODULE_NOTFOUND:
343                                 case RLM_MODULE_REJECT:
344                                 case RLM_MODULE_UPDATED:
345                                 case RLM_MODULE_USERLOCK:
346                                 default:
347                                         result = -1;
348                                         break;
349                                 case RLM_MODULE_OK:
350                                         result = 0;
351                                         break;
352                                 case RLM_MODULE_HANDLED:
353                                         result = 1;
354                                         break;
355                         }
356                         break;
357         }
358
359         return result;
360 }
361
362 /*
363  *      Post-authentication step processes the response before it is
364  *      sent to the NAS. It can receive both Access-Accept and Access-Reject
365  *      replies.
366  */
367 int rad_postauth(REQUEST *request)
368 {
369         int     result;
370         int     postauth_type = 0;
371         VALUE_PAIR *vp;
372
373         /*
374          *      Do post-authentication calls. ignoring the return code.
375          */
376         vp = pairfind(request->config_items, PW_POST_AUTH_TYPE);
377         if (vp) {
378                 DEBUG2("  Found Post-Auth-Type %s", vp->vp_strvalue);
379                 postauth_type = vp->lvalue;
380         }
381         result = module_post_auth(postauth_type, request);
382         switch (result) {
383                 /*
384                  *      The module failed, or said to reject the user: Do so.
385                  */
386                 case RLM_MODULE_FAIL:
387                 case RLM_MODULE_INVALID:
388                 case RLM_MODULE_REJECT:
389                 case RLM_MODULE_USERLOCK:
390                 default:
391                         request->reply->code = PW_AUTHENTICATION_REJECT;
392                         result = RLM_MODULE_REJECT;
393                         break;
394                 /*
395                  *      The module handled the request, cancel the reply.
396                  */
397                 case RLM_MODULE_HANDLED:
398                         /* FIXME */
399                         break;
400                 /*
401                  *      The module had a number of OK return codes.
402                  */
403                 case RLM_MODULE_NOOP:
404                 case RLM_MODULE_NOTFOUND:
405                 case RLM_MODULE_OK:
406                 case RLM_MODULE_UPDATED:
407                         result = RLM_MODULE_OK;
408                         break;
409         }
410         return result;
411 }
412
413 /*
414  *      Before sending an Access-Reject, call the modules in the
415  *      Post-Auth-Type REJECT stanza.
416  */
417 static int rad_postauth_reject(REQUEST *request)
418 {
419         int             result;
420         VALUE_PAIR      *tmp;
421         DICT_VALUE      *dval;
422
423         dval = dict_valbyname(PW_POST_AUTH_TYPE, "REJECT");
424         if (dval) {
425                 /* Overwrite the Post-Auth-Type with the value REJECT */
426                 pairdelete(&request->config_items, PW_POST_AUTH_TYPE);
427                 tmp = paircreate(PW_POST_AUTH_TYPE, PW_TYPE_INTEGER);
428                 tmp->lvalue = dval->value;
429                 pairadd(&request->config_items, tmp);
430                 result = rad_postauth(request);
431         } else {
432                 /* No REJECT stanza */
433                 result = RLM_MODULE_OK;
434         }
435         return result;
436 }
437
438 /*
439  *      Process and reply to an authentication request
440  *
441  *      The return value of this function isn't actually used right now, so
442  *      it's not entirely clear if it is returning the right things. --Pac.
443  */
444 int rad_authenticate(REQUEST *request)
445 {
446         VALUE_PAIR      *namepair;
447         VALUE_PAIR      *check_item;
448         VALUE_PAIR      *auth_item;
449         VALUE_PAIR      *module_msg;
450         VALUE_PAIR      *tmp = NULL;
451         int             result;
452         char            umsg[MAX_STRING_LEN + 1];
453         const char      *user_msg = NULL;
454         const char      *password;
455         char            logstr[1024];
456         char            autz_retry = 0;
457         int             autz_type = 0;
458
459         password = "";
460
461         /*
462          *      If this request got proxied to another server, we need
463          *      to check whether it authenticated the request or not.
464          */
465         if (request->proxy_reply) {
466                 switch (request->proxy_reply->code) {
467                 /*
468                  *      Reply of ACCEPT means accept, thus set Auth-Type
469                  *      accordingly.
470                  */
471                 case PW_AUTHENTICATION_ACK:
472                         tmp = paircreate(PW_AUTH_TYPE, PW_TYPE_INTEGER);
473                         if (tmp == NULL) {
474                                 radlog(L_ERR|L_CONS, "Not enough memory");
475                                 exit(1);
476                         }
477                         tmp->lvalue = PW_AUTHTYPE_ACCEPT;
478                         pairadd(&request->config_items, tmp);
479                         break;
480                 /*
481                  *      Challenges are punted back to the NAS without any
482                  *      further processing.
483                  */
484                 case PW_ACCESS_CHALLENGE:
485                         request->reply->code = PW_ACCESS_CHALLENGE;
486                         return RLM_MODULE_OK;
487                 /*
488                  *      ALL other replies mean reject. (this is fail-safe)
489                  *
490                  *      Do NOT do any authorization or authentication. They
491                  *      are being rejected, so we minimize the amount of work
492                  *      done by the server, by rejecting them here.
493                  */
494                 case PW_AUTHENTICATION_REJECT:
495                 default:
496                         rad_authlog("Login incorrect (Home Server says so)",
497                                     request, 0);
498                         request->reply->code = PW_AUTHENTICATION_REJECT;
499                         rad_postauth_reject(request);
500                         return RLM_MODULE_REJECT;
501                 }
502         }
503
504         /*
505          *      Get the username from the request.
506          *
507          *      Note that namepair MAY be NULL, in which case there
508          *      is no User-Name attribute in the request.
509          */
510         namepair = request->username;
511
512         /*
513          *      Look for, and cache, passwords.
514          */
515         if (!request->password) {
516                 request->password = pairfind(request->packet->vps,
517                                              PW_PASSWORD);
518         }
519
520         /*
521          *      Discover which password we want to use.
522          */
523         auth_item = request->password;
524         if (auth_item) {
525                 password = (const char *)auth_item->vp_strvalue;
526
527         } else {
528                 /*
529                  *      Maybe there's a CHAP-Password?
530                  */
531                 if ((auth_item = pairfind(request->packet->vps,
532                                 PW_CHAP_PASSWORD)) != NULL) {
533                         password = "<CHAP-PASSWORD>";
534
535                 } else {
536                         /*
537                          *      No password we recognize.
538                          */
539                         password = "<NO-PASSWORD>";
540                 }
541         }
542         request->password = auth_item;
543
544         /*
545          *      Get the user's authorization information from the database
546          */
547 autz_redo:
548         result = module_authorize(autz_type, request);
549         switch (result) {
550                 case RLM_MODULE_NOOP:
551                 case RLM_MODULE_NOTFOUND:
552                 case RLM_MODULE_OK:
553                 case RLM_MODULE_UPDATED:
554                         break;
555                 case RLM_MODULE_FAIL:
556                 case RLM_MODULE_HANDLED:
557                         return result;
558                 case RLM_MODULE_INVALID:
559                 case RLM_MODULE_REJECT:
560                 case RLM_MODULE_USERLOCK:
561                 default:
562                         if ((module_msg = pairfind(request->packet->vps,
563                                         PW_MODULE_FAILURE_MESSAGE)) != NULL) {
564                                 char msg[MAX_STRING_LEN + 16];
565                                 snprintf(msg, sizeof(msg), "Invalid user (%s)",
566                                          module_msg->vp_strvalue);
567                                 rad_authlog(msg,request,0);
568                         } else {
569                                 rad_authlog("Invalid user", request, 0);
570                         }
571                         request->reply->code = PW_AUTHENTICATION_REJECT;
572                         return result;
573         }
574         if (!autz_retry) {
575                 tmp = pairfind(request->config_items, PW_AUTZ_TYPE);
576                 if (tmp) {
577                         DEBUG2("  Found Autz-Type %s", tmp->vp_strvalue);
578                         autz_type = tmp->lvalue;
579                         autz_retry = 1;
580                         goto autz_redo;
581                 }
582         }
583
584         /*
585          *      If we haven't already proxied the packet, then check
586          *      to see if we should.  Maybe one of the authorize
587          *      modules has decided that a proxy should be used. If
588          *      so, get out of here and send the packet.
589          */
590         if ((request->proxy == NULL) &&
591             ((tmp = pairfind(request->config_items, PW_PROXY_TO_REALM)) != NULL)) {
592                 REALM *realm;
593
594                 /*
595                  *      Catch users who set Proxy-To-Realm to a LOCAL
596                  *      realm (sigh).
597                  */
598                 realm = realm_find(tmp->vp_strvalue, 0);
599                 rad_assert((realm == NULL) || (realm->ipaddr.af == AF_INET));
600                 if (realm && (realm->ipaddr.ipaddr.ip4addr.s_addr == htonl(INADDR_NONE))) {
601                         DEBUG2("  WARNING: You set Proxy-To-Realm = %s, but it is a LOCAL realm!  Cancelling invalid proxy request.", realm->realm);
602                 } else {
603                         /*
604                          *      Don't authenticate, as the request is
605                          *      proxied.
606                          */
607                         return RLM_MODULE_OK;
608                 }
609         }
610
611         /*
612          *      Perhaps there is a Stripped-User-Name now.
613          */
614         namepair = request->username;
615
616         /*
617          *      Validate the user
618          */
619         do {
620                 result = rad_check_password(request);
621                 if (result > 0) {
622                         /* don't reply! */
623                         return RLM_MODULE_HANDLED;
624                 }
625         } while(0);
626
627         /*
628          *      Failed to validate the user.
629          *
630          *      We PRESUME that the code which failed will clean up
631          *      request->reply->vps, to be ONLY the reply items it
632          *      wants to send back.
633          */
634         if (result < 0) {
635                 DEBUG2("auth: Failed to validate the user.");
636                 request->reply->code = PW_AUTHENTICATION_REJECT;
637
638                 if ((module_msg = pairfind(request->packet->vps,PW_MODULE_FAILURE_MESSAGE)) != NULL){
639                         char msg[MAX_STRING_LEN+19];
640
641                         snprintf(msg, sizeof(msg), "Login incorrect (%s)",
642                                  module_msg->vp_strvalue);
643                         rad_authlog(msg, request, 0);
644                 } else {
645                         rad_authlog("Login incorrect", request, 0);
646                 }
647
648                 /* double check: maybe the secret is wrong? */
649                 if ((debug_flag > 1) && (auth_item != NULL) &&
650                                 (auth_item->attribute == PW_PASSWORD)) {
651                         u_char *p;
652
653                         p = auth_item->vp_strvalue;
654                         while (*p != '\0') {
655                                 if (!isprint((int) *p)) {
656                                         log_debug("  WARNING: Unprintable characters in the password.\n\t  Double-check the shared secret on the server and the NAS!");
657                                         break;
658                                 }
659                                 p++;
660                         }
661                 }
662         }
663
664         if (result >= 0 &&
665             (check_item = pairfind(request->config_items, PW_SIMULTANEOUS_USE)) != NULL) {
666                 int r, session_type = 0;
667
668                 tmp = pairfind(request->config_items, PW_SESSION_TYPE);
669                 if (tmp) {
670                         DEBUG2("  Found Session-Type %s", tmp->vp_strvalue);
671                         session_type = tmp->lvalue;
672                 }
673
674                 /*
675                  *      User authenticated O.K. Now we have to check
676                  *      for the Simultaneous-Use parameter.
677                  */
678                 if (namepair &&
679                     (r = module_checksimul(session_type, request, check_item->lvalue)) != 0) {
680                         char mpp_ok = 0;
681
682                         if (r == 2){
683                                 /* Multilink attempt. Check if port-limit > simultaneous-use */
684                                 VALUE_PAIR *port_limit;
685
686                                 if ((port_limit = pairfind(request->reply->vps, PW_PORT_LIMIT)) != NULL &&
687                                         port_limit->lvalue > check_item->lvalue){
688                                         DEBUG2("main auth: MPP is OK");
689                                         mpp_ok = 1;
690                                 }
691                         }
692                         if (!mpp_ok){
693                                 if (check_item->lvalue > 1) {
694                                 snprintf(umsg, sizeof(umsg),
695                                                         "\r\nYou are already logged in %d times  - access denied\r\n\n",
696                                                         (int)check_item->lvalue);
697                                         user_msg = umsg;
698                                 } else {
699                                         user_msg = "\r\nYou are already logged in - access denied\r\n\n";
700                                 }
701
702                                 request->reply->code = PW_AUTHENTICATION_REJECT;
703
704                                 /*
705                                  *      They're trying to log in too many times.
706                                  *      Remove ALL reply attributes.
707                                  */
708                                 pairfree(&request->reply->vps);
709                                 tmp = pairmake("Reply-Message", user_msg, T_OP_SET);
710                                 request->reply->vps = tmp;
711
712                                 snprintf(logstr, sizeof(logstr), "Multiple logins (max %d) %s",
713                                         check_item->lvalue,
714                                         r == 2 ? "[MPP attempt]" : "");
715                                 rad_authlog(logstr, request, 1);
716
717                                 result = -1;
718                         }
719                 }
720         }
721
722         /*
723          *      Result should be >= 0 here - if not, it means the user
724          *      is rejected, so we just process post-auth and return.
725          */
726         if (result < 0) {
727                 rad_postauth_reject(request);
728                 return RLM_MODULE_REJECT;
729         }
730
731         /*
732          *      We might need this later.  The 'password' string
733          *      is NOT used anywhere below here, except for logging,
734          *      so it should be safe...
735          */
736         if ((auth_item != NULL) && (auth_item->attribute == PW_CHAP_PASSWORD)) {
737                 password = "CHAP-Password";
738         }
739
740         /*
741          *      Add the port number to the Framed-IP-Address if
742          *      vp->addport is set.
743          */
744         if (((tmp = pairfind(request->reply->vps,
745                              PW_FRAMED_IP_ADDRESS)) != NULL) &&
746             (tmp->flags.addport != 0)) {
747                 VALUE_PAIR *vpPortId;
748
749                 /*
750                  *  Find the NAS port ID.
751                  */
752                 if ((vpPortId = pairfind(request->packet->vps,
753                                          PW_NAS_PORT)) != NULL) {
754                   unsigned long tvalue = ntohl(tmp->lvalue);
755                   tmp->lvalue = htonl(tvalue + vpPortId->lvalue);
756                   tmp->flags.addport = 0;
757                   ip_ntoa(tmp->vp_strvalue, tmp->lvalue);
758                 } else {
759                         DEBUG2("WARNING: No NAS-Port attribute in request.  CANNOT return a Framed-IP-Address + NAS-Port.\n");
760                         pairdelete(&request->reply->vps, PW_FRAMED_IP_ADDRESS);
761                 }
762         }
763
764         /*
765          *      Set the reply to Access-Accept, if it hasn't already
766          *      been set to something.  (i.e. Access-Challenge)
767          */
768         if (request->reply->code == 0)
769           request->reply->code = PW_AUTHENTICATION_ACK;
770
771         if ((module_msg = pairfind(request->packet->vps,PW_MODULE_SUCCESS_MESSAGE)) != NULL){
772                 char msg[MAX_STRING_LEN+12];
773
774                 snprintf(msg, sizeof(msg), "Login OK (%s)",
775                          module_msg->vp_strvalue);
776                 rad_authlog(msg, request, 1);
777         } else {
778                 rad_authlog("Login OK", request, 1);
779         }
780
781         /*
782          *      Run the modules in the 'post-auth' section.
783          */
784         result = rad_postauth(request);
785
786         return result;
787 }