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