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