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