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