~ubuntu-branches/ubuntu/feisty/freeradius/feisty-security

« back to all changes in this revision

Viewing changes to src/main/auth.c

  • Committer: Bazaar Package Importer
  • Author(s): Mark Hymers
  • Date: 2006-12-16 20:45:11 UTC
  • mfrom: (3.1.10 feisty)
  • Revision ID: james.westby@ubuntu.com-20061216204511-3pbbsu4s8jtehsor
Tags: 1.1.3-3
Fix POSIX compliance problem in init script.  Closes: #403384. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * auth.c       User authentication.
3
3
 *
4
 
 * Version:     $Id: auth.c,v 1.136 2004/03/08 21:51:03 aland Exp $
 
4
 * Version:     $Id: auth.c,v 1.136.2.5 2005/10/31 17:59:21 nbk Exp $
5
5
 *
6
6
 *   This program is free software; you can redistribute it and/or modify
7
7
 *   it under the terms of the GNU General Public License as published by
22
22
 * Copyright 2000  Jeff Carneal <jeff@apex.net>
23
23
 */
24
24
 
25
 
static const char rcsid[] = "$Id: auth.c,v 1.136 2004/03/08 21:51:03 aland Exp $";
 
25
static const char rcsid[] = "$Id: auth.c,v 1.136.2.5 2005/10/31 17:59:21 nbk Exp $";
26
26
 
27
27
#include "autoconf.h"
28
28
#include "libradius.h"
65
65
 */
66
66
static int check_expiration(REQUEST *request)
67
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;
 
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;
98
89
        }
99
 
        return result;
 
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;
100
107
}
101
108
 
102
109
 
256
263
        }
257
264
 
258
265
        switch(auth_type) {
 
266
                DICT_VALUE *dval;
 
267
 
259
268
                case PW_AUTHTYPE_CRYPT:
260
269
                        /*
261
270
                         *      Find the password sent by the user. It
342
351
                        DEBUG2("auth: user supplied CHAP-Password matches local User-Password");
343
352
                        break;
344
353
                default:
345
 
                        DEBUG2("auth: type \"%s\"",
346
 
                                        dict_valbyattr(PW_AUTH_TYPE, auth_type)->name);
 
354
                        dval = dict_valbyattr(PW_AUTH_TYPE, auth_type);
 
355
                        if (dval) {
 
356
                                DEBUG2("auth: type \"%s\"", dval->name);
 
357
                        } else {
 
358
                                DEBUG2("auth: type UNKNOWN-%d", auth_type);
 
359
                        }
 
360
 
347
361
                        /*
348
362
                         *      See if there is a module that handles
349
363
                         *      this type, and turn the RLM_ return
359
373
                                 *      is the same as an explicit REJECT!
360
374
                                 */
361
375
                                case RLM_MODULE_FAIL:
362
 
                                case RLM_MODULE_REJECT:
363
 
                                case RLM_MODULE_USERLOCK:
364
376
                                case RLM_MODULE_INVALID:
 
377
                                case RLM_MODULE_NOOP:
365
378
                                case RLM_MODULE_NOTFOUND:
366
 
                                case RLM_MODULE_NOOP:
 
379
                                case RLM_MODULE_REJECT:
367
380
                                case RLM_MODULE_UPDATED:
 
381
                                case RLM_MODULE_USERLOCK:
 
382
                                default:
368
383
                                        result = -1;
369
384
                                        break;
370
385
                                case RLM_MODULE_OK:
389
404
{
390
405
        int     result;
391
406
        int     postauth_type = 0;
392
 
        VALUE_PAIR      *postauth_type_item = NULL;
 
407
        VALUE_PAIR *vp;
393
408
 
394
409
        /*
395
410
         *      Do post-authentication calls. ignoring the return code.
396
411
         */
397
 
        postauth_type_item = pairfind(request->config_items, PW_POST_AUTH_TYPE);
398
 
        if (postauth_type_item)
399
 
                postauth_type = postauth_type_item->lvalue;
 
412
        vp = pairfind(request->config_items, PW_POST_AUTH_TYPE);
 
413
        if (vp) {
 
414
                DEBUG2("  Found Post-Auth-Type %s", vp->strvalue);
 
415
                postauth_type = vp->lvalue;
 
416
        }
400
417
        result = module_post_auth(postauth_type, request);
401
418
        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;
 
419
                /*
 
420
                 *      The module failed, or said to reject the user: Do so.
 
421
                 */
 
422
                case RLM_MODULE_FAIL:
 
423
                case RLM_MODULE_INVALID:
 
424
                case RLM_MODULE_REJECT:
 
425
                case RLM_MODULE_USERLOCK:
 
426
                default:
 
427
                        request->reply->code = PW_AUTHENTICATION_REJECT;
 
428
                        result = RLM_MODULE_REJECT;
 
429
                        break;
 
430
                /*
 
431
                 *      The module handled the request, cancel the reply.
 
432
                 */
 
433
                case RLM_MODULE_HANDLED:
 
434
                        /* FIXME */
 
435
                        result = RLM_MODULE_OK;
 
436
                        break;
 
437
                /*
 
438
                 *      The module had a number of OK return codes.
 
439
                 */
 
440
                case RLM_MODULE_NOOP:
 
441
                case RLM_MODULE_NOTFOUND:
 
442
                case RLM_MODULE_OK:
 
443
                case RLM_MODULE_UPDATED:
 
444
                        result = RLM_MODULE_OK;
 
445
                        break;
 
446
        }
 
447
        return result;
 
448
}
 
