1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 * $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 * 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 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 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 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 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 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 * 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 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 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 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 440 auth_StopTimer(struct authinfo *authp) 441 { 442 timer_Stop(&authp->authtimer); 443 } 444 445 struct mbuf * 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 * 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