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