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