Annotation of embedaddon/mpd/src/auth.c, revision 1.1

1.1     ! misho       1: 
        !             2: /*
        !             3:  * auth.c
        !             4:  *
        !             5:  * Written by Archie Cobbs <archie@freebsd.org>
        !             6:  * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved.
        !             7:  * See ``COPYRIGHT.whistle''
        !             8:  */
        !             9: 
        !            10: #include "ppp.h"
        !            11: #include "auth.h"
        !            12: #include "pap.h"
        !            13: #include "chap.h"
        !            14: #include "lcp.h"
        !            15: #include "log.h"
        !            16: #include "ngfunc.h"
        !            17: #include "msoft.h"
        !            18: #include "util.h"
        !            19: 
        !            20: #ifdef USE_PAM
        !            21: #include <security/pam_appl.h> 
        !            22: #endif
        !            23: #ifdef USE_SYSTEM
        !            24: #if __FreeBSD_version >= 900007
        !            25: #include <utmpx.h>
        !            26: #else
        !            27: #include <utmp.h>
        !            28: #include <libutil.h>
        !            29: #endif
        !            30: #endif
        !            31: 
        !            32: /*
        !            33:  * DEFINITIONS
        !            34:  */
        !            35:     
        !            36: #ifdef USE_OPIE
        !            37:   #define OPIE_ALG_MD5 5
        !            38: #endif
        !            39:   
        !            40: /*
        !            41:  * INTERNAL FUNCTIONS
        !            42:  */
        !            43: 
        !            44:   static void          AuthTimeout(void *arg);
        !            45:   static int           AuthGetExternalPassword(char * extcmd, char *authname,
        !            46:                            char *password, size_t passlen);
        !            47:   static void          AuthAsync(void *arg);
        !            48:   static void          AuthAsyncFinish(void *arg, int was_canceled);
        !            49:   static int           AuthPreChecks(AuthData auth);
        !            50:   static void          AuthAccount(void *arg);
        !            51:   static void          AuthAccountFinish(void *arg, int was_canceled);
        !            52:   static void          AuthInternal(AuthData auth);
        !            53:   static int           AuthExternal(AuthData auth);
        !            54:   static int           AuthExternalAcct(AuthData auth);
        !            55: #ifdef USE_SYSTEM
        !            56:   static void          AuthSystem(AuthData auth);
        !            57:   static int           AuthSystemAcct(AuthData auth);
        !            58: #endif
        !            59: #ifdef USE_PAM
        !            60:   static void          AuthPAM(AuthData auth);
        !            61:   static int           AuthPAMAcct(AuthData auth);
        !            62:   static int           pam_conv(int n, const struct pam_message **msg,
        !            63:                            struct pam_response **resp, void *data);
        !            64: #endif
        !            65: #ifdef USE_OPIE
        !            66:   static void          AuthOpie(AuthData auth);
        !            67: #endif
        !            68:   static const char    *AuthCode(int proto, u_char code, char *buf, size_t len);
        !            69:   static int           AuthSetCommand(Context ctx, int ac, char *av[], void *arg);
        !            70: 
        !            71:   /* Set menu options */
        !            72:   enum {
        !            73:     SET_ACCEPT,
        !            74:     SET_DENY,
        !            75:     SET_ENABLE,
        !            76:     SET_DISABLE,
        !            77:     SET_YES,
        !            78:     SET_NO,
        !            79:     SET_AUTHNAME,
        !            80:     SET_PASSWORD,
        !            81:     SET_EXTAUTH_SCRIPT,
        !            82:     SET_EXTACCT_SCRIPT,
        !            83:     SET_MAX_LOGINS,
        !            84:     SET_ACCT_UPDATE,
        !            85:     SET_ACCT_UPDATE_LIMIT_IN,
        !            86:     SET_ACCT_UPDATE_LIMIT_OUT,
        !            87:     SET_TIMEOUT
        !            88:   };
        !            89: 
        !            90: /*
        !            91:  * GLOBAL VARIABLES
        !            92:  */
        !            93: 
        !            94:   const struct cmdtab AuthSetCmds[] = {
        !            95:     { "max-logins {num}",              "Max concurrent logins",
        !            96:        AuthSetCommand, NULL, 2, (void *) SET_MAX_LOGINS },
        !            97:     { "authname {name}",               "Authentication name",
        !            98:        AuthSetCommand, NULL, 2, (void *) SET_AUTHNAME },
        !            99:     { "password {pass}",               "Authentication password",
        !           100:        AuthSetCommand, NULL, 2, (void *) SET_PASSWORD },
        !           101:     { "extauth-script {script}",       "Authentication script",
        !           102:        AuthSetCommand, NULL, 2, (void *) SET_EXTAUTH_SCRIPT },
        !           103:     { "extacct-script {script}",       "Accounting script",
        !           104:        AuthSetCommand, NULL, 2, (void *) SET_EXTACCT_SCRIPT },
        !           105:     { "acct-update {seconds}",         "set update interval",
        !           106:        AuthSetCommand, NULL, 2, (void *) SET_ACCT_UPDATE },
        !           107:     { "update-limit-in {bytes}",       "set update suppresion limit",
        !           108:        AuthSetCommand, NULL, 2, (void *) SET_ACCT_UPDATE_LIMIT_IN },
        !           109:     { "update-limit-out {bytes}",      "set update suppresion limit",
        !           110:        AuthSetCommand, NULL, 2, (void *) SET_ACCT_UPDATE_LIMIT_OUT },
        !           111:     { "timeout {seconds}",             "set auth timeout",
        !           112:        AuthSetCommand, NULL, 2, (void *) SET_TIMEOUT },
        !           113:     { "accept [opt ...]",              "Accept option",
        !           114:        AuthSetCommand, NULL, 2, (void *) SET_ACCEPT },
        !           115:     { "deny [opt ...]",                        "Deny option",
        !           116:        AuthSetCommand, NULL, 2, (void *) SET_DENY },
        !           117:     { "enable [opt ...]",              "Enable option",
        !           118:        AuthSetCommand, NULL, 2, (void *) SET_ENABLE },
        !           119:     { "disable [opt ...]",             "Disable option",
        !           120:        AuthSetCommand, NULL, 2, (void *) SET_DISABLE },
        !           121:     { "yes [opt ...]",                 "Enable and accept option",
        !           122:        AuthSetCommand, NULL, 2, (void *) SET_YES },
        !           123:     { "no [opt ...]",                  "Disable and deny option",
        !           124:        AuthSetCommand, NULL, 2, (void *) SET_NO },
        !           125:     { NULL },
        !           126:   };
        !           127: 
        !           128:   const u_char gMsoftZeros[32];
        !           129:   int          gMaxLogins = 0; /* max number of concurrent logins per user */
        !           130:   int          gMaxLoginsCI = 0;
        !           131: 
        !           132: /*
        !           133:  * INTERNAL VARIABLES
        !           134:  */
        !           135: 
        !           136:   static struct confinfo       gConfList[] = {
        !           137:     { 0,       AUTH_CONF_RADIUS_AUTH,  "radius-auth"   },
        !           138:     { 0,       AUTH_CONF_RADIUS_ACCT,  "radius-acct"   },
        !           139:     { 0,       AUTH_CONF_INTERNAL,     "internal"      },
        !           140:     { 0,       AUTH_CONF_EXT_AUTH,     "ext-auth"      },
        !           141:     { 0,       AUTH_CONF_EXT_ACCT,     "ext-acct"      },
        !           142: #ifdef USE_SYSTEM
        !           143:     { 0,       AUTH_CONF_SYSTEM_AUTH,  "system-auth"   },
        !           144:     { 0,       AUTH_CONF_SYSTEM_ACCT,  "system-acct"   },
        !           145: #endif
        !           146: #ifdef USE_PAM
        !           147:     { 0,       AUTH_CONF_PAM_AUTH,     "pam-auth"      },
        !           148:     { 0,       AUTH_CONF_PAM_ACCT,     "pam-acct"      },
        !           149: #endif
        !           150: #ifdef USE_OPIE
        !           151:     { 0,       AUTH_CONF_OPIE,         "opie"          },
        !           152: #endif
        !           153:     { 0,       AUTH_CONF_ACCT_MANDATORY,       "acct-mandatory"        },
        !           154:     { 0,       0,                      NULL            },
        !           155:   };
        !           156: 
        !           157: void
        !           158: ACLCopy(struct acl *src, struct acl **dst)
        !           159: {
        !           160:     while (src != NULL) {
        !           161:        *dst = Mdup(MB_AUTH, src, sizeof(struct acl) + strlen(src->rule));
        !           162:        src = src->next;
        !           163:        dst = &((*dst)->next);
        !           164:     };
        !           165:     *dst = NULL;
        !           166: }
        !           167: 
        !           168: void
        !           169: ACLDestroy(struct acl *acl)
        !           170: {
        !           171:     struct acl *acl1;
        !           172: 
        !           173:     while (acl != NULL) {
        !           174:        acl1 = acl->next;
        !           175:        Freee(acl);
        !           176:        acl = acl1;
        !           177:     };
        !           178: }
        !           179: 
        !           180: void   authparamsInit(struct authparams *ap) {
        !           181:     memset(ap,0,sizeof(struct authparams));
        !           182:     ap->msdomain = NULL;
        !           183: #ifdef SIOCSIFDESCR
        !           184:     ap->ifdescr = NULL;
        !           185: #endif
        !           186:     SLIST_INIT(&ap->routes);
        !           187: }
        !           188: 
        !           189: void   authparamsDestroy(struct authparams *ap) {
        !           190:     IfaceRoute         r;
        !           191: #ifdef USE_NG_BPF
        !           192:     int i;
        !           193: #endif
        !           194:   
        !           195:     Freee(ap->eapmsg);
        !           196:     Freee(ap->state);
        !           197:     Freee(ap->class);
        !           198: 
        !           199: #ifdef USE_IPFW
        !           200:     ACLDestroy(ap->acl_rule);
        !           201:     ACLDestroy(ap->acl_pipe);
        !           202:     ACLDestroy(ap->acl_queue);
        !           203:     ACLDestroy(ap->acl_table);
        !           204: #endif /* USE_IPFW */
        !           205: 
        !           206: #ifdef USE_NG_BPF
        !           207:     for (i = 0; i < ACL_FILTERS; i++)
        !           208:        ACLDestroy(ap->acl_filters[i]);
        !           209:     for (i = 0; i < ACL_DIRS; i++)
        !           210:        ACLDestroy(ap->acl_limits[i]);
        !           211: #endif /* USE_NG_BPF */
        !           212: 
        !           213:     while ((r = SLIST_FIRST(&ap->routes)) != NULL) {
        !           214:        SLIST_REMOVE_HEAD(&ap->routes, next);
        !           215:        Freee(r);
        !           216:     }
        !           217: 
        !           218:     Freee(ap->msdomain);
        !           219: #ifdef SIOCSIFDESCR
        !           220:     Freee(ap->ifdescr);
        !           221: #endif
        !           222:     
        !           223:     memset(ap,0,sizeof(struct authparams));
        !           224: }
        !           225: 
        !           226: void   authparamsCopy(struct authparams *src, struct authparams *dst) {
        !           227:     IfaceRoute         r, r1;
        !           228: #ifdef USE_NG_BPF
        !           229:     int                        i;
        !           230: #endif
        !           231: 
        !           232:     memcpy(dst,src,sizeof(struct authparams));
        !           233:   
        !           234:     if (src->eapmsg)
        !           235:        dst->eapmsg = Mdup(MB_AUTH, src->eapmsg, src->eapmsg_len);
        !           236:     if (src->state)
        !           237:        dst->state = Mdup(MB_AUTH, src->state, src->state_len);
        !           238:     if (src->class)
        !           239:        dst->class = Mdup(MB_AUTH, src->class, src->class_len);
        !           240: 
        !           241: #ifdef USE_IPFW
        !           242:     ACLCopy(src->acl_rule, &dst->acl_rule);
        !           243:     ACLCopy(src->acl_pipe, &dst->acl_pipe);
        !           244:     ACLCopy(src->acl_queue, &dst->acl_queue);
        !           245:     ACLCopy(src->acl_table, &dst->acl_table);
        !           246: #endif /* USE_IPFW */
        !           247: #ifdef USE_NG_BPF
        !           248:     for (i = 0; i < ACL_FILTERS; i++)
        !           249:        ACLCopy(src->acl_filters[i], &dst->acl_filters[i]);
        !           250:     for (i = 0; i < ACL_DIRS; i++)
        !           251:        ACLCopy(src->acl_limits[i], &dst->acl_limits[i]);
        !           252: #endif
        !           253: 
        !           254:     SLIST_INIT(&dst->routes);
        !           255:     SLIST_FOREACH(r, &src->routes, next) {
        !           256:        r1 = Mdup(MB_AUTH, r, sizeof(*r1));
        !           257:        SLIST_INSERT_HEAD(&dst->routes, r1, next);
        !           258:     }
        !           259: 
        !           260:     if (src->msdomain)
        !           261:        dst->msdomain = Mstrdup(MB_AUTH, src->msdomain);
        !           262: #ifdef SIOCSIFDESCR
        !           263:     if (src->ifdescr)
        !           264:        dst->ifdescr = Mstrdup(MB_AUTH, src->ifdescr);
        !           265: #endif
        !           266: }
        !           267: 
        !           268: void   authparamsMove(struct authparams *src, struct authparams *dst)
        !           269: {
        !           270:     memcpy(dst,src,sizeof(struct authparams));
        !           271:     memset(src,0,sizeof(struct authparams));
        !           272: }
        !           273: 
        !           274: /*
        !           275:  * AuthInit()
        !           276:  */
        !           277: 
        !           278: void
        !           279: AuthInit(Link l)
        !           280: {
        !           281:     AuthConf   const ac = &l->lcp.auth.conf;
        !           282:   
        !           283:     ac->timeout = 40;
        !           284:     Enable(&ac->options, AUTH_CONF_INTERNAL);
        !           285:     Enable(&ac->options, AUTH_CONF_ACCT_MANDATORY);
        !           286: 
        !           287:     EapInit(l);
        !           288:     RadiusInit(l);
        !           289: }
        !           290: 
        !           291: /*
        !           292:  * AuthInst()
        !           293:  *
        !           294:  * Instantiate auth structure from template
        !           295:  */
        !           296: 
        !           297: void
        !           298: AuthInst(Auth auth, Auth autht)
        !           299: {
        !           300:     memcpy(auth, autht, sizeof(*auth));
        !           301:     if (auth->conf.extauth_script)
        !           302:        autht->conf.extauth_script = Mstrdup(MB_AUTH, auth->conf.extauth_script);
        !           303:     if (auth->conf.extacct_script)
        !           304:        autht->conf.extacct_script = Mstrdup(MB_AUTH, auth->conf.extacct_script);
        !           305: }
        !           306: 
        !           307: /*
        !           308:  * AuthShutdown()
        !           309:  */
        !           310: 
        !           311: void
        !           312: AuthShutdown(Link l)
        !           313: {
        !           314:     Auth       a = &l->lcp.auth;
        !           315:   
        !           316:     if (a->thread)
        !           317:        paction_cancel(&a->thread);
        !           318:     if (a->acct_thread)
        !           319:        paction_cancel(&a->acct_thread);
        !           320:     Freee(a->conf.extauth_script);
        !           321:     Freee(a->conf.extacct_script);
        !           322: }
        !           323: 
        !           324: /*
        !           325:  * AuthStart()
        !           326:  *
        !           327:  * Initialize authorization info for a link
        !           328:  */
        !           329: 
        !           330: void
        !           331: AuthStart(Link l)
        !           332: {
        !           333:     Auth       a = &l->lcp.auth;
        !           334: 
        !           335:     /* generate a uniq session id */
        !           336:     snprintf(l->session_id, AUTH_MAX_SESSIONID, "%d-%s",
        !           337:        (int)(time(NULL) % 10000000), l->name);
        !           338: 
        !           339:     authparamsInit(&a->params);
        !           340:     
        !           341:     /* What auth protocols were negotiated by LCP? */
        !           342:     a->self_to_peer = l->lcp.peer_auth;
        !           343:     a->peer_to_self = l->lcp.want_auth;
        !           344:     a->self_to_peer_alg = l->lcp.peer_alg;
        !           345:     a->peer_to_self_alg = l->lcp.want_alg;
        !           346: 
        !           347:     /* remember self's name */
        !           348:     PhysGetSelfName(l, a->params.selfname, sizeof(a->params.selfname));
        !           349:   
        !           350:     /* remember peer's name */
        !           351:     PhysGetPeerName(l, a->params.peername, sizeof(a->params.peername));
        !           352:   
        !           353:     /* remember self's IP address */
        !           354:     PhysGetSelfAddr(l, a->params.selfaddr, sizeof(a->params.selfaddr));
        !           355:   
        !           356:     /* remember peer's IP address */
        !           357:     PhysGetPeerAddr(l, a->params.peeraddr, sizeof(a->params.peeraddr));
        !           358:   
        !           359:     /* remember peer's TCP or UDP port */
        !           360:     PhysGetPeerPort(l, a->params.peerport, sizeof(a->params.peerport));
        !           361:   
        !           362:     /* remember peer's MAC address */
        !           363:     PhysGetPeerMacAddr(l, a->params.peermacaddr, sizeof(a->params.peermacaddr));
        !           364:   
        !           365:     /* remember peer's iface */
        !           366:     PhysGetPeerIface(l, a->params.peeriface, sizeof(a->params.peeriface));
        !           367:   
        !           368:     /* remember calling number */
        !           369:     PhysGetCallingNum(l, a->params.callingnum, sizeof(a->params.callingnum));
        !           370:   
        !           371:     /* remember called number */
        !           372:     PhysGetCalledNum(l, a->params.callednum, sizeof(a->params.callednum));
        !           373:     
        !           374:   Log(LG_AUTH, ("[%s] %s: auth: peer wants %s, I want %s",
        !           375:     Pref(&l->lcp.fsm), Fsm(&l->lcp.fsm),
        !           376:     a->self_to_peer ? ProtoName(a->self_to_peer) : "nothing",
        !           377:     a->peer_to_self ? ProtoName(a->peer_to_self) : "nothing"));
        !           378: 
        !           379:   /* Is there anything to do? */
        !           380:   if (!a->self_to_peer && !a->peer_to_self) {
        !           381:     LcpAuthResult(l, TRUE);
        !           382:     return;
        !           383:   }
        !           384: 
        !           385:   /* Start global auth timer */
        !           386:   TimerInit(&a->timer, "AuthTimer",
        !           387:     l->lcp.auth.conf.timeout * SECONDS, AuthTimeout, l);
        !           388:   TimerStart(&a->timer);
        !           389: 
        !           390:   /* Start my auth to him */
        !           391:   switch (a->self_to_peer) {
        !           392:     case 0:
        !           393:       break;
        !           394:     case PROTO_PAP:
        !           395:       PapStart(l, AUTH_SELF_TO_PEER);
        !           396:       break;
        !           397:     case PROTO_CHAP:
        !           398:       ChapStart(l, AUTH_SELF_TO_PEER);
        !           399:       break;
        !           400:     case PROTO_EAP:
        !           401:       EapStart(l, AUTH_SELF_TO_PEER);
        !           402:       break;
        !           403:     default:
        !           404:       assert(0);
        !           405:   }
        !           406: 
        !           407:   /* Start his auth to me */
        !           408:   switch (a->peer_to_self) {
        !           409:     case 0:
        !           410:       break;
        !           411:     case PROTO_PAP:
        !           412:       PapStart(l, AUTH_PEER_TO_SELF);
        !           413:       break;
        !           414:     case PROTO_CHAP:
        !           415:       ChapStart(l, AUTH_PEER_TO_SELF);
        !           416:       break;
        !           417:     case PROTO_EAP:
        !           418:       EapStart(l, AUTH_PEER_TO_SELF);
        !           419:       break;
        !           420:     default:
        !           421:       assert(0);
        !           422:   }
        !           423: }
        !           424: 
        !           425: /*
        !           426:  * AuthInput()
        !           427:  *
        !           428:  * Deal with PAP/CHAP/EAP packet
        !           429:  */
        !           430: 
        !           431: void
        !           432: AuthInput(Link l, int proto, Mbuf bp)
        !           433: {
        !           434:   AuthData             auth;
        !           435:   int                  len;
        !           436:   struct fsmheader     fsmh;
        !           437:   u_char               *pkt;
        !           438:   char                 buf[16];
        !           439: 
        !           440:   /* Sanity check */
        !           441:   if (l->lcp.phase != PHASE_AUTHENTICATE && l->lcp.phase != PHASE_NETWORK) {
        !           442:     Log(LG_AUTH, ("[%s] AUTH: rec'd stray packet", l->name));
        !           443:     mbfree(bp);
        !           444:     return;
        !           445:   }
        !           446: 
        !           447:   len = MBLEN(bp);
        !           448: 
        !           449:   /* Sanity check length */
        !           450:   if (len < sizeof(fsmh)) {
        !           451:     Log(LG_AUTH, ("[%s] AUTH: rec'd runt packet: %d bytes",
        !           452:       l->name, len));
        !           453:     mbfree(bp);
        !           454:     return;
        !           455:   }
        !           456: 
        !           457:   auth = AuthDataNew(l);
        !           458:   auth->proto = proto;
        !           459: 
        !           460:   bp = mbread(bp, &fsmh, sizeof(fsmh));
        !           461:   if (len > ntohs(fsmh.length))
        !           462:     len = ntohs(fsmh.length);
        !           463:   len -= sizeof(fsmh);
        !           464: 
        !           465:   pkt = MBDATA(bp);
        !           466: 
        !           467:   if (proto == PROTO_EAP && bp) {
        !           468:     Log(LG_AUTH, ("[%s] %s: rec'd %s #%d len: %d, type: %s", l->name,
        !           469:       ProtoName(proto), AuthCode(proto, fsmh.code, buf, sizeof(buf)), fsmh.id,
        !           470:         ntohs(fsmh.length), EapType(pkt[0])));
        !           471:   } else {
        !           472:     Log(LG_AUTH, ("[%s] %s: rec'd %s #%d len: %d", l->name,
        !           473:       ProtoName(proto), AuthCode(proto, fsmh.code, buf, sizeof(buf)), fsmh.id,
        !           474:         ntohs(fsmh.length)));
        !           475:   }
        !           476: 
        !           477:   auth->id = fsmh.id;
        !           478:   auth->code = fsmh.code;
        !           479:   /* Status defaults to undefined */
        !           480:   auth->status = AUTH_STATUS_UNDEF;
        !           481:   
        !           482:   switch (proto) {
        !           483:     case PROTO_PAP:
        !           484:       PapInput(l, auth, pkt, len);
        !           485:       break;
        !           486:     case PROTO_CHAP:
        !           487:       ChapInput(l, auth, pkt, len);
        !           488:       break;
        !           489:     case PROTO_EAP:
        !           490:       EapInput(l, auth, pkt, len);
        !           491:       break;
        !           492:     default:
        !           493:       assert(0);
        !           494:   }
        !           495:   
        !           496:   mbfree(bp);
        !           497: }
        !           498: 
        !           499: /*
        !           500:  * AuthOutput()
        !           501:  *
        !           502:  */
        !           503: 
        !           504: void
        !           505: AuthOutput(Link l, int proto, u_int code, u_int id, const u_char *ptr,
        !           506:        int len, int add_len, u_char eap_type)
        !           507: {
        !           508:   struct fsmheader     lh;
        !           509:   Mbuf                 bp;
        !           510:   int                  plen;
        !           511:   char                 buf[32];
        !           512: 
        !           513:   add_len = !!add_len;
        !           514:   /* Setup header */
        !           515:   if (proto == PROTO_EAP)
        !           516:     plen = sizeof(lh) + len + add_len + 1;
        !           517:   else
        !           518:     plen = sizeof(lh) + len + add_len;
        !           519:   lh.code = code;
        !           520:   lh.id = id;
        !           521:   lh.length = htons(plen);
        !           522: 
        !           523:   /* Build packet */
        !           524:   bp = mbcopyback(NULL, 0, &lh, sizeof(lh));
        !           525:   if (proto == PROTO_EAP)
        !           526:     bp = mbcopyback(bp, MBLEN(bp), &eap_type, 1);
        !           527:   if (add_len) {
        !           528:     u_char tl = len;
        !           529:     bp = mbcopyback(bp, MBLEN(bp), &tl, 1);
        !           530:   }
        !           531:   bp = mbcopyback(bp, MBLEN(bp), ptr, len);
        !           532: 
        !           533:   if (proto == PROTO_EAP) {
        !           534:     Log(LG_AUTH, ("[%s] %s: sending %s #%d len: %d, type: %s", l->name,
        !           535:       ProtoName(proto), AuthCode(proto, code, buf, sizeof(buf)), id, plen, EapType(eap_type)));
        !           536:   } else {
        !           537:     Log(LG_AUTH, ("[%s] %s: sending %s #%d len: %d", l->name,
        !           538:       ProtoName(proto), AuthCode(proto, code, buf, sizeof(buf)), id, plen));
        !           539:   }
        !           540: 
        !           541:   /* Send it out */
        !           542:   NgFuncWritePppFrameLink(l, proto, bp);
        !           543: }
        !           544: 
        !           545: /*
        !           546:  * AuthFinish()
        !           547:  *
        !           548:  * Authorization is finished, so continue one way or the other
        !           549:  */
        !           550: 
        !           551: void
        !           552: AuthFinish(Link l, int which, int ok)
        !           553: {
        !           554:     Auth       const a = &l->lcp.auth;
        !           555: 
        !           556:     if (which == AUTH_SELF_TO_PEER)
        !           557:         a->self_to_peer = 0;
        !           558:     else
        !           559:         a->peer_to_self = 0;
        !           560:     /* Did auth fail (in either direction)? */
        !           561:     if (!ok) {
        !           562:        AuthStop(l);
        !           563:        LcpAuthResult(l, FALSE);
        !           564:        return;
        !           565:     }
        !           566:     /* Did auth succeed (in both directions)? */
        !           567:     if (!a->peer_to_self && !a->self_to_peer) {
        !           568:        AuthStop(l);
        !           569:        LcpAuthResult(l, TRUE);
        !           570:        return;
        !           571:     }
        !           572: }
        !           573: 
        !           574: /*
        !           575:  * AuthCleanup()
        !           576:  *
        !           577:  * Cleanup auth structure, invoked on link-down
        !           578:  */
        !           579: 
        !           580: void
        !           581: AuthCleanup(Link l)
        !           582: {
        !           583:     Auth       a = &l->lcp.auth;
        !           584: 
        !           585:     Log(LG_AUTH2, ("[%s] AUTH: Cleanup", l->name));
        !           586: 
        !           587:     authparamsDestroy(&a->params);
        !           588: 
        !           589:     l->session_id[0] = 0;
        !           590: }
        !           591: 
        !           592: /* 
        !           593:  * AuthDataNew()
        !           594:  *
        !           595:  * Create a new auth-data object
        !           596:  */
        !           597: 
        !           598: AuthData
        !           599: AuthDataNew(Link l) 
        !           600: {
        !           601:     AuthData   auth;
        !           602:     Auth       a = &l->lcp.auth;  
        !           603: 
        !           604:     auth = Malloc(MB_AUTH, sizeof(*auth));
        !           605:     auth->conf = l->lcp.auth.conf;
        !           606:     if (l->lcp.auth.conf.extauth_script)
        !           607:        auth->conf.extauth_script = Mstrdup(MB_AUTH, l->lcp.auth.conf.extauth_script);
        !           608:     if (l->lcp.auth.conf.extacct_script)
        !           609:        auth->conf.extacct_script = Mstrdup(MB_AUTH, l->lcp.auth.conf.extacct_script);
        !           610: 
        !           611:     strlcpy(auth->info.lnkname, l->name, sizeof(auth->info.lnkname));
        !           612:     strlcpy(auth->info.msession_id, l->msession_id, sizeof(auth->info.msession_id));
        !           613:     strlcpy(auth->info.session_id, l->session_id, sizeof(auth->info.session_id));
        !           614:     strlcpy(auth->info.peer_ident, l->lcp.peer_ident, sizeof(l->lcp.peer_ident));
        !           615:     auth->info.originate = l->originate;
        !           616: 
        !           617:     if (l->bund) {
        !           618:        strlcpy(auth->info.ifname, l->bund->iface.ifname, sizeof(auth->info.ifname));
        !           619:        auth->info.ifindex = l->bund->iface.ifindex;
        !           620:        strlcpy(auth->info.bundname, l->bund->name, sizeof(auth->info.bundname));
        !           621:         auth->info.n_links = l->bund->n_links;
        !           622:        auth->info.peer_addr = l->bund->ipcp.peer_addr;
        !           623:     }
        !           624: 
        !           625:     /* Copy current link statistics */
        !           626:     memcpy(&auth->info.stats, &l->stats, sizeof(auth->info.stats));
        !           627:     
        !           628: #ifdef USE_NG_BPF
        !           629:     /* If it is present copy services statistics */
        !           630:     if (l->bund) {
        !           631:        IfaceGetStats(l->bund, &auth->info.ss);
        !           632:        IfaceAddStats(&auth->info.ss, &l->bund->iface.prevstats);
        !           633:     }
        !           634: #endif
        !           635: 
        !           636:     if (l->downReasonValid)
        !           637:        auth->info.downReason = Mstrdup(MB_AUTH, l->downReason);
        !           638: 
        !           639:     auth->info.last_up = l->last_up;
        !           640:     auth->info.phys_type = l->type;
        !           641:     auth->info.linkID = l->id;
        !           642: 
        !           643:     authparamsCopy(&a->params,&auth->params);
        !           644: 
        !           645:     return auth;
        !           646: }
        !           647: 
        !           648: /*
        !           649:  * AuthDataDestroy()
        !           650:  *
        !           651:  * Destroy authdata
        !           652:  */
        !           653: 
        !           654: void
        !           655: AuthDataDestroy(AuthData auth)
        !           656: {
        !           657:     authparamsDestroy(&auth->params);
        !           658:     Freee(auth->info.downReason);
        !           659:     Freee(auth->reply_message);
        !           660:     Freee(auth->mschap_error);
        !           661:     Freee(auth->mschapv2resp);
        !           662: #ifdef USE_NG_BPF
        !           663:     IfaceFreeStats(&auth->info.ss);
        !           664: #endif
        !           665:     Freee(auth->conf.extauth_script);
        !           666:     Freee(auth->conf.extacct_script);
        !           667:     Freee(auth);
        !           668: }
        !           669: 
        !           670: /*
        !           671:  * AuthStop()
        !           672:  *
        !           673:  * Stop the authorization process
        !           674:  */
        !           675: 
        !           676: void
        !           677: AuthStop(Link l)
        !           678: {
        !           679:   Auth a = &l->lcp.auth;
        !           680: 
        !           681:   TimerStop(&a->timer);
        !           682:   PapStop(&a->pap);
        !           683:   ChapStop(&a->chap);
        !           684:   EapStop(&a->eap);
        !           685:   paction_cancel(&a->thread);
        !           686: }
        !           687: 
        !           688: /*
        !           689:  * AuthStat()
        !           690:  *
        !           691:  * Show auth stats
        !           692:  */
        !           693:  
        !           694: int
        !           695: AuthStat(Context ctx, int ac, char *av[], void *arg)
        !           696: {
        !           697:     Auth       const au = &ctx->lnk->lcp.auth;
        !           698:     AuthConf   const conf = &au->conf;
        !           699:     char       buf[48], buf2[16];
        !           700: #if defined(USE_IPFW) || defined(USE_NG_BPF)
        !           701:     struct acl *a;
        !           702: #endif
        !           703:     IfaceRoute r;
        !           704: #ifdef USE_NG_BPF
        !           705:     int                k;
        !           706: #endif
        !           707: 
        !           708:     Printf("Configuration:\r\n");
        !           709:     Printf("\tMy authname     : %s\r\n", conf->authname);
        !           710:     Printf("\tMax-Logins      : %d%s\r\n", gMaxLogins, (gMaxLoginsCI?" CI":""));
        !           711:     Printf("\tAcct Update     : %d\r\n", conf->acct_update);
        !           712:     Printf("\t   Limit In     : %d\r\n", conf->acct_update_lim_recv);
        !           713:     Printf("\t   Limit Out    : %d\r\n", conf->acct_update_lim_xmit);
        !           714:     Printf("\tAuth timeout    : %d\r\n", conf->timeout);
        !           715:     Printf("\tExtAuth script  : %s\r\n", conf->extauth_script?conf->extauth_script:"");
        !           716:     Printf("\tExtAcct script  : %s\r\n", conf->extacct_script?conf->extacct_script:"");
        !           717:   
        !           718:     Printf("Auth options\r\n");
        !           719:     OptStat(ctx, &conf->options, gConfList);
        !           720: 
        !           721:     Printf("Auth Data\r\n");
        !           722:     Printf("\tPeer authname   : %s\r\n", au->params.authname);
        !           723:     Printf("\tInterface name  : %s\r\n", au->params.ifname);
        !           724: #ifdef SIOCSIFDESCR
        !           725:     Printf("\tInterface descr.: \"%s\"\r\n", 
        !           726:        au->params.ifdescr != NULL ? au->params.ifdescr : "<none>");
        !           727: #endif
        !           728:     Printf("\tInterface group : %s\r\n", au->params.ifgroup);
        !           729:     Printf("\tIP range        : %s\r\n", (au->params.range_valid)?
        !           730:        u_rangetoa(&au->params.range,buf,sizeof(buf)):"");
        !           731:     Printf("\tIP pool         : %s\r\n", au->params.ippool);
        !           732:     Printf("\tDNS             : %s %s\r\n",
        !           733:        inet_ntop(AF_INET, &au->params.peer_dns[0], buf, sizeof(buf)),
        !           734:        inet_ntop(AF_INET, &au->params.peer_dns[1], buf2, sizeof(buf2)));
        !           735:     Printf("\tNBNS            : %s %s\r\n",
        !           736:        inet_ntop(AF_INET, &au->params.peer_nbns[0], buf, sizeof(buf)),
        !           737:        inet_ntop(AF_INET, &au->params.peer_nbns[1], buf2, sizeof(buf2)));
        !           738:     Printf("\tMTU             : %u\r\n", au->params.mtu);
        !           739:     Printf("\tSession-Timeout : %u\r\n", au->params.session_timeout);
        !           740:     Printf("\tIdle-Timeout    : %u\r\n", au->params.idle_timeout);
        !           741:     Printf("\tAcct-Update     : %u\r\n", au->params.acct_update);
        !           742:     Printf("\tRoutes          :\r\n");
        !           743:     SLIST_FOREACH(r, &au->params.routes, next) {
        !           744:         Printf("\t\t%s\r\n", u_rangetoa(&r->dest,buf,sizeof(buf)));
        !           745:     }
        !           746: #ifdef USE_IPFW
        !           747:     Printf("\tIPFW rules      :\r\n");
        !           748:     a = au->params.acl_rule;
        !           749:     while (a) {
        !           750:         Printf("\t\t%d\t: '%s'\r\n", a->number, a->rule);
        !           751:         a = a->next;
        !           752:     }
        !           753:     Printf("\tIPFW pipes      :\r\n");
        !           754:     a = au->params.acl_pipe;
        !           755:     while (a) {
        !           756:         Printf("\t\t%d\t: '%s'\r\n", a->number, a->rule);
        !           757:         a = a->next;
        !           758:     }
        !           759:     Printf("\tIPFW queues     :\r\n");
        !           760:     a = au->params.acl_queue;
        !           761:     while (a) {
        !           762:         Printf("\t\t%d\t: '%s'\r\n", a->number, a->rule);
        !           763:         a = a->next;
        !           764:     }
        !           765:     Printf("\tIPFW tables     :\r\n");
        !           766:     a = au->params.acl_table;
        !           767:     while (a) {
        !           768:         if (a->number != 0)
        !           769:            Printf("\t\t%d\t: '%s'\r\n", a->number, a->rule);
        !           770:         else
        !           771:            Printf("\t\t#%d\t: '%s'\r\n", a->real_number, a->rule);
        !           772:         a = a->next;
        !           773:     }
        !           774: #endif /* USE_IPFW */
        !           775: #ifdef USE_NG_BPF
        !           776:     Printf("\tTraffic filters :\r\n");
        !           777:     for (k = 0; k < ACL_FILTERS; k++) {
        !           778:         a = au->params.acl_filters[k];
        !           779:         while (a) {
        !           780:            Printf("\t%d#%d\t: '%s'\r\n", (k + 1), a->number, a->rule);
        !           781:            a = a->next;
        !           782:        }
        !           783:     }
        !           784:     Printf("\tTraffic limits  :\r\n");
        !           785:     for (k = 0; k < 2; k++) {
        !           786:         a = au->params.acl_limits[k];
        !           787:        while (a) {
        !           788:            Printf("\t\t%s#%d%s%s\t: '%s'\r\n", (k?"out":"in"), a->number,
        !           789:                ((a->name[0])?"#":""), a->name, a->rule);
        !           790:            a = a->next;
        !           791:        }
        !           792:     }
        !           793: #endif /* USE_NG_BPF */
        !           794:     Printf("\tMS-Domain       : %s\r\n", au->params.msdomain);  
        !           795:     Printf("\tMPPE Types      : %s\r\n", AuthMPPEPolicyname(au->params.msoft.policy));
        !           796:     Printf("\tMPPE Policy     : %s\r\n", AuthMPPETypesname(au->params.msoft.types, buf, sizeof(buf)));
        !           797:     Printf("\tMPPE Keys       : %s\r\n", au->params.msoft.has_keys ? "yes" : "no");
        !           798: 
        !           799:     return (0);
        !           800: }
        !           801: 
        !           802: 
        !           803: /*
        !           804:  * AuthAccount()
        !           805:  *
        !           806:  * Accounting stuff, 
        !           807:  */
        !           808:  
        !           809: void
        !           810: AuthAccountStart(Link l, int type)
        !           811: {
        !           812:     Auth               const a = &l->lcp.auth;
        !           813:     AuthData           auth;
        !           814:       
        !           815:     /* maybe an outstanding thread is running */
        !           816:     if (a->acct_thread) {
        !           817:        if (type == AUTH_ACCT_START || type == AUTH_ACCT_STOP) {
        !           818:            paction_cancel(&a->acct_thread);
        !           819:        } else {
        !           820:            Log(LG_AUTH2, ("[%s] ACCT: Accounting thread is already running", 
        !           821:                l->name));
        !           822:            return;
        !           823:        }
        !           824:     }
        !           825: 
        !           826:     LinkUpdateStats(l);
        !           827:     if (type == AUTH_ACCT_STOP) {
        !           828:        Log(LG_AUTH2, ("[%s] ACCT: Accounting data for user '%s': %lu seconds, %llu octets in, %llu octets out",
        !           829:            l->name, a->params.authname,
        !           830:            (unsigned long) (time(NULL) - l->last_up),
        !           831:            (unsigned long long)l->stats.recvOctets,
        !           832:            (unsigned long long)l->stats.xmitOctets));
        !           833:     }
        !           834: 
        !           835:     if (type == AUTH_ACCT_START) {
        !           836:        u_int           updateInterval;
        !           837:   
        !           838:        if (a->params.acct_update > 0)
        !           839:            updateInterval = a->params.acct_update;
        !           840:        else
        !           841:            updateInterval = a->conf.acct_update;
        !           842: 
        !           843:        if (updateInterval > 0) {
        !           844:            /* Save initial statistics. */
        !           845:            memcpy(&a->prev_stats, &l->stats, 
        !           846:                sizeof(a->prev_stats));
        !           847: 
        !           848:            /* Start accounting update timer. */
        !           849:            TimerInit(&a->acct_timer, "AuthAccountTimer",
        !           850:                updateInterval * SECONDS, AuthAccountTimeout, l);
        !           851:            TimerStartRecurring(&a->acct_timer);
        !           852:        }
        !           853:     }
        !           854:   
        !           855:     if (type == AUTH_ACCT_UPDATE) {
        !           856:        /*
        !           857:        * Suppress sending of accounting update, if byte threshold
        !           858:         * is configured, and delta since last update doesn't exceed it.
        !           859:         */
        !           860:        u_int   lim_recv, lim_xmit;
        !           861: 
        !           862:        if (a->params.acct_update_lim_recv > 0)
        !           863:            lim_recv = a->params.acct_update_lim_recv;
        !           864:        else
        !           865:            lim_recv = a->conf.acct_update_lim_recv;
        !           866:        if (a->params.acct_update_lim_xmit > 0)
        !           867:            lim_xmit = a->params.acct_update_lim_xmit;
        !           868:        else
        !           869:            lim_xmit = a->conf.acct_update_lim_xmit;
        !           870:        if (lim_recv > 0 || lim_xmit > 0) {
        !           871:            if ((l->stats.recvOctets - a->prev_stats.recvOctets < lim_recv) &&
        !           872:                    (l->stats.xmitOctets - a->prev_stats.xmitOctets < lim_xmit)) {
        !           873:                Log(LG_AUTH2, ("[%s] ACCT: Shouldn't send Interim-Update", l->name));
        !           874:                return;
        !           875:            } else {
        !           876:                /* Save current statistics. */
        !           877:                memcpy(&a->prev_stats, &l->stats, sizeof(a->prev_stats));
        !           878:            }
        !           879:        }
        !           880:     }
        !           881:     
        !           882:     if (type == AUTH_ACCT_STOP) {
        !           883:        /* Stop accounting update timer if running. */
        !           884:        TimerStop(&a->acct_timer);
        !           885:     }
        !           886: 
        !           887:     if (Enabled(&a->conf.options, AUTH_CONF_RADIUS_ACCT) ||
        !           888: #ifdef USE_PAM
        !           889:        Enabled(&a->conf.options, AUTH_CONF_PAM_ACCT) ||
        !           890: #endif
        !           891: #ifdef USE_SYSTEM
        !           892:        Enabled(&a->conf.options, AUTH_CONF_SYSTEM_ACCT) ||
        !           893: #endif
        !           894:        Enabled(&a->conf.options, AUTH_CONF_EXT_ACCT)) {
        !           895:     
        !           896:        auth = AuthDataNew(l);
        !           897:        auth->acct_type = type;
        !           898: 
        !           899:        if (paction_start(&a->acct_thread, &gGiantMutex, AuthAccount, 
        !           900:                AuthAccountFinish, auth) == -1) {
        !           901:            Log(LG_ERR, ("[%s] ACCT: Couldn't start thread: %d", 
        !           902:                l->name, errno));
        !           903:            AuthDataDestroy(auth);
        !           904:        }
        !           905:     }
        !           906: 
        !           907: }
        !           908: 
        !           909: /*
        !           910:  * AuthAccountTimeout()
        !           911:  *
        !           912:  * Timer function for accounting updates
        !           913:  */
        !           914:  
        !           915: void
        !           916: AuthAccountTimeout(void *arg)
        !           917: {
        !           918:     Link       l = (Link)arg;
        !           919:   
        !           920:     Log(LG_AUTH2, ("[%s] ACCT: Time for Accounting Update",
        !           921:        l->name));
        !           922: 
        !           923:     AuthAccountStart(l, AUTH_ACCT_UPDATE);
        !           924: }
        !           925: 
        !           926: /*
        !           927:  * AuthAccount()
        !           928:  *
        !           929:  * Asynchr. accounting handler, called from a paction.
        !           930:  * NOTE: Thread safety is needed here
        !           931:  */
        !           932:  
        !           933: static void
        !           934: AuthAccount(void *arg)
        !           935: {
        !           936:     AuthData   const auth = (AuthData)arg;
        !           937:     int                err = 0;
        !           938:   
        !           939:     Log(LG_AUTH2, ("[%s] ACCT: Thread started", auth->info.lnkname));
        !           940:   
        !           941:     if (Enabled(&auth->conf.options, AUTH_CONF_RADIUS_ACCT))
        !           942:        err |= RadiusAccount(auth);
        !           943: #ifdef USE_PAM
        !           944:     if (Enabled(&auth->conf.options, AUTH_CONF_PAM_ACCT))
        !           945:        err |= AuthPAMAcct(auth);
        !           946: #endif
        !           947: #ifdef USE_SYSTEM
        !           948:     if (Enabled(&auth->conf.options, AUTH_CONF_SYSTEM_ACCT))
        !           949:        err |= AuthSystemAcct(auth);
        !           950: #endif
        !           951:     if (Enabled(&auth->conf.options, AUTH_CONF_EXT_ACCT))
        !           952:        err |= AuthExternalAcct(auth);
        !           953:        
        !           954:     if (err != 0 && auth->acct_type == AUTH_ACCT_START &&
        !           955:            Enabled(&auth->conf.options, AUTH_CONF_ACCT_MANDATORY)) {
        !           956:        Log(LG_AUTH, ("[%s] ACCT: Close link due to accounting start error", 
        !           957:            auth->info.lnkname));
        !           958:        auth->drop_user = 1;
        !           959:     }
        !           960: }
        !           961: 
        !           962: /*
        !           963:  * AuthAccountFinish
        !           964:  * 
        !           965:  * Return point for the accounting thread()
        !           966:  */
        !           967:  
        !           968: static void
        !           969: AuthAccountFinish(void *arg, int was_canceled)
        !           970: {
        !           971:     AuthData           auth = (AuthData)arg;
        !           972:     Link               l;
        !           973: 
        !           974:     if (was_canceled) {
        !           975:        Log(LG_AUTH2, ("[%s] ACCT: Thread was canceled", 
        !           976:            auth->info.lnkname));
        !           977:     } else {
        !           978:        Log(LG_AUTH2, ("[%s] ACCT: Thread finished normally", 
        !           979:            auth->info.lnkname));
        !           980:     }
        !           981:     
        !           982:     /* Cleanup */
        !           983:     RadiusClose(auth);
        !           984: 
        !           985:     if (was_canceled) {
        !           986:        AuthDataDestroy(auth);
        !           987:        return;
        !           988:     }  
        !           989:     
        !           990:     l = gLinks[auth->info.linkID];
        !           991:     if (l == NULL) {
        !           992:        AuthDataDestroy(auth);
        !           993:        return;
        !           994:     }    
        !           995: 
        !           996:     if (auth->drop_user && auth->acct_type != AUTH_ACCT_STOP) {
        !           997:        Log(LG_AUTH, ("[%s] ACCT: Link close requested by the accounting", 
        !           998:            l->name));
        !           999:        RecordLinkUpDownReason(NULL, l, 0, STR_MANUALLY, NULL);
        !          1000:        LinkClose(l);
        !          1001:     }
        !          1002:     AuthDataDestroy(auth);
        !          1003:     LinkShutdownCheck(l, l->lcp.fsm.state);
        !          1004: }
        !          1005: 
        !          1006: /*
        !          1007:  * AuthGetData()
        !          1008:  *
        !          1009:  * NOTE: Thread safety is needed here
        !          1010:  */
        !          1011: 
        !          1012: int
        !          1013: AuthGetData(char *authname, char *password, size_t passlen, 
        !          1014:     struct u_range *range, u_char *range_valid)
        !          1015: {
        !          1016:   FILE         *fp;
        !          1017:   int          ac;
        !          1018:   char         *av[20];
        !          1019:   char         *line;
        !          1020: 
        !          1021:   /* Check authname, must be non-empty */
        !          1022:   if (authname == NULL || authname[0] == 0) {
        !          1023:     return(-1);
        !          1024:   }
        !          1025: 
        !          1026:   /* Search secrets file */
        !          1027:   if ((fp = OpenConfFile(SECRET_FILE, NULL)) == NULL)
        !          1028:     return(-1);
        !          1029:   while ((line = ReadFullLine(fp, NULL, NULL, 0)) != NULL) {
        !          1030:     memset(av, 0, sizeof(av));
        !          1031:     ac = ParseLine(line, av, sizeof(av) / sizeof(*av), 1);
        !          1032:     Freee(line);
        !          1033:     if (ac >= 2
        !          1034:        && (strcmp(av[0], authname) == 0
        !          1035:         || (av[1][0] == '!' && strcmp(av[0], "*") == 0))) {
        !          1036:       if (av[1][0] == '!') {           /* external auth program */
        !          1037:        if (AuthGetExternalPassword((av[1]+1), 
        !          1038:            authname, password, passlen) == -1) {
        !          1039:          FreeArgs(ac, av);
        !          1040:          fclose(fp);
        !          1041:          return(-1);
        !          1042:        }
        !          1043:       } else {
        !          1044:        strlcpy(password, av[1], passlen);
        !          1045:       }
        !          1046:       if (range != NULL && range_valid != NULL) {
        !          1047:         u_rangeclear(range);
        !          1048:         if (ac >= 3)
        !          1049:            *range_valid = ParseRange(av[2], range, ALLOW_IPV4);
        !          1050:        else
        !          1051:            *range_valid = FALSE;
        !          1052:       }
        !          1053:       FreeArgs(ac, av);
        !          1054:       fclose(fp);
        !          1055:       return(0);
        !          1056:     }
        !          1057:     FreeArgs(ac, av);
        !          1058:   }
        !          1059:   fclose(fp);
        !          1060: 
        !          1061:   return(-1);          /* Invalid */
        !          1062: }
        !          1063: 
        !          1064: /*
        !          1065:  * AuthAsyncStart()
        !          1066:  *
        !          1067:  * Starts the Auth-Thread
        !          1068:  */
        !          1069: 
        !          1070: void 
        !          1071: AuthAsyncStart(Link l, AuthData auth)
        !          1072: {
        !          1073:     Auth       const a = &l->lcp.auth;
        !          1074:     const char *rept;
        !          1075:     
        !          1076:     /* Check link action */
        !          1077:     rept = LinkMatchAction(l, 2, auth->params.authname);
        !          1078:     if (rept) {
        !          1079:        if (strcmp(rept,"##DROP##") == 0) {
        !          1080:            /* Action told we must drop this connection */
        !          1081:            Log(LG_AUTH, ("[%s] Drop connection", l->name));
        !          1082:            PhysClose(l);
        !          1083:            AuthDataDestroy(auth);
        !          1084:            return;
        !          1085:        }
        !          1086:        
        !          1087:        /* Action told we must forward this connection */
        !          1088:        if (RepCreate(l, rept)) {
        !          1089:            Log(LG_ERR, ("[%s] Repeater to \"%s\" creation error", l->name, rept));
        !          1090:            PhysClose(l);
        !          1091:            AuthDataDestroy(auth);
        !          1092:            return;
        !          1093:        }
        !          1094:        /* Create repeater */
        !          1095:        RepIncoming(l);
        !          1096:        /* Reconnect link netgraph hook to repeater */
        !          1097:        LinkNgToRep(l);
        !          1098:        /* Kill the LCP */
        !          1099:        LcpDown(l);
        !          1100:        LcpClose(l);
        !          1101:        AuthDataDestroy(auth);
        !          1102:        return;
        !          1103:     }
        !          1104: 
        !          1105:     /* Check if we are ready to process request. */
        !          1106:     if (a->thread) {
        !          1107:        auth->status = AUTH_STATUS_BUSY;
        !          1108:        auth->finish(l, auth);
        !          1109:        return;
        !          1110:     }
        !          1111:   
        !          1112:     /* perform pre authentication checks (single-login, etc.) */
        !          1113:     if (AuthPreChecks(auth) < 0) {
        !          1114:        Log(LG_AUTH, ("[%s] AUTH: AuthPreCheck failed for \"%s\"", 
        !          1115:            l->name, auth->params.authname));
        !          1116:        auth->finish(l, auth);
        !          1117:        return;
        !          1118:     }
        !          1119: 
        !          1120:     if (paction_start(&a->thread, &gGiantMutex, AuthAsync, 
        !          1121:        AuthAsyncFinish, auth) == -1) {
        !          1122:        Log(LG_ERR, ("[%s] AUTH: Couldn't start thread: %d", 
        !          1123:            l->name, errno));
        !          1124:        auth->status = AUTH_STATUS_FAIL;
        !          1125:        auth->why_fail = AUTH_FAIL_NOT_EXPECTED;
        !          1126:        auth->finish(l, auth);
        !          1127:     }
        !          1128: }
        !          1129: 
        !          1130: /*
        !          1131:  * AuthAsync()
        !          1132:  *
        !          1133:  * Asynchr. auth handler, called from a paction.
        !          1134:  * NOTE: Thread safety is needed here
        !          1135:  */
        !          1136:  
        !          1137: static void
        !          1138: AuthAsync(void *arg)
        !          1139: {
        !          1140:     AuthData   const auth = (AuthData)arg;
        !          1141: 
        !          1142:     Log(LG_AUTH2, ("[%s] AUTH: Thread started", auth->info.lnkname));
        !          1143: 
        !          1144:     if (Enabled(&auth->conf.options, AUTH_CONF_EXT_AUTH)) {
        !          1145:         auth->params.authentic = AUTH_CONF_EXT_AUTH;
        !          1146:        Log(LG_AUTH, ("[%s] AUTH: Trying EXTERNAL", auth->info.lnkname));
        !          1147:        if (AuthExternal(auth)) {
        !          1148:            Log(LG_AUTH, ("[%s] AUTH: EXTERNAL returned error",
        !          1149:                auth->info.lnkname));
        !          1150:        } else {
        !          1151:            Log(LG_AUTH, ("[%s] AUTH: EXTERNAL returned: %s",
        !          1152:                auth->info.lnkname, AuthStatusText(auth->status)));
        !          1153:            if (auth->status == AUTH_STATUS_SUCCESS 
        !          1154:                    || auth->status == AUTH_STATUS_UNDEF)
        !          1155:                return;
        !          1156:        }
        !          1157:     }
        !          1158: 
        !          1159:     if (auth->proto == PROTO_EAP && auth->eap_radius) {
        !          1160:        auth->params.authentic = AUTH_CONF_RADIUS_AUTH;
        !          1161:        RadiusEapProxy(auth);
        !          1162:        return;
        !          1163:     } else if (Enabled(&auth->conf.options, AUTH_CONF_RADIUS_AUTH)) {
        !          1164:        auth->params.authentic = AUTH_CONF_RADIUS_AUTH;
        !          1165:        Log(LG_AUTH, ("[%s] AUTH: Trying RADIUS", auth->info.lnkname));
        !          1166:        if (RadiusAuthenticate(auth)) {
        !          1167:            Log(LG_AUTH, ("[%s] AUTH: RADIUS returned error",
        !          1168:                auth->info.lnkname));
        !          1169:        } else {
        !          1170:            Log(LG_AUTH, ("[%s] AUTH: RADIUS returned: %s", 
        !          1171:                auth->info.lnkname, AuthStatusText(auth->status)));
        !          1172:            if (auth->status == AUTH_STATUS_SUCCESS)
        !          1173:                return;
        !          1174:        }
        !          1175:     }
        !          1176:   
        !          1177: #ifdef USE_PAM
        !          1178:   if (Enabled(&auth->conf.options, AUTH_CONF_PAM_AUTH)) {
        !          1179:     auth->params.authentic = AUTH_CONF_PAM_AUTH;
        !          1180:     Log(LG_AUTH, ("[%s] AUTH: Trying PAM", auth->info.lnkname));
        !          1181:     AuthPAM(auth);
        !          1182:     Log(LG_AUTH, ("[%s] AUTH: PAM returned: %s", 
        !          1183:       auth->info.lnkname, AuthStatusText(auth->status)));
        !          1184:     if (auth->status == AUTH_STATUS_SUCCESS 
        !          1185:       || auth->status == AUTH_STATUS_UNDEF)
        !          1186:         return;
        !          1187:   }
        !          1188: #endif
        !          1189: 
        !          1190: #ifdef USE_SYSTEM
        !          1191:   if (Enabled(&auth->conf.options, AUTH_CONF_SYSTEM_AUTH)) {
        !          1192:     auth->params.authentic = AUTH_CONF_SYSTEM_AUTH;
        !          1193:     Log(LG_AUTH, ("[%s] AUTH: Trying SYSTEM", auth->info.lnkname));
        !          1194:     AuthSystem(auth);
        !          1195:     Log(LG_AUTH, ("[%s] AUTH: SYSTEM returned: %s", 
        !          1196:       auth->info.lnkname, AuthStatusText(auth->status)));
        !          1197:     if (auth->status == AUTH_STATUS_SUCCESS 
        !          1198:       || auth->status == AUTH_STATUS_UNDEF)
        !          1199:         return;
        !          1200:   }
        !          1201: #endif
        !          1202:   
        !          1203: #ifdef USE_OPIE
        !          1204:   if (Enabled(&auth->conf.options, AUTH_CONF_OPIE)) {
        !          1205:     auth->params.authentic = AUTH_CONF_OPIE;
        !          1206:     Log(LG_AUTH, ("[%s] AUTH: Trying OPIE", auth->info.lnkname));
        !          1207:     AuthOpie(auth);
        !          1208:     Log(LG_AUTH, ("[%s] AUTH: OPIE returned: %s", 
        !          1209:       auth->info.lnkname, AuthStatusText(auth->status)));
        !          1210:     if (auth->status == AUTH_STATUS_SUCCESS 
        !          1211:       || auth->status == AUTH_STATUS_UNDEF)
        !          1212:         return;
        !          1213:   }    
        !          1214: #endif /* USE_OPIE */
        !          1215:   
        !          1216:   if (Enabled(&auth->conf.options, AUTH_CONF_INTERNAL)) {
        !          1217:     auth->params.authentic = AUTH_CONF_INTERNAL;
        !          1218:     Log(LG_AUTH, ("[%s] AUTH: Trying INTERNAL", auth->info.lnkname));
        !          1219:     AuthInternal(auth);
        !          1220:     Log(LG_AUTH, ("[%s] AUTH: INTERNAL returned: %s", 
        !          1221:       auth->info.lnkname, AuthStatusText(auth->status)));
        !          1222:     if (auth->status == AUTH_STATUS_SUCCESS 
        !          1223:       || auth->status == AUTH_STATUS_UNDEF)
        !          1224:          return;
        !          1225:   } 
        !          1226: 
        !          1227:   Log(LG_AUTH, ("[%s] AUTH: ran out of backends", auth->info.lnkname));
        !          1228:   auth->status = AUTH_STATUS_FAIL;
        !          1229:   auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
        !          1230: }
        !          1231: 
        !          1232: /*
        !          1233:  * AuthAsyncFinish()
        !          1234:  * 
        !          1235:  * Return point for the auth thread
        !          1236:  */
        !          1237:  
        !          1238: static void
        !          1239: AuthAsyncFinish(void *arg, int was_canceled)
        !          1240: {
        !          1241:     AuthData   auth = (AuthData)arg;
        !          1242:     Link       l;
        !          1243: 
        !          1244:     if (was_canceled)
        !          1245:        Log(LG_AUTH2, ("[%s] AUTH: Thread was canceled", auth->info.lnkname));
        !          1246: 
        !          1247:     /* cleanup */
        !          1248:     RadiusClose(auth);
        !          1249:   
        !          1250:     if (was_canceled) {
        !          1251:        AuthDataDestroy(auth);
        !          1252:        return;
        !          1253:     }  
        !          1254:   
        !          1255:     l = gLinks[auth->info.linkID];
        !          1256:     if (l == NULL) {
        !          1257:        AuthDataDestroy(auth);
        !          1258:        return;
        !          1259:     }    
        !          1260: 
        !          1261:     Log(LG_AUTH2, ("[%s] AUTH: Thread finished normally", l->name));
        !          1262: 
        !          1263:     /* Replace modified data */
        !          1264:     authparamsDestroy(&l->lcp.auth.params);
        !          1265:     authparamsMove(&auth->params,&l->lcp.auth.params);
        !          1266: 
        !          1267:     if (strcmp(l->lcp.auth.params.action, "drop") == 0) {
        !          1268:        auth->status = AUTH_STATUS_FAIL;
        !          1269:        auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
        !          1270:     } else if (strncmp(l->lcp.auth.params.action, "forward ", 8) == 0) {
        !          1271:        const char  *rept = l->lcp.auth.params.action + 8;
        !          1272: 
        !          1273:        /* Action told we must forward this connection */
        !          1274:        if (RepCreate(l, rept)) {
        !          1275:            Log(LG_ERR, ("[%s] Repeater to \"%s\" creation error", l->name, rept));
        !          1276:            PhysClose(l);
        !          1277:            AuthDataDestroy(auth);
        !          1278:            return;
        !          1279:        }
        !          1280:        /* Create repeater */
        !          1281:        RepIncoming(l);
        !          1282:        /* Reconnect link netgraph hook to repeater */
        !          1283:        LinkNgToRep(l);
        !          1284:        /* Kill the LCP */
        !          1285:        LcpDown(l);
        !          1286:        LcpClose(l);
        !          1287:        AuthDataDestroy(auth);
        !          1288:        return;
        !          1289:     }
        !          1290: 
        !          1291:     auth->finish(l, auth);
        !          1292: }
        !          1293: 
        !          1294: /*
        !          1295:  * AuthInternal()
        !          1296:  * 
        !          1297:  * Authenticate against mpd.secret
        !          1298:  */
        !          1299:  
        !          1300: static void
        !          1301: AuthInternal(AuthData auth)
        !          1302: {
        !          1303:     if (AuthGetData(auth->params.authname, auth->params.password, 
        !          1304:            sizeof(auth->params.password), &auth->params.range, 
        !          1305:            &auth->params.range_valid) < 0) {
        !          1306:        Log(LG_AUTH, ("[%s] AUTH: User \"%s\" not found in secret file", 
        !          1307:            auth->info.lnkname, auth->params.authname));
        !          1308:        auth->status = AUTH_STATUS_FAIL;
        !          1309:        auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
        !          1310:        return;
        !          1311:     }
        !          1312:     auth->status = AUTH_STATUS_UNDEF;
        !          1313: }
        !          1314: 
        !          1315: #ifdef USE_SYSTEM
        !          1316: /*
        !          1317:  * AuthSystem()
        !          1318:  * 
        !          1319:  * Authenticate against Systems password database
        !          1320:  */
        !          1321:  
        !          1322: static void
        !          1323: AuthSystem(AuthData auth)
        !          1324: {
        !          1325:   PapParams    pp = &auth->params.pap;
        !          1326:   struct passwd        *pw;
        !          1327:   struct passwd pwc;
        !          1328:   u_char       *bin;
        !          1329:   int          err;
        !          1330:   
        !          1331:   /* protect getpwnam and errno 
        !          1332:    * NOTE: getpwnam_r doesen't exists on FreeBSD < 5.1 */
        !          1333:   GIANT_MUTEX_LOCK();
        !          1334:   errno = 0;
        !          1335:   pw = getpwnam(auth->params.authname);
        !          1336:   if (!pw) {
        !          1337:     err=errno;
        !          1338:     GIANT_MUTEX_UNLOCK(); /* We must release lock before Log() */
        !          1339:     if (err)
        !          1340:       Perror("[%s] AUTH: Error retrieving passwd", auth->info.lnkname);
        !          1341:     else
        !          1342:       Log(LG_AUTH, ("[%s] AUTH: User \"%s\" not found in the systems database",
        !          1343:         auth->info.lnkname, auth->params.authname));
        !          1344:     auth->status = AUTH_STATUS_FAIL;
        !          1345:     auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
        !          1346:     return;
        !          1347:   }
        !          1348:   memcpy(&pwc,pw,sizeof(struct passwd)); /* we must make copy before release lock */
        !          1349:   GIANT_MUTEX_UNLOCK();
        !          1350:   
        !          1351:   Log(LG_AUTH, ("[%s] AUTH: Found user %s Uid:%d Gid:%d Fmt:%*.*s",
        !          1352:     auth->info.lnkname, pwc.pw_name, pwc.pw_uid, pwc.pw_gid, 3, 3, pwc.pw_passwd));
        !          1353: 
        !          1354:   if (auth->proto == PROTO_PAP) {
        !          1355:     /* protect non-ts crypt() */
        !          1356:     GIANT_MUTEX_LOCK();
        !          1357:     if (strcmp(crypt(pp->peer_pass, pwc.pw_passwd), pwc.pw_passwd) == 0) {
        !          1358:       auth->status = AUTH_STATUS_SUCCESS;
        !          1359:     } else {
        !          1360:       auth->status = AUTH_STATUS_FAIL;
        !          1361:       auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
        !          1362:     }
        !          1363:     GIANT_MUTEX_UNLOCK();
        !          1364:     return;
        !          1365:   } else if (auth->proto == PROTO_CHAP 
        !          1366:       && (auth->alg == CHAP_ALG_MSOFT 
        !          1367:         || auth->alg == CHAP_ALG_MSOFTv2)) {
        !          1368: 
        !          1369:     if (!strstr(pwc.pw_passwd, "$3$$")) {
        !          1370:       Log(LG_AUTH, ("[%s] AUTH: Password has the wrong format, nth ($3$) is needed",
        !          1371:            auth->info.lnkname));
        !          1372:       auth->status = AUTH_STATUS_FAIL;
        !          1373:       auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
        !          1374:       return;
        !          1375:     }
        !          1376: 
        !          1377:     bin = Hex2Bin(&pwc.pw_passwd[4]);
        !          1378:     memcpy(auth->params.msoft.nt_hash, bin, sizeof(auth->params.msoft.nt_hash));
        !          1379:     Freee(bin);
        !          1380:     NTPasswordHashHash(auth->params.msoft.nt_hash, auth->params.msoft.nt_hash_hash);
        !          1381:     auth->params.msoft.has_nt_hash = TRUE;
        !          1382:     auth->status = AUTH_STATUS_UNDEF;
        !          1383:     return;
        !          1384: 
        !          1385:   } else {
        !          1386:     Log(LG_ERR, ("[%s] AUTH: Using systems password database only possible for PAP and MS-CHAP",
        !          1387:        auth->info.lnkname));
        !          1388:     auth->status = AUTH_STATUS_FAIL;
        !          1389:     auth->why_fail = AUTH_FAIL_NOT_EXPECTED;
        !          1390:     return;
        !          1391:   }
        !          1392: 
        !          1393: }
        !          1394: 
        !          1395: /*
        !          1396:  * AuthSystemAcct()
        !          1397:  * 
        !          1398:  * Account with system
        !          1399:  */
        !          1400: 
        !          1401: #if __FreeBSD_version >= 900007
        !          1402: static int
        !          1403: AuthSystemAcct(AuthData auth)
        !          1404: {
        !          1405:        struct utmpx    ut;
        !          1406: 
        !          1407:        memset(&ut, 0, sizeof(ut));
        !          1408:        snprintf(ut.ut_id, sizeof(ut.ut_id), "mpd%x", auth->info.linkID);
        !          1409:        strlcpy(ut.ut_line, auth->info.lnkname, sizeof(ut.ut_line));
        !          1410: 
        !          1411:        if (auth->acct_type == AUTH_ACCT_START) {
        !          1412:                ut.ut_type = USER_PROCESS;
        !          1413:                strlcpy(ut.ut_host, auth->params.peeraddr, sizeof(ut.ut_host));
        !          1414:                strlcpy(ut.ut_user, auth->params.authname, sizeof(ut.ut_user));
        !          1415:                gettimeofday(&ut.ut_tv, NULL);
        !          1416:                Log(LG_AUTH, ("[%s] ACCT: wtmp %s %s %s login", auth->info.lnkname, ut.ut_line,
        !          1417:                        ut.ut_user, ut.ut_host));
        !          1418:                pututxline(&ut);
        !          1419:        } else if (auth->acct_type == AUTH_ACCT_STOP) {
        !          1420:                ut.ut_type = DEAD_PROCESS;
        !          1421:                Log(LG_AUTH, ("[%s] ACCT: wtmp %s logout", auth->info.lnkname, ut.ut_line));
        !          1422:                pututxline(&ut);
        !          1423:        }
        !          1424:        return (0);
        !          1425: }
        !          1426: #else
        !          1427: static int
        !          1428: AuthSystemAcct(AuthData auth)
        !          1429: {
        !          1430:        struct utmp     ut;
        !          1431: 
        !          1432:        memset(&ut, 0, sizeof(ut));
        !          1433:        strlcpy(ut.ut_line, auth->info.lnkname, sizeof(ut.ut_line));
        !          1434: 
        !          1435:        if (auth->acct_type == AUTH_ACCT_START) {
        !          1436:            time_t      t;
        !          1437: 
        !          1438:            strlcpy(ut.ut_host, auth->params.peeraddr, sizeof(ut.ut_host));
        !          1439:            strlcpy(ut.ut_name, auth->params.authname, sizeof(ut.ut_name));
        !          1440:            time(&t);
        !          1441:            ut.ut_time = t;
        !          1442:            login(&ut);
        !          1443:            Log(LG_AUTH, ("[%s] ACCT: wtmp %s %s %s login", auth->info.lnkname, ut.ut_line, 
        !          1444:                ut.ut_name, ut.ut_host));
        !          1445:        } else if (auth->acct_type == AUTH_ACCT_STOP) {
        !          1446:            Log(LG_AUTH, ("[%s] ACCT: wtmp %s logout", auth->info.lnkname, ut.ut_line));
        !          1447:            logout(ut.ut_line);
        !          1448:            logwtmp(ut.ut_line, "", "");
        !          1449:        }
        !          1450:        return (0);
        !          1451: }
        !          1452: #endif /* __FreeBSD_version >= 900007 */
        !          1453: #endif /* USE_SYSTEM */
        !          1454: 
        !          1455: #ifdef USE_PAM
        !          1456: /*
        !          1457:  * AuthPAM()
        !          1458:  * 
        !          1459:  * Authenticate with PAM system
        !          1460:  */
        !          1461: 
        !          1462: static int
        !          1463: pam_conv(int n, const struct pam_message **msg, struct pam_response **resp,
        !          1464:   void *data)
        !          1465: {
        !          1466:     AuthData   auth = (AuthData)data;
        !          1467:     int                i;
        !          1468: 
        !          1469:     for (i = 0; i < n; i++) {
        !          1470:        Log(LG_AUTH2, ("[%s] AUTH: PAM: %s",
        !          1471:            auth->info.lnkname, msg[i]->msg));
        !          1472:     }
        !          1473: 
        !          1474:     /* We support only requests for password */
        !          1475:     if (n != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF)
        !          1476:        return (PAM_CONV_ERR);
        !          1477: 
        !          1478:     if ((*resp = malloc(sizeof(struct pam_response))) == NULL)
        !          1479:        return (PAM_CONV_ERR);
        !          1480:     (*resp)[0].resp = strdup(auth->params.pap.peer_pass);
        !          1481:     (*resp)[0].resp_retcode = 0;
        !          1482: 
        !          1483:     return ((*resp)[0].resp != NULL ? PAM_SUCCESS : PAM_CONV_ERR);
        !          1484: }
        !          1485:  
        !          1486: static void
        !          1487: AuthPAM(AuthData auth)
        !          1488: {
        !          1489:     struct pam_conv pamc = {
        !          1490:         &pam_conv,
        !          1491:        auth
        !          1492:     };
        !          1493:     pam_handle_t *pamh;
        !          1494:     int status;
        !          1495: 
        !          1496:     if (auth->proto != PROTO_PAP) {
        !          1497:        Log(LG_ERR, ("[%s] AUTH: Using PAM only possible for PAP", auth->info.lnkname));
        !          1498:        auth->status = AUTH_STATUS_FAIL;
        !          1499:        auth->why_fail = AUTH_FAIL_NOT_EXPECTED;
        !          1500:        return;
        !          1501:     }
        !          1502:     
        !          1503:     if (pam_start("mpd", auth->params.authname, &pamc, &pamh) != PAM_SUCCESS) {
        !          1504:        Log(LG_ERR, ("[%s] AUTH: PAM error", auth->info.lnkname));
        !          1505:        auth->status = AUTH_STATUS_FAIL;
        !          1506:        auth->why_fail = AUTH_FAIL_NOT_EXPECTED;
        !          1507:        return;
        !          1508:     }
        !          1509: 
        !          1510:     if (auth->params.peeraddr[0] &&
        !          1511:        pam_set_item(pamh, PAM_RHOST, auth->params.peeraddr) != PAM_SUCCESS) {
        !          1512:        Log(LG_ERR, ("[%s] AUTH: PAM set PAM_RHOST error", auth->info.lnkname));
        !          1513:     }
        !          1514: 
        !          1515:     if (pam_set_item(pamh, PAM_TTY, auth->info.lnkname) != PAM_SUCCESS) {
        !          1516:        Log(LG_ERR, ("[%s] AUTH: PAM set PAM_TTY error", auth->info.lnkname));
        !          1517:     }
        !          1518: 
        !          1519:     status = pam_authenticate(pamh, 0);
        !          1520: 
        !          1521:     if (status == PAM_SUCCESS) {
        !          1522:        status = pam_acct_mgmt(pamh, 0);
        !          1523:     }
        !          1524: 
        !          1525:     if (status == PAM_SUCCESS) {
        !          1526:        auth->status = AUTH_STATUS_SUCCESS;
        !          1527:     } else {
        !          1528:        Log(LG_AUTH, ("[%s] AUTH: PAM error: %s",
        !          1529:            auth->info.lnkname, pam_strerror(pamh, status)));
        !          1530:        switch (status) {
        !          1531:        case PAM_AUTH_ERR:
        !          1532:        case PAM_USER_UNKNOWN:
        !          1533:            auth->status = AUTH_STATUS_FAIL;
        !          1534:            auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
        !          1535:            break;
        !          1536:        case PAM_ACCT_EXPIRED:
        !          1537:        case PAM_AUTHTOK_EXPIRED:
        !          1538:        case PAM_CRED_EXPIRED:
        !          1539:            auth->status = AUTH_STATUS_FAIL;
        !          1540:            auth->why_fail = AUTH_FAIL_ACCT_DISABLED;
        !          1541:            break;
        !          1542:        default:
        !          1543:            auth->status = AUTH_STATUS_FAIL;
        !          1544:            auth->why_fail = AUTH_FAIL_NOT_EXPECTED;
        !          1545:        }
        !          1546:     }
        !          1547: 
        !          1548:     pam_end(pamh, status);
        !          1549: }
        !          1550: 
        !          1551: /*
        !          1552:  * AuthPAMAcct()
        !          1553:  * 
        !          1554:  * Account with system
        !          1555:  */
        !          1556: 
        !          1557: static int
        !          1558: AuthPAMAcct(AuthData auth)
        !          1559: {
        !          1560:     pam_handle_t *pamh;
        !          1561:     int status;
        !          1562:     struct pam_conv pamc = {
        !          1563:         &pam_conv,
        !          1564:        auth
        !          1565:     };
        !          1566:     
        !          1567:     if (auth->acct_type != AUTH_ACCT_START &&
        !          1568:       auth->acct_type != AUTH_ACCT_STOP) {
        !          1569:         return (0);
        !          1570:     }
        !          1571: 
        !          1572:     if (pam_start("mpd", auth->params.authname, &pamc, &pamh) != PAM_SUCCESS) {
        !          1573:        Log(LG_ERR, ("[%s] ACCT: PAM error", auth->info.lnkname));
        !          1574:        return (-1);
        !          1575:     }
        !          1576: 
        !          1577:     if (auth->params.peeraddr[0] &&
        !          1578:        pam_set_item(pamh, PAM_RHOST, auth->params.peeraddr) != PAM_SUCCESS) {
        !          1579:        Log(LG_ERR, ("[%s] ACCT: PAM set PAM_RHOST error", auth->info.lnkname));
        !          1580:        return (-1);
        !          1581:     }
        !          1582: 
        !          1583:     if (pam_set_item(pamh, PAM_TTY, auth->info.lnkname) != PAM_SUCCESS) {
        !          1584:        Log(LG_ERR, ("[%s] ACCT: PAM set PAM_TTY error", auth->info.lnkname));
        !          1585:        return (-1);
        !          1586:     }
        !          1587: 
        !          1588:     if (auth->acct_type == AUTH_ACCT_START) {
        !          1589:            Log(LG_AUTH, ("[%s] ACCT: PAM open session \"%s\"",
        !          1590:                auth->info.lnkname, auth->params.authname));
        !          1591:            status = pam_open_session(pamh, 0);
        !          1592:     } else {
        !          1593:            Log(LG_AUTH, ("[%s] ACCT: PAM close session \"%s\"",
        !          1594:                auth->info.lnkname, auth->params.authname));
        !          1595:            status = pam_close_session(pamh, 0);
        !          1596:     }
        !          1597:     if (status != PAM_SUCCESS) {
        !          1598:        Log(LG_AUTH, ("[%s] ACCT: PAM session error",
        !          1599:            auth->info.lnkname));
        !          1600:        return (-1);
        !          1601:     }
        !          1602:     
        !          1603:     pam_end(pamh, status);
        !          1604:     return (0);
        !          1605: }
        !          1606: #endif /* USE_PAM */
        !          1607: 
        !          1608: #ifdef USE_OPIE
        !          1609: /*
        !          1610:  * AuthOpie()
        !          1611:  */
        !          1612: 
        !          1613: static void
        !          1614: AuthOpie(AuthData auth)
        !          1615: {
        !          1616:   PapParams    const pp = &auth->params.pap;
        !          1617:   struct       opie_otpkey key;
        !          1618:   char         opieprompt[OPIE_CHALLENGE_MAX + 1];
        !          1619:   int          ret, n;
        !          1620:   char         secret[OPIE_SECRET_MAX + 1];
        !          1621:   char         english[OPIE_RESPONSE_MAX + 1];
        !          1622: 
        !          1623:   ret = opiechallenge(&auth->opie.data, auth->params.authname, opieprompt);
        !          1624: 
        !          1625:   auth->status = AUTH_STATUS_UNDEF;
        !          1626:   
        !          1627:   switch (ret) {
        !          1628:     case 0:
        !          1629:       break;
        !          1630:   
        !          1631:     case 1:
        !          1632:       Log(LG_ERR, ("[%s] AUTH: User \"%s\" not found in opiekeys",
        !          1633:         auth->info.lnkname, auth->params.authname));
        !          1634:       auth->status = AUTH_STATUS_FAIL;
        !          1635:       auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
        !          1636:       return;
        !          1637: 
        !          1638:     case -1:
        !          1639:     case 2:
        !          1640:     default:
        !          1641:       Log(LG_ERR, ("[%s] AUTH: System error", auth->info.lnkname));
        !          1642:       auth->status = AUTH_STATUS_FAIL;
        !          1643:       auth->why_fail = AUTH_FAIL_NOT_EXPECTED;
        !          1644:       return;
        !          1645:   };
        !          1646: 
        !          1647:   Log(LG_AUTH, ("[%s] AUTH: Opieprompt:%s", auth->info.lnkname, opieprompt));
        !          1648: 
        !          1649:   if (auth->proto == PROTO_PAP ) {
        !          1650:     if (!opieverify(&auth->opie.data, pp->peer_pass)) {
        !          1651:       auth->status = AUTH_STATUS_SUCCESS;
        !          1652:     } else {
        !          1653:       auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
        !          1654:       auth->status = AUTH_STATUS_FAIL;
        !          1655:     }
        !          1656:     return;
        !          1657:   }
        !          1658: 
        !          1659:   if (AuthGetData(auth->params.authname, secret, sizeof(secret), NULL, NULL) < 0) {
        !          1660:     Log(LG_AUTH, ("[%s] AUTH: Can't get credentials for \"%s\"",
        !          1661:        auth->info.lnkname, auth->params.authname));
        !          1662:     auth->status = AUTH_STATUS_FAIL;
        !          1663:     auth->why_fail = AUTH_FAIL_INVALID_LOGIN;    
        !          1664:     return;
        !          1665:   }
        !          1666:   
        !          1667:   opiekeycrunch(OPIE_ALG_MD5, &key, auth->opie.data.opie_seed, secret);
        !          1668:   n = auth->opie.data.opie_n - 1;
        !          1669:   while (n-- > 0)
        !          1670:     opiehash(&key, OPIE_ALG_MD5);
        !          1671: 
        !          1672:   opiebtoe(english, &key);
        !          1673:   strlcpy(auth->params.password, english, sizeof(auth->params.password));
        !          1674: }
        !          1675: #endif /* USE_OPIE */
        !          1676: 
        !          1677: /*
        !          1678:  * AuthPreChecks()
        !          1679:  */
        !          1680: 
        !          1681: static int
        !          1682: AuthPreChecks(AuthData auth)
        !          1683: {
        !          1684: 
        !          1685:   if (!strlen(auth->params.authname)) {
        !          1686:     Log(LG_AUTH, ("[%s] AUTH: We don't accept empty usernames", auth->info.lnkname));
        !          1687:     auth->status = AUTH_STATUS_FAIL;
        !          1688:     auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
        !          1689:     return (-1);
        !          1690:   }
        !          1691:   /* check max. number of logins */
        !          1692:   if (gMaxLogins != 0) {
        !          1693:     int                ac;
        !          1694:     u_long     num = 0;
        !          1695:     for(ac = 0; ac < gNumBundles; ac++) {
        !          1696:       if (gBundles[ac] && gBundles[ac]->open) {
        !          1697:         if (gMaxLoginsCI) {
        !          1698:            if (!strcasecmp(gBundles[ac]->params.authname, auth->params.authname))
        !          1699:                num++;
        !          1700:        } else {
        !          1701:            if (!strcmp(gBundles[ac]->params.authname, auth->params.authname))
        !          1702:                num++;
        !          1703:        }
        !          1704:       }
        !          1705:     }
        !          1706: 
        !          1707:     if (num >= gMaxLogins) {
        !          1708:        Log(LG_AUTH, ("[%s] AUTH: Name: \"%s\" max. number of logins exceeded",
        !          1709:            auth->info.lnkname, auth->params.authname));
        !          1710:         auth->status = AUTH_STATUS_FAIL;
        !          1711:         auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
        !          1712:         return (-1);
        !          1713:     }
        !          1714:   }
        !          1715:   return (0);
        !          1716: }
        !          1717: 
        !          1718: /*
        !          1719:  * AuthTimeout()
        !          1720:  *
        !          1721:  * Timer expired for the whole authorization process
        !          1722:  */
        !          1723: 
        !          1724: static void
        !          1725: AuthTimeout(void *arg)
        !          1726: {
        !          1727:     Link l = (Link)arg;
        !          1728: 
        !          1729:   Log(LG_AUTH, ("[%s] %s: authorization timer expired", Pref(&l->lcp.fsm), Fsm(&l->lcp.fsm)));
        !          1730:   AuthStop(l);
        !          1731:   LcpAuthResult(l, FALSE);
        !          1732: }
        !          1733: 
        !          1734: /* 
        !          1735:  * AuthFailMsg()
        !          1736:  */
        !          1737: 
        !          1738: const char *
        !          1739: AuthFailMsg(AuthData auth, char *buf, size_t len)
        !          1740: {
        !          1741:     const char *mesg;
        !          1742: 
        !          1743:     if (auth->proto == PROTO_CHAP
        !          1744:         && (auth->alg == CHAP_ALG_MSOFT || auth->alg == CHAP_ALG_MSOFTv2)) {
        !          1745:            int mscode;
        !          1746: 
        !          1747:            if (auth->mschap_error != NULL) {
        !          1748:                    strlcpy(buf, auth->mschap_error, len);
        !          1749:                    return(buf);
        !          1750:            }
        !          1751: 
        !          1752:            switch (auth->why_fail) {
        !          1753:              case AUTH_FAIL_ACCT_DISABLED:
        !          1754:                mscode = MSCHAP_ERROR_ACCT_DISABLED;
        !          1755:                mesg = AUTH_MSG_ACCT_DISAB;
        !          1756:                break;
        !          1757:              case AUTH_FAIL_NO_PERMISSION:
        !          1758:                mscode = MSCHAP_ERROR_NO_DIALIN_PERMISSION;
        !          1759:                mesg = AUTH_MSG_NOT_ALLOWED;
        !          1760:                break;
        !          1761:              case AUTH_FAIL_RESTRICTED_HOURS:
        !          1762:                mscode = MSCHAP_ERROR_RESTRICTED_LOGON_HOURS;
        !          1763:                mesg = AUTH_MSG_RESTR_HOURS;
        !          1764:                break;
        !          1765:              case AUTH_FAIL_INVALID_PACKET:
        !          1766:              case AUTH_FAIL_INVALID_LOGIN:
        !          1767:              case AUTH_FAIL_NOT_EXPECTED:
        !          1768:              default:
        !          1769:                mscode = MSCHAP_ERROR_AUTHENTICATION_FAILURE;
        !          1770:                mesg = AUTH_MSG_INVALID;
        !          1771:                break;
        !          1772:            }
        !          1773: 
        !          1774:            /* If we have reply message, send it instead of default. */
        !          1775:            if (auth->reply_message != NULL)
        !          1776:                mesg = auth->reply_message;
        !          1777: 
        !          1778:            snprintf(buf, len, "E=%d R=0 M=%s", mscode, mesg);
        !          1779:     
        !          1780:     } else {
        !          1781: 
        !          1782:            if (auth->reply_message != NULL) {
        !          1783:                    strlcpy(buf, auth->reply_message, len);
        !          1784:                    return(buf);
        !          1785:            }
        !          1786: 
        !          1787:            switch (auth->why_fail) {
        !          1788:              case AUTH_FAIL_ACCT_DISABLED:
        !          1789:                mesg = AUTH_MSG_ACCT_DISAB;
        !          1790:                break;
        !          1791:              case AUTH_FAIL_NO_PERMISSION:
        !          1792:                mesg = AUTH_MSG_NOT_ALLOWED;
        !          1793:                break;
        !          1794:              case AUTH_FAIL_RESTRICTED_HOURS:
        !          1795:                mesg = AUTH_MSG_RESTR_HOURS;
        !          1796:                break;
        !          1797:              case AUTH_FAIL_NOT_EXPECTED:
        !          1798:                mesg = AUTH_MSG_NOT_EXPECTED;
        !          1799:                break;
        !          1800:              case AUTH_FAIL_INVALID_PACKET:
        !          1801:                mesg = AUTH_MSG_BAD_PACKET;
        !          1802:                break;
        !          1803:              case AUTH_FAIL_INVALID_LOGIN:
        !          1804:              default:
        !          1805:                mesg = AUTH_MSG_INVALID;
        !          1806:                break;
        !          1807:            }
        !          1808:            strlcpy(buf, mesg, len);
        !          1809:     }
        !          1810:     return(buf);
        !          1811: }
        !          1812: 
        !          1813: /* 
        !          1814:  * AuthStatusText()
        !          1815:  */
        !          1816: 
        !          1817: const char *
        !          1818: AuthStatusText(int status)
        !          1819: {  
        !          1820:   switch (status) {
        !          1821:     case AUTH_STATUS_UNDEF:
        !          1822:       return "undefined";
        !          1823: 
        !          1824:     case AUTH_STATUS_SUCCESS:
        !          1825:       return "authenticated";
        !          1826: 
        !          1827:     case AUTH_STATUS_FAIL:
        !          1828:       return "failed";
        !          1829: 
        !          1830:     case AUTH_STATUS_BUSY:
        !          1831:       return "busy";
        !          1832: 
        !          1833:     default:
        !          1834:       return "INCORRECT STATUS";
        !          1835:   }
        !          1836: }
        !          1837: 
        !          1838: /* 
        !          1839:  * AuthMPPEPolicyname()
        !          1840:  */
        !          1841: 
        !          1842: const char *
        !          1843: AuthMPPEPolicyname(int policy) 
        !          1844: {
        !          1845:   switch(policy) {
        !          1846:     case MPPE_POLICY_ALLOWED:
        !          1847:       return "Allowed";
        !          1848:     case MPPE_POLICY_REQUIRED:
        !          1849:       return "Required";
        !          1850:     case MPPE_POLICY_NONE:
        !          1851:       return "Not available";
        !          1852:     default:
        !          1853:       return "Unknown Policy";
        !          1854:   }
        !          1855: 
        !          1856: }
        !          1857: 
        !          1858: /* 
        !          1859:  * AuthMPPETypesname()
        !          1860:  */
        !          1861: 
        !          1862: const char *
        !          1863: AuthMPPETypesname(int types, char *buf, size_t len) 
        !          1864: {
        !          1865:   if (types == 0) {
        !          1866:     sprintf(buf, "no encryption required");
        !          1867:     return (buf);
        !          1868:   }
        !          1869: 
        !          1870:   buf[0]=0;
        !          1871:   if (types & MPPE_TYPE_40BIT) sprintf (buf, "40 ");
        !          1872:   if (types & MPPE_TYPE_56BIT) sprintf (&buf[strlen(buf)], "56 ");
        !          1873:   if (types & MPPE_TYPE_128BIT) sprintf (&buf[strlen(buf)], "128 ");
        !          1874: 
        !          1875:   if (strlen(buf) == 0) {
        !          1876:     sprintf (buf, "unknown types");
        !          1877:   } else {
        !          1878:     sprintf (&buf[strlen(buf)], "bit");
        !          1879:   }
        !          1880: 
        !          1881:   return (buf);
        !          1882: }
        !          1883: 
        !          1884: /*
        !          1885:  * AuthGetExternalPassword()
        !          1886:  *
        !          1887:  * Run the named external program to fill in the password for the user
        !          1888:  * mentioned in the AuthData
        !          1889:  * -1 on error (can't fork, no data read, whatever)
        !          1890:  */
        !          1891: static int
        !          1892: AuthGetExternalPassword(char * extcmd, char *authname, char *password, size_t passlen)
        !          1893: {
        !          1894:   char cmd[AUTH_MAX_PASSWORD + 5 + AUTH_MAX_AUTHNAME];
        !          1895:   int ok = 0;
        !          1896:   FILE *fp;
        !          1897:   int len;
        !          1898: 
        !          1899:   snprintf(cmd, sizeof(cmd), "%s %s", extcmd, authname);
        !          1900:   Log(LG_AUTH, ("Invoking external auth program: '%s'", cmd));
        !          1901:   if ((fp = popen(cmd, "r")) == NULL) {
        !          1902:     Perror("Popen");
        !          1903:     return (-1);
        !          1904:   }
        !          1905:   if (fgets(password, passlen, fp) != NULL) {
        !          1906:     len = strlen(password);    /* trim trailing newline */
        !          1907:     if (len > 0 && password[len - 1] == '\n')
        !          1908:       password[len - 1] = '\0';
        !          1909:     ok = (password[0] != '\0');
        !          1910:   } else {
        !          1911:     if (ferror(fp))
        !          1912:       Perror("Error reading from external auth program");
        !          1913:   }
        !          1914:   if (!ok)
        !          1915:     Log(LG_AUTH, ("External auth program failed for user \"%s\"", 
        !          1916:       authname));
        !          1917:   pclose(fp);
        !          1918:   return (ok ? 0 : -1);
        !          1919: }
        !          1920: 
        !          1921: /*
        !          1922:  * AuthCode()
        !          1923:  */
        !          1924: 
        !          1925: static const char *
        !          1926: AuthCode(int proto, u_char code, char *buf, size_t len)
        !          1927: {
        !          1928:   switch (proto) {
        !          1929:     case PROTO_EAP:
        !          1930:       return EapCode(code, buf, len);
        !          1931: 
        !          1932:     case PROTO_CHAP:
        !          1933:       return ChapCode(code, buf, len);
        !          1934: 
        !          1935:     case PROTO_PAP:
        !          1936:       return PapCode(code, buf, len);
        !          1937: 
        !          1938:     default:
        !          1939:       snprintf(buf, len, "code %d", code);
        !          1940:       return(buf);
        !          1941:   }
        !          1942: }
        !          1943: 
        !          1944: 
        !          1945: /*
        !          1946:  * AuthSetCommand()
        !          1947:  */
        !          1948: 
        !          1949: static int
        !          1950: AuthSetCommand(Context ctx, int ac, char *av[], void *arg)
        !          1951: {
        !          1952:   AuthConf     const autc = &ctx->lnk->lcp.auth.conf;
        !          1953:   int          val;
        !          1954: 
        !          1955:   if (ac == 0)
        !          1956:     return(-1);
        !          1957: 
        !          1958:   switch ((intptr_t)arg) {
        !          1959: 
        !          1960:     case SET_AUTHNAME:
        !          1961:       strlcpy(autc->authname, *av, sizeof(autc->authname));
        !          1962:       break;
        !          1963: 
        !          1964:     case SET_PASSWORD:
        !          1965:       strlcpy(autc->password, *av, sizeof(autc->password));
        !          1966:       break;
        !          1967:       
        !          1968:     case SET_EXTAUTH_SCRIPT:
        !          1969:        Freee(autc->extauth_script);
        !          1970:        autc->extauth_script = Mstrdup(MB_AUTH, *av);
        !          1971:        break;
        !          1972:       
        !          1973:     case SET_EXTACCT_SCRIPT:
        !          1974:        Freee(autc->extacct_script);
        !          1975:        autc->extacct_script = Mstrdup(MB_AUTH, *av);
        !          1976:        break;
        !          1977:       
        !          1978:     case SET_MAX_LOGINS:
        !          1979:       gMaxLogins = atoi(av[0]);
        !          1980:       if (ac >= 2 && strcasecmp(av[1], "ci") == 0) {
        !          1981:         gMaxLoginsCI = 1;
        !          1982:       } else {
        !          1983:         gMaxLoginsCI = 0;
        !          1984:       }
        !          1985:       break;
        !          1986:       
        !          1987:     case SET_ACCT_UPDATE:
        !          1988:       val = atoi(*av);
        !          1989:       if (val < 0)
        !          1990:        Error("Update interval must be positive.");
        !          1991:       else
        !          1992:        autc->acct_update = val;
        !          1993:       break;
        !          1994: 
        !          1995:     case SET_ACCT_UPDATE_LIMIT_IN:
        !          1996:     case SET_ACCT_UPDATE_LIMIT_OUT:
        !          1997:       val = atoi(*av);
        !          1998:       if (val < 0)
        !          1999:        Error("Update suppression limit must be positive.");
        !          2000:       else {
        !          2001:        if ((intptr_t)arg == SET_ACCT_UPDATE_LIMIT_IN)
        !          2002:          autc->acct_update_lim_recv = val;
        !          2003:        else
        !          2004:          autc->acct_update_lim_xmit = val;
        !          2005:       }
        !          2006:       break;
        !          2007: 
        !          2008:     case SET_TIMEOUT:
        !          2009:       val = atoi(*av);
        !          2010:       if (val <= 20)
        !          2011:        Error("Authorization timeout must be greater then 20.");
        !          2012:       else
        !          2013:        autc->timeout = val;
        !          2014:       break;
        !          2015:       
        !          2016:     case SET_ACCEPT:
        !          2017:       AcceptCommand(ac, av, &autc->options, gConfList);
        !          2018:       break;
        !          2019: 
        !          2020:     case SET_DENY:
        !          2021:       DenyCommand(ac, av, &autc->options, gConfList);
        !          2022:       break;
        !          2023: 
        !          2024:     case SET_ENABLE:
        !          2025:       EnableCommand(ac, av, &autc->options, gConfList);
        !          2026:       break;
        !          2027: 
        !          2028:     case SET_DISABLE:
        !          2029:       DisableCommand(ac, av, &autc->options, gConfList);
        !          2030:       break;
        !          2031: 
        !          2032:     case SET_YES:
        !          2033:       YesCommand(ac, av, &autc->options, gConfList);
        !          2034:       break;
        !          2035: 
        !          2036:     case SET_NO:
        !          2037:       NoCommand(ac, av, &autc->options, gConfList);
        !          2038:       break;
        !          2039: 
        !          2040:     default:
        !          2041:       assert(0);
        !          2042:   }
        !          2043: 
        !          2044:   return(0);
        !          2045: }
        !          2046: 
        !          2047: /*
        !          2048:  * AuthExternal()
        !          2049:  * 
        !          2050:  * Authenticate via call external script extauth-script
        !          2051:  */
        !          2052:  
        !          2053: static int
        !          2054: AuthExternal(AuthData auth)
        !          2055: {
        !          2056:     char       line[256];
        !          2057:     FILE       *fp;
        !          2058:     char       *attr, *val;
        !          2059:     int                len;
        !          2060:  
        !          2061:     if (!auth->conf.extauth_script || !auth->conf.extauth_script[0]) {
        !          2062:            Log(LG_ERR, ("[%s] Ext-auth: Script not specified!", 
        !          2063:                auth->info.lnkname));
        !          2064:            return (-1);
        !          2065:     }
        !          2066:     if (strchr(auth->params.authname, '\'') ||
        !          2067:        strchr(auth->params.authname, '\n')) {
        !          2068:            Log(LG_ERR, ("[%s] Ext-auth: Denied character in USER_NAME!", 
        !          2069:                auth->info.lnkname));
        !          2070:            return (-1);
        !          2071:     }
        !          2072:     snprintf(line, sizeof(line), "%s '%s'", 
        !          2073:        auth->conf.extauth_script, auth->params.authname);
        !          2074:     Log(LG_AUTH, ("[%s] Ext-auth: Invoking auth program: '%s'", 
        !          2075:        auth->info.lnkname, line));
        !          2076:     if ((fp = popen(line, "r+")) == NULL) {
        !          2077:        Perror("Popen");
        !          2078:        return (-1);
        !          2079:     }
        !          2080: 
        !          2081:     /* SENDING REQUEST */
        !          2082:     fprintf(fp, "USER_NAME:%s\n", auth->params.authname);
        !          2083:     fprintf(fp, "AUTH_TYPE:%s", ProtoName(auth->proto));
        !          2084:     if (auth->proto == PROTO_CHAP) {
        !          2085:        switch (auth->alg) {
        !          2086:            case CHAP_ALG_MD5:
        !          2087:                fprintf(fp, " MD5\n");
        !          2088:                break;
        !          2089:            case CHAP_ALG_MSOFT:
        !          2090:                fprintf(fp, " MSOFT\n");
        !          2091:                break;
        !          2092:            case CHAP_ALG_MSOFTv2:
        !          2093:                fprintf(fp, " MSOFTv2\n");
        !          2094:                break;
        !          2095:            default:
        !          2096:                fprintf(fp, " 0x%02x\n", auth->alg);
        !          2097:                break;
        !          2098:        }
        !          2099:     } else
        !          2100:        fprintf(fp, "\n");
        !          2101: 
        !          2102:     if (auth->proto == PROTO_PAP)
        !          2103:        fprintf(fp, "USER_PASSWORD:%s\n", auth->params.pap.peer_pass);
        !          2104: 
        !          2105:     fprintf(fp, "ACCT_SESSION_ID:%s\n", auth->info.session_id);
        !          2106:     fprintf(fp, "LINK:%s\n", auth->info.lnkname);
        !          2107:     fprintf(fp, "NAS_PORT:%d\n", auth->info.linkID);
        !          2108:     fprintf(fp, "NAS_PORT_TYPE:%s\n", auth->info.phys_type->name);
        !          2109:     fprintf(fp, "CALLING_STATION_ID:%s\n", auth->params.callingnum);
        !          2110:     fprintf(fp, "CALLED_STATION_ID:%s\n", auth->params.callednum);
        !          2111:     fprintf(fp, "SELF_NAME:%s\n", auth->params.selfname);
        !          2112:     fprintf(fp, "PEER_NAME:%s\n", auth->params.peername);
        !          2113:     fprintf(fp, "SELF_ADDR:%s\n", auth->params.selfaddr);
        !          2114:     fprintf(fp, "PEER_ADDR:%s\n", auth->params.peeraddr);
        !          2115:     fprintf(fp, "PEER_PORT:%s\n", auth->params.peerport);
        !          2116:     fprintf(fp, "PEER_MAC_ADDR:%s\n", auth->params.peermacaddr);
        !          2117:     fprintf(fp, "PEER_IFACE:%s\n", auth->params.peeriface);
        !          2118:     fprintf(fp, "PEER_IDENT:%s\n", auth->info.peer_ident);
        !          2119:  
        !          2120: 
        !          2121:     /* REQUEST DONE */
        !          2122:     fprintf(fp, "\n");
        !          2123: 
        !          2124:     /* REPLY PROCESSING */
        !          2125:     auth->status = AUTH_STATUS_FAIL;
        !          2126:     while (fgets(line, sizeof(line), fp)) {
        !          2127:        /* trim trailing newline */
        !          2128:        len = strlen(line);
        !          2129:        if (len > 0 && line[len - 1] == '\n') {
        !          2130:            line[len - 1] = '\0';
        !          2131:            len--;
        !          2132:        }
        !          2133: 
        !          2134:        /* Empty line is the end marker */
        !          2135:        if (len == 0)
        !          2136:            break;
        !          2137: 
        !          2138:        /* split line on attr:value */
        !          2139:        val = line;
        !          2140:        attr = strsep(&val, ":");
        !          2141: 
        !          2142:        /* Log data w/o password */
        !          2143:        if (strcmp(attr, "USER_PASSWORD") != 0) {
        !          2144:            Log(LG_AUTH2, ("[%s] Ext-auth: attr:'%s', value:'%s'", 
        !          2145:                auth->info.lnkname, attr, val));
        !          2146:        } else {
        !          2147:            Log(LG_AUTH2, ("[%s] Ext-auth: attr:'%s', value:'XXX'", 
        !          2148:                auth->info.lnkname, attr));
        !          2149:        }
        !          2150:     
        !          2151:     if (strcmp(attr, "RESULT") == 0) {
        !          2152:        if (strcmp(val, "SUCCESS") == 0) {
        !          2153:            auth->status = AUTH_STATUS_SUCCESS;
        !          2154:        } else if (strcmp(val, "UNDEF") == 0) {
        !          2155:            auth->status = AUTH_STATUS_UNDEF;
        !          2156:        } else 
        !          2157:            auth->status = AUTH_STATUS_FAIL;
        !          2158: 
        !          2159:     } else if (strcmp(attr, "USER_NAME") == 0) {
        !          2160:        strlcpy(auth->params.authname, val, sizeof(auth->params.authname));
        !          2161: 
        !          2162:     } else if (strcmp(attr, "USER_PASSWORD") == 0) {
        !          2163:        strlcpy(auth->params.password, val, sizeof(auth->params.password));
        !          2164: 
        !          2165:     } else if (strcmp(attr, "USER_NT_HASH") == 0) {
        !          2166:        if (strlen(val) != 32) {
        !          2167:            Log(LG_AUTH, ("[%s] Ext-auth: Incorrect USER_NT_HASH length", auth->info.lnkname));
        !          2168:        } else {
        !          2169:            u_char *bin = Hex2Bin(val);
        !          2170:            memcpy(auth->params.msoft.nt_hash, bin, sizeof(auth->params.msoft.nt_hash));
        !          2171:            Freee(bin);
        !          2172:            NTPasswordHashHash(auth->params.msoft.nt_hash, auth->params.msoft.nt_hash_hash);
        !          2173:            auth->params.msoft.has_nt_hash = TRUE;
        !          2174:        }
        !          2175: 
        !          2176:     } else if (strcmp(attr, "USER_LM_HASH") == 0) {
        !          2177:        if (strlen(val) != 32) {
        !          2178:            Log(LG_AUTH, ("[%s] Ext-auth: Incorrect USER_LM_HASH length", auth->info.lnkname));
        !          2179:        } else {
        !          2180:            u_char *bin = Hex2Bin(val);
        !          2181:            memcpy(auth->params.msoft.lm_hash, bin, sizeof(auth->params.msoft.lm_hash));
        !          2182:            Freee(bin);
        !          2183:            auth->params.msoft.has_lm_hash = TRUE;
        !          2184:        }
        !          2185: 
        !          2186:     } else if (strcmp(attr, "FRAMED_IP_ADDRESS") == 0) {
        !          2187:         auth->params.range_valid = 
        !          2188:            ParseRange(val, &auth->params.range, ALLOW_IPV4);
        !          2189: 
        !          2190:     } else if (strcmp(attr, "PRIMARY_DNS_SERVER") == 0) {
        !          2191:        inet_pton(AF_INET, val, &auth->params.peer_dns[0]);
        !          2192: 
        !          2193:     } else if (strcmp(attr, "SECONDARY_DNS_SERVER") == 0) {
        !          2194:        inet_pton(AF_INET, val, &auth->params.peer_dns[1]);
        !          2195: 
        !          2196:     } else if (strcmp(attr, "PRIMARY_NBNS_SERVER") == 0) {
        !          2197:        inet_pton(AF_INET, val, &auth->params.peer_nbns[0]);
        !          2198: 
        !          2199:     } else if (strcmp(attr, "SECONDARY_NBNS_SERVER") == 0) {
        !          2200:        inet_pton(AF_INET, val, &auth->params.peer_nbns[1]);
        !          2201: 
        !          2202:     } else if (strcmp(attr, "FRAMED_ROUTE") == 0) {
        !          2203:        struct u_range        range;
        !          2204: 
        !          2205:        if (!ParseRange(val, &range, ALLOW_IPV4)) {
        !          2206:          Log(LG_AUTH, ("[%s] Ext-auth: FRAMED_ROUTE: Bad route \"%s\"", 
        !          2207:            auth->info.lnkname, val));
        !          2208:        } else {
        !          2209:            struct ifaceroute     *r, *r1;
        !          2210:            int         j;
        !          2211: 
        !          2212:            r = Malloc(MB_AUTH, sizeof(struct ifaceroute));
        !          2213:            r->dest = range;
        !          2214:            r->ok = 0;
        !          2215:            j = 0;
        !          2216:            SLIST_FOREACH(r1, &auth->params.routes, next) {
        !          2217:              if (!u_rangecompare(&r->dest, &r1->dest)) {
        !          2218:                Log(LG_AUTH, ("[%s] Ext-auth: Duplicate route", auth->info.lnkname));
        !          2219:                j = 1;
        !          2220:              }
        !          2221:            };
        !          2222:            if (j == 0) {
        !          2223:                SLIST_INSERT_HEAD(&auth->params.routes, r, next);
        !          2224:            } else {
        !          2225:                Freee(r);
        !          2226:            }
        !          2227:        }
        !          2228: 
        !          2229:     } else if (strcmp(attr, "FRAMED_IPV6_ROUTE") == 0) {
        !          2230:        struct u_range        range;
        !          2231: 
        !          2232:        if (!ParseRange(val, &range, ALLOW_IPV6)) {
        !          2233:          Log(LG_AUTH, ("[%s] Ext-auth: FRAMED_IPV6_ROUTE: Bad route \"%s\"", 
        !          2234:            auth->info.lnkname, val));
        !          2235:        } else {
        !          2236:            struct ifaceroute     *r, *r1;
        !          2237:            int         j;
        !          2238: 
        !          2239:            r = Malloc(MB_AUTH, sizeof(struct ifaceroute));
        !          2240:            r->dest = range;
        !          2241:            r->ok = 0;
        !          2242:            j = 0;
        !          2243:            SLIST_FOREACH(r1, &auth->params.routes, next) {
        !          2244:              if (!u_rangecompare(&r->dest, &r1->dest)) {
        !          2245:                Log(LG_AUTH, ("[%s] Ext-auth: Duplicate route", auth->info.lnkname));
        !          2246:                j = 1;
        !          2247:              }
        !          2248:            };
        !          2249:            if (j == 0) {
        !          2250:                SLIST_INSERT_HEAD(&auth->params.routes, r, next);
        !          2251:            } else {
        !          2252:                Freee(r);
        !          2253:            }
        !          2254:        }
        !          2255: 
        !          2256:     } else if (strcmp(attr, "SESSION_TIMEOUT") == 0) {
        !          2257:        auth->params.session_timeout = atoi(val);
        !          2258: 
        !          2259:     } else if (strcmp(attr, "IDLE_TIMEOUT") == 0) {
        !          2260:        auth->params.idle_timeout = atoi(val);
        !          2261: 
        !          2262:     } else if (strcmp(attr, "ACCT_INTERIM_INTERVAL") == 0) {
        !          2263:        auth->params.acct_update = atoi(val);
        !          2264: 
        !          2265:     } else if (strcmp(attr, "ACCT_INTERIM_LIM_RECV") == 0) {
        !          2266:        auth->params.acct_update_lim_recv = atoi(val);
        !          2267: 
        !          2268:     } else if (strcmp(attr, "ACCT_INTERIM_LIM_XMIT") == 0) {
        !          2269:        auth->params.acct_update_lim_xmit = atoi(val);
        !          2270: 
        !          2271:     } else if (strcmp(attr, "FRAMED_MTU") == 0) {
        !          2272:        auth->params.mtu = atoi(val);
        !          2273: 
        !          2274:     } else if (strcmp(attr, "FRAMED_COMPRESSION") == 0) {
        !          2275:        if (atoi(val) == 1)
        !          2276:            auth->params.vjc_enable = 1;
        !          2277: 
        !          2278:     } else if (strcmp(attr, "FRAMED_POOL") == 0) {
        !          2279:        strlcpy(auth->params.ippool, val, sizeof(auth->params.ippool));
        !          2280: 
        !          2281:     } else if (strcmp(attr, "REPLY_MESSAGE") == 0) {
        !          2282:        Freee(auth->reply_message);
        !          2283:        auth->reply_message = Mstrdup(MB_AUTH, val);
        !          2284: 
        !          2285:     } else if (strcmp(attr, "MS_CHAP_ERROR") == 0) {
        !          2286:        Freee(auth->mschap_error);
        !          2287:        /* "E=%d R=0 M=%s" */
        !          2288:        auth->mschap_error = Mstrdup(MB_AUTH, val);
        !          2289: 
        !          2290:     } else if (strcmp(attr, "MPD_ACTION") == 0) {
        !          2291:        strlcpy(auth->params.action, val, sizeof(auth->params.action));
        !          2292: 
        !          2293:     } else if (strcmp(attr, "MPD_IFACE_NAME") == 0) {
        !          2294:        strlcpy(auth->params.ifname, val, sizeof(auth->params.ifname));
        !          2295: 
        !          2296: #ifdef SIOCSIFDESCR
        !          2297:     } else if (strcmp(attr, "MPD_IFACE_DESCR") == 0) {
        !          2298:        Freee(auth->params.ifdescr);
        !          2299:        auth->params.ifdescr = Mstrdup(MB_AUTH, val);
        !          2300: #endif /* SIOCSIFDESCR */
        !          2301: #ifdef SIOCAIFGROUP
        !          2302:     } else if (strcmp(attr, "MPD_IFACE_GROUP") == 0) {
        !          2303:        strlcpy(auth->params.ifgroup, val, sizeof(auth->params.ifgroup));
        !          2304: #endif
        !          2305: #if defined(USE_IPFW) || defined(USE_NG_BPF)
        !          2306:     } else if (strncmp(attr, "MPD_", 4) == 0) {
        !          2307:        struct acl      **acls, *acls1;
        !          2308:        char            *acl1, *acl2, *acl3;
        !          2309:        int             i;
        !          2310:        
        !          2311:            acl1 = NULL;
        !          2312:            acls = NULL;
        !          2313: #ifdef USE_IPFW
        !          2314:            if (strcmp(attr, "MPD_RULE") == 0) {
        !          2315:              acl1 = val;
        !          2316:              acls = &(auth->params.acl_rule);
        !          2317:            } else if (strcmp(attr, "MPD_PIPE") == 0) {
        !          2318:              acl1 = val;
        !          2319:              acls = &(auth->params.acl_pipe);
        !          2320:            } else if (strcmp(attr, "MPD_QUEUE") == 0) {
        !          2321:              acl1 = val;
        !          2322:              acls = &(auth->params.acl_queue);
        !          2323:            } else if (strcmp(attr, "MPD_TABLE") == 0) {
        !          2324:              acl1 = val;
        !          2325:              acls = &(auth->params.acl_table);
        !          2326:            } else if (strcmp(attr, "MPD_TABLE_STATIC") == 0) {
        !          2327:              acl1 = val;
        !          2328:              acls = &(auth->params.acl_table);
        !          2329:            } else
        !          2330: #endif /* USE_IPFW */
        !          2331: #ifdef USE_NG_BPF
        !          2332:             if (strcmp(attr, "MPD_FILTER") == 0) {
        !          2333:              acl1 = val;
        !          2334:              acl2 = strsep(&acl1, "#");
        !          2335:              i = atol(acl2);
        !          2336:              if (i <= 0 || i > ACL_FILTERS) {
        !          2337:                Log(LG_ERR, ("[%s] Ext-auth: wrong filter number: %i",
        !          2338:                  auth->info.lnkname, i));
        !          2339:                continue;
        !          2340:              }
        !          2341:              acls = &(auth->params.acl_filters[i - 1]);
        !          2342:            } else if (strcmp(attr, "MPD_LIMIT") == 0) {
        !          2343:              acl1 = val;
        !          2344:              acl2 = strsep(&acl1, "#");
        !          2345:              if (strcasecmp(acl2, "in") == 0) {
        !          2346:                i = 0;
        !          2347:              } else if (strcasecmp(acl2, "out") == 0) {
        !          2348:                i = 1;
        !          2349:              } else {
        !          2350:                Log(LG_ERR, ("[%s] Ext-auth: wrong limit direction: '%s'",
        !          2351:                  auth->info.lnkname, acl2));
        !          2352:                continue;
        !          2353:              }
        !          2354:              acls = &(auth->params.acl_limits[i]);
        !          2355:            } else {
        !          2356:              Log(LG_ERR, ("[%s] Ext-auth: Dropping MPD vendor specific attribute: '%s'",
        !          2357:                auth->info.lnkname, attr));
        !          2358:              continue;
        !          2359:            }
        !          2360: #endif /* USE_NG_BPF */
        !          2361: 
        !          2362:            if (acl1 == NULL) {
        !          2363:              Log(LG_ERR, ("[%s] Ext-auth: incorrect acl!",
        !          2364:                auth->info.lnkname));
        !          2365:              continue;
        !          2366:            }
        !          2367:            
        !          2368:            acl3 = acl1;
        !          2369:            strsep(&acl3, "=");
        !          2370:            acl2 = acl1;
        !          2371:            strsep(&acl2, "#");
        !          2372:            i = atol(acl1);
        !          2373:            if (i <= 0) {
        !          2374:              Log(LG_ERR, ("[%s] Ext-auth: wrong acl number: %i",
        !          2375:                auth->info.lnkname, i));
        !          2376:              continue;
        !          2377:            }
        !          2378:            if ((acl3 == NULL) || (acl3[0] == 0)) {
        !          2379:              Log(LG_ERR, ("[%s] Ext-auth: wrong acl", auth->info.lnkname));
        !          2380:              continue;
        !          2381:            }
        !          2382:            acls1 = Malloc(MB_AUTH, sizeof(struct acl) + strlen(acl3));
        !          2383:            if (strcmp(attr, "MPD_TABLE_STATIC") != 0) {
        !          2384:                    acls1->number = i;
        !          2385:                    acls1->real_number = 0;
        !          2386:            } else {
        !          2387:                    acls1->number = 0;
        !          2388:                    acls1->real_number = i;
        !          2389:            }
        !          2390:            if (acl2)
        !          2391:                strlcpy(acls1->name, acl2, sizeof(acls1->name));
        !          2392:            strcpy(acls1->rule, acl3);
        !          2393:            while ((*acls != NULL) && ((*acls)->number < acls1->number))
        !          2394:              acls = &((*acls)->next);
        !          2395: 
        !          2396:            if (*acls == NULL) {
        !          2397:              acls1->next = NULL;
        !          2398:            } else if (((*acls)->number == acls1->number) &&
        !          2399:                (strcmp(attr, "MPD_TABLE") != 0) &&
        !          2400:                (strcmp(attr, "MPD_TABLE_STATIC") != 0)) {
        !          2401:              Log(LG_ERR, ("[%s] Ext-auth: duplicate acl",
        !          2402:                auth->info.lnkname));
        !          2403:              continue;
        !          2404:            } else {
        !          2405:              acls1->next = *acls;
        !          2406:            }
        !          2407:            *acls = acls1;
        !          2408: #endif /* USE_IPFW or USE_NG_BPF */
        !          2409: 
        !          2410:     } else {
        !          2411:        Log(LG_ERR, ("[%s] Ext-auth: Unknown attr:'%s'", 
        !          2412:            auth->info.lnkname, attr));
        !          2413:     }
        !          2414:     }
        !          2415:  
        !          2416:     pclose(fp);
        !          2417:     return (0);
        !          2418: }
        !          2419: 
        !          2420: /*
        !          2421:  * AuthExternalAcct()
        !          2422:  * 
        !          2423:  * Accounting via call external script extacct-script
        !          2424:  */
        !          2425:  
        !          2426: static int
        !          2427: AuthExternalAcct(AuthData auth)
        !          2428: {
        !          2429:     char       line[256];
        !          2430:     FILE       *fp;
        !          2431:     char       *attr, *val;
        !          2432:     int                len;
        !          2433:  
        !          2434:     if (!auth->conf.extacct_script || !auth->conf.extacct_script[0]) {
        !          2435:        Log(LG_ERR, ("[%s] Ext-acct: Script not specified!", 
        !          2436:            auth->info.lnkname));
        !          2437:        return (-1);
        !          2438:     }
        !          2439:     if (strchr(auth->params.authname, '\'') ||
        !          2440:            strchr(auth->params.authname, '\n')) {
        !          2441:        Log(LG_ERR, ("[%s] Ext-acct: Denied character in USER_NAME!", 
        !          2442:            auth->info.lnkname));
        !          2443:        return (-1);
        !          2444:     }
        !          2445:     snprintf(line, sizeof(line), "%s '%s'", 
        !          2446:        auth->conf.extacct_script, auth->params.authname);
        !          2447:     Log(LG_AUTH, ("[%s] Ext-acct: Invoking acct program: '%s'", 
        !          2448:        auth->info.lnkname, line));
        !          2449:     if ((fp = popen(line, "r+")) == NULL) {
        !          2450:        Perror("Popen");
        !          2451:        return (-1);
        !          2452:     }
        !          2453: 
        !          2454:     /* SENDING REQUEST */
        !          2455:     fprintf(fp, "ACCT_STATUS_TYPE:%s\n", 
        !          2456:        (auth->acct_type == AUTH_ACCT_START)?
        !          2457:            "START":((auth->acct_type == AUTH_ACCT_STOP)?
        !          2458:                "STOP":"UPDATE"));
        !          2459: 
        !          2460:     fprintf(fp, "ACCT_SESSION_ID:%s\n", auth->info.session_id);
        !          2461:     fprintf(fp, "ACCT_MULTI_SESSION_ID:%s\n", auth->info.msession_id);
        !          2462:     fprintf(fp, "USER_NAME:%s\n", auth->params.authname);
        !          2463:     fprintf(fp, "IFACE:%s\n", auth->info.ifname);
        !          2464:     fprintf(fp, "IFACE_INDEX:%d\n", auth->info.ifindex);
        !          2465:     fprintf(fp, "BUNDLE:%s\n", auth->info.bundname);
        !          2466:     fprintf(fp, "LINK:%s\n", auth->info.lnkname);
        !          2467:     fprintf(fp, "NAS_PORT:%d\n", auth->info.linkID);
        !          2468:     fprintf(fp, "NAS_PORT_TYPE:%s\n", auth->info.phys_type->name);
        !          2469:     fprintf(fp, "ACCT_LINK_COUNT:%d\n", auth->info.n_links);
        !          2470:     fprintf(fp, "CALLING_STATION_ID:%s\n", auth->params.callingnum);
        !          2471:     fprintf(fp, "CALLED_STATION_ID:%s\n", auth->params.callednum);
        !          2472:     fprintf(fp, "SELF_NAME:%s\n", auth->params.selfname);
        !          2473:     fprintf(fp, "PEER_NAME:%s\n", auth->params.peername);
        !          2474:     fprintf(fp, "SELF_ADDR:%s\n", auth->params.selfaddr);
        !          2475:     fprintf(fp, "PEER_ADDR:%s\n", auth->params.peeraddr);
        !          2476:     fprintf(fp, "PEER_PORT:%s\n", auth->params.peerport);
        !          2477:     fprintf(fp, "PEER_MAC_ADDR:%s\n", auth->params.peermacaddr);
        !          2478:     fprintf(fp, "PEER_IFACE:%s\n", auth->params.peeriface);
        !          2479:     fprintf(fp, "PEER_IDENT:%s\n", auth->info.peer_ident);
        !          2480: 
        !          2481:     fprintf(fp, "FRAMED_IP_ADDRESS:%s\n",
        !          2482:        inet_ntoa(auth->info.peer_addr));
        !          2483: 
        !          2484:     if (auth->acct_type == AUTH_ACCT_STOP)
        !          2485:        fprintf(fp, "ACCT_TERMINATE_CAUSE:%s\n", auth->info.downReason);
        !          2486: 
        !          2487:     if (auth->acct_type != AUTH_ACCT_START) {
        !          2488: #ifdef USE_NG_BPF
        !          2489:        struct svcstatrec *ssr;
        !          2490: #endif
        !          2491:        fprintf(fp, "ACCT_SESSION_TIME:%ld\n", 
        !          2492:            (long int)(time(NULL) - auth->info.last_up));
        !          2493:        fprintf(fp, "ACCT_INPUT_OCTETS:%llu\n", 
        !          2494:            (long long unsigned)auth->info.stats.recvOctets);
        !          2495:        fprintf(fp, "ACCT_INPUT_PACKETS:%llu\n", 
        !          2496:            (long long unsigned)auth->info.stats.recvFrames);
        !          2497:        fprintf(fp, "ACCT_OUTPUT_OCTETS:%llu\n", 
        !          2498:            (long long unsigned)auth->info.stats.xmitOctets);
        !          2499:        fprintf(fp, "ACCT_OUTPUT_PACKETS:%llu\n", 
        !          2500:            (long long unsigned)auth->info.stats.xmitFrames);
        !          2501: #ifdef USE_NG_BPF
        !          2502:        SLIST_FOREACH(ssr, &auth->info.ss.stat[0], next) {
        !          2503:            fprintf(fp, "MPD_INPUT_OCTETS:%s:%llu\n",
        !          2504:                ssr->name, (long long unsigned)ssr->Octets);
        !          2505:            fprintf(fp, "MPD_INPUT_PACKETS:%s:%llu\n",
        !          2506:                ssr->name, (long long unsigned)ssr->Packets);
        !          2507:        }
        !          2508:        SLIST_FOREACH(ssr, &auth->info.ss.stat[1], next) {
        !          2509:            fprintf(fp, "MPD_OUTPUT_OCTETS:%s:%llu\n",
        !          2510:                ssr->name, (long long unsigned)ssr->Octets);
        !          2511:            fprintf(fp, "MPD_OUTPUT_PACKETS:%s:%llu\n",
        !          2512:                ssr->name, (long long unsigned)ssr->Packets);
        !          2513:        }
        !          2514: #endif /* USE_NG_BPF */
        !          2515:     }
        !          2516: 
        !          2517:     /* REQUEST DONE */
        !          2518:     fprintf(fp, "\n");
        !          2519: 
        !          2520:     /* REPLY PROCESSING */
        !          2521:     while (fgets(line, sizeof(line), fp)) {
        !          2522:        /* trim trailing newline */
        !          2523:        len = strlen(line);
        !          2524:        if (len > 0 && line[len - 1] == '\n') {
        !          2525:            line[len - 1] = '\0';
        !          2526:            len--;
        !          2527:        }
        !          2528: 
        !          2529:        /* Empty line is the end marker */
        !          2530:        if (len == 0)
        !          2531:            break;
        !          2532: 
        !          2533:        /* split line on attr:value */
        !          2534:        val = line;
        !          2535:        attr = strsep(&val, ":");
        !          2536: 
        !          2537:        Log(LG_AUTH2, ("[%s] Ext-acct: attr:'%s', value:'%s'", 
        !          2538:            auth->info.lnkname, attr, val));
        !          2539:     
        !          2540:        if (strcmp(attr, "MPD_DROP_USER") == 0) {
        !          2541:            auth->drop_user = atoi(val);
        !          2542: 
        !          2543:        } else {
        !          2544:            Log(LG_ERR, ("[%s] Ext-acct: Unknown attr:'%s'", 
        !          2545:                auth->info.lnkname, attr));
        !          2546:        }
        !          2547:     }
        !          2548:  
        !          2549:     pclose(fp);
        !          2550:     return (0);
        !          2551: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>