2 * upap.c - User/Password Authentication Protocol.
4 * Copyright (c) 1989 Carnegie Mellon University.
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.
21 static char rcsid[] = "$Id: upap.c,v 1.12 1998/11/07 06:59:32 paulus Exp $";
30 #include <sys/types.h>
38 * Command-line options.
40 static option_t pap_option_list[] = {
41 { "pap-restart", o_int, &upap[0].us_timeouttime,
42 "Set retransmit timeout for PAP" },
43 { "pap-max-authreq", o_int, &upap[0].us_maxtransmits,
44 "Set max #xmits for auth-reqs" },
45 { "pap-timeout", o_int, &upap[0].us_reqtimeout,
46 "Set time limit for peer PAP auth." },
51 * Protocol entry points.
53 static void upap_init __P((int));
54 static void upap_lowerup __P((int));
55 static void upap_lowerdown __P((int));
56 static void upap_input __P((int, u_char *, int));
57 static void upap_protrej __P((int));
58 static int upap_printpkt __P((u_char *, int,
59 void (*) __P((void *, char *, ...)), void *));
61 struct protent pap_protent = {
80 upap_state upap[NUM_PPP]; /* UPAP state; one for each unit */
82 static void upap_timeout __P((void *));
83 static void upap_reqtimeout __P((void *));
84 static void upap_rauthreq __P((upap_state *, u_char *, int, int));
85 static void upap_rauthack __P((upap_state *, u_char *, int, int));
86 static void upap_rauthnak __P((upap_state *, u_char *, int, int));
87 static void upap_sauthreq __P((upap_state *));
88 static void upap_sresp __P((upap_state *, int, int, char *, int));
92 * upap_init - Initialize a UPAP unit.
98 upap_state *u = &upap[unit];
105 u->us_clientstate = UPAPCS_INITIAL;
106 u->us_serverstate = UPAPSS_INITIAL;
108 u->us_timeouttime = UPAP_DEFTIMEOUT;
109 u->us_maxtransmits = 10;
110 u->us_reqtimeout = UPAP_DEFREQTIME;
115 * upap_authwithpeer - Authenticate us with our peer (start client).
117 * Set new state and send authenticate's.
120 upap_authwithpeer(unit, user, password)
122 char *user, *password;
124 upap_state *u = &upap[unit];
126 /* Save the username and password we're given */
128 u->us_userlen = strlen(user);
129 u->us_passwd = password;
130 u->us_passwdlen = strlen(password);
133 /* Lower layer up yet? */
134 if (u->us_clientstate == UPAPCS_INITIAL ||
135 u->us_clientstate == UPAPCS_PENDING) {
136 u->us_clientstate = UPAPCS_PENDING;
140 upap_sauthreq(u); /* Start protocol */
145 * upap_authpeer - Authenticate our peer (start server).
153 upap_state *u = &upap[unit];
155 /* Lower layer up yet? */
156 if (u->us_serverstate == UPAPSS_INITIAL ||
157 u->us_serverstate == UPAPSS_PENDING) {
158 u->us_serverstate = UPAPSS_PENDING;
162 u->us_serverstate = UPAPSS_LISTEN;
163 if (u->us_reqtimeout > 0)
164 TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
169 * upap_timeout - Retransmission timer for sending auth-reqs expired.
175 upap_state *u = (upap_state *) arg;
177 if (u->us_clientstate != UPAPCS_AUTHREQ)
180 if (u->us_transmits >= u->us_maxtransmits) {
181 /* give up in disgust */
182 syslog(LOG_ERR, "No response to PAP authenticate-requests");
183 u->us_clientstate = UPAPCS_BADAUTH;
184 auth_withpeer_fail(u->us_unit, PPP_PAP);
188 upap_sauthreq(u); /* Send Authenticate-Request */
193 * upap_reqtimeout - Give up waiting for the peer to send an auth-req.
199 upap_state *u = (upap_state *) arg;
201 if (u->us_serverstate != UPAPSS_LISTEN)
204 auth_peer_fail(u->us_unit, PPP_PAP);
205 u->us_serverstate = UPAPSS_BADAUTH;
210 * upap_lowerup - The lower layer is up.
212 * Start authenticating if pending.
218 upap_state *u = &upap[unit];
220 if (u->us_clientstate == UPAPCS_INITIAL)
221 u->us_clientstate = UPAPCS_CLOSED;
222 else if (u->us_clientstate == UPAPCS_PENDING) {
223 upap_sauthreq(u); /* send an auth-request */
226 if (u->us_serverstate == UPAPSS_INITIAL)
227 u->us_serverstate = UPAPSS_CLOSED;
228 else if (u->us_serverstate == UPAPSS_PENDING) {
229 u->us_serverstate = UPAPSS_LISTEN;
230 if (u->us_reqtimeout > 0)
231 TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
237 * upap_lowerdown - The lower layer is down.
239 * Cancel all timeouts.
245 upap_state *u = &upap[unit];
247 if (u->us_clientstate == UPAPCS_AUTHREQ) /* Timeout pending? */
248 UNTIMEOUT(upap_timeout, u); /* Cancel timeout */
249 if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0)
250 UNTIMEOUT(upap_reqtimeout, u);
252 u->us_clientstate = UPAPCS_INITIAL;
253 u->us_serverstate = UPAPSS_INITIAL;
258 * upap_protrej - Peer doesn't speak this protocol.
260 * This shouldn't happen. In any case, pretend lower layer went down.
266 upap_state *u = &upap[unit];
268 if (u->us_clientstate == UPAPCS_AUTHREQ) {
269 syslog(LOG_ERR, "PAP authentication failed due to protocol-reject");
270 auth_withpeer_fail(unit, PPP_PAP);
272 if (u->us_serverstate == UPAPSS_LISTEN) {
273 syslog(LOG_ERR, "PAP authentication of peer failed (protocol-reject)");
274 auth_peer_fail(unit, PPP_PAP);
276 upap_lowerdown(unit);
281 * upap_input - Input UPAP packet.
284 upap_input(unit, inpacket, l)
289 upap_state *u = &upap[unit];
295 * Parse header (code, id and length).
296 * If packet too short, drop it.
299 if (l < UPAP_HEADERLEN) {
300 UPAPDEBUG((LOG_INFO, "pap_input: rcvd short header."));
306 if (len < UPAP_HEADERLEN) {
307 UPAPDEBUG((LOG_INFO, "pap_input: rcvd illegal length."));
311 UPAPDEBUG((LOG_INFO, "pap_input: rcvd short packet."));
314 len -= UPAP_HEADERLEN;
317 * Action depends on code.
321 upap_rauthreq(u, inp, id, len);
325 upap_rauthack(u, inp, id, len);
329 upap_rauthnak(u, inp, id, len);
332 default: /* XXX Need code reject */
339 * upap_rauth - Receive Authenticate.
342 upap_rauthreq(u, inp, id, len)
348 u_char ruserlen, rpasswdlen;
349 char *ruser, *rpasswd;
354 UPAPDEBUG((LOG_INFO, "pap_rauth: Rcvd id %d.", id));
356 if (u->us_serverstate < UPAPSS_LISTEN)
360 * If we receive a duplicate authenticate-request, we are
361 * supposed to return the same status as for the first request.
363 if (u->us_serverstate == UPAPSS_OPEN) {
364 upap_sresp(u, UPAP_AUTHACK, id, "", 0); /* return auth-ack */
367 if (u->us_serverstate == UPAPSS_BADAUTH) {
368 upap_sresp(u, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */
375 if (len < sizeof (u_char)) {
376 UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet."));
379 GETCHAR(ruserlen, inp);
380 len -= sizeof (u_char) + ruserlen + sizeof (u_char);
382 UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet."));
385 ruser = (char *) inp;
386 INCPTR(ruserlen, inp);
387 GETCHAR(rpasswdlen, inp);
388 if (len < rpasswdlen) {
389 UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet."));
392 rpasswd = (char *) inp;
395 * Check the username and password given.
397 retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
398 rpasswdlen, &msg, &msglen);
399 BZERO(rpasswd, rpasswdlen);
401 upap_sresp(u, retcode, id, msg, msglen);
403 if (retcode == UPAP_AUTHACK) {
404 u->us_serverstate = UPAPSS_OPEN;
405 auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen);
407 u->us_serverstate = UPAPSS_BADAUTH;
408 auth_peer_fail(u->us_unit, PPP_PAP);
411 if (u->us_reqtimeout > 0)
412 UNTIMEOUT(upap_reqtimeout, u);
417 * upap_rauthack - Receive Authenticate-Ack.
420 upap_rauthack(u, inp, id, len)
429 UPAPDEBUG((LOG_INFO, "pap_rauthack: Rcvd id %d.", id));
430 if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
436 if (len < sizeof (u_char)) {
437 UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet."));
440 GETCHAR(msglen, inp);
441 len -= sizeof (u_char);
443 UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet."));
447 PRINTMSG(msg, msglen);
449 u->us_clientstate = UPAPCS_OPEN;
451 auth_withpeer_success(u->us_unit, PPP_PAP);
456 * upap_rauthnak - Receive Authenticate-Nakk.
459 upap_rauthnak(u, inp, id, len)
468 UPAPDEBUG((LOG_INFO, "pap_rauthnak: Rcvd id %d.", id));
469 if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
475 if (len < sizeof (u_char)) {
476 UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet."));
479 GETCHAR(msglen, inp);
480 len -= sizeof (u_char);
482 UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet."));
486 PRINTMSG(msg, msglen);
488 u->us_clientstate = UPAPCS_BADAUTH;
490 syslog(LOG_ERR, "PAP authentication failed");
491 auth_withpeer_fail(u->us_unit, PPP_PAP);
496 * upap_sauthreq - Send an Authenticate-Request.
505 outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) +
506 u->us_userlen + u->us_passwdlen;
507 outp = outpacket_buf;
509 MAKEHEADER(outp, PPP_PAP);
511 PUTCHAR(UPAP_AUTHREQ, outp);
512 PUTCHAR(++u->us_id, outp);
513 PUTSHORT(outlen, outp);
514 PUTCHAR(u->us_userlen, outp);
515 BCOPY(u->us_user, outp, u->us_userlen);
516 INCPTR(u->us_userlen, outp);
517 PUTCHAR(u->us_passwdlen, outp);
518 BCOPY(u->us_passwd, outp, u->us_passwdlen);
520 output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
522 UPAPDEBUG((LOG_INFO, "pap_sauth: Sent id %d.", u->us_id));
524 TIMEOUT(upap_timeout, u, u->us_timeouttime);
526 u->us_clientstate = UPAPCS_AUTHREQ;
531 * upap_sresp - Send a response (ack or nak).
534 upap_sresp(u, code, id, msg, msglen)
543 outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
544 outp = outpacket_buf;
545 MAKEHEADER(outp, PPP_PAP);
549 PUTSHORT(outlen, outp);
550 PUTCHAR(msglen, outp);
551 BCOPY(msg, outp, msglen);
552 output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
554 UPAPDEBUG((LOG_INFO, "pap_sresp: Sent code %d, id %d.", code, id));
558 * upap_printpkt - print the contents of a PAP packet.
560 static char *upap_codenames[] = {
561 "AuthReq", "AuthAck", "AuthNak"
565 upap_printpkt(p, plen, printer, arg)
568 void (*printer) __P((void *, char *, ...));
572 int mlen, ulen, wlen;
573 char *user, *pwd, *msg;
576 if (plen < UPAP_HEADERLEN)
582 if (len < UPAP_HEADERLEN || len > plen)
585 if (code >= 1 && code <= sizeof(upap_codenames) / sizeof(char *))
586 printer(arg, " %s", upap_codenames[code-1]);
588 printer(arg, " code=0x%x", code);
589 printer(arg, " id=0x%x", id);
590 len -= UPAP_HEADERLEN;
599 if (len < ulen + wlen + 2)
601 user = (char *) (p + 1);
602 pwd = (char *) (p + ulen + 2);
603 p += ulen + wlen + 2;
604 len -= ulen + wlen + 2;
605 printer(arg, " user=");
606 print_string(user, ulen, printer, arg);
607 printer(arg, " password=");
608 print_string(pwd, wlen, printer, arg);
617 msg = (char *) (p + 1);
621 print_string(msg, mlen, printer, arg);
625 /* print the rest of the bytes in the packet */
626 for (; len > 0; --len) {
628 printer(arg, " %.2x", code);