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