]> git.ozlabs.org Git - ppp.git/blob - pppd/upap.c
added hide-password option
[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.13 1999/03/02 05:29:39 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 static bool hide_password;
38
39 /*
40  * Command-line options.
41  */
42 static option_t pap_option_list[] = {
43     { "hide-password", o_bool, &hide_password,
44       "Don't output passwords to log" },
45     { "pap-restart", o_int, &upap[0].us_timeouttime,
46       "Set retransmit timeout for PAP" },
47     { "pap-max-authreq", o_int, &upap[0].us_maxtransmits,
48       "Set max number of transmissions for auth-reqs" },
49     { "pap-timeout", o_int, &upap[0].us_reqtimeout,
50       "Set time limit for peer PAP authentication" },
51     { NULL }
52 };
53
54 /*
55  * Protocol entry points.
56  */
57 static void upap_init __P((int));
58 static void upap_lowerup __P((int));
59 static void upap_lowerdown __P((int));
60 static void upap_input __P((int, u_char *, int));
61 static void upap_protrej __P((int));
62 static int  upap_printpkt __P((u_char *, int,
63                                void (*) __P((void *, char *, ...)), void *));
64
65 struct protent pap_protent = {
66     PPP_PAP,
67     upap_init,
68     upap_input,
69     upap_protrej,
70     upap_lowerup,
71     upap_lowerdown,
72     NULL,
73     NULL,
74     upap_printpkt,
75     NULL,
76     1,
77     "PAP",
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         syslog(LOG_ERR, "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         syslog(LOG_ERR, "PAP authentication failed due to protocol-reject");
274         auth_withpeer_fail(unit, PPP_PAP);
275     }
276     if (u->us_serverstate == UPAPSS_LISTEN) {
277         syslog(LOG_ERR, "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((LOG_INFO, "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((LOG_INFO, "pap_input: rcvd illegal length."));
312         return;
313     }
314     if (len > l) {
315         UPAPDEBUG((LOG_INFO, "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     UPAPDEBUG((LOG_INFO, "pap_rauth: Rcvd id %d.", id));
359
360     if (u->us_serverstate < UPAPSS_LISTEN)
361         return;
362
363     /*
364      * If we receive a duplicate authenticate-request, we are
365      * supposed to return the same status as for the first request.
366      */
367     if (u->us_serverstate == UPAPSS_OPEN) {
368         upap_sresp(u, UPAP_AUTHACK, id, "", 0); /* return auth-ack */
369         return;
370     }
371     if (u->us_serverstate == UPAPSS_BADAUTH) {
372         upap_sresp(u, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */
373         return;
374     }
375
376     /*
377      * Parse user/passwd.
378      */
379     if (len < sizeof (u_char)) {
380         UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet."));
381         return;
382     }
383     GETCHAR(ruserlen, inp);
384     len -= sizeof (u_char) + ruserlen + sizeof (u_char);
385     if (len < 0) {
386         UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet."));
387         return;
388     }
389     ruser = (char *) inp;
390     INCPTR(ruserlen, inp);
391     GETCHAR(rpasswdlen, inp);
392     if (len < rpasswdlen) {
393         UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet."));
394         return;
395     }
396     rpasswd = (char *) inp;
397
398     /*
399      * Check the username and password given.
400      */
401     retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
402                            rpasswdlen, &msg, &msglen);
403     BZERO(rpasswd, rpasswdlen);
404
405     upap_sresp(u, retcode, id, msg, msglen);
406
407     if (retcode == UPAP_AUTHACK) {
408         u->us_serverstate = UPAPSS_OPEN;
409         auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen);
410     } else {
411         u->us_serverstate = UPAPSS_BADAUTH;
412         auth_peer_fail(u->us_unit, PPP_PAP);
413     }
414
415     if (u->us_reqtimeout > 0)
416         UNTIMEOUT(upap_reqtimeout, u);
417 }
418
419
420 /*
421  * upap_rauthack - Receive Authenticate-Ack.
422  */
423 static void
424 upap_rauthack(u, inp, id, len)
425     upap_state *u;
426     u_char *inp;
427     int id;
428     int len;
429 {
430     u_char msglen;
431     char *msg;
432
433     UPAPDEBUG((LOG_INFO, "pap_rauthack: Rcvd id %d.", id));
434     if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
435         return;
436
437     /*
438      * Parse message.
439      */
440     if (len < sizeof (u_char)) {
441         UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet."));
442         return;
443     }
444     GETCHAR(msglen, inp);
445     len -= sizeof (u_char);
446     if (len < msglen) {
447         UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet."));
448         return;
449     }
450     msg = (char *) inp;
451     PRINTMSG(msg, msglen);
452
453     u->us_clientstate = UPAPCS_OPEN;
454
455     auth_withpeer_success(u->us_unit, PPP_PAP);
456 }
457
458
459 /*
460  * upap_rauthnak - Receive Authenticate-Nakk.
461  */
462 static void
463 upap_rauthnak(u, inp, id, len)
464     upap_state *u;
465     u_char *inp;
466     int id;
467     int len;
468 {
469     u_char msglen;
470     char *msg;
471
472     UPAPDEBUG((LOG_INFO, "pap_rauthnak: Rcvd id %d.", id));
473     if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
474         return;
475
476     /*
477      * Parse message.
478      */
479     if (len < sizeof (u_char)) {
480         UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet."));
481         return;
482     }
483     GETCHAR(msglen, inp);
484     len -= sizeof (u_char);
485     if (len < msglen) {
486         UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet."));
487         return;
488     }
489     msg = (char *) inp;
490     PRINTMSG(msg, msglen);
491
492     u->us_clientstate = UPAPCS_BADAUTH;
493
494     syslog(LOG_ERR, "PAP authentication failed");
495     auth_withpeer_fail(u->us_unit, PPP_PAP);
496 }
497
498
499 /*
500  * upap_sauthreq - Send an Authenticate-Request.
501  */
502 static void
503 upap_sauthreq(u)
504     upap_state *u;
505 {
506     u_char *outp;
507     int outlen;
508
509     outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) +
510         u->us_userlen + u->us_passwdlen;
511     outp = outpacket_buf;
512     
513     MAKEHEADER(outp, PPP_PAP);
514
515     PUTCHAR(UPAP_AUTHREQ, outp);
516     PUTCHAR(++u->us_id, outp);
517     PUTSHORT(outlen, outp);
518     PUTCHAR(u->us_userlen, outp);
519     BCOPY(u->us_user, outp, u->us_userlen);
520     INCPTR(u->us_userlen, outp);
521     PUTCHAR(u->us_passwdlen, outp);
522     BCOPY(u->us_passwd, outp, u->us_passwdlen);
523
524     output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
525
526     UPAPDEBUG((LOG_INFO, "pap_sauth: Sent id %d.", u->us_id));
527
528     TIMEOUT(upap_timeout, u, u->us_timeouttime);
529     ++u->us_transmits;
530     u->us_clientstate = UPAPCS_AUTHREQ;
531 }
532
533
534 /*
535  * upap_sresp - Send a response (ack or nak).
536  */
537 static void
538 upap_sresp(u, code, id, msg, msglen)
539     upap_state *u;
540     u_char code, id;
541     char *msg;
542     int msglen;
543 {
544     u_char *outp;
545     int outlen;
546
547     outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
548     outp = outpacket_buf;
549     MAKEHEADER(outp, PPP_PAP);
550
551     PUTCHAR(code, outp);
552     PUTCHAR(id, outp);
553     PUTSHORT(outlen, outp);
554     PUTCHAR(msglen, outp);
555     BCOPY(msg, outp, msglen);
556     output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
557
558     UPAPDEBUG((LOG_INFO, "pap_sresp: Sent code %d, id %d.", code, id));
559 }
560
561 /*
562  * upap_printpkt - print the contents of a PAP packet.
563  */
564 static char *upap_codenames[] = {
565     "AuthReq", "AuthAck", "AuthNak"
566 };
567
568 static int
569 upap_printpkt(p, plen, printer, arg)
570     u_char *p;
571     int plen;
572     void (*printer) __P((void *, char *, ...));
573     void *arg;
574 {
575     int code, id, len;
576     int mlen, ulen, wlen;
577     char *user, *pwd, *msg;
578     u_char *pstart;
579
580     if (plen < UPAP_HEADERLEN)
581         return 0;
582     pstart = p;
583     GETCHAR(code, p);
584     GETCHAR(id, p);
585     GETSHORT(len, p);
586     if (len < UPAP_HEADERLEN || len > plen)
587         return 0;
588
589     if (code >= 1 && code <= sizeof(upap_codenames) / sizeof(char *))
590         printer(arg, " %s", upap_codenames[code-1]);
591     else
592         printer(arg, " code=0x%x", code);
593     printer(arg, " id=0x%x", id);
594     len -= UPAP_HEADERLEN;
595     switch (code) {
596     case UPAP_AUTHREQ:
597         if (len < 1)
598             break;
599         ulen = p[0];
600         if (len < ulen + 2)
601             break;
602         wlen = p[ulen + 1];
603         if (len < ulen + wlen + 2)
604             break;
605         user = (char *) (p + 1);
606         pwd = (char *) (p + ulen + 2);
607         p += ulen + wlen + 2;
608         len -= ulen + wlen + 2;
609         printer(arg, " user=");
610         print_string(user, ulen, printer, arg);
611         printer(arg, " password=");
612         if (!hide_password)
613             print_string(pwd, wlen, printer, arg);
614         else
615             printer(arg, "<hidden>");
616         break;
617     case UPAP_AUTHACK:
618     case UPAP_AUTHNAK:
619         if (len < 1)
620             break;
621         mlen = p[0];
622         if (len < mlen + 1)
623             break;
624         msg = (char *) (p + 1);
625         p += mlen + 1;
626         len -= mlen + 1;
627         printer(arg, " ");
628         print_string(msg, mlen, printer, arg);
629         break;
630     }
631
632     /* print the rest of the bytes in the packet */
633     for (; len > 0; --len) {
634         GETCHAR(code, p);
635         printer(arg, " %.2x", code);
636     }
637
638     return p - pstart;
639 }