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