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