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