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