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