Annotation of embedaddon/mpd/src/auth.c, revision 1.1.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>