1 /*- 2 * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 3 * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 4 * Internet Initiative Japan, Inc (IIJ) 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 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 * 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 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 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; 129 char *cryptpw; 130 131 cryptpw = crypt(key, pw->pw_passwd); 132 result = (pw = getpwnam(name)) && 133 (cryptpw == NULL || !strcmp(cryptpw, pw->pw_passwd)); 134 endpwent(); 135 return result; 136 #else /* !NOPAM */ 137 /* Then consult with PAM. */ 138 pam_handle_t *pamh; 139 int status; 140 141 struct pam_conv pamc = { 142 #ifdef OPENPAM 143 &openpam_nullconv, NULL 144 #else 145 &pam_conv, key 146 #endif 147 }; 148 149 if (pam_start("ppp", name, &pamc, &pamh) != PAM_SUCCESS) 150 return (0); 151 #ifdef OPENPAM 152 if ((status = pam_set_item(pamh, PAM_AUTHTOK, key)) == PAM_SUCCESS) 153 #endif 154 status = pam_authenticate(pamh, 0); 155 pam_end(pamh, status); 156 return (status == PAM_SUCCESS); 157 #endif /* !NOPAM */ 158 } 159 160 return !strcmp(data, key); 161 } 162 163 int 164 auth_SetPhoneList(const char *name, char *phone, int phonelen) 165 { 166 FILE *fp; 167 int n, lineno; 168 char *vector[6], buff[LINE_LEN]; 169 const char *slash; 170 171 fp = OpenSecret(SECRETFILE); 172 if (fp != NULL) { 173 again: 174 lineno = 0; 175 while (fgets(buff, sizeof buff, fp)) { 176 lineno++; 177 if (buff[0] == '#') 178 continue; 179 buff[strlen(buff) - 1] = '\0'; 180 memset(vector, '\0', sizeof vector); 181 if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0) 182 log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno); 183 if (n < 5) 184 continue; 185 if (strcmp(vector[0], name) == 0) { 186 CloseSecret(fp); 187 if (*vector[4] == '\0') 188 return 0; 189 strncpy(phone, vector[4], phonelen - 1); 190 phone[phonelen - 1] = '\0'; 191 return 1; /* Valid */ 192 } 193 } 194 195 if ((slash = strrchr(name, '\\')) != NULL && slash[1]) { 196 /* Look for the name without the leading domain */ 197 name = slash + 1; 198 rewind(fp); 199 goto again; 200 } 201 202 CloseSecret(fp); 203 } 204 *phone = '\0'; 205 return 0; 206 } 207 208 int 209 auth_Select(struct bundle *bundle, const char *name) 210 { 211 FILE *fp; 212 int n, lineno; 213 char *vector[5], buff[LINE_LEN]; 214 const char *slash; 215 216 if (*name == '\0') { 217 ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE); 218 return 1; 219 } 220 221 #ifndef NORADIUS 222 if (bundle->radius.valid && bundle->radius.ip.s_addr != INADDR_NONE && 223 bundle->radius.ip.s_addr != RADIUS_INADDR_POOL) { 224 /* We've got a radius IP - it overrides everything */ 225 if (!ipcp_UseHisIPaddr(bundle, bundle->radius.ip)) 226 return 0; 227 ipcp_Setup(&bundle->ncp.ipcp, bundle->radius.mask.s_addr); 228 /* Continue with ppp.secret in case we've got a new label */ 229 } 230 #endif 231 232 fp = OpenSecret(SECRETFILE); 233 if (fp != NULL) { 234 again: 235 lineno = 0; 236 while (fgets(buff, sizeof buff, fp)) { 237 lineno++; 238 if (buff[0] == '#') 239 continue; 240 buff[strlen(buff) - 1] = '\0'; 241 memset(vector, '\0', sizeof vector); 242 if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0) 243 log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno); 244 if (n < 2) 245 continue; 246 if (strcmp(vector[0], name) == 0) { 247 CloseSecret(fp); 248 #ifndef NORADIUS 249 if (!bundle->radius.valid || bundle->radius.ip.s_addr == INADDR_NONE) { 250 #endif 251 if (n > 2 && *vector[2] && strcmp(vector[2], "*") && 252 !ipcp_UseHisaddr(bundle, vector[2], 1)) 253 return 0; 254 ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE); 255 #ifndef NORADIUS 256 } 257 #endif 258 if (n > 3 && *vector[3] && strcmp(vector[3], "*")) 259 bundle_SetLabel(bundle, vector[3]); 260 return 1; /* Valid */ 261 } 262 } 263 264 if ((slash = strrchr(name, '\\')) != NULL && slash[1]) { 265 /* Look for the name without the leading domain */ 266 name = slash + 1; 267 rewind(fp); 268 goto again; 269 } 270 271 CloseSecret(fp); 272 } 273 274 #ifndef NOPASSWDAUTH 275 /* Let 'em in anyway - they must have been in the passwd file */ 276 ipcp_Setup(&bundle->ncp.ipcp, INADDR_NONE); 277 return 1; 278 #else 279 #ifndef NORADIUS 280 if (bundle->radius.valid) 281 return 1; 282 #endif 283 284 /* Disappeared from ppp.secret ??? */ 285 return 0; 286 #endif 287 } 288 289 int 290 auth_Validate(struct bundle *bundle, const char *name, const char *key) 291 { 292 /* Used by PAP routines */ 293 294 FILE *fp; 295 int n, lineno; 296 char *vector[5], buff[LINE_LEN]; 297 const char *slash; 298 299 fp = OpenSecret(SECRETFILE); 300 again: 301 lineno = 0; 302 if (fp != NULL) { 303 while (fgets(buff, sizeof buff, fp)) { 304 lineno++; 305 if (buff[0] == '#') 306 continue; 307 buff[strlen(buff) - 1] = 0; 308 memset(vector, '\0', sizeof vector); 309 if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0) 310 log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno); 311 if (n < 2) 312 continue; 313 if (strcmp(vector[0], name) == 0) { 314 CloseSecret(fp); 315 return auth_CheckPasswd(name, vector[1], key); 316 } 317 } 318 } 319 320 if ((slash = strrchr(name, '\\')) != NULL && slash[1]) { 321 /* Look for the name without the leading domain */ 322 name = slash + 1; 323 if (fp != NULL) { 324 rewind(fp); 325 goto again; 326 } 327 } 328 329 if (fp != NULL) 330 CloseSecret(fp); 331 332 #ifndef NOPASSWDAUTH 333 if (Enabled(bundle, OPT_PASSWDAUTH)) 334 return auth_CheckPasswd(name, "*", key); 335 #endif 336 337 return 0; /* Invalid */ 338 } 339 340 char * 341 auth_GetSecret(const char *name, size_t len) 342 { 343 /* Used by CHAP routines */ 344 345 FILE *fp; 346 int n, lineno; 347 char *vector[5]; 348 const char *slash; 349 static char buff[LINE_LEN]; /* vector[] will point here when returned */ 350 351 fp = OpenSecret(SECRETFILE); 352 if (fp == NULL) 353 return (NULL); 354 355 again: 356 lineno = 0; 357 while (fgets(buff, sizeof buff, fp)) { 358 lineno++; 359 if (buff[0] == '#') 360 continue; 361 n = strlen(buff) - 1; 362 if (buff[n] == '\n') 363 buff[n] = '\0'; /* Trim the '\n' */ 364 memset(vector, '\0', sizeof vector); 365 if ((n = MakeArgs(buff, vector, VECSIZE(vector), PARSE_REDUCE)) < 0) 366 log_Printf(LogWARN, "%s: %d: Invalid line\n", SECRETFILE, lineno); 367 if (n < 2) 368 continue; 369 if (strlen(vector[0]) == len && strncmp(vector[0], name, len) == 0) { 370 CloseSecret(fp); 371 return vector[1]; 372 } 373 } 374 375 if ((slash = strrchr(name, '\\')) != NULL && slash[1]) { 376 /* Go back and look for the name without the leading domain */ 377 len -= slash - name + 1; 378 name = slash + 1; 379 rewind(fp); 380 goto again; 381 } 382 383 CloseSecret(fp); 384 return (NULL); /* Invalid */ 385 } 386 387 static void 388 AuthTimeout(void *vauthp) 389 { 390 struct authinfo *authp = (struct authinfo *)vauthp; 391 392 timer_Stop(&authp->authtimer); 393 if (--authp->retry > 0) { 394 authp->id++; 395 (*authp->fn.req)(authp); 396 timer_Start(&authp->authtimer); 397 } else { 398 log_Printf(LogPHASE, "Auth: No response from server\n"); 399 datalink_AuthNotOk(authp->physical->dl); 400 } 401 } 402 403 void 404 auth_Init(struct authinfo *authp, struct physical *p, auth_func req, 405 auth_func success, auth_func failure) 406 { 407 memset(authp, '\0', sizeof(struct authinfo)); 408 authp->cfg.fsm.timeout = DEF_FSMRETRY; 409 authp->cfg.fsm.maxreq = DEF_FSMAUTHTRIES; 410 authp->cfg.fsm.maxtrm = 0; /* not used */ 411 authp->fn.req = req; 412 authp->fn.success = success; 413 authp->fn.failure = failure; 414 authp->physical = p; 415 } 416 417 void 418 auth_StartReq(struct authinfo *authp) 419 { 420 timer_Stop(&authp->authtimer); 421 authp->authtimer.func = AuthTimeout; 422 authp->authtimer.name = "auth"; 423 authp->authtimer.load = authp->cfg.fsm.timeout * SECTICKS; 424 authp->authtimer.arg = (void *)authp; 425 authp->retry = authp->cfg.fsm.maxreq; 426 authp->id = 1; 427 (*authp->fn.req)(authp); 428 timer_Start(&authp->authtimer); 429 } 430 431 void 432 auth_StopTimer(struct authinfo *authp) 433 { 434 timer_Stop(&authp->authtimer); 435 } 436 437 struct mbuf * 438 auth_ReadHeader(struct authinfo *authp, struct mbuf *bp) 439 { 440 size_t len; 441 442 len = m_length(bp); 443 if (len >= sizeof authp->in.hdr) { 444 bp = mbuf_Read(bp, (u_char *)&authp->in.hdr, sizeof authp->in.hdr); 445 if (len >= ntohs(authp->in.hdr.length)) 446 return bp; 447 authp->in.hdr.length = htons(0); 448 log_Printf(LogWARN, "auth_ReadHeader: Short packet (%u > %zu) !\n", 449 ntohs(authp->in.hdr.length), len); 450 } else { 451 authp->in.hdr.length = htons(0); 452 log_Printf(LogWARN, "auth_ReadHeader: Short packet header (%u > %zu) !\n", 453 (int)(sizeof authp->in.hdr), len); 454 } 455 456 m_freem(bp); 457 return NULL; 458 } 459 460 struct mbuf * 461 auth_ReadName(struct authinfo *authp, struct mbuf *bp, size_t len) 462 { 463 if (len > sizeof authp->in.name - 1) 464 log_Printf(LogWARN, "auth_ReadName: Name too long (%zu) !\n", len); 465 else { 466 size_t mlen = m_length(bp); 467 468 if (len > mlen) 469 log_Printf(LogWARN, "auth_ReadName: Short packet (%zu > %zu) !\n", 470 len, mlen); 471 else { 472 bp = mbuf_Read(bp, (u_char *)authp->in.name, len); 473 authp->in.name[len] = '\0'; 474 return bp; 475 } 476 } 477 478 *authp->in.name = '\0'; 479 m_freem(bp); 480 return NULL; 481 } 482