Diff for /embedaddon/mpd/src/auth.c between versions 1.1.1.2 and 1.1.1.4.2.1

version 1.1.1.2, 2013/07/22 08:44:29 version 1.1.1.4.2.1, 2023/09/27 11:08:00
Line 18 Line 18
 #include "util.h"  #include "util.h"
   
 #ifdef USE_PAM  #ifdef USE_PAM
#include <security/pam_appl.h>  #include <security/pam_appl.h>
 #endif  #endif
 #ifdef USE_SYSTEM  #ifdef USE_SYSTEM
 #if __FreeBSD_version >= 900007  #if __FreeBSD_version >= 900007
Line 32 Line 32
 /*  /*
  * DEFINITIONS   * DEFINITIONS
  */   */
    
 #ifdef USE_OPIE  #ifdef USE_OPIE
  #define OPIE_ALG_MD5  5#define OPIE_ALG_MD5    5
 #endif  #endif
  
 /*  /*
  * INTERNAL FUNCTIONS   * INTERNAL FUNCTIONS
  */   */
   
  static void           AuthTimeout(void *arg);static void AuthTimeout(void *arg);
  static int            AuthGetExternalPassword(char * extcmd, char *authname,static int 
                            char *password, size_t passlen);AuthGetExternalPassword(const char *extcmd, char *authname,
  static void           AuthAsync(void *arg);    char *password, size_t passlen);
  static void           AuthAsyncFinish(void *arg, int was_canceled);static void AuthAsync(void *arg);
  static int            AuthPreChecks(AuthData auth);static void AuthAsyncFinish(void *arg, int was_canceled);
  static void           AuthAccount(void *arg);static int AuthPreChecks(AuthData auth);
  static void           AuthAccountFinish(void *arg, int was_canceled);static void AuthAccount(void *arg);
  static void           AuthInternal(AuthData auth);static void AuthAccountFinish(void *arg, int was_canceled);
  static int            AuthExternal(AuthData auth);static void AuthInternal(AuthData auth);
  static int            AuthExternalAcct(AuthData auth);static int AuthExternal(AuthData auth);
 static int AuthExternalAcct(AuthData auth);
 
 #ifdef USE_SYSTEM  #ifdef USE_SYSTEM
  static void           AuthSystem(AuthData auth);static void AuthSystem(AuthData auth);
  static int            AuthSystemAcct(AuthData auth);static int AuthSystemAcct(AuthData auth);
 
 #endif  #endif
 #ifdef USE_PAM  #ifdef USE_PAM
  static void           AuthPAM(AuthData auth);static void AuthPAM(AuthData auth);
  static int            AuthPAMAcct(AuthData auth);static int AuthPAMAcct(AuthData auth);
  static int            pam_conv(int n, const struct pam_message **msg,static int 
                            struct pam_response **resp, void *data);pam_conv(int n, const struct pam_message **msg,
     struct pam_response **resp, void *data);
 
 #endif  #endif
 #ifdef USE_OPIE  #ifdef USE_OPIE
  static void           AuthOpie(AuthData auth);static void AuthOpie(AuthData auth);
 
 #endif  #endif
  static const char     *AuthCode(int proto, u_char code, char *buf, size_t len);static const char *AuthCode(int proto, u_char code, char *buf, size_t len);
  static int            AuthSetCommand(Context ctx, int ac, char *av[], void *arg);static int AuthSetCommand(Context ctx, int ac, const char *const av[], const void *arg);
   
  /* Set menu options */ /* Set menu options */
  enum {enum {
    SET_ACCEPT,        SET_ACCEPT,
    SET_DENY,        SET_DENY,
    SET_ENABLE,        SET_ENABLE,
    SET_DISABLE,        SET_DISABLE,
    SET_YES,        SET_YES,
    SET_NO,        SET_NO,
    SET_AUTHNAME,        SET_AUTHNAME,
    SET_PASSWORD,        SET_PASSWORD,
    SET_EXTAUTH_SCRIPT,        SET_EXTAUTH_SCRIPT,
    SET_EXTACCT_SCRIPT,        SET_EXTACCT_SCRIPT,
    SET_MAX_LOGINS,        SET_MAX_LOGINS,
    SET_ACCT_UPDATE,        SET_ACCT_UPDATE,
    SET_ACCT_UPDATE_LIMIT_IN,        SET_ACCT_UPDATE_LIMIT_IN,
    SET_ACCT_UPDATE_LIMIT_OUT,        SET_ACCT_UPDATE_LIMIT_OUT,
    SET_TIMEOUT        SET_TIMEOUT
  };};
   
 /*  /*
  * GLOBAL VARIABLES   * GLOBAL VARIABLES
  */   */
   
  const struct cmdtab AuthSetCmds[] = {const struct cmdtab AuthSetCmds[] = {
    { "max-logins {num}",                "Max concurrent logins",        {"max-logins {num} [CI]", "Max concurrent logins",
        AuthSetCommand, NULL, 2, (void *) SET_MAX_LOGINS },        AuthSetCommand, NULL, 2, (void *)SET_MAX_LOGINS},
    { "authname {name}",             "Authentication name",        {"authname {name}", "Authentication name",
        AuthSetCommand, NULL, 2, (void *) SET_AUTHNAME },        AuthSetCommand, NULL, 2, (void *)SET_AUTHNAME},
    { "password {pass}",             "Authentication password",        {"password {pass}", "Authentication password",
        AuthSetCommand, NULL, 2, (void *) SET_PASSWORD },        AuthSetCommand, NULL, 2, (void *)SET_PASSWORD},
    { "extauth-script {script}",     "Authentication script",        {"extauth-script {script}", "Authentication script",
        AuthSetCommand, NULL, 2, (void *) SET_EXTAUTH_SCRIPT },        AuthSetCommand, NULL, 2, (void *)SET_EXTAUTH_SCRIPT},
    { "extacct-script {script}",     "Accounting script",        {"extacct-script {script}", "Accounting script",
        AuthSetCommand, NULL, 2, (void *) SET_EXTACCT_SCRIPT },        AuthSetCommand, NULL, 2, (void *)SET_EXTACCT_SCRIPT},
    { "acct-update {seconds}",               "set update interval",        {"acct-update {seconds}", "set update interval",
        AuthSetCommand, NULL, 2, (void *) SET_ACCT_UPDATE },        AuthSetCommand, NULL, 2, (void *)SET_ACCT_UPDATE},
    { "update-limit-in {bytes}",     "set update suppresion limit",        {"update-limit-in {bytes}", "set update suppresion limit",
        AuthSetCommand, NULL, 2, (void *) SET_ACCT_UPDATE_LIMIT_IN },        AuthSetCommand, NULL, 2, (void *)SET_ACCT_UPDATE_LIMIT_IN},
    { "update-limit-out {bytes}",    "set update suppresion limit",        {"update-limit-out {bytes}", "set update suppresion limit",
        AuthSetCommand, NULL, 2, (void *) SET_ACCT_UPDATE_LIMIT_OUT },        AuthSetCommand, NULL, 2, (void *)SET_ACCT_UPDATE_LIMIT_OUT},
    { "timeout {seconds}",           "set auth timeout",        {"timeout {seconds}", "set auth timeout",
        AuthSetCommand, NULL, 2, (void *) SET_TIMEOUT },        AuthSetCommand, NULL, 2, (void *)SET_TIMEOUT},
    { "accept [opt ...]",            "Accept option",        {"accept [opt ...]", "Accept option",
        AuthSetCommand, NULL, 2, (void *) SET_ACCEPT },        AuthSetCommand, NULL, 2, (void *)SET_ACCEPT},
    { "deny [opt ...]",                      "Deny option",        {"deny [opt ...]", "Deny option",
        AuthSetCommand, NULL, 2, (void *) SET_DENY },        AuthSetCommand, NULL, 2, (void *)SET_DENY},
    { "enable [opt ...]",            "Enable option",        {"enable [opt ...]", "Enable option",
        AuthSetCommand, NULL, 2, (void *) SET_ENABLE },        AuthSetCommand, NULL, 2, (void *)SET_ENABLE},
    { "disable [opt ...]",           "Disable option",        {"disable [opt ...]", "Disable option",
        AuthSetCommand, NULL, 2, (void *) SET_DISABLE },        AuthSetCommand, NULL, 2, (void *)SET_DISABLE},
    { "yes [opt ...]",                       "Enable and accept option",        {"yes [opt ...]", "Enable and accept option",
        AuthSetCommand, NULL, 2, (void *) SET_YES },        AuthSetCommand, NULL, 2, (void *)SET_YES},
    { "no [opt ...]",                        "Disable and deny option",        {"no [opt ...]", "Disable and deny option",
        AuthSetCommand, NULL, 2, (void *) SET_NO },        AuthSetCommand, NULL, 2, (void *)SET_NO},
    { NULL },        {NULL, NULL, NULL, NULL, 0, NULL},
  };};
   
  const u_char  gMsoftZeros[32];const u_char gMsoftZeros[32];
  int             gMaxLogins = 0; /* max number of concurrent logins per user */static unsigned        gMaxLogins = 0;                 /* max number of concurrent logins per
  int             gMaxLoginsCI = 0;                                         * user */
 static unsigned        gMaxLoginsCI = 0;
   
 /*  /*
  * INTERNAL VARIABLES   * INTERNAL VARIABLES
  */   */
   
  static struct confinfo gConfList[] = {static const struct confinfo gConfList[] = {
    { 0,        AUTH_CONF_RADIUS_AUTH,  "radius-auth"   },        {0, AUTH_CONF_RADIUS_AUTH, "radius-auth"},
    { 0,        AUTH_CONF_RADIUS_ACCT,  "radius-acct"   },        {0, AUTH_CONF_RADIUS_ACCT, "radius-acct"},
    { 0,        AUTH_CONF_INTERNAL,     "internal"      },        {0, AUTH_CONF_INTERNAL, "internal"},
    { 0,        AUTH_CONF_EXT_AUTH,     "ext-auth"      },        {0, AUTH_CONF_EXT_AUTH, "ext-auth"},
    { 0,        AUTH_CONF_EXT_ACCT,     "ext-acct"      },        {0, AUTH_CONF_EXT_ACCT, "ext-acct"},
 #ifdef USE_SYSTEM  #ifdef USE_SYSTEM
    { 0,        AUTH_CONF_SYSTEM_AUTH,  "system-auth"   },        {0, AUTH_CONF_SYSTEM_AUTH, "system-auth"},
    { 0,        AUTH_CONF_SYSTEM_ACCT,  "system-acct"   },        {0, AUTH_CONF_SYSTEM_ACCT, "system-acct"},
 #endif  #endif
 #ifdef USE_PAM  #ifdef USE_PAM
    { 0,        AUTH_CONF_PAM_AUTH,     "pam-auth"      },        {0, AUTH_CONF_PAM_AUTH, "pam-auth"},
    { 0,        AUTH_CONF_PAM_ACCT,     "pam-acct"      },        {0, AUTH_CONF_PAM_ACCT, "pam-acct"},
 #endif  #endif
 #ifdef USE_OPIE  #ifdef USE_OPIE
    { 0,        AUTH_CONF_OPIE,         "opie"          },        {0, AUTH_CONF_OPIE, "opie"},
 #endif  #endif
    { 0,        AUTH_CONF_ACCT_MANDATORY,       "acct-mandatory"        },        {0, AUTH_CONF_ACCT_MANDATORY, "acct-mandatory"},
    { 0,        0,                        NULL            },        {0, 0, NULL},
  };};
   
 void  void
 ACLCopy(struct acl *src, struct acl **dst)  ACLCopy(struct acl *src, struct acl **dst)
 {  {
    while (src != NULL) {        while (src != NULL) {
        *dst = Mdup(MB_AUTH, src, sizeof(struct acl) + strlen(src->rule));                *dst = Mdup(MB_AUTH, src, sizeof(struct acl) + strlen(src->rule));
        src = src->next;                src = src->next;
        dst = &((*dst)->next);                dst = &((*dst)->next);
    };        };
    *dst = NULL;        *dst = NULL;
 }  }
   
 void  void
 ACLDestroy(struct acl *acl)  ACLDestroy(struct acl *acl)
 {  {
    struct acl *acl1;        struct acl *acl1;
   
    while (acl != NULL) {        while (acl != NULL) {
        acl1 = acl->next;                acl1 = acl->next;
        Freee(acl);                Freee(acl);
        acl = acl1;                acl = acl1;
    };        };
 }  }
   
void    authparamsInit(struct authparams *ap) {void 
    memset(ap,0,sizeof(struct authparams));authparamsInit(struct authparams *ap)
    ap->eapmsg = NULL;{
    ap->state = NULL;        memset(ap, 0, sizeof(struct authparams));
    ap->class = NULL;#ifdef USE_RADIUS
    ap->msdomain = NULL;        ap->eapmsg = NULL;
         ap->state = NULL;
         ap->class = NULL;
         ap->filter_id = NULL;
 #endif
         ap->msdomain = NULL;
 #ifdef SIOCSIFDESCR  #ifdef SIOCSIFDESCR
    ap->ifdescr = NULL;        ap->ifdescr = NULL;
 #endif  #endif
    SLIST_INIT(&ap->routes);        SLIST_INIT(&ap->routes);
 }  }
   
void    authparamsDestroy(struct authparams *ap) {void 
    IfaceRoute          r;authparamsDestroy(struct authparams *ap)
 {
         IfaceRoute r;
 
 #ifdef USE_NG_BPF  #ifdef USE_NG_BPF
    int i;        int i;
 #endif  #endif
     
     Freee(ap->eapmsg);  
     Freee(ap->state);  
     Freee(ap->class);  
   
   #ifdef USE_RADIUS
           Freee(ap->eapmsg);
           Freee(ap->state);
           Freee(ap->class);
           Freee(ap->filter_id);
   #endif
   
 #ifdef USE_IPFW  #ifdef USE_IPFW
    ACLDestroy(ap->acl_rule);        ACLDestroy(ap->acl_rule);
    ACLDestroy(ap->acl_pipe);        ACLDestroy(ap->acl_pipe);
    ACLDestroy(ap->acl_queue);        ACLDestroy(ap->acl_queue);
    ACLDestroy(ap->acl_table);        ACLDestroy(ap->acl_table);
#endif /* USE_IPFW */#endif                                  /* USE_IPFW */
   
 #ifdef USE_NG_BPF  #ifdef USE_NG_BPF
    for (i = 0; i < ACL_FILTERS; i++)        for (i = 0; i < ACL_FILTERS; i++)
        ACLDestroy(ap->acl_filters[i]);                ACLDestroy(ap->acl_filters[i]);
    for (i = 0; i < ACL_DIRS; i++)        for (i = 0; i < ACL_DIRS; i++)
        ACLDestroy(ap->acl_limits[i]);                ACLDestroy(ap->acl_limits[i]);
#endif /* USE_NG_BPF */#endif                                  /* USE_NG_BPF */
   
    while ((r = SLIST_FIRST(&ap->routes)) != NULL) {        while ((r = SLIST_FIRST(&ap->routes)) != NULL) {
        SLIST_REMOVE_HEAD(&ap->routes, next);                SLIST_REMOVE_HEAD(&ap->routes, next);
        Freee(r);                Freee(r);
    }        }
   
    Freee(ap->msdomain);        Freee(ap->msdomain);
 #ifdef SIOCSIFDESCR  #ifdef SIOCSIFDESCR
    Freee(ap->ifdescr);        Freee(ap->ifdescr);
 #endif  #endif
    
    memset(ap,0,sizeof(struct authparams));        memset(ap, 0, sizeof(struct authparams));
 }  }
   
void    authparamsCopy(struct authparams *src, struct authparams *dst) {void 
    IfaceRoute          r, r1;authparamsCopy(struct authparams *src, struct authparams *dst)
 {
         IfaceRoute r, r1;
 
 #ifdef USE_NG_BPF  #ifdef USE_NG_BPF
    int                 i;        int i;
 
 #endif  #endif
   
    memcpy(dst,src,sizeof(struct authparams));        memcpy(dst, src, sizeof(struct authparams));
   
    if (src->eapmsg) 
        dst->eapmsg = Mdup(MB_AUTH, src->eapmsg, src->eapmsg_len); 
    if (src->state) 
        dst->state = Mdup(MB_AUTH, src->state, src->state_len); 
    if (src->class) 
        dst->class = Mdup(MB_AUTH, src->class, src->class_len); 
   
   #ifdef USE_RADIUS
           if (src->eapmsg)
                   dst->eapmsg = Mdup(MB_AUTH, src->eapmsg, src->eapmsg_len);
           if (src->state)
                   dst->state = Mdup(MB_AUTH, src->state, src->state_len);
           if (src->class)
                   dst->class = Mdup(MB_AUTH, src->class, src->class_len);
           if (src->filter_id)
                   dst->filter_id = Mstrdup(MB_AUTH, src->filter_id);
   #endif
   
 #ifdef USE_IPFW  #ifdef USE_IPFW
    ACLCopy(src->acl_rule, &dst->acl_rule);        ACLCopy(src->acl_rule, &dst->acl_rule);
    ACLCopy(src->acl_pipe, &dst->acl_pipe);        ACLCopy(src->acl_pipe, &dst->acl_pipe);
    ACLCopy(src->acl_queue, &dst->acl_queue);        ACLCopy(src->acl_queue, &dst->acl_queue);
    ACLCopy(src->acl_table, &dst->acl_table);        ACLCopy(src->acl_table, &dst->acl_table);
#endif /* USE_IPFW */#endif                                  /* USE_IPFW */
 #ifdef USE_NG_BPF  #ifdef USE_NG_BPF
    for (i = 0; i < ACL_FILTERS; i++)        for (i = 0; i < ACL_FILTERS; i++)
        ACLCopy(src->acl_filters[i], &dst->acl_filters[i]);                ACLCopy(src->acl_filters[i], &dst->acl_filters[i]);
    for (i = 0; i < ACL_DIRS; i++)        for (i = 0; i < ACL_DIRS; i++)
        ACLCopy(src->acl_limits[i], &dst->acl_limits[i]);                ACLCopy(src->acl_limits[i], &dst->acl_limits[i]);
 #endif  #endif
   
    SLIST_INIT(&dst->routes);        SLIST_INIT(&dst->routes);
    SLIST_FOREACH(r, &src->routes, next) {        SLIST_FOREACH(r, &src->routes, next) {
        r1 = Mdup(MB_AUTH, r, sizeof(*r1));                r1 = Mdup(MB_AUTH, r, sizeof(*r1));
        SLIST_INSERT_HEAD(&dst->routes, r1, next);                SLIST_INSERT_HEAD(&dst->routes, r1, next);
    }        }
   
    if (src->msdomain)        if (src->msdomain)
        dst->msdomain = Mstrdup(MB_AUTH, src->msdomain);                dst->msdomain = Mstrdup(MB_AUTH, src->msdomain);
 #ifdef SIOCSIFDESCR  #ifdef SIOCSIFDESCR
    if (src->ifdescr)        if (src->ifdescr)
        dst->ifdescr = Mstrdup(MB_AUTH, src->ifdescr);                dst->ifdescr = Mstrdup(MB_AUTH, src->ifdescr);
 #endif  #endif
 }  }
   
