xref: /freebsd/usr.sbin/ppp/auth.c (revision 1b6c76a2fe091c74f08427e6c870851025a9cf67)
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$
29  */
30 
31 #include <sys/param.h>
32 #include <netinet/in.h>
33 #include <netinet/in_systm.h>
34 #include <netinet/ip.h>
35 #include <sys/un.h>
36 
37 #include <pwd.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <termios.h>
41 #include <unistd.h>
42 
43 #include "layer.h"
44 #include "mbuf.h"
45 #include "defs.h"
46 #include "log.h"
47 #include "timer.h"
48 #include "fsm.h"
49 #include "iplist.h"
50 #include "throughput.h"
51 #include "slcompress.h"
52 #include "lqr.h"
53 #include "hdlc.h"
54 #include "ipcp.h"
55 #include "auth.h"
56 #include "systems.h"
57 #include "lcp.h"
58 #include "ccp.h"
59 #include "link.h"
60 #include "descriptor.h"
61 #include "chat.h"
62 #include "proto.h"
63 #include "filter.h"
64 #include "mp.h"
65 #ifndef NORADIUS
66 #include "radius.h"
67 #endif
68 #include "cbcp.h"
69 #include "chap.h"
70 #include "async.h"
71 #include "physical.h"
72 #include "datalink.h"
73 #include "bundle.h"
74 
75 const char *
76 Auth2Nam(u_short auth, u_char type)
77 {
78   static char chap[10];
79 
80   switch (auth) {
81   case PROTO_PAP:
82     return "PAP";
83   case PROTO_CHAP:
84     snprintf(chap, sizeof chap, "CHAP 0x%02x", type);
85     return chap;
86   case 0:
87     return "none";
88   }
89   return "unknown";
90 }
91 
92 static int
93 auth_CheckPasswd(const char *name, const char *data, const char *key)
94 {
95   if (!strcmp(data, "*")) {
96     /* Then look up the real password database */
97     struct passwd *pw;
98     int result;
99 
100     result = (pw = getpwnam(name)) &&
101              !strcmp(crypt(key, pw->pw_passwd), pw->pw_passwd);
102     endpwent();
103     return result;
104   }
105 
106   return !strcmp(data, key);
107 }
108 
109 int
110 auth_SetPhoneList(const char *name, char *phone, int phonelen)
111 {
112   FILE *fp;
113   int n, lineno;
114   char *vector[6];
115   char buff[LINE_LEN];
116 
117   fp = OpenSecret(SECRETFILE);
118   lineno = 0;
119   if (fp != NULL) {
120     while (fgets(buff, sizeof buff, fp)) {
121       lineno++;
122       if (buff[0] == '#')
123         continue;
124       buff[strlen(buff) - 1] = '\0';
125       memset(vector, '\0', sizeof vector);
126       if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0)
127         log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno);
128       if (n < 5)
129         continue;
130       if (strcmp(vector[0], name) == 0) {
131         CloseSecret(fp);
132         if (*vector[4] == '\0')
133           return 0;
134         strncpy(phone, vector[4], phonelen - 1);
135         phone[phonelen - 1] = '\0';
136         return 1;		/* Valid */
137       }
138     }
139     CloseSecret(fp);
140   }
141   *phone = '\0';
142   return 0;
143 }
144 
145 int
146 auth_Select(struct bundle *bundle, const char *name)
147 {
148   FILE *fp;
149   int n, lineno;
150   char *vector[5];
151   char buff[LINE_LEN];
152 
153   if (*name == '\0') {
154     ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE);
155     return 1;
156   }
157 
158 #ifndef NORADIUS
159   if (bundle->radius.valid && bundle->radius.ip.s_addr != INADDR_NONE) {
160     /* We've got a radius IP - it overrides everything */
161     if (!ipcp_UseHisIPaddr(bundle, bundle->radius.ip))
162       return 0;
163     ipcp_Setup(&bundle->ncp.ipcp, bundle->radius.mask.s_addr);
164     /* Continue with ppp.secret in case we've got a new label */
165   }
166 #endif
167 
168   fp = OpenSecret(SECRETFILE);
169   lineno = 0;
170   if (fp != NULL) {
171     while (fgets(buff, sizeof buff, fp)) {
172       lineno++;
173       if (buff[0] == '#')
174         continue;
175       buff[strlen(buff) - 1] = '\0';
176       memset(vector, '\0', sizeof vector);
177       if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0)
178         log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno);
179       if (n < 2)
180         continue;
181       if (strcmp(vector[0], name) == 0) {
182         CloseSecret(fp);
183 #ifndef NORADIUS
184         if (!bundle->radius.valid || bundle->radius.ip.s_addr == INADDR_NONE) {
185 #endif
186           if (n > 2 && *vector[2] && strcmp(vector[2], "*") &&
187               !ipcp_UseHisaddr(bundle, vector[2], 1))
188             return 0;
189           ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE);
190 #ifndef NORADIUS
191         }
192 #endif
193         if (n > 3 && *vector[3] && strcmp(vector[3], "*"))
194           bundle_SetLabel(bundle, vector[3]);
195         return 1;		/* Valid */
196       }
197     }
198     CloseSecret(fp);
199   }
200 
201 #ifndef NOPASSWDAUTH
202   /* Let 'em in anyway - they must have been in the passwd file */
203   ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE);
204   return 1;
205 #else
206 #ifndef NORADIUS
207   if (bundle->radius.valid)
208     return 1;
209 #endif
210 
211   /* Disappeared from ppp.secret ??? */
212   return 0;
213 #endif
214 }
215 
216 int
217 auth_Validate(struct bundle *bundle, const char *name,
218              const char *key, struct physical *physical)
219 {
220   /* Used by PAP routines */
221 
222   FILE *fp;
223   int n, lineno;
224   char *vector[5];
225   char buff[LINE_LEN];
226 
227   fp = OpenSecret(SECRETFILE);
228   lineno = 0;
229   if (fp != NULL) {
230     while (fgets(buff, sizeof buff, fp)) {
231       lineno++;
232       if (buff[0] == '#')
233         continue;
234       buff[strlen(buff) - 1] = 0;
235       memset(vector, '\0', sizeof vector);
236       if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0)
237         log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno);
238       if (n < 2)
239         continue;
240       if (strcmp(vector[0], name) == 0) {
241         CloseSecret(fp);
242         return auth_CheckPasswd(name, vector[1], key);
243       }
244     }
245     CloseSecret(fp);
246   }
247 
248 #ifndef NOPASSWDAUTH
249   if (Enabled(bundle, OPT_PASSWDAUTH))
250     return auth_CheckPasswd(name, "*", key);
251 #endif
252 
253   return 0;			/* Invalid */
254 }
255 
256 char *
257 auth_GetSecret(struct bundle *bundle, const char *name, int len,
258               struct physical *physical)
259 {
260   /* Used by CHAP routines */
261 
262   FILE *fp;
263   int n, lineno;
264   char *vector[5];
265   static char buff[LINE_LEN];	/* vector[] will point here when returned */
266 
267   fp = OpenSecret(SECRETFILE);
268   if (fp == NULL)
269     return (NULL);
270 
271   lineno = 0;
272   while (fgets(buff, sizeof buff, fp)) {
273     lineno++;
274     if (buff[0] == '#')
275       continue;
276     n = strlen(buff) - 1;
277     if (buff[n] == '\n')
278       buff[n] = '\0';	/* Trim the '\n' */
279     memset(vector, '\0', sizeof vector);
280     if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0)
281       log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno);
282     if (n < 2)
283       continue;
284     if (strlen(vector[0]) == len && strncmp(vector[0], name, len) == 0) {
285       CloseSecret(fp);
286       return vector[1];
287     }
288   }
289   CloseSecret(fp);
290   return (NULL);		/* Invalid */
291 }
292 
293 static void
294 AuthTimeout(void *vauthp)
295 {
296   struct authinfo *authp = (struct authinfo *)vauthp;
297 
298   timer_Stop(&authp->authtimer);
299   if (--authp->retry > 0) {
300     authp->id++;
301     (*authp->fn.req)(authp);
302     timer_Start(&authp->authtimer);
303   } else {
304     log_Printf(LogPHASE, "Auth: No response from server\n");
305     datalink_AuthNotOk(authp->physical->dl);
306   }
307 }
308 
309 void
310 auth_Init(struct authinfo *authp, struct physical *p, auth_func req,
311           auth_func success, auth_func failure)
312 {
313   memset(authp, '\0', sizeof(struct authinfo));
314   authp->cfg.fsm.timeout = DEF_FSMRETRY;
315   authp->cfg.fsm.maxreq = DEF_FSMAUTHTRIES;
316   authp->cfg.fsm.maxtrm = 0;	/* not used */
317   authp->fn.req = req;
318   authp->fn.success = success;
319   authp->fn.failure = failure;
320   authp->physical = p;
321 }
322 
323 void
324 auth_StartReq(struct authinfo *authp)
325 {
326   timer_Stop(&authp->authtimer);
327   authp->authtimer.func = AuthTimeout;
328   authp->authtimer.name = "auth";
329   authp->authtimer.load = authp->cfg.fsm.timeout * SECTICKS;
330   authp->authtimer.arg = (void *)authp;
331   authp->retry = authp->cfg.fsm.maxreq;
332   authp->id = 1;
333   (*authp->fn.req)(authp);
334   timer_Start(&authp->authtimer);
335 }
336 
337 void
338 auth_StopTimer(struct authinfo *authp)
339 {
340   timer_Stop(&authp->authtimer);
341 }
342 
343 struct mbuf *
344 auth_ReadHeader(struct authinfo *authp, struct mbuf *bp)
345 {
346   int len;
347 
348   len = m_length(bp);
349   if (len >= sizeof authp->in.hdr) {
350     bp = mbuf_Read(bp, (u_char *)&authp->in.hdr, sizeof authp->in.hdr);
351     if (len >= ntohs(authp->in.hdr.length))
352       return bp;
353     authp->in.hdr.length = htons(0);
354     log_Printf(LogWARN, "auth_ReadHeader: Short packet (%d > %d) !\n",
355                ntohs(authp->in.hdr.length), len);
356   } else {
357     authp->in.hdr.length = htons(0);
358     log_Printf(LogWARN, "auth_ReadHeader: Short packet header (%d > %d) !\n",
359                (int)(sizeof authp->in.hdr), len);
360   }
361 
362   m_freem(bp);
363   return NULL;
364 }
365 
366 struct mbuf *
367 auth_ReadName(struct authinfo *authp, struct mbuf *bp, int len)
368 {
369   if (len > sizeof authp->in.name - 1)
370     log_Printf(LogWARN, "auth_ReadName: Name too long (%d) !\n", len);
371   else {
372     int mlen = m_length(bp);
373 
374     if (len > mlen)
375       log_Printf(LogWARN, "auth_ReadName: Short packet (%d > %d) !\n",
376                  len, mlen);
377     else {
378       bp = mbuf_Read(bp, (u_char *)authp->in.name, len);
379       authp->in.name[len] = '\0';
380       return bp;
381     }
382   }
383 
384   *authp->in.name = '\0';
385   m_freem(bp);
386   return NULL;
387 }
388