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