xref: /netbsd-src/external/bsd/ppp/dist/pppd/upap.c (revision a24efa7dea9f1f56c3bdb15a927d3516792ace1c)
1 /*	$NetBSD: upap.c,v 1.4 2014/10/25 21:11:37 christos Exp $	*/
2 
3 /*
4  * upap.c - User/Password Authentication Protocol.
5  *
6  * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. The name "Carnegie Mellon University" must not be used to
21  *    endorse or promote products derived from this software without
22  *    prior written permission. For permission or any legal
23  *    details, please contact
24  *      Office of Technology Transfer
25  *      Carnegie Mellon University
26  *      5000 Forbes Avenue
27  *      Pittsburgh, PA  15213-3890
28  *      (412) 268-4387, fax: (412) 268-7395
29  *      tech-transfer@andrew.cmu.edu
30  *
31  * 4. Redistributions of any form whatsoever must retain the following
32  *    acknowledgment:
33  *    "This product includes software developed by Computing Services
34  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
35  *
36  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
37  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
38  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
39  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
40  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
41  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
42  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
43  */
44 
45 #include <sys/cdefs.h>
46 #if 0
47 #define RCSID	"Id: upap.c,v 1.30 2005/07/13 10:41:58 paulus Exp "
48 static const char rcsid[] = RCSID;
49 #else
50 __RCSID("$NetBSD: upap.c,v 1.4 2014/10/25 21:11:37 christos Exp $");
51 #endif
52 
53 /*
54  * TODO:
55  */
56 
57 #include <stdio.h>
58 #include <string.h>
59 
60 #include "pppd.h"
61 #include "upap.h"
62 
63 
64 static bool hide_password = 1;
65 
66 /*
67  * Command-line options.
68  */
69 static option_t pap_option_list[] = {
70     { "hide-password", o_bool, &hide_password,
71       "Don't output passwords to log", OPT_PRIO | 1 },
72     { "show-password", o_bool, &hide_password,
73       "Show password string in debug log messages", OPT_PRIOSUB | 0 },
74 
75     { "pap-restart", o_int, &upap[0].us_timeouttime,
76       "Set retransmit timeout for PAP", OPT_PRIO },
77     { "pap-max-authreq", o_int, &upap[0].us_maxtransmits,
78       "Set max number of transmissions for auth-reqs", OPT_PRIO },
79     { "pap-timeout", o_int, &upap[0].us_reqtimeout,
80       "Set time limit for peer PAP authentication", OPT_PRIO },
81 
82     { NULL }
83 };
84 
85 /*
86  * Protocol entry points.
87  */
88 static void upap_init __P((int));
89 static void upap_lowerup __P((int));
90 static void upap_lowerdown __P((int));
91 static void upap_input __P((int, u_char *, int));
92 static void upap_protrej __P((int));
93 static int  upap_printpkt __P((u_char *, int,
94 			       void (*) __P((void *, char *, ...)), void *));
95 
96 struct protent pap_protent = {
97     PPP_PAP,
98     upap_init,
99     upap_input,
100     upap_protrej,
101     upap_lowerup,
102     upap_lowerdown,
103     NULL,
104     NULL,
105     upap_printpkt,
106     NULL,
107     1,
108     "PAP",
109     NULL,
110     pap_option_list,
111     NULL,
112     NULL,
113     NULL
114 };
115 
116 upap_state upap[NUM_PPP];		/* UPAP state; one for each unit */
117 
118 static void upap_timeout __P((void *));
119 static void upap_reqtimeout __P((void *));
120 static void upap_rauthreq __P((upap_state *, u_char *, int, int));
121 static void upap_rauthack __P((upap_state *, u_char *, int, int));
122 static void upap_rauthnak __P((upap_state *, u_char *, int, int));
123 static void upap_sauthreq __P((upap_state *));
124 static void upap_sresp __P((upap_state *, int, int, char *, int));
125 
126 
127 /*
128  * upap_init - Initialize a UPAP unit.
129  */
130 static void
131 upap_init(unit)
132     int unit;
133 {
134     upap_state *u = &upap[unit];
135 
136     u->us_unit = unit;
137     u->us_user = NULL;
138     u->us_userlen = 0;
139     u->us_passwd = NULL;
140     u->us_passwdlen = 0;
141     u->us_clientstate = UPAPCS_INITIAL;
142     u->us_serverstate = UPAPSS_INITIAL;
143     u->us_id = 0;
144     u->us_timeouttime = UPAP_DEFTIMEOUT;
145     u->us_maxtransmits = 10;
146     u->us_reqtimeout = UPAP_DEFREQTIME;
147 }
148 
149 
150 /*
151  * upap_authwithpeer - Authenticate us with our peer (start client).
152  *
153  * Set new state and send authenticate's.
154  */
155 void
156 upap_authwithpeer(unit, user, password)
157     int unit;
158     char *user, *password;
159 {
160     upap_state *u = &upap[unit];
161 
162     /* Save the username and password we're given */
163     u->us_user = user;
164     u->us_userlen = strlen(user);
165     u->us_passwd = password;
166     u->us_passwdlen = strlen(password);
167     u->us_transmits = 0;
168 
169     /* Lower layer up yet? */
170     if (u->us_clientstate == UPAPCS_INITIAL ||
171 	u->us_clientstate == UPAPCS_PENDING) {
172 	u->us_clientstate = UPAPCS_PENDING;
173 	return;
174     }
175 
176     upap_sauthreq(u);			/* Start protocol */
177 }
178 
179 
180 /*
181  * upap_authpeer - Authenticate our peer (start server).
182  *
183  * Set new state.
184  */
185 void
186 upap_authpeer(unit)
187     int unit;
188 {
189     upap_state *u = &upap[unit];
190 
191     /* Lower layer up yet? */
192     if (u->us_serverstate == UPAPSS_INITIAL ||
193 	u->us_serverstate == UPAPSS_PENDING) {
194 	u->us_serverstate = UPAPSS_PENDING;
195 	return;
196     }
197 
198     u->us_serverstate = UPAPSS_LISTEN;
199     if (u->us_reqtimeout > 0)
200 	TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
201 }
202 
203 
204 /*
205  * upap_timeout - Retransmission timer for sending auth-reqs expired.
206  */
207 static void
208 upap_timeout(arg)
209     void *arg;
210 {
211     upap_state *u = (upap_state *) arg;
212 
213     if (u->us_clientstate != UPAPCS_AUTHREQ)
214 	return;
215 
216     if (u->us_transmits >= u->us_maxtransmits) {
217 	/* give up in disgust */
218 	error("No response to PAP authenticate-requests");
219 	u->us_clientstate = UPAPCS_BADAUTH;
220 	auth_withpeer_fail(u->us_unit, PPP_PAP);
221 	return;
222     }
223 
224     upap_sauthreq(u);		/* Send Authenticate-Request */
225 }
226 
227 
228 /*
229  * upap_reqtimeout - Give up waiting for the peer to send an auth-req.
230  */
231 static void
232 upap_reqtimeout(arg)
233     void *arg;
234 {
235     upap_state *u = (upap_state *) arg;
236 
237     if (u->us_serverstate != UPAPSS_LISTEN)
238 	return;			/* huh?? */
239 
240     auth_peer_fail(u->us_unit, PPP_PAP);
241     u->us_serverstate = UPAPSS_BADAUTH;
242 }
243 
244 
245 /*
246  * upap_lowerup - The lower layer is up.
247  *
248  * Start authenticating if pending.
249  */
250 static void
251 upap_lowerup(unit)
252     int unit;
253 {
254     upap_state *u = &upap[unit];
255 
256     if (u->us_clientstate == UPAPCS_INITIAL)
257 	u->us_clientstate = UPAPCS_CLOSED;
258     else if (u->us_clientstate == UPAPCS_PENDING) {
259 	upap_sauthreq(u);	/* send an auth-request */
260     }
261 
262     if (u->us_serverstate == UPAPSS_INITIAL)
263 	u->us_serverstate = UPAPSS_CLOSED;
264     else if (u->us_serverstate == UPAPSS_PENDING) {
265 	u->us_serverstate = UPAPSS_LISTEN;
266 	if (u->us_reqtimeout > 0)
267 	    TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
268     }
269 }
270 
271 
272 /*
273  * upap_lowerdown - The lower layer is down.
274  *
275  * Cancel all timeouts.
276  */
277 static void
278 upap_lowerdown(unit)
279     int unit;
280 {
281     upap_state *u = &upap[unit];
282 
283     if (u->us_clientstate == UPAPCS_AUTHREQ)	/* Timeout pending? */
284 	UNTIMEOUT(upap_timeout, u);		/* Cancel timeout */
285     if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0)
286 	UNTIMEOUT(upap_reqtimeout, u);
287 
288     u->us_clientstate = UPAPCS_INITIAL;
289     u->us_serverstate = UPAPSS_INITIAL;
290 }
291 
292 
293 /*
294  * upap_protrej - Peer doesn't speak this protocol.
295  *
296  * This shouldn't happen.  In any case, pretend lower layer went down.
297  */
298 static void
299 upap_protrej(unit)
300     int unit;
301 {
302     upap_state *u = &upap[unit];
303 
304     if (u->us_clientstate == UPAPCS_AUTHREQ) {
305 	error("PAP authentication failed due to protocol-reject");
306 	auth_withpeer_fail(unit, PPP_PAP);
307     }
308     if (u->us_serverstate == UPAPSS_LISTEN) {
309 	error("PAP authentication of peer failed (protocol-reject)");
310 	auth_peer_fail(unit, PPP_PAP);
311     }
312     upap_lowerdown(unit);
313 }
314 
315 
316 /*
317  * upap_input - Input UPAP packet.
318  */
319 static void
320 upap_input(unit, inpacket, l)
321     int unit;
322     u_char *inpacket;
323     int l;
324 {
325     upap_state *u = &upap[unit];
326     u_char *inp;
327     u_char code, id;
328     int len;
329 
330     /*
331      * Parse header (code, id and length).
332      * If packet too short, drop it.
333      */
334     inp = inpacket;
335     if (l < UPAP_HEADERLEN) {
336 	UPAPDEBUG(("pap_input: rcvd short header."));
337 	return;
338     }
339     GETCHAR(code, inp);
340     GETCHAR(id, inp);
341     GETSHORT(len, inp);
342     if (len < UPAP_HEADERLEN) {
343 	UPAPDEBUG(("pap_input: rcvd illegal length."));
344 	return;
345     }
346     if (len > l) {
347 	UPAPDEBUG(("pap_input: rcvd short packet."));
348 	return;
349     }
350     len -= UPAP_HEADERLEN;
351 
352     /*
353      * Action depends on code.
354      */
355     switch (code) {
356     case UPAP_AUTHREQ:
357 	upap_rauthreq(u, inp, id, len);
358 	break;
359 
360     case UPAP_AUTHACK:
361 	upap_rauthack(u, inp, id, len);
362 	break;
363 
364     case UPAP_AUTHNAK:
365 	upap_rauthnak(u, inp, id, len);
366 	break;
367 
368     default:				/* XXX Need code reject */
369 	break;
370     }
371 }
372 
373 
374 /*
375  * upap_rauth - Receive Authenticate.
376  */
377 static void
378 upap_rauthreq(u, inp, id, len)
379     upap_state *u;
380     u_char *inp;
381     int id;
382     int len;
383 {
384     u_char ruserlen, rpasswdlen;
385     char *ruser, *rpasswd;
386     char rhostname[256];
387     int retcode;
388     char *msg;
389     int msglen;
390 
391     if (u->us_serverstate < UPAPSS_LISTEN)
392 	return;
393 
394     /*
395      * If we receive a duplicate authenticate-request, we are
396      * supposed to return the same status as for the first request.
397      */
398     if (u->us_serverstate == UPAPSS_OPEN) {
399 	upap_sresp(u, UPAP_AUTHACK, id, "", 0);	/* return auth-ack */
400 	return;
401     }
402     if (u->us_serverstate == UPAPSS_BADAUTH) {
403 	upap_sresp(u, UPAP_AUTHNAK, id, "", 0);	/* return auth-nak */
404 	return;
405     }
406 
407     /*
408      * Parse user/passwd.
409      */
410     if (len < 1) {
411 	UPAPDEBUG(("pap_rauth: rcvd short packet."));
412 	return;
413     }
414     GETCHAR(ruserlen, inp);
415     len -= sizeof (u_char) + ruserlen + sizeof (u_char);
416     if (len < 0) {
417 	UPAPDEBUG(("pap_rauth: rcvd short packet."));
418 	return;
419     }
420     ruser = (char *) inp;
421     INCPTR(ruserlen, inp);
422     GETCHAR(rpasswdlen, inp);
423     if (len < rpasswdlen) {
424 	UPAPDEBUG(("pap_rauth: rcvd short packet."));
425 	return;
426     }
427     rpasswd = (char *) inp;
428 
429     /*
430      * Check the username and password given.
431      */
432     retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
433 			   rpasswdlen, &msg);
434     BZERO(rpasswd, rpasswdlen);
435 
436     /*
437      * Check remote number authorization.  A plugin may have filled in
438      * the remote number or added an allowed number, and rather than
439      * return an authenticate failure, is leaving it for us to verify.
440      */
441     if (retcode == UPAP_AUTHACK) {
442 	if (!auth_number()) {
443 	    /* We do not want to leak info about the pap result. */
444 	    retcode = UPAP_AUTHNAK; /* XXX exit value will be "wrong" */
445 	    warn("calling number %q is not authorized", remote_number);
446 	}
447     }
448 
449     msglen = strlen(msg);
450     if (msglen > 255)
451 	msglen = 255;
452     upap_sresp(u, retcode, id, msg, msglen);
453 
454     /* Null terminate and clean remote name. */
455     slprintf(rhostname, sizeof(rhostname), "%.*v", ruserlen, ruser);
456 
457     if (retcode == UPAP_AUTHACK) {
458 	u->us_serverstate = UPAPSS_OPEN;
459 	notice("PAP peer authentication succeeded for %q", rhostname);
460 	auth_peer_success(u->us_unit, PPP_PAP, 0, ruser, ruserlen);
461     } else {
462 	u->us_serverstate = UPAPSS_BADAUTH;
463 	warn("PAP peer authentication failed for %q", rhostname);
464 	auth_peer_fail(u->us_unit, PPP_PAP);
465     }
466 
467     if (u->us_reqtimeout > 0)
468 	UNTIMEOUT(upap_reqtimeout, u);
469 }
470 
471 
472 /*
473  * upap_rauthack - Receive Authenticate-Ack.
474  */
475 static void
476 upap_rauthack(u, inp, id, len)
477     upap_state *u;
478     u_char *inp;
479     int id;
480     int len;
481 {
482     u_char msglen;
483     char *msg;
484 
485     if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
486 	return;
487 
488     /*
489      * Parse message.
490      */
491     if (len < 1) {
492 	UPAPDEBUG(("pap_rauthack: ignoring missing msg-length."));
493     } else {
494 	GETCHAR(msglen, inp);
495 	if (msglen > 0) {
496 	    len -= sizeof (u_char);
497 	    if (len < msglen) {
498 		UPAPDEBUG(("pap_rauthack: rcvd short packet."));
499 		return;
500 	    }
501 	    msg = (char *) inp;
502 	    PRINTMSG(msg, msglen);
503 	}
504     }
505 
506     u->us_clientstate = UPAPCS_OPEN;
507 
508     auth_withpeer_success(u->us_unit, PPP_PAP, 0);
509 }
510 
511 
512 /*
513  * upap_rauthnak - Receive Authenticate-Nak.
514  */
515 static void
516 upap_rauthnak(u, inp, id, len)
517     upap_state *u;
518     u_char *inp;
519     int id;
520     int len;
521 {
522     u_char msglen;
523     char *msg;
524 
525     if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
526 	return;
527 
528     /*
529      * Parse message.
530      */
531     if (len < 1) {
532 	UPAPDEBUG(("pap_rauthnak: ignoring missing msg-length."));
533     } else {
534 	GETCHAR(msglen, inp);
535 	if (msglen > 0) {
536 	    len -= sizeof (u_char);
537 	    if (len < msglen) {
538 		UPAPDEBUG(("pap_rauthnak: rcvd short packet."));
539 		return;
540 	    }
541 	    msg = (char *) inp;
542 	    PRINTMSG(msg, msglen);
543 	}
544     }
545 
546     u->us_clientstate = UPAPCS_BADAUTH;
547 
548     error("PAP authentication failed");
549     auth_withpeer_fail(u->us_unit, PPP_PAP);
550 }
551 
552 
553 /*
554  * upap_sauthreq - Send an Authenticate-Request.
555  */
556 static void
557 upap_sauthreq(u)
558     upap_state *u;
559 {
560     u_char *outp;
561     int outlen;
562 
563     outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) +
564 	u->us_userlen + u->us_passwdlen;
565     outp = outpacket_buf;
566 
567     MAKEHEADER(outp, PPP_PAP);
568 
569     PUTCHAR(UPAP_AUTHREQ, outp);
570     PUTCHAR(++u->us_id, outp);
571     PUTSHORT(outlen, outp);
572     PUTCHAR(u->us_userlen, outp);
573     BCOPY(u->us_user, outp, u->us_userlen);
574     INCPTR(u->us_userlen, outp);
575     PUTCHAR(u->us_passwdlen, outp);
576     BCOPY(u->us_passwd, outp, u->us_passwdlen);
577 
578     output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
579 
580     TIMEOUT(upap_timeout, u, u->us_timeouttime);
581     ++u->us_transmits;
582     u->us_clientstate = UPAPCS_AUTHREQ;
583 }
584 
585 
586 /*
587  * upap_sresp - Send a response (ack or nak).
588  */
589 static void
590 upap_sresp(u, code, id, msg, msglen)
591     upap_state *u;
592     u_char code, id;
593     char *msg;
594     int msglen;
595 {
596     u_char *outp;
597     int outlen;
598 
599     outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
600     outp = outpacket_buf;
601     MAKEHEADER(outp, PPP_PAP);
602 
603     PUTCHAR(code, outp);
604     PUTCHAR(id, outp);
605     PUTSHORT(outlen, outp);
606     PUTCHAR(msglen, outp);
607     BCOPY(msg, outp, msglen);
608     output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
609 }
610 
611 /*
612  * upap_printpkt - print the contents of a PAP packet.
613  */
614 static char *upap_codenames[] = {
615     "AuthReq", "AuthAck", "AuthNak"
616 };
617 
618 static int
619 upap_printpkt(p, plen, printer, arg)
620     u_char *p;
621     int plen;
622     void (*printer) __P((void *, char *, ...));
623     void *arg;
624 {
625     int code, id, len;
626     int mlen, ulen, wlen;
627     char *user, *pwd, *msg;
628     u_char *pstart;
629 
630     if (plen < UPAP_HEADERLEN)
631 	return 0;
632     pstart = p;
633     GETCHAR(code, p);
634     GETCHAR(id, p);
635     GETSHORT(len, p);
636     if (len < UPAP_HEADERLEN || len > plen)
637 	return 0;
638 
639     if (code >= 1 && code <= sizeof(upap_codenames) / sizeof(char *))
640 	printer(arg, " %s", upap_codenames[code-1]);
641     else
642 	printer(arg, " code=0x%x", code);
643     printer(arg, " id=0x%x", id);
644     len -= UPAP_HEADERLEN;
645     switch (code) {
646     case UPAP_AUTHREQ:
647 	if (len < 1)
648 	    break;
649 	ulen = p[0];
650 	if (len < ulen + 2)
651 	    break;
652 	wlen = p[ulen + 1];
653 	if (len < ulen + wlen + 2)
654 	    break;
655 	user = (char *) (p + 1);
656 	pwd = (char *) (p + ulen + 2);
657 	p += ulen + wlen + 2;
658 	len -= ulen + wlen + 2;
659 	printer(arg, " user=");
660 	print_string(user, ulen, printer, arg);
661 	printer(arg, " password=");
662 	if (!hide_password)
663 	    print_string(pwd, wlen, printer, arg);
664 	else
665 	    printer(arg, "<hidden>");
666 	break;
667     case UPAP_AUTHACK:
668     case UPAP_AUTHNAK:
669 	if (len < 1)
670 	    break;
671 	mlen = p[0];
672 	if (len < mlen + 1)
673 	    break;
674 	msg = (char *) (p + 1);
675 	p += mlen + 1;
676 	len -= mlen + 1;
677 	printer(arg, " ");
678 	print_string(msg, mlen, printer, arg);
679 	break;
680     }
681 
682     /* print the rest of the bytes in the packet */
683     for (; len > 0; --len) {
684 	GETCHAR(code, p);
685 	printer(arg, " %.2x", code);
686     }
687 
688     return p - pstart;
689 }
690