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