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.
40 static bool hide_password
= 1;
43 * Command-line options.
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" },
62 * Protocol entry points.
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 *));
72 struct protent pap_protent
= {
92 upap_state upap
[NUM_PPP
]; /* UPAP state; one for each unit */
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));
103 pap_cstate(clientstate
)
106 static const char *cstate
[] = { UPAPCS__NAMES
};
109 if (clientstate
< 0 || clientstate
>= Dim(cstate
)) {
110 (void) slprintf(buf
, sizeof (buf
), "Cli#%d", clientstate
);
111 return ((const char *)buf
);
113 return (cstate
[clientstate
]);
117 pap_sstate(serverstate
)
120 static const char *sstate
[] = { UPAPSS__NAMES
};
123 if (serverstate
< 0 || serverstate
>= Dim(sstate
)) {
124 (void) slprintf(buf
, sizeof (buf
), "Srv#%d", serverstate
);
125 return ((const char *)buf
);
127 return (sstate
[serverstate
]);
131 * upap_init - Initialize a UPAP unit.
137 upap_state
*u
= &upap
[unit
];
143 u
->us_clientstate
= UPAPCS_INITIAL
;
144 u
->us_serverstate
= UPAPSS_INITIAL
;
146 u
->us_timeouttime
= UPAP_DEFTIMEOUT
;
147 u
->us_maxtransmits
= 10;
148 u
->us_reqtimeout
= UPAP_DEFREQTIME
;
149 u
->us_maxreceives
= 3;
156 * upap_authwithpeer - Authenticate us with our peer (start client).
158 * Set new state and send authenticate's.
161 upap_authwithpeer(unit
, user
, password
)
163 char *user
, *password
;
165 upap_state
*u
= &upap
[unit
];
167 /* Save the username and password we're given */
169 u
->us_userlen
= strlen(user
);
170 u
->us_passwd
= password
;
173 /* Lower layer up yet? */
174 if (u
->us_clientstate
== UPAPCS_INITIAL
||
175 u
->us_clientstate
== UPAPCS_PENDING
) {
176 u
->us_clientstate
= UPAPCS_PENDING
;
180 upap_sauthreq(u
); /* Start protocol */
185 * upap_authpeer - Authenticate our peer (start server).
193 upap_state
*u
= &upap
[unit
];
195 /* Lower layer up yet? */
196 if (u
->us_serverstate
== UPAPSS_INITIAL
||
197 u
->us_serverstate
== UPAPSS_PENDING
) {
198 u
->us_serverstate
= UPAPSS_PENDING
;
202 u
->us_serverstate
= UPAPSS_LISTEN
;
204 if (u
->us_reqtimeout
> 0)
205 TIMEOUT(upap_reqtimeout
, u
, u
->us_reqtimeout
);
210 * upap_timeout - Retransmission timer for sending auth-reqs expired.
216 upap_state
*u
= (upap_state
*) arg
;
218 if (u
->us_clientstate
!= UPAPCS_AUTHREQ
)
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
);
229 upap_sauthreq(u
); /* Send Authenticate-Request */
234 * upap_reqtimeout - Give up waiting for the peer to send a valid auth-req.
240 upap_state
*u
= (upap_state
*) arg
;
242 if (u
->us_serverstate
!= UPAPSS_LISTEN
)
245 auth_peer_fail(u
->us_unit
, PPP_PAP
);
246 u
->us_serverstate
= UPAPSS_BADAUTH
;
251 * upap_lowerup - The lower layer is up.
253 * Start authenticating if pending.
259 upap_state
*u
= &upap
[unit
];
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 */
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
);
278 * upap_lowerdown - The lower layer is down.
280 * Cancel all timeouts.
286 upap_state
*u
= &upap
[unit
];
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
);
294 u
->us_clientstate
= UPAPCS_INITIAL
;
295 u
->us_serverstate
= UPAPSS_INITIAL
;
300 * upap_protrej - Peer doesn't speak this protocol.
302 * This shouldn't happen. In any case, pretend lower layer went down.
308 upap_state
*u
= &upap
[unit
];
310 if (u
->us_clientstate
== UPAPCS_AUTHREQ
) {
311 error("PAP authentication failed due to protocol-reject");
312 auth_withpeer_fail(unit
, PPP_PAP
);
314 if (u
->us_serverstate
== UPAPSS_LISTEN
) {
315 error("PAP authentication of peer failed (protocol-reject)");
316 auth_peer_fail(unit
, PPP_PAP
);
318 upap_lowerdown(unit
);
323 * upap_input - Input UPAP packet.
326 upap_input(unit
, inpacket
, l
)
331 upap_state
*u
= &upap
[unit
];
337 * Parse header (code, id and length).
338 * If packet too short, drop it.
341 if (l
< UPAP_HEADERLEN
) {
342 error("PAP: packet is too small (%d < %d)", l
, UPAP_HEADERLEN
);
348 if ((len
< UPAP_HEADERLEN
) || (len
> l
)) {
349 error("PAP: packet has illegal length %d (%d..%d)", len
,
353 len
-= UPAP_HEADERLEN
;
356 * Action depends on code.
360 upap_rauthreq(u
, inp
, id
, len
);
364 upap_rauthack(u
, inp
, id
, len
);
368 upap_rauthnak(u
, inp
, id
, len
);
372 warn("Unknown PAP code (%d) received.", code
);
379 * upap_rauth - Receive Authenticate.
382 upap_rauthreq(u
, inp
, id
, len
)
388 u_char ruserlen
, rpasswdlen
;
389 char *ruser
, *rpasswd
;
394 if (u
->us_serverstate
< UPAPSS_LISTEN
) {
395 info("PAP: discarded Authenticate-Request in state %s",
396 pap_sstate(u
->us_serverstate
));
401 * If we receive a duplicate authenticate-request, we are
402 * supposed to return the same status as for the first request.
404 if (u
->us_serverstate
== UPAPSS_OPEN
) {
405 /* return auth-ack */
406 upap_sresp(u
, UPAP_AUTHACK
, id
, u
->us_msg
, u
->us_msglen
);
409 if (u
->us_serverstate
== UPAPSS_BADAUTH
) {
410 /* return auth-nak */
411 upap_sresp(u
, UPAP_AUTHNAK
, id
, u
->us_msg
, u
->us_msglen
);
419 error("PAP: rcvd short packet; no data");
422 GETCHAR(ruserlen
, inp
);
423 len
-= sizeof (u_char
) + ruserlen
+ sizeof (u_char
);
425 error("PAP: rcvd short packet; peer name missing");
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
);
435 rpasswd
= (char *) inp
;
438 * Check the username and password given.
440 retcode
= check_passwd(u
->us_unit
, ruser
, ruserlen
, rpasswd
,
442 BZERO(rpasswd
, rpasswdlen
);
443 msglen
= strlen(msg
);
448 u
->us_msglen
= msglen
;
449 upap_sresp(u
, retcode
, id
, u
->us_msg
, u
->us_msglen
);
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
);
458 /* Just wait for a good one to arrive, or for time-out. */
462 if (u
->us_reqtimeout
> 0)
463 UNTIMEOUT(upap_reqtimeout
, u
);
468 * upap_rauthack - Receive Authenticate-Ack.
472 upap_rauthack(u
, inp
, id
, len
)
481 if (u
->us_clientstate
!= UPAPCS_AUTHREQ
) {
482 info("PAP: discarded Authenticate-Ack in state %s",
483 pap_cstate(u
->us_clientstate
));
487 if (id
!= u
->us_id
) {
488 dbglog("PAP: discard Authenticate-Ack; ID %d != %d",
493 if (u
->us_timeouttime
> 0)
494 UNTIMEOUT(upap_timeout
, u
);
500 info("PAP: Ignoring missing ack msg-length octet");
502 GETCHAR(msglen
, inp
);
504 len
-= sizeof (u_char
);
506 error("PAP: Discarding short packet (%d < %d)", len
, msglen
);
510 PRINTMSG(msg
, msglen
);
514 u
->us_clientstate
= UPAPCS_OPEN
;
516 auth_withpeer_success(u
->us_unit
, PPP_PAP
);
521 * upap_rauthnak - Receive Authenticate-Nakk.
525 upap_rauthnak(u
, inp
, id
, len
)
534 if (u
->us_clientstate
!= UPAPCS_AUTHREQ
) {
535 info("PAP: discarded Authenticate-Nak in state %s",
536 pap_cstate(u
->us_clientstate
));
540 if (id
!= u
->us_id
) {
541 dbglog("PAP: discard Authenticate-Ack; ID %d != %d",
546 if (u
->us_timeouttime
> 0)
547 UNTIMEOUT(upap_timeout
, u
);
553 error("PAP: ignoring missing nak msg-length octet");
555 GETCHAR(msglen
, inp
);
557 len
-= sizeof (u_char
);
559 error("PAP: Discarding short packet (%d < %d)", len
, msglen
);
563 PRINTMSG(msg
, msglen
);
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) {
575 /* Tell plug-in that we're giving up. */
576 (void) (*pap_passwd_hook
)(NULL
, NULL
);
580 u
->us_clientstate
= UPAPCS_BADAUTH
;
582 error("PAP authentication failed");
583 auth_withpeer_fail(u
->us_unit
, PPP_PAP
);
588 * upap_sauthreq - Send an Authenticate-Request.
598 pwlen
= strllen(passwd
, MAXSECRETLEN
);
601 outlen
= UPAP_HEADERLEN
+ 2 * sizeof (u_char
) + u
->us_userlen
+ pwlen
;
602 outp
= outpacket_buf
;
604 MAKEHEADER(outp
, PPP_PAP
);
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
);
615 output(u
->us_unit
, outpacket_buf
, outlen
+ PPP_HDRLEN
);
617 if (u
->us_timeouttime
> 0)
618 TIMEOUT(upap_timeout
, u
, u
->us_timeouttime
);
620 u
->us_clientstate
= UPAPCS_AUTHREQ
;
625 * upap_sresp - Send a response (ack or nak).
628 upap_sresp(u
, code
, id
, msg
, msglen
)
637 outlen
= UPAP_HEADERLEN
+ sizeof (u_char
) + msglen
;
638 outp
= outpacket_buf
;
639 MAKEHEADER(outp
, PPP_PAP
);
643 PUTSHORT(outlen
, outp
);
644 PUTCHAR(msglen
, outp
);
645 BCOPY(msg
, outp
, msglen
);
646 output(u
->us_unit
, outpacket_buf
, outlen
+ PPP_HDRLEN
);
650 * upap_printpkt - print the contents of a PAP packet.
652 static char *upap_codenames
[] = {
653 "AuthReq", "AuthAck", "AuthNak"
657 upap_printpkt(p
, plen
, printer
, arg
)
660 void (*printer
) __P((void *, const char *, ...));
664 int mlen
, ulen
, wlen
;
665 char *user
, *pwd
, *msg
;
668 if (plen
< UPAP_HEADERLEN
)
674 if (len
< UPAP_HEADERLEN
|| len
> plen
)
677 if (code
>= 1 && code
<= Dim(upap_codenames
))
678 printer(arg
, " %s", upap_codenames
[code
-1]);
680 printer(arg
, " code=0x%x", code
);
681 printer(arg
, " id=0x%x", id
);
682 len
-= UPAP_HEADERLEN
;
691 if (len
< ulen
+ wlen
+ 2)
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=");
701 print_string(pwd
, wlen
, printer
, arg
);
703 printer(arg
, "<hidden>");
712 msg
= (char *) (p
+ 1);
716 print_string(msg
, mlen
, printer
, arg
);
720 /* print the rest of the bytes in the packet */
721 for (; len
> 0; --len
) {
723 printer(arg
, " %.2x", code
);