1 /*
2 * upap.c - User/Password Authentication Protocol.
3 *
4 * Copyright (c) 2000 by Sun Microsystems, Inc.
5 * All rights reserved.
6 *
7 * Permission to use, copy, modify, and distribute this software and its
8 * documentation is hereby granted, provided that the above copyright
9 * notice appears in all copies.
10 *
11 * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
12 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
13 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
14 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
15 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
16 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
17 *
18 * Copyright (c) 1989 Carnegie Mellon University.
19 * All rights reserved.
20 *
21 * Redistribution and use in source and binary forms are permitted
22 * provided that the above copyright notice and this paragraph are
23 * duplicated in all such forms and that any documentation,
24 * advertising materials, and other materials related to such
25 * distribution and use acknowledge that the software was developed
26 * by Carnegie Mellon University. The name of the
27 * University may not be used to endorse or promote products derived
28 * from this software without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
30 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
31 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32 */
33
34 #include <stdio.h>
35 #include <string.h>
36
37 #include "pppd.h"
38 #include "upap.h"
39
40 static bool hide_password = 1;
41
42 /*
43 * Command-line options.
44 */
45 static option_t pap_option_list[] = {
46 { "hide-password", o_bool, &hide_password,
47 "Don't output passwords to log", 1 },
48 { "show-password", o_bool, &hide_password,
49 "Show password string in debug log messages", 0 },
50 { "pap-restart", o_int, &upap[0].us_timeouttime,
51 "Set retransmit timeout for PAP" },
52 { "pap-max-authreq", o_int, &upap[0].us_maxtransmits,
53 "Max number of PAP Authenticate-Request sent" },
54 { "pap-max-receive", o_int, &upap[0].us_maxreceives,
55 "Max allowable PAP Authenticate-Request received" },
56 { "pap-timeout", o_int, &upap[0].us_reqtimeout,
57 "Set time limit for peer PAP authentication" },
58 { NULL }
59 };
60
61 /*
62 * Protocol entry points.
63 */
64 static void upap_init __P((int));
65 static void upap_lowerup __P((int));
66 static void upap_lowerdown __P((int));
67 static void upap_input __P((int, u_char *, int));
68 static void upap_protrej __P((int));
69 static int upap_printpkt __P((u_char *, int,
70 void (*) __P((void *, const char *, ...)), void *));
71
72 struct protent pap_protent = {
73 PPP_PAP,
74 upap_init,
75 upap_input,
76 upap_protrej,
77 upap_lowerup,
78 upap_lowerdown,
79 NULL,
80 NULL,
81 upap_printpkt,
82 NULL,
83 1,
84 "PAP",
85 NULL,
86 pap_option_list,
87 NULL,
88 NULL,
89 NULL
90 };
91
92 upap_state upap[NUM_PPP]; /* UPAP state; one for each unit */
93
94 static void upap_timeout __P((void *));
95 static void upap_reqtimeout __P((void *));
96 static void upap_rauthreq __P((upap_state *, u_char *, int, int));
97 static void upap_rauthack __P((upap_state *, u_char *, int, int));
98 static void upap_rauthnak __P((upap_state *, u_char *, int, int));
99 static void upap_sauthreq __P((upap_state *));
100 static void upap_sresp __P((upap_state *, int, int, char *, int));
101
102 static const char *
pap_cstate(clientstate)103 pap_cstate(clientstate)
104 int clientstate;
105 {
106 static const char *cstate[] = { UPAPCS__NAMES };
107 static char buf[32];
108
109 if (clientstate < 0 || clientstate >= Dim(cstate)) {
110 (void) slprintf(buf, sizeof (buf), "Cli#%d", clientstate);
111 return ((const char *)buf);
112 }
113 return (cstate[clientstate]);
114 }
115
116 static const char *
pap_sstate(serverstate)117 pap_sstate(serverstate)
118 int serverstate;
119 {
120 static const char *sstate[] = { UPAPSS__NAMES };
121 static char buf[32];
122
123 if (serverstate < 0 || serverstate >= Dim(sstate)) {
124 (void) slprintf(buf, sizeof (buf), "Srv#%d", serverstate);
125 return ((const char *)buf);
126 }
127 return (sstate[serverstate]);
128 }
129
130 /*
131 * upap_init - Initialize a UPAP unit.
132 */
133 static void
upap_init(unit)134 upap_init(unit)
135 int unit;
136 {
137 upap_state *u = &upap[unit];
138
139 u->us_unit = unit;
140 u->us_user = NULL;
141 u->us_userlen = 0;
142 u->us_passwd = NULL;
143 u->us_clientstate = UPAPCS_INITIAL;
144 u->us_serverstate = UPAPSS_INITIAL;
145 u->us_id = 0;
146 u->us_timeouttime = UPAP_DEFTIMEOUT;
147 u->us_maxtransmits = 10;
148 u->us_reqtimeout = UPAP_DEFREQTIME;
149 u->us_maxreceives = 3;
150 u->us_msg = "";
151 u->us_msglen = 0;
152 }
153
154
155 /*
156 * upap_authwithpeer - Authenticate us with our peer (start client).
157 *
158 * Set new state and send authenticate's.
159 */
160 void
upap_authwithpeer(unit,user,password)161 upap_authwithpeer(unit, user, password)
162 int unit;
163 char *user, *password;
164 {
165 upap_state *u = &upap[unit];
166
167 /* Save the username and password we're given */
168 u->us_user = user;
169 u->us_userlen = strlen(user);
170 u->us_passwd = password;
171 u->us_transmits = 0;
172
173 /* Lower layer up yet? */
174 if (u->us_clientstate == UPAPCS_INITIAL ||
175 u->us_clientstate == UPAPCS_PENDING) {
176 u->us_clientstate = UPAPCS_PENDING;
177 return;
178 }
179
180 upap_sauthreq(u); /* Start protocol */
181 }
182
183
184 /*
185 * upap_authpeer - Authenticate our peer (start server).
186 *
187 * Set new state.
188 */
189 void
upap_authpeer(unit)190 upap_authpeer(unit)
191 int unit;
192 {
193 upap_state *u = &upap[unit];
194
195 /* Lower layer up yet? */
196 if (u->us_serverstate == UPAPSS_INITIAL ||
197 u->us_serverstate == UPAPSS_PENDING) {
198 u->us_serverstate = UPAPSS_PENDING;
199 return;
200 }
201
202 u->us_serverstate = UPAPSS_LISTEN;
203 u->us_receives = 0;
204 if (u->us_reqtimeout > 0)
205 TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
206 }
207
208
209 /*
210 * upap_timeout - Retransmission timer for sending auth-reqs expired.
211 */
212 static void
upap_timeout(arg)213 upap_timeout(arg)
214 void *arg;
215 {
216 upap_state *u = (upap_state *) arg;
217
218 if (u->us_clientstate != UPAPCS_AUTHREQ)
219 return;
220
221 if (u->us_transmits >= u->us_maxtransmits) {
222 /* give up in disgust */
223 error("No response to %d PAP Authenticate-Requests", u->us_transmits);
224 u->us_clientstate = UPAPCS_BADAUTH;
225 auth_withpeer_fail(u->us_unit, PPP_PAP);
226 return;
227 }
228
229 upap_sauthreq(u); /* Send Authenticate-Request */
230 }
231
232
233 /*
234 * upap_reqtimeout - Give up waiting for the peer to send a valid auth-req.
235 */
236 static void
upap_reqtimeout(arg)237 upap_reqtimeout(arg)
238 void *arg;
239 {
240 upap_state *u = (upap_state *) arg;
241
242 if (u->us_serverstate != UPAPSS_LISTEN)
243 return; /* huh?? */
244
245 auth_peer_fail(u->us_unit, PPP_PAP);
246 u->us_serverstate = UPAPSS_BADAUTH;
247 }
248
249
250 /*
251 * upap_lowerup - The lower layer is up.
252 *
253 * Start authenticating if pending.
254 */
255 static void
upap_lowerup(unit)256 upap_lowerup(unit)
257 int unit;
258 {
259 upap_state *u = &upap[unit];
260
261 if (u->us_clientstate == UPAPCS_INITIAL)
262 u->us_clientstate = UPAPCS_CLOSED;
263 else if (u->us_clientstate == UPAPCS_PENDING) {
264 upap_sauthreq(u); /* send an auth-request */
265 }
266
267 if (u->us_serverstate == UPAPSS_INITIAL)
268 u->us_serverstate = UPAPSS_CLOSED;
269 else if (u->us_serverstate == UPAPSS_PENDING) {
270 u->us_serverstate = UPAPSS_LISTEN;
271 if (u->us_reqtimeout > 0)
272 TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
273 }
274 }
275
276
277 /*
278 * upap_lowerdown - The lower layer is down.
279 *
280 * Cancel all timeouts.
281 */
282 static void
upap_lowerdown(unit)283 upap_lowerdown(unit)
284 int unit;
285 {
286 upap_state *u = &upap[unit];
287
288 /* Cancel timeouts */
289 if (u->us_clientstate == UPAPCS_AUTHREQ && u->us_timeouttime > 0)
290 UNTIMEOUT(upap_timeout, u);
291 if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0)
292 UNTIMEOUT(upap_reqtimeout, u);
293
294 u->us_clientstate = UPAPCS_INITIAL;
295 u->us_serverstate = UPAPSS_INITIAL;
296 }
297
298
299 /*
300 * upap_protrej - Peer doesn't speak this protocol.
301 *
302 * This shouldn't happen. In any case, pretend lower layer went down.
303 */
304 static void
upap_protrej(unit)305 upap_protrej(unit)
306 int unit;
307 {
308 upap_state *u = &upap[unit];
309
310 if (u->us_clientstate == UPAPCS_AUTHREQ) {
311 error("PAP authentication failed due to protocol-reject");
312 auth_withpeer_fail(unit, PPP_PAP);
313 }
314 if (u->us_serverstate == UPAPSS_LISTEN) {
315 error("PAP authentication of peer failed (protocol-reject)");
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
upap_input(unit,inpacket,l)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 error("PAP: packet is too small (%d < %d)", l, UPAP_HEADERLEN);
343 return;
344 }
345 GETCHAR(code, inp);
346 GETCHAR(id, inp);
347 GETSHORT(len, inp);
348 if ((len < UPAP_HEADERLEN) || (len > l)) {
349 error("PAP: packet has illegal length %d (%d..%d)", len,
350 UPAP_HEADERLEN, l);
351 return;
352 }
353 len -= UPAP_HEADERLEN;
354
355 /*
356 * Action depends on code.
357 */
358 switch (code) {
359 case UPAP_AUTHREQ:
360 upap_rauthreq(u, inp, id, len);
361 break;
362
363 case UPAP_AUTHACK:
364 upap_rauthack(u, inp, id, len);
365 break;
366
367 case UPAP_AUTHNAK:
368 upap_rauthnak(u, inp, id, len);
369 break;
370
371 default:
372 warn("Unknown PAP code (%d) received.", code);
373 break;
374 }
375 }
376
377
378 /*
379 * upap_rauth - Receive Authenticate.
380 */
381 static void
upap_rauthreq(u,inp,id,len)382 upap_rauthreq(u, inp, id, len)
383 upap_state *u;
384 u_char *inp;
385 int id;
386 int len;
387 {
388 u_char ruserlen, rpasswdlen;
389 char *ruser, *rpasswd;
390 int retcode;
391 char *msg;
392 int msglen;
393
394 if (u->us_serverstate < UPAPSS_LISTEN) {
395 info("PAP: discarded Authenticate-Request in state %s",
396 pap_sstate(u->us_serverstate));
397 return;
398 }
399
400 /*
401 * If we receive a duplicate authenticate-request, we are
402 * supposed to return the same status as for the first request.
403 */
404 if (u->us_serverstate == UPAPSS_OPEN) {
405 /* return auth-ack */
406 upap_sresp(u, UPAP_AUTHACK, id, u->us_msg, u->us_msglen);
407 return;
408 }
409 if (u->us_serverstate == UPAPSS_BADAUTH) {
410 /* return auth-nak */
411 upap_sresp(u, UPAP_AUTHNAK, id, u->us_msg, u->us_msglen);
412 return;
413 }
414
415 /*
416 * Parse user/passwd.
417 */
418 if (len < 1) {
419 error("PAP: rcvd short packet; no data");
420 return;
421 }
422 GETCHAR(ruserlen, inp);
423 len -= sizeof (u_char) + ruserlen + sizeof (u_char);
424 if (len < 0) {
425 error("PAP: rcvd short packet; peer name missing");
426 return;
427 }
428 ruser = (char *) inp;
429 INCPTR(ruserlen, inp);
430 GETCHAR(rpasswdlen, inp);
431 if (len < rpasswdlen) {
432 error("PAP: rcvd short packet; pass len %d < %d", len, rpasswdlen);
433 return;
434 }
435 rpasswd = (char *) inp;
436
437 /*
438 * Check the username and password given.
439 */
440 retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
441 rpasswdlen, &msg);
442 BZERO(rpasswd, rpasswdlen);
443 msglen = strlen(msg);
444 if (msglen > 255)
445 msglen = 255;
446
447 u->us_msg = msg;
448 u->us_msglen = msglen;
449 upap_sresp(u, retcode, id, u->us_msg, u->us_msglen);
450
451 if (retcode == UPAP_AUTHACK) {
452 u->us_serverstate = UPAPSS_OPEN;
453 auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen);
454 } else if (++u->us_receives >= u->us_maxreceives) {
455 u->us_serverstate = UPAPSS_BADAUTH;
456 auth_peer_fail(u->us_unit, PPP_PAP);
457 } else {
458 /* Just wait for a good one to arrive, or for time-out. */
459 return;
460 }
461
462 if (u->us_reqtimeout > 0)
463 UNTIMEOUT(upap_reqtimeout, u);
464 }
465
466
467 /*
468 * upap_rauthack - Receive Authenticate-Ack.
469 */
470 /*ARGSUSED*/
471 static void
upap_rauthack(u,inp,id,len)472 upap_rauthack(u, inp, id, len)
473 upap_state *u;
474 u_char *inp;
475 int id;
476 int len;
477 {
478 u_char msglen;
479 char *msg;
480
481 if (u->us_clientstate != UPAPCS_AUTHREQ) {
482 info("PAP: discarded Authenticate-Ack in state %s",
483 pap_cstate(u->us_clientstate));
484 return;
485 }
486
487 if (id != u->us_id) {
488 dbglog("PAP: discard Authenticate-Ack; ID %d != %d",
489 id, u->us_id);
490 return;
491 }
492
493 if (u->us_timeouttime > 0)
494 UNTIMEOUT(upap_timeout, u);
495
496 /*
497 * Parse message.
498 */
499 if (len < 1) {
500 info("PAP: Ignoring missing ack msg-length octet");
501 } else {
502 GETCHAR(msglen, inp);
503 if (msglen > 0) {
504 len -= sizeof (u_char);
505 if (len < msglen) {
506 error("PAP: Discarding short packet (%d < %d)", len, msglen);
507 return;
508 }
509 msg = (char *) inp;
510 PRINTMSG(msg, msglen);
511 }
512 }
513
514 u->us_clientstate = UPAPCS_OPEN;
515
516 auth_withpeer_success(u->us_unit, PPP_PAP);
517 }
518
519
520 /*
521 * upap_rauthnak - Receive Authenticate-Nakk.
522 */
523 /*ARGSUSED*/
524 static void
upap_rauthnak(u,inp,id,len)525 upap_rauthnak(u, inp, id, len)
526 upap_state *u;
527 u_char *inp;
528 int id;
529 int len;
530 {
531 u_char msglen;
532 char *msg;
533
534 if (u->us_clientstate != UPAPCS_AUTHREQ) {
535 info("PAP: discarded Authenticate-Nak in state %s",
536 pap_cstate(u->us_clientstate));
537 return;
538 }
539
540 if (id != u->us_id) {
541 dbglog("PAP: discard Authenticate-Ack; ID %d != %d",
542 id, u->us_id);
543 return;
544 }
545
546 if (u->us_timeouttime > 0)
547 UNTIMEOUT(upap_timeout, u);
548
549 /*
550 * Parse message.
551 */
552 if (len < 1) {
553 error("PAP: ignoring missing nak msg-length octet");
554 } else {
555 GETCHAR(msglen, inp);
556 if (msglen > 0) {
557 len -= sizeof (u_char);
558 if (len < msglen) {
559 error("PAP: Discarding short packet (%d < %d)", len, msglen);
560 return;
561 }
562 msg = (char *) inp;
563 PRINTMSG(msg, msglen);
564 }
565 }
566
567 /* Try to get a new password from the plugin. */
568 if (pap_passwd_hook != NULL) {
569 if (u->us_transmits < u->us_maxtransmits) {
570 if ((*pap_passwd_hook)(user, passwd) >= 0) {
571 upap_sauthreq(u);
572 return;
573 }
574 } else {
575 /* Tell plug-in that we're giving up. */
576 (void) (*pap_passwd_hook)(NULL, NULL);
577 }
578 }
579
580 u->us_clientstate = UPAPCS_BADAUTH;
581
582 error("PAP authentication failed");
583 auth_withpeer_fail(u->us_unit, PPP_PAP);
584 }
585
586
587 /*
588 * upap_sauthreq - Send an Authenticate-Request.
589 */
590 static void
upap_sauthreq(u)591 upap_sauthreq(u)
592 upap_state *u;
593 {
594 u_char *outp;
595 int pwlen;
596 int outlen;
597
598 pwlen = strllen(passwd, MAXSECRETLEN);
599 if (pwlen > 0xFF)
600 pwlen = 0xFF;
601 outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) + u->us_userlen + pwlen;
602 outp = outpacket_buf;
603
604 MAKEHEADER(outp, PPP_PAP);
605
606 PUTCHAR(UPAP_AUTHREQ, outp);
607 PUTCHAR(++u->us_id, outp);
608 PUTSHORT(outlen, outp);
609 PUTCHAR(u->us_userlen, outp);
610 BCOPY(u->us_user, outp, u->us_userlen);
611 INCPTR(u->us_userlen, outp);
612 PUTCHAR(pwlen, outp);
613 BCOPY(u->us_passwd, outp, pwlen);
614
615 output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
616
617 if (u->us_timeouttime > 0)
618 TIMEOUT(upap_timeout, u, u->us_timeouttime);
619 ++u->us_transmits;
620 u->us_clientstate = UPAPCS_AUTHREQ;
621 }
622
623
624 /*
625 * upap_sresp - Send a response (ack or nak).
626 */
627 static void
upap_sresp(u,code,id,msg,msglen)628 upap_sresp(u, code, id, msg, msglen)
629 upap_state *u;
630 u_char code, id;
631 char *msg;
632 int msglen;
633 {
634 u_char *outp;
635 int outlen;
636
637 outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
638 outp = outpacket_buf;
639 MAKEHEADER(outp, PPP_PAP);
640
641 PUTCHAR(code, outp);
642 PUTCHAR(id, outp);
643 PUTSHORT(outlen, outp);
644 PUTCHAR(msglen, outp);
645 BCOPY(msg, outp, msglen);
646 output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
647 }
648
649 /*
650 * upap_printpkt - print the contents of a PAP packet.
651 */
652 static char *upap_codenames[] = {
653 "AuthReq", "AuthAck", "AuthNak"
654 };
655
656 static int
upap_printpkt(p,plen,printer,arg)657 upap_printpkt(p, plen, printer, arg)
658 u_char *p;
659 int plen;
660 void (*printer) __P((void *, const char *, ...));
661 void *arg;
662 {
663 int code, id, len;
664 int mlen, ulen, wlen;
665 char *user, *pwd, *msg;
666 u_char *pstart;
667
668 if (plen < UPAP_HEADERLEN)
669 return (0);
670 pstart = p;
671 GETCHAR(code, p);
672 GETCHAR(id, p);
673 GETSHORT(len, p);
674 if (len < UPAP_HEADERLEN || len > plen)
675 return (0);
676
677 if (code >= 1 && code <= Dim(upap_codenames))
678 printer(arg, " %s", upap_codenames[code-1]);
679 else
680 printer(arg, " code=0x%x", code);
681 printer(arg, " id=0x%x", id);
682 len -= UPAP_HEADERLEN;
683 switch (code) {
684 case UPAP_AUTHREQ:
685 if (len < 1)
686 break;
687 ulen = p[0];
688 if (len < ulen + 2)
689 break;
690 wlen = p[ulen + 1];
691 if (len < ulen + wlen + 2)
692 break;
693 user = (char *) (p + 1);
694 pwd = (char *) (p + ulen + 2);
695 p += ulen + wlen + 2;
696 len -= ulen + wlen + 2;
697 printer(arg, " user=");
698 print_string(user, ulen, printer, arg);
699 printer(arg, " password=");
700 if (!hide_password)
701 print_string(pwd, wlen, printer, arg);
702 else
703 printer(arg, "<hidden>");
704 break;
705 case UPAP_AUTHACK:
706 case UPAP_AUTHNAK:
707 if (len < 1)
708 break;
709 mlen = p[0];
710 if (len < mlen + 1)
711 break;
712 msg = (char *) (p + 1);
713 p += mlen + 1;
714 len -= mlen + 1;
715 printer(arg, " ");
716 print_string(msg, mlen, printer, arg);
717 break;
718 }
719
720 /* print the rest of the bytes in the packet */
721 for (; len > 0; --len) {
722 GETCHAR(code, p);
723 printer(arg, " %.2x", code);
724 }
725
726 return (p - pstart);
727 }
728