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