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 static const char rcsid
[] = RCSID
;
45 static bool hide_password
= 1;
48 * Command-line options.
50 static option_t pap_option_list
[] = {
51 { "hide-password", o_bool
, &hide_password
,
52 "Don't output passwords to log", 1 },
53 { "show-password", o_bool
, &hide_password
,
54 "Show password string in debug log messages", 0 },
55 { "pap-restart", o_int
, &upap
[0].us_timeouttime
,
56 "Set retransmit timeout for PAP" },
57 { "pap-max-authreq", o_int
, &upap
[0].us_maxtransmits
,
58 "Max number of PAP Authenticate-Request sent" },
59 { "pap-max-receive", o_int
, &upap
[0].us_maxreceives
,
60 "Max allowable PAP Authenticate-Request received" },
61 { "pap-timeout", o_int
, &upap
[0].us_reqtimeout
,
62 "Set time limit for peer PAP authentication" },
67 * Protocol entry points.
69 static void upap_init
__P((int));
70 static void upap_lowerup
__P((int));
71 static void upap_lowerdown
__P((int));
72 static void upap_input
__P((int, u_char
*, int));
73 static void upap_protrej
__P((int));
74 static int upap_printpkt
__P((u_char
*, int,
75 void (*) __P((void *, const char *, ...)), void *));
77 struct protent pap_protent
= {
97 upap_state upap
[NUM_PPP
]; /* UPAP state; one for each unit */
99 static void upap_timeout
__P((void *));
100 static void upap_reqtimeout
__P((void *));
101 static void upap_rauthreq
__P((upap_state
*, u_char
*, int, int));
102 static void upap_rauthack
__P((upap_state
*, u_char
*, int, int));
103 static void upap_rauthnak
__P((upap_state
*, u_char
*, int, int));
104 static void upap_sauthreq
__P((upap_state
*));
105 static void upap_sresp
__P((upap_state
*, int, int, char *, int));
108 pap_cstate(clientstate
)
111 static const char *cstate
[] = { UPAPCS__NAMES
};
114 if (clientstate
< 0 || clientstate
>= Dim(cstate
)) {
115 (void) slprintf(buf
, sizeof (buf
), "Cli#%d", clientstate
);
116 return ((const char *)buf
);
118 return (cstate
[clientstate
]);
122 pap_sstate(serverstate
)
125 static const char *sstate
[] = { UPAPSS__NAMES
};
128 if (serverstate
< 0 || serverstate
>= Dim(sstate
)) {
129 (void) slprintf(buf
, sizeof (buf
), "Srv#%d", serverstate
);
130 return ((const char *)buf
);
132 return (sstate
[serverstate
]);
136 * upap_init - Initialize a UPAP unit.
142 upap_state
*u
= &upap
[unit
];
148 u
->us_clientstate
= UPAPCS_INITIAL
;
149 u
->us_serverstate
= UPAPSS_INITIAL
;
151 u
->us_timeouttime
= UPAP_DEFTIMEOUT
;
152 u
->us_maxtransmits
= 10;
153 u
->us_reqtimeout
= UPAP_DEFREQTIME
;
154 u
->us_maxreceives
= 3;
161 * upap_authwithpeer - Authenticate us with our peer (start client).
163 * Set new state and send authenticate's.
166 upap_authwithpeer(unit
, user
, password
)
168 char *user
, *password
;
170 upap_state
*u
= &upap
[unit
];
172 /* Save the username and password we're given */
174 u
->us_userlen
= strlen(user
);
175 u
->us_passwd
= password
;
178 /* Lower layer up yet? */
179 if (u
->us_clientstate
== UPAPCS_INITIAL
||
180 u
->us_clientstate
== UPAPCS_PENDING
) {
181 u
->us_clientstate
= UPAPCS_PENDING
;
185 upap_sauthreq(u
); /* Start protocol */
190 * upap_authpeer - Authenticate our peer (start server).
198 upap_state
*u
= &upap
[unit
];
200 /* Lower layer up yet? */
201 if (u
->us_serverstate
== UPAPSS_INITIAL
||
202 u
->us_serverstate
== UPAPSS_PENDING
) {
203 u
->us_serverstate
= UPAPSS_PENDING
;
207 u
->us_serverstate
= UPAPSS_LISTEN
;
209 if (u
->us_reqtimeout
> 0)
210 TIMEOUT(upap_reqtimeout
, u
, u
->us_reqtimeout
);
215 * upap_timeout - Retransmission timer for sending auth-reqs expired.
221 upap_state
*u
= (upap_state
*) arg
;
223 if (u
->us_clientstate
!= UPAPCS_AUTHREQ
)
226 if (u
->us_transmits
>= u
->us_maxtransmits
) {
227 /* give up in disgust */
228 error("No response to %d PAP Authenticate-Requests", u
->us_transmits
);
229 u
->us_clientstate
= UPAPCS_BADAUTH
;
230 auth_withpeer_fail(u
->us_unit
, PPP_PAP
);
234 upap_sauthreq(u
); /* Send Authenticate-Request */
239 * upap_reqtimeout - Give up waiting for the peer to send a valid auth-req.
245 upap_state
*u
= (upap_state
*) arg
;
247 if (u
->us_serverstate
!= UPAPSS_LISTEN
)
250 auth_peer_fail(u
->us_unit
, PPP_PAP
);
251 u
->us_serverstate
= UPAPSS_BADAUTH
;
256 * upap_lowerup - The lower layer is up.
258 * Start authenticating if pending.
264 upap_state
*u
= &upap
[unit
];
266 if (u
->us_clientstate
== UPAPCS_INITIAL
)
267 u
->us_clientstate
= UPAPCS_CLOSED
;
268 else if (u
->us_clientstate
== UPAPCS_PENDING
) {
269 upap_sauthreq(u
); /* send an auth-request */
272 if (u
->us_serverstate
== UPAPSS_INITIAL
)
273 u
->us_serverstate
= UPAPSS_CLOSED
;
274 else if (u
->us_serverstate
== UPAPSS_PENDING
) {
275 u
->us_serverstate
= UPAPSS_LISTEN
;
276 if (u
->us_reqtimeout
> 0)
277 TIMEOUT(upap_reqtimeout
, u
, u
->us_reqtimeout
);
283 * upap_lowerdown - The lower layer is down.
285 * Cancel all timeouts.
291 upap_state
*u
= &upap
[unit
];
293 /* Cancel timeouts */
294 if (u
->us_clientstate
== UPAPCS_AUTHREQ
&& u
->us_timeouttime
> 0)
295 UNTIMEOUT(upap_timeout
, u
);
296 if (u
->us_serverstate
== UPAPSS_LISTEN
&& u
->us_reqtimeout
> 0)
297 UNTIMEOUT(upap_reqtimeout
, u
);
299 u
->us_clientstate
= UPAPCS_INITIAL
;
300 u
->us_serverstate
= UPAPSS_INITIAL
;
305 * upap_protrej - Peer doesn't speak this protocol.
307 * This shouldn't happen. In any case, pretend lower layer went down.
313 upap_state
*u
= &upap
[unit
];
315 if (u
->us_clientstate
== UPAPCS_AUTHREQ
) {
316 error("PAP authentication failed due to protocol-reject");
317 auth_withpeer_fail(unit
, PPP_PAP
);
319 if (u
->us_serverstate
== UPAPSS_LISTEN
) {
320 error("PAP authentication of peer failed (protocol-reject)");
321 auth_peer_fail(unit
, PPP_PAP
);
323 upap_lowerdown(unit
);
328 * upap_input - Input UPAP packet.
331 upap_input(unit
, inpacket
, l
)
336 upap_state
*u
= &upap
[unit
];
342 * Parse header (code, id and length).
343 * If packet too short, drop it.
346 if (l
< UPAP_HEADERLEN
) {
347 error("PAP: packet is too small (%d < %d)", l
, UPAP_HEADERLEN
);
353 if ((len
< UPAP_HEADERLEN
) || (len
> l
)) {
354 error("PAP: packet has illegal length %d (%d..%d)", len
,
358 len
-= UPAP_HEADERLEN
;
361 * Action depends on code.
365 upap_rauthreq(u
, inp
, id
, len
);
369 upap_rauthack(u
, inp
, id
, len
);
373 upap_rauthnak(u
, inp
, id
, len
);
377 warn("Unknown PAP code (%d) received.", code
);
384 * upap_rauth - Receive Authenticate.
387 upap_rauthreq(u
, inp
, id
, len
)
393 u_char ruserlen
, rpasswdlen
;
394 char *ruser
, *rpasswd
;
399 if (u
->us_serverstate
< UPAPSS_LISTEN
) {
400 info("PAP: discarded Authenticate-Request in state %s",
401 pap_sstate(u
->us_serverstate
));
406 * If we receive a duplicate authenticate-request, we are
407 * supposed to return the same status as for the first request.
409 if (u
->us_serverstate
== UPAPSS_OPEN
) {
410 /* return auth-ack */
411 upap_sresp(u
, UPAP_AUTHACK
, id
, u
->us_msg
, u
->us_msglen
);
414 if (u
->us_serverstate
== UPAPSS_BADAUTH
) {
415 /* return auth-nak */
416 upap_sresp(u
, UPAP_AUTHNAK
, id
, u
->us_msg
, u
->us_msglen
);
424 error("PAP: rcvd short packet; no data");
427 GETCHAR(ruserlen
, inp
);
428 len
-= sizeof (u_char
) + ruserlen
+ sizeof (u_char
);
430 error("PAP: rcvd short packet; peer name missing");
433 ruser
= (char *) inp
;
434 INCPTR(ruserlen
, inp
);
435 GETCHAR(rpasswdlen
, inp
);
436 if (len
< rpasswdlen
) {
437 error("PAP: rcvd short packet; pass len %d < %d", len
, rpasswdlen
);
440 rpasswd
= (char *) inp
;
443 * Check the username and password given.
445 retcode
= check_passwd(u
->us_unit
, ruser
, ruserlen
, rpasswd
,
447 BZERO(rpasswd
, rpasswdlen
);
448 msglen
= strlen(msg
);
453 u
->us_msglen
= msglen
;
454 upap_sresp(u
, retcode
, id
, u
->us_msg
, u
->us_msglen
);
456 if (retcode
== UPAP_AUTHACK
) {
457 u
->us_serverstate
= UPAPSS_OPEN
;
458 auth_peer_success(u
->us_unit
, PPP_PAP
, ruser
, ruserlen
);
459 } else if (++u
->us_receives
>= u
->us_maxreceives
) {
460 u
->us_serverstate
= UPAPSS_BADAUTH
;
461 auth_peer_fail(u
->us_unit
, PPP_PAP
);
463 /* Just wait for a good one to arrive, or for time-out. */
467 if (u
->us_reqtimeout
> 0)
468 UNTIMEOUT(upap_reqtimeout
, u
);
473 * upap_rauthack - Receive Authenticate-Ack.
477 upap_rauthack(u
, inp
, id
, len
)
486 if (u
->us_clientstate
!= UPAPCS_AUTHREQ
) {
487 info("PAP: discarded Authenticate-Ack in state %s",
488 pap_cstate(u
->us_clientstate
));
492 if (id
!= u
->us_id
) {
493 dbglog("PAP: discard Authenticate-Ack; ID %d != %d",
498 if (u
->us_timeouttime
> 0)
499 UNTIMEOUT(upap_timeout
, u
);
505 info("PAP: Ignoring missing ack msg-length octet");
507 GETCHAR(msglen
, inp
);
509 len
-= sizeof (u_char
);
511 error("PAP: Discarding short packet (%d < %d)", len
, msglen
);
515 PRINTMSG(msg
, msglen
);
519 u
->us_clientstate
= UPAPCS_OPEN
;
521 auth_withpeer_success(u
->us_unit
, PPP_PAP
);
526 * upap_rauthnak - Receive Authenticate-Nakk.
530 upap_rauthnak(u
, inp
, id
, len
)
539 if (u
->us_clientstate
!= UPAPCS_AUTHREQ
) {
540 info("PAP: discarded Authenticate-Nak in state %s",
541 pap_cstate(u
->us_clientstate
));
545 if (id
!= u
->us_id
) {
546 dbglog("PAP: discard Authenticate-Ack; ID %d != %d",
551 if (u
->us_timeouttime
> 0)
552 UNTIMEOUT(upap_timeout
, u
);
558 error("PAP: ignoring missing nak msg-length octet");
560 GETCHAR(msglen
, inp
);
562 len
-= sizeof (u_char
);
564 error("PAP: Discarding short packet (%d < %d)", len
, msglen
);
568 PRINTMSG(msg
, msglen
);
572 /* Try to get a new password from the plugin. */
573 if (pap_passwd_hook
!= NULL
) {
574 if (u
->us_transmits
< u
->us_maxtransmits
) {
575 if ((*pap_passwd_hook
)(user
, passwd
) >= 0) {
580 /* Tell plug-in that we're giving up. */
581 (void) (*pap_passwd_hook
)(NULL
, NULL
);
585 u
->us_clientstate
= UPAPCS_BADAUTH
;
587 error("PAP authentication failed");
588 auth_withpeer_fail(u
->us_unit
, PPP_PAP
);
593 * upap_sauthreq - Send an Authenticate-Request.
603 pwlen
= strllen(passwd
, MAXSECRETLEN
);
606 outlen
= UPAP_HEADERLEN
+ 2 * sizeof (u_char
) + u
->us_userlen
+ pwlen
;
607 outp
= outpacket_buf
;
609 MAKEHEADER(outp
, PPP_PAP
);
611 PUTCHAR(UPAP_AUTHREQ
, outp
);
612 PUTCHAR(++u
->us_id
, outp
);
613 PUTSHORT(outlen
, outp
);
614 PUTCHAR(u
->us_userlen
, outp
);
615 BCOPY(u
->us_user
, outp
, u
->us_userlen
);
616 INCPTR(u
->us_userlen
, outp
);
617 PUTCHAR(pwlen
, outp
);
618 BCOPY(u
->us_passwd
, outp
, pwlen
);
620 output(u
->us_unit
, outpacket_buf
, outlen
+ PPP_HDRLEN
);
622 if (u
->us_timeouttime
> 0)
623 TIMEOUT(upap_timeout
, u
, u
->us_timeouttime
);
625 u
->us_clientstate
= UPAPCS_AUTHREQ
;
630 * upap_sresp - Send a response (ack or nak).
633 upap_sresp(u
, code
, id
, msg
, msglen
)
642 outlen
= UPAP_HEADERLEN
+ sizeof (u_char
) + msglen
;
643 outp
= outpacket_buf
;
644 MAKEHEADER(outp
, PPP_PAP
);
648 PUTSHORT(outlen
, outp
);
649 PUTCHAR(msglen
, outp
);
650 BCOPY(msg
, outp
, msglen
);
651 output(u
->us_unit
, outpacket_buf
, outlen
+ PPP_HDRLEN
);
655 * upap_printpkt - print the contents of a PAP packet.
657 static char *upap_codenames
[] = {
658 "AuthReq", "AuthAck", "AuthNak"
662 upap_printpkt(p
, plen
, printer
, arg
)
665 void (*printer
) __P((void *, const char *, ...));
669 int mlen
, ulen
, wlen
;
670 char *user
, *pwd
, *msg
;
673 if (plen
< UPAP_HEADERLEN
)
679 if (len
< UPAP_HEADERLEN
|| len
> plen
)
682 if (code
>= 1 && code
<= Dim(upap_codenames
))
683 printer(arg
, " %s", upap_codenames
[code
-1]);
685 printer(arg
, " code=0x%x", code
);
686 printer(arg
, " id=0x%x", id
);
687 len
-= UPAP_HEADERLEN
;
696 if (len
< ulen
+ wlen
+ 2)
698 user
= (char *) (p
+ 1);
699 pwd
= (char *) (p
+ ulen
+ 2);
700 p
+= ulen
+ wlen
+ 2;
701 len
-= ulen
+ wlen
+ 2;
702 printer(arg
, " user=");
703 print_string(user
, ulen
, printer
, arg
);
704 printer(arg
, " password=");
706 print_string(pwd
, wlen
, printer
, arg
);
708 printer(arg
, "<hidden>");
717 msg
= (char *) (p
+ 1);
721 print_string(msg
, mlen
, printer
, arg
);
725 /* print the rest of the bytes in the packet */
726 for (; len
> 0; --len
) {
728 printer(arg
, " %.2x", code
);