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