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