Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / usr.sbin / ppp / auth.c
1 /*-
2  * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
3  *          based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
4  *                           Internet Initiative Japan, Inc (IIJ)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD: src/usr.sbin/ppp/auth.c,v 1.50.2.2 2002/09/01 02:12:22 brian Exp $
29  * $DragonFly: src/usr.sbin/ppp/auth.c,v 1.2 2003/06/17 04:30:00 dillon Exp $
30  */
31
32 #include <sys/param.h>
33 #include <netinet/in.h>
34 #include <netinet/in_systm.h>
35 #include <netinet/ip.h>
36 #include <sys/socket.h>
37 #include <sys/un.h>
38
39 #include <pwd.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <termios.h>
43 #include <unistd.h>
44
45 #include "layer.h"
46 #include "mbuf.h"
47 #include "defs.h"
48 #include "log.h"
49 #include "timer.h"
50 #include "fsm.h"
51 #include "iplist.h"
52 #include "throughput.h"
53 #include "slcompress.h"
54 #include "lqr.h"
55 #include "hdlc.h"
56 #include "ncpaddr.h"
57 #include "ipcp.h"
58 #include "auth.h"
59 #include "systems.h"
60 #include "lcp.h"
61 #include "ccp.h"
62 #include "link.h"
63 #include "descriptor.h"
64 #include "chat.h"
65 #include "proto.h"
66 #include "filter.h"
67 #include "mp.h"
68 #ifndef NORADIUS
69 #include "radius.h"
70 #endif
71 #include "cbcp.h"
72 #include "chap.h"
73 #include "async.h"
74 #include "physical.h"
75 #include "datalink.h"
76 #include "ipv6cp.h"
77 #include "ncp.h"
78 #include "bundle.h"
79
80 const char *
81 Auth2Nam(u_short auth, u_char type)
82 {
83   static char chap[10];
84
85   switch (auth) {
86   case PROTO_PAP:
87     return "PAP";
88   case PROTO_CHAP:
89     snprintf(chap, sizeof chap, "CHAP 0x%02x", type);
90     return chap;
91   case 0:
92     return "none";
93   }
94   return "unknown";
95 }
96
97 static int
98 auth_CheckPasswd(const char *name, const char *data, const char *key)
99 {
100   if (!strcmp(data, "*")) {
101     /* Then look up the real password database */
102     struct passwd *pw;
103     int result;
104
105     result = (pw = getpwnam(name)) &&
106              !strcmp(crypt(key, pw->pw_passwd), pw->pw_passwd);
107     endpwent();
108     return result;
109   }
110
111   return !strcmp(data, key);
112 }
113
114 int
115 auth_SetPhoneList(const char *name, char *phone, int phonelen)
116 {
117   FILE *fp;
118   int n, lineno;
119   char *vector[6], buff[LINE_LEN];
120   const char *slash;
121
122   fp = OpenSecret(SECRETFILE);
123   if (fp != NULL) {
124 again:
125     lineno = 0;
126     while (fgets(buff, sizeof buff, fp)) {
127       lineno++;
128       if (buff[0] == '#')
129         continue;
130       buff[strlen(buff) - 1] = '\0';
131       memset(vector, '\0', sizeof vector);
132       if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0)
133         log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno);
134       if (n < 5)
135         continue;
136       if (strcmp(vector[0], name) == 0) {
137         CloseSecret(fp);
138         if (*vector[4] == '\0')
139           return 0;
140         strncpy(phone, vector[4], phonelen - 1);
141         phone[phonelen - 1] = '\0';
142         return 1;               /* Valid */
143       }
144     }
145
146     if ((slash = strrchr(name, '\\')) != NULL && slash[1]) {
147       /* Look for the name without the leading domain */
148       name = slash + 1;
149       rewind(fp);
150       goto again;
151     }
152
153     CloseSecret(fp);
154   }
155   *phone = '\0';
156   return 0;
157 }
158
159 int
160 auth_Select(struct bundle *bundle, const char *name)
161 {
162   FILE *fp;
163   int n, lineno;
164   char *vector[5], buff[LINE_LEN];
165   const char *slash;
166
167   if (*name == '\0') {
168     ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE);
169     return 1;
170   }
171
172 #ifndef NORADIUS
173   if (bundle->radius.valid && bundle->radius.ip.s_addr != INADDR_NONE &&
174         bundle->radius.ip.s_addr != RADIUS_INADDR_POOL) {
175     /* We've got a radius IP - it overrides everything */
176     if (!ipcp_UseHisIPaddr(bundle, bundle->radius.ip))
177       return 0;
178     ipcp_Setup(&bundle->ncp.ipcp, bundle->radius.mask.s_addr);
179     /* Continue with ppp.secret in case we've got a new label */
180   }
181 #endif
182
183   fp = OpenSecret(SECRETFILE);
184   if (fp != NULL) {
185 again:
186     lineno = 0;
187     while (fgets(buff, sizeof buff, fp)) {
188       lineno++;
189       if (buff[0] == '#')
190         continue;
191       buff[strlen(buff) - 1] = '\0';
192       memset(vector, '\0', sizeof vector);
193       if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0)
194         log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno);
195       if (n < 2)
196         continue;
197       if (strcmp(vector[0], name) == 0) {
198         CloseSecret(fp);
199 #ifndef NORADIUS
200         if (!bundle->radius.valid || bundle->radius.ip.s_addr == INADDR_NONE) {
201 #endif
202           if (n > 2 && *vector[2] && strcmp(vector[2], "*") &&
203               !ipcp_UseHisaddr(bundle, vector[2], 1))
204             return 0;
205           ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE);
206 #ifndef NORADIUS
207         }
208 #endif
209         if (n > 3 && *vector[3] && strcmp(vector[3], "*"))
210           bundle_SetLabel(bundle, vector[3]);
211         return 1;               /* Valid */
212       }
213     }
214
215     if ((slash = strrchr(name, '\\')) != NULL && slash[1]) {
216       /* Look for the name without the leading domain */
217       name = slash + 1;
218       rewind(fp);
219       goto again;
220     }
221
222     CloseSecret(fp);
223   }
224
225 #ifndef NOPASSWDAUTH
226   /* Let 'em in anyway - they must have been in the passwd file */
227   ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE);
228   return 1;
229 #else
230 #ifndef NORADIUS
231   if (bundle->radius.valid)
232     return 1;
233 #endif
234
235   /* Disappeared from ppp.secret ??? */
236   return 0;
237 #endif
238 }
239
240 int
241 auth_Validate(struct bundle *bundle, const char *name,
242              const char *key, struct physical *physical)
243 {
244   /* Used by PAP routines */
245
246   FILE *fp;
247   int n, lineno;
248   char *vector[5], buff[LINE_LEN];
249   const char *slash;
250
251   fp = OpenSecret(SECRETFILE);
252 again:
253   lineno = 0;
254   if (fp != NULL) {
255     while (fgets(buff, sizeof buff, fp)) {
256       lineno++;
257       if (buff[0] == '#')
258         continue;
259       buff[strlen(buff) - 1] = 0;
260       memset(vector, '\0', sizeof vector);
261       if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0)
262         log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno);
263       if (n < 2)
264         continue;
265       if (strcmp(vector[0], name) == 0) {
266         CloseSecret(fp);
267         return auth_CheckPasswd(name, vector[1], key);
268       }
269     }
270   }
271
272   if ((slash = strrchr(name, '\\')) != NULL && slash[1]) {
273     /* Look for the name without the leading domain */
274     name = slash + 1;
275     if (fp != NULL) {
276       rewind(fp);
277       goto again;
278     }
279   }
280
281   if (fp != NULL)
282     CloseSecret(fp);
283
284 #ifndef NOPASSWDAUTH
285   if (Enabled(bundle, OPT_PASSWDAUTH))
286     return auth_CheckPasswd(name, "*", key);
287 #endif
288
289   return 0;                     /* Invalid */
290 }
291
292 char *
293 auth_GetSecret(struct bundle *bundle, const char *name, int len,
294               struct physical *physical)
295 {
296   /* Used by CHAP routines */
297
298   FILE *fp;
299   int n, lineno;
300   char *vector[5];
301   const char *slash;
302   static char buff[LINE_LEN];   /* vector[] will point here when returned */
303
304   fp = OpenSecret(SECRETFILE);
305   if (fp == NULL)
306     return (NULL);
307
308 again:
309   lineno = 0;
310   while (fgets(buff, sizeof buff, fp)) {
311     lineno++;
312     if (buff[0] == '#')
313       continue;
314     n = strlen(buff) - 1;
315     if (buff[n] == '\n')
316       buff[n] = '\0';   /* Trim the '\n' */
317     memset(vector, '\0', sizeof vector);
318     if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0)
319       log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno);
320     if (n < 2)
321       continue;
322     if (strlen(vector[0]) == len && strncmp(vector[0], name, len) == 0) {
323       CloseSecret(fp);
324       return vector[1];
325     }
326   }
327
328   if ((slash = strrchr(name, '\\')) != NULL && slash[1]) {
329     /* Go back and look for the name without the leading domain */
330     len -= slash - name + 1;
331     name = slash + 1;
332     rewind(fp);
333     goto again;
334   }
335
336   CloseSecret(fp);
337   return (NULL);                /* Invalid */
338 }
339
340 static void
341 AuthTimeout(void *vauthp)
342 {
343   struct authinfo *authp = (struct authinfo *)vauthp;
344
345   timer_Stop(&authp->authtimer);
346   if (--authp->retry > 0) {
347     authp->id++;
348     (*authp->fn.req)(authp);
349     timer_Start(&authp->authtimer);
350   } else {
351     log_Printf(LogPHASE, "Auth: No response from server\n");
352     datalink_AuthNotOk(authp->physical->dl);
353   }
354 }
355
356 void
357 auth_Init(struct authinfo *authp, struct physical *p, auth_func req,
358           auth_func success, auth_func failure)
359 {
360   memset(authp, '\0', sizeof(struct authinfo));
361   authp->cfg.fsm.timeout = DEF_FSMRETRY;
362   authp->cfg.fsm.maxreq = DEF_FSMAUTHTRIES;
363   authp->cfg.fsm.maxtrm = 0;    /* not used */
364   authp->fn.req = req;
365   authp->fn.success = success;
366   authp->fn.failure = failure;
367   authp->physical = p;
368 }
369
370 void
371 auth_StartReq(struct authinfo *authp)
372 {
373   timer_Stop(&authp->authtimer);
374   authp->authtimer.func = AuthTimeout;
375   authp->authtimer.name = "auth";
376   authp->authtimer.load = authp->cfg.fsm.timeout * SECTICKS;
377   authp->authtimer.arg = (void *)authp;
378   authp->retry = authp->cfg.fsm.maxreq;
379   authp->id = 1;
380   (*authp->fn.req)(authp);
381   timer_Start(&authp->authtimer);
382 }
383
384 void
385 auth_StopTimer(struct authinfo *authp)
386 {
387   timer_Stop(&authp->authtimer);
388 }
389
390 struct mbuf *
391 auth_ReadHeader(struct authinfo *authp, struct mbuf *bp)
392 {
393   int len;
394
395   len = m_length(bp);
396   if (len >= sizeof authp->in.hdr) {
397     bp = mbuf_Read(bp, (u_char *)&authp->in.hdr, sizeof authp->in.hdr);
398     if (len >= ntohs(authp->in.hdr.length))
399       return bp;
400     authp->in.hdr.length = htons(0);
401     log_Printf(LogWARN, "auth_ReadHeader: Short packet (%d > %d) !\n",
402                ntohs(authp->in.hdr.length), len);
403   } else {
404     authp->in.hdr.length = htons(0);
405     log_Printf(LogWARN, "auth_ReadHeader: Short packet header (%d > %d) !\n",
406                (int)(sizeof authp->in.hdr), len);
407   }
408
409   m_freem(bp);
410   return NULL;
411 }
412
413 struct mbuf *
414 auth_ReadName(struct authinfo *authp, struct mbuf *bp, int len)
415 {
416   if (len > sizeof authp->in.name - 1)
417     log_Printf(LogWARN, "auth_ReadName: Name too long (%d) !\n", len);
418   else {
419     int mlen = m_length(bp);
420
421     if (len > mlen)
422       log_Printf(LogWARN, "auth_ReadName: Short packet (%d > %d) !\n",
423                  len, mlen);
424     else {
425       bp = mbuf_Read(bp, (u_char *)authp->in.name, len);
426       authp->in.name[len] = '\0';
427       return bp;
428     }
429   }
430
431   *authp->in.name = '\0';
432   m_freem(bp);
433   return NULL;
434 }