449
 
 
450
/*
 
451
 *      Before sending an Access-Reject, call the modules in the
 
452
 *      Post-Auth-Type REJECT stanza.
 
453
 */
 
454
static int rad_postauth_reject(REQUEST *request)
 
455
{
 
456
        int             result;
 
457
        VALUE_PAIR      *tmp;
 
458
        DICT_VALUE      *dval;
 
459
 
 
460
        dval = dict_valbyname(PW_POST_AUTH_TYPE, "REJECT");
 
461
        if (dval) {
 
462
                /* Overwrite the Post-Auth-Type with the value REJECT */
 
463
                pairdelete(&request->config_items, PW_POST_AUTH_TYPE);
 
464
                tmp = paircreate(PW_POST_AUTH_TYPE, PW_TYPE_INTEGER);
 
465
                tmp->lvalue = dval->value;
 
466
                pairadd(&request->config_items, tmp);
 
467
                result = rad_postauth(request);
 
468
        } else {
 
469
                /* No REJECT stanza */
 
470
                result = RLM_MODULE_OK;
426
471
        }
427
472
        return result;
428
473
}
455
500
        password = "";
456
501
 
457
502
        /*
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
 
         *      Huh?  If the request wasn't an authentication request,
465
 
         *      WTF are we doing here?
 
503
         *      If this request got proxied to another server, we need
 
504
         *      to check whether it authenticated the request or not.
466
505
         */
