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: stable/11/usr.sbin/ppp/auth.c 330449 2018-03-05 07:26:05Z eadler $ 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 89const char * 90Auth2Nam(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) 107static int 108pam_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 123static int 124auth_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; 131 char *cryptpw; 132 133 cryptpw = crypt(key, pw->pw_passwd); 134 result = (pw = getpwnam(name)) && 135 (cryptpw == NULL || !strcmp(cryptpw, pw->pw_passwd)); 136 endpwent(); 137 return result; 138#else /* !NOPAM */ 139 /* Then consult with PAM. */ 140 pam_handle_t *pamh; 141 int status; 142 143 struct pam_conv pamc = { 144#ifdef OPENPAM 145 &openpam_nullconv, NULL 146#else 147 &pam_conv, key 148#endif 149 }; 150 151 if (pam_start("ppp", name, &pamc, &pamh) != PAM_SUCCESS) 152 return (0); 153#ifdef OPENPAM 154 if ((status = pam_set_item(pamh, PAM_AUTHTOK, key)) == PAM_SUCCESS) 155#endif 156 status = pam_authenticate(pamh, 0); 157 pam_end(pamh, status); 158 return (status == PAM_SUCCESS); 159#endif /* !NOPAM */ 160 } 161 162 return !strcmp(data, key); 163} 164 165int 166auth_SetPhoneList(const char *name, char *phone, int phonelen) 167{ 168 FILE *fp; 169 int n, lineno; 170 char *vector[6], buff[LINE_LEN]; 171 const char *slash; 172 173 fp = OpenSecret(SECRETFILE); 174 if (fp != NULL) { 175again: 176 lineno = 0; 177 while (fgets(buff, sizeof buff, fp)) { 178 lineno++; 179 if (buff[0] == '#') 180 continue; 181 buff[strlen(buff) - 1] = '\0'; 182 memset(vector, '\0', sizeof vector); 183 if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0) 184 log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno); 185 if (n < 5) 186 continue; 187 if (strcmp(vector[0], name) == 0) { 188 CloseSecret(fp); 189 if (*vector[4] == '\0') 190 return 0; 191 strncpy(phone, vector[4], phonelen - 1); 192 phone[phonelen - 1] = '\0'; 193 return 1; /* Valid */ 194 } 195 } 196 197 if ((slash = strrchr(name, '\\')) != NULL && slash[1]) { 198 /* Look for the name without the leading domain */ 199 name = slash + 1; 200 rewind(fp); 201 goto again; 202 } 203 204 CloseSecret(fp); 205 } 206 *phone = '\0'; 207 return 0; 208} 209 210int 211auth_Select(struct bundle *bundle, const char *name) 212{ 213 FILE *fp; 214 int n, lineno; 215 char *vector[5], buff[LINE_LEN]; 216 const char *slash; 217 218 if (*name == '\0') { 219 ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE); 220 return 1; 221 } 222 223#ifndef NORADIUS 224 if (bundle->radius.valid && bundle->radius.ip.s_addr != INADDR_NONE && 225 bundle->radius.ip.s_addr != RADIUS_INADDR_POOL) { 226 /* We've got a radius IP - it overrides everything */ 227 if (!ipcp_UseHisIPaddr(bundle, bundle->radius.ip)) 228 return 0; 229 ipcp_Setup(&bundle->ncp.ipcp, bundle->radius.mask.s_addr); 230 /* Continue with ppp.secret in case we've got a new label */ 231 } 232#endif 233 234 fp = OpenSecret(SECRETFILE); 235 if (fp != NULL) { 236again: 237 lineno = 0; 238 while (fgets(buff, sizeof buff, fp)) { 239 lineno++; 240 if (buff[0] == '#') 241 continue; 242 buff[strlen(buff) - 1] = '\0'; 243 memset(vector, '\0', sizeof vector); 244 if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0) 245 log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno); 246 if (n < 2) 247 continue; 248 if (strcmp(vector[0], name) == 0) { 249 CloseSecret(fp); 250#ifndef NORADIUS 251 if (!bundle->radius.valid || bundle->radius.ip.s_addr == INADDR_NONE) { 252#endif 253 if (n > 2 && *vector[2] && strcmp(vector[2], "*") && 254 !ipcp_UseHisaddr(bundle, vector[2], 1)) 255 return 0; 256 ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE); 257#ifndef NORADIUS 258 } 259#endif 260 if (n > 3 && *vector[3] && strcmp(vector[3], "*")) 261 bundle_SetLabel(bundle, vector[3]); 262 return 1; /* Valid */ 263 } 264 } 265 266 if ((slash = strrchr(name, '\\')) != NULL && slash[1]) { 267 /* Look for the name without the leading domain */ 268 name = slash + 1; 269 rewind(fp); 270 goto again; 271 } 272 273 CloseSecret(fp); 274 } 275 276#ifndef NOPASSWDAUTH 277 /* Let 'em in anyway - they must have been in the passwd file */ 278 ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE); 279 return 1; 280#else 281#ifndef NORADIUS 282 if (bundle->radius.valid) 283 return 1; 284#endif 285 286 /* Disappeared from ppp.secret ??? */ 287 return 0; 288#endif 289} 290 291int 292auth_Validate(struct bundle *bundle, const char *name, const char *key) 293{ 294 /* Used by PAP routines */ 295 296 FILE *fp; 297 int n, lineno; 298 char *vector[5], buff[LINE_LEN]; 299 const char *slash; 300 301 fp = OpenSecret(SECRETFILE); 302again: 303 lineno = 0; 304 if (fp != NULL) { 305 while (fgets(buff, sizeof buff, fp)) { 306 lineno++; 307 if (buff[0] == '#') 308 continue; 309 buff[strlen(buff) - 1] = 0; 310 memset(vector, '\0', sizeof vector); 311 if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0) 312 log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno); 313 if (n < 2) 314 continue; 315 if (strcmp(vector[0], name) == 0) { 316 CloseSecret(fp); 317 return auth_CheckPasswd(name, vector[1], key); 318 } 319 } 320 } 321 322 if ((slash = strrchr(name, '\\')) != NULL && slash[1]) { 323 /* Look for the name without the leading domain */ 324 name = slash + 1; 325 if (fp != NULL) { 326 rewind(fp); 327 goto again; 328 } 329 } 330 331 if (fp != NULL) 332 CloseSecret(fp); 333 334#ifndef NOPASSWDAUTH 335 if (Enabled(bundle, OPT_PASSWDAUTH)) 336 return auth_CheckPasswd(name, "*", key); 337#endif 338 339 return 0; /* Invalid */ 340} 341 342char * 343auth_GetSecret(const char *name, size_t len) 344{ 345 /* Used by CHAP routines */ 346 347 FILE *fp; 348 int n, lineno; 349 char *vector[5]; 350 const char *slash; 351 static char buff[LINE_LEN]; /* vector[] will point here when returned */ 352 353 fp = OpenSecret(SECRETFILE); 354 if (fp == NULL) 355 return (NULL); 356 357again: 358 lineno = 0; 359 while (fgets(buff, sizeof buff, fp)) { 360 lineno++; 361 if (buff[0] == '#') 362 continue; 363 n = strlen(buff) - 1; 364 if (buff[n] == '\n') 365 buff[n] = '\0'; /* Trim the '\n' */ 366 memset(vector, '\0', sizeof vector); 367 if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0) 368 log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno); 369 if (n < 2) 370 continue; 371 if (strlen(vector[0]) == len && strncmp(vector[0], name, len) == 0) { 372 CloseSecret(fp); 373 return vector[1]; 374 } 375 } 376 377 if ((slash = strrchr(name, '\\')) != NULL && slash[1]) { 378 /* Go back and look for the name without the leading domain */ 379 len -= slash - name + 1; 380 name = slash + 1; 381 rewind(fp); 382 goto again; 383 } 384 385 CloseSecret(fp); 386 return (NULL); /* Invalid */ 387} 388 389static void 390AuthTimeout(void *vauthp) 391{ 392 struct authinfo *authp = (struct authinfo *)vauthp; 393 394 timer_Stop(&authp->authtimer); 395 if (--authp->retry > 0) { 396 authp->id++; 397 (*authp->fn.req)(authp); 398 timer_Start(&authp->authtimer); 399 } else { 400 log_Printf(LogPHASE, "Auth: No response from server\n"); 401 datalink_AuthNotOk(authp->physical->dl); 402 } 403} 404 405void 406auth_Init(struct authinfo *authp, struct physical *p, auth_func req, 407 auth_func success, auth_func failure) 408{ 409 memset(authp, '\0', sizeof(struct authinfo)); 410 authp->cfg.fsm.timeout = DEF_FSMRETRY; 411 authp->cfg.fsm.maxreq = DEF_FSMAUTHTRIES; 412 authp->cfg.fsm.maxtrm = 0; /* not used */ 413 authp->fn.req = req; 414 authp->fn.success = success; 415 authp->fn.failure = failure; 416 authp->physical = p; 417} 418 419void 420auth_StartReq(struct authinfo *authp) 421{ 422 timer_Stop(&authp->authtimer); 423 authp->authtimer.func = AuthTimeout; 424 authp->authtimer.name = "auth"; 425 authp->authtimer.load = authp->cfg.fsm.timeout * SECTICKS; 426 authp->authtimer.arg = (void *)authp; 427 authp->retry = authp->cfg.fsm.maxreq; 428 authp->id = 1; 429 (*authp->fn.req)(authp); 430 timer_Start(&authp->authtimer); 431} 432 433void 434auth_StopTimer(struct authinfo *authp) 435{ 436 timer_Stop(&authp->authtimer); 437} 438 439struct mbuf * 440auth_ReadHeader(struct authinfo *authp, struct mbuf *bp) 441{ 442 size_t len; 443 444 len = m_length(bp); 445 if (len >= sizeof authp->in.hdr) { 446 bp = mbuf_Read(bp, (u_char *)&authp->in.hdr, sizeof authp->in.hdr); 447 if (len >= ntohs(authp->in.hdr.length)) 448 return bp; 449 authp->in.hdr.length = htons(0); 450 log_Printf(LogWARN, "auth_ReadHeader: Short packet (%u > %zu) !\n", 451 ntohs(authp->in.hdr.length), len); 452 } else { 453 authp->in.hdr.length = htons(0); 454 log_Printf(LogWARN, "auth_ReadHeader: Short packet header (%u > %zu) !\n", 455 (int)(sizeof authp->in.hdr), len); 456 } 457 458 m_freem(bp); 459 return NULL; 460} 461 462struct mbuf * 463auth_ReadName(struct authinfo *authp, struct mbuf *bp, size_t len) 464{ 465 if (len > sizeof authp->in.name - 1) 466 log_Printf(LogWARN, "auth_ReadName: Name too long (%zu) !\n", len); 467 else { 468 size_t mlen = m_length(bp); 469 470 if (len > mlen) 471 log_Printf(LogWARN, "auth_ReadName: Short packet (%zu > %zu) !\n", 472 len, mlen); 473 else { 474 bp = mbuf_Read(bp, (u_char *)authp->in.name, len); 475 authp->in.name[len] = '\0'; 476 return bp; 477 } 478 } 479 480 *authp->in.name = '\0'; 481 m_freem(bp); 482 return NULL; 483} 484