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