void    authparamsMove(struct authparams *src, struct authparams *dst)void 
 authparamsMove(struct authparams *src, struct authparams *dst)
 {  {
    memcpy(dst,src,sizeof(struct authparams));        memcpy(dst, src, sizeof(struct authparams));
    memset(src,0,sizeof(struct authparams));        memset(src, 0, sizeof(struct authparams));
 }  }
   
 /*  /*
Line 281  void authparamsMove(struct authparams *src, struct aut Line 308  void authparamsMove(struct authparams *src, struct aut
 void  void
 AuthInit(Link l)  AuthInit(Link l)
 {  {
    AuthConf    const ac = &l->lcp.auth.conf;        AuthConf const ac = &l->lcp.auth.conf;
   
    ac->timeout = 40; 
    Enable(&ac->options, AUTH_CONF_INTERNAL); 
    Enable(&ac->options, AUTH_CONF_ACCT_MANDATORY); 
   
    EapInit(l);        ac->timeout = 40;
    RadiusInit(l);        Enable(&ac->options, AUTH_CONF_INTERNAL);
         Enable(&ac->options, AUTH_CONF_ACCT_MANDATORY);
 
 #ifdef USE_RADIUS
         EapInit(l);
         RadiusInit(l);
 #endif
 }  }
   
 /*  /*
Line 300  AuthInit(Link l) Line 329  AuthInit(Link l)
 void  void
 AuthInst(Auth auth, Auth autht)  AuthInst(Auth auth, Auth autht)
 {  {
    memcpy(auth, autht, sizeof(*auth));        memcpy(auth, autht, sizeof(*auth));
    if (auth->conf.extauth_script)        if (auth->conf.extauth_script)
        autht->conf.extauth_script = Mstrdup(MB_AUTH, auth->conf.extauth_script);                autht->conf.extauth_script = Mstrdup(MB_AUTH, auth->conf.extauth_script);
    if (auth->conf.extacct_script)        if (auth->conf.extacct_script)
        autht->conf.extacct_script = Mstrdup(MB_AUTH, auth->conf.extacct_script);                autht->conf.extacct_script = Mstrdup(MB_AUTH, auth->conf.extacct_script);
 }  }
   
 /*  /*
Line 314  AuthInst(Auth auth, Auth autht) Line 343  AuthInst(Auth auth, Auth autht)
 void  void
 AuthShutdown(Link l)  AuthShutdown(Link l)
 {  {
    Auth        a = &l->lcp.auth;        Auth a = &l->lcp.auth;
  
    if (a->thread)        if (a->thread)
        paction_cancel(&a->thread);                paction_cancel(&a->thread);
    if (a->acct_thread)        if (a->acct_thread)
        paction_cancel(&a->acct_thread);                paction_cancel(&a->acct_thread);
    Freee(a->conf.extauth_script);        Freee(a->conf.extauth_script);
    Freee(a->conf.extacct_script);        Freee(a->conf.extacct_script);
 }  }
   
 /*  /*
Line 333  AuthShutdown(Link l) Line 362  AuthShutdown(Link l)
 void  void
 AuthStart(Link l)  AuthStart(Link l)
 {  {
    Auth        a = &l->lcp.auth;        Auth a = &l->lcp.auth;
   
    /* generate a uniq session id */        /* generate a uniq session id */
    snprintf(l->session_id, AUTH_MAX_SESSIONID, "%d-%s",        snprintf(l->session_id, AUTH_MAX_SESSIONID, "%d-%s",
        (int)(time(NULL) % 10000000), l->name);            (int)(time(NULL) % 10000000), l->name);
   
    authparamsInit(&a->params);        authparamsInit(&a->params);
     
    /* What auth protocols were negotiated by LCP? */ 
    a->self_to_peer = l->lcp.peer_auth; 
    a->peer_to_self = l->lcp.want_auth; 
    a->self_to_peer_alg = l->lcp.peer_alg; 
    a->peer_to_self_alg = l->lcp.want_alg; 
   
    /* remember self's name */        /* What auth protocols were negotiated by LCP? */
    PhysGetSelfName(l, a->params.selfname, sizeof(a->params.selfname));        a->self_to_peer = l->lcp.peer_auth;
          a->peer_to_self = l->lcp.want_auth;
    /* remember peer's name */        a->self_to_peer_alg = l->lcp.peer_alg;
    PhysGetPeerName(l, a->params.peername, sizeof(a->params.peername));        a->peer_to_self_alg = l->lcp.want_alg;
   
    /* remember self's IP address */ 
    PhysGetSelfAddr(l, a->params.selfaddr, sizeof(a->params.selfaddr)); 
   
    /* remember peer's IP address */ 
    PhysGetPeerAddr(l, a->params.peeraddr, sizeof(a->params.peeraddr)); 
   
    /* remember peer's TCP or UDP port */ 
    PhysGetPeerPort(l, a->params.peerport, sizeof(a->params.peerport)); 
   
    /* remember peer's MAC address */ 
    PhysGetPeerMacAddr(l, a->params.peermacaddr, sizeof(a->params.peermacaddr)); 
   
    /* remember peer's iface */ 
    PhysGetPeerIface(l, a->params.peeriface, sizeof(a->params.peeriface)); 
   
    /* remember calling number */ 
    PhysGetCallingNum(l, a->params.callingnum, sizeof(a->params.callingnum)); 
   
    /* remember called number */ 
    PhysGetCalledNum(l, a->params.callednum, sizeof(a->params.callednum)); 
     
  Log(LG_AUTH, ("[%s] %s: auth: peer wants %s, I want %s", 
    Pref(&l->lcp.fsm), Fsm(&l->lcp.fsm), 
    a->self_to_peer ? ProtoName(a->self_to_peer) : "nothing", 
    a->peer_to_self ? ProtoName(a->peer_to_self) : "nothing")); 
   
  /* Is there anything to do? */        /* remember self's name */
  if (!a->self_to_peer && !a->peer_to_self) {        PhysGetSelfName(l, a->params.selfname, sizeof(a->params.selfname));
    LcpAuthResult(l, TRUE); 
    return; 
  } 
   
  /* Start global auth timer */        /* remember peer's name */
  TimerInit(&a->timer, "AuthTimer",        PhysGetPeerName(l, a->params.peername, sizeof(a->params.peername));
    l->lcp.auth.conf.timeout * SECONDS, AuthTimeout, l); 
  TimerStart(&a->timer); 
   
  /* Start my auth to him */        /* remember self's IP address */
  switch (a->self_to_peer) {        PhysGetSelfAddr(l, a->params.selfaddr, sizeof(a->params.selfaddr));
    case 0: 
      break; 
    case PROTO_PAP: 
      PapStart(l, AUTH_SELF_TO_PEER); 
      break; 
    case PROTO_CHAP: 
      ChapStart(l, AUTH_SELF_TO_PEER); 
      break; 
    case PROTO_EAP: 
      EapStart(l, AUTH_SELF_TO_PEER); 
      break; 
    default: 
      assert(0); 
  } 
   
  /* Start his auth to me */        /* remember peer's IP address */
  switch (a->peer_to_self) {        PhysGetPeerAddr(l, a->params.peeraddr, sizeof(a->params.peeraddr));
    case 0:
      break;        /* remember peer's TCP or UDP port */
    case PROTO_PAP:        PhysGetPeerPort(l, a->params.peerport, sizeof(a->params.peerport));
      PapStart(l, AUTH_PEER_TO_SELF);
      break;        /* remember peer's MAC address */
    case PROTO_CHAP:        PhysGetPeerMacAddr(l, a->params.peermacaddr, sizeof(a->params.peermacaddr));
      ChapStart(l, AUTH_PEER_TO_SELF);
      break;        /* remember peer's iface */
    case PROTO_EAP:        PhysGetPeerIface(l, a->params.peeriface, sizeof(a->params.peeriface));
      EapStart(l, AUTH_PEER_TO_SELF);
      break;        /* remember calling number */
    default:        PhysGetCallingNum(l, a->params.callingnum, sizeof(a->params.callingnum));
      assert(0);
  }        /* remember called number */
         PhysGetCalledNum(l, a->params.callednum, sizeof(a->params.callednum));
 
         Log(LG_AUTH, ("[%s] %s: auth: peer wants %s, I want %s",
             Pref(&l->lcp.fsm), Fsm(&l->lcp.fsm),
             a->self_to_peer ? ProtoName(a->self_to_peer) : "nothing",
             a->peer_to_self ? ProtoName(a->peer_to_self) : "nothing"));
 
         /* Is there anything to do? */
         if (!a->self_to_peer && !a->peer_to_self) {
                 LcpAuthResult(l, TRUE);
                 return;
         }
         /* Start global auth timer */
         TimerInit(&a->timer, "AuthTimer",
             l->lcp.auth.conf.timeout * SECONDS, AuthTimeout, l);
         TimerStart(&a->timer);
 
         /* Start my auth to him */
         switch (a->self_to_peer) {
         case 0:
                 break;
         case PROTO_PAP:
                 PapStart(l, AUTH_SELF_TO_PEER);
                 break;
         case PROTO_CHAP:
                 ChapStart(l, AUTH_SELF_TO_PEER);
                 break;
 #ifdef USE_RADIUS
         case PROTO_EAP:
                 EapStart(l, AUTH_SELF_TO_PEER);
                 break;
 #endif
         default:
                 assert(0);
         }
 
         /* Start his auth to me */
         switch (a->peer_to_self) {
         case 0:
                 break;
         case PROTO_PAP:
                 PapStart(l, AUTH_PEER_TO_SELF);
                 break;
         case PROTO_CHAP:
                 ChapStart(l, AUTH_PEER_TO_SELF);
                 break;
 #ifdef USE_RADIUS
         case PROTO_EAP:
                 EapStart(l, AUTH_PEER_TO_SELF);
                 break;
 #endif
         default:
                 assert(0);
         }
 }  }
   
 /*  /*
  * AuthInput()   * AuthInput()
  *   *
  * Deal with PAP/CHAP/EAP packet   * Deal with PAP/CHAP/EAP packet
    * But cannot be called for EAP packet if RADIUS support is not compiled in.
  */   */
   
 void  void
 AuthInput(Link l, int proto, Mbuf bp)  AuthInput(Link l, int proto, Mbuf bp)
 {  {
  AuthData              auth;        AuthData auth;
  int                   len;        struct fsmheader fsmh;
  struct fsmheader      fsmh;        u_char *pkt;
  u_char                *pkt;        char buf[16];
  char                  buf[16];        u_short len;
         uint16_t fsmh_len;
   
  /* Sanity check */        /* Sanity check */
  if (l->lcp.phase != PHASE_AUTHENTICATE && l->lcp.phase != PHASE_NETWORK) {        if (l->lcp.phase != PHASE_AUTHENTICATE && l->lcp.phase != PHASE_NETWORK) {
    Log(LG_AUTH, ("[%s] AUTH: rec'd stray packet", l->name));                Log(LG_ERR | LG_AUTH, ("[%s] AUTH: rec'd stray packet", l->name));
    mbfree(bp);                mbfree(bp);
    return;                return;
  }        }
         len = MBLEN(bp);
   
  len = MBLEN(bp);        /* Sanity check length */
         if (len < sizeof(fsmh)) {
                 Log(LG_ERR | LG_AUTH, ("[%s] AUTH: rec'd runt packet: %hu bytes",
                     l->name, len));
                 mbfree(bp);
                 return;
         }
   
  /* Sanity check length */        bp = mbread(bp, &fsmh, sizeof(fsmh));
  if (len < sizeof(fsmh)) { 
    Log(LG_AUTH, ("[%s] AUTH: rec'd runt packet: %d bytes", 
      l->name, len)); 
    mbfree(bp); 
    return; 
  } 
   
  auth = AuthDataNew(l);        fsmh_len = ntohs(fsmh.length);
  auth->proto = proto;        if (len > fsmh_len) {
                 /* Sanity check length */
                 if (fsmh_len < sizeof(fsmh)) {
                     Log(LG_ERR | LG_AUTH, ("[%s] AUTH: bad length: says %hu, rec'd %hu",
                         l->name, fsmh_len, len));
                     mbfree(bp);
                     return;
                 }
                 len = fsmh_len;
         }
   
  bp = mbread(bp, &fsmh, sizeof(fsmh));        len -= sizeof(fsmh);
  if (len > ntohs(fsmh.length))        pkt = MBDATA(bp);
    len = ntohs(fsmh.length); 
  len -= sizeof(fsmh); 
   
  pkt = MBDATA(bp);#ifdef USE_RADIUS
         if (proto == PROTO_EAP && bp) {
                 Log(LG_AUTH, ("[%s] %s: rec'd %s #%d len: %hu, type: %s", l->name,
                     ProtoName(proto), AuthCode(proto, fsmh.code, buf, sizeof(buf)), fsmh.id,
                     fsmh_len, EapType(pkt[0])));
         } else
 #endif
                 Log(LG_AUTH, ("[%s] %s: rec'd %s #%d len: %hu", l->name,
                     ProtoName(proto), AuthCode(proto, fsmh.code, buf, sizeof(buf)), fsmh.id,
                     fsmh_len));
   
  if (proto == PROTO_EAP && bp) {        auth = AuthDataNew(l);
    Log(LG_AUTH, ("[%s] %s: rec'd %s #%d len: %d, type: %s", l->name,        auth->proto = proto;
      ProtoName(proto), AuthCode(proto, fsmh.code, buf, sizeof(buf)), fsmh.id,        auth->id = fsmh.id;
        ntohs(fsmh.length), EapType(pkt[0])));        auth->code = fsmh.code;
  } else {        /* Status defaults to undefined */
    Log(LG_AUTH, ("[%s] %s: rec'd %s #%d len: %d", l->name,        auth->status = AUTH_STATUS_UNDEF;
      ProtoName(proto), AuthCode(proto, fsmh.code, buf, sizeof(buf)), fsmh.id, 
        ntohs(fsmh.length))); 
  } 
   
  auth->id = fsmh.id;        switch (proto) {
  auth->code = fsmh.code;        case PROTO_PAP:
  /* Status defaults to undefined */                PapInput(l, auth, pkt, len);
  auth->status = AUTH_STATUS_UNDEF;                break;
          case PROTO_CHAP:
  switch (proto) {                ChapInput(l, auth, pkt, len);
    case PROTO_PAP:                break;
      PapInput(l, auth, pkt, len);#ifdef USE_RADIUS
      break;        case PROTO_EAP:
    case PROTO_CHAP:                EapInput(l, auth, pkt, len);
      ChapInput(l, auth, pkt, len);                break;
      break;#endif
    case PROTO_EAP:        default:
      EapInput(l, auth, pkt, len);                assert(0);
      break;        }
    default:
      assert(0);        mbfree(bp);
  } 
   
  mbfree(bp); 
 }  }
   
 /*  /*
Line 506  AuthInput(Link l, int proto, Mbuf bp) Line 551  AuthInput(Link l, int proto, Mbuf bp)
   
 void  void
 AuthOutput(Link l, int proto, u_int code, u_int id, const u_char *ptr,  AuthOutput(Link l, int proto, u_int code, u_int id, const u_char *ptr,
        int len, int add_len, u_char eap_type)    int len, int add_len, u_char eap_type)
 {  {
  struct fsmheader      lh;        struct fsmheader lh;
  Mbuf                  bp;        Mbuf bp;
  int                   plen;        int plen;
  char                  buf[32];        char buf[32];
   
  add_len = !!add_len;        add_len = !!add_len;
  /* Setup header */        /* Setup header */
  if (proto == PROTO_EAP)        if (proto == PROTO_EAP)
    plen = sizeof(lh) + len + add_len + 1;                plen = sizeof(lh) + len + add_len + 1;
  else        else
    plen = sizeof(lh) + len + add_len;                plen = sizeof(lh) + len + add_len;
  lh.code = code;        lh.code = code;
  lh.id = id;        lh.id = id;
  lh.length = htons(plen);        lh.length = htons(plen);
   
  /* Build packet */        /* Build packet */
  bp = mbcopyback(NULL, 0, &lh, sizeof(lh));        bp = mbcopyback(NULL, 0, &lh, sizeof(lh));
  if (proto == PROTO_EAP)        if (proto == PROTO_EAP)
    bp = mbcopyback(bp, MBLEN(bp), &eap_type, 1);                bp = mbcopyback(bp, MBLEN(bp), &eap_type, 1);
  if (add_len) {        if (add_len) {
    u_char tl = len;                u_char tl = len;
    bp = mbcopyback(bp, MBLEN(bp), &tl, 1); 
  } 
  bp = mbcopyback(bp, MBLEN(bp), ptr, len); 
   
  if (proto == PROTO_EAP) {                bp = mbcopyback(bp, MBLEN(bp), &tl, 1);
    Log(LG_AUTH, ("[%s] %s: sending %s #%d len: %d, type: %s", l->name,        }
      ProtoName(proto), AuthCode(proto, code, buf, sizeof(buf)), id, plen, EapType(eap_type)));        bp = mbcopyback(bp, MBLEN(bp), ptr, len);
  } else { 
    Log(LG_AUTH, ("[%s] %s: sending %s #%d len: %d", l->name, 
      ProtoName(proto), AuthCode(proto, code, buf, sizeof(buf)), id, plen)); 
  } 
   
  /* Send it out */#ifdef USE_RADIUS
  NgFuncWritePppFrameLink(l, proto, bp);        if (proto == PROTO_EAP) {
                 Log(LG_AUTH, ("[%s] %s: sending %s #%d len: %d, type: %s", l->name,
                     ProtoName(proto), AuthCode(proto, code, buf, sizeof(buf)), id, plen, EapType(eap_type)));
         } else
 #endif
                 Log(LG_AUTH, ("[%s] %s: sending %s #%d len: %d", l->name,
                     ProtoName(proto), AuthCode(proto, code, buf, sizeof(buf)), id, plen));
 
         /* Send it out */
         NgFuncWritePppFrameLink(l, proto, bp);
 }  }
   
 /*  /*
Line 554  AuthOutput(Link l, int proto, u_int code, u_int id, co Line 601  AuthOutput(Link l, int proto, u_int code, u_int id, co
 void  void
 AuthFinish(Link l, int which, int ok)  AuthFinish(Link l, int which, int ok)
 {  {
    Auth        const a = &l->lcp.auth;        Auth const a = &l->lcp.auth;
   
    if (which == AUTH_SELF_TO_PEER)        if (which == AUTH_SELF_TO_PEER)
        a->self_to_peer = 0;                a->self_to_peer = 0;
    else        else
        a->peer_to_self = 0;                a->peer_to_self = 0;
    /* Did auth fail (in either direction)? */        /* Did auth fail (in either direction)? */
    if (!ok) {        if (!ok) {
        AuthStop(l);                AuthStop(l);
        LcpAuthResult(l, FALSE);                LcpAuthResult(l, FALSE);
        return;                return;
    }        }
    /* Did auth succeed (in both directions)? */        /* Did auth succeed (in both directions)? */
    if (!a->peer_to_self && !a->self_to_peer) {        if (!a->peer_to_self && !a->self_to_peer) {
        AuthStop(l);                AuthStop(l);
        LcpAuthResult(l, TRUE);                LcpAuthResult(l, TRUE);
        return;                return;
    }        }
 }  }
   
 /*  /*
Line 583  AuthFinish(Link l, int which, int ok) Line 630  AuthFinish(Link l, int which, int ok)
 void  void
 AuthCleanup(Link l)  AuthCleanup(Link l)
 {  {
    Auth        a = &l->lcp.auth;        Auth a = &l->lcp.auth;
   
    Log(LG_AUTH2, ("[%s] AUTH: Cleanup", l->name));        Log(LG_AUTH2, ("[%s] AUTH: Cleanup", l->name));
   
    authparamsDestroy(&a->params);        authparamsDestroy(&a->params);
   
    l->session_id[0] = 0;        l->session_id[0] = 0;
 }  }
   
/* /*
  * AuthDataNew()   * AuthDataNew()
  *   *
  * Create a new auth-data object   * Create a new auth-data object
  */   */
   
 AuthData  AuthData
AuthDataNew(Link l) AuthDataNew(Link l)
 {  {
    AuthData    auth;        AuthData auth;
    Auth        a = &l->lcp.auth;          Auth a = &l->lcp.auth;
   
    auth = Malloc(MB_AUTH, sizeof(*auth));        auth = Malloc(MB_AUTH, sizeof(*auth));
    auth->reply_message = NULL;        auth->reply_message = NULL;
    auth->mschap_error = NULL;        auth->mschap_error = NULL;
    auth->mschapv2resp = NULL;        auth->mschapv2resp = NULL;
    auth->conf = l->lcp.auth.conf;        auth->conf = l->lcp.auth.conf;
    if (l->lcp.auth.conf.extauth_script)        if (l->lcp.auth.conf.extauth_script)
        auth->conf.extauth_script = Mstrdup(MB_AUTH, l->lcp.auth.conf.extauth_script);                auth->conf.extauth_script = Mstrdup(MB_AUTH, l->lcp.auth.conf.extauth_script);
    if (l->lcp.auth.conf.extacct_script)        if (l->lcp.auth.conf.extacct_script)
        auth->conf.extacct_script = Mstrdup(MB_AUTH, l->lcp.auth.conf.extacct_script);                auth->conf.extacct_script = Mstrdup(MB_AUTH, l->lcp.auth.conf.extacct_script);
   
    strlcpy(auth->info.lnkname, l->name, sizeof(auth->info.lnkname));        strlcpy(auth->info.lnkname, l->name, sizeof(auth->info.lnkname));
    strlcpy(auth->info.msession_id, l->msession_id, sizeof(auth->info.msession_id));        strlcpy(auth->info.msession_id, l->msession_id, sizeof(auth->info.msession_id));
    strlcpy(auth->info.session_id, l->session_id, sizeof(auth->info.session_id));        strlcpy(auth->info.session_id, l->session_id, sizeof(auth->info.session_id));
    strlcpy(auth->info.peer_ident, l->lcp.peer_ident, sizeof(l->lcp.peer_ident));        strlcpy(auth->info.peer_ident, l->lcp.peer_ident, sizeof(l->lcp.peer_ident));
    auth->info.originate = l->originate;        auth->info.originate = l->originate;
    auth->info.downReason = NULL;        auth->info.downReason = NULL;
   
    if (l->bund) {        if (l->bund) {
        strlcpy(auth->info.ifname, l->bund->iface.ifname, sizeof(auth->info.ifname));                strlcpy(auth->info.ifname, l->bund->iface.ifname, sizeof(auth->info.ifname));
        auth->info.ifindex = l->bund->iface.ifindex;                auth->info.ifindex = l->bund->iface.ifindex;
        strlcpy(auth->info.bundname, l->bund->name, sizeof(auth->info.bundname));                strlcpy(auth->info.bundname, l->bund->name, sizeof(auth->info.bundname));
        auth->info.n_links = l->bund->n_links;                auth->info.n_links = l->bund->n_links;
        auth->info.peer_addr = l->bund->ipcp.peer_addr;                auth->info.peer_addr = l->bund->ipcp.peer_addr;
    }                bcopy(&auth->info.peer_addr6, &l->bund->ipv6cp.peer_addr, sizeof(struct in6_addr));
         }
         /* Copy current link statistics */
         memcpy(&auth->info.stats, &l->stats, sizeof(auth->info.stats));
   
     /* Copy current link statistics */  
     memcpy(&auth->info.stats, &l->stats, sizeof(auth->info.stats));  
       
 #ifdef USE_NG_BPF  #ifdef USE_NG_BPF
    /* If it is present copy services statistics */        /* If it is present copy services statistics */
    if (l->bund) {        if (l->bund) {
        IfaceGetStats(l->bund, &auth->info.ss);                IfaceGetStats(l->bund, &auth->info.ss);
        IfaceAddStats(&auth->info.ss, &l->bund->iface.prevstats);                IfaceAddStats(&auth->info.ss, &l->bund->iface.prevstats);
    }        }
 #endif  #endif
   
    if (l->downReasonValid)        if (l->downReasonValid)
        auth->info.downReason = Mstrdup(MB_AUTH, l->downReason);                auth->info.downReason = Mstrdup(MB_AUTH, l->downReason);
   
    auth->info.last_up = l->last_up;        auth->info.last_up = l->last_up;
    auth->info.phys_type = l->type;        auth->info.phys_type = l->type;
    auth->info.linkID = l->id;        auth->info.linkID = l->id;
   
    authparamsCopy(&a->params,&auth->params);        authparamsCopy(&a->params, &auth->params);
   
    return auth;        return auth;
 }  }
   
 /*  /*
Line 661  AuthDataNew(Link l)  Line 708  AuthDataNew(Link l) 
 void  void
 AuthDataDestroy(AuthData auth)  AuthDataDestroy(AuthData auth)
 {  {
    authparamsDestroy(&auth->params);        authparamsDestroy(&auth->params);
    Freee(auth->info.downReason);        Freee(auth->info.downReason);
    Freee(auth->reply_message);        Freee(auth->reply_message);
    Freee(auth->mschap_error);        Freee(auth->mschap_error);
    Freee(auth->mschapv2resp);        Freee(auth->mschapv2resp);
 #ifdef USE_NG_BPF  #ifdef USE_NG_BPF
    IfaceFreeStats(&auth->info.ss);        IfaceFreeStats(&auth->info.ss);
 #endif  #endif
    Freee(auth->conf.extauth_script);        Freee(auth->conf.extauth_script);
    Freee(auth->conf.extacct_script);        Freee(auth->conf.extacct_script);
    Freee(auth);        Freee(auth);
 }  }
   
 /*  /*
Line 683  AuthDataDestroy(AuthData auth) Line 730  AuthDataDestroy(AuthData auth)
 void  void
 AuthStop(Link l)  AuthStop(Link l)
 {  {
  Auth  a = &l->lcp.auth;        Auth a = &l->lcp.auth;
   
  TimerStop(&a->timer);        TimerStop(&a->timer);
  PapStop(&a->pap);        PapStop(&a->pap);
  ChapStop(&a->chap);        ChapStop(&a->chap);
  EapStop(&a->eap);#ifdef USE_RADIUS
  paction_cancel(&a->thread);        EapStop(&a->eap);
 #endif
         paction_cancel(&a->thread);
 }  }
   
 /*  /*
Line 697  AuthStop(Link l) Line 746  AuthStop(Link l)
  *   *
  * Show auth stats   * Show auth stats
  */   */
 
 int  int
