xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.bin/pppd/upap.c (revision 711890bc9379ceea66272dc8d4981812224ea86e)
1 /*
2  * upap.c - User/Password Authentication Protocol.
3  *
4  * Copyright (c) 2000 by Sun Microsystems, Inc.
5  * All rights reserved.
6  *
7  * Permission to use, copy, modify, and distribute this software and its
8  * documentation is hereby granted, provided that the above copyright
9  * notice appears in all copies.
10  *
11  * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
12  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
13  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
14  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT.  SUN SHALL NOT BE LIABLE FOR
15  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
16  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
17  *
18  * Copyright (c) 1989 Carnegie Mellon University.
19  * All rights reserved.
20  *
21  * Redistribution and use in source and binary forms are permitted
22  * provided that the above copyright notice and this paragraph are
23  * duplicated in all such forms and that any documentation,
24  * advertising materials, and other materials related to such
25  * distribution and use acknowledge that the software was developed
26  * by Carnegie Mellon University.  The name of the
27  * University may not be used to endorse or promote products derived
28  * from this software without specific prior written permission.
29  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
30  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
31  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32  */
33 
34 #pragma ident	"%Z%%M%	%I%	%E% SMI"
35 #define RCSID	"$Id: upap.c,v 1.23 1999/11/20 05:11:47 paulus Exp $"
36 
37 #include <stdio.h>
38 #include <string.h>
39 
40 #include "pppd.h"
41 #include "upap.h"
42 
43 #if !defined(lint) && !defined(_lint)
44 static const char rcsid[] = RCSID;
45 #endif
46 
47 static bool hide_password = 1;
48 
49 /*
50  * Command-line options.
51  */
52 static option_t pap_option_list[] = {
53     { "hide-password", o_bool, &hide_password,
54       "Don't output passwords to log", 1 },
55     { "show-password", o_bool, &hide_password,
56       "Show password string in debug log messages", 0 },
57     { "pap-restart", o_int, &upap[0].us_timeouttime,
58       "Set retransmit timeout for PAP" },
59     { "pap-max-authreq", o_int, &upap[0].us_maxtransmits,
60       "Max number of PAP Authenticate-Request sent" },
61     { "pap-max-receive", o_int, &upap[0].us_maxreceives,
62       "Max allowable PAP Authenticate-Request received" },
63     { "pap-timeout", o_int, &upap[0].us_reqtimeout,
64       "Set time limit for peer PAP authentication" },
65     { NULL }
66 };
67 
68 /*
69  * Protocol entry points.
70  */
71 static void upap_init __P((int));
72 static void upap_lowerup __P((int));
73 static void upap_lowerdown __P((int));
74 static void upap_input __P((int, u_char *, int));
75 static void upap_protrej __P((int));
76 static int  upap_printpkt __P((u_char *, int,
77     void (*) __P((void *, const char *, ...)), void *));
78 
79 struct protent pap_protent = {
80     PPP_PAP,
81     upap_init,
82     upap_input,
83     upap_protrej,
84     upap_lowerup,
85     upap_lowerdown,
86     NULL,
87     NULL,
88     upap_printpkt,
89     NULL,
90     1,
91     "PAP",
92     NULL,
93     pap_option_list,
94     NULL,
95     NULL,
96     NULL
97 };
98 
99 upap_state upap[NUM_PPP];		/* UPAP state; one for each unit */
100 
101 static void upap_timeout __P((void *));
102 static void upap_reqtimeout __P((void *));
103 static void upap_rauthreq __P((upap_state *, u_char *, int, int));
104 static void upap_rauthack __P((upap_state *, u_char *, int, int));
105 static void upap_rauthnak __P((upap_state *, u_char *, int, int));
106 static void upap_sauthreq __P((upap_state *));
107 static void upap_sresp __P((upap_state *, int, int, char *, int));
108 
109 static const char *
110 pap_cstate(clientstate)
111     int clientstate;
112 {
113     static const char *cstate[] = { UPAPCS__NAMES };
114     static char buf[32];
115 
116     if (clientstate < 0 || clientstate >= Dim(cstate)) {
117 	(void) slprintf(buf, sizeof (buf), "Cli#%d", clientstate);
118 	return ((const char *)buf);
119     }
120     return (cstate[clientstate]);
121 }
122 
123 static const char *
124 pap_sstate(serverstate)
125     int serverstate;
126 {
127     static const char *sstate[] = { UPAPSS__NAMES };
128     static char buf[32];
129 
130     if (serverstate < 0 || serverstate >= Dim(sstate)) {
131 	(void) slprintf(buf, sizeof (buf), "Srv#%d", serverstate);
132 	return ((const char *)buf);
133     }
134     return (sstate[serverstate]);
135 }
136 
137 /*
138  * upap_init - Initialize a UPAP unit.
139  */
140 static void
141 upap_init(unit)
142     int unit;
143 {
144     upap_state *u = &upap[unit];
145 
146     u->us_unit = unit;
147     u->us_user = NULL;
148     u->us_userlen = 0;
149     u->us_passwd = NULL;
150     u->us_clientstate = UPAPCS_INITIAL;
151     u->us_serverstate = UPAPSS_INITIAL;
152     u->us_id = 0;
153     u->us_timeouttime = UPAP_DEFTIMEOUT;
154     u->us_maxtransmits = 10;
155     u->us_reqtimeout = UPAP_DEFREQTIME;
156     u->us_maxreceives = 3;
157     u->us_msg = "";
158     u->us_msglen = 0;
159 }
160 
161 
162 /*
163  * upap_authwithpeer - Authenticate us with our peer (start client).
164  *
165  * Set new state and send authenticate's.
166  */
167 void
168 upap_authwithpeer(unit, user, password)
169     int unit;
170     char *user, *password;
171 {
172     upap_state *u = &upap[unit];
173 
174     /* Save the username and password we're given */
175     u->us_user = user;
176     u->us_userlen = strlen(user);
177     u->us_passwd = password;
178     u->us_transmits = 0;
179 
180     /* Lower layer up yet? */
181     if (u->us_clientstate == UPAPCS_INITIAL ||
182 	u->us_clientstate == UPAPCS_PENDING) {
183 	u->us_clientstate = UPAPCS_PENDING;
184 	return;
185     }
186 
187     upap_sauthreq(u);			/* Start protocol */
188 }
189 
190 
191 /*
192  * upap_authpeer - Authenticate our peer (start server).
193  *
194  * Set new state.
195  */
196 void
197 upap_authpeer(unit)
198     int unit;
199 {
200     upap_state *u = &upap[unit];
201 
202     /* Lower layer up yet? */
203     if (u->us_serverstate == UPAPSS_INITIAL ||
204 	u->us_serverstate == UPAPSS_PENDING) {
205 	u->us_serverstate = UPAPSS_PENDING;
206 	return;
207     }
208 
209     u->us_serverstate = UPAPSS_LISTEN;
210     u->us_receives = 0;
211     if (u->us_reqtimeout > 0)
212 	TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
213 }
214 
215 
216 /*
217  * upap_timeout - Retransmission timer for sending auth-reqs expired.
218  */
219 static void
220 upap_timeout(arg)
221     void *arg;
222 {
223     upap_state *u = (upap_state *) arg;
224 
225     if (u->us_clientstate != UPAPCS_AUTHREQ)
226 	return;
227 
228     if (u->us_transmits >= u->us_maxtransmits) {
229 	/* give up in disgust */
230 	error("No response to %d PAP Authenticate-Requests", u->us_transmits);
231 	u->us_clientstate = UPAPCS_BADAUTH;
232 	auth_withpeer_fail(u->us_unit, PPP_PAP);
233 	return;
234     }
235 
236     upap_sauthreq(u);		/* Send Authenticate-Request */
237 }
238 
239 
240 /*
241  * upap_reqtimeout - Give up waiting for the peer to send a valid auth-req.
242  */
243 static void
244 upap_reqtimeout(arg)
245     void *arg;
246 {
247     upap_state *u = (upap_state *) arg;
248 
249     if (u->us_serverstate != UPAPSS_LISTEN)
250 	return;			/* huh?? */
251 
252     auth_peer_fail(u->us_unit, PPP_PAP);
253     u->us_serverstate = UPAPSS_BADAUTH;
254 }
255 
256 
257 /*
258  * upap_lowerup - The lower layer is up.
259  *
260  * Start authenticating if pending.
261  */
262 static void
263 upap_lowerup(unit)
264     int unit;
265 {
266     upap_state *u = &upap[unit];
267 
268     if (u->us_clientstate == UPAPCS_INITIAL)
269 	u->us_clientstate = UPAPCS_CLOSED;
270     else if (u->us_clientstate == UPAPCS_PENDING) {
271 	upap_sauthreq(u);	/* send an auth-request */
272     }
273 
274     if (u->us_serverstate == UPAPSS_INITIAL)
275 	u->us_serverstate = UPAPSS_CLOSED;
276     else if (u->us_serverstate == UPAPSS_PENDING) {
277 	u->us_serverstate = UPAPSS_LISTEN;
278 	if (u->us_reqtimeout > 0)
279 	    TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
280     }
281 }
282 
283 
284 /*
285  * upap_lowerdown - The lower layer is down.
286  *
287  * Cancel all timeouts.
288  */
289 static void
290 upap_lowerdown(unit)
291     int unit;
292 {
293     upap_state *u = &upap[unit];
294 
295     /* Cancel timeouts */
296     if (u->us_clientstate == UPAPCS_AUTHREQ && u->us_timeouttime > 0)
297 	UNTIMEOUT(upap_timeout, u);
298     if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0)
299 	UNTIMEOUT(upap_reqtimeout, u);
300 
301     u->us_clientstate = UPAPCS_INITIAL;
302     u->us_serverstate = UPAPSS_INITIAL;
303 }
304 
305 
306 /*
307  * upap_protrej - Peer doesn't speak this protocol.
308  *
309  * This shouldn't happen.  In any case, pretend lower layer went down.
310  */
311 static void
312 upap_protrej(unit)
313     int unit;
314 {
315     upap_state *u = &upap[unit];
316 
317     if (u->us_clientstate == UPAPCS_AUTHREQ) {
318 	error("PAP authentication failed due to protocol-reject");
319 	auth_withpeer_fail(unit, PPP_PAP);
320     }
321     if (u->us_serverstate == UPAPSS_LISTEN) {
322 	error("PAP authentication of peer failed (protocol-reject)");
323 	auth_peer_fail(unit, PPP_PAP);
324     }
325     upap_lowerdown(unit);
326 }
327 
328 
329 /*
330  * upap_input - Input UPAP packet.
331  */
332 static void
333 upap_input(unit, inpacket, l)
334     int unit;
335     u_char *inpacket;
336     int l;
337 {
338     upap_state *u = &upap[unit];
339     u_char *inp;
340     u_char code, id;
341     int len;
342 
343     /*
344      * Parse header (code, id and length).
345      * If packet too short, drop it.
346      */
347     inp = inpacket;
348     if (l < UPAP_HEADERLEN) {
349 	error("PAP: packet is too small (%d < %d)", l, UPAP_HEADERLEN);
350 	return;
351     }
352     GETCHAR(code, inp);
353     GETCHAR(id, inp);
354     GETSHORT(len, inp);
355     if ((len < UPAP_HEADERLEN) || (len > l)) {
356 	error("PAP: packet has illegal length %d (%d..%d)", len,
357 	    UPAP_HEADERLEN, l);
358 	return;
359     }
360     len -= UPAP_HEADERLEN;
361 
362     /*
363      * Action depends on code.
364      */
365     switch (code) {
366     case UPAP_AUTHREQ:
367 	upap_rauthreq(u, inp, id, len);
368 	break;
369 
370     case UPAP_AUTHACK:
371 	upap_rauthack(u, inp, id, len);
372 	break;
373 
374     case UPAP_AUTHNAK:
375 	upap_rauthnak(u, inp, id, len);
376 	break;
377 
378     default:
379 	warn("Unknown PAP code (%d) received.", code);
380 	break;
381     }
382 }
383 
384 
385 /*
386  * upap_rauth - Receive Authenticate.
387  */
388 static void
389 upap_rauthreq(u, inp, id, len)
390     upap_state *u;
391     u_char *inp;
392     int id;
393     int len;
394 {
395     u_char ruserlen, rpasswdlen;
396     char *ruser, *rpasswd;
397     int retcode;
398     char *msg;
399     int msglen;
400 
401     if (u->us_serverstate < UPAPSS_LISTEN) {
402 	info("PAP: discarded Authenticate-Request in state %s",
403 	    pap_sstate(u->us_serverstate));
404 	return;
405     }
406 
407     /*
408      * If we receive a duplicate authenticate-request, we are
409      * supposed to return the same status as for the first request.
410      */
411     if (u->us_serverstate == UPAPSS_OPEN) {
412 	/* return auth-ack */
413 	upap_sresp(u, UPAP_AUTHACK, id, u->us_msg, u->us_msglen);
414 	return;
415     }
416     if (u->us_serverstate == UPAPSS_BADAUTH) {
417 	/* return auth-nak */
418 	upap_sresp(u, UPAP_AUTHNAK, id, u->us_msg, u->us_msglen);
419 	return;
420     }
421 
422     /*
423      * Parse user/passwd.
424      */
425     if (len < 1) {
426 	error("PAP: rcvd short packet; no data");
427 	return;
428     }
429     GETCHAR(ruserlen, inp);
430     len -= sizeof (u_char) + ruserlen + sizeof (u_char);
431     if (len < 0) {
432 	error("PAP: rcvd short packet; peer name missing");
433 	return;
434     }
435     ruser = (char *) inp;
436     INCPTR(ruserlen, inp);
437     GETCHAR(rpasswdlen, inp);
438     if (len < rpasswdlen) {
439 	error("PAP: rcvd short packet; pass len %d < %d", len, rpasswdlen);
440 	return;
441     }
442     rpasswd = (char *) inp;
443 
444     /*
445      * Check the username and password given.
446      */
447     retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
448 			   rpasswdlen, &msg);
449     BZERO(rpasswd, rpasswdlen);
450     msglen = strlen(msg);
451     if (msglen > 255)
452 	msglen = 255;
453 
454     u->us_msg = msg;
455     u->us_msglen = msglen;
456     upap_sresp(u, retcode, id, u->us_msg, u->us_msglen);
457 
458     if (retcode == UPAP_AUTHACK) {
459 	u->us_serverstate = UPAPSS_OPEN;
460 	auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen);
461     } else if (++u->us_receives >= u->us_maxreceives) {
462 	u->us_serverstate = UPAPSS_BADAUTH;
463 	auth_peer_fail(u->us_unit, PPP_PAP);
464     } else {
465 	/* Just wait for a good one to arrive, or for time-out. */
466 	return;
467     }
468 
469     if (u->us_reqtimeout > 0)
470 	UNTIMEOUT(upap_reqtimeout, u);
471 }
472 
473 
474 /*
475  * upap_rauthack - Receive Authenticate-Ack.
476  */
477 /*ARGSUSED*/
478 static void
479 upap_rauthack(u, inp, id, len)
480     upap_state *u;
481     u_char *inp;
482     int id;
483     int len;
484 {
485     u_char msglen;
486     char *msg;
487 
488     if (u->us_clientstate != UPAPCS_AUTHREQ) {
489 	info("PAP: discarded Authenticate-Ack in state %s",
490 	    pap_cstate(u->us_clientstate));
491 	return;
492     }
493 
494     if (id != u->us_id) {
495 	dbglog("PAP: discard Authenticate-Ack; ID %d != %d",
496 	    id, u->us_id);
497 	return;
498     }
499 
500     if (u->us_timeouttime > 0)
501 	UNTIMEOUT(upap_timeout, u);
502 
503     /*
504      * Parse message.
505      */
506     if (len < 1) {
507 	info("PAP:  Ignoring missing ack msg-length octet");
508     } else {
509 	GETCHAR(msglen, inp);
510 	if (msglen > 0) {
511 	    len -= sizeof (u_char);
512 	    if (len < msglen) {
513 		error("PAP:  Discarding short packet (%d < %d)", len, msglen);
514 		return;
515 	    }
516 	    msg = (char *) inp;
517 	    PRINTMSG(msg, msglen);
518 	}
519     }
520 
521     u->us_clientstate = UPAPCS_OPEN;
522 
523     auth_withpeer_success(u->us_unit, PPP_PAP);
524 }
525 
526 
527 /*
528  * upap_rauthnak - Receive Authenticate-Nakk.
529  */
530 /*ARGSUSED*/
531 static void
532 upap_rauthnak(u, inp, id, len)
533     upap_state *u;
534     u_char *inp;
535     int id;
536     int len;
537 {
538     u_char msglen;
539     char *msg;
540 
541     if (u->us_clientstate != UPAPCS_AUTHREQ) {
542 	info("PAP: discarded Authenticate-Nak in state %s",
543 	    pap_cstate(u->us_clientstate));
544 	return;
545     }
546 
547     if (id != u->us_id) {
548 	dbglog("PAP: discard Authenticate-Ack; ID %d != %d",
549 	    id, u->us_id);
550 	return;
551     }
552 
553     if (u->us_timeouttime > 0)
554 	UNTIMEOUT(upap_timeout, u);
555 
556     /*
557      * Parse message.
558      */
559     if (len < 1) {
560 	error("PAP: ignoring missing nak msg-length octet");
561     } else {
562 	GETCHAR(msglen, inp);
563 	if (msglen > 0) {
564 	    len -= sizeof (u_char);
565 	    if (len < msglen) {
566 		error("PAP: Discarding short packet (%d < %d)", len, msglen);
567 		return;
568 	    }
569 	    msg = (char *) inp;
570 	    PRINTMSG(msg, msglen);
571 	}
572     }
573 
574     /* Try to get a new password from the plugin. */
575     if (pap_passwd_hook != NULL) {
576 	if (u->us_transmits < u->us_maxtransmits) {
577 	    if ((*pap_passwd_hook)(user, passwd) >= 0) {
578 		upap_sauthreq(u);
579 		return;
580 	    }
581 	} else {
582 	    /* Tell plug-in that we're giving up. */
583 	    (void) (*pap_passwd_hook)(NULL, NULL);
584 	}
585     }
586 
587     u->us_clientstate = UPAPCS_BADAUTH;
588 
589     error("PAP authentication failed");
590     auth_withpeer_fail(u->us_unit, PPP_PAP);
591 }
592 
593 
594 /*
595  * upap_sauthreq - Send an Authenticate-Request.
596  */
597 static void
598 upap_sauthreq(u)
599     upap_state *u;
600 {
601     u_char *outp;
602     int pwlen;
603     int outlen;
604 
605     pwlen = strllen(passwd, MAXSECRETLEN);
606     if (pwlen > 0xFF)
607 	pwlen = 0xFF;
608     outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) + u->us_userlen + pwlen;
609     outp = outpacket_buf;
610 
611     MAKEHEADER(outp, PPP_PAP);
612 
613     PUTCHAR(UPAP_AUTHREQ, outp);
614     PUTCHAR(++u->us_id, outp);
615     PUTSHORT(outlen, outp);
616     PUTCHAR(u->us_userlen, outp);
617     BCOPY(u->us_user, outp, u->us_userlen);
618     INCPTR(u->us_userlen, outp);
619     PUTCHAR(pwlen, outp);
620     BCOPY(u->us_passwd, outp, pwlen);
621 
622     output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
623 
624     if (u->us_timeouttime > 0)
625 	TIMEOUT(upap_timeout, u, u->us_timeouttime);
626     ++u->us_transmits;
627     u->us_clientstate = UPAPCS_AUTHREQ;
628 }
629 
630 
631 /*
632  * upap_sresp - Send a response (ack or nak).
633  */
634 static void
635 upap_sresp(u, code, id, msg, msglen)
636     upap_state *u;
637     u_char code, id;
638     char *msg;
639     int msglen;
640 {
641     u_char *outp;
642     int outlen;
643 
644     outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
645     outp = outpacket_buf;
646     MAKEHEADER(outp, PPP_PAP);
647 
648     PUTCHAR(code, outp);
649     PUTCHAR(id, outp);
650     PUTSHORT(outlen, outp);
651     PUTCHAR(msglen, outp);
652     BCOPY(msg, outp, msglen);
653     output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
654 }
655 
656 /*
657  * upap_printpkt - print the contents of a PAP packet.
658  */
659 static char *upap_codenames[] = {
660     "AuthReq", "AuthAck", "AuthNak"
661 };
662 
663 static int
664 upap_printpkt(p, plen, printer, arg)
665     u_char *p;
666     int plen;
667     void (*printer) __P((void *, const char *, ...));
668     void *arg;
669 {
670     int code, id, len;
671     int mlen, ulen, wlen;
672     char *user, *pwd, *msg;
673     u_char *pstart;
674 
675     if (plen < UPAP_HEADERLEN)
676 	return (0);
677     pstart = p;
678     GETCHAR(code, p);
679     GETCHAR(id, p);
680     GETSHORT(len, p);
681     if (len < UPAP_HEADERLEN || len > plen)
682 	return (0);
683 
684     if (code >= 1 && code <= Dim(upap_codenames))
685 	printer(arg, " %s", upap_codenames[code-1]);
686     else
687 	printer(arg, " code=0x%x", code);
688     printer(arg, " id=0x%x", id);
689     len -= UPAP_HEADERLEN;
690     switch (code) {
691     case UPAP_AUTHREQ:
692 	if (len < 1)
693 	    break;
694 	ulen = p[0];
695 	if (len < ulen + 2)
696 	    break;
697 	wlen = p[ulen + 1];
698 	if (len < ulen + wlen + 2)
699 	    break;
700 	user = (char *) (p + 1);
701 	pwd = (char *) (p + ulen + 2);
702 	p += ulen + wlen + 2;
703 	len -= ulen + wlen + 2;
704 	printer(arg, " user=");
705 	print_string(user, ulen, printer, arg);
706 	printer(arg, " password=");
707 	if (!hide_password)
708 	    print_string(pwd, wlen, printer, arg);
709 	else
710 	    printer(arg, "<hidden>");
711 	break;
712     case UPAP_AUTHACK:
713     case UPAP_AUTHNAK:
714 	if (len < 1)
715 	    break;
716 	mlen = p[0];
717 	if (len < mlen + 1)
718 	    break;
719 	msg = (char *) (p + 1);
720 	p += mlen + 1;
721 	len -= mlen + 1;
722 	printer(arg, " ");
723 	print_string(msg, mlen, printer, arg);
724 	break;
725     }
726 
727     /* print the rest of the bytes in the packet */
728     for (; len > 0; --len) {
729 	GETCHAR(code, p);
730 	printer(arg, " %.2x", code);
731     }
732 
733     return (p - pstart);
734 }
735