xref: /dragonfly/usr.sbin/ppp/auth.c (revision 335b9e93)
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   struct passwd *pw;
101   int result = 0;
102   char *cryptpw;
103 
104   if (!strcmp(data, "*")) {
105     /* Then look up the real password database */
106     pw = getpwnam(name);
107 
108     if (pw) {
109       cryptpw = crypt(key, pw->pw_passwd);
110 
111       result = (cryptpw != NULL) && !strcmp(cryptpw, pw->pw_passwd);
112     }
113 
114     endpwent();
115 
116     return result;
117   }
118 
119   return !strcmp(data, key);
120 }
121 
122 int
123 auth_SetPhoneList(const char *name, char *phone, int phonelen)
124 {
125   FILE *fp;
126   int n, lineno;
127   char *vector[6], buff[LINE_LEN];
128   const char *slash;
129 
130   fp = OpenSecret(SECRETFILE);
131   if (fp != NULL) {
132 again:
133     lineno = 0;
134     while (fgets(buff, sizeof buff, fp)) {
135       lineno++;
136       if (buff[0] == '#')
137         continue;
138       buff[strlen(buff) - 1] = '\0';
139       memset(vector, '\0', sizeof vector);
140       if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0)
141         log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno);
142       if (n < 5)
143         continue;
144       if (strcmp(vector[0], name) == 0) {
145         CloseSecret(fp);
146         if (*vector[4] == '\0')
147           return 0;
148         strncpy(phone, vector[4], phonelen - 1);
149         phone[phonelen - 1] = '\0';
150         return 1;		/* Valid */
151       }
152     }
153 
154     if ((slash = strrchr(name, '\\')) != NULL && slash[1]) {
155       /* Look for the name without the leading domain */
156       name = slash + 1;
157       rewind(fp);
158       goto again;
159     }
160 
161     CloseSecret(fp);
162   }
163   *phone = '\0';
164   return 0;
165 }
166 
167 int
168 auth_Select(struct bundle *bundle, const char *name)
169 {
170   FILE *fp;
171   int n, lineno;
172   char *vector[5], buff[LINE_LEN];
173   const char *slash;
174 
175   if (*name == '\0') {
176     ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE);
177     return 1;
178   }
179 
180 #ifndef NORADIUS
181   if (bundle->radius.valid && bundle->radius.ip.s_addr != INADDR_NONE &&
182 	bundle->radius.ip.s_addr != RADIUS_INADDR_POOL) {
183     /* We've got a radius IP - it overrides everything */
184     if (!ipcp_UseHisIPaddr(bundle, bundle->radius.ip))
185       return 0;
186     ipcp_Setup(&bundle->ncp.ipcp, bundle->radius.mask.s_addr);
187     /* Continue with ppp.secret in case we've got a new label */
188   }
189 #endif
190 
191   fp = OpenSecret(SECRETFILE);
192   if (fp != NULL) {
193 again:
194     lineno = 0;
195     while (fgets(buff, sizeof buff, fp)) {
196       lineno++;
197       if (buff[0] == '#')
198         continue;
199       buff[strlen(buff) - 1] = '\0';
200       memset(vector, '\0', sizeof vector);
201       if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0)
202         log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno);
203       if (n < 2)
204         continue;
205       if (strcmp(vector[0], name) == 0) {
206         CloseSecret(fp);
207 #ifndef NORADIUS
208         if (!bundle->radius.valid || bundle->radius.ip.s_addr == INADDR_NONE) {
209 #endif
210           if (n > 2 && *vector[2] && strcmp(vector[2], "*") &&
211               !ipcp_UseHisaddr(bundle, vector[2], 1))
212             return 0;
213           ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE);
214 #ifndef NORADIUS
215         }
216 #endif
217         if (n > 3 && *vector[3] && strcmp(vector[3], "*"))
218           bundle_SetLabel(bundle, vector[3]);
219         return 1;		/* Valid */
220       }
221     }
222 
223     if ((slash = strrchr(name, '\\')) != NULL && slash[1]) {
224       /* Look for the name without the leading domain */
225       name = slash + 1;
226       rewind(fp);
227       goto again;
228     }
229 
230     CloseSecret(fp);
231   }
232 
233 #ifndef NOPASSWDAUTH
234   /* Let 'em in anyway - they must have been in the passwd file */
235   ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE);
236   return 1;
237 #else
238 #ifndef NORADIUS
239   if (bundle->radius.valid)
240     return 1;
241 #endif
242 
243   /* Disappeared from ppp.secret ??? */
244   return 0;
245 #endif
246 }
247 
248 int
249 auth_Validate(struct bundle *bundle, const char *name, const char *key)
250 {
251   /* Used by PAP routines */
252 
253   FILE *fp;
254   int n, lineno;
255   char *vector[5], buff[LINE_LEN];
256   const char *slash;
257 
258   fp = OpenSecret(SECRETFILE);
259 again:
260   lineno = 0;
261   if (fp != NULL) {
262     while (fgets(buff, sizeof buff, fp)) {
263       lineno++;
264       if (buff[0] == '#')
265         continue;
266       buff[strlen(buff) - 1] = 0;
267       memset(vector, '\0', sizeof vector);
268       if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0)
269         log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno);
270       if (n < 2)
271         continue;
272       if (strcmp(vector[0], name) == 0) {
273         CloseSecret(fp);
274         return auth_CheckPasswd(name, vector[1], key);
275       }
276     }
277   }
278 
279   if ((slash = strrchr(name, '\\')) != NULL && slash[1]) {
280     /* Look for the name without the leading domain */
281     name = slash + 1;
282     if (fp != NULL) {
283       rewind(fp);
284       goto again;
285     }
286   }
287 
288   if (fp != NULL)
289     CloseSecret(fp);
290 
291 #ifndef NOPASSWDAUTH
292   if (Enabled(bundle, OPT_PASSWDAUTH))
293     return auth_CheckPasswd(name, "*", key);
294 #endif
295 
296   return 0;			/* Invalid */
297 }
298 
299 char *
300 auth_GetSecret(const char *name, size_t len)
301 {
302   /* Used by CHAP routines */
303 
304   FILE *fp;
305   int n, lineno;
306   char *vector[5];
307   const char *slash;
308   static char buff[LINE_LEN];	/* vector[] will point here when returned */
309 
310   fp = OpenSecret(SECRETFILE);
311   if (fp == NULL)
312     return (NULL);
313 
314 again:
315   lineno = 0;
316   while (fgets(buff, sizeof buff, fp)) {
317     lineno++;
318     if (buff[0] == '#')
319       continue;
320     n = strlen(buff) - 1;
321     if (buff[n] == '\n')
322       buff[n] = '\0';	/* Trim the '\n' */
323     memset(vector, '\0', sizeof vector);
324     if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0)
325       log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno);
326     if (n < 2)
327       continue;
328     if (strlen(vector[0]) == len && strncmp(vector[0], name, len) == 0) {
329       CloseSecret(fp);
330       return vector[1];
331     }
332   }
333 
334   if ((slash = strrchr(name, '\\')) != NULL && slash[1]) {
335     /* Go back and look for the name without the leading domain */
336     len -= slash - name + 1;
337     name = slash + 1;
338     rewind(fp);
339     goto again;
340   }
341 
342   CloseSecret(fp);
343   return (NULL);		/* Invalid */
344 }
345 
346 static void
347 AuthTimeout(void *vauthp)
348 {
349   struct authinfo *authp = (struct authinfo *)vauthp;
350 
351   timer_Stop(&authp->authtimer);
352   if (--authp->retry > 0) {
353     authp->id++;
354     (*authp->fn.req)(authp);
355     timer_Start(&authp->authtimer);
356   } else {
357     log_Printf(LogPHASE, "Auth: No response from server\n");
358     datalink_AuthNotOk(authp->physical->dl);
359   }
360 }
361 
362 void
363 auth_Init(struct authinfo *authp, struct physical *p, auth_func req,
364           auth_func success, auth_func failure)
365 {
366   memset(authp, '\0', sizeof(struct authinfo));
367   authp->cfg.fsm.timeout = DEF_FSMRETRY;
368   authp->cfg.fsm.maxreq = DEF_FSMAUTHTRIES;
369   authp->cfg.fsm.maxtrm = 0;	/* not used */
370   authp->fn.req = req;
371   authp->fn.success = success;
372   authp->fn.failure = failure;
373   authp->physical = p;
374 }
375 
376 void
377 auth_StartReq(struct authinfo *authp)
378 {
379   timer_Stop(&authp->authtimer);
380   authp->authtimer.func = AuthTimeout;
381   authp->authtimer.name = "auth";
382   authp->authtimer.load = authp->cfg.fsm.timeout * SECTICKS;
383   authp->authtimer.arg = (void *)authp;
384   authp->retry = authp->cfg.fsm.maxreq;
385   authp->id = 1;
386   (*authp->fn.req)(authp);
387   timer_Start(&authp->authtimer);
388 }
389 
390 void
391 auth_StopTimer(struct authinfo *authp)
392 {
393   timer_Stop(&authp->authtimer);
394 }
395 
396 struct mbuf *
397 auth_ReadHeader(struct authinfo *authp, struct mbuf *bp)
398 {
399   size_t len;
400 
401   len = m_length(bp);
402   if (len >= sizeof authp->in.hdr) {
403     bp = mbuf_Read(bp, (u_char *)&authp->in.hdr, sizeof authp->in.hdr);
404     if (len >= ntohs(authp->in.hdr.length))
405       return bp;
406     authp->in.hdr.length = htons(0);
407     log_Printf(LogWARN, "auth_ReadHeader: Short packet (%u > %zu) !\n",
408                ntohs(authp->in.hdr.length), len);
409   } else {
410     authp->in.hdr.length = htons(0);
411     log_Printf(LogWARN, "auth_ReadHeader: Short packet header (%u > %zu) !\n",
412                (int)(sizeof authp->in.hdr), len);
413   }
414 
415   m_freem(bp);
416   return NULL;
417 }
418 
419 struct mbuf *
420 auth_ReadName(struct authinfo *authp, struct mbuf *bp, size_t len)
421 {
422   if (len > sizeof authp->in.name - 1)
423     log_Printf(LogWARN, "auth_ReadName: Name too long (%zu) !\n", len);
424   else {
425     size_t mlen = m_length(bp);
426 
427     if (len > mlen)
428       log_Printf(LogWARN, "auth_ReadName: Short packet (%zu > %zu) !\n",
429                  len, mlen);
430     else {
431       bp = mbuf_Read(bp, (u_char *)authp->in.name, len);
432       authp->in.name[len] = '\0';
433       return bp;
434     }
435   }
436 
437   *authp->in.name = '\0';
438   m_freem(bp);
439   return NULL;
440 }
441