d5ad3eee541df39a56639f37e46eb876a6809d1b
[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.4 1994/10/22 11:54:04 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[N_PPP];         /* UPAP state; one for each unit */
39
40
41 static void upap_timeout __P((caddr_t));
42 static void upap_rauthreq __P((upap_state *, u_char *, int, int));
43 static void upap_rauthack __P((upap_state *, u_char *, int, int));
44 static void upap_rauthnak __P((upap_state *, u_char *, int, int));
45 static void upap_sauthreq __P((upap_state *));
46 static void upap_sresp __P((upap_state *, int, int, char *, int));
47
48
49 /*
50  * upap_init - Initialize a UPAP unit.
51  */
52 void
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
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
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
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, PPP_PAP);
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
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
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
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, PPP_PAP);
204     }
205     if (u->us_serverstate == UPAPSS_LISTEN) {
206         syslog(LOG_ERR, "PAP authentication of peer failed (protocol-reject)");
207         auth_peer_fail(unit, PPP_PAP);
208     }
209     upap_lowerdown(unit);
210 }
211
212
213 /*
214  * upap_input - Input UPAP packet.
215  */
216 void
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
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, PPP_PAP);
338     } else {
339         u->us_serverstate = UPAPSS_BADAUTH;
340         auth_peer_fail(u->us_unit, PPP_PAP);
341     }
342 }
343
344
345 /*
346  * upap_rauthack - Receive Authenticate-Ack.
347  */
348 static void
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, PPP_PAP);
381 }
382
383
384 /*
385  * upap_rauthnak - Receive Authenticate-Nakk.
386  */
387 static void
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, PPP_PAP);
421 }
422
423
424 /*
425  * upap_sauthreq - Send an Authenticate-Request.
426  */
427 static void
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, PPP_PAP);
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 + PPP_HDRLEN);
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
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, PPP_PAP);
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 + PPP_HDRLEN);
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
494 upap_printpkt(p, plen, printer, arg)
495     u_char *p;
496     int plen;
497     void (*printer) __P((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 }