AuthStat(Context ctx, int ac, char *av[], void *arg)AuthStat(Context ctx, int ac, const char *const av[], const void *arg)
 {  {
    Auth        const au = &ctx->lnk->lcp.auth;        Auth const au = &ctx->lnk->lcp.auth;
    AuthConf    const conf = &au->conf;        AuthConf const conf = &au->conf;
    char        buf[48], buf2[16];        char buf[48], buf2[16];
 
 #if defined(USE_IPFW) || defined(USE_NG_BPF)  #if defined(USE_IPFW) || defined(USE_NG_BPF)
    struct acl  *a;        struct acl *a;
 
 #endif  #endif
    IfaceRoute  r;        IfaceRoute r;
 
 #ifdef USE_NG_BPF  #ifdef USE_NG_BPF
    int         k;        int k;
 
 #endif  #endif
   
    Printf("Configuration:\r\n");        (void)ac;
    Printf("\tMy authname     : %s\r\n", conf->authname);        (void)av;
    Printf("\tMax-Logins      : %d%s\r\n", gMaxLogins, (gMaxLoginsCI?" CI":""));        (void)arg;
    Printf("\tAcct Update     : %d\r\n", conf->acct_update); 
    Printf("\t   Limit In     : %d\r\n", conf->acct_update_lim_recv); 
    Printf("\t   Limit Out    : %d\r\n", conf->acct_update_lim_xmit); 
    Printf("\tAuth timeout    : %d\r\n", conf->timeout); 
    Printf("\tExtAuth script  : %s\r\n", conf->extauth_script?conf->extauth_script:""); 
    Printf("\tExtAcct script  : %s\r\n", conf->extacct_script?conf->extacct_script:""); 
   
    Printf("Auth options\r\n"); 
    OptStat(ctx, &conf->options, gConfList); 
   
    Printf("Auth Data\r\n");        Printf("Configuration:\r\n");
    Printf("\tPeer authname   : %s\r\n", au->params.authname);        Printf("\tMy authname     : %s\r\n", conf->authname);
    Printf("\tInterface name  : %s\r\n", au->params.ifname);        Printf("\tMax-Logins      : %u%s\r\n", gMaxLogins, (gMaxLoginsCI ? " CI" : ""));
         Printf("\tAcct Update     : %d\r\n", conf->acct_update);
         Printf("\t   Limit In     : %d\r\n", conf->acct_update_lim_recv);
         Printf("\t   Limit Out    : %d\r\n", conf->acct_update_lim_xmit);
         Printf("\tAuth timeout    : %d\r\n", conf->timeout);
         Printf("\tExtAuth script  : %s\r\n", conf->extauth_script ? conf->extauth_script : "");
         Printf("\tExtAcct script  : %s\r\n", conf->extacct_script ? conf->extacct_script : "");
 
         Printf("Auth options\r\n");
         OptStat(ctx, &conf->options, gConfList);
 
         Printf("Auth Data\r\n");
         Printf("\tPeer authname   : %s\r\n", au->params.authname);
         Printf("\tInterface name  : %s\r\n", au->params.ifname);
 #ifdef SIOCSIFDESCR  #ifdef SIOCSIFDESCR
    Printf("\tInterface descr.: \"%s\"\r\n",         Printf("\tInterface descr.: \"%s\"\r\n",
        au->params.ifdescr != NULL ? au->params.ifdescr : "<none>");            au->params.ifdescr != NULL ? au->params.ifdescr : "<none>");
 #endif  #endif
 #ifdef SIOCAIFGROUP  #ifdef SIOCAIFGROUP
    Printf("\tInterface group : %s\r\n", au->params.ifgroup);        Printf("\tInterface group : %s\r\n", au->params.ifgroup);
 #endif  #endif
    Printf("\tIP range        : %s\r\n", (au->params.range_valid)?        Printf("\tIP range        : %s\r\n", (au->params.range_valid) ?
        u_rangetoa(&au->params.range,buf,sizeof(buf)):"");            u_rangetoa(&au->params.range, buf, sizeof(buf)) : "");
    Printf("\tIP pool         : %s\r\n", au->params.ippool);        Printf("\tIP pool         : %s\r\n", au->params.ippool);
    Printf("\tDNS             : %s %s\r\n",        Printf("\tDNS             : %s %s\r\n",
        inet_ntop(AF_INET, &au->params.peer_dns[0], buf, sizeof(buf)),            inet_ntop(AF_INET, &au->params.peer_dns[0], buf, sizeof(buf)),
        inet_ntop(AF_INET, &au->params.peer_dns[1], buf2, sizeof(buf2)));            inet_ntop(AF_INET, &au->params.peer_dns[1], buf2, sizeof(buf2)));
    Printf("\tNBNS            : %s %s\r\n",        Printf("\tNBNS            : %s %s\r\n",
        inet_ntop(AF_INET, &au->params.peer_nbns[0], buf, sizeof(buf)),            inet_ntop(AF_INET, &au->params.peer_nbns[0], buf, sizeof(buf)),
        inet_ntop(AF_INET, &au->params.peer_nbns[1], buf2, sizeof(buf2)));            inet_ntop(AF_INET, &au->params.peer_nbns[1], buf2, sizeof(buf2)));
    Printf("\tMTU             : %u\r\n", au->params.mtu);        Printf("\tVJ Compression  : %s\r\n", au->params.vjc_enable ? "yes" : "no");
    Printf("\tSession-Timeout : %u\r\n", au->params.session_timeout);        Printf("\tMTU             : %u\r\n", au->params.mtu);
    Printf("\tIdle-Timeout    : %u\r\n", au->params.idle_timeout);        Printf("\tSession-Timeout : %u\r\n", au->params.session_timeout);
    Printf("\tAcct-Update     : %u\r\n", au->params.acct_update);        Printf("\tIdle-Timeout    : %u\r\n", au->params.idle_timeout);
    Printf("\tRoutes          :\r\n");        Printf("\tAcct-Update     : %u\r\n", au->params.acct_update);
    SLIST_FOREACH(r, &au->params.routes, next) {        Printf("\tRoutes          :\r\n");
        Printf("\t\t%s\r\n", u_rangetoa(&r->dest,buf,sizeof(buf)));        SLIST_FOREACH(r, &au->params.routes, next) {
    }                Printf("\t\t%s\r\n", u_rangetoa(&r->dest, buf, sizeof(buf)));
         }
 #ifdef USE_IPFW  #ifdef USE_IPFW
    Printf("\tIPFW rules      :\r\n");        Printf("\tIPFW rules      :\r\n");
    a = au->params.acl_rule;        a = au->params.acl_rule;
    while (a) {        while (a) {
        Printf("\t\t%d\t: '%s'\r\n", a->number, a->rule);                Printf("\t\t%d\t: '%s'\r\n", a->number, a->rule);
        a = a->next;                a = a->next;
    } 
    Printf("\tIPFW pipes      :\r\n"); 
    a = au->params.acl_pipe; 
    while (a) { 
        Printf("\t\t%d\t: '%s'\r\n", a->number, a->rule); 
        a = a->next; 
    } 
    Printf("\tIPFW queues     :\r\n"); 
    a = au->params.acl_queue; 
    while (a) { 
        Printf("\t\t%d\t: '%s'\r\n", a->number, a->rule); 
        a = a->next; 
    } 
    Printf("\tIPFW tables     :\r\n"); 
    a = au->params.acl_table; 
    while (a) { 
        if (a->number != 0) 
            Printf("\t\t%d\t: '%s'\r\n", a->number, a->rule); 
        else 
            Printf("\t\t#%d\t: '%s'\r\n", a->real_number, a->rule); 
        a = a->next; 
    } 
#endif /* USE_IPFW */ 
#ifdef USE_NG_BPF 
    Printf("\tTraffic filters :\r\n"); 
    for (k = 0; k < ACL_FILTERS; k++) { 
        a = au->params.acl_filters[k]; 
        while (a) { 
            Printf("\t%d#%d\t: '%s'\r\n", (k + 1), a->number, a->rule); 
            a = a->next; 
         }          }
    }        Printf("\tIPFW pipes      :\r\n");
    Printf("\tTraffic limits  :\r\n");        a = au->params.acl_pipe;
    for (k = 0; k < 2; k++) { 
        a = au->params.acl_limits[k]; 
         while (a) {          while (a) {
            Printf("\t\t%s#%d%s%s\t: '%s'\r\n", (k?"out":"in"), a->number,                Printf("\t\t%d\t: '%s'\r\n", a->number, a->rule);
                ((a->name[0])?"#":""), a->name, a->rule);                a = a->next;
            a = a->next; 
         }          }
    }        Printf("\tIPFW queues     :\r\n");
#endif /* USE_NG_BPF */        a = au->params.acl_queue;
    Printf("\tMS-Domain       : %s\r\n", au->params.msdomain);          while (a) {
    Printf("\tMPPE Types      : %s\r\n", AuthMPPEPolicyname(au->params.msoft.policy));                Printf("\t\t%d\t: '%s'\r\n", a->number, a->rule);
    Printf("\tMPPE Policy     : %s\r\n", AuthMPPETypesname(au->params.msoft.types, buf, sizeof(buf)));                a = a->next;
    Printf("\tMPPE Keys       : %s\r\n", au->params.msoft.has_keys ? "yes" : "no");        }
         Printf("\tIPFW tables     :\r\n");
         a = au->params.acl_table;
         while (a) {
                 if (a->number != 0)
                         Printf("\t\t%d\t: '%s'\r\n", a->number, a->rule);
                 else
                         Printf("\t\t#%d\t: '%s'\r\n", a->real_number, a->rule);
                 a = a->next;
         }
 #endif                                  /* USE_IPFW */
 #ifdef USE_NG_BPF
         Printf("\tTraffic filters :\r\n");
         for (k = 0; k < ACL_FILTERS; k++) {
                 a = au->params.acl_filters[k];
                 while (a) {
                         Printf("\t%d#%d\t: '%s'\r\n", (k + 1), a->number, a->rule);
                         a = a->next;
                 }
         }
         Printf("\tTraffic limits  :\r\n");
         for (k = 0; k < 2; k++) {
                 a = au->params.acl_limits[k];
                 while (a) {
                         Printf("\t\t%s#%d%s%s\t: '%s'\r\n", (k ? "out" : "in"), a->number,
                             ((a->name[0]) ? "#" : ""), a->name, a->rule);
                         a = a->next;
                 }
         }
 #endif                                        /* USE_NG_BPF */
         Printf("\tMS-Domain       : %s\r\n", au->params.msdomain);
         Printf("\tMPPE Types      : %s\r\n", AuthMPPEPolicyname(au->params.msoft.policy));
         Printf("\tMPPE Policy     : %s\r\n", AuthMPPETypesname(au->params.msoft.types, buf, sizeof(buf)));
         Printf("\tMPPE Keys       : %s\r\n", au->params.msoft.has_keys ? "yes" : "no");
   
    return (0);        return (0);
 }  }
   
   
 /*  /*
  * AuthAccount()   * AuthAccount()
  *   *
 * Accounting stuff,  * Accounting stuff,
  */   */
 
 void  void
 AuthAccountStart(Link l, int type)  AuthAccountStart(Link l, int type)
 {  {
    Auth                const a = &l->lcp.auth;        Auth const a = &l->lcp.auth;
    AuthData            auth;        AuthData auth;
      
    /* maybe an outstanding thread is running */        /* maybe an outstanding thread is running */
    if (a->acct_thread) {        if (a->acct_thread) {
        if (type == AUTH_ACCT_START || type == AUTH_ACCT_STOP) {                if (type == AUTH_ACCT_START || type == AUTH_ACCT_STOP) {
            paction_cancel(&a->acct_thread);                        paction_cancel(&a->acct_thread);
        } else {                } else {
            Log(LG_AUTH2, ("[%s] ACCT: Accounting thread is already running",                         Log(LG_AUTH2, ("[%s] ACCT: Accounting thread is already running",
                l->name));                            l->name));
            return;                        return;
                 }
         }          }
    }        LinkUpdateStats(l);
         if (type == AUTH_ACCT_STOP) {
                 Log(LG_AUTH2, ("[%s] ACCT: Accounting data for user '%s': %lu seconds, %llu octets in, %llu octets out",
                     l->name, a->params.authname,
                     (unsigned long)(time(NULL) - l->last_up),
                     (unsigned long long)l->stats.recvOctets,
                     (unsigned long long)l->stats.xmitOctets));
         }
         if (type == AUTH_ACCT_START) {
                 u_int updateInterval;
   
    LinkUpdateStats(l);                if (a->params.acct_update > 0)
    if (type == AUTH_ACCT_STOP) {                        updateInterval = a->params.acct_update;
        Log(LG_AUTH2, ("[%s] ACCT: Accounting data for user '%s': %lu seconds, %llu octets in, %llu octets out",                else
            l->name, a->params.authname,                        updateInterval = a->conf.acct_update;
            (unsigned long) (time(NULL) - l->last_up), 
            (unsigned long long)l->stats.recvOctets, 
            (unsigned long long)l->stats.xmitOctets)); 
    } 
   
    if (type == AUTH_ACCT_START) {                if (updateInterval > 0) {
        u_int           updateInterval;                        /* Save initial statistics. */
                          memcpy(&a->prev_stats, &l->stats,
        if (a->params.acct_update > 0)                            sizeof(a->prev_stats));
            updateInterval = a->params.acct_update; 
        else 
            updateInterval = a->conf.acct_update; 
   
        if (updateInterval > 0) {                        /* Start accounting update timer. */
            /* Save initial statistics. */                        TimerInit(&a->acct_timer, "AuthAccountTimer",
            memcpy(&a->prev_stats, &l->stats,                             updateInterval * SECONDS, AuthAccountTimeout, l);
                sizeof(a->prev_stats));                        TimerStartRecurring(&a->acct_timer);
                }
            /* Start accounting update timer. */ 
            TimerInit(&a->acct_timer, "AuthAccountTimer", 
                updateInterval * SECONDS, AuthAccountTimeout, l); 
            TimerStartRecurring(&a->acct_timer); 
         }          }
    }        if (type == AUTH_ACCT_UPDATE) {
                  /*
    if (type == AUTH_ACCT_UPDATE) {                * Suppress sending of accounting update, if byte threshold
        /*                * is configured, and delta since last update doesn't exceed it.
        * Suppress sending of accounting update, if byte threshold                */
        * is configured, and delta since last update doesn't exceed it.                u_int lim_recv, lim_xmit;
        */ 
        u_int   lim_recv, lim_xmit; 
   
        if (a->params.acct_update_lim_recv > 0)                if (a->params.acct_update_lim_recv > 0)
            lim_recv = a->params.acct_update_lim_recv;                        lim_recv = a->params.acct_update_lim_recv;
        else                else
            lim_recv = a->conf.acct_update_lim_recv;                        lim_recv = a->conf.acct_update_lim_recv;
        if (a->params.acct_update_lim_xmit > 0)                if (a->params.acct_update_lim_xmit > 0)
            lim_xmit = a->params.acct_update_lim_xmit;                        lim_xmit = a->params.acct_update_lim_xmit;
        else                else
            lim_xmit = a->conf.acct_update_lim_xmit;                        lim_xmit = a->conf.acct_update_lim_xmit;
        if (lim_recv > 0 || lim_xmit > 0) {                if (lim_recv > 0 || lim_xmit > 0) {
            if ((l->stats.recvOctets - a->prev_stats.recvOctets < lim_recv) &&                        if ((l->stats.recvOctets - a->prev_stats.recvOctets < lim_recv) &&
                    (l->stats.xmitOctets - a->prev_stats.xmitOctets < lim_xmit)) {                            (l->stats.xmitOctets - a->prev_stats.xmitOctets < lim_xmit)) {
                Log(LG_AUTH2, ("[%s] ACCT: Shouldn't send Interim-Update", l->name));                                Log(LG_AUTH2, ("[%s] ACCT: Shouldn't send Interim-Update", l->name));
                return;                                return;
            } else {                        } else {
                /* Save current statistics. */                                /* Save current statistics. */
                memcpy(&a->prev_stats, &l->stats, sizeof(a->prev_stats));                                memcpy(&a->prev_stats, &l->stats, sizeof(a->prev_stats));
            }                        }
                 }
         }          }
    }        if (type == AUTH_ACCT_STOP) {
                    /* Stop accounting update timer if running. */
    if (type == AUTH_ACCT_STOP) {                TimerStop(&a->acct_timer);
        /* Stop accounting update timer if running. */        }
        TimerStop(&a->acct_timer);        if (Enabled(&a->conf.options, AUTH_CONF_RADIUS_ACCT) ||
    } 
 
    if (Enabled(&a->conf.options, AUTH_CONF_RADIUS_ACCT) || 
 #ifdef USE_PAM  #ifdef USE_PAM
        Enabled(&a->conf.options, AUTH_CONF_PAM_ACCT) ||            Enabled(&a->conf.options, AUTH_CONF_PAM_ACCT) ||
 #endif  #endif
 #ifdef USE_SYSTEM  #ifdef USE_SYSTEM
        Enabled(&a->conf.options, AUTH_CONF_SYSTEM_ACCT) ||            Enabled(&a->conf.options, AUTH_CONF_SYSTEM_ACCT) ||
 #endif  #endif
        Enabled(&a->conf.options, AUTH_CONF_EXT_ACCT)) {            Enabled(&a->conf.options, AUTH_CONF_EXT_ACCT)) {
     
        auth = AuthDataNew(l); 
        auth->acct_type = type; 
   
        if (paction_start(&a->acct_thread, &gGiantMutex, AuthAccount,                 auth = AuthDataNew(l);
                AuthAccountFinish, auth) == -1) {                auth->acct_type = type;
            Perror("[%s] ACCT: Couldn't start thread", l->name); 
            AuthDataDestroy(auth); 
        } 
    } 
   
                   if (paction_start(&a->acct_thread, &gGiantMutex, AuthAccount,
                       AuthAccountFinish, auth) == -1) {
                           Perror("[%s] ACCT: Couldn't start thread", l->name);
                           AuthDataDestroy(auth);
                   }
           }
 }  }
   
 /*  /*
Line 919  AuthAccountStart(Link l, int type) Line 971  AuthAccountStart(Link l, int type)
  *   *
  * Timer function for accounting updates   * Timer function for accounting updates
  */   */
 
 void  void
 AuthAccountTimeout(void *arg)  AuthAccountTimeout(void *arg)
 {  {
    Link        l = (Link)arg;        Link l = (Link) arg;
   
    Log(LG_AUTH2, ("[%s] ACCT: Time for Accounting Update", 
        l->name)); 
   
    AuthAccountStart(l, AUTH_ACCT_UPDATE);        Log(LG_AUTH2, ("[%s] ACCT: Time for Accounting Update",
             l->name));
 
         AuthAccountStart(l, AUTH_ACCT_UPDATE);
 }  }
   
 /*  /*
Line 937  AuthAccountTimeout(void *arg) Line 989  AuthAccountTimeout(void *arg)
  * Asynchr. accounting handler, called from a paction.   * Asynchr. accounting handler, called from a paction.
  * NOTE: Thread safety is needed here   * NOTE: Thread safety is needed here
  */   */
 
 static void  static void
 AuthAccount(void *arg)  AuthAccount(void *arg)
 {  {
    AuthData    const auth = (AuthData)arg;        AuthData const auth = (AuthData) arg;
    int         err = 0;        int err = 0;
  
    Log(LG_AUTH2, ("[%s] ACCT: Thread started", auth->info.lnkname));        Log(LG_AUTH2, ("[%s] ACCT: Thread started", auth->info.lnkname));
  
    if (Enabled(&auth->conf.options, AUTH_CONF_RADIUS_ACCT))#ifdef USE_RADIUS
        err |= RadiusAccount(auth);        if (Enabled(&auth->conf.options, AUTH_CONF_RADIUS_ACCT))
                 err |= RadiusAccount(auth);
 #endif
 #ifdef USE_PAM  #ifdef USE_PAM
    if (Enabled(&auth->conf.options, AUTH_CONF_PAM_ACCT))        if (Enabled(&auth->conf.options, AUTH_CONF_PAM_ACCT))
        err |= AuthPAMAcct(auth);                err |= AuthPAMAcct(auth);
 #endif  #endif
 #ifdef USE_SYSTEM  #ifdef USE_SYSTEM
    if (Enabled(&auth->conf.options, AUTH_CONF_SYSTEM_ACCT))        if (Enabled(&auth->conf.options, AUTH_CONF_SYSTEM_ACCT))
        err |= AuthSystemAcct(auth);                err |= AuthSystemAcct(auth);
 #endif  #endif
    if (Enabled(&auth->conf.options, AUTH_CONF_EXT_ACCT))        if (Enabled(&auth->conf.options, AUTH_CONF_EXT_ACCT))
        err |= AuthExternalAcct(auth);                err |= AuthExternalAcct(auth);
        
    if (err != 0 && auth->acct_type == AUTH_ACCT_START &&        if (err != 0 && auth->acct_type == AUTH_ACCT_START &&
             Enabled(&auth->conf.options, AUTH_CONF_ACCT_MANDATORY)) {              Enabled(&auth->conf.options, AUTH_CONF_ACCT_MANDATORY)) {
        Log(LG_AUTH, ("[%s] ACCT: Close link due to accounting start error",                 Log(LG_AUTH, ("[%s] ACCT: Close link due to accounting start error",
            auth->info.lnkname));                    auth->info.lnkname));
        auth->drop_user = 1;                auth->drop_user = 1;
    }        }
 }  }
   
 /*  /*
  * AuthAccountFinish   * AuthAccountFinish
 *  *
  * Return point for the accounting thread()   * Return point for the accounting thread()
  */   */
 
 static void  static void
 AuthAccountFinish(void *arg, int was_canceled)  AuthAccountFinish(void *arg, int was_canceled)
 {  {
    AuthData            auth = (AuthData)arg;        AuthData auth = (AuthData) arg;
    Link                l;        Link l;
   
    if (was_canceled) {        if (was_canceled) {
        Log(LG_AUTH2, ("[%s] ACCT: Thread was canceled",                 Log(LG_AUTH2, ("[%s] ACCT: Thread was canceled",
            auth->info.lnkname));                    auth->info.lnkname));
    } else {        } else {
        Log(LG_AUTH2, ("[%s] ACCT: Thread finished normally",                 Log(LG_AUTH2, ("[%s] ACCT: Thread finished normally",
            auth->info.lnkname));                    auth->info.lnkname));
    }        }
     
    /* Cleanup */ 
    RadiusClose(auth); 
   
    if (was_canceled) {#ifdef USE_RADIUS
        AuthDataDestroy(auth);        /* Cleanup */
        return;        RadiusClose(auth);
    }  #endif
     
    l = gLinks[auth->info.linkID]; 
    if (l == NULL) { 
        AuthDataDestroy(auth); 
        return; 
    }     
   
    if (auth->drop_user && auth->acct_type != AUTH_ACCT_STOP) {        if (was_canceled) {
        Log(LG_AUTH, ("[%s] ACCT: Link close requested by the accounting",                 AuthDataDestroy(auth);
            l->name));                return;
        RecordLinkUpDownReason(NULL, l, 0, STR_MANUALLY, NULL);        }
        LinkClose(l);        l = gLinks[auth->info.linkID];
    }        if (l == NULL) {
    AuthDataDestroy(auth);                AuthDataDestroy(auth);
    LinkShutdownCheck(l, l->lcp.fsm.state);                return;
         }
         if (auth->drop_user && auth->acct_type != AUTH_ACCT_STOP) {
                 Log(LG_AUTH, ("[%s] ACCT: Link close requested by the accounting",
                     l->name));
                 RecordLinkUpDownReason(NULL, l, 0, STR_MANUALLY, NULL);
                 LinkClose(l);
         }
         AuthDataDestroy(auth);
         LinkShutdownCheck(l, l->lcp.fsm.state);
 }  }
   
 /*  /*
Line 1018  AuthAccountFinish(void *arg, int was_canceled) Line 1072  AuthAccountFinish(void *arg, int was_canceled)
  */   */
   
 int  int
