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 87const char * 88Auth2Nam(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) 105static int 106pam_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 121static int 122auth_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 169int 170auth_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) { 179again: 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 214int 215auth_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) { 240again: 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 295int 296auth_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); 306again: 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 346char * 347auth_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 361again: 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 393static void 394AuthTimeout(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 409void 410auth_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 423void 424auth_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 437void 438auth_StopTimer(struct authinfo *authp) 439{ 440 timer_Stop(&authp->authtimer); 441} 442 443struct mbuf * 444auth_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 466struct mbuf * 467auth_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