Annotation of embedaddon/libpdel/ppp/ppp_link.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * Copyright (c) 2001-2002 Packet Design, LLC.
4: * All rights reserved.
5: *
6: * Subject to the following obligations and disclaimer of warranty,
7: * use and redistribution of this software, in source or object code
8: * forms, with or without modifications are expressly permitted by
9: * Packet Design; provided, however, that:
10: *
11: * (i) Any and all reproductions of the source or object code
12: * must include the copyright notice above and the following
13: * disclaimer of warranties; and
14: * (ii) No rights are granted, in any manner or form, to use
15: * Packet Design trademarks, including the mark "PACKET DESIGN"
16: * on advertising, endorsements, or otherwise except as such
17: * appears in the above copyright notice or in the software.
18: *
19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
36: * THE POSSIBILITY OF SUCH DAMAGE.
37: *
38: * Author: Archie Cobbs <archie@freebsd.org>
39: */
40:
41: #include "ppp/ppp_defs.h"
42: #include "ppp/ppp_log.h"
43: #include "ppp/ppp_fsm_option.h"
44: #include "ppp/ppp_fsm.h"
45: #include "ppp/ppp_auth.h"
46: #include "ppp/ppp_lcp.h"
47: #include "ppp/ppp_node.h"
48: #include "ppp/ppp_engine.h"
49: #include "ppp/ppp_bundle.h"
50: #include "ppp/ppp_channel.h"
51: #include "ppp/ppp_link.h"
52:
53: #define LINK_MTYPE "ppp_link"
54: #define PKTBUFLEN 4096
55: #define LINK_LATENCY 100 /* arbitrary fixed value */
56: #define LINK_BANDWIDTH 100 /* arbitrary fixed value */
57:
58: #define AUTH_TIMEOUT 20 /* time limit for auth phase */
59:
60: #define WINXP_PPTP_HACK(x) ((x) - 20) /* winxp pptp stupidity hack */
61:
62: /*
63: * Authorization info for one direction
64: */
65: struct ppp_link_auth {
66: struct ppp_link *link; /* back pointer */
67: u_int16_t proto; /* auth protocol number */
68: const struct ppp_auth_type *type; /* auth type negotiated */
69: void *arg; /* auth object in progress */
70: struct ppp_auth_cred cred; /* auth credentials */
71: struct ppp_auth_resp resp; /* auth response */
72: union ppp_auth_mppe mppe; /* mppe keys from ms-chap */
73: struct paction *action;/* auth acquire/check action */
74: };
75:
76: /*
77: * PPP link structure
78: */
79: struct ppp_link {
80: enum ppp_link_state state; /* link state */
81: struct ppp_log *log; /* log */
82: struct ppp_link_config conf; /* link configuration */
83: struct ppp_engine *engine; /* ppp engine */
84: struct ppp_channel *device; /* underlying device */
85: struct ppp_node *node; /* ng_ppp(4) node */
86: struct ppp_fsm *lcp; /* lcp fsm */
87: struct ppp_lcp_req lcp_req; /* lcp negotiation result */
88: struct ppp_bundle *bundle; /* bundle, if joined */
89: struct pevent_ctx *ev_ctx; /* event context */
90: pthread_mutex_t *mutex; /* mutex */
91: struct pevent *lcp_event; /* lcp fsm event */
92: struct pevent *dev_event; /* device event */
93: struct pevent *auth_timer; /* timer for auth phase */
94: u_char device_up; /* device is up */
95: struct ppp_link_auth auth[2]; /* authorization info */
96: u_int16_t link_num; /* ppp node link number */
97: u_char shutdown; /* normal shutdown */
98: };
99:
100: /* Internal functions */
101: static void ppp_link_join(struct ppp_link *link);
102: static void ppp_link_unjoin(struct ppp_link *link);
103: static int ppp_link_get_node(struct ppp_link *link);
104: static void ppp_link_auth_start(struct ppp_link *link);
105: static void ppp_link_auth_stop(struct ppp_link *link);
106:
107: static ppp_node_recv_t ppp_link_node_recv;
108:
109: static pevent_handler_t ppp_link_device_event;
110: static pevent_handler_t ppp_link_lcp_event;
111: static pevent_handler_t ppp_link_auth_timeout;
112:
113: /* Macro for logging */
114: #define LOG(sev, fmt, args...) PPP_LOG(link->log, sev, fmt , ## args)
115:
116: /***********************************************************************
117: PUBLIC FUNCTIONS
118: ***********************************************************************/
119:
120: /*
121: * Create a new PPP link.
122: *
123: * The link is not returned. Instead it disappears into the PPP engine.
124: * The "device" and "log" are destroyed when the link is destroyed.
125: */
126: int
127: ppp_link_create(struct ppp_engine *engine, struct ppp_channel *device,
128: struct ppp_link_config *conf, struct ppp_log *log)
129: {
130: struct ppp_fsm_instance *inst = NULL;
131: struct ppp_lcp_config lcp_conf;
132: struct ppp_fsm *lcp = NULL;
133: struct ppp_link *link;
134: int esave;
135: int i;
136: int j;
137:
138: /* Create new link structure */
139: if ((link = MALLOC(LINK_MTYPE, sizeof(*link))) == NULL)
140: return (-1);
141: memset(link, 0, sizeof(*link));
142: link->state = PPP_LINK_DOWN;
143: link->engine = engine;
144: link->ev_ctx = ppp_engine_get_ev_ctx(engine);
145: link->mutex = ppp_engine_get_mutex(engine);
146: link->device = device;
147: link->conf = *conf;
148: link->log = log;
149: for (i = 0; i < 2; i++)
150: link->auth[i].link = link;
151:
152: /* Derive LCP configuration from link configuration and device info */
153: memset(&lcp_conf, 0, sizeof(lcp_conf));
154: lcp_conf.max_mru[PPP_SELF] = conf->max_self_mru;
155: lcp_conf.min_mru[PPP_PEER] = conf->min_peer_mru;
156: lcp_conf.accm = ppp_channel_is_async(device) ? 0x0a000000 : ~0;
157: if (ppp_channel_get_acfcomp(device)) {
158: lcp_conf.acfcomp[PPP_SELF] = 1;
159: lcp_conf.acfcomp[PPP_PEER] = 1;
160: }
161: if (ppp_channel_get_pfcomp(device)) {
162: lcp_conf.pfcomp[PPP_SELF] = 1;
163: lcp_conf.pfcomp[PPP_PEER] = 1;
164: }
165: for (i = 0; i < PPP_AUTH_MAX; i++) {
166: for (j = 0; j < 2; j++) {
167: if ((conf->auth.allow[j] & (1 << i)) != 0)
168: lcp_conf.auth[j][i] = 1;
169: }
170: }
171: lcp_conf.eid = conf->eid;
172: if (conf->multilink) {
173: lcp_conf.max_mrru[PPP_SELF] = conf->max_self_mrru;
174: lcp_conf.min_mrru[PPP_PEER] = conf->min_peer_mrru;
175: lcp_conf.multilink[PPP_SELF] = 1;
176: lcp_conf.multilink[PPP_PEER] = 1;
177: lcp_conf.shortseq[PPP_SELF] = 1;
178: lcp_conf.shortseq[PPP_PEER] = 1;
179: }
180:
181: /* Create ppp node object */
182: if (ppp_link_get_node(link) == -1)
183: goto fail;
184:
185: /* Create a new LCP FSM for this link */
186: if ((inst = ppp_lcp_create(&lcp_conf)) == NULL) {
187: LOG(LOG_ERR, "failed to create LCP: %m");
188: goto fail;
189: }
190: if ((link->lcp = ppp_fsm_create(link->ev_ctx,
191: link->mutex, inst, link->log)) == NULL) {
192: LOG(LOG_ERR, "failed to create LCP: %m");
193: goto fail;
194: }
195: inst = NULL;
196:
197: /* Listen for device events */
198: if (pevent_register(link->ev_ctx, &link->dev_event, PEVENT_RECURRING,
199: link->mutex, ppp_link_device_event, link, PEVENT_MESG_PORT,
200: ppp_channel_get_outport(link->device)) == -1) {
201: LOG(LOG_ERR, "%s: %m", "adding read event");
202: goto fail;
203: }
204:
205: /* Listen for LCP events */
206: if (pevent_register(link->ev_ctx, &link->lcp_event, PEVENT_RECURRING,
207: link->mutex, ppp_link_lcp_event, link, PEVENT_MESG_PORT,
208: ppp_fsm_get_outport(link->lcp)) == -1) {
209: LOG(LOG_ERR, "%s: %m", "adding read event");
210: goto fail;
211: }
212:
213: /* Notify engine of new link */
214: if (ppp_engine_add_link(engine, link) == -1) {
215: LOG(LOG_ERR, "failed to add link: %m");
216: goto fail;
217: }
218:
219: /* Start LCP negotiations (whenver link comes up) */
220: ppp_fsm_input(link->lcp, FSM_INPUT_OPEN);
221:
222: /* Done */
223: return (0);
224:
225: fail:
226: /* Clean up after failure */
227: esave = errno;
228: pevent_unregister(&link->dev_event);
229: pevent_unregister(&link->lcp_event);
230: ppp_node_destroy(&link->node);
231: ppp_node_destroy(&link->node);
232: ppp_fsm_destroy(&lcp);
233: if (inst != NULL)
234: (*inst->type->destroy)(inst);
235: FREE(LINK_MTYPE, link);
236: errno = esave;
237: return (-1);
238: }
239:
240: /*
241: * Destroy a link.
242: */
243: void
244: ppp_link_destroy(struct ppp_link **linkp)
245: {
246: struct ppp_link *const link = *linkp;
247: int r;
248:
249: /* Sanity check */
250: if (link == NULL)
251: return;
252: *linkp = NULL;
253:
254: /* Avoid recursion */
255: if (link->shutdown)
256: return;
257: link->shutdown = 1;
258:
259: /* Acquire lock */
260: r = pthread_mutex_lock(link->mutex);
261: assert(r == 0);
262:
263: /* Stop authentication (if any) */
264: ppp_link_auth_stop(link);
265:
266: /* Disconnect from bundle or engine */
267: ppp_bundle_unjoin(&link->bundle, link);
268: ppp_engine_del_link(link->engine, link);
269:
270: /* Destroy link */
271: r = pthread_mutex_unlock(link->mutex);
272: assert(r == 0);
273: ppp_fsm_destroy(&link->lcp);
274: pevent_unregister(&link->dev_event);
275: pevent_unregister(&link->lcp_event);
276: ppp_node_destroy(&link->node);
277: ppp_channel_destroy(&link->device);
278: ppp_log_close(&link->log);
279: FREE(LINK_MTYPE, link);
280: }
281:
282: /*
283: * Close a link.
284: */
285: void
286: ppp_link_close(struct ppp_link *link)
287: {
288: ppp_link_auth_stop(link);
289: ppp_fsm_input(link->lcp, FSM_INPUT_CLOSE);
290: }
291:
292: /*
293: * Get the device associated with a link.
294: */
295: struct ppp_channel *
296: ppp_link_get_device(struct ppp_link *link)
297: {
298: return (link->device);
299: }
300:
301: /*
302: * Get the link's origination (PPP_SELF or PPP_PEER) which
303: * is simply inherited from the underlying device.
304: */
305: int
306: ppp_link_get_origination(struct ppp_link *link)
307: {
308: return (ppp_channel_get_origination(link->device));
309: }
310:
311: /*
312: * Get link state.
313: */
314: enum ppp_link_state
315: ppp_link_get_state(struct ppp_link *link)
316: {
317: return (link->state);
318: }
319:
320: /*
321: * Get bundle associated with link, if any.
322: */
323: struct ppp_bundle *
324: ppp_link_get_bundle(struct ppp_link *link)
325: {
326: if (link->bundle == NULL)
327: errno = ENXIO;
328: return (link->bundle);
329: }
330:
331: /*
332: * Get LCP request state.
333: */
334: void
335: ppp_link_get_lcp_req(struct ppp_link *link, struct ppp_lcp_req *req)
336: {
337: ppp_lcp_get_req(link->lcp, req);
338: }
339:
340: /*
341: * Get link authorization name.
342: *
343: * Note: we reverse the sense of 'dir' because we want PPP_SELF to
344: * mean my authname to peer, which is the opposite of the way that
345: * authorization is negotiated, i.e., PPP_SELF is peer's auth to me.
346: */
347: const char *
348: ppp_link_get_authname(struct ppp_link *link, int dir)
349: {
350: struct ppp_link_auth *const auth = &link->auth[!dir];
351:
352: if (auth->type == NULL)
353: return ("");
354: switch (auth->type->index) {
355: case PPP_AUTH_PAP:
356: return (auth->cred.u.pap.name);
357: case PPP_AUTH_CHAP_MSV1:
358: case PPP_AUTH_CHAP_MSV2:
359: case PPP_AUTH_CHAP_MD5:
360: return (auth->cred.u.chap.name);
361: default:
362: return ("");
363: }
364: }
365:
366: /*
367: * Get endpoint ID.
368: */
369: void
370: ppp_link_get_eid(struct ppp_link *link, int dir, struct ppp_eid *eid)
371: {
372: struct ppp_lcp_req req;
373:
374: dir &= 1;
375: ppp_lcp_get_req(link->lcp, &req);
376: *eid = req.eid[dir];
377: }
378:
379: void
380: ppp_link_get_mppe(struct ppp_link *link, int dir, union ppp_auth_mppe *mppe)
381: {
382: struct ppp_link_auth *const auth = &link->auth[dir & 1];
383:
384: memcpy(mppe, &auth->mppe, sizeof(*mppe));
385: }
386:
387: /*
388: * Ouput a packet on the link.
389: */
390: void
391: ppp_link_write(struct ppp_link *link,
392: u_int16_t proto, const void *data, size_t len)
393: {
394: int rtn;
395:
396: /* Drop packet if channel is down */
397: if (!link->device_up)
398: return;
399:
400: /* Write packet */
401: if (link->bundle != NULL) {
402: rtn = ppp_bundle_write(link->bundle,
403: link->link_num, proto, data, len);
404: } else {
405: rtn = ppp_node_write(link->node,
406: link->link_num, proto, data, len);
407: }
408:
409: if (rtn == -1) {
410: LOG(LOG_ERR, "%s: %m", "error writing to bypass");
411: ppp_link_close(link);
412: }
413: }
414:
415: /***********************************************************************
416: LCP EVENT HANDLER
417: ***********************************************************************/
418:
419: static void
420: ppp_link_lcp_event(void *arg)
421: {
422: struct ppp_link *link = arg;
423: struct mesg_port *const outport = ppp_fsm_get_outport(link->lcp);
424: struct ppp_fsm_output *output;
425:
426: /* Read and handle all FSM events */
427: while ((output = mesg_port_get(outport, 0)) != NULL) {
428:
429: /* Check it out */
430: switch (output->type) {
431: case FSM_OUTPUT_OPEN:
432: ppp_channel_open(link->device);
433: break;
434: case FSM_OUTPUT_CLOSE:
435: ppp_channel_close(link->device);
436: break;
437: case FSM_OUTPUT_UP:
438: {
439: struct ng_ppp_node_conf conf;
440: struct ng_ppp_link_conf *const lconf = &conf.links[0];
441:
442: /* Get ng_ppp(4) node configuration */
443: if (ppp_node_get_config(link->node, &conf) == -1) {
444: LOG(LOG_ERR, "can't configure node: %m");
445: ppp_link_close(link);
446: break;
447: }
448:
449: /* Update with negotiated LCP parameters */
450: ppp_lcp_get_req(link->lcp, &link->lcp_req);
451: lconf->enableProtoComp = link->lcp_req.pfcomp[PPP_PEER];
452: lconf->enableACFComp = link->lcp_req.acfcomp[PPP_PEER];
453: lconf->mru = MIN(
454: WINXP_PPTP_HACK(link->lcp_req.mru[PPP_PEER]),
455: ppp_channel_get_mtu(link->device));
456: lconf->latency = LINK_LATENCY;
457: lconf->bandwidth = LINK_BANDWIDTH;
458: if (ppp_node_set_config(link->node, &conf) == -1) {
459: LOG(LOG_ERR, "can't configure node: %m");
460: ppp_link_close(link);
461: break;
462: }
463:
464: /* Begin authentication phase */
465: link->state = PPP_LINK_AUTH;
466: ppp_link_auth_start(link);
467: break;
468: }
469: case FSM_OUTPUT_DOWN:
470: link->state = PPP_LINK_DOWN;
471: ppp_link_auth_stop(link);
472: if (link->bundle != NULL) {
473:
474: /* Leave our bundle */
475: assert(link->node == NULL);
476: ppp_bundle_unjoin(&link->bundle, link);
477:
478: /* Create a new node for this link */
479: if (ppp_link_get_node(link) == -1) {
480: ppp_link_close(link);
481: break;
482: }
483: }
484: break;
485: case FSM_OUTPUT_DATA:
486: ppp_link_write(link, PPP_PROTO_LCP,
487: output->u.data.data, output->u.data.length);
488: break;
489: case FSM_OUTPUT_PROTOREJ:
490: {
491: /* Log it */
492: LOG(LOG_NOTICE,
493: "peer rejected protocol 0x%04x", output->u.proto);
494:
495: /* If fatal, shut down, else report to bundle */
496: switch (output->u.proto) {
497: case PPP_PROTO_LCP:
498: case PPP_PROTO_CHAP:
499: case PPP_PROTO_PAP:
500: case PPP_PROTO_MP:
501: ppp_fsm_input(link->lcp,
502: FSM_INPUT_RECD_PROTOREJ, output->u.proto);
503: break;
504: default:
505: if (link->bundle != NULL) {
506: ppp_bundle_protorej(link->bundle,
507: output->u.proto);
508: }
509: break;
510: }
511: break;
512: }
513: case FSM_OUTPUT_DEAD:
514: LOG(LOG_INFO, "LCP is dead: %s",
515: ppp_fsm_reason_str(output));
516: if (link->bundle != NULL)
517: ppp_link_unjoin(link);
518: ppp_fsm_free_output(output);
519: ppp_link_destroy(&link);
520: return;
521: }
522:
523: /* Free output */
524: ppp_fsm_free_output(output);
525: }
526: }
527:
528: /***********************************************************************
529: DEVICE EVENT HANDLER
530: ***********************************************************************/
531:
532: static void
533: ppp_link_device_event(void *arg)
534: {
535: struct ppp_link *const link = arg;
536: struct mesg_port *const outport = ppp_channel_get_outport(link->device);
537: struct ppp_channel_output *output;
538:
539: /* Handle channel events */
540: while ((output = mesg_port_get(outport, 0)) != NULL) {
541:
542: /* Check event */
543: switch (output->type) {
544: case PPP_CHANNEL_OUTPUT_UP:
545: LOG(LOG_INFO, "device layer is up");
546: ppp_fsm_input(link->lcp, FSM_INPUT_UP);
547: link->device_up = 1;
548: break;
549: case PPP_CHANNEL_OUTPUT_DOWN_FATAL:
550: case PPP_CHANNEL_OUTPUT_DOWN_NONFATAL:
551: LOG(LOG_INFO, "device layer is down: %s", output->info);
552: ppp_fsm_input(link->lcp,
553: output->type == PPP_CHANNEL_OUTPUT_DOWN_FATAL ?
554: FSM_INPUT_DOWN_FATAL : FSM_INPUT_DOWN_NONFATAL);
555: link->device_up = 0;
556: break;
557: }
558:
559: /* Free channel output */
560: ppp_channel_free_output(link->device, output);
561: }
562: }
563:
564: /***********************************************************************
565: PPP NODE OUTPUT HANDLER
566: ***********************************************************************/
567:
568: /*
569: * Handle data received from the node's bypass hook.
570: */
571: void
572: ppp_link_recv_bypass(struct ppp_link *link,
573: u_int16_t proto, u_char *data, size_t len)
574: {
575: LOG(LOG_DEBUG + 1, "rec'd proto 0x%04x %u bytes", proto, len);
576: switch (proto) {
577: case PPP_PROTO_LCP:
578: ppp_fsm_input(link->lcp, FSM_INPUT_DATA, data, len);
579: break;
580: case PPP_PROTO_PAP:
581: case PPP_PROTO_CHAP:
582: {
583: int i;
584:
585: for (i = 0; i < 2; i++) {
586: struct ppp_link_auth *const auth = &link->auth[i];
587:
588: if (auth->type == NULL
589: || auth->arg == NULL
590: || auth->proto != proto)
591: continue;
592: (*auth->type->input)(auth->arg, i, data, len);
593: }
594: break;
595: }
596: case PPP_PROTO_MP:
597: case PPP_PROTO_IPCP:
598: case PPP_PROTO_IP:
599: case PPP_PROTO_VJCOMP:
600: case PPP_PROTO_VJUNCOMP:
601: case PPP_PROTO_CCP:
602: case PPP_PROTO_COMPD:
603: break;
604: default: /* send a protocol-reject */
605: ppp_fsm_input(link->lcp,
606: FSM_INPUT_XMIT_PROTOREJ, proto, data, len);
607: break;
608: }
609: }
610:
611: static void
612: ppp_link_node_recv(void *arg, u_int link_num,
613: u_int16_t proto, u_char *data, size_t len)
614: {
615: struct ppp_link *const link = arg;
616:
617: assert(link_num == 0);
618: ppp_link_recv_bypass(link, proto, data, len);
619: }
620:
621: /***********************************************************************
622: AUTHORIZATION PHASE
623: ***********************************************************************/
624:
625: /*
626: * Begin link authorization.
627: */
628: static void
629: ppp_link_auth_start(struct ppp_link *link)
630: {
631: int i;
632:
633: /* Get auth types negotiated by LCP */
634: for (i = 0; i < 2; i++) {
635: link->auth[i].type = (link->lcp_req.auth[i] != PPP_AUTH_NONE) ?
636: ppp_auth_by_index(link->lcp_req.auth[i]) : NULL;
637: }
638: LOG(LOG_DEBUG, "auth required: self=%s peer=%s",
639: link->auth[PPP_PEER].type != NULL ?
640: link->auth[PPP_PEER].type->name : "None",
641: link->auth[PPP_SELF].type != NULL ?
642: link->auth[PPP_SELF].type->name : "None");
643:
644: /* If no auth required, skip it */
645: if (link->auth[PPP_SELF].type == NULL
646: && link->auth[PPP_PEER].type == NULL) {
647: ppp_link_join(link);
648: return;
649: }
650:
651: /* Start auth timer */
652: pevent_unregister(&link->auth_timer);
653: if (pevent_register(link->ev_ctx, &link->auth_timer, 0,
654: link->mutex, ppp_link_auth_timeout, link, PEVENT_TIME,
655: AUTH_TIMEOUT * 1000) == -1) {
656: LOG(LOG_ERR, "%s: %m", "pevent_register");
657: ppp_link_close(link);
658: return;
659: }
660:
661: /* Start authorization in each direction */
662: for (i = 0; i < 2; i++) {
663: struct ppp_link_auth *const auth = &link->auth[i];
664:
665: if (auth->type == NULL)
666: continue;
667: if ((auth->arg = (*auth->type->start)(link->ev_ctx, link,
668: link->mutex, i, &auth->proto, ppp_log_dup(link->log)))
669: == NULL) {
670: LOG(LOG_ERR, "failed to initialize authorization");
671: ppp_link_close(link);
672: return;
673: }
674: }
675: }
676:
677: /*
678: * Stop link authorization.
679: */
680: static void
681: ppp_link_auth_stop(struct ppp_link *link)
682: {
683: int i;
684:
685: /* Stop auth timer */
686: pevent_unregister(&link->auth_timer);
687:
688: /* Stop auth in both directions */
689: for (i = 0; i < 2; i++) {
690: struct ppp_link_auth *const auth = &link->auth[i];
691:
692: /* Kill any threads */
693: paction_cancel(&auth->action);
694:
695: /* Clean up authorization code */
696: if (auth->arg != NULL) {
697: (*auth->type->cancel)(auth->arg);
698: auth->arg = NULL;
699: }
700: }
701: }
702:
703: /*
704: * Authorization failed to happen within the alloted time.
705: */
706: static void
707: ppp_link_auth_timeout(void *arg)
708: {
709: struct ppp_link *const link = arg;
710:
711: pevent_unregister(&link->auth_timer);
712: LOG(LOG_ERR, "authorization timed out");
713: ppp_link_close(link);
714: }
715:
716: /***********************************************************************
717: AUTHORIZATION CALLBACKS
718: ***********************************************************************/
719:
720: #define AUTHINFO_MTYPE "ppp_link.authinfo"
721:
722: /* Authorization acquire/check state */
723: struct ppp_link_auth_info {
724: struct ppp_link *link; /* link being authorized */
725: struct ppp_auth_cred cred; /* auth credentials */
726: struct ppp_auth_resp resp; /* auth response */
727: ppp_link_auth_finish_t *finish;/* auth finish routine */
728: int rtn; /* return value from user */
729: int error; /* saved value of 'errno' */
730: };
731:
732: static paction_handler_t ppp_link_auth_acquire_main;
733: static paction_finish_t ppp_link_auth_acquire_finish;
734:
735: static paction_handler_t ppp_link_auth_check_main;
736: static paction_finish_t ppp_link_auth_check_finish;
737:
738: /*
739: * Acquire or check authorization credentials.
740: *
741: * This action is done in a separate thread.
742: */
743: int
744: ppp_link_authorize(struct ppp_link *link, int dir,
745: const struct ppp_auth_cred *cred, ppp_link_auth_finish_t *authfinish)
746: {
747: struct ppp_link_auth *const auth = &link->auth[dir];
748: struct ppp_link_auth_info *authinfo;
749: paction_handler_t *handler;
750: paction_finish_t *finish;
751:
752: /* Sanity check */
753: assert(auth->action == NULL);
754:
755: /* Set up for 'acquire' or 'check' */
756: if (dir == PPP_PEER) {
757: if (link->conf.auth.meth->acquire == NULL) {
758: LOG(LOG_ERR, "no method provided for %s credentials",
759: "acquiring");
760: return (-1);
761: }
762: handler = ppp_link_auth_acquire_main;
763: finish = ppp_link_auth_acquire_finish;
764: } else {
765: if (link->conf.auth.meth->check == NULL) {
766: LOG(LOG_ERR, "no method provided for %s credentials",
767: "checking");
768: return (-1);
769: }
770: handler = ppp_link_auth_check_main;
771: finish = ppp_link_auth_check_finish;
772: }
773:
774: /* Create auth info */
775: if ((authinfo = MALLOC(AUTHINFO_MTYPE, sizeof(*authinfo))) == NULL) {
776: LOG(LOG_ERR, "%s: %m", "malloc");
777: return (-1);
778: }
779: memset(authinfo, 0, sizeof(*authinfo));
780: authinfo->link = link;
781: authinfo->cred = *cred;
782: authinfo->finish = authfinish;
783:
784: /* Initiate authorization action */
785: if (paction_start(&auth->action, link->mutex,
786: handler, finish, authinfo) == -1) {
787: LOG(LOG_ERR, "%s: %m", "paction_start");
788: FREE(AUTHINFO_MTYPE, authinfo);
789: return (-1);
790: }
791:
792: /* Done */
793: return (0);
794: }
795:
796: /*
797: * Acquire authorization credentials.
798: *
799: * The mutex is NOT locked when this is called.
800: */
801: static void
802: ppp_link_auth_acquire_main(void *arg)
803: {
804: struct ppp_link_auth_info *const authinfo = arg;
805: struct ppp_link *const link = authinfo->link;
806:
807: /* Acquire credentials */
808: authinfo->rtn = (*link->conf.auth.meth->acquire)(link,
809: &authinfo->cred, &authinfo->resp);
810: authinfo->error = errno;
811: }
812:
813: /*
814: * Finish acquiring authorization credentials.
815: *
816: * The mutex is locked when this is called unless 'canceled' is true.
817: */
818: static void
819: ppp_link_auth_acquire_finish(void *arg, int canceled)
820: {
821: struct ppp_link_auth_info *const authinfo = arg;
822: struct ppp_link *const link = authinfo->link;
823: struct ppp_link_auth *const auth = &link->auth[PPP_PEER];
824:
825: /* If canceled, just clean up */
826: if (canceled)
827: goto done;
828:
829: /* If acquiring credentials failed, bail out here */
830: if (authinfo->rtn != 0) {
831: if (*authinfo->resp.errmsg == '\0') {
832: strlcpy(authinfo->resp.errmsg,
833: strerror(authinfo->error),
834: sizeof(authinfo->resp.errmsg));
835: }
836: LOG(LOG_WARNING, "failed to acquire credentials: %s",
837: auth->resp.errmsg);
838: ppp_link_auth_complete(link, PPP_PEER, NULL, NULL);
839: return;
840: }
841:
842: /* Save a copy of credentials */
843: auth->cred = authinfo->cred;
844: auth->resp = authinfo->resp;
845:
846: /* Report credentials back to authorization code */
847: (*authinfo->finish)(auth->arg, &authinfo->cred, &authinfo->resp);
848:
849: done:
850: /* Free authinfo */
851: FREE(AUTHINFO_MTYPE, authinfo);
852: }
853:
854: /*
855: * Check authorization credentials.
856: *
857: * The mutex is NOT locked when this is called.
858: */
859: static void
860: ppp_link_auth_check_main(void *arg)
861: {
862: struct ppp_link_auth_info *const authinfo = arg;
863: struct ppp_link *const link = authinfo->link;
864:
865: /* Check credentials */
866: authinfo->rtn = (*link->conf.auth.meth->check)(link,
867: &authinfo->cred, &authinfo->resp);
868: authinfo->error = errno;
869: }
870:
871: /*
872: * Finish checking authorization credentials.
873: *
874: * The mutex is locked when this is called.
875: */
876: static void
877: ppp_link_auth_check_finish(void *arg, int canceled)
878: {
879: struct ppp_link_auth_info *const authinfo = arg;
880: struct ppp_link *const link = authinfo->link;
881: struct ppp_link_auth *const auth = &link->auth[PPP_SELF];
882:
883: /* If canceled, just clean up */
884: if (canceled)
885: goto done;
886:
887: /* Save a copy of credentials */
888: auth->cred = authinfo->cred;
889: auth->resp = authinfo->resp;
890:
891: /* Fill in error message to indicate invalid credentials */
892: if (authinfo->rtn != 0) {
893: if (*authinfo->resp.errmsg == '\0') {
894: strlcpy(authinfo->resp.errmsg,
895: strerror(authinfo->error),
896: sizeof(authinfo->resp.errmsg));
897: }
898: }
899:
900: /* Report result back to authorization code */
901: (*authinfo->finish)(auth->arg, &authinfo->cred, &authinfo->resp);
902:
903: done:
904: /* Free authinfo */
905: FREE(AUTHINFO_MTYPE, authinfo);
906: }
907:
908: /*
909: * Determine if an authorization action is already in progress.
910: */
911: int
912: ppp_link_auth_in_progress(struct ppp_link *link, int dir)
913: {
914: struct ppp_link_auth *const auth = &link->auth[dir];
915:
916: return (auth->action != NULL);
917: }
918:
919: /*
920: * Finish link authorization (in one direction).
921: *
922: * A NULL 'cred' indicates failure.
923: */
924: void
925: ppp_link_auth_complete(struct ppp_link *link, int dir,
926: const struct ppp_auth_cred *cred, const union ppp_auth_mppe *mppe)
927: {
928: struct ppp_link_auth *const auth = &link->auth[dir];
929:
930: /* Sanity check */
931: assert(auth->arg != NULL);
932:
933: /* If auth failed, close link */
934: if (cred == NULL) {
935: LOG(LOG_NOTICE, "authorization %s peer failed",
936: dir == PPP_SELF ? "from" : "to");
937: ppp_link_close(link);
938: return;
939: }
940:
941: /* Save credentials and MPPE info */
942: auth->cred = *cred;
943: if (mppe != NULL)
944: auth->mppe = *mppe;
945:
946: /* Destroy auth object for this direction */
947: (*auth->type->cancel)(auth->arg);
948: auth->arg = NULL;
949:
950: /* If other direction still active, let it finish */
951: if (link->auth[!dir].arg != NULL)
952: return;
953:
954: /* Move to the 'UP' state */
955: ppp_link_auth_stop(link);
956: ppp_link_join(link);
957: }
958:
959: /*
960: * Get this link's authorization configuration.
961: */
962: const struct ppp_auth_config *
963: ppp_link_auth_get_config(struct ppp_link *link)
964: {
965: return (&link->conf.auth);
966: }
967:
968: /*
969: * Get this link's authorization type in one direction.
970: */
971: const struct ppp_auth_type *
972: ppp_link_get_auth(struct ppp_link *link, int dir)
973: {
974: dir &= 1;
975: return (link->auth[dir].type);
976: }
977:
978: /*
979: * Get this link's log
980: */
981: struct ppp_log *
982: ppp_link_get_log(struct ppp_link *link)
983: {
984: return (link->log);
985: }
986:
987: /***********************************************************************
988: BUNDLE OPERATIONS
989: ***********************************************************************/
990:
991: /*
992: * The link FSM has reached the OPENED state and authentication
993: * was successful, so join a bundle.
994: */
995: static void
996: ppp_link_join(struct ppp_link *link)
997: {
998: assert(link->bundle == NULL);
999: if ((link->bundle = ppp_engine_join(link->engine,
1000: link, &link->node, &link->link_num)) == NULL) {
1001: ppp_link_close(link);
1002: return;
1003: }
1004: link->state = PPP_LINK_UP;
1005: }
1006:
1007: /*
1008: * Link has left the OPENED state, so leave bundle (if any).
1009: */
1010: static void
1011: ppp_link_unjoin(struct ppp_link *link)
1012: {
1013: ppp_bundle_unjoin(&link->bundle, link); /* ok if bundle null */
1014: }
1015:
1016: /***********************************************************************
1017: INTERNAL FUNCTIONS
1018: ***********************************************************************/
1019:
1020: /*
1021: * Acquire an ng_ppp(4) node for this link to use.
1022: */
1023: static int
1024: ppp_link_get_node(struct ppp_link *link)
1025: {
1026: const char *node;
1027: const char *hook;
1028:
1029: /* Sanity check */
1030: if (link->node != NULL)
1031: return (0);
1032:
1033: /* Get new node */
1034: if ((link->node = ppp_node_create(link->ev_ctx,
1035: link->mutex, ppp_log_dup(link->log))) == NULL) {
1036: LOG(LOG_ERR, "%s: %m", "creating ppp node");
1037: return (-1);
1038: }
1039:
1040: /* Connect device to node */
1041: if ((node = ppp_channel_get_node(link->device)) == NULL
1042: || (hook = ppp_channel_get_hook(link->device)) == NULL) {
1043: LOG(LOG_ERR, "channel is not a device");
1044: ppp_node_destroy(&link->node);
1045: return (-1);
1046: }
1047: if (ppp_node_connect(link->node, 0, node, hook) == -1) {
1048: LOG(LOG_ERR, "%s: %m", "connecting device to node");
1049: ppp_node_destroy(&link->node);
1050: return (-1);
1051: }
1052:
1053: /* Receive all node bypass packets */
1054: ppp_node_set_recv(link->node, ppp_link_node_recv, link);
1055:
1056: /* Done */
1057: return (0);
1058: }
1059:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>