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