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