Remove __P macros from src/usr.bin and src/usr.sbin.
[dragonfly.git] / usr.sbin / pppd / upap.c
1 /*
2  * upap.c - User/Password Authentication Protocol.
3  *
4  * Copyright (c) 1989 Carnegie Mellon University.
5  * All rights reserved.
6  *
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.
18  *
19  * $FreeBSD: src/usr.sbin/pppd/upap.c,v 1.8 1999/08/28 01:19:08 peter Exp $
20  * $DragonFly: src/usr.sbin/pppd/upap.c,v 1.3 2003/11/03 19:31:40 eirikn Exp $
21  */
22
23 /*
24  * TODO:
25  */
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #include <sys/time.h>
31 #include <syslog.h>
32
33 #include "pppd.h"
34 #include "upap.h"
35
36 /*
37  * Protocol entry points.
38  */
39 static void upap_init(int);
40 static void upap_lowerup(int);
41 static void upap_lowerdown(int);
42 static void upap_input(int, u_char *, int);
43 static void upap_protrej(int);
44 static int  upap_printpkt(u_char *, int,
45                                void (*)(void *, char *, ...), void *);
46
47 struct protent pap_protent = {
48     PPP_PAP,
49     upap_init,
50     upap_input,
51     upap_protrej,
52     upap_lowerup,
53     upap_lowerdown,
54     NULL,
55     NULL,
56     upap_printpkt,
57     NULL,
58     1,
59     "PAP",
60     NULL,
61     NULL,
62     NULL
63 };
64
65 upap_state upap[NUM_PPP];               /* UPAP state; one for each unit */
66
67 static void upap_timeout(void *);
68 static void upap_reqtimeout(void *);
69 static void upap_rauthreq(upap_state *, u_char *, int, int);
70 static void upap_rauthack(upap_state *, u_char *, int, int);
71 static void upap_rauthnak(upap_state *, u_char *, int, int);
72 static void upap_sauthreq(upap_state *);
73 static void upap_sresp(upap_state *, int, int, char *, int);
74
75
76 /*
77  * upap_init - Initialize a UPAP unit.
78  */
79 static void
80 upap_init(unit)
81     int unit;
82 {
83     upap_state *u = &upap[unit];
84
85     u->us_unit = unit;
86     u->us_user = NULL;
87     u->us_userlen = 0;
88     u->us_passwd = NULL;
89     u->us_passwdlen = 0;
90     u->us_clientstate = UPAPCS_INITIAL;
91     u->us_serverstate = UPAPSS_INITIAL;
92     u->us_id = 0;
93     u->us_timeouttime = UPAP_DEFTIMEOUT;
94     u->us_maxtransmits = 10;
95     u->us_reqtimeout = UPAP_DEFREQTIME;
96 }
97
98
99 /*
100  * upap_authwithpeer - Authenticate us with our peer (start client).
101  *
102  * Set new state and send authenticate's.
103  */
104 void
105 upap_authwithpeer(unit, user, password)
106     int unit;
107     char *user, *password;
108 {
109     upap_state *u = &upap[unit];
110
111     /* Save the username and password we're given */
112     u->us_user = user;
113     u->us_userlen = strlen(user);
114     u->us_passwd = password;
115     u->us_passwdlen = strlen(password);
116     u->us_transmits = 0;
117
118     /* Lower layer up yet? */
119     if (u->us_clientstate == UPAPCS_INITIAL ||
120         u->us_clientstate == UPAPCS_PENDING) {
121         u->us_clientstate = UPAPCS_PENDING;
122         return;
123     }
124
125     upap_sauthreq(u);                   /* Start protocol */
126 }
127
128
129 /*
130  * upap_authpeer - Authenticate our peer (start server).
131  *
132  * Set new state.
133  */
134 void
135 upap_authpeer(unit)
136     int unit;
137 {
138     upap_state *u = &upap[unit];
139
140     /* Lower layer up yet? */
141     if (u->us_serverstate == UPAPSS_INITIAL ||
142         u->us_serverstate == UPAPSS_PENDING) {
143         u->us_serverstate = UPAPSS_PENDING;
144         return;
145     }
146
147     u->us_serverstate = UPAPSS_LISTEN;
148     if (u->us_reqtimeout > 0)
149         TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
150 }
151
152
153 /*
154  * upap_timeout - Retransmission timer for sending auth-reqs expired.
155  */
156 static void
157 upap_timeout(arg)
158     void *arg;
159 {
160     upap_state *u = (upap_state *) arg;
161
162     if (u->us_clientstate != UPAPCS_AUTHREQ)
163         return;
164
165     if (u->us_transmits >= u->us_maxtransmits) {
166         /* give up in disgust */
167         syslog(LOG_ERR, "No response to PAP authenticate-requests");
168         u->us_clientstate = UPAPCS_BADAUTH;
169         auth_withpeer_fail(u->us_unit, PPP_PAP);
170         return;
171     }
172
173     upap_sauthreq(u);           /* Send Authenticate-Request */
174 }
175
176
177 /*
178  * upap_reqtimeout - Give up waiting for the peer to send an auth-req.
179  */
180 static void
181 upap_reqtimeout(arg)
182     void *arg;
183 {
184     upap_state *u = (upap_state *) arg;
185
186     if (u->us_serverstate != UPAPSS_LISTEN)
187         return;                 /* huh?? */
188
189     auth_peer_fail(u->us_unit, PPP_PAP);
190     u->us_serverstate = UPAPSS_BADAUTH;
191 }
192
193
194 /*
195  * upap_lowerup - The lower layer is up.
196  *
197  * Start authenticating if pending.
198  */
199 static void
200 upap_lowerup(unit)
201     int unit;
202 {
203     upap_state *u = &upap[unit];
204
205     if (u->us_clientstate == UPAPCS_INITIAL)
206         u->us_clientstate = UPAPCS_CLOSED;
207     else if (u->us_clientstate == UPAPCS_PENDING) {
208         upap_sauthreq(u);       /* send an auth-request */
209     }
210
211     if (u->us_serverstate == UPAPSS_INITIAL)
212         u->us_serverstate = UPAPSS_CLOSED;
213     else if (u->us_serverstate == UPAPSS_PENDING) {
214         u->us_serverstate = UPAPSS_LISTEN;
215         if (u->us_reqtimeout > 0)
216             TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
217     }
218 }
219
220
221 /*
222  * upap_lowerdown - The lower layer is down.
223  *
224  * Cancel all timeouts.
225  */
226 static void
227 upap_lowerdown(unit)
228     int unit;
229 {
230     upap_state *u = &upap[unit];
231
232     if (u->us_clientstate == UPAPCS_AUTHREQ)    /* Timeout pending? */
233         UNTIMEOUT(upap_timeout, u);             /* Cancel timeout */
234     if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0)
235         UNTIMEOUT(upap_reqtimeout, u);
236
237     u->us_clientstate = UPAPCS_INITIAL;
238     u->us_serverstate = UPAPSS_INITIAL;
239 }
240
241
242 /*
243  * upap_protrej - Peer doesn't speak this protocol.
244  *
245  * This shouldn't happen.  In any case, pretend lower layer went down.
246  */
247 static void
248 upap_protrej(unit)
249     int unit;
250 {
251     upap_state *u = &upap[unit];
252
253     if (u->us_clientstate == UPAPCS_AUTHREQ) {
254         syslog(LOG_ERR, "PAP authentication failed due to protocol-reject");
255         auth_withpeer_fail(unit, PPP_PAP);
256     }
257     if (u->us_serverstate == UPAPSS_LISTEN) {
258         syslog(LOG_ERR, "PAP authentication of peer failed (protocol-reject)");
259         auth_peer_fail(unit, PPP_PAP);
260     }
261     upap_lowerdown(unit);
262 }
263
264
265 /*
266  * upap_input - Input UPAP packet.
267  */
268 static void
269 upap_input(unit, inpacket, l)
270     int unit;
271     u_char *inpacket;
272     int l;
273 {
274     upap_state *u = &upap[unit];
275     u_char *inp;
276     u_char code, id;
277     int len;
278
279     /*
280      * Parse header (code, id and length).
281      * If packet too short, drop it.
282      */
283     inp = inpacket;
284     if (l < UPAP_HEADERLEN) {
285         UPAPDEBUG((LOG_INFO, "pap_input: rcvd short header."));
286         return;
287     }
288     GETCHAR(code, inp);
289     GETCHAR(id, inp);
290     GETSHORT(len, inp);
291     if (len < UPAP_HEADERLEN) {
292         UPAPDEBUG((LOG_INFO, "pap_input: rcvd illegal length."));
293         return;
294     }
295     if (len > l) {
296         UPAPDEBUG((LOG_INFO, "pap_input: rcvd short packet."));
297         return;
298     }
299     len -= UPAP_HEADERLEN;
300
301     /*
302      * Action depends on code.
303      */
304     switch (code) {
305     case UPAP_AUTHREQ:
306         upap_rauthreq(u, inp, id, len);
307         break;
308
309     case UPAP_AUTHACK:
310         upap_rauthack(u, inp, id, len);
311         break;
312
313     case UPAP_AUTHNAK:
314         upap_rauthnak(u, inp, id, len);
315         break;
316
317     default:                            /* XXX Need code reject */
318         break;
319     }
320 }
321
322
323 /*
324  * upap_rauth - Receive Authenticate.
325  */
326 static void
327 upap_rauthreq(u, inp, id, len)
328     upap_state *u;
329     u_char *inp;
330     int id;
331     int len;
332 {
333     u_char ruserlen, rpasswdlen;
334     char *ruser, *rpasswd;
335     int retcode;
336     char *msg;
337     int msglen;
338
339     UPAPDEBUG((LOG_INFO, "pap_rauth: Rcvd id %d.", id));
340
341     if (u->us_serverstate < UPAPSS_LISTEN)
342         return;
343
344     /*
345      * If we receive a duplicate authenticate-request, we are
346      * supposed to return the same status as for the first request.
347      */
348     if (u->us_serverstate == UPAPSS_OPEN) {
349         upap_sresp(u, UPAP_AUTHACK, id, "", 0); /* return auth-ack */
350         return;
351     }
352     if (u->us_serverstate == UPAPSS_BADAUTH) {
353         upap_sresp(u, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */
354         return;
355     }
356
357     /*
358      * Parse user/passwd.
359      */
360     if (len < sizeof (u_char)) {
361         UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet."));
362         return;
363     }
364     GETCHAR(ruserlen, inp);
365     len -= sizeof (u_char) + ruserlen + sizeof (u_char);
366     if (len < 0) {
367         UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet."));
368         return;
369     }
370     ruser = (char *) inp;
371     INCPTR(ruserlen, inp);
372     GETCHAR(rpasswdlen, inp);
373     if (len < rpasswdlen) {
374         UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet."));
375         return;
376     }
377     rpasswd = (char *) inp;
378
379     /*
380      * Check the username and password given.
381      */
382     retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
383                            rpasswdlen, &msg, &msglen);
384     BZERO(rpasswd, rpasswdlen);
385
386     upap_sresp(u, retcode, id, msg, msglen);
387
388     if (retcode == UPAP_AUTHACK) {
389         u->us_serverstate = UPAPSS_OPEN;
390         auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen);
391     } else {
392         u->us_serverstate = UPAPSS_BADAUTH;
393         auth_peer_fail(u->us_unit, PPP_PAP);
394     }
395
396     if (u->us_reqtimeout > 0)
397         UNTIMEOUT(upap_reqtimeout, u);
398 }
399
400
401 /*
402  * upap_rauthack - Receive Authenticate-Ack.
403  */
404 static void
405 upap_rauthack(u, inp, id, len)
406     upap_state *u;
407     u_char *inp;
408     int id;
409     int len;
410 {
411     u_char msglen;
412     char *msg;
413
414     UPAPDEBUG((LOG_INFO, "pap_rauthack: Rcvd id %d.", id));
415     if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
416         return;
417
418     /*
419      * Parse message.
420      */
421     if (len < sizeof (u_char)) {
422         UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet."));
423         return;
424     }
425     GETCHAR(msglen, inp);
426     len -= sizeof (u_char);
427     if (len < msglen) {
428         UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet."));
429         return;
430     }
431     msg = (char *) inp;
432     PRINTMSG(msg, msglen);
433
434     u->us_clientstate = UPAPCS_OPEN;
435
436     auth_withpeer_success(u->us_unit, PPP_PAP);
437 }
438
439
440 /*
441  * upap_rauthnak - Receive Authenticate-Nakk.
442  */
443 static void
444 upap_rauthnak(u, inp, id, len)
445     upap_state *u;
446     u_char *inp;
447     int id;
448     int len;
449 {
450     u_char msglen;
451     char *msg;
452
453     UPAPDEBUG((LOG_INFO, "pap_rauthnak: Rcvd id %d.", id));
454     if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
455         return;
456
457     /*
458      * Parse message.
459      */
460     if (len < sizeof (u_char)) {
461         UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet."));
462         return;
463     }
464     GETCHAR(msglen, inp);
465     len -= sizeof (u_char);
466     if (len < msglen) {
467         UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet."));
468         return;
469     }
470     msg = (char *) inp;
471     PRINTMSG(msg, msglen);
472
473     u->us_clientstate = UPAPCS_BADAUTH;
474
475     syslog(LOG_ERR, "PAP authentication failed");
476     auth_withpeer_fail(u->us_unit, PPP_PAP);
477 }
478
479
480 /*
481  * upap_sauthreq - Send an Authenticate-Request.
482  */
483 static void
484 upap_sauthreq(u)
485     upap_state *u;
486 {
487     u_char *outp;
488     int outlen;
489
490     outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) +
491         u->us_userlen + u->us_passwdlen;
492     outp = outpacket_buf;
493     
494     MAKEHEADER(outp, PPP_PAP);
495
496     PUTCHAR(UPAP_AUTHREQ, outp);
497     PUTCHAR(++u->us_id, outp);
498     PUTSHORT(outlen, outp);
499     PUTCHAR(u->us_userlen, outp);
500     BCOPY(u->us_user, outp, u->us_userlen);
501     INCPTR(u->us_userlen, outp);
502     PUTCHAR(u->us_passwdlen, outp);
503     BCOPY(u->us_passwd, outp, u->us_passwdlen);
504
505     output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
506
507     UPAPDEBUG((LOG_INFO, "pap_sauth: Sent id %d.", u->us_id));
508
509     TIMEOUT(upap_timeout, u, u->us_timeouttime);
510     ++u->us_transmits;
511     u->us_clientstate = UPAPCS_AUTHREQ;
512 }
513
514
515 /*
516  * upap_sresp - Send a response (ack or nak).
517  */
518 static void
519 upap_sresp(u, code, id, msg, msglen)
520     upap_state *u;
521     u_char code, id;
522     char *msg;
523     int msglen;
524 {
525     u_char *outp;
526     int outlen;
527
528     outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
529     outp = outpacket_buf;
530     MAKEHEADER(outp, PPP_PAP);
531
532     PUTCHAR(code, outp);
533     PUTCHAR(id, outp);
534     PUTSHORT(outlen, outp);
535     PUTCHAR(msglen, outp);
536     BCOPY(msg, outp, msglen);
537     output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
538
539     UPAPDEBUG((LOG_INFO, "pap_sresp: Sent code %d, id %d.", code, id));
540 }
541
542 /*
543  * upap_printpkt - print the contents of a PAP packet.
544  */
545 static char *upap_codenames[] = {
546     "AuthReq", "AuthAck", "AuthNak"
547 };
548
549 static int
550 upap_printpkt(p, plen, printer, arg)
551     u_char *p;
552     int plen;
553     void (*printer)(void *, char *, ...);
554     void *arg;
555 {
556     int code, id, len;
557     int mlen, ulen, wlen;
558     char *user, *pwd, *msg;
559     u_char *pstart;
560
561     if (plen < UPAP_HEADERLEN)
562         return 0;
563     pstart = p;
564     GETCHAR(code, p);
565     GETCHAR(id, p);
566     GETSHORT(len, p);
567     if (len < UPAP_HEADERLEN || len > plen)
568         return 0;
569
570     if (code >= 1 && code <= sizeof(upap_codenames) / sizeof(char *))
571         printer(arg, " %s", upap_codenames[code-1]);
572     else
573         printer(arg, " code=0x%x", code);
574     printer(arg, " id=0x%x", id);
575     len -= UPAP_HEADERLEN;
576     switch (code) {
577     case UPAP_AUTHREQ:
578         if (len < 1)
579             break;
580         ulen = p[0];
581         if (len < ulen + 2)
582             break;
583         wlen = p[ulen + 1];
584         if (len < ulen + wlen + 2)
585             break;
586         user = (char *) (p + 1);
587         pwd = (char *) (p + ulen + 2);
588         p += ulen + wlen + 2;
589         len -= ulen + wlen + 2;
590         printer(arg, " user=");
591         print_string(user, ulen, printer, arg);
592         printer(arg, " password=");
593         print_string(pwd, wlen, printer, arg);
594         break;
595     case UPAP_AUTHACK:
596     case UPAP_AUTHNAK:
597         if (len < 1)
598             break;
599         mlen = p[0];
600         if (len < mlen + 1)
601             break;
602         msg = (char *) (p + 1);
603         p += mlen + 1;
604         len -= mlen + 1;
605         printer(arg, " ");
606         print_string(msg, mlen, printer, arg);
607         break;
608     }
609
610     /* print the rest of the bytes in the packet */
611     for (; len > 0; --len) {
612         GETCHAR(code, p);
613         printer(arg, " %.2x", code);
614     }
615
616     return p - pstart;
617 }