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
upap_init(int unit)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
upap_authwithpeer(int unit,char * user,char * password)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
upap_authpeer(int unit)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
upap_timeout(void * arg)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
upap_reqtimeout(void * arg)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
upap_lowerup(int unit)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
upap_lowerdown(int unit)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
upap_protrej(int unit)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
upap_input(int unit,u_char * inpacket,int l)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
upap_rauthreq(upap_state * u,u_char * inp,int id,int len)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
upap_rauthack(upap_state * u,u_char * inp,int id,int len)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
upap_rauthnak(upap_state * u,u_char * inp,int id,int len)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
upap_sauthreq(upap_state * u)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
upap_sresp(upap_state * u,int code,int id,char * msg,int msglen)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
upap_printpkt(u_char * p,int plen,void (* printer)(void *,char *,...),void * arg)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