xref: /386bsd/usr/src/usr.sbin/pppd/upap.c (revision a2142627)
1 /*
2  * upap.c - User/Password Authentication Protocol.
3  *
4  * Copyright (c) 1989 Carnegie Mellon University.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms are permitted
8  * provided that the above copyright notice and this paragraph are
9  * duplicated in all such forms and that any documentation,
10  * advertising materials, and other materials related to such
11  * distribution and use acknowledge that the software was developed
12  * by Carnegie Mellon University.  The name of the
13  * University may not be used to endorse or promote products derived
14  * from this software without specific prior written permission.
15  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18  */
19 
20 #ifndef lint
21 static char rcsid[] = "$Id: upap.c,v 1.2 1994/04/11 07:13:44 paulus Exp $";
22 #endif
23 
24 /*
25  * TODO:
26  */
27 
28 #include <stdio.h>
29 #include <sys/types.h>
30 #include <sys/time.h>
31 #include <syslog.h>
32 
33 #include "ppp.h"
34 #include "pppd.h"
35 #include "upap.h"
36 
37 
38 upap_state upap[NPPP];		/* UPAP state; one for each unit */
39 
40 
41 static void upap_timeout __ARGS((caddr_t));
42 static void upap_rauthreq __ARGS((upap_state *, u_char *, int, int));
43 static void upap_rauthack __ARGS((upap_state *, u_char *, int, int));
44 static void upap_rauthnak __ARGS((upap_state *, u_char *, int, int));
45 static void upap_sauthreq __ARGS((upap_state *));
46 static void upap_sresp __ARGS((upap_state *, int, int, char *, int));
47 
48 
49 /*
50  * upap_init - Initialize a UPAP unit.
51  */
52 void
upap_init(unit)53 upap_init(unit)
54     int unit;
55 {
56     upap_state *u = &upap[unit];
57 
58     u->us_unit = unit;
59     u->us_user = NULL;
60     u->us_userlen = 0;
61     u->us_passwd = NULL;
62     u->us_passwdlen = 0;
63     u->us_clientstate = UPAPCS_INITIAL;
64     u->us_serverstate = UPAPSS_INITIAL;
65     u->us_id = 0;
66     u->us_timeouttime = UPAP_DEFTIMEOUT;
67     u->us_maxtransmits = 10;
68 }
69 
70 
71 /*
72  * upap_authwithpeer - Authenticate us with our peer (start client).
73  *
74  * Set new state and send authenticate's.
75  */
76 void
upap_authwithpeer(unit,user,password)77 upap_authwithpeer(unit, user, password)
78     int unit;
79     char *user, *password;
80 {
81     upap_state *u = &upap[unit];
82 
83     /* Save the username and password we're given */
84     u->us_user = user;
85     u->us_userlen = strlen(user);
86     u->us_passwd = password;
87     u->us_passwdlen = strlen(password);
88     u->us_transmits = 0;
89 
90     /* Lower layer up yet? */
91     if (u->us_clientstate == UPAPCS_INITIAL ||
92 	u->us_clientstate == UPAPCS_PENDING) {
93 	u->us_clientstate = UPAPCS_PENDING;
94 	return;
95     }
96 
97     upap_sauthreq(u);			/* Start protocol */
98 }
99 
100 
101 /*
102  * upap_authpeer - Authenticate our peer (start server).
103  *
104  * Set new state.
105  */
106 void
upap_authpeer(unit)107 upap_authpeer(unit)
108     int unit;
109 {
110     upap_state *u = &upap[unit];
111 
112     /* Lower layer up yet? */
113     if (u->us_serverstate == UPAPSS_INITIAL ||
114 	u->us_serverstate == UPAPSS_PENDING) {
115 	u->us_serverstate = UPAPSS_PENDING;
116 	return;
117     }
118 
119     u->us_serverstate = UPAPSS_LISTEN;
120 }
121 
122 
123 /*
124  * upap_timeout - Timeout expired.
125  */
126 static void
upap_timeout(arg)127 upap_timeout(arg)
128     caddr_t arg;
129 {
130     upap_state *u = (upap_state *) arg;
131 
132     if (u->us_clientstate != UPAPCS_AUTHREQ)
133 	return;
134 
135     if (u->us_transmits >= u->us_maxtransmits) {
136 	/* give up in disgust */
137 	syslog(LOG_ERR, "No response to PAP authenticate-requests");
138 	u->us_clientstate = UPAPCS_BADAUTH;
139 	auth_withpeer_fail(u->us_unit, UPAP);
140 	return;
141     }
142 
143     upap_sauthreq(u);		/* Send Authenticate-Request */
144 }
145 
146 
147 /*
148  * upap_lowerup - The lower layer is up.
149  *
150  * Start authenticating if pending.
151  */
152 void
upap_lowerup(unit)153 upap_lowerup(unit)
154     int unit;
155 {
156     upap_state *u = &upap[unit];
157 
158     if (u->us_clientstate == UPAPCS_INITIAL)
159 	u->us_clientstate = UPAPCS_CLOSED;
160     else if (u->us_clientstate == UPAPCS_PENDING) {
161 	upap_sauthreq(u);	/* send an auth-request */
162     }
163 
164     if (u->us_serverstate == UPAPSS_INITIAL)
165 	u->us_serverstate = UPAPSS_CLOSED;
166     else if (u->us_serverstate == UPAPSS_PENDING)
167 	u->us_serverstate = UPAPSS_LISTEN;
168 }
169 
170 
171 /*
172  * upap_lowerdown - The lower layer is down.
173  *
174  * Cancel all timeouts.
175  */
176 void
upap_lowerdown(unit)177 upap_lowerdown(unit)
178     int unit;
179 {
180     upap_state *u = &upap[unit];
181 
182     if (u->us_clientstate == UPAPCS_AUTHREQ) /* Timeout pending? */
183 	UNTIMEOUT(upap_timeout, (caddr_t) u);	/* Cancel timeout */
184 
185     u->us_clientstate = UPAPCS_INITIAL;
186     u->us_serverstate = UPAPSS_INITIAL;
187 }
188 
189 
190 /*
191  * upap_protrej - Peer doesn't speak this protocol.
192  *
193  * This shouldn't happen.  In any case, pretend lower layer went down.
194  */
195 void
upap_protrej(unit)196 upap_protrej(unit)
197     int unit;
198 {
199     upap_state *u = &upap[unit];
200 
201     if (u->us_clientstate == UPAPCS_AUTHREQ) {
202 	syslog(LOG_ERR, "PAP authentication failed due to protocol-reject");
203 	auth_withpeer_fail(unit, UPAP);
204     }
205     if (u->us_serverstate == UPAPSS_LISTEN) {
206 	syslog(LOG_ERR, "PAP authentication of peer failed (protocol-reject)");
207 	auth_peer_fail(unit, UPAP);
208     }
209     upap_lowerdown(unit);
210 }
211 
212 
213 /*
214  * upap_input - Input UPAP packet.
215  */
216 void
upap_input(unit,inpacket,l)217 upap_input(unit, inpacket, l)
218     int unit;
219     u_char *inpacket;
220     int l;
221 {
222     upap_state *u = &upap[unit];
223     u_char *inp;
224     u_char code, id;
225     int len;
226 
227     /*
228      * Parse header (code, id and length).
229      * If packet too short, drop it.
230      */
231     inp = inpacket;
232     if (l < UPAP_HEADERLEN) {
233 	UPAPDEBUG((LOG_INFO, "upap_input: rcvd short header."));
234 	return;
235     }
236     GETCHAR(code, inp);
237     GETCHAR(id, inp);
238     GETSHORT(len, inp);
239     if (len < UPAP_HEADERLEN) {
240 	UPAPDEBUG((LOG_INFO, "upap_input: rcvd illegal length."));
241 	return;
242     }
243     if (len > l) {
244 	UPAPDEBUG((LOG_INFO, "upap_input: rcvd short packet."));
245 	return;
246     }
247     len -= UPAP_HEADERLEN;
248 
249     /*
250      * Action depends on code.
251      */
252     switch (code) {
253     case UPAP_AUTHREQ:
254 	upap_rauthreq(u, inp, id, len);
255 	break;
256 
257     case UPAP_AUTHACK:
258 	upap_rauthack(u, inp, id, len);
259 	break;
260 
261     case UPAP_AUTHNAK:
262 	upap_rauthnak(u, inp, id, len);
263 	break;
264 
265     default:				/* XXX Need code reject */
266 	break;
267     }
268 }
269 
270 
271 /*
272  * upap_rauth - Receive Authenticate.
273  */
274 static void
upap_rauthreq(u,inp,id,len)275 upap_rauthreq(u, inp, id, len)
276     upap_state *u;
277     u_char *inp;
278     int id;
279     int len;
280 {
281     u_char ruserlen, rpasswdlen;
282     char *ruser, *rpasswd;
283     int retcode;
284     char *msg;
285     int msglen;
286 
287     UPAPDEBUG((LOG_INFO, "upap_rauth: Rcvd id %d.", id));
288 
289     if (u->us_serverstate < UPAPSS_LISTEN)
290 	return;
291 
292     /*
293      * If we receive a duplicate authenticate-request, we are
294      * supposed to return the same status as for the first request.
295      */
296     if (u->us_serverstate == UPAPSS_OPEN) {
297 	upap_sresp(u, UPAP_AUTHACK, id, "", 0);	/* return auth-ack */
298 	return;
299     }
300     if (u->us_serverstate == UPAPSS_BADAUTH) {
301 	upap_sresp(u, UPAP_AUTHNAK, id, "", 0);	/* return auth-nak */
302 	return;
303     }
304 
305     /*
306      * Parse user/passwd.
307      */
308     if (len < sizeof (u_char)) {
309 	UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet."));
310 	return;
311     }
312     GETCHAR(ruserlen, inp);
313     len -= sizeof (u_char) + ruserlen + sizeof (u_char);
314     if (len < 0) {
315 	UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet."));
316 	return;
317     }
318     ruser = (char *) inp;
319     INCPTR(ruserlen, inp);
320     GETCHAR(rpasswdlen, inp);
321     if (len < rpasswdlen) {
322 	UPAPDEBUG((LOG_INFO, "upap_rauth: rcvd short packet."));
323 	return;
324     }
325     rpasswd = (char *) inp;
326 
327     /*
328      * Check the username and password given.
329      */
330     retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
331 			   rpasswdlen, &msg, &msglen);
332 
333     upap_sresp(u, retcode, id, msg, msglen);
334 
335     if (retcode == UPAP_AUTHACK) {
336 	u->us_serverstate = UPAPSS_OPEN;
337 	auth_peer_success(u->us_unit, UPAP);
338     } else {
339 	u->us_serverstate = UPAPSS_BADAUTH;
340 	auth_peer_fail(u->us_unit, UPAP);
341     }
342 }
343 
344 
345 /*
346  * upap_rauthack - Receive Authenticate-Ack.
347  */
348 static void
upap_rauthack(u,inp,id,len)349 upap_rauthack(u, inp, id, len)
350     upap_state *u;
351     u_char *inp;
352     int id;
353     int len;
354 {
355     u_char msglen;
356     char *msg;
357 
358     UPAPDEBUG((LOG_INFO, "upap_rauthack: Rcvd id %d.", id));
359     if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
360 	return;
361 
362     /*
363      * Parse message.
364      */
365     if (len < sizeof (u_char)) {
366 	UPAPDEBUG((LOG_INFO, "upap_rauthack: rcvd short packet."));
367 	return;
368     }
369     GETCHAR(msglen, inp);
370     len -= sizeof (u_char);
371     if (len < msglen) {
372 	UPAPDEBUG((LOG_INFO, "upap_rauthack: rcvd short packet."));
373 	return;
374     }
375     msg = (char *) inp;
376     PRINTMSG(msg, msglen);
377 
378     u->us_clientstate = UPAPCS_OPEN;
379 
380     auth_withpeer_success(u->us_unit, UPAP);
381 }
382 
383 
384 /*
385  * upap_rauthnak - Receive Authenticate-Nakk.
386  */
387 static void
upap_rauthnak(u,inp,id,len)388 upap_rauthnak(u, inp, id, len)
389     upap_state *u;
390     u_char *inp;
391     int id;
392     int len;
393 {
394     u_char msglen;
395     char *msg;
396 
397     UPAPDEBUG((LOG_INFO, "upap_rauthnak: Rcvd id %d.", id));
398     if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
399 	return;
400 
401     /*
402      * Parse message.
403      */
404     if (len < sizeof (u_char)) {
405 	UPAPDEBUG((LOG_INFO, "upap_rauthnak: rcvd short packet."));
406 	return;
407     }
408     GETCHAR(msglen, inp);
409     len -= sizeof (u_char);
410     if (len < msglen) {
411 	UPAPDEBUG((LOG_INFO, "upap_rauthnak: rcvd short packet."));
412 	return;
413     }
414     msg = (char *) inp;
415     PRINTMSG(msg, msglen);
416 
417     u->us_clientstate = UPAPCS_BADAUTH;
418 
419     syslog(LOG_ERR, "PAP authentication failed");
420     auth_withpeer_fail(u->us_unit, UPAP);
421 }
422 
423 
424 /*
425  * upap_sauthreq - Send an Authenticate-Request.
426  */
427 static void
upap_sauthreq(u)428 upap_sauthreq(u)
429     upap_state *u;
430 {
431     u_char *outp;
432     int outlen;
433 
434     outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) +
435 	u->us_userlen + u->us_passwdlen;
436     outp = outpacket_buf;
437 
438     MAKEHEADER(outp, UPAP);
439 
440     PUTCHAR(UPAP_AUTHREQ, outp);
441     PUTCHAR(++u->us_id, outp);
442     PUTSHORT(outlen, outp);
443     PUTCHAR(u->us_userlen, outp);
444     BCOPY(u->us_user, outp, u->us_userlen);
445     INCPTR(u->us_userlen, outp);
446     PUTCHAR(u->us_passwdlen, outp);
447     BCOPY(u->us_passwd, outp, u->us_passwdlen);
448 
449     output(u->us_unit, outpacket_buf, outlen + DLLHEADERLEN);
450 
451     UPAPDEBUG((LOG_INFO, "upap_sauth: Sent id %d.", u->us_id));
452 
453     TIMEOUT(upap_timeout, (caddr_t) u, u->us_timeouttime);
454     ++u->us_transmits;
455     u->us_clientstate = UPAPCS_AUTHREQ;
456 }
457 
458 
459 /*
460  * upap_sresp - Send a response (ack or nak).
461  */
462 static void
upap_sresp(u,code,id,msg,msglen)463 upap_sresp(u, code, id, msg, msglen)
464     upap_state *u;
465     u_char code, id;
466     char *msg;
467     int msglen;
468 {
469     u_char *outp;
470     int outlen;
471 
472     outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
473     outp = outpacket_buf;
474     MAKEHEADER(outp, UPAP);
475 
476     PUTCHAR(code, outp);
477     PUTCHAR(id, outp);
478     PUTSHORT(outlen, outp);
479     PUTCHAR(msglen, outp);
480     BCOPY(msg, outp, msglen);
481     output(u->us_unit, outpacket_buf, outlen + DLLHEADERLEN);
482 
483     UPAPDEBUG((LOG_INFO, "upap_sresp: Sent code %d, id %d.", code, id));
484 }
485 
486 /*
487  * upap_printpkt - print the contents of a PAP packet.
488  */
489 char *upap_codenames[] = {
490     "AuthReq", "AuthAck", "AuthNak"
491 };
492 
493 int
upap_printpkt(p,plen,printer,arg)494 upap_printpkt(p, plen, printer, arg)
495     u_char *p;
496     int plen;
497     void (*printer) __ARGS((void *, char *, ...));
498     void *arg;
499 {
500     int code, id, len;
501     int mlen, ulen, wlen;
502     char *user, *pwd, *msg;
503     u_char *pstart;
504 
505     if (plen < UPAP_HEADERLEN)
506 	return 0;
507     pstart = p;
508     GETCHAR(code, p);
509     GETCHAR(id, p);
510     GETSHORT(len, p);
511     if (len < UPAP_HEADERLEN || len > plen)
512 	return 0;
513 
514     if (code >= 1 && code <= sizeof(upap_codenames) / sizeof(char *))
515 	printer(arg, " %s", upap_codenames[code-1]);
516     else
517 	printer(arg, " code=0x%x", code);
518     printer(arg, " id=0x%x", id);
519     len -= UPAP_HEADERLEN;
520     switch (code) {
521     case UPAP_AUTHREQ:
522 	if (len < 1)
523 	    break;
524 	ulen = p[0];
525 	if (len < ulen + 2)
526 	    break;
527 	wlen = p[ulen + 1];
528 	if (len < ulen + wlen + 2)
529 	    break;
530 	user = (char *) (p + 1);
531 	pwd = (char *) (p + ulen + 2);
532 	p += ulen + wlen + 2;
533 	len -= ulen + wlen + 2;
534 	printer(arg, " user=");
535 	print_string(user, ulen, printer, arg);
536 	printer(arg, " password=");
537 	print_string(pwd, wlen, printer, arg);
538 	break;
539     case UPAP_AUTHACK:
540     case UPAP_AUTHNAK:
541 	if (len < 1)
542 	    break;
543 	mlen = p[0];
544 	if (len < mlen + 1)
545 	    break;
546 	msg = (char *) (p + 1);
547 	p += mlen + 1;
548 	len -= mlen + 1;
549 	printer(arg, "msg=");
550 	print_string(msg, mlen, printer, arg);
551 	break;
552     }
553 
554     /* print the rest of the bytes in the packet */
555     for (; len > 0; --len) {
556 	GETCHAR(code, p);
557 	printer(arg, " %.2x", code);
558     }
559 
560     return p - pstart;
561 }
562