2 * upap.c - User/Password Authentication Protocol.
4 * Copyright (c) 2000 by Sun Microsystems, Inc.
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.
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
18 * Copyright (c) 1989 Carnegie Mellon University.
19 * All rights reserved.
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.
34 #pragma ident "%Z%%M% %I% %E% SMI"
35 #define RCSID "$Id: upap.c,v 1.23 1999/11/20 05:11:47 paulus Exp $"
43 #if !defined(lint) && !defined(_lint)
44 static const char rcsid
[] = RCSID
;
47 static bool hide_password
= 1;
50 * Command-line options.
52 static option_t pap_option_list
[] = {
53 { "hide-password", o_bool
, &hide_password
,
54 "Don't output passwords to log", 1 },
55 { "show-password", o_bool
, &hide_password
,
56 "Show password string in debug log messages", 0 },
57 { "pap-restart", o_int
, &upap
[0].us_timeouttime
,
58 "Set retransmit timeout for PAP" },
59 { "pap-max-authreq", o_int
, &upap
[0].us_maxtransmits
,
60 "Max number of PAP Authenticate-Request sent" },
61 { "pap-max-receive", o_int
, &upap
[0].us_maxreceives
,
62 "Max allowable PAP Authenticate-Request received" },
63 { "pap-timeout", o_int
, &upap
[0].us_reqtimeout
,
64 "Set time limit for peer PAP authentication" },
69 * Protocol entry points.
71 static void upap_init
__P((int));
72 static void upap_lowerup
__P((int));
73 static void upap_lowerdown
__P((int));
74 static void upap_input
__P((int, u_char
*, int));
75 static void upap_protrej
__P((int));
76 static int upap_printpkt
__P((u_char
*, int,
77 void (*) __P((void *, const char *, ...)), void *));
79 struct protent pap_protent
= {
99 upap_state upap
[NUM_PPP
]; /* UPAP state; one for each unit */
101 static void upap_timeout
__P((void *));
102 static void upap_reqtimeout
__P((void *));
103 static void upap_rauthreq
__P((upap_state
*, u_char
*, int, int));
104 static void upap_rauthack
__P((upap_state
*, u_char
*, int, int));
105 static void upap_rauthnak
__P((upap_state
*, u_char
*, int, int));
106 static void upap_sauthreq
__P((upap_state
*));
107 static void upap_sresp
__P((upap_state
*, int, int, char *, int));
110 pap_cstate(clientstate
)
113 static const char *cstate
[] = { UPAPCS__NAMES
};
116 if (clientstate
< 0 || clientstate
>= Dim(cstate
)) {
117 (void) slprintf(buf
, sizeof (buf
), "Cli#%d", clientstate
);
118 return ((const char *)buf
);
120 return (cstate
[clientstate
]);
124 pap_sstate(serverstate
)
127 static const char *sstate
[] = { UPAPSS__NAMES
};
130 if (serverstate
< 0 || serverstate
>= Dim(sstate
)) {
131 (void) slprintf(buf
, sizeof (buf
), "Srv#%d", serverstate
);
132 return ((const char *)buf
);
134 return (sstate
[serverstate
]);
138 * upap_init - Initialize a UPAP unit.
144 upap_state
*u
= &upap
[unit
];
150 u
->us_clientstate
= UPAPCS_INITIAL
;
151 u
->us_serverstate
= UPAPSS_INITIAL
;
153 u
->us_timeouttime
= UPAP_DEFTIMEOUT
;
154 u
->us_maxtransmits
= 10;
155 u
->us_reqtimeout
= UPAP_DEFREQTIME
;
156 u
->us_maxreceives
= 3;
163 * upap_authwithpeer - Authenticate us with our peer (start client).
165 * Set new state and send authenticate's.
168 upap_authwithpeer(unit
, user
, password
)
170 char *user
, *password
;
172 upap_state
*u
= &upap
[unit
];
174 /* Save the username and password we're given */
176 u
->us_userlen
= strlen(user
);
177 u
->us_passwd
= password
;
180 /* Lower layer up yet? */
181 if (u
->us_clientstate
== UPAPCS_INITIAL
||
182 u
->us_clientstate
== UPAPCS_PENDING
) {
183 u
->us_clientstate
= UPAPCS_PENDING
;
187 upap_sauthreq(u
); /* Start protocol */
192 * upap_authpeer - Authenticate our peer (start server).
200 upap_state
*u
= &upap
[unit
];
202 /* Lower layer up yet? */
203 if (u
->us_serverstate
== UPAPSS_INITIAL
||
204 u
->us_serverstate
== UPAPSS_PENDING
) {
205 u
->us_serverstate
= UPAPSS_PENDING
;
209 u
->us_serverstate
= UPAPSS_LISTEN
;
211 if (u
->us_reqtimeout
> 0)
212 TIMEOUT(upap_reqtimeout
, u
, u
->us_reqtimeout
);
217 * upap_timeout - Retransmission timer for sending auth-reqs expired.
223 upap_state
*u
= (upap_state
*) arg
;
225 if (u
->us_clientstate
!= UPAPCS_AUTHREQ
)
228 if (u
->us_transmits
>= u
->us_maxtransmits
) {
229 /* give up in disgust */
230 error("No response to %d PAP Authenticate-Requests", u
->us_transmits
);
231 u
->us_clientstate
= UPAPCS_BADAUTH
;
232 auth_withpeer_fail(u
->us_unit
, PPP_PAP
);
236 upap_sauthreq(u
); /* Send Authenticate-Request */
241 * upap_reqtimeout - Give up waiting for the peer to send a valid auth-req.
247 upap_state
*u
= (upap_state
*) arg
;
249 if (u
->us_serverstate
!= UPAPSS_LISTEN
)
252 auth_peer_fail(u
->us_unit
, PPP_PAP
);
253 u
->us_serverstate
= UPAPSS_BADAUTH
;
258 * upap_lowerup - The lower layer is up.
260 * Start authenticating if pending.
266 upap_state
*u
= &upap
[unit
];
268 if (u
->us_clientstate
== UPAPCS_INITIAL
)
269 u
->us_clientstate
= UPAPCS_CLOSED
;
270 else if (u
->us_clientstate
== UPAPCS_PENDING
) {
271 upap_sauthreq(u
); /* send an auth-request */
274 if (u
->us_serverstate
== UPAPSS_INITIAL
)
275 u
->us_serverstate
= UPAPSS_CLOSED
;
276 else if (u
->us_serverstate
== UPAPSS_PENDING
) {
277 u
->us_serverstate
= UPAPSS_LISTEN
;
278 if (u
->us_reqtimeout
> 0)
279 TIMEOUT(upap_reqtimeout
, u
, u
->us_reqtimeout
);
285 * upap_lowerdown - The lower layer is down.
287 * Cancel all timeouts.
293 upap_state
*u
= &upap
[unit
];
295 /* Cancel timeouts */
296 if (u
->us_clientstate
== UPAPCS_AUTHREQ
&& u
->us_timeouttime
> 0)
297 UNTIMEOUT(upap_timeout
, u
);
298 if (u
->us_serverstate
== UPAPSS_LISTEN
&& u
->us_reqtimeout
> 0)
299 UNTIMEOUT(upap_reqtimeout
, u
);
301 u
->us_clientstate
= UPAPCS_INITIAL
;
302 u
->us_serverstate
= UPAPSS_INITIAL
;
307 * upap_protrej - Peer doesn't speak this protocol.
309 * This shouldn't happen. In any case, pretend lower layer went down.
315 upap_state
*u
= &upap
[unit
];
317 if (u
->us_clientstate
== UPAPCS_AUTHREQ
) {
318 error("PAP authentication failed due to protocol-reject");
319 auth_withpeer_fail(unit
, PPP_PAP
);
321 if (u
->us_serverstate
== UPAPSS_LISTEN
) {
322 error("PAP authentication of peer failed (protocol-reject)");
323 auth_peer_fail(unit
, PPP_PAP
);
325 upap_lowerdown(unit
);
330 * upap_input - Input UPAP packet.
333 upap_input(unit
, inpacket
, l
)
338 upap_state
*u
= &upap
[unit
];
344 * Parse header (code, id and length).
345 * If packet too short, drop it.
348 if (l
< UPAP_HEADERLEN
) {
349 error("PAP: packet is too small (%d < %d)", l
, UPAP_HEADERLEN
);
355 if ((len
< UPAP_HEADERLEN
) || (len
> l
)) {
356 error("PAP: packet has illegal length %d (%d..%d)", len
,
360 len
-= UPAP_HEADERLEN
;
363 * Action depends on code.
367 upap_rauthreq(u
, inp
, id
, len
);
371 upap_rauthack(u
, inp
, id
, len
);
375 upap_rauthnak(u
, inp
, id
, len
);
379 warn("Unknown PAP code (%d) received.", code
);
386 * upap_rauth - Receive Authenticate.
389 upap_rauthreq(u
, inp
, id
, len
)
395 u_char ruserlen
, rpasswdlen
;
396 char *ruser
, *rpasswd
;
401 if (u
->us_serverstate
< UPAPSS_LISTEN
) {
402 info("PAP: discarded Authenticate-Request in state %s",
403 pap_sstate(u
->us_serverstate
));
408 * If we receive a duplicate authenticate-request, we are
409 * supposed to return the same status as for the first request.
411 if (u
->us_serverstate
== UPAPSS_OPEN
) {
412 /* return auth-ack */
413 upap_sresp(u
, UPAP_AUTHACK
, id
, u
->us_msg
, u
->us_msglen
);
416 if (u
->us_serverstate
== UPAPSS_BADAUTH
) {
417 /* return auth-nak */
418 upap_sresp(u
, UPAP_AUTHNAK
, id
, u
->us_msg
, u
->us_msglen
);
426 error("PAP: rcvd short packet; no data");
429 GETCHAR(ruserlen
, inp
);
430 len
-= sizeof (u_char
) + ruserlen
+ sizeof (u_char
);
432 error("PAP: rcvd short packet; peer name missing");
435 ruser
= (char *) inp
;
436 INCPTR(ruserlen
, inp
);
437 GETCHAR(rpasswdlen
, inp
);
438 if (len
< rpasswdlen
) {
439 error("PAP: rcvd short packet; pass len %d < %d", len
, rpasswdlen
);
442 rpasswd
= (char *) inp
;
445 * Check the username and password given.
447 retcode
= check_passwd(u
->us_unit
, ruser
, ruserlen
, rpasswd
,
449 BZERO(rpasswd
, rpasswdlen
);
450 msglen
= strlen(msg
);
455 u
->us_msglen
= msglen
;
456 upap_sresp(u
, retcode
, id
, u
->us_msg
, u
->us_msglen
);
458 if (retcode
== UPAP_AUTHACK
) {
459 u
->us_serverstate
= UPAPSS_OPEN
;
460 auth_peer_success(u
->us_unit
, PPP_PAP
, ruser
, ruserlen
);
461 } else if (++u
->us_receives
>= u
->us_maxreceives
) {
462 u
->us_serverstate
= UPAPSS_BADAUTH
;
463 auth_peer_fail(u
->us_unit
, PPP_PAP
);
465 /* Just wait for a good one to arrive, or for time-out. */
469 if (u
->us_reqtimeout
> 0)
470 UNTIMEOUT(upap_reqtimeout
, u
);
475 * upap_rauthack - Receive Authenticate-Ack.
479 upap_rauthack(u
, inp
, id
, len
)
488 if (u
->us_clientstate
!= UPAPCS_AUTHREQ
) {
489 info("PAP: discarded Authenticate-Ack in state %s",
490 pap_cstate(u
->us_clientstate
));
494 if (id
!= u
->us_id
) {
495 dbglog("PAP: discard Authenticate-Ack; ID %d != %d",
500 if (u
->us_timeouttime
> 0)
501 UNTIMEOUT(upap_timeout
, u
);
507 info("PAP: Ignoring missing ack msg-length octet");
509 GETCHAR(msglen
, inp
);
511 len
-= sizeof (u_char
);
513 error("PAP: Discarding short packet (%d < %d)", len
, msglen
);
517 PRINTMSG(msg
, msglen
);
521 u
->us_clientstate
= UPAPCS_OPEN
;
523 auth_withpeer_success(u
->us_unit
, PPP_PAP
);
528 * upap_rauthnak - Receive Authenticate-Nakk.
532 upap_rauthnak(u
, inp
, id
, len
)
541 if (u
->us_clientstate
!= UPAPCS_AUTHREQ
) {
542 info("PAP: discarded Authenticate-Nak in state %s",
543 pap_cstate(u
->us_clientstate
));
547 if (id
!= u
->us_id
) {
548 dbglog("PAP: discard Authenticate-Ack; ID %d != %d",
553 if (u
->us_timeouttime
> 0)
554 UNTIMEOUT(upap_timeout
, u
);
560 error("PAP: ignoring missing nak msg-length octet");
562 GETCHAR(msglen
, inp
);
564 len
-= sizeof (u_char
);
566 error("PAP: Discarding short packet (%d < %d)", len
, msglen
);
570 PRINTMSG(msg
, msglen
);
574 /* Try to get a new password from the plugin. */
575 if (pap_passwd_hook
!= NULL
) {
576 if (u
->us_transmits
< u
->us_maxtransmits
) {
577 if ((*pap_passwd_hook
)(user
, passwd
) >= 0) {
582 /* Tell plug-in that we're giving up. */
583 (void) (*pap_passwd_hook
)(NULL
, NULL
);
587 u
->us_clientstate
= UPAPCS_BADAUTH
;
589 error("PAP authentication failed");
590 auth_withpeer_fail(u
->us_unit
, PPP_PAP
);
595 * upap_sauthreq - Send an Authenticate-Request.
605 pwlen
= strllen(passwd
, MAXSECRETLEN
);
608 outlen
= UPAP_HEADERLEN
+ 2 * sizeof (u_char
) + u
->us_userlen
+ pwlen
;
609 outp
= outpacket_buf
;
611 MAKEHEADER(outp
, PPP_PAP
);
613 PUTCHAR(UPAP_AUTHREQ
, outp
);
614 PUTCHAR(++u
->us_id
, outp
);
615 PUTSHORT(outlen
, outp
);
616 PUTCHAR(u
->us_userlen
, outp
);
617 BCOPY(u
->us_user
, outp
, u
->us_userlen
);
618 INCPTR(u
->us_userlen
, outp
);
619 PUTCHAR(pwlen
, outp
);
620 BCOPY(u
->us_passwd
, outp
, pwlen
);
622 output(u
->us_unit
, outpacket_buf
, outlen
+ PPP_HDRLEN
);
624 if (u
->us_timeouttime
> 0)
625 TIMEOUT(upap_timeout
, u
, u
->us_timeouttime
);
627 u
->us_clientstate
= UPAPCS_AUTHREQ
;
632 * upap_sresp - Send a response (ack or nak).
635 upap_sresp(u
, code
, id
, msg
, msglen
)
644 outlen
= UPAP_HEADERLEN
+ sizeof (u_char
) + msglen
;
645 outp
= outpacket_buf
;
646 MAKEHEADER(outp
, PPP_PAP
);
650 PUTSHORT(outlen
, outp
);
651 PUTCHAR(msglen
, outp
);
652 BCOPY(msg
, outp
, msglen
);
653 output(u
->us_unit
, outpacket_buf
, outlen
+ PPP_HDRLEN
);
657 * upap_printpkt - print the contents of a PAP packet.
659 static char *upap_codenames
[] = {
660 "AuthReq", "AuthAck", "AuthNak"
664 upap_printpkt(p
, plen
, printer
, arg
)
667 void (*printer
) __P((void *, const char *, ...));
671 int mlen
, ulen
, wlen
;
672 char *user
, *pwd
, *msg
;
675 if (plen
< UPAP_HEADERLEN
)
681 if (len
< UPAP_HEADERLEN
|| len
> plen
)
684 if (code
>= 1 && code
<= Dim(upap_codenames
))
685 printer(arg
, " %s", upap_codenames
[code
-1]);
687 printer(arg
, " code=0x%x", code
);
688 printer(arg
, " id=0x%x", id
);
689 len
-= UPAP_HEADERLEN
;
698 if (len
< ulen
+ wlen
+ 2)
700 user
= (char *) (p
+ 1);
701 pwd
= (char *) (p
+ ulen
+ 2);
702 p
+= ulen
+ wlen
+ 2;
703 len
-= ulen
+ wlen
+ 2;
704 printer(arg
, " user=");
705 print_string(user
, ulen
, printer
, arg
);
706 printer(arg
, " password=");
708 print_string(pwd
, wlen
, printer
, arg
);
710 printer(arg
, "<hidden>");
719 msg
= (char *) (p
+ 1);
723 print_string(msg
, mlen
, printer
, arg
);
727 /* print the rest of the bytes in the packet */
728 for (; len
> 0; --len
) {
730 printer(arg
, " %.2x", code
);