AuthGetData(char *authname, char *password, size_t passlen, AuthGetData(char *authname, char *password, size_t passlen,
     struct u_range *range, u_char *range_valid)      struct u_range *range, u_char *range_valid)
 {  {
  FILE          *fp;        FILE *fp;
  int           ac;        int ac;
  char          *av[20];        char *av[20];
  char          *line;        char *line;
   
  /* Check authname, must be non-empty */        /* Check authname, must be non-empty */
  if (authname == NULL || authname[0] == 0) {        if (authname == NULL || authname[0] == 0) {
    return(-1);                return (-1);
  } 
 
  /* Search secrets file */ 
  if ((fp = OpenConfFile(SECRET_FILE, NULL)) == NULL) 
    return(-1); 
  while ((line = ReadFullLine(fp, NULL, NULL, 0)) != NULL) { 
    memset(av, 0, sizeof(av)); 
    ac = ParseLine(line, av, sizeof(av) / sizeof(*av), 1); 
    Freee(line); 
    if (ac >= 2 
        && (strcmp(av[0], authname) == 0 
         || (av[1][0] == '!' && strcmp(av[0], "*") == 0))) { 
      if (av[1][0] == '!') {            /* external auth program */ 
        if (AuthGetExternalPassword((av[1]+1),  
            authname, password, passlen) == -1) { 
          FreeArgs(ac, av); 
          fclose(fp); 
          return(-1); 
         }          }
      } else {        /* Search secrets file */
        strlcpy(password, av[1], passlen);        if ((fp = OpenConfFile(SECRET_FILE, NULL)) == NULL)
      }                return (-1);
      if (range != NULL && range_valid != NULL) {        while ((line = ReadFullLine(fp, NULL, NULL, 0)) != NULL) {
        u_rangeclear(range);                memset(av, 0, sizeof(av));
        if (ac >= 3)                ac = ParseLine(line, av, sizeof(av) / sizeof(*av), 1);
            *range_valid = ParseRange(av[2], range, ALLOW_IPV4);                Freee(line);
        else                if (ac >= 2
            *range_valid = FALSE;                    && (strcmp(av[0], authname) == 0
      }                    || (av[1][0] == '!' && strcmp(av[0], "*") == 0))) {
      FreeArgs(ac, av);                        if (av[1][0] == '!') {  /* external auth program */
      fclose(fp);                                if (AuthGetExternalPassword((av[1] + 1),
      return(0);                                    authname, password, passlen) == -1) {
    }                                        FreeArgs(ac, av);
    FreeArgs(ac, av);                                        fclose(fp);
  }                                        return (-1);
  fclose(fp);                                }
                         } else {
                                 strlcpy(password, av[1], passlen);
                         }
                         if (range != NULL && range_valid != NULL) {
                                 u_rangeclear(range);
                                 if (ac >= 3)
                                         *range_valid = ParseRange(av[2], range, ALLOW_IPV4);
                                 else
                                         *range_valid = FALSE;
                         }
                         FreeArgs(ac, av);
                         fclose(fp);
                         return (0);
                 }
                 FreeArgs(ac, av);
         }
         fclose(fp);
   
  return(-1);           /* Invalid */        return (-1);                   /* Invalid */
 }  }
   
 /*  /*
Line 1075  AuthGetData(char *authname, char *password, size_t pas Line 1128  AuthGetData(char *authname, char *password, size_t pas
  * Starts the Auth-Thread   * Starts the Auth-Thread
  */   */
   
void void
 AuthAsyncStart(Link l, AuthData auth)  AuthAsyncStart(Link l, AuthData auth)
 {  {
    Auth        const a = &l->lcp.auth;        Auth const a = &l->lcp.auth;
    const char  *rept;        const char *rept;
    
    /* Check link action */        /* Check link action */
    rept = LinkMatchAction(l, 2, auth->params.authname);        rept = LinkMatchAction(l, 2, auth->params.authname);
    if (rept) {        if (rept) {
        if (strcmp(rept,"##DROP##") == 0) {                if (strcmp(rept, "##DROP##") == 0) {
            /* Action told we must drop this connection */                        /* Action told we must drop this connection */
            Log(LG_AUTH, ("[%s] Drop connection", l->name));                        Log(LG_AUTH, ("[%s] Drop connection", l->name));
            PhysClose(l);                        PhysClose(l);
            AuthDataDestroy(auth);                        AuthDataDestroy(auth);
            return;                        return;
                 }
                 /* Action told we must forward this connection */
                 if (RepCreate(l, rept)) {
                         Log(LG_ERR, ("[%s] Repeater to \"%s\" creation error", l->name, rept));
                         PhysClose(l);
                         AuthDataDestroy(auth);
                         return;
                 }
                 /* Create repeater */
                 RepIncoming(l);
                 /* Reconnect link netgraph hook to repeater */
                 LinkNgToRep(l);
                 /* Kill the LCP */
                 LcpDown(l);
                 LcpClose(l);
                 AuthDataDestroy(auth);
                 return;
         }          }
                /* Check if we are ready to process request. */
        /* Action told we must forward this connection */        if (a->thread) {
        if (RepCreate(l, rept)) {                auth->status = AUTH_STATUS_BUSY;
            Log(LG_ERR, ("[%s] Repeater to \"%s\" creation error", l->name, rept));                auth->finish(l, auth);
            PhysClose(l);                return;
            AuthDataDestroy(auth); 
            return; 
         }          }
        /* Create repeater */        /* perform pre authentication checks (single-login, etc.) */
        RepIncoming(l);        if (AuthPreChecks(auth) < 0) {
        /* Reconnect link netgraph hook to repeater */                Log(LG_AUTH, ("[%s] AUTH: AuthPreCheck failed for \"%s\"",
        LinkNgToRep(l);                    l->name, auth->params.authname));
        /* Kill the LCP */                auth->finish(l, auth);
        LcpDown(l);                return;
        LcpClose(l);        }
        AuthDataDestroy(auth);        if (paction_start(&a->thread, &gGiantMutex, AuthAsync,
        return;            AuthAsyncFinish, auth) == -1) {
    }                Perror("[%s] AUTH: Couldn't start thread", l->name);
                auth->status = AUTH_STATUS_FAIL;
    /* Check if we are ready to process request. */                auth->why_fail = AUTH_FAIL_NOT_EXPECTED;
    if (a->thread) {                auth->finish(l, auth);
        auth->status = AUTH_STATUS_BUSY;        }
        auth->finish(l, auth); 
        return; 
    } 
   
    /* perform pre authentication checks (single-login, etc.) */ 
    if (AuthPreChecks(auth) < 0) { 
        Log(LG_AUTH, ("[%s] AUTH: AuthPreCheck failed for \"%s\"",  
            l->name, auth->params.authname)); 
        auth->finish(l, auth); 
        return; 
    } 
 
    if (paction_start(&a->thread, &gGiantMutex, AuthAsync,  
        AuthAsyncFinish, auth) == -1) { 
        Perror("[%s] AUTH: Couldn't start thread", l->name); 
        auth->status = AUTH_STATUS_FAIL; 
        auth->why_fail = AUTH_FAIL_NOT_EXPECTED; 
        auth->finish(l, auth); 
    } 
 }  }
   
 /*  /*
Line 1140  AuthAsyncStart(Link l, AuthData auth) Line 1189  AuthAsyncStart(Link l, AuthData auth)
  * Asynchr. auth handler, called from a paction.   * Asynchr. auth handler, called from a paction.
  * NOTE: Thread safety is needed here   * NOTE: Thread safety is needed here
  */   */
 
 static void  static void
 AuthAsync(void *arg)  AuthAsync(void *arg)
 {  {
    AuthData    const auth = (AuthData)arg;        AuthData const auth = (AuthData) arg;
   
    Log(LG_AUTH2, ("[%s] AUTH: Thread started", auth->info.lnkname));        Log(LG_AUTH2, ("[%s] AUTH: Thread started", auth->info.lnkname));
   
    if (Enabled(&auth->conf.options, AUTH_CONF_EXT_AUTH)) {        if (Enabled(&auth->conf.options, AUTH_CONF_EXT_AUTH)) {
        auth->params.authentic = AUTH_CONF_EXT_AUTH;                auth->params.authentic = AUTH_CONF_EXT_AUTH;
        Log(LG_AUTH, ("[%s] AUTH: Trying EXTERNAL", auth->info.lnkname));                Log(LG_AUTH, ("[%s] AUTH: Trying EXTERNAL", auth->info.lnkname));
        if (AuthExternal(auth)) {                if (AuthExternal(auth)) {
            Log(LG_AUTH, ("[%s] AUTH: EXTERNAL returned error",                        Log(LG_ERR | LG_AUTH, ("[%s] AUTH: EXTERNAL returned error",
                auth->info.lnkname));                            auth->info.lnkname));
        } else {                } else {
            Log(LG_AUTH, ("[%s] AUTH: EXTERNAL returned: %s",                        Log(LG_AUTH, ("[%s] AUTH: EXTERNAL returned: %s",
                auth->info.lnkname, AuthStatusText(auth->status)));                            auth->info.lnkname, AuthStatusText(auth->status)));
            if (auth->status == AUTH_STATUS_SUCCESS                         if (auth->status == AUTH_STATUS_SUCCESS
                    || auth->status == AUTH_STATUS_UNDEF)                            || auth->status == AUTH_STATUS_UNDEF)
                                 return;
                 }
         }
 #ifdef USE_RADIUS
         if (auth->proto == PROTO_EAP && auth->eap_radius) {
                 auth->params.authentic = AUTH_CONF_RADIUS_AUTH;
                 RadiusEapProxy(auth);
                 return;                  return;
           } else if (Enabled(&auth->conf.options, AUTH_CONF_RADIUS_AUTH)) {
                   auth->params.authentic = AUTH_CONF_RADIUS_AUTH;
                   Log(LG_AUTH, ("[%s] AUTH: Trying RADIUS", auth->info.lnkname));
                   if (RadiusAuthenticate(auth)) {
                           Log(LG_ERR | LG_AUTH, ("[%s] AUTH: RADIUS returned error",
                               auth->info.lnkname));
                   } else {
                           Log(LG_AUTH, ("[%s] AUTH: RADIUS returned: %s",
                               auth->info.lnkname, AuthStatusText(auth->status)));
                           if (auth->status == AUTH_STATUS_SUCCESS)
                                   return;
                   }
         }          }
    }#endif
 
    if (auth->proto == PROTO_EAP && auth->eap_radius) { 
        auth->params.authentic = AUTH_CONF_RADIUS_AUTH; 
        RadiusEapProxy(auth); 
        return; 
    } else if (Enabled(&auth->conf.options, AUTH_CONF_RADIUS_AUTH)) { 
        auth->params.authentic = AUTH_CONF_RADIUS_AUTH; 
        Log(LG_AUTH, ("[%s] AUTH: Trying RADIUS", auth->info.lnkname)); 
        if (RadiusAuthenticate(auth)) { 
            Log(LG_AUTH, ("[%s] AUTH: RADIUS returned error", 
                auth->info.lnkname)); 
        } else { 
            Log(LG_AUTH, ("[%s] AUTH: RADIUS returned: %s",  
                auth->info.lnkname, AuthStatusText(auth->status))); 
            if (auth->status == AUTH_STATUS_SUCCESS) 
                return; 
        } 
    } 
   
 #ifdef USE_PAM  #ifdef USE_PAM
  if (Enabled(&auth->conf.options, AUTH_CONF_PAM_AUTH)) {        if (Enabled(&auth->conf.options, AUTH_CONF_PAM_AUTH)) {
    auth->params.authentic = AUTH_CONF_PAM_AUTH;                auth->params.authentic = AUTH_CONF_PAM_AUTH;
    Log(LG_AUTH, ("[%s] AUTH: Trying PAM", auth->info.lnkname));                Log(LG_AUTH, ("[%s] AUTH: Trying PAM", auth->info.lnkname));
    AuthPAM(auth);                AuthPAM(auth);
    Log(LG_AUTH, ("[%s] AUTH: PAM returned: %s",                 Log(LG_AUTH, ("[%s] AUTH: PAM returned: %s",
      auth->info.lnkname, AuthStatusText(auth->status)));                    auth->info.lnkname, AuthStatusText(auth->status)));
    if (auth->status == AUTH_STATUS_SUCCESS                 if (auth->status == AUTH_STATUS_SUCCESS
      || auth->status == AUTH_STATUS_UNDEF)                    || auth->status == AUTH_STATUS_UNDEF)
        return;                        return;
  }        }
 #endif  #endif
   
 #ifdef USE_SYSTEM  #ifdef USE_SYSTEM
  if (Enabled(&auth->conf.options, AUTH_CONF_SYSTEM_AUTH)) {        if (Enabled(&auth->conf.options, AUTH_CONF_SYSTEM_AUTH)) {
    auth->params.authentic = AUTH_CONF_SYSTEM_AUTH;                auth->params.authentic = AUTH_CONF_SYSTEM_AUTH;
    Log(LG_AUTH, ("[%s] AUTH: Trying SYSTEM", auth->info.lnkname));                Log(LG_AUTH, ("[%s] AUTH: Trying SYSTEM", auth->info.lnkname));
    AuthSystem(auth);                AuthSystem(auth);
    Log(LG_AUTH, ("[%s] AUTH: SYSTEM returned: %s",                 Log(LG_AUTH, ("[%s] AUTH: SYSTEM returned: %s",
      auth->info.lnkname, AuthStatusText(auth->status)));                    auth->info.lnkname, AuthStatusText(auth->status)));
    if (auth->status == AUTH_STATUS_SUCCESS                 if (auth->status == AUTH_STATUS_SUCCESS
      || auth->status == AUTH_STATUS_UNDEF)                    || auth->status == AUTH_STATUS_UNDEF)
        return;                        return;
  }        }
 #endif  #endif
  
 #ifdef USE_OPIE  #ifdef USE_OPIE
  if (Enabled(&auth->conf.options, AUTH_CONF_OPIE)) {        if (Enabled(&auth->conf.options, AUTH_CONF_OPIE)) {
    auth->params.authentic = AUTH_CONF_OPIE;                auth->params.authentic = AUTH_CONF_OPIE;
    Log(LG_AUTH, ("[%s] AUTH: Trying OPIE", auth->info.lnkname));                Log(LG_AUTH, ("[%s] AUTH: Trying OPIE", auth->info.lnkname));
    AuthOpie(auth);                AuthOpie(auth);
    Log(LG_AUTH, ("[%s] AUTH: OPIE returned: %s",                 Log(LG_AUTH, ("[%s] AUTH: OPIE returned: %s",
      auth->info.lnkname, AuthStatusText(auth->status)));                    auth->info.lnkname, AuthStatusText(auth->status)));
    if (auth->status == AUTH_STATUS_SUCCESS                 if (auth->status == AUTH_STATUS_SUCCESS
      || auth->status == AUTH_STATUS_UNDEF)                    || auth->status == AUTH_STATUS_UNDEF)
        return;                        return;
  }            }
#endif /* USE_OPIE */#endif                                  /* USE_OPIE */
   
  if (Enabled(&auth->conf.options, AUTH_CONF_INTERNAL)) { 
    auth->params.authentic = AUTH_CONF_INTERNAL; 
    Log(LG_AUTH, ("[%s] AUTH: Trying INTERNAL", auth->info.lnkname)); 
    AuthInternal(auth); 
    Log(LG_AUTH, ("[%s] AUTH: INTERNAL returned: %s",  
      auth->info.lnkname, AuthStatusText(auth->status))); 
    if (auth->status == AUTH_STATUS_SUCCESS  
      || auth->status == AUTH_STATUS_UNDEF) 
         return; 
  }  
   
  Log(LG_AUTH, ("[%s] AUTH: ran out of backends", auth->info.lnkname));        if (Enabled(&auth->conf.options, AUTH_CONF_INTERNAL)) {
  auth->status = AUTH_STATUS_FAIL;                auth->params.authentic = AUTH_CONF_INTERNAL;
  auth->why_fail = AUTH_FAIL_INVALID_LOGIN;                Log(LG_AUTH, ("[%s] AUTH: Trying INTERNAL", auth->info.lnkname));
                 AuthInternal(auth);
                 Log(LG_AUTH, ("[%s] AUTH: INTERNAL returned: %s",
                     auth->info.lnkname, AuthStatusText(auth->status)));
                 if (auth->status == AUTH_STATUS_SUCCESS
                     || auth->status == AUTH_STATUS_UNDEF)
                         return;
         }
         Log(LG_AUTH, ("[%s] AUTH: ran out of backends", auth->info.lnkname));
         auth->status = AUTH_STATUS_FAIL;
         auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
 }  }
   
 /*  /*
  * AuthAsyncFinish()   * AuthAsyncFinish()
 *  *
  * Return point for the auth thread   * Return point for the auth thread
  */   */
 
 static void  static void
 AuthAsyncFinish(void *arg, int was_canceled)  AuthAsyncFinish(void *arg, int was_canceled)
 {  {
    AuthData    auth = (AuthData)arg;        AuthData auth = (AuthData) arg;
    Link        l;        Link l;
   
    if (was_canceled)        if (was_canceled)
        Log(LG_AUTH2, ("[%s] AUTH: Thread was canceled", auth->info.lnkname));                Log(LG_AUTH2, ("[%s] AUTH: Thread was canceled", auth->info.lnkname));
   
    /* cleanup */#ifdef USE_RADIUS
    RadiusClose(auth);        /* cleanup */
          RadiusClose(auth);
    if (was_canceled) {#endif
        AuthDataDestroy(auth); 
        return; 
    }   
   
    l = gLinks[auth->info.linkID]; 
    if (l == NULL) { 
        AuthDataDestroy(auth); 
        return; 
    }     
   
    Log(LG_AUTH2, ("[%s] AUTH: Thread finished normally", l->name));        if (was_canceled) {
                 AuthDataDestroy(auth);
                 return;
         }
         l = gLinks[auth->info.linkID];
         if (l == NULL) {
                 AuthDataDestroy(auth);
                 return;
         }
         Log(LG_AUTH2, ("[%s] AUTH: Thread finished normally", l->name));
   
    /* Replace modified data */        /* Replace modified data */
    authparamsDestroy(&l->lcp.auth.params);        authparamsDestroy(&l->lcp.auth.params);
    authparamsMove(&auth->params,&l->lcp.auth.params);        authparamsMove(&auth->params, &l->lcp.auth.params);
   
    if (strcmp(l->lcp.auth.params.action, "drop") == 0) {        if (strcmp(l->lcp.auth.params.action, "drop") == 0) {
        auth->status = AUTH_STATUS_FAIL;                auth->status = AUTH_STATUS_FAIL;
        auth->why_fail = AUTH_FAIL_INVALID_LOGIN;                auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
    } else if (strncmp(l->lcp.auth.params.action, "forward ", 8) == 0) {        } else if (strncmp(l->lcp.auth.params.action, "forward ", 8) == 0) {
        const char  *rept = l->lcp.auth.params.action + 8;                const char *rept = l->lcp.auth.params.action + 8;
   
        /* Action told we must forward this connection */                /* Action told we must forward this connection */
        if (RepCreate(l, rept)) {                if (RepCreate(l, rept)) {
            Log(LG_ERR, ("[%s] Repeater to \"%s\" creation error", l->name, rept));                        Log(LG_ERR, ("[%s] Repeater to \"%s\" creation error", l->name, rept));
            PhysClose(l);                        PhysClose(l);
            AuthDataDestroy(auth);                        AuthDataDestroy(auth);
            return;                        return;
                 }
                 /* Create repeater */
                 RepIncoming(l);
                 /* Reconnect link netgraph hook to repeater */
                 LinkNgToRep(l);
                 /* Kill the LCP */
                 LcpDown(l);
                 LcpClose(l);
                 AuthDataDestroy(auth);
                 return;
         }          }
        /* Create repeater */        auth->finish(l, auth);
        RepIncoming(l); 
        /* Reconnect link netgraph hook to repeater */ 
        LinkNgToRep(l); 
        /* Kill the LCP */ 
        LcpDown(l); 
        LcpClose(l); 
        AuthDataDestroy(auth); 
        return; 
    } 
 
    auth->finish(l, auth); 
 }  }
   
 /*  /*
  * AuthInternal()   * AuthInternal()
 *  *
  * Authenticate against mpd.secret   * Authenticate against mpd.secret
  */   */
 
 static void  static void
 AuthInternal(AuthData auth)  AuthInternal(AuthData auth)
 {  {
    if (AuthGetData(auth->params.authname, auth->params.password,         if (AuthGetData(auth->params.authname, auth->params.password,
            sizeof(auth->params.password), &auth->params.range,             sizeof(auth->params.password), &auth->params.range,
             &auth->params.range_valid) < 0) {              &auth->params.range_valid) < 0) {
        Log(LG_AUTH, ("[%s] AUTH: User \"%s\" not found in secret file",                 Log(LG_AUTH, ("[%s] AUTH: User \"%s\" not found in secret file",
            auth->info.lnkname, auth->params.authname));                    auth->info.lnkname, auth->params.authname));
        auth->status = AUTH_STATUS_FAIL;                auth->status = AUTH_STATUS_FAIL;
        auth->why_fail = AUTH_FAIL_INVALID_LOGIN;                auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
        return;                return;
    }        }
    auth->status = AUTH_STATUS_UNDEF;        auth->status = AUTH_STATUS_UNDEF;
 }  }
   
 #ifdef USE_SYSTEM  #ifdef USE_SYSTEM
 /*  /*
  * AuthSystem()   * AuthSystem()
 *  *
  * Authenticate against Systems password database   * Authenticate against Systems password database
  */   */
 
 static void  static void
 AuthSystem(AuthData auth)  AuthSystem(AuthData auth)
 {  {
  PapParams     pp = &auth->params.pap;        PapParams pp = &auth->params.pap;
  struct passwd *pw;        struct passwd *pw;
  struct passwd pwc;        struct passwd pwc;
  u_char        *bin;        u_char *bin;
  int           err;        int err;
   
  /* protect getpwnam and errno  
   * NOTE: getpwnam_r doesen't exists on FreeBSD < 5.1 */ 
  GIANT_MUTEX_LOCK(); 
  errno = 0; 
  pw = getpwnam(auth->params.authname); 
  if (!pw) { 
    err=errno; 
    GIANT_MUTEX_UNLOCK(); /* We must release lock before Log() */ 
    if (err) 
      Log(LG_ERR, ("[%s] AUTH: Error retrieving passwd: %s", 
        auth->info.lnkname, strerror(err))); 
    else 
      Log(LG_AUTH, ("[%s] AUTH: User \"%s\" not found in the systems database", 
        auth->info.lnkname, auth->params.authname)); 
    auth->status = AUTH_STATUS_FAIL; 
    auth->why_fail = AUTH_FAIL_INVALID_LOGIN; 
    return; 
  } 
  memcpy(&pwc,pw,sizeof(struct passwd)); /* we must make copy before release lock */ 
  GIANT_MUTEX_UNLOCK(); 
   
  Log(LG_AUTH, ("[%s] AUTH: Found user %s Uid:%d Gid:%d Fmt:%*.*s", 
    auth->info.lnkname, pwc.pw_name, pwc.pw_uid, pwc.pw_gid, 3, 3, pwc.pw_passwd)); 
   
  if (auth->proto == PROTO_PAP) {        /*
    /* protect non-ts crypt() */         * protect getpwnam and errno NOTE: getpwnam_r doesen't exists on
    GIANT_MUTEX_LOCK();         * FreeBSD < 5.1
    if (strcmp(crypt(pp->peer_pass, pwc.pw_passwd), pwc.pw_passwd) == 0) {         */
      auth->status = AUTH_STATUS_SUCCESS;        GIANT_MUTEX_LOCK();
    } else {        errno = 0;
      auth->status = AUTH_STATUS_FAIL;        pw = getpwnam(auth->params.authname);
      auth->why_fail = AUTH_FAIL_INVALID_LOGIN;        if (!pw) {
    }                err = errno;
    GIANT_MUTEX_UNLOCK();                GIANT_MUTEX_UNLOCK();   /* We must release lock before Log() */
    return;                if (err)
  } else if (auth->proto == PROTO_CHAP                         Perror("[%s] AUTH: Error retrieving passwd", auth->info.lnkname);
      && (auth->alg == CHAP_ALG_MSOFT                 else
        || auth->alg == CHAP_ALG_MSOFTv2)) {                        Log(LG_AUTH, ("[%s] AUTH: User \"%s\" not found in the systems database",
                             auth->info.lnkname, auth->params.authname));
                 auth->status = AUTH_STATUS_FAIL;
                 auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
                 return;
         }
         memcpy(&pwc, pw, sizeof(struct passwd));        /* we must make copy
                                                          * before release lock */
         GIANT_MUTEX_UNLOCK();
   
    if (!strstr(pwc.pw_passwd, "$3$$")) {        Log(LG_AUTH, ("[%s] AUTH: Found user %s Uid:%d Gid:%d Fmt:%*.*s",
      Log(LG_AUTH, ("[%s] AUTH: Password has the wrong format, nth ($3$) is needed",            auth->info.lnkname, pwc.pw_name, pwc.pw_uid, pwc.pw_gid, 3, 3, pwc.pw_passwd));
            auth->info.lnkname)); 
      auth->status = AUTH_STATUS_FAIL; 
      auth->why_fail = AUTH_FAIL_INVALID_LOGIN; 
      return; 
    } 
   
    bin = Hex2Bin(&pwc.pw_passwd[4]);        if (auth->proto == PROTO_PAP) {
    memcpy(auth->params.msoft.nt_hash, bin, sizeof(auth->params.msoft.nt_hash));                /* protect non-ts crypt() */
    Freee(bin);                GIANT_MUTEX_LOCK();
    NTPasswordHashHash(auth->params.msoft.nt_hash, auth->params.msoft.nt_hash_hash);                if (strcmp(crypt(pp->peer_pass, pwc.pw_passwd), pwc.pw_passwd) == 0) {
    auth->params.msoft.has_nt_hash = TRUE;                        auth->status = AUTH_STATUS_SUCCESS;
    auth->status = AUTH_STATUS_UNDEF;                } else {
    return;                        auth->status = AUTH_STATUS_FAIL;
                         auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
                 }
                 GIANT_MUTEX_UNLOCK();
                 return;
         } else if (auth->proto == PROTO_CHAP
                     && (auth->alg == CHAP_ALG_MSOFT
             || auth->alg == CHAP_ALG_MSOFTv2)) {
   
  } else {                if (!strstr(pwc.pw_passwd, "$3$$")) {
    Log(LG_ERR, ("[%s] AUTH: Using systems password database only possible for PAP and MS-CHAP",                        Log(LG_AUTH, ("[%s] AUTH: Password has the wrong format, nth ($3$) is needed",
        auth->info.lnkname));                            auth->info.lnkname));
    auth->status = AUTH_STATUS_FAIL;                        auth->status = AUTH_STATUS_FAIL;
    auth->why_fail = AUTH_FAIL_NOT_EXPECTED;                        auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
    return;                        return;
  }                }
                 bin = Hex2Bin(&pwc.pw_passwd[4]);
                 memcpy(auth->params.msoft.nt_hash, bin, sizeof(auth->params.msoft.nt_hash));
                 Freee(bin);
                 NTPasswordHashHash(auth->params.msoft.nt_hash, auth->params.msoft.nt_hash_hash);
                 auth->params.msoft.has_nt_hash = TRUE;
                 auth->status = AUTH_STATUS_UNDEF;
                 return;
   
           } else {
                   Log(LG_ERR, ("[%s] AUTH: Using systems password database only possible for PAP and MS-CHAP",
                       auth->info.lnkname));
                   auth->status = AUTH_STATUS_FAIL;
                   auth->why_fail = AUTH_FAIL_NOT_EXPECTED;
                   return;
           }
   
 }  }
   
 /*  /*
  * AuthSystemAcct()   * AuthSystemAcct()
 *  *
  * Account with system   * Account with system
  */   */
   
