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