467
 
        if ((request->proxy_reply) &&
468
 
            (request->packet->code == PW_AUTHENTICATION_REQUEST)) {
469
 
                tmp = paircreate(PW_AUTH_TYPE, PW_TYPE_INTEGER);
470
 
                if (tmp == NULL) {
471
 
                        radlog(L_ERR|L_CONS, "no memory");
472
 
                        exit(1);
473
 
                }
474
 
 
475
 
                /*
476
 
                 *      Challenges are punted back to the NAS
477
 
                 *      without any further processing.
478
 
                 */
479
 
                if (request->proxy_reply->code == PW_ACCESS_CHALLENGE) {
 
506
        if (request->proxy_reply) {
 
507
                switch (request->proxy_reply->code) {
 
508
                /*
 
509
                 *      Reply of ACCEPT means accept, thus set Auth-Type
 
510
                 *      accordingly.
 
511
                 */
 
512
                case PW_AUTHENTICATION_ACK:
 
513
                        tmp = paircreate(PW_AUTH_TYPE, PW_TYPE_INTEGER);
 
514
                        if (tmp == NULL) {
 
515
                                radlog(L_ERR|L_CONS, "Not enough memory");
 
516
                                exit(1);
 
517
                        }
 
518
                        tmp->lvalue = PW_AUTHTYPE_ACCEPT;
 
519
                        pairadd(&request->config_items, tmp);
 
520
                        break;
 
521
                /*
 
522
                 *      Challenges are punted back to the NAS without any
 
523
                 *      further processing.
 
524
                 */
 
525
                case PW_ACCESS_CHALLENGE:
480
526
                        request->reply->code = PW_ACCESS_CHALLENGE;
481
 
                        return RLM_MODULE_HANDLED;
482
 
                }
483
 
 
484
 
                /*
485
 
                 *      Reply of ACCEPT means accept, ALL other
486
 
                 *      replies mean reject.  This is fail-safe.
487
 
                 */
488
 
                if (request->proxy_reply->code == PW_AUTHENTICATION_ACK)
489
 
                        tmp->lvalue = PW_AUTHTYPE_ACCEPT;
490
 
                else
491
 
                        tmp->lvalue = PW_AUTHTYPE_REJECT;
492
 
                pairadd(&request->config_items, tmp);
493
 
 
494
 
                /*
495
 
                 *      If it's an Access-Reject, then do NOT do any
496
 
                 *      authorization or authentication.  They're being
497
 
                 *      rejected, so we minimize the amount of work
 
527
                        return RLM_MODULE_OK;
 
528
                /*
 
529
                 *      ALL other replies mean reject. (this is fail-safe)
 
530
                 *
 
531
                 *      Do NOT do any authorization or authentication. They
 
532
                 *      are being rejected, so we minimize the amount of work
498
533
                 *      done by the server, by rejecting them here.
499
534
                 */
500
 
                if ((request->proxy_reply->code != PW_AUTHENTICATION_ACK) &&
501
 
                    (request->proxy_reply->code != PW_ACCESS_CHALLENGE)) {
502
 
                        rad_authlog("Login incorrect (Home Server says so)", request, 0);
 
535
                case PW_AUTHENTICATION_REJECT:
 
536
                default:
 
537
                        rad_authlog("Login incorrect (Home Server says so)",
 
538
                                    request, 0);
503
539
                        request->reply->code = PW_AUTHENTICATION_REJECT;
 
540
                        rad_postauth_reject(request);
504
541
                        return RLM_MODULE_REJECT;
505
542
                }
506
543
        }
549
586
         *      Get the user's authorization information from the database
550
587
         */
551
588
autz_redo:
552
 
        r = module_authorize(autz_type, request);
553
 
        if (r != RLM_MODULE_NOTFOUND &&
554
 
            r != RLM_MODULE_NOOP &&
555
 
            r != RLM_MODULE_OK &&
556
 
            r != RLM_MODULE_UPDATED) {
557
 
                if (r != RLM_MODULE_FAIL && r != RLM_MODULE_HANDLED) {
 
589
        result = module_authorize(autz_type, request);
 
590
        switch (result) {
 
591
                case RLM_MODULE_NOOP:
 
592
                case RLM_MODULE_NOTFOUND:
 
593
                case RLM_MODULE_OK:
 
594
                case RLM_MODULE_UPDATED:
 
595
                        break;
 
596
                case RLM_MODULE_FAIL:
 
597
                case RLM_MODULE_HANDLED:
 
598
                        return result;
 
599
                case RLM_MODULE_INVALID:
 
600
                case RLM_MODULE_REJECT:
 
601
                case RLM_MODULE_USERLOCK:
 
602
                default:
558
603
                        if ((module_msg = pairfind(request->packet->vps,
559
 
                                        PW_MODULE_FAILURE_MESSAGE)) != NULL){
560
 
                                char msg[MAX_STRING_LEN+16];
 
604
                                        PW_MODULE_FAILURE_MESSAGE)) != NULL) {
 
605
                                char msg[MAX_STRING_LEN + 16];
561
606
                                snprintf(msg, sizeof(msg), "Invalid user (%s)",
562
607
                                         module_msg->strvalue);
563
608
                                rad_authlog(msg,request,0);
565
610
                                rad_authlog("Invalid user", request, 0);
566
611
                        }
567
612
                        request->reply->code = PW_AUTHENTICATION_REJECT;
568
 
                }
569
 
                return r;
 
613
                        return result;
570
614
        }
571
 
        if (!autz_retry){
572
 
                VALUE_PAIR      *autz_type_item = NULL;
573
 
                autz_type_item = pairfind(request->config_items, PW_AUTZ_TYPE);
574
 
                if (autz_type_item){
575
 
                        autz_type = autz_type_item->lvalue;
 
615
        if (!autz_retry) {
 
616
                tmp = pairfind(request->config_items, PW_AUTZ_TYPE);
 
617
                if (tmp) {
 
618
                        DEBUG2("  Found Autz-Type %s", tmp->strvalue);
 
619
                        autz_type = tmp->lvalue;
576
620
                        autz_retry = 1;
577
621
                        goto autz_redo;
578
622
                }
661
705
 
662
706
        if (result >= 0 &&
663
707
            (check_item = pairfind(request->config_items, PW_SIMULTANEOUS_USE)) != NULL) {
664
 
                VALUE_PAIR      *session_type;
665
 
                int             sess_type = 0;
 
708
                int session_type = 0;
666
709
 
667
 
                session_type = pairfind(request->config_items, PW_SESSION_TYPE);
668
 
                if (session_type)
669
 
                        sess_type = session_type->lvalue;
 
710
                tmp = pairfind(request->config_items, PW_SESSION_TYPE);
 
711
                if (tmp) {
 
712
                        DEBUG2("  Found Session-Type %s", tmp->strvalue);
 
713
                        session_type = tmp->lvalue;
 
714
                }
670
715
 
671
716
                /*
672
717
                 *      User authenticated O.K. Now we have to check
673
718
                 *      for the Simultaneous-Use parameter.
674
719
                 */
675
720
                if (namepair &&
676
 
                    (r = module_checksimul(sess_type,request, check_item->lvalue)) != 0) {
 
721
                    (r = module_checksimul(session_type, request, check_item->lvalue)) != 0) {
677
722
                        char mpp_ok = 0;
678
723
 
679
724
                        if (r == 2){
777
822
 
778
823
        /*
779
824
         *      Result should be >= 0 here - if not, it means the user
780
 
         *      is rejected, so we overwrite the Post-Auth-Type with
781
 
         *      the value REJECT and call the post-authentication
782
 
         *      step.
 
825
         *      is rejected, so we just process post-auth and return.
783
826
         */
784
827
        if (result < 0) {
785
 
                DICT_VALUE *dval;
786
 
 
787
 
                dval = dict_valbyname(PW_POST_AUTH_TYPE, "REJECT");
788
 
                if (dval) {
789
 
                        pairdelete(&request->config_items, PW_POST_AUTH_TYPE);
790
 
                        tmp = paircreate(PW_POST_AUTH_TYPE, PW_TYPE_INTEGER);
791
 
                        tmp->lvalue = dval->value;
792
 
                        pairadd(&request->config_items, tmp);
793
 
                        rad_postauth(request);
794
 
                }
795
 
                return RLM_MODULE_OK;
 
828
                rad_postauth_reject(request);
 
829
                return RLM_MODULE_REJECT;
796
830
        }
797
831
 
798
832
        /*
869
903
        if (exec_program && exec_wait) {
870
904
                r = radius_exec_program(exec_program, request,
871
905
                                        exec_wait,
872
 
                                        umsg, sizeof(umsg),
 
906
                                        NULL, 0,
873
907
                                        request->packet->vps, &tmp);
874
908
                free(exec_program);
875
909
                exec_program = NULL;
880
914
                pairmove(&request->reply->vps, &tmp);
881
915
                pairfree(&tmp);
882
916
 
883
 
                if (r != 0) {
 
917
                if (r < 0) {
884
918
                        /*
885
919
                         *      Error. radius_exec_program() returns -1 on
886
 
                         *      fork/exec errors, or >0 if the exec'ed program
887
 
                         *      had a non-zero exit status.
 
920
                         *      fork/exec errors.
888
921
                         */
889
 
                        if (umsg[0] == '\0') {
890
 
                                user_msg = "\r\nAccess denied (external check failed).";
891
 
                        } else {
892
 
                                user_msg = &umsg[0];
893
 
                        }
894
 
 
895
 
                        request->reply->code = PW_AUTHENTICATION_REJECT;
 
922
                        user_msg = "Access denied (external check failed)";
896
923
                        tmp = pairmake("Reply-Message", user_msg, T_OP_SET);
897
 
 
898
924
                        pairadd(&request->reply->vps, tmp);
 
925
 
 
926
                        request->reply->code = PW_AUTHENTICATION_REJECT;
899
927
                        rad_authlog("Login incorrect (external check failed)",
900
 
                                        request, 0);
 
928
                                    request, 0);
 
929
                        rad_postauth_reject(request);
 
930
 
 
931
                        return RLM_MODULE_REJECT;
 
932
                }
 
933
                if (r > 0) {
 
934
                        /*
 
935
                         *      Reject. radius_exec_program() returns >0
 
936
                         *      if the exec'ed program had a non-zero
 
937
                         *      exit status.
 
938
                         */
 
939
                        request->reply->code = PW_AUTHENTICATION_REJECT;
 
940
                        rad_authlog("Login incorrect (external check said so)",
 
941
                                    request, 0);
 
942
                        rad_postauth_reject(request);
901
943
 
902
944
                        return RLM_MODULE_REJECT;
903
945
                }