Line 1410  AuthSystem(AuthData auth) Line 1458  AuthSystem(AuthData auth)
 static int  static int
 AuthSystemAcct(AuthData auth)  AuthSystemAcct(AuthData auth)
 {  {
        struct utmpx    ut;        struct utmpx ut;
   
         memset(&ut, 0, sizeof(ut));          memset(&ut, 0, sizeof(ut));
         snprintf(ut.ut_id, sizeof(ut.ut_id), "mpd%x", auth->info.linkID);          snprintf(ut.ut_id, sizeof(ut.ut_id), "mpd%x", auth->info.linkID);
Line 1422  AuthSystemAcct(AuthData auth) Line 1470  AuthSystemAcct(AuthData auth)
                 strlcpy(ut.ut_user, auth->params.authname, sizeof(ut.ut_user));                  strlcpy(ut.ut_user, auth->params.authname, sizeof(ut.ut_user));
                 gettimeofday(&ut.ut_tv, NULL);                  gettimeofday(&ut.ut_tv, NULL);
                 Log(LG_AUTH, ("[%s] ACCT: wtmp %s %s %s login", auth->info.lnkname, ut.ut_line,                  Log(LG_AUTH, ("[%s] ACCT: wtmp %s %s %s login", auth->info.lnkname, ut.ut_line,
                        ut.ut_user, ut.ut_host));                    ut.ut_user, ut.ut_host));
                 pututxline(&ut);                  pututxline(&ut);
         } else if (auth->acct_type == AUTH_ACCT_STOP) {          } else if (auth->acct_type == AUTH_ACCT_STOP) {
                 ut.ut_type = DEAD_PROCESS;                  ut.ut_type = DEAD_PROCESS;
Line 1431  AuthSystemAcct(AuthData auth) Line 1479  AuthSystemAcct(AuthData auth)
         }          }
         return (0);          return (0);
 }  }
   
 #else  #else
 static int  static int
 AuthSystemAcct(AuthData auth)  AuthSystemAcct(AuthData auth)
 {  {
        struct utmp     ut;        struct utmp ut;
   
         memset(&ut, 0, sizeof(ut));          memset(&ut, 0, sizeof(ut));
         strlcpy(ut.ut_line, auth->info.lnkname, sizeof(ut.ut_line));          strlcpy(ut.ut_line, auth->info.lnkname, sizeof(ut.ut_line));
   
         if (auth->acct_type == AUTH_ACCT_START) {          if (auth->acct_type == AUTH_ACCT_START) {
            time_t      t;                time_t t;
   
            strlcpy(ut.ut_host, auth->params.peeraddr, sizeof(ut.ut_host));                strlcpy(ut.ut_host, auth->params.peeraddr, sizeof(ut.ut_host));
            strlcpy(ut.ut_name, auth->params.authname, sizeof(ut.ut_name));                strlcpy(ut.ut_name, auth->params.authname, sizeof(ut.ut_name));
            time(&t);                time(&t);
            ut.ut_time = t;                ut.ut_time = t;
            login(&ut);                login(&ut);
            Log(LG_AUTH, ("[%s] ACCT: wtmp %s %s %s login", auth->info.lnkname, ut.ut_line,                 Log(LG_AUTH, ("[%s] ACCT: wtmp %s %s %s login", auth->info.lnkname, ut.ut_line,
                ut.ut_name, ut.ut_host));                    ut.ut_name, ut.ut_host));
         } else if (auth->acct_type == AUTH_ACCT_STOP) {          } else if (auth->acct_type == AUTH_ACCT_STOP) {
            Log(LG_AUTH, ("[%s] ACCT: wtmp %s logout", auth->info.lnkname, ut.ut_line));                Log(LG_AUTH, ("[%s] ACCT: wtmp %s logout", auth->info.lnkname, ut.ut_line));
            logout(ut.ut_line);                logout(ut.ut_line);
            logwtmp(ut.ut_line, "", "");                logwtmp(ut.ut_line, "", "");
         }          }
         return (0);          return (0);
 }  }
 #endif /* __FreeBSD_version >= 900007 */  
 #endif /* USE_SYSTEM */  
   
   #endif                                  /* __FreeBSD_version >= 900007 */
   #endif                                  /* USE_SYSTEM */
   
 #ifdef USE_PAM  #ifdef USE_PAM
 /*  /*
  * AuthPAM()   * AuthPAM()
 *  *
  * Authenticate with PAM system   * Authenticate with PAM system
  */   */
   
 static int  static int
 pam_conv(int n, const struct pam_message **msg, struct pam_response **resp,  pam_conv(int n, const struct pam_message **msg, struct pam_response **resp,
  void *data)    void *data)
 {  {
    AuthData    auth = (AuthData)data;        AuthData auth = (AuthData) data;
    int         i;        int i;
   
    for (i = 0; i < n; i++) {        for (i = 0; i < n; i++) {
        Log(LG_AUTH2, ("[%s] AUTH: PAM: %s",                Log(LG_AUTH2, ("[%s] AUTH: PAM: %s",
            auth->info.lnkname, msg[i]->msg));                    auth->info.lnkname, msg[i]->msg));
    }        }
   
    /* We support only requests for password */        /* We support only requests for password */
    if (n != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF)        if (n != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF)
        return (PAM_CONV_ERR);                return (PAM_CONV_ERR);
   
    if ((*resp = malloc(sizeof(struct pam_response))) == NULL)        if ((*resp = malloc(sizeof(struct pam_response))) == NULL)
        return (PAM_CONV_ERR);                return (PAM_CONV_ERR);
    (*resp)[0].resp = strdup(auth->params.pap.peer_pass);        (*resp)[0].resp = strdup(auth->params.pap.peer_pass);
    (*resp)[0].resp_retcode = 0;        (*resp)[0].resp_retcode = 0;
   
    return ((*resp)[0].resp != NULL ? PAM_SUCCESS : PAM_CONV_ERR);        return ((*resp)[0].resp != NULL ? PAM_SUCCESS : PAM_CONV_ERR);
 }  }
 
 static void  static void
 AuthPAM(AuthData auth)  AuthPAM(AuthData auth)
 {  {
    struct pam_conv pamc = {        struct pam_conv pamc = {
        &pam_conv,                &pam_conv,
        auth                auth
    };        };
    pam_handle_t *pamh;        pam_handle_t *pamh;
    int status;        int status;
   
    if (auth->proto != PROTO_PAP) {        if (auth->proto != PROTO_PAP) {
        Log(LG_ERR, ("[%s] AUTH: Using PAM only possible for PAP", auth->info.lnkname));                Log(LG_ERR, ("[%s] AUTH: Using PAM only possible for PAP", auth->info.lnkname));
        auth->status = AUTH_STATUS_FAIL;                auth->status = AUTH_STATUS_FAIL;
        auth->why_fail = AUTH_FAIL_NOT_EXPECTED;                auth->why_fail = AUTH_FAIL_NOT_EXPECTED;
        return;                return;
    }        }
            if (pam_start(gPamService, auth->params.authname, &pamc, &pamh) != PAM_SUCCESS) {
    if (pam_start(gPamService, auth->params.authname, &pamc, &pamh) != PAM_SUCCESS) {                Log(LG_ERR, ("[%s] AUTH: PAM error", auth->info.lnkname));
        Log(LG_ERR, ("[%s] AUTH: PAM error", auth->info.lnkname));                auth->status = AUTH_STATUS_FAIL;
        auth->status = AUTH_STATUS_FAIL;                auth->why_fail = AUTH_FAIL_NOT_EXPECTED;
        auth->why_fail = AUTH_FAIL_NOT_EXPECTED;                return;
        return;        }
    }        if (auth->params.peeraddr[0] &&
             pam_set_item(pamh, PAM_RHOST, auth->params.peeraddr) != PAM_SUCCESS) {
                 Log(LG_ERR, ("[%s] AUTH: PAM set PAM_RHOST error", auth->info.lnkname));
         }
         if (pam_set_item(pamh, PAM_TTY, auth->info.lnkname) != PAM_SUCCESS) {
                 Log(LG_ERR, ("[%s] AUTH: PAM set PAM_TTY error", auth->info.lnkname));
         }
         status = pam_authenticate(pamh, 0);
   
    if (auth->params.peeraddr[0] &&        if (status == PAM_SUCCESS) {
        pam_set_item(pamh, PAM_RHOST, auth->params.peeraddr) != PAM_SUCCESS) {                status = pam_acct_mgmt(pamh, 0);
        Log(LG_ERR, ("[%s] AUTH: PAM set PAM_RHOST error", auth->info.lnkname)); 
    } 
 
    if (pam_set_item(pamh, PAM_TTY, auth->info.lnkname) != PAM_SUCCESS) { 
        Log(LG_ERR, ("[%s] AUTH: PAM set PAM_TTY error", auth->info.lnkname)); 
    } 
 
    status = pam_authenticate(pamh, 0); 
 
    if (status == PAM_SUCCESS) { 
        status = pam_acct_mgmt(pamh, 0); 
    } 
 
    if (status == PAM_SUCCESS) { 
        auth->status = AUTH_STATUS_SUCCESS; 
    } else { 
        Log(LG_AUTH, ("[%s] AUTH: PAM error: %s", 
            auth->info.lnkname, pam_strerror(pamh, status))); 
        switch (status) { 
        case PAM_AUTH_ERR: 
        case PAM_USER_UNKNOWN: 
            auth->status = AUTH_STATUS_FAIL; 
            auth->why_fail = AUTH_FAIL_INVALID_LOGIN; 
            break; 
        case PAM_ACCT_EXPIRED: 
        case PAM_AUTHTOK_EXPIRED: 
        case PAM_CRED_EXPIRED: 
            auth->status = AUTH_STATUS_FAIL; 
            auth->why_fail = AUTH_FAIL_ACCT_DISABLED; 
            break; 
        default: 
            auth->status = AUTH_STATUS_FAIL; 
            auth->why_fail = AUTH_FAIL_NOT_EXPECTED; 
         }          }
    }        if (status == PAM_SUCCESS) {
                 auth->status = AUTH_STATUS_SUCCESS;
         } else {
                 Log(LG_AUTH, ("[%s] AUTH: PAM error: %s",
                     auth->info.lnkname, pam_strerror(pamh, status)));
                 switch (status) {
                 case PAM_AUTH_ERR:
                 case PAM_USER_UNKNOWN:
                         auth->status = AUTH_STATUS_FAIL;
                         auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
                         break;
                 case PAM_ACCT_EXPIRED:
                 case PAM_AUTHTOK_EXPIRED:
                 case PAM_CRED_EXPIRED:
                         auth->status = AUTH_STATUS_FAIL;
                         auth->why_fail = AUTH_FAIL_ACCT_DISABLED;
                         break;
                 default:
                         auth->status = AUTH_STATUS_FAIL;
                         auth->why_fail = AUTH_FAIL_NOT_EXPECTED;
                 }
         }
   
    pam_end(pamh, status);        pam_end(pamh, status);
 }  }
   
 /*  /*
  * AuthPAMAcct()   * AuthPAMAcct()
 *  *
  * Account with system   * Account with system
  */   */
   
 static int  static int
 AuthPAMAcct(AuthData auth)  AuthPAMAcct(AuthData auth)
 {  {
    pam_handle_t *pamh;        pam_handle_t *pamh;
    int status;        int status;
    struct pam_conv pamc = {        struct pam_conv pamc = {
        &pam_conv,                &pam_conv,
        auth                auth
    };        };
     
    if (auth->acct_type != AUTH_ACCT_START && 
      auth->acct_type != AUTH_ACCT_STOP) { 
        return (0); 
    } 
   
    if (pam_start(gPamService, auth->params.authname, &pamc, &pamh) != PAM_SUCCESS) {        if (auth->acct_type != AUTH_ACCT_START &&
        Log(LG_ERR, ("[%s] ACCT: PAM error", auth->info.lnkname));            auth->acct_type != AUTH_ACCT_STOP) {
        return (-1);                return (0);
    }        }
        if (pam_start(gPamService, auth->params.authname, &pamc, &pamh) != PAM_SUCCESS) {
    if (auth->params.peeraddr[0] &&                Log(LG_ERR, ("[%s] ACCT: PAM error", auth->info.lnkname));
        pam_set_item(pamh, PAM_RHOST, auth->params.peeraddr) != PAM_SUCCESS) {                return (-1);
        Log(LG_ERR, ("[%s] ACCT: PAM set PAM_RHOST error", auth->info.lnkname));        }
        return (-1);        if (auth->params.peeraddr[0] &&
    }            pam_set_item(pamh, PAM_RHOST, auth->params.peeraddr) != PAM_SUCCESS) {
                Log(LG_ERR, ("[%s] ACCT: PAM set PAM_RHOST error", auth->info.lnkname));
    if (pam_set_item(pamh, PAM_TTY, auth->info.lnkname) != PAM_SUCCESS) {                return (-1);
        Log(LG_ERR, ("[%s] ACCT: PAM set PAM_TTY error", auth->info.lnkname));        }
        return (-1);        if (pam_set_item(pamh, PAM_TTY, auth->info.lnkname) != PAM_SUCCESS) {
    }                Log(LG_ERR, ("[%s] ACCT: PAM set PAM_TTY error", auth->info.lnkname));
                return (-1);
    if (auth->acct_type == AUTH_ACCT_START) {        }
            Log(LG_AUTH, ("[%s] ACCT: PAM open session \"%s\"",        if (auth->acct_type == AUTH_ACCT_START) {
                auth->info.lnkname, auth->params.authname));                Log(LG_AUTH, ("[%s] ACCT: PAM open session \"%s\"",
            status = pam_open_session(pamh, 0);                    auth->info.lnkname, auth->params.authname));
    } else {                status = pam_open_session(pamh, 0);
            Log(LG_AUTH, ("[%s] ACCT: PAM close session \"%s\"",        } else {
                auth->info.lnkname, auth->params.authname));                Log(LG_AUTH, ("[%s] ACCT: PAM close session \"%s\"",
            status = pam_close_session(pamh, 0);                    auth->info.lnkname, auth->params.authname));
    }                status = pam_close_session(pamh, 0);
    if (status != PAM_SUCCESS) {        }
        Log(LG_AUTH, ("[%s] ACCT: PAM session error",        if (status != PAM_SUCCESS) {
            auth->info.lnkname));                Log(LG_AUTH, ("[%s] ACCT: PAM session error",
        return (-1);                    auth->info.lnkname));
    }                return (-1);
            }
    pam_end(pamh, status);        pam_end(pamh, status);
    return (0);        return (0);
 }  }
 #endif /* USE_PAM */  
   
   #endif                                  /* USE_PAM */
   
 #ifdef USE_OPIE  #ifdef USE_OPIE
 /*  /*
  * AuthOpie()   * AuthOpie()
Line 1621  AuthPAMAcct(AuthData auth) Line 1662  AuthPAMAcct(AuthData auth)
 static void  static void
 AuthOpie(AuthData auth)  AuthOpie(AuthData auth)
 {  {
  PapParams     const pp = &auth->params.pap;        PapParams const pp = &auth->params.pap;
  struct        opie_otpkey key;        struct opie_otpkey key;
  char          opieprompt[OPIE_CHALLENGE_MAX + 1];        char opieprompt[OPIE_CHALLENGE_MAX + 1];
  int           ret, n;        int ret, n;
  char          secret[OPIE_SECRET_MAX + 1];        char secret[OPIE_SECRET_MAX + 1];
  char          english[OPIE_RESPONSE_MAX + 1];        char english[OPIE_RESPONSE_MAX + 1];
   
  ret = opiechallenge(&auth->opie.data, auth->params.authname, opieprompt);        ret = opiechallenge(&auth->opie.data, auth->params.authname, opieprompt);
   
  auth->status = AUTH_STATUS_UNDEF;        auth->status = AUTH_STATUS_UNDEF;
   
  switch (ret) { 
    case 0: 
      break; 
   
    case 1: 
      Log(LG_ERR, ("[%s] AUTH: User \"%s\" not found in opiekeys", 
        auth->info.lnkname, auth->params.authname)); 
      auth->status = AUTH_STATUS_FAIL; 
      auth->why_fail = AUTH_FAIL_INVALID_LOGIN; 
      return; 
   
    case -1:        switch (ret) {
    case 2:        case 0:
    default:                break;
      Log(LG_ERR, ("[%s] AUTH: System error", auth->info.lnkname)); 
      auth->status = AUTH_STATUS_FAIL; 
      auth->why_fail = AUTH_FAIL_NOT_EXPECTED; 
      return; 
  }; 
   
  Log(LG_AUTH, ("[%s] AUTH: Opieprompt:%s", auth->info.lnkname, opieprompt));        case 1:
                 Log(LG_ERR, ("[%s] AUTH: User \"%s\" not found in opiekeys",
                     auth->info.lnkname, auth->params.authname));
                 auth->status = AUTH_STATUS_FAIL;
                 auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
                 return;
   
  if (auth->proto == PROTO_PAP ) {        case -1:
    if (!opieverify(&auth->opie.data, pp->peer_pass)) {        case 2:
      auth->status = AUTH_STATUS_SUCCESS;        default:
    } else {                Log(LG_ERR, ("[%s] AUTH: System error", auth->info.lnkname));
      auth->why_fail = AUTH_FAIL_INVALID_LOGIN;                auth->status = AUTH_STATUS_FAIL;
      auth->status = AUTH_STATUS_FAIL;                auth->why_fail = AUTH_FAIL_NOT_EXPECTED;
    }                return;
    return;        };
  } 
   
  if (AuthGetData(auth->params.authname, secret, sizeof(secret), NULL, NULL) < 0) {        Log(LG_AUTH, ("[%s] AUTH: Opieprompt:%s", auth->info.lnkname, opieprompt));
    Log(LG_AUTH, ("[%s] AUTH: Can't get credentials for \"%s\"", 
        auth->info.lnkname, auth->params.authname)); 
    auth->status = AUTH_STATUS_FAIL; 
    auth->why_fail = AUTH_FAIL_INVALID_LOGIN;     
    return; 
  } 
   
  opiekeycrunch(OPIE_ALG_MD5, &key, auth->opie.data.opie_seed, secret); 
  n = auth->opie.data.opie_n - 1; 
  while (n-- > 0) 
    opiehash(&key, OPIE_ALG_MD5); 
   
  opiebtoe(english, &key);        if (auth->proto == PROTO_PAP) {
  strlcpy(auth->params.password, english, sizeof(auth->params.password));                if (!opieverify(&auth->opie.data, pp->peer_pass)) {
                         auth->status = AUTH_STATUS_SUCCESS;
                 } else {
                         auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
                         auth->status = AUTH_STATUS_FAIL;
                 }
                 return;
         }
         if (AuthGetData(auth->params.authname, secret, sizeof(secret), NULL, NULL) < 0) {
                 Log(LG_AUTH, ("[%s] AUTH: Can't get credentials for \"%s\"",
                     auth->info.lnkname, auth->params.authname));
                 auth->status = AUTH_STATUS_FAIL;
                 auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
                 return;
         }
         opiekeycrunch(OPIE_ALG_MD5, &key, auth->opie.data.opie_seed, secret);
         n = auth->opie.data.opie_n - 1;
         while (n-- > 0)
                 opiehash(&key, OPIE_ALG_MD5);
 
         opiebtoe(english, &key);
         strlcpy(auth->params.password, english, sizeof(auth->params.password));
 }  }
 #endif /* USE_OPIE */  
   
   #endif                                  /* USE_OPIE */
   
 /*  /*
  * AuthPreChecks()   * AuthPreChecks()
  */   */
Line 1690  static int Line 1730  static int
 AuthPreChecks(AuthData auth)  AuthPreChecks(AuthData auth)
 {  {
   
  if (!strlen(auth->params.authname)) {        if (!strlen(auth->params.authname)) {
    Log(LG_AUTH, ("[%s] AUTH: We don't accept empty usernames", auth->info.lnkname));                Log(LG_AUTH, ("[%s] AUTH: We don't accept empty usernames", auth->info.lnkname));
    auth->status = AUTH_STATUS_FAIL;                auth->status = AUTH_STATUS_FAIL;
    auth->why_fail = AUTH_FAIL_INVALID_LOGIN;                auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
    return (-1);                return (-1);
  } 
  /* check max. number of logins */ 
  if (gMaxLogins != 0) { 
    int         ac; 
    u_long      num = 0; 
    for(ac = 0; ac < gNumBundles; ac++) { 
      if (gBundles[ac] && gBundles[ac]->open) { 
        if (gMaxLoginsCI) { 
            if (!strcasecmp(gBundles[ac]->params.authname, auth->params.authname)) 
                num++; 
        } else { 
            if (!strcmp(gBundles[ac]->params.authname, auth->params.authname)) 
                num++; 
         }          }
      }        /* check max. number of logins */
    }        if (gMaxLogins != 0) {
                 int ac;
                 u_long num = 0;
   
    if (num >= gMaxLogins) {                for (ac = 0; ac < gNumBundles; ac++) {
        Log(LG_AUTH, ("[%s] AUTH: Name: \"%s\" max. number of logins exceeded",                        if (gBundles[ac] && gBundles[ac]->open) {
            auth->info.lnkname, auth->params.authname));                                if (gMaxLoginsCI) {
        auth->status = AUTH_STATUS_FAIL;                                        if (!strcasecmp(gBundles[ac]->params.authname, auth->params.authname))
        auth->why_fail = AUTH_FAIL_INVALID_LOGIN;                                                num++;
        return (-1);                                } else {
    }                                        if (!strcmp(gBundles[ac]->params.authname, auth->params.authname))
  }                                                num++;
  return (0);                                }
                         }
                 }
 
                 if (num >= gMaxLogins) {
                         Log(LG_ERR | LG_AUTH, ("[%s] AUTH: Name: \"%s\" max. number of logins exceeded",
                             auth->info.lnkname, auth->params.authname));
                         auth->status = AUTH_STATUS_FAIL;
                         auth->why_fail = AUTH_FAIL_INVALID_LOGIN;
                         return (-1);
                 }
         }
         return (0);
 }  }
   
 /*  /*
Line 1732  AuthPreChecks(AuthData auth) Line 1773  AuthPreChecks(AuthData auth)
 static void  static void
 AuthTimeout(void *arg)  AuthTimeout(void *arg)
 {  {
    Link l = (Link)arg;        Link l = (Link) arg;
   
  Log(LG_AUTH, ("[%s] %s: authorization timer expired", Pref(&l->lcp.fsm), Fsm(&l->lcp.fsm)));        Log(LG_AUTH, ("[%s] %s: authorization timer expired", Pref(&l->lcp.fsm), Fsm(&l->lcp.fsm)));
  AuthStop(l);        AuthStop(l);
  LcpAuthResult(l, FALSE);        LcpAuthResult(l, FALSE);
 }  }
   
/* /*
  * AuthFailMsg()   * AuthFailMsg()
  */   */
   
 const char *  const char *
 AuthFailMsg(AuthData auth, char *buf, size_t len)  AuthFailMsg(AuthData auth, char *buf, size_t len)
 {  {
    const char  *mesg;        const char *mesg;
   
    if (auth->proto == PROTO_CHAP        if (auth->proto == PROTO_CHAP
        && (auth->alg == CHAP_ALG_MSOFT || auth->alg == CHAP_ALG_MSOFTv2)) {            && (auth->alg == CHAP_ALG_MSOFT || auth->alg == CHAP_ALG_MSOFTv2)) {
            int mscode;                int mscode;
   
            if (auth->mschap_error != NULL) {                if (auth->mschap_error != NULL) {
                    strlcpy(buf, auth->mschap_error, len);                        strlcpy(buf, auth->mschap_error, len);
                    return(buf);                        return (buf);
            }                }
                 switch (auth->why_fail) {
                 case AUTH_FAIL_ACCT_DISABLED:
                         mscode = MSCHAP_ERROR_ACCT_DISABLED;
                         mesg = AUTH_MSG_ACCT_DISAB;
                         break;
                 case AUTH_FAIL_NO_PERMISSION:
                         mscode = MSCHAP_ERROR_NO_DIALIN_PERMISSION;
                         mesg = AUTH_MSG_NOT_ALLOWED;
                         break;
                 case AUTH_FAIL_RESTRICTED_HOURS:
                         mscode = MSCHAP_ERROR_RESTRICTED_LOGON_HOURS;
                         mesg = AUTH_MSG_RESTR_HOURS;
                         break;
                 case AUTH_FAIL_INVALID_PACKET:
                 case AUTH_FAIL_INVALID_LOGIN:
                 case AUTH_FAIL_NOT_EXPECTED:
                 default:
                         mscode = MSCHAP_ERROR_AUTHENTICATION_FAILURE;
                         mesg = AUTH_MSG_INVALID;
                         break;
                 }
   
            switch (auth->why_fail) {                /* If we have reply message, send it instead of default. */
              case AUTH_FAIL_ACCT_DISABLED:                if (auth->reply_message != NULL)
                mscode = MSCHAP_ERROR_ACCT_DISABLED;                        mesg = auth->reply_message;
                mesg = AUTH_MSG_ACCT_DISAB; 
                break; 
              case AUTH_FAIL_NO_PERMISSION: 
                mscode = MSCHAP_ERROR_NO_DIALIN_PERMISSION; 
                mesg = AUTH_MSG_NOT_ALLOWED; 
                break; 
              case AUTH_FAIL_RESTRICTED_HOURS: 
                mscode = MSCHAP_ERROR_RESTRICTED_LOGON_HOURS; 
                mesg = AUTH_MSG_RESTR_HOURS; 
                break; 
              case AUTH_FAIL_INVALID_PACKET: 
              case AUTH_FAIL_INVALID_LOGIN: 
              case AUTH_FAIL_NOT_EXPECTED: 
              default: 
                mscode = MSCHAP_ERROR_AUTHENTICATION_FAILURE; 
                mesg = AUTH_MSG_INVALID; 
                break; 
            } 
   
            /* If we have reply message, send it instead of default. */                snprintf(buf, len, "E=%d R=0 M=%s", mscode, mesg);
            if (auth->reply_message != NULL) 
                mesg = auth->reply_message; 
   
            snprintf(buf, len, "E=%d R=0 M=%s", mscode, mesg);        } else {
     
    } else { 
   
            if (auth->reply_message != NULL) {                if (auth->reply_message != NULL) {
                    strlcpy(buf, auth->reply_message, len);                        strlcpy(buf, auth->reply_message, len);
                    return(buf);                        return (buf);
            }                }
                switch (auth->why_fail) {
            switch (auth->why_fail) {                case AUTH_FAIL_ACCT_DISABLED:
              case AUTH_FAIL_ACCT_DISABLED:                        mesg = AUTH_MSG_ACCT_DISAB;
                mesg = AUTH_MSG_ACCT_DISAB;                        break;
                break;                case AUTH_FAIL_NO_PERMISSION:
              case AUTH_FAIL_NO_PERMISSION:                        mesg = AUTH_MSG_NOT_ALLOWED;
                mesg = AUTH_MSG_NOT_ALLOWED;                        break;
                break;                case AUTH_FAIL_RESTRICTED_HOURS:
              case AUTH_FAIL_RESTRICTED_HOURS:                        mesg = AUTH_MSG_RESTR_HOURS;
                mesg = AUTH_MSG_RESTR_HOURS;                        break;
                break;                case AUTH_FAIL_NOT_EXPECTED:
              case AUTH_FAIL_NOT_EXPECTED:                        mesg = AUTH_MSG_NOT_EXPECTED;
                mesg = AUTH_MSG_NOT_EXPECTED;                        break;
                break;                case AUTH_FAIL_INVALID_PACKET:
              case AUTH_FAIL_INVALID_PACKET:                        mesg = AUTH_MSG_BAD_PACKET;
                mesg = AUTH_MSG_BAD_PACKET;                        break;
                break;                case AUTH_FAIL_INVALID_LOGIN:
              case AUTH_FAIL_INVALID_LOGIN:                default:
              default:                        mesg = AUTH_MSG_INVALID;
                mesg = AUTH_MSG_INVALID;                        break;
                break;                }
            }                strlcpy(buf, mesg, len);
            strlcpy(buf, mesg, len);        }
    }        return (buf);
    return(buf); 
 }  }
   
/* /*
  * AuthStatusText()   * AuthStatusText()
  */   */
   
 const char *  const char *
 AuthStatusText(int status)  AuthStatusText(int status)
{  {
  switch (status) {        switch (status) {
    case AUTH_STATUS_UNDEF:        case AUTH_STATUS_UNDEF:
      return "undefined";                return "undefined";
   
    case AUTH_STATUS_SUCCESS:        case AUTH_STATUS_SUCCESS:
      return "authenticated";                return "authenticated";
   
    case AUTH_STATUS_FAIL:        case AUTH_STATUS_FAIL:
      return "failed";                return "failed";
   
    case AUTH_STATUS_BUSY:        case AUTH_STATUS_BUSY:
      return "busy";                return "busy";
   
    default:        default:
      return "INCORRECT STATUS";                return "INCORRECT STATUS";
  }        }
 }  }
   
/* /*
  * AuthMPPEPolicyname()   * AuthMPPEPolicyname()
  */   */
   
 const char *  const char *
AuthMPPEPolicyname(int policy) AuthMPPEPolicyname(int policy)
 {  {
  switch(policy) {        switch (policy) {
    case MPPE_POLICY_ALLOWED:        case MPPE_POLICY_ALLOWED:
      return "Allowed";                return "Allowed";
    case MPPE_POLICY_REQUIRED:        case MPPE_POLICY_REQUIRED:
      return "Required";                return "Required";
    case MPPE_POLICY_NONE:        case MPPE_POLICY_NONE:
      return "Not available";                return "Not available";
    default:        default:
      return "Unknown Policy";                return "Unknown Policy";
  }        }
   
 }  }
   
/* /*
  * AuthMPPETypesname()   * AuthMPPETypesname()
  */   */
   
 const char *  const char *
AuthMPPETypesname(int types, char *buf, size_t len) AuthMPPETypesname(int types, char *buf, size_t len)
 {  {
  if (types == 0) {        if (types == 0) {
    sprintf(buf, "no encryption required");                strlcpy(buf, "no encryption required", len);
    return (buf);                return (buf);
  }        }
         buf[0] = 0;
         if (types & MPPE_TYPE_40BIT)
                 strlcpy(buf, "40 ", len);
         if (types & MPPE_TYPE_56BIT)
                 strlcat(buf, "56 ", len);
         if (types & MPPE_TYPE_128BIT)
                 strlcat(buf, "128 ", len);
   
  buf[0]=0;        if (strlen(buf) == 0) {
  if (types & MPPE_TYPE_40BIT) sprintf (buf, "40 ");                strlcpy(buf, "unknown types", len);
  if (types & MPPE_TYPE_56BIT) sprintf (&buf[strlen(buf)], "56 ");        } else {
  if (types & MPPE_TYPE_128BIT) sprintf (&buf[strlen(buf)], "128 ");                strlcat(buf, "bit", len);
         }
   
  if (strlen(buf) == 0) {        return (buf);
    sprintf (buf, "unknown types"); 
  } else { 
    sprintf (&buf[strlen(buf)], "bit"); 
  } 
 
  return (buf); 
 }  }
   
 /*  /*
Line 1897  AuthMPPETypesname(int types, char *buf, size_t len)  Line 1938  AuthMPPETypesname(int types, char *buf, size_t len) 
  * -1 on error (can't fork, no data read, whatever)   * -1 on error (can't fork, no data read, whatever)
  */   */
 static int  static int
AuthGetExternalPassword(char * extcmd, char *authname, char *password, size_t passlen)AuthGetExternalPassword(const char *extcmd, char *authname, char *password, size_t passlen)
 {  {
  char cmd[AUTH_MAX_PASSWORD + 5 + AUTH_MAX_AUTHNAME];        char cmd[AUTH_MAX_PASSWORD + 5 + AUTH_MAX_AUTHNAME];
  int ok = 0;        int ok = 0;
  FILE *fp;        FILE *fp;
  int len;        int len;
   
  snprintf(cmd, sizeof(cmd), "%s %s", extcmd, authname);        snprintf(cmd, sizeof(cmd), "%s %s", extcmd, authname);
  Log(LG_AUTH, ("Invoking external auth program: '%s'", cmd));        Log(LG_AUTH, ("Invoking external auth program: '%s'", cmd));
  if ((fp = popen(cmd, "r")) == NULL) {        if ((fp = popen(cmd, "r")) == NULL) {
    Perror("Popen");                Perror("Popen");
    return (-1);                return (-1);
  }        }
  if (fgets(password, passlen, fp) != NULL) {        if (fgets(password, passlen, fp) != NULL) {
    len = strlen(password);     /* trim trailing newline */                len = strlen(password); /* trim trailing newline */
    if (len > 0 && password[len - 1] == '\n')                if (len > 0 && password[len - 1] == '\n')
      password[len - 1] = '\0';                        password[len - 1] = '\0';
    ok = (password[0] != '\0');                ok = (password[0] != '\0');
  } else {        } else {
    if (ferror(fp))                if (ferror(fp))
      Perror("Error reading from external auth program");                        Perror("Error reading from external auth program");
  }        }
  if (!ok)        if (!ok)
    Log(LG_AUTH, ("External auth program failed for user \"%s\"",                 Log(LG_AUTH, ("External auth program failed for user \"%s\"",
      authname));                    authname));
  pclose(fp);        pclose(fp);
  return (ok ? 0 : -1);        return (ok ? 0 : -1);
 }  }
   
 /*  /*
Line 1933  AuthGetExternalPassword(char * extcmd, char *authname, Line 1974  AuthGetExternalPassword(char * extcmd, char *authname,
 static const char *  static const char *
 AuthCode(int proto, u_char code, char *buf, size_t len)  AuthCode(int proto, u_char code, char *buf, size_t len)
 {  {
  switch (proto) {        switch (proto) {
    case PROTO_EAP:#ifdef USE_RADIUS
      return EapCode(code, buf, len);        case PROTO_EAP:
                 return EapCode(code, buf, len);
   
    case PROTO_CHAP:#endif
      return ChapCode(code, buf, len);        case PROTO_CHAP:
                 return ChapCode(code, buf, len);
   
    case PROTO_PAP:        case PROTO_PAP:
      return PapCode(code, buf, len);                return PapCode(code, buf, len);
   
    default:        default:
      snprintf(buf, len, "code %d", code);                snprintf(buf, len, "code %d", code);
      return(buf);                return (buf);
  }        }
 }  }
   
   
Line 1955  AuthCode(int proto, u_char code, char *buf, size_t len Line 1998  AuthCode(int proto, u_char code, char *buf, size_t len
  */   */
   
 static int  static int
AuthSetCommand(Context ctx, int ac, char *av[], void *arg)AuthSetCommand(Context ctx, int ac, const char *const av[], const void *arg)
 {  {
  AuthConf      const autc = &ctx->lnk->lcp.auth.conf;        AuthConf const autc = &ctx->lnk->lcp.auth.conf;
  int           val;        int val;
   
  if (ac == 0)        if (ac == 0)
    return(-1);                return (-1);
   
  switch ((intptr_t)arg) {        switch ((intptr_t)arg) {
   
    case SET_AUTHNAME:        case SET_AUTHNAME:
      strlcpy(autc->authname, *av, sizeof(autc->authname));                strlcpy(autc->authname, *av, sizeof(autc->authname));
      break;                break;
   
    case SET_PASSWORD:        case SET_PASSWORD:
      strlcpy(autc->password, *av, sizeof(autc->password));                strlcpy(autc->password, *av, sizeof(autc->password));
      break;                break;
       
    case SET_EXTAUTH_SCRIPT: 
        Freee(autc->extauth_script); 
        autc->extauth_script = Mstrdup(MB_AUTH, *av); 
        break; 
       
    case SET_EXTACCT_SCRIPT: 
        Freee(autc->extacct_script); 
        autc->extacct_script = Mstrdup(MB_AUTH, *av); 
        break; 
       
    case SET_MAX_LOGINS: 
      gMaxLogins = atoi(av[0]); 
      if (ac >= 2 && strcasecmp(av[1], "ci") == 0) { 
        gMaxLoginsCI = 1; 
      } else { 
        gMaxLoginsCI = 0; 
      } 
      break; 
       
    case SET_ACCT_UPDATE: 
      val = atoi(*av); 
      if (val < 0) 
        Error("Update interval must be positive."); 
      else 
        autc->acct_update = val; 
      break; 
   
    case SET_ACCT_UPDATE_LIMIT_IN:        case SET_EXTAUTH_SCRIPT:
    case SET_ACCT_UPDATE_LIMIT_OUT:                Freee(autc->extauth_script);
      val = atoi(*av);                autc->extauth_script = Mstrdup(MB_AUTH, *av);
      if (val < 0)                break;
        Error("Update suppression limit must be positive."); 
      else { 
        if ((intptr_t)arg == SET_ACCT_UPDATE_LIMIT_IN) 
          autc->acct_update_lim_recv = val; 
        else 
          autc->acct_update_lim_xmit = val; 
      } 
      break; 
   
    case SET_TIMEOUT:        case SET_EXTACCT_SCRIPT:
      val = atoi(*av);                Freee(autc->extacct_script);
      if (val <= 20)                autc->extacct_script = Mstrdup(MB_AUTH, *av);
        Error("Authorization timeout must be greater then 20.");                break;
      else 
        autc->timeout = val; 
      break; 
       
    case SET_ACCEPT: 
      AcceptCommand(ac, av, &autc->options, gConfList); 
      break; 
   
    case SET_DENY:        case SET_MAX_LOGINS:
      DenyCommand(ac, av, &autc->options, gConfList);                gMaxLogins = (unsigned)atoi(av[0]);
      break;                if (ac >= 2 && strcasecmp(av[1], "ci") == 0) {
                         gMaxLoginsCI = 1;
                 } else {
                         gMaxLoginsCI = 0;
                 }
                 break;
   
    case SET_ENABLE:        case SET_ACCT_UPDATE:
      EnableCommand(ac, av, &autc->options, gConfList);                val = atoi(*av);
      break;                if (val < 0)
                         Error("Update interval must be positive.");
                 else
                         autc->acct_update = val;
                 break;
   
    case SET_DISABLE:        case SET_ACCT_UPDATE_LIMIT_IN:
      DisableCommand(ac, av, &autc->options, gConfList);        case SET_ACCT_UPDATE_LIMIT_OUT:
      break;                val = atoi(*av);
                 if (val < 0)
                         Error("Update suppression limit must be positive.");
                 else {
                         if ((intptr_t)arg == SET_ACCT_UPDATE_LIMIT_IN)
                                 autc->acct_update_lim_recv = val;
                         else
                                 autc->acct_update_lim_xmit = val;
                 }
                 break;
   
    case SET_YES:        case SET_TIMEOUT:
      YesCommand(ac, av, &autc->options, gConfList);                val = atoi(*av);
      break;                if (val <= 20)
                         Error("Authorization timeout must be greater then 20.");
                 else
                         autc->timeout = val;
                 break;
   
    case SET_NO:        case SET_ACCEPT:
      NoCommand(ac, av, &autc->options, gConfList);                AcceptCommand(ac, av, &autc->options, gConfList);
      break;                break;
   
    default:        case SET_DENY:
      assert(0);                DenyCommand(ac, av, &autc->options, gConfList);
  }                break;
   
  return(0);        case SET_ENABLE:
                 EnableCommand(ac, av, &autc->options, gConfList);
                 break;
 
         case SET_DISABLE:
                 DisableCommand(ac, av, &autc->options, gConfList);
                 break;
 
         case SET_YES:
                 YesCommand(ac, av, &autc->options, gConfList);
                 break;
 
         case SET_NO:
                 NoCommand(ac, av, &autc->options, gConfList);
                 break;
 
         default:
                 assert(0);
         }
 
         return (0);
 }  }
   
 /*  /*
  * AuthExternal()   * AuthExternal()
 *  *
  * Authenticate via call external script extauth-script   * Authenticate via call external script extauth-script
  */   */
 
 static int  static int
 AuthExternal(AuthData auth)  AuthExternal(AuthData auth)
 {  {
    char        line[256];        char line[256];
    FILE        *fp;        FILE *fp;
    char        *attr, *val;        char *attr, *val;
    int         len;        int len;
  
    if (!auth->conf.extauth_script || !auth->conf.extauth_script[0]) { 
            Log(LG_ERR, ("[%s] Ext-auth: Script not specified!",  
                auth->info.lnkname)); 
            return (-1); 
    } 
    if (strchr(auth->params.authname, '\'') || 
        strchr(auth->params.authname, '\n')) { 
            Log(LG_ERR, ("[%s] Ext-auth: Denied character in USER_NAME!",  
                auth->info.lnkname)); 
            return (-1); 
    } 
    snprintf(line, sizeof(line), "%s '%s'",  
        auth->conf.extauth_script, auth->params.authname); 
    Log(LG_AUTH, ("[%s] Ext-auth: Invoking auth program: '%s'",  
        auth->info.lnkname, line)); 
    if ((fp = popen(line, "r+")) == NULL) { 
        Perror("Popen"); 
        return (-1); 
    } 
   
    /* SENDING REQUEST */        if (!auth->conf.extauth_script || !auth->conf.extauth_script[0]) {
    fprintf(fp, "USER_NAME:%s\n", auth->params.authname);                Log(LG_ERR, ("[%s] Ext-auth: Script not specified!",
    fprintf(fp, "AUTH_TYPE:%s", ProtoName(auth->proto));                    auth->info.lnkname));
    if (auth->proto == PROTO_CHAP) {                return (-1);
        switch (auth->alg) { 
            case CHAP_ALG_MD5: 
                fprintf(fp, " MD5\n"); 
                break; 
            case CHAP_ALG_MSOFT: 
                fprintf(fp, " MSOFT\n"); 
                break; 
            case CHAP_ALG_MSOFTv2: 
                fprintf(fp, " MSOFTv2\n"); 
                break; 
            default: 
                fprintf(fp, " 0x%02x\n", auth->alg); 
                break; 
         }          }
    } else        if (strchr(auth->params.authname, '\'') ||
        fprintf(fp, "\n");            strchr(auth->params.authname, '\n')) {
                 Log(LG_ERR, ("[%s] Ext-auth: Denied character in USER_NAME!",
                     auth->info.lnkname));
                 return (-1);
         }
         snprintf(line, sizeof(line), "%s '%s'",
             auth->conf.extauth_script, auth->params.authname);
         Log(LG_AUTH, ("[%s] Ext-auth: Invoking auth program: '%s'",
             auth->info.lnkname, line));
         if ((fp = popen(line, "r+")) == NULL) {
                 Perror("Popen");
                 return (-1);
         }
         /* SENDING REQUEST */
         fprintf(fp, "USER_NAME:%s\n", auth->params.authname);
         fprintf(fp, "AUTH_TYPE:%s", ProtoName(auth->proto));
         if (auth->proto == PROTO_CHAP) {
                 switch (auth->alg) {
                 case CHAP_ALG_MD5:
                         fprintf(fp, " MD5\n");
                         break;
                 case CHAP_ALG_MSOFT:
                         fprintf(fp, " MSOFT\n");
                         break;
                 case CHAP_ALG_MSOFTv2:
                         fprintf(fp, " MSOFTv2\n");
                         break;
                 default:
                         fprintf(fp, " 0x%02x\n", auth->alg);
                         break;
                 }
         } else
                 fprintf(fp, "\n");
   
    if (auth->proto == PROTO_PAP)        if (auth->proto == PROTO_PAP)
        fprintf(fp, "USER_PASSWORD:%s\n", auth->params.pap.peer_pass);                fprintf(fp, "USER_PASSWORD:%s\n", auth->params.pap.peer_pass);
   
    fprintf(fp, "ACCT_SESSION_ID:%s\n", auth->info.session_id);        fprintf(fp, "ACCT_SESSION_ID:%s\n", auth->info.session_id);
    fprintf(fp, "LINK:%s\n", auth->info.lnkname);        fprintf(fp, "LINK:%s\n", auth->info.lnkname);
    fprintf(fp, "NAS_PORT:%d\n", auth->info.linkID);        fprintf(fp, "NAS_PORT:%d\n", auth->info.linkID);
    fprintf(fp, "NAS_PORT_TYPE:%s\n", auth->info.phys_type->name);        fprintf(fp, "NAS_PORT_TYPE:%s\n", auth->info.phys_type->name);
    fprintf(fp, "CALLING_STATION_ID:%s\n", auth->params.callingnum);        fprintf(fp, "CALLING_STATION_ID:%s\n", auth->params.callingnum);
    fprintf(fp, "CALLED_STATION_ID:%s\n", auth->params.callednum);        fprintf(fp, "CALLED_STATION_ID:%s\n", auth->params.callednum);
    fprintf(fp, "SELF_NAME:%s\n", auth->params.selfname);        fprintf(fp, "SELF_NAME:%s\n", auth->params.selfname);
    fprintf(fp, "PEER_NAME:%s\n", auth->params.peername);        fprintf(fp, "PEER_NAME:%s\n", auth->params.peername);
    fprintf(fp, "SELF_ADDR:%s\n", auth->params.selfaddr);        fprintf(fp, "SELF_ADDR:%s\n", auth->params.selfaddr);
    fprintf(fp, "PEER_ADDR:%s\n", auth->params.peeraddr);        fprintf(fp, "PEER_ADDR:%s\n", auth->params.peeraddr);
    fprintf(fp, "PEER_PORT:%s\n", auth->params.peerport);        fprintf(fp, "PEER_PORT:%s\n", auth->params.peerport);
    fprintf(fp, "PEER_MAC_ADDR:%s\n", auth->params.peermacaddr);        fprintf(fp, "PEER_MAC_ADDR:%s\n", auth->params.peermacaddr);
    fprintf(fp, "PEER_IFACE:%s\n", auth->params.peeriface);        fprintf(fp, "PEER_IFACE:%s\n", auth->params.peeriface);
    fprintf(fp, "PEER_IDENT:%s\n", auth->info.peer_ident);        fprintf(fp, "PEER_IDENT:%s\n", auth->info.peer_ident);
  
   
     /* REQUEST DONE */  
     fprintf(fp, "\n");  
   
    /* REPLY PROCESSING */        /* REQUEST DONE */
    auth->status = AUTH_STATUS_FAIL;        fprintf(fp, "\n");
    while (fgets(line, sizeof(line), fp)) { 
        /* trim trailing newline */ 
        len = strlen(line); 
        if (len > 0 && line[len - 1] == '\n') { 
            line[len - 1] = '\0'; 
            len--; 
        } 
   
        /* Empty line is the end marker */        /* REPLY PROCESSING */
        if (len == 0)        auth->status = AUTH_STATUS_FAIL;
            break;        while (fgets(line, sizeof(line), fp)) {
                 /* trim trailing newline */
                 len = strlen(line);
                 if (len > 0 && line[len - 1] == '\n') {
                         line[len - 1] = '\0';
                         len--;
                 }
                 /* Empty line is the end marker */
                 if (len == 0)
                         break;
   
        /* split line on attr:value */                /* split line on attr:value */
        val = line;                val = line;
        attr = strsep(&val, ":");                attr = strsep(&val, ":");
   
        /* Log data w/o password */                /* Log data w/o password */
        if (strcmp(attr, "USER_PASSWORD") != 0) {                if (strcmp(attr, "USER_PASSWORD") != 0) {
            Log(LG_AUTH2, ("[%s] Ext-auth: attr:'%s', value:'%s'",                         Log(LG_AUTH2, ("[%s] Ext-auth: attr:'%s', value:'%s'",
                auth->info.lnkname, attr, val));                            auth->info.lnkname, attr, val));
        } else {                } else {
            Log(LG_AUTH2, ("[%s] Ext-auth: attr:'%s', value:'XXX'",                         Log(LG_AUTH2, ("[%s] Ext-auth: attr:'%s', value:'XXX'",
                auth->info.lnkname, attr));                            auth->info.lnkname, attr));
        }                }
     
    if (strcmp(attr, "RESULT") == 0) { 
        if (strcmp(val, "SUCCESS") == 0) { 
            auth->status = AUTH_STATUS_SUCCESS; 
        } else if (strcmp(val, "UNDEF") == 0) { 
            auth->status = AUTH_STATUS_UNDEF; 
        } else  
            auth->status = AUTH_STATUS_FAIL; 
   
    } else if (strcmp(attr, "USER_NAME") == 0) {                if (strcmp(attr, "RESULT") == 0) {
        strlcpy(auth->params.authname, val, sizeof(auth->params.authname));                        if (strcmp(val, "SUCCESS") == 0) {
                                 auth->status = AUTH_STATUS_SUCCESS;
                         } else if (strcmp(val, "UNDEF") == 0) {
                                 auth->status = AUTH_STATUS_UNDEF;
                         } else
                                 auth->status = AUTH_STATUS_FAIL;
   
    } else if (strcmp(attr, "USER_PASSWORD") == 0) {                } else if (strcmp(attr, "USER_NAME") == 0) {
        strlcpy(auth->params.password, val, sizeof(auth->params.password));                        strlcpy(auth->params.authname, val, sizeof(auth->params.authname));
   
    } else if (strcmp(attr, "USER_NT_HASH") == 0) {                } else if (strcmp(attr, "USER_PASSWORD") == 0) {
        if (strlen(val) != 32) {                        strlcpy(auth->params.password, val, sizeof(auth->params.password));
            Log(LG_AUTH, ("[%s] Ext-auth: Incorrect USER_NT_HASH length", auth->info.lnkname)); 
        } else { 
            u_char *bin = Hex2Bin(val); 
            memcpy(auth->params.msoft.nt_hash, bin, sizeof(auth->params.msoft.nt_hash)); 
            Freee(bin); 
            NTPasswordHashHash(auth->params.msoft.nt_hash, auth->params.msoft.nt_hash_hash); 
            auth->params.msoft.has_nt_hash = TRUE; 
        } 
   
    } else if (strcmp(attr, "USER_LM_HASH") == 0) {                } else if (strcmp(attr, "USER_NT_HASH") == 0) {
        if (strlen(val) != 32) {                        if (strlen(val) != 32) {
            Log(LG_AUTH, ("[%s] Ext-auth: Incorrect USER_LM_HASH length", auth->info.lnkname));                                Log(LG_AUTH, ("[%s] Ext-auth: Incorrect USER_NT_HASH length", auth->info.lnkname));
        } else {                        } else {
            u_char *bin = Hex2Bin(val);                                u_char *bin = Hex2Bin(val);
            memcpy(auth->params.msoft.lm_hash, bin, sizeof(auth->params.msoft.lm_hash)); 
            Freee(bin); 
            auth->params.msoft.has_lm_hash = TRUE; 
        } 
   
    } else if (strcmp(attr, "FRAMED_IP_ADDRESS") == 0) {                                memcpy(auth->params.msoft.nt_hash, bin, sizeof(auth->params.msoft.nt_hash));
        auth->params.range_valid =                                 Freee(bin);
            ParseRange(val, &auth->params.range, ALLOW_IPV4);                                NTPasswordHashHash(auth->params.msoft.nt_hash, auth->params.msoft.nt_hash_hash);
                                 auth->params.msoft.has_nt_hash = TRUE;
                         }
   
    } else if (strcmp(attr, "PRIMARY_DNS_SERVER") == 0) {                } else if (strcmp(attr, "USER_LM_HASH") == 0) {
        inet_pton(AF_INET, val, &auth->params.peer_dns[0]);                        if (strlen(val) != 32) {
                                 Log(LG_AUTH, ("[%s] Ext-auth: Incorrect USER_LM_HASH length", auth->info.lnkname));
                         } else {
                                 u_char *bin = Hex2Bin(val);
   
    } else if (strcmp(attr, "SECONDARY_DNS_SERVER") == 0) {                                memcpy(auth->params.msoft.lm_hash, bin, sizeof(auth->params.msoft.lm_hash));
        inet_pton(AF_INET, val, &auth->params.peer_dns[1]);                                Freee(bin);
                                 auth->params.msoft.has_lm_hash = TRUE;
                         }
   
    } else if (strcmp(attr, "PRIMARY_NBNS_SERVER") == 0) {                } else if (strcmp(attr, "FRAMED_IP_ADDRESS") == 0) {
        inet_pton(AF_INET, val, &auth->params.peer_nbns[0]);                        auth->params.range_valid =
                             ParseRange(val, &auth->params.range, ALLOW_IPV4);
   
    } else if (strcmp(attr, "SECONDARY_NBNS_SERVER") == 0) {                } else if (strcmp(attr, "PRIMARY_DNS_SERVER") == 0) {
        inet_pton(AF_INET, val, &auth->params.peer_nbns[1]);                        inet_pton(AF_INET, val, &auth->params.peer_dns[0]);
   
    } else if (strcmp(attr, "FRAMED_ROUTE") == 0) {                } else if (strcmp(attr, "SECONDARY_DNS_SERVER") == 0) {
        struct u_range        range;                        inet_pton(AF_INET, val, &auth->params.peer_dns[1]);
   
        if (!ParseRange(val, &range, ALLOW_IPV4)) {                } else if (strcmp(attr, "PRIMARY_NBNS_SERVER") == 0) {
          Log(LG_AUTH, ("[%s] Ext-auth: FRAMED_ROUTE: Bad route \"%s\"",                         inet_pton(AF_INET, val, &auth->params.peer_nbns[0]);
            auth->info.lnkname, val)); 
        } else { 
            struct ifaceroute     *r, *r1; 
            int         j; 
   
            r = Malloc(MB_AUTH, sizeof(struct ifaceroute));                } else if (strcmp(attr, "SECONDARY_NBNS_SERVER") == 0) {
            r->dest = range;                        inet_pton(AF_INET, val, &auth->params.peer_nbns[1]);
            r->ok = 0; 
            j = 0; 
            SLIST_FOREACH(r1, &auth->params.routes, next) { 
              if (!u_rangecompare(&r->dest, &r1->dest)) { 
                Log(LG_AUTH, ("[%s] Ext-auth: Duplicate route", auth->info.lnkname)); 
                j = 1; 
              } 
            }; 
            if (j == 0) { 
                SLIST_INSERT_HEAD(&auth->params.routes, r, next); 
            } else { 
                Freee(r); 
            } 
        } 
   
    } else if (strcmp(attr, "FRAMED_IPV6_ROUTE") == 0) {                } else if (strcmp(attr, "FRAMED_ROUTE") == 0) {
        struct u_range        range;                        struct u_range range;
   
        if (!ParseRange(val, &range, ALLOW_IPV6)) {                        if (!ParseRange(val, &range, ALLOW_IPV4)) {
          Log(LG_AUTH, ("[%s] Ext-auth: FRAMED_IPV6_ROUTE: Bad route \"%s\"",                                 Log(LG_ERR | LG_AUTH, ("[%s] Ext-auth: FRAMED_ROUTE: Bad route \"%s\"",
            auth->info.lnkname, val));                                    auth->info.lnkname, val));
        } else {                        } else {
            struct ifaceroute     *r, *r1;                                struct ifaceroute *r, *r1;
            int         j;                                int j;
   
            r = Malloc(MB_AUTH, sizeof(struct ifaceroute));                                r = Malloc(MB_AUTH, sizeof(struct ifaceroute));
            r->dest = range;                                r->dest = range;
            r->ok = 0;                                r->ok = 0;
            j = 0;                                j = 0;
            SLIST_FOREACH(r1, &auth->params.routes, next) {                                SLIST_FOREACH(r1, &auth->params.routes, next) {
              if (!u_rangecompare(&r->dest, &r1->dest)) {                                        if (!u_rangecompare(&r->dest, &r1->dest)) {
                Log(LG_AUTH, ("[%s] Ext-auth: Duplicate route", auth->info.lnkname));                                                Log(LG_ERR | LG_AUTH, ("[%s] Ext-auth: Duplicate route",
                j = 1;                                                    auth->info.lnkname));
              }                                                j = 1;
            };                                        }
            if (j == 0) {                                };
                SLIST_INSERT_HEAD(&auth->params.routes, r, next);                                if (j == 0) {
            } else {                                        SLIST_INSERT_HEAD(&auth->params.routes, r, next);
                Freee(r);                                } else {
            }                                        Freee(r);
        }                                }
                         }
   
    } else if (strcmp(attr, "SESSION_TIMEOUT") == 0) {                } else if (strcmp(attr, "FRAMED_IPV6_ROUTE") == 0) {
        auth->params.session_timeout = atoi(val);                        struct u_range range;
   
    } else if (strcmp(attr, "IDLE_TIMEOUT") == 0) {                        if (!ParseRange(val, &range, ALLOW_IPV6)) {
        auth->params.idle_timeout = atoi(val);                                Log(LG_ERR | LG_AUTH, ("[%s] Ext-auth: FRAMED_IPV6_ROUTE: Bad route \"%s\"",
                                     auth->info.lnkname, val));
                         } else {
                                 struct ifaceroute *r, *r1;
                                 int j;
   
    } else if (strcmp(attr, "ACCT_INTERIM_INTERVAL") == 0) {                                r = Malloc(MB_AUTH, sizeof(struct ifaceroute));
        auth->params.acct_update = atoi(val);                                r->dest = range;
                                 r->ok = 0;
                                 j = 0;
                                 SLIST_FOREACH(r1, &auth->params.routes, next) {
                                         if (!u_rangecompare(&r->dest, &r1->dest)) {
                                                 Log(LG_ERR | LG_AUTH, ("[%s] Ext-auth: Duplicate route",
                                                     auth->info.lnkname));
                                                 j = 1;
                                         }
                                 };
                                 if (j == 0) {
                                         SLIST_INSERT_HEAD(&auth->params.routes, r, next);
                                 } else {
                                         Freee(r);
                                 }
                         }
   
    } else if (strcmp(attr, "ACCT_INTERIM_LIM_RECV") == 0) {                } else if (strcmp(attr, "SESSION_TIMEOUT") == 0) {
        auth->params.acct_update_lim_recv = atoi(val);                        auth->params.session_timeout = atoi(val);
   
    } else if (strcmp(attr, "ACCT_INTERIM_LIM_XMIT") == 0) {                } else if (strcmp(attr, "IDLE_TIMEOUT") == 0) {
        auth->params.acct_update_lim_xmit = atoi(val);                        auth->params.idle_timeout = atoi(val);
   
    } else if (strcmp(attr, "FRAMED_MTU") == 0) {                } else if (strcmp(attr, "ACCT_INTERIM_INTERVAL") == 0) {
        auth->params.mtu = atoi(val);                        auth->params.acct_update = atoi(val);
   
    } else if (strcmp(attr, "FRAMED_COMPRESSION") == 0) {                } else if (strcmp(attr, "ACCT_INTERIM_LIM_RECV") == 0) {
        if (atoi(val) == 1)                        auth->params.acct_update_lim_recv = atoi(val);
            auth->params.vjc_enable = 1; 
   
    } else if (strcmp(attr, "FRAMED_POOL") == 0) {                } else if (strcmp(attr, "ACCT_INTERIM_LIM_XMIT") == 0) {
        strlcpy(auth->params.ippool, val, sizeof(auth->params.ippool));                        auth->params.acct_update_lim_xmit = atoi(val);
   
    } else if (strcmp(attr, "REPLY_MESSAGE") == 0) {                } else if (strcmp(attr, "FRAMED_MTU") == 0) {
        Freee(auth->reply_message);                        auth->params.mtu = atoi(val);
        auth->reply_message = Mstrdup(MB_AUTH, val); 
   
    } else if (strcmp(attr, "MS_CHAP_ERROR") == 0) {                } else if (strcmp(attr, "FRAMED_COMPRESSION") == 0) {
        Freee(auth->mschap_error);                        if (atoi(val) == 1)
        /* "E=%d R=0 M=%s" */                                auth->params.vjc_enable = 1;
        auth->mschap_error = Mstrdup(MB_AUTH, val); 
   
    } else if (strcmp(attr, "MPD_ACTION") == 0) {                } else if (strcmp(attr, "FRAMED_POOL") == 0) {
        strlcpy(auth->params.action, val, sizeof(auth->params.action));                        strlcpy(auth->params.ippool, val, sizeof(auth->params.ippool));
   
    } else if (strcmp(attr, "MPD_IFACE_NAME") == 0) {                } else if (strcmp(attr, "REPLY_MESSAGE") == 0) {
        strlcpy(auth->params.ifname, val, sizeof(auth->params.ifname));                        Freee(auth->reply_message);
                         auth->reply_message = Mstrdup(MB_AUTH, val);
   
                   } else if (strcmp(attr, "MS_CHAP_ERROR") == 0) {
                           Freee(auth->mschap_error);
                           /* "E=%d R=0 M=%s" */
                           auth->mschap_error = Mstrdup(MB_AUTH, val);
   
                   } else if (strcmp(attr, "MPD_ACTION") == 0) {
                           strlcpy(auth->params.action, val, sizeof(auth->params.action));
   
                   } else if (strcmp(attr, "MPD_IFACE_NAME") == 0) {
                           strlcpy(auth->params.ifname, val, sizeof(auth->params.ifname));
   
 #ifdef SIOCSIFDESCR  #ifdef SIOCSIFDESCR
    } else if (strcmp(attr, "MPD_IFACE_DESCR") == 0) {                } else if (strcmp(attr, "MPD_IFACE_DESCR") == 0) {
        Freee(auth->params.ifdescr);                        Freee(auth->params.ifdescr);
        auth->params.ifdescr = Mstrdup(MB_AUTH, val);                        auth->params.ifdescr = Mstrdup(MB_AUTH, val);
#endif /* SIOCSIFDESCR */#endif                                  /* SIOCSIFDESCR */
 #ifdef SIOCAIFGROUP  #ifdef SIOCAIFGROUP
    } else if (strcmp(attr, "MPD_IFACE_GROUP") == 0) {                } else if (strcmp(attr, "MPD_IFACE_GROUP") == 0) {
        strlcpy(auth->params.ifgroup, val, sizeof(auth->params.ifgroup));                        strlcpy(auth->params.ifgroup, val, sizeof(auth->params.ifgroup));
 #endif  #endif
 #if defined(USE_IPFW) || defined(USE_NG_BPF)  #if defined(USE_IPFW) || defined(USE_NG_BPF)
    } else if (strncmp(attr, "MPD_", 4) == 0) {                } else if (strncmp(attr, "MPD_", 4) == 0) {
        struct acl      **acls, *acls1;                        struct acl **acls, *acls1;
        char            *acl1, *acl2, *acl3;                        char *acl1, *acl2, *acl3;
        int             i;                        int i;
        
            acl1 = NULL;                        acl1 = NULL;
            acls = NULL;                        acls = NULL;
 #ifdef USE_IPFW  #ifdef USE_IPFW
            if (strcmp(attr, "MPD_RULE") == 0) {                        if (strcmp(attr, "MPD_RULE") == 0) {
              acl1 = val;                                acl1 = val;
              acls = &(auth->params.acl_rule);                                acls = &(auth->params.acl_rule);
            } else if (strcmp(attr, "MPD_PIPE") == 0) {                        } else if (strcmp(attr, "MPD_PIPE") == 0) {
              acl1 = val;                                acl1 = val;
              acls = &(auth->params.acl_pipe);                                acls = &(auth->params.acl_pipe);
            } else if (strcmp(attr, "MPD_QUEUE") == 0) {                        } else if (strcmp(attr, "MPD_QUEUE") == 0) {
              acl1 = val;                                acl1 = val;
              acls = &(auth->params.acl_queue);                                acls = &(auth->params.acl_queue);
            } else if (strcmp(attr, "MPD_TABLE") == 0) {                        } else if (strcmp(attr, "MPD_TABLE") == 0) {
              acl1 = val;                                acl1 = val;
              acls = &(auth->params.acl_table);                                acls = &(auth->params.acl_table);
            } else if (strcmp(attr, "MPD_TABLE_STATIC") == 0) {                        } else if (strcmp(attr, "MPD_TABLE_STATIC") == 0) {
              acl1 = val;                                acl1 = val;
              acls = &(auth->params.acl_table);                                acls = &(auth->params.acl_table);
            } else                        } else
#endif /* USE_IPFW */#endif                                  /* USE_IPFW */
 #ifdef USE_NG_BPF  #ifdef USE_NG_BPF
            if (strcmp(attr, "MPD_FILTER") == 0) {                        if (strcmp(attr, "MPD_FILTER") == 0) {
              acl1 = val;                                acl1 = val;
              acl2 = strsep(&acl1, "#");                                acl2 = strsep(&acl1, "#");
              i = atol(acl2);                                i = atol(acl2);
              if (i <= 0 || i > ACL_FILTERS) {                                if (i <= 0 || i > ACL_FILTERS) {
                Log(LG_ERR, ("[%s] Ext-auth: wrong filter number: %i",                                        Log(LG_ERR, ("[%s] Ext-auth: wrong filter number: %i",
                  auth->info.lnkname, i));                                            auth->info.lnkname, i));
                continue;                                        continue;
              }                                }
              acls = &(auth->params.acl_filters[i - 1]);                                acls = &(auth->params.acl_filters[i - 1]);
            } else if (strcmp(attr, "MPD_LIMIT") == 0) {                        } else if (strcmp(attr, "MPD_LIMIT") == 0) {
              acl1 = val;                                acl1 = val;
              acl2 = strsep(&acl1, "#");                                acl2 = strsep(&acl1, "#");
              if (strcasecmp(acl2, "in") == 0) {                                if (strcasecmp(acl2, "in") == 0) {
                i = 0;                                        i = 0;
              } else if (strcasecmp(acl2, "out") == 0) {                                } else if (strcasecmp(acl2, "out") == 0) {
                i = 1;                                        i = 1;
              } else {                                } else {
                Log(LG_ERR, ("[%s] Ext-auth: wrong limit direction: '%s'",                                        Log(LG_ERR, ("[%s] Ext-auth: wrong limit direction: '%s'",
                  auth->info.lnkname, acl2));                                            auth->info.lnkname, acl2));
                continue;                                        continue;
              }                                }
              acls = &(auth->params.acl_limits[i]);                                acls = &(auth->params.acl_limits[i]);
            } else {                        } else {
              Log(LG_ERR, ("[%s] Ext-auth: Dropping MPD vendor specific attribute: '%s'",                                Log(LG_ERR, ("[%s] Ext-auth: Dropping MPD vendor specific attribute: '%s'",
                auth->info.lnkname, attr));                                    auth->info.lnkname, attr));
              continue;                                continue;
            }                        }
#endif /* USE_NG_BPF */#endif                                  /* USE_NG_BPF */
   
            if (acl1 == NULL) {                        if (acl1 == NULL) {
              Log(LG_ERR, ("[%s] Ext-auth: incorrect acl!",                                Log(LG_ERR, ("[%s] Ext-auth: incorrect acl!",
                auth->info.lnkname));                                    auth->info.lnkname));
              continue;                                continue;
            }                        }
                                    acl3 = acl1;
            acl3 = acl1;                        strsep(&acl3, "=");
            strsep(&acl3, "=");                        acl2 = acl1;
            acl2 = acl1;                        strsep(&acl2, "#");
            strsep(&acl2, "#");                        i = atol(acl1);
            i = atol(acl1);                        if (i <= 0) {
            if (i <= 0) {                                Log(LG_ERR, ("[%s] Ext-auth: wrong acl number: %i",
              Log(LG_ERR, ("[%s] Ext-auth: wrong acl number: %i",                                    auth->info.lnkname, i));
                auth->info.lnkname, i));                                continue;
              continue;                        }
            }                        if ((acl3 == NULL) || (acl3[0] == 0)) {
            if ((acl3 == NULL) || (acl3[0] == 0)) {                                Log(LG_ERR, ("[%s] Ext-auth: wrong acl", auth->info.lnkname));
              Log(LG_ERR, ("[%s] Ext-auth: wrong acl", auth->info.lnkname));                                continue;
              continue;                        }
            }                        acls1 = Malloc(MB_AUTH, sizeof(struct acl) + strlen(acl3));
            acls1 = Malloc(MB_AUTH, sizeof(struct acl) + strlen(acl3));                        if (strcmp(attr, "MPD_TABLE_STATIC") != 0) {
            if (strcmp(attr, "MPD_TABLE_STATIC") != 0) {                                acls1->number = i;
                    acls1->number = i;                                acls1->real_number = 0;
                    acls1->real_number = 0;                        } else {
            } else {                                acls1->number = 0;
                    acls1->number = 0;                                acls1->real_number = i;
                    acls1->real_number = i;                        }
            }                        if (acl2)
            if (acl2)                                strlcpy(acls1->name, acl2, sizeof(acls1->name));
                strlcpy(acls1->name, acl2, sizeof(acls1->name));                        strcpy(acls1->rule, acl3);
            strcpy(acls1->rule, acl3);                        while ((*acls != NULL) && ((*acls)->number < acls1->number))
            while ((*acls != NULL) && ((*acls)->number < acls1->number))                                acls = &((*acls)->next);
              acls = &((*acls)->next); 
   
            if (*acls == NULL) {                        if (*acls == NULL) {
              acls1->next = NULL;                                acls1->next = NULL;
            } else if (((*acls)->number == acls1->number) &&                        } else if (((*acls)->number == acls1->number) &&
                (strcmp(attr, "MPD_TABLE") != 0) &&                                    (strcmp(attr, "MPD_TABLE") != 0) &&
                (strcmp(attr, "MPD_TABLE_STATIC") != 0)) {                            (strcmp(attr, "MPD_TABLE_STATIC") != 0)) {
              Log(LG_ERR, ("[%s] Ext-auth: duplicate acl",                                Log(LG_ERR, ("[%s] Ext-auth: duplicate acl",
                auth->info.lnkname));                                    auth->info.lnkname));
              continue;                                continue;
            } else {                        } else {
              acls1->next = *acls;                                acls1->next = *acls;
            }                        }
            *acls = acls1;                        *acls = acls1;
#endif /* USE_IPFW or USE_NG_BPF */#endif                                  /* USE_IPFW or USE_NG_BPF */
   
    } else {                } else {
        Log(LG_ERR, ("[%s] Ext-auth: Unknown attr:'%s'",                         Log(LG_ERR, ("[%s] Ext-auth: Unknown attr:'%s'",
            auth->info.lnkname, attr));                            auth->info.lnkname, attr));
    }                }
    }        }
 
    pclose(fp);        pclose(fp);
    return (0);        return (0);
 }  }
   
 /*  /*
  * AuthExternalAcct()   * AuthExternalAcct()
 *  *
  * Accounting via call external script extacct-script   * Accounting via call external script extacct-script
  */   */
 
 static int  static int
 AuthExternalAcct(AuthData auth)  AuthExternalAcct(AuthData auth)
 {  {
    char        line[256];        char line[256];
    FILE        *fp;        FILE *fp;
    char        *attr, *val;        char *attr, *val;
    int         len;        int len;
 
    if (!auth->conf.extacct_script || !auth->conf.extacct_script[0]) {        if (!auth->conf.extacct_script || !auth->conf.extacct_script[0]) {
        Log(LG_ERR, ("[%s] Ext-acct: Script not specified!",                 Log(LG_ERR, ("[%s] Ext-acct: Script not specified!",
            auth->info.lnkname));                    auth->info.lnkname));
        return (-1);                return (-1);
    }        }
    if (strchr(auth->params.authname, '\'') ||        if (strchr(auth->params.authname, '\'') ||
             strchr(auth->params.authname, '\n')) {              strchr(auth->params.authname, '\n')) {
        Log(LG_ERR, ("[%s] Ext-acct: Denied character in USER_NAME!",                 Log(LG_ERR, ("[%s] Ext-acct: Denied character in USER_NAME!",
            auth->info.lnkname));                    auth->info.lnkname));
        return (-1);                return (-1);
    }        }
    snprintf(line, sizeof(line), "%s '%s'",         snprintf(line, sizeof(line), "%s '%s'",
        auth->conf.extacct_script, auth->params.authname);            auth->conf.extacct_script, auth->params.authname);
    Log(LG_AUTH, ("[%s] Ext-acct: Invoking acct program: '%s'",         Log(LG_AUTH, ("[%s] Ext-acct: Invoking acct program: '%s'",
        auth->info.lnkname, line));            auth->info.lnkname, line));
    if ((fp = popen(line, "r+")) == NULL) {        if ((fp = popen(line, "r+")) == NULL) {
        Perror("Popen");                Perror("Popen");
        return (-1);                return (-1);
    }        }
         /* SENDING REQUEST */
         fprintf(fp, "ACCT_STATUS_TYPE:%s\n",
             (auth->acct_type == AUTH_ACCT_START) ?
             "START" : ((auth->acct_type == AUTH_ACCT_STOP) ?
             "STOP" : "UPDATE"));
   
    /* SENDING REQUEST */        fprintf(fp, "ACCT_SESSION_ID:%s\n", auth->info.session_id);
    fprintf(fp, "ACCT_STATUS_TYPE:%s\n",         fprintf(fp, "ACCT_MULTI_SESSION_ID:%s\n", auth->info.msession_id);
        (auth->acct_type == AUTH_ACCT_START)?        fprintf(fp, "USER_NAME:%s\n", auth->params.authname);
            "START":((auth->acct_type == AUTH_ACCT_STOP)?        fprintf(fp, "IFACE:%s\n", auth->info.ifname);
                "STOP":"UPDATE"));        fprintf(fp, "IFACE_INDEX:%d\n", auth->info.ifindex);
         fprintf(fp, "BUNDLE:%s\n", auth->info.bundname);
         fprintf(fp, "LINK:%s\n", auth->info.lnkname);
         fprintf(fp, "NAS_PORT:%d\n", auth->info.linkID);
         fprintf(fp, "NAS_PORT_TYPE:%s\n", auth->info.phys_type->name);
         fprintf(fp, "ACCT_LINK_COUNT:%d\n", auth->info.n_links);
         fprintf(fp, "CALLING_STATION_ID:%s\n", auth->params.callingnum);
         fprintf(fp, "CALLED_STATION_ID:%s\n", auth->params.callednum);
         fprintf(fp, "SELF_NAME:%s\n", auth->params.selfname);
         fprintf(fp, "PEER_NAME:%s\n", auth->params.peername);
         fprintf(fp, "SELF_ADDR:%s\n", auth->params.selfaddr);
         fprintf(fp, "PEER_ADDR:%s\n", auth->params.peeraddr);
         fprintf(fp, "PEER_PORT:%s\n", auth->params.peerport);
         fprintf(fp, "PEER_MAC_ADDR:%s\n", auth->params.peermacaddr);
         fprintf(fp, "PEER_IFACE:%s\n", auth->params.peeriface);
         fprintf(fp, "PEER_IDENT:%s\n", auth->info.peer_ident);
   
    fprintf(fp, "ACCT_SESSION_ID:%s\n", auth->info.session_id);        fprintf(fp, "FRAMED_IP_ADDRESS:%s\n",
    fprintf(fp, "ACCT_MULTI_SESSION_ID:%s\n", auth->info.msession_id);            inet_ntoa(auth->info.peer_addr));
    fprintf(fp, "USER_NAME:%s\n", auth->params.authname); 
    fprintf(fp, "IFACE:%s\n", auth->info.ifname); 
    fprintf(fp, "IFACE_INDEX:%d\n", auth->info.ifindex); 
    fprintf(fp, "BUNDLE:%s\n", auth->info.bundname); 
    fprintf(fp, "LINK:%s\n", auth->info.lnkname); 
    fprintf(fp, "NAS_PORT:%d\n", auth->info.linkID); 
    fprintf(fp, "NAS_PORT_TYPE:%s\n", auth->info.phys_type->name); 
    fprintf(fp, "ACCT_LINK_COUNT:%d\n", auth->info.n_links); 
    fprintf(fp, "CALLING_STATION_ID:%s\n", auth->params.callingnum); 
    fprintf(fp, "CALLED_STATION_ID:%s\n", auth->params.callednum); 
    fprintf(fp, "SELF_NAME:%s\n", auth->params.selfname); 
    fprintf(fp, "PEER_NAME:%s\n", auth->params.peername); 
    fprintf(fp, "SELF_ADDR:%s\n", auth->params.selfaddr); 
    fprintf(fp, "PEER_ADDR:%s\n", auth->params.peeraddr); 
    fprintf(fp, "PEER_PORT:%s\n", auth->params.peerport); 
    fprintf(fp, "PEER_MAC_ADDR:%s\n", auth->params.peermacaddr); 
    fprintf(fp, "PEER_IFACE:%s\n", auth->params.peeriface); 
    fprintf(fp, "PEER_IDENT:%s\n", auth->info.peer_ident); 
   
    fprintf(fp, "FRAMED_IP_ADDRESS:%s\n",        if (auth->acct_type == AUTH_ACCT_STOP)
        inet_ntoa(auth->info.peer_addr));                fprintf(fp, "ACCT_TERMINATE_CAUSE:%s\n", auth->info.downReason);
   
    if (auth->acct_type == AUTH_ACCT_STOP)        if (auth->acct_type != AUTH_ACCT_START) {
        fprintf(fp, "ACCT_TERMINATE_CAUSE:%s\n", auth->info.downReason); 
 
    if (auth->acct_type != AUTH_ACCT_START) { 
 #ifdef USE_NG_BPF  #ifdef USE_NG_BPF
        struct svcstatrec *ssr;                struct svcstatrec *ssr;
 
 #endif  #endif
        fprintf(fp, "ACCT_SESSION_TIME:%ld\n",                 fprintf(fp, "ACCT_SESSION_TIME:%ld\n",
            (long int)(time(NULL) - auth->info.last_up));                    (long int)(time(NULL) - auth->info.last_up));
        fprintf(fp, "ACCT_INPUT_OCTETS:%llu\n",                 fprintf(fp, "ACCT_INPUT_OCTETS:%llu\n",
            (long long unsigned)auth->info.stats.recvOctets);                    (long long unsigned)auth->info.stats.recvOctets);
        fprintf(fp, "ACCT_INPUT_PACKETS:%llu\n",                 fprintf(fp, "ACCT_INPUT_PACKETS:%llu\n",
            (long long unsigned)auth->info.stats.recvFrames);                    (long long unsigned)auth->info.stats.recvFrames);
        fprintf(fp, "ACCT_OUTPUT_OCTETS:%llu\n",                 fprintf(fp, "ACCT_OUTPUT_OCTETS:%llu\n",
            (long long unsigned)auth->info.stats.xmitOctets);                    (long long unsigned)auth->info.stats.xmitOctets);
        fprintf(fp, "ACCT_OUTPUT_PACKETS:%llu\n",                 fprintf(fp, "ACCT_OUTPUT_PACKETS:%llu\n",
            (long long unsigned)auth->info.stats.xmitFrames);                    (long long unsigned)auth->info.stats.xmitFrames);
 #ifdef USE_NG_BPF  #ifdef USE_NG_BPF
        SLIST_FOREACH(ssr, &auth->info.ss.stat[0], next) {                SLIST_FOREACH(ssr, &auth->info.ss.stat[0], next) {
            fprintf(fp, "MPD_INPUT_OCTETS:%s:%llu\n",                        fprintf(fp, "MPD_INPUT_OCTETS:%s:%llu\n",
                ssr->name, (long long unsigned)ssr->Octets);                            ssr->name, (long long unsigned)ssr->Octets);
            fprintf(fp, "MPD_INPUT_PACKETS:%s:%llu\n",                        fprintf(fp, "MPD_INPUT_PACKETS:%s:%llu\n",
                ssr->name, (long long unsigned)ssr->Packets);                            ssr->name, (long long unsigned)ssr->Packets);
                 }
                 SLIST_FOREACH(ssr, &auth->info.ss.stat[1], next) {
                         fprintf(fp, "MPD_OUTPUT_OCTETS:%s:%llu\n",
                             ssr->name, (long long unsigned)ssr->Octets);
                         fprintf(fp, "MPD_OUTPUT_PACKETS:%s:%llu\n",
                             ssr->name, (long long unsigned)ssr->Packets);
                 }
 #endif                                  /* USE_NG_BPF */
         }          }
        SLIST_FOREACH(ssr, &auth->info.ss.stat[1], next) {        /* REQUEST DONE */
            fprintf(fp, "MPD_OUTPUT_OCTETS:%s:%llu\n",        fprintf(fp, "\n");
                ssr->name, (long long unsigned)ssr->Octets); 
            fprintf(fp, "MPD_OUTPUT_PACKETS:%s:%llu\n", 
                ssr->name, (long long unsigned)ssr->Packets); 
        } 
#endif /* USE_NG_BPF */ 
    } 
   
    /* REQUEST DONE */        /* REPLY PROCESSING */
    fprintf(fp, "\n");        while (fgets(line, sizeof(line), fp)) {
                 /* trim trailing newline */
                 len = strlen(line);
                 if (len > 0 && line[len - 1] == '\n') {
                         line[len - 1] = '\0';
                         len--;
                 }
                 /* Empty line is the end marker */
                 if (len == 0)
                         break;
   
    /* REPLY PROCESSING */                /* split line on attr:value */
    while (fgets(line, sizeof(line), fp)) {                val = line;
        /* trim trailing newline */                attr = strsep(&val, ":");
        len = strlen(line); 
        if (len > 0 && line[len - 1] == '\n') { 
            line[len - 1] = '\0'; 
            len--; 
        } 
   
        /* Empty line is the end marker */                Log(LG_AUTH2, ("[%s] Ext-acct: attr:'%s', value:'%s'",
        if (len == 0)                    auth->info.lnkname, attr, val));
            break; 
   
        /* split line on attr:value */                if (strcmp(attr, "MPD_DROP_USER") == 0) {
        val = line;                        auth->drop_user = atoi(val);
        attr = strsep(&val, ":"); 
   
        Log(LG_AUTH2, ("[%s] Ext-acct: attr:'%s', value:'%s'",                 } else {
            auth->info.lnkname, attr, val));                        Log(LG_ERR, ("[%s] Ext-acct: Unknown attr:'%s'",
                                auth->info.lnkname, attr));
        if (strcmp(attr, "MPD_DROP_USER") == 0) {                }
            auth->drop_user = atoi(val); 
 
        } else { 
            Log(LG_ERR, ("[%s] Ext-acct: Unknown attr:'%s'",  
                auth->info.lnkname, attr)); 
         }          }
    }
         pclose(fp);
    pclose(fp);        return (0);
    return (0); 
 }  }

Removed from v.1.1.1.2  
changed lines
  Added in v.1.1.1.4.2.1


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