1 /*****************************************************************************
\r
2 * pap.c - Network Password Authentication Protocol program file.
\r
4 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
\r
5 * portions Copyright (c) 1997 by Global Election Systems Inc.
\r
7 * The authors hereby grant permission to use, copy, modify, distribute,
\r
8 * and license this software and its documentation for any purpose, provided
\r
9 * that existing copyright notices are retained in all copies and that this
\r
10 * notice and the following disclaimer are included verbatim in any
\r
11 * distributions. No written agreement, license, or royalty fee is required
\r
12 * for any of the authorized uses.
\r
14 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
\r
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
\r
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
\r
17 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
\r
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
\r
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
\r
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
\r
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
\r
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
\r
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
25 ******************************************************************************
\r
28 * 03-01-01 Marc Boucher <marc@mbsi.ca>
\r
30 * 97-12-12 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
\r
32 *****************************************************************************/
\r
34 * upap.c - User/Password Authentication Protocol.
\r
36 * Copyright (c) 1989 Carnegie Mellon University.
\r
37 * All rights reserved.
\r
39 * Redistribution and use in source and binary forms are permitted
\r
40 * provided that the above copyright notice and this paragraph are
\r
41 * duplicated in all such forms and that any documentation,
\r
42 * advertising materials, and other materials related to such
\r
43 * distribution and use acknowledge that the software was developed
\r
44 * by Carnegie Mellon University. The name of the
\r
45 * University may not be used to endorse or promote products derived
\r
46 * from this software without specific prior written permission.
\r
47 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
\r
48 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
\r
49 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
\r
55 #include "pppdebug.h"
\r
60 /***********************************/
\r
61 /*** LOCAL FUNCTION DECLARATIONS ***/
\r
62 /***********************************/
\r
64 * Protocol entry points.
\r
66 static void upap_init (int);
\r
67 static void upap_lowerup (int);
\r
68 static void upap_lowerdown (int);
\r
69 static void upap_input (int, u_char *, int);
\r
70 static void upap_protrej (int);
\r
72 static void upap_timeout (void *);
\r
73 static void upap_reqtimeout (void *);
\r
74 static void upap_rauthreq (upap_state *, u_char *, int, int);
\r
75 static void upap_rauthack (upap_state *, u_char *, int, int);
\r
76 static void upap_rauthnak (upap_state *, u_char *, int, int);
\r
77 static void upap_sauthreq (upap_state *);
\r
78 static void upap_sresp (upap_state *, u_char, u_char, char *, int);
\r
83 /******************************/
\r
84 /*** PUBLIC DATA STRUCTURES ***/
\r
85 /******************************/
\r
86 struct protent pap_protent = {
\r
108 upap_state upap[NUM_PPP]; /* UPAP state; one for each unit */
\r
112 /***********************************/
\r
113 /*** PUBLIC FUNCTION DEFINITIONS ***/
\r
114 /***********************************/
\r
116 * Set the default login name and password for the pap sessions
\r
118 void upap_setloginpasswd(int unit, const char *luser, const char *lpassword)
\r
120 upap_state *u = &upap[unit];
\r
122 /* Save the username and password we're given */
\r
123 u->us_user = luser;
\r
124 u->us_userlen = strlen(luser);
\r
125 u->us_passwd = lpassword;
\r
126 u->us_passwdlen = strlen(lpassword);
\r
131 * upap_authwithpeer - Authenticate us with our peer (start client).
\r
133 * Set new state and send authenticate's.
\r
135 void upap_authwithpeer(int unit, char *user, char *password)
\r
137 upap_state *u = &upap[unit];
\r
139 UPAPDEBUG((LOG_INFO, "upap_authwithpeer: %d user=%s password=%s s=%d\n",
\r
140 unit, user, password, u->us_clientstate));
\r
142 upap_setloginpasswd(unit, user, password);
\r
144 u->us_transmits = 0;
\r
146 /* Lower layer up yet? */
\r
147 if (u->us_clientstate == UPAPCS_INITIAL ||
\r
148 u->us_clientstate == UPAPCS_PENDING) {
\r
149 u->us_clientstate = UPAPCS_PENDING;
\r
153 upap_sauthreq(u); /* Start protocol */
\r
158 * upap_authpeer - Authenticate our peer (start server).
\r
162 void upap_authpeer(int unit)
\r
164 upap_state *u = &upap[unit];
\r
166 /* Lower layer up yet? */
\r
167 if (u->us_serverstate == UPAPSS_INITIAL ||
\r
168 u->us_serverstate == UPAPSS_PENDING) {
\r
169 u->us_serverstate = UPAPSS_PENDING;
\r
173 u->us_serverstate = UPAPSS_LISTEN;
\r
174 if (u->us_reqtimeout > 0)
\r
175 TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
\r
180 /**********************************/
\r
181 /*** LOCAL FUNCTION DEFINITIONS ***/
\r
182 /**********************************/
\r
184 * upap_init - Initialize a UPAP unit.
\r
186 static void upap_init(int unit)
\r
188 upap_state *u = &upap[unit];
\r
190 UPAPDEBUG((LOG_INFO, "upap_init: %d\n", unit));
\r
194 u->us_passwd = NULL;
\r
195 u->us_passwdlen = 0;
\r
196 u->us_clientstate = UPAPCS_INITIAL;
\r
197 u->us_serverstate = UPAPSS_INITIAL;
\r
199 u->us_timeouttime = UPAP_DEFTIMEOUT;
\r
200 u->us_maxtransmits = 10;
\r
201 u->us_reqtimeout = UPAP_DEFREQTIME;
\r
205 * upap_timeout - Retransmission timer for sending auth-reqs expired.
\r
207 static void upap_timeout(void *arg)
\r
209 upap_state *u = (upap_state *) arg;
\r
211 UPAPDEBUG((LOG_INFO, "upap_timeout: %d timeout %d expired s=%d\n",
\r
212 u->us_unit, u->us_timeouttime, u->us_clientstate));
\r
214 if (u->us_clientstate != UPAPCS_AUTHREQ)
\r
217 if (u->us_transmits >= u->us_maxtransmits) {
\r
218 /* give up in disgust */
\r
219 UPAPDEBUG((LOG_ERR, "No response to PAP authenticate-requests\n"));
\r
220 u->us_clientstate = UPAPCS_BADAUTH;
\r
221 auth_withpeer_fail(u->us_unit, PPP_PAP);
\r
225 upap_sauthreq(u); /* Send Authenticate-Request */
\r
230 * upap_reqtimeout - Give up waiting for the peer to send an auth-req.
\r
232 static void upap_reqtimeout(void *arg)
\r
234 upap_state *u = (upap_state *) arg;
\r
236 if (u->us_serverstate != UPAPSS_LISTEN)
\r
237 return; /* huh?? */
\r
239 auth_peer_fail(u->us_unit, PPP_PAP);
\r
240 u->us_serverstate = UPAPSS_BADAUTH;
\r
245 * upap_lowerup - The lower layer is up.
\r
247 * Start authenticating if pending.
\r
249 static void upap_lowerup(int unit)
\r
251 upap_state *u = &upap[unit];
\r
253 UPAPDEBUG((LOG_INFO, "upap_lowerup: %d s=%d\n", unit, u->us_clientstate));
\r
255 if (u->us_clientstate == UPAPCS_INITIAL)
\r
256 u->us_clientstate = UPAPCS_CLOSED;
\r
257 else if (u->us_clientstate == UPAPCS_PENDING) {
\r
258 upap_sauthreq(u); /* send an auth-request */
\r
261 if (u->us_serverstate == UPAPSS_INITIAL)
\r
262 u->us_serverstate = UPAPSS_CLOSED;
\r
263 else if (u->us_serverstate == UPAPSS_PENDING) {
\r
264 u->us_serverstate = UPAPSS_LISTEN;
\r
265 if (u->us_reqtimeout > 0)
\r
266 TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
\r
272 * upap_lowerdown - The lower layer is down.
\r
274 * Cancel all timeouts.
\r
276 static void upap_lowerdown(int unit)
\r
278 upap_state *u = &upap[unit];
\r
280 UPAPDEBUG((LOG_INFO, "upap_lowerdown: %d s=%d\n", unit, u->us_clientstate));
\r
282 if (u->us_clientstate == UPAPCS_AUTHREQ) /* Timeout pending? */
\r
283 UNTIMEOUT(upap_timeout, u); /* Cancel timeout */
\r
284 if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0)
\r
285 UNTIMEOUT(upap_reqtimeout, u);
\r
287 u->us_clientstate = UPAPCS_INITIAL;
\r
288 u->us_serverstate = UPAPSS_INITIAL;
\r
293 * upap_protrej - Peer doesn't speak this protocol.
\r
295 * This shouldn't happen. In any case, pretend lower layer went down.
\r
297 static void upap_protrej(int unit)
\r
299 upap_state *u = &upap[unit];
\r
301 if (u->us_clientstate == UPAPCS_AUTHREQ) {
\r
302 UPAPDEBUG((LOG_ERR, "PAP authentication failed due to protocol-reject\n"));
\r
303 auth_withpeer_fail(unit, PPP_PAP);
\r
305 if (u->us_serverstate == UPAPSS_LISTEN) {
\r
306 UPAPDEBUG((LOG_ERR, "PAP authentication of peer failed (protocol-reject)\n"));
\r
307 auth_peer_fail(unit, PPP_PAP);
\r
309 upap_lowerdown(unit);
\r
314 * upap_input - Input UPAP packet.
\r
316 static void upap_input(int unit, u_char *inpacket, int l)
\r
318 upap_state *u = &upap[unit];
\r
324 * Parse header (code, id and length).
\r
325 * If packet too short, drop it.
\r
328 if (l < UPAP_HEADERLEN) {
\r
329 UPAPDEBUG((LOG_INFO, "pap_input: rcvd short header.\n"));
\r
332 GETCHAR(code, inp);
\r
334 GETSHORT(len, inp);
\r
335 if (len < UPAP_HEADERLEN) {
\r
336 UPAPDEBUG((LOG_INFO, "pap_input: rcvd illegal length.\n"));
\r
340 UPAPDEBUG((LOG_INFO, "pap_input: rcvd short packet.\n"));
\r
343 len -= UPAP_HEADERLEN;
\r
346 * Action depends on code.
\r
350 upap_rauthreq(u, inp, id, len);
\r
354 upap_rauthack(u, inp, id, len);
\r
358 upap_rauthnak(u, inp, id, len);
\r
361 default: /* XXX Need code reject */
\r
368 * upap_rauth - Receive Authenticate.
\r
370 static void upap_rauthreq(
\r
377 u_char ruserlen, rpasswdlen;
\r
378 char *ruser, *rpasswd;
\r
383 UPAPDEBUG((LOG_INFO, "pap_rauth: Rcvd id %d.\n", id));
\r
385 if (u->us_serverstate < UPAPSS_LISTEN)
\r
389 * If we receive a duplicate authenticate-request, we are
\r
390 * supposed to return the same status as for the first request.
\r
392 if (u->us_serverstate == UPAPSS_OPEN) {
\r
393 upap_sresp(u, UPAP_AUTHACK, id, "", 0); /* return auth-ack */
\r
396 if (u->us_serverstate == UPAPSS_BADAUTH) {
\r
397 upap_sresp(u, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */
\r
402 * Parse user/passwd.
\r
404 if (len < sizeof (u_char)) {
\r
405 UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n"));
\r
408 GETCHAR(ruserlen, inp);
\r
409 len -= sizeof (u_char) + ruserlen + sizeof (u_char);
\r
411 UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n"));
\r
414 ruser = (char *) inp;
\r
415 INCPTR(ruserlen, inp);
\r
416 GETCHAR(rpasswdlen, inp);
\r
417 if (len < rpasswdlen) {
\r
418 UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n"));
\r
421 rpasswd = (char *) inp;
\r
424 * Check the username and password given.
\r
426 retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
\r
427 rpasswdlen, &msg, &msglen);
\r
428 BZERO(rpasswd, rpasswdlen);
\r
430 upap_sresp(u, retcode, id, msg, msglen);
\r
432 if (retcode == UPAP_AUTHACK) {
\r
433 u->us_serverstate = UPAPSS_OPEN;
\r
434 auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen);
\r
436 u->us_serverstate = UPAPSS_BADAUTH;
\r
437 auth_peer_fail(u->us_unit, PPP_PAP);
\r
440 if (u->us_reqtimeout > 0)
\r
441 UNTIMEOUT(upap_reqtimeout, u);
\r
446 * upap_rauthack - Receive Authenticate-Ack.
\r
448 static void upap_rauthack(
\r
458 UPAPDEBUG((LOG_INFO, "pap_rauthack: Rcvd id %d s=%d\n", id, u->us_clientstate));
\r
460 if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
\r
466 if (len < sizeof (u_char)) {
\r
467 UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet.\n"));
\r
470 GETCHAR(msglen, inp);
\r
471 len -= sizeof (u_char);
\r
472 if (len < msglen) {
\r
473 UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet.\n"));
\r
476 msg = (char *) inp;
\r
477 PRINTMSG(msg, msglen);
\r
479 u->us_clientstate = UPAPCS_OPEN;
\r
481 auth_withpeer_success(u->us_unit, PPP_PAP);
\r
486 * upap_rauthnak - Receive Authenticate-Nakk.
\r
488 static void upap_rauthnak(
\r
498 UPAPDEBUG((LOG_INFO, "pap_rauthnak: Rcvd id %d s=%d\n", id, u->us_clientstate));
\r
500 if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
\r
506 if (len < sizeof (u_char)) {
\r
507 UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n"));
\r
510 GETCHAR(msglen, inp);
\r
511 len -= sizeof (u_char);
\r
512 if (len < msglen) {
\r
513 UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n"));
\r
516 msg = (char *) inp;
\r
517 PRINTMSG(msg, msglen);
\r
519 u->us_clientstate = UPAPCS_BADAUTH;
\r
521 UPAPDEBUG((LOG_ERR, "PAP authentication failed\n"));
\r
522 auth_withpeer_fail(u->us_unit, PPP_PAP);
\r
527 * upap_sauthreq - Send an Authenticate-Request.
\r
529 static void upap_sauthreq(upap_state *u)
\r
534 outlen = UPAP_HEADERLEN + 2 * sizeof (u_char)
\r
535 + u->us_userlen + u->us_passwdlen;
\r
536 outp = outpacket_buf[u->us_unit];
\r
538 MAKEHEADER(outp, PPP_PAP);
\r
540 PUTCHAR(UPAP_AUTHREQ, outp);
\r
541 PUTCHAR(++u->us_id, outp);
\r
542 PUTSHORT(outlen, outp);
\r
543 PUTCHAR(u->us_userlen, outp);
\r
544 BCOPY(u->us_user, outp, u->us_userlen);
\r
545 INCPTR(u->us_userlen, outp);
\r
546 PUTCHAR(u->us_passwdlen, outp);
\r
547 BCOPY(u->us_passwd, outp, u->us_passwdlen);
\r
549 pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN);
\r
551 UPAPDEBUG((LOG_INFO, "pap_sauth: Sent id %d\n", u->us_id));
\r
553 TIMEOUT(upap_timeout, u, u->us_timeouttime);
\r
555 u->us_clientstate = UPAPCS_AUTHREQ;
\r
560 * upap_sresp - Send a response (ack or nak).
\r
562 static void upap_sresp(
\r
573 outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
\r
574 outp = outpacket_buf[u->us_unit];
\r
575 MAKEHEADER(outp, PPP_PAP);
\r
577 PUTCHAR(code, outp);
\r
579 PUTSHORT(outlen, outp);
\r
580 PUTCHAR(msglen, outp);
\r
581 BCOPY(msg, outp, msglen);
\r
582 pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN);
\r
584 UPAPDEBUG((LOG_INFO, "pap_sresp: Sent code %d, id %d s=%d\n",
\r
585 code, id, u->us_clientstate));
\r
590 * upap_printpkt - print the contents of a PAP packet.
\r
592 static int upap_printpkt(
\r
595 void (*printer) (void *, char *, ...),
\r
607 #endif /* PAP_SUPPORT */
\r