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