| File: | src/usr.sbin/pppd/auth.c |
| Warning: | line 769, column 44 Access to field 'pw_uid' results in a dereference of a null pointer (loaded from variable 'pw') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: auth.c,v 1.39 2017/11/17 20:48:30 jca Exp $ */ | |||
| 2 | ||||
| 3 | /* | |||
| 4 | * auth.c - PPP authentication and phase control. | |||
| 5 | * | |||
| 6 | * Copyright (c) 1989-2002 Paul Mackerras. All rights reserved. | |||
| 7 | * | |||
| 8 | * Redistribution and use in source and binary forms, with or without | |||
| 9 | * modification, are permitted provided that the following conditions | |||
| 10 | * are met: | |||
| 11 | * | |||
| 12 | * 1. Redistributions of source code must retain the above copyright | |||
| 13 | * notice, this list of conditions and the following disclaimer. | |||
| 14 | * | |||
| 15 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 16 | * notice, this list of conditions and the following disclaimer in | |||
| 17 | * the documentation and/or other materials provided with the | |||
| 18 | * distribution. | |||
| 19 | * | |||
| 20 | * 3. The name(s) of the authors of this software must not be used to | |||
| 21 | * endorse or promote products derived from this software without | |||
| 22 | * prior written permission. | |||
| 23 | * | |||
| 24 | * 4. Redistributions of any form whatsoever must retain the following | |||
| 25 | * acknowledgment: | |||
| 26 | * "This product includes software developed by Paul Mackerras | |||
| 27 | * <paulus@samba.org>". | |||
| 28 | * | |||
| 29 | * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO | |||
| 30 | * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | |||
| 31 | * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY | |||
| 32 | * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
| 33 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |||
| 34 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | |||
| 35 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| 36 | * | |||
| 37 | * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. | |||
| 38 | * | |||
| 39 | * Redistribution and use in source and binary forms, with or without | |||
| 40 | * modification, are permitted provided that the following conditions | |||
| 41 | * are met: | |||
| 42 | * | |||
| 43 | * 1. Redistributions of source code must retain the above copyright | |||
| 44 | * notice, this list of conditions and the following disclaimer. | |||
| 45 | * | |||
| 46 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 47 | * notice, this list of conditions and the following disclaimer in | |||
| 48 | * the documentation and/or other materials provided with the | |||
| 49 | * distribution. | |||
| 50 | * | |||
| 51 | * 3. The name "Carnegie Mellon University" must not be used to | |||
| 52 | * endorse or promote products derived from this software without | |||
| 53 | * prior written permission. For permission or any legal | |||
| 54 | * details, please contact | |||
| 55 | * Office of Technology Transfer | |||
| 56 | * Carnegie Mellon University | |||
| 57 | * 5000 Forbes Avenue | |||
| 58 | * Pittsburgh, PA 15213-3890 | |||
| 59 | * (412) 268-4387, fax: (412) 268-7395 | |||
| 60 | * tech-transfer@andrew.cmu.edu | |||
| 61 | * | |||
| 62 | * 4. Redistributions of any form whatsoever must retain the following | |||
| 63 | * acknowledgment: | |||
| 64 | * "This product includes software developed by Computing Services | |||
| 65 | * at Carnegie Mellon University (http://www.cmu.edu/computing/)." | |||
| 66 | * | |||
| 67 | * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO | |||
| 68 | * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | |||
| 69 | * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE | |||
| 70 | * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
| 71 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN | |||
| 72 | * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING | |||
| 73 | * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
| 74 | */ | |||
| 75 | ||||
| 76 | #include <stdio.h> | |||
| 77 | #include <stddef.h> | |||
| 78 | #include <stdlib.h> | |||
| 79 | #include <unistd.h> | |||
| 80 | #include <limits.h> | |||
| 81 | #include <syslog.h> | |||
| 82 | #include <pwd.h> | |||
| 83 | #include <string.h> | |||
| 84 | #include <sys/types.h> | |||
| 85 | #include <sys/stat.h> | |||
| 86 | #include <sys/socket.h> | |||
| 87 | #include <utmp.h> | |||
| 88 | #include <fcntl.h> | |||
| 89 | #if defined(_PATH_LASTLOG"/var/log/lastlog") && defined(_linux_) | |||
| 90 | #include <lastlog.h> | |||
| 91 | #endif | |||
| 92 | ||||
| 93 | #include <netdb.h> | |||
| 94 | #include <netinet/in.h> | |||
| 95 | #include <arpa/inet.h> | |||
| 96 | ||||
| 97 | ||||
| 98 | ||||
| 99 | #include "pppd.h" | |||
| 100 | #include "fsm.h" | |||
| 101 | #include "lcp.h" | |||
| 102 | #include "ipcp.h" | |||
| 103 | #include "upap.h" | |||
| 104 | #include "chap.h" | |||
| 105 | #ifdef CBCP_SUPPORT | |||
| 106 | #include "cbcp.h" | |||
| 107 | #endif | |||
| 108 | #include "pathnames.h" | |||
| 109 | ||||
| 110 | /* Used for storing a sequence of words. Usually malloced. */ | |||
| 111 | struct wordlist { | |||
| 112 | struct wordlist *next; | |||
| 113 | char word[1]; | |||
| 114 | }; | |||
| 115 | ||||
| 116 | /* Bits in scan_authfile return value */ | |||
| 117 | #define NONWILD_SERVER1 1 | |||
| 118 | #define NONWILD_CLIENT2 2 | |||
| 119 | ||||
| 120 | #define ISWILD(word)(word[0] == '*' && word[1] == 0) (word[0] == '*' && word[1] == 0) | |||
| 121 | ||||
| 122 | #define FALSE0 0 | |||
| 123 | #define TRUE1 1 | |||
| 124 | ||||
| 125 | /* The name by which the peer authenticated itself to us. */ | |||
| 126 | char peer_authname[MAXNAMELEN256]; | |||
| 127 | ||||
| 128 | /* Records which authentication operations haven't completed yet. */ | |||
| 129 | static int auth_pending[NUM_PPP1]; | |||
| 130 | ||||
| 131 | /* Set if we have successfully called plogin() */ | |||
| 132 | static int logged_in; | |||
| 133 | ||||
| 134 | /* Set if we have run the /etc/ppp/auth-up script. */ | |||
| 135 | static int did_authup; | |||
| 136 | ||||
| 137 | /* List of addresses which the peer may use. */ | |||
| 138 | static struct wordlist *addresses[NUM_PPP1]; | |||
| 139 | ||||
| 140 | /* Number of network protocols which we have opened. */ | |||
| 141 | static int num_np_open; | |||
| 142 | ||||
| 143 | /* Number of network protocols which have come up. */ | |||
| 144 | static int num_np_up; | |||
| 145 | ||||
| 146 | /* Set if we got the contents of passwd[] from the pap-secrets file. */ | |||
| 147 | static int passwd_from_file; | |||
| 148 | ||||
| 149 | /* Bits in auth_pending[] */ | |||
| 150 | #define PAP_WITHPEER1 1 | |||
| 151 | #define PAP_PEER2 2 | |||
| 152 | #define CHAP_WITHPEER4 4 | |||
| 153 | #define CHAP_PEER8 8 | |||
| 154 | ||||
| 155 | extern char *crypt(const char *, const char *); | |||
| 156 | ||||
| 157 | /* Prototypes for procedures local to this file. */ | |||
| 158 | ||||
| 159 | static void network_phase(int); | |||
| 160 | static void check_idle(void *); | |||
| 161 | static void connect_time_expired(void *); | |||
| 162 | static int plogin(char *, char *, char **, int *); | |||
| 163 | static void plogout(void); | |||
| 164 | static int null_login(int); | |||
| 165 | static int get_pap_passwd(char *); | |||
| 166 | static int have_pap_secret(void); | |||
| 167 | static int have_chap_secret(char *, char *, u_int32_t); | |||
| 168 | static int ip_addr_check(u_int32_t, struct wordlist *); | |||
| 169 | static int scan_authfile(FILE *, char *, char *, u_int32_t, char *, | |||
| 170 | struct wordlist **, char *); | |||
| 171 | static void free_wordlist(struct wordlist *); | |||
| 172 | static void auth_script(char *); | |||
| 173 | static void set_allowed_addrs(int, struct wordlist *); | |||
| 174 | ||||
| 175 | /* | |||
| 176 | * An Open on LCP has requested a change from Dead to Establish phase. | |||
| 177 | * Do what's necessary to bring the physical layer up. | |||
| 178 | */ | |||
| 179 | void | |||
| 180 | link_required(unit) | |||
| 181 | int unit; | |||
| 182 | { | |||
| 183 | } | |||
| 184 | ||||
| 185 | /* | |||
| 186 | * LCP has terminated the link; go to the Dead phase and take the | |||
| 187 | * physical layer down. | |||
| 188 | */ | |||
| 189 | void | |||
| 190 | link_terminated(unit) | |||
| 191 | int unit; | |||
| 192 | { | |||
| 193 | if (phase == PHASE_DEAD0) | |||
| 194 | return; | |||
| 195 | if (logged_in) | |||
| 196 | plogout(); | |||
| 197 | phase = PHASE_DEAD0; | |||
| 198 | syslog(LOG_NOTICE5, "Connection terminated."); | |||
| 199 | } | |||
| 200 | ||||
| 201 | /* | |||
| 202 | * LCP has gone down; it will either die or try to re-establish. | |||
| 203 | */ | |||
| 204 | void | |||
| 205 | link_down(unit) | |||
| 206 | int unit; | |||
| 207 | { | |||
| 208 | int i; | |||
| 209 | struct protent *protp; | |||
| 210 | ||||
| 211 | if (did_authup) { | |||
| 212 | auth_script(_PATH_AUTHDOWN"/etc/ppp/auth-down"); | |||
| 213 | did_authup = 0; | |||
| 214 | } | |||
| 215 | for (i = 0; (protp = protocols[i]) != NULL((void*)0); ++i) { | |||
| 216 | if (!protp->enabled_flag) | |||
| 217 | continue; | |||
| 218 | if (protp->protocol != PPP_LCP0xc021 && protp->lowerdown != NULL((void*)0)) | |||
| 219 | (*protp->lowerdown)(unit); | |||
| 220 | if (protp->protocol < 0xC000 && protp->close != NULL((void*)0)) | |||
| 221 | (*protp->close)(unit, "LCP down"); | |||
| 222 | } | |||
| 223 | num_np_open = 0; | |||
| 224 | num_np_up = 0; | |||
| 225 | if (phase != PHASE_DEAD0) | |||
| 226 | phase = PHASE_TERMINATE7; | |||
| 227 | } | |||
| 228 | ||||
| 229 | /* | |||
| 230 | * The link is established. | |||
| 231 | * Proceed to the Dead, Authenticate or Network phase as appropriate. | |||
| 232 | */ | |||
| 233 | void | |||
| 234 | link_established(unit) | |||
| 235 | int unit; | |||
| 236 | { | |||
| 237 | int auth; | |||
| 238 | lcp_options *wo = &lcp_wantoptions[unit]; | |||
| 239 | lcp_options *go = &lcp_gotoptions[unit]; | |||
| 240 | lcp_options *ho = &lcp_hisoptions[unit]; | |||
| 241 | int i; | |||
| 242 | struct protent *protp; | |||
| 243 | ||||
| 244 | /* | |||
| 245 | * Tell higher-level protocols that LCP is up. | |||
| 246 | */ | |||
| 247 | for (i = 0; (protp = protocols[i]) != NULL((void*)0); ++i) | |||
| 248 | if (protp->protocol != PPP_LCP0xc021 && protp->enabled_flag | |||
| 249 | && protp->lowerup != NULL((void*)0)) | |||
| 250 | (*protp->lowerup)(unit); | |||
| 251 | ||||
| 252 | if (auth_required && !(go->neg_chap || go->neg_upap)) { | |||
| 253 | /* | |||
| 254 | * We wanted the peer to authenticate itself, and it refused: | |||
| 255 | * treat it as though it authenticated with PAP using a username | |||
| 256 | * of "" and a password of "". If that's not OK, boot it out. | |||
| 257 | */ | |||
| 258 | if (!wo->neg_upap || !null_login(unit)) { | |||
| 259 | syslog(LOG_WARNING4, "peer refused to authenticate"); | |||
| 260 | lcp_close(unit, "peer refused to authenticate"); | |||
| 261 | return; | |||
| 262 | } | |||
| 263 | } | |||
| 264 | ||||
| 265 | phase = PHASE_AUTHENTICATE4; | |||
| 266 | auth = 0; | |||
| 267 | if (go->neg_chap) { | |||
| 268 | ChapAuthPeer(unit, our_name, go->chap_mdtype); | |||
| 269 | auth |= CHAP_PEER8; | |||
| 270 | } else if (go->neg_upap) { | |||
| 271 | upap_authpeer(unit); | |||
| 272 | auth |= PAP_PEER2; | |||
| 273 | } | |||
| 274 | if (ho->neg_chap) { | |||
| 275 | ChapAuthWithPeer(unit, user, ho->chap_mdtype); | |||
| 276 | auth |= CHAP_WITHPEER4; | |||
| 277 | } else if (ho->neg_upap) { | |||
| 278 | if (passwd[0] == 0) { | |||
| 279 | passwd_from_file = 1; | |||
| 280 | if (!get_pap_passwd(passwd)) | |||
| 281 | syslog(LOG_ERR3, "No secret found for PAP login"); | |||
| 282 | } | |||
| 283 | upap_authwithpeer(unit, user, passwd); | |||
| 284 | auth |= PAP_WITHPEER1; | |||
| 285 | } | |||
| 286 | auth_pending[unit] = auth; | |||
| 287 | ||||
| 288 | if (!auth) | |||
| 289 | network_phase(unit); | |||
| 290 | } | |||
| 291 | ||||
| 292 | /* | |||
| 293 | * Proceed to the network phase. | |||
| 294 | */ | |||
| 295 | static void | |||
| 296 | network_phase(unit) | |||
| 297 | int unit; | |||
| 298 | { | |||
| 299 | int i; | |||
| 300 | struct protent *protp; | |||
| 301 | lcp_options *go = &lcp_gotoptions[unit]; | |||
| 302 | ||||
| 303 | /* | |||
| 304 | * If the peer had to authenticate, run the auth-up script now. | |||
| 305 | */ | |||
| 306 | if ((go->neg_chap || go->neg_upap) && !did_authup) { | |||
| 307 | auth_script(_PATH_AUTHUP"/etc/ppp/auth-up"); | |||
| 308 | did_authup = 1; | |||
| 309 | } | |||
| 310 | ||||
| 311 | #ifdef CBCP_SUPPORT | |||
| 312 | /* | |||
| 313 | * If we negotiated callback, do it now. | |||
| 314 | */ | |||
| 315 | if (go->neg_cbcp) { | |||
| 316 | phase = PHASE_CALLBACK5; | |||
| 317 | (*cbcp_protent.open)(unit); | |||
| 318 | return; | |||
| 319 | } | |||
| 320 | #endif | |||
| 321 | ||||
| 322 | phase = PHASE_NETWORK6; | |||
| 323 | #if 0 | |||
| 324 | if (!demand) | |||
| 325 | set_filters(&pass_filter, &active_filter); | |||
| 326 | #endif | |||
| 327 | for (i = 0; (protp = protocols[i]) != NULL((void*)0); ++i) | |||
| 328 | if (protp->protocol < 0xC000 && protp->enabled_flag | |||
| 329 | && protp->open != NULL((void*)0)) { | |||
| 330 | (*protp->open)(unit); | |||
| 331 | if (protp->protocol != PPP_CCP0x80fd) | |||
| 332 | ++num_np_open; | |||
| 333 | } | |||
| 334 | ||||
| 335 | if (num_np_open == 0) | |||
| 336 | /* nothing to do */ | |||
| 337 | lcp_close(0, "No network protocols running"); | |||
| 338 | } | |||
| 339 | ||||
| 340 | /* | |||
| 341 | * The peer has failed to authenticate himself using `protocol'. | |||
| 342 | */ | |||
| 343 | void | |||
| 344 | auth_peer_fail(unit, protocol) | |||
| 345 | int unit, protocol; | |||
| 346 | { | |||
| 347 | /* | |||
| 348 | * Authentication failure: take the link down | |||
| 349 | */ | |||
| 350 | lcp_close(unit, "Authentication failed"); | |||
| 351 | } | |||
| 352 | ||||
| 353 | /* | |||
| 354 | * The peer has been successfully authenticated using `protocol'. | |||
| 355 | */ | |||
| 356 | void | |||
| 357 | auth_peer_success(unit, protocol, name, namelen) | |||
| 358 | int unit, protocol; | |||
| 359 | char *name; | |||
| 360 | int namelen; | |||
| 361 | { | |||
| 362 | int bit; | |||
| 363 | ||||
| 364 | switch (protocol) { | |||
| 365 | case PPP_CHAP0xc223: | |||
| 366 | bit = CHAP_PEER8; | |||
| 367 | break; | |||
| 368 | case PPP_PAP0xc023: | |||
| 369 | bit = PAP_PEER2; | |||
| 370 | break; | |||
| 371 | default: | |||
| 372 | syslog(LOG_WARNING4, "auth_peer_success: unknown protocol %x", | |||
| 373 | protocol); | |||
| 374 | return; | |||
| 375 | } | |||
| 376 | ||||
| 377 | /* | |||
| 378 | * Save the authenticated name of the peer for later. | |||
| 379 | */ | |||
| 380 | if (namelen > sizeof(peer_authname) - 1) | |||
| 381 | namelen = sizeof(peer_authname) - 1; | |||
| 382 | BCOPY(name, peer_authname, namelen)memcpy(peer_authname, name, namelen); | |||
| 383 | peer_authname[namelen] = 0; | |||
| 384 | script_setenv("PEERNAME", peer_authname); | |||
| 385 | ||||
| 386 | /* | |||
| 387 | * If there is no more authentication still to be done, | |||
| 388 | * proceed to the network (or callback) phase. | |||
| 389 | */ | |||
| 390 | if ((auth_pending[unit] &= ~bit) == 0) | |||
| 391 | network_phase(unit); | |||
| 392 | } | |||
| 393 | ||||
| 394 | /* | |||
| 395 | * We have failed to authenticate ourselves to the peer using `protocol'. | |||
| 396 | */ | |||
| 397 | void | |||
| 398 | auth_withpeer_fail(unit, protocol) | |||
| 399 | int unit, protocol; | |||
| 400 | { | |||
| 401 | if (passwd_from_file) | |||
| 402 | EXPLICIT_BZERO(passwd, MAXSECRETLEN)explicit_bzero(passwd, 256); | |||
| 403 | /* | |||
| 404 | * We've failed to authenticate ourselves to our peer. | |||
| 405 | * He'll probably take the link down, and there's not much | |||
| 406 | * we can do except wait for that. | |||
| 407 | */ | |||
| 408 | } | |||
| 409 | ||||
| 410 | /* | |||
| 411 | * We have successfully authenticated ourselves with the peer using `protocol'. | |||
| 412 | */ | |||
| 413 | void | |||
| 414 | auth_withpeer_success(unit, protocol) | |||
| 415 | int unit, protocol; | |||
| 416 | { | |||
| 417 | int bit; | |||
| 418 | ||||
| 419 | switch (protocol) { | |||
| 420 | case PPP_CHAP0xc223: | |||
| 421 | bit = CHAP_WITHPEER4; | |||
| 422 | break; | |||
| 423 | case PPP_PAP0xc023: | |||
| 424 | if (passwd_from_file) | |||
| 425 | EXPLICIT_BZERO(passwd, MAXSECRETLEN)explicit_bzero(passwd, 256); | |||
| 426 | bit = PAP_WITHPEER1; | |||
| 427 | break; | |||
| 428 | default: | |||
| 429 | syslog(LOG_WARNING4, "auth_peer_success: unknown protocol %x", | |||
| 430 | protocol); | |||
| 431 | bit = 0; | |||
| 432 | } | |||
| 433 | ||||
| 434 | /* | |||
| 435 | * If there is no more authentication still being done, | |||
| 436 | * proceed to the network (or callback) phase. | |||
| 437 | */ | |||
| 438 | if ((auth_pending[unit] &= ~bit) == 0) | |||
| 439 | network_phase(unit); | |||
| 440 | } | |||
| 441 | ||||
| 442 | ||||
| 443 | /* | |||
| 444 | * np_up - a network protocol has come up. | |||
| 445 | */ | |||
| 446 | void | |||
| 447 | np_up(unit, proto) | |||
| 448 | int unit, proto; | |||
| 449 | { | |||
| 450 | if (num_np_up == 0) { | |||
| 451 | /* | |||
| 452 | * At this point we consider that the link has come up successfully. | |||
| 453 | */ | |||
| 454 | need_holdoff = 0; | |||
| 455 | ||||
| 456 | if (idle_time_limit > 0) | |||
| 457 | TIMEOUT(check_idle, NULL, idle_time_limit)timeout((check_idle), (((void*)0)), (idle_time_limit)); | |||
| 458 | ||||
| 459 | /* | |||
| 460 | * Set a timeout to close the connection once the maximum | |||
| 461 | * connect time has expired. | |||
| 462 | */ | |||
| 463 | if (maxconnect > 0) | |||
| 464 | TIMEOUT(connect_time_expired, 0, maxconnect)timeout((connect_time_expired), (0), (maxconnect)); | |||
| 465 | ||||
| 466 | /* | |||
| 467 | * Detach now, if the updetach option was given. | |||
| 468 | */ | |||
| 469 | if (nodetach == -1) | |||
| 470 | detach(); | |||
| 471 | } | |||
| 472 | ++num_np_up; | |||
| 473 | } | |||
| 474 | ||||
| 475 | /* | |||
| 476 | * np_down - a network protocol has gone down. | |||
| 477 | */ | |||
| 478 | void | |||
| 479 | np_down(unit, proto) | |||
| 480 | int unit, proto; | |||
| 481 | { | |||
| 482 | if (--num_np_up == 0 && idle_time_limit > 0) { | |||
| 483 | UNTIMEOUT(check_idle, NULL)untimeout((check_idle), (((void*)0))); | |||
| 484 | } | |||
| 485 | } | |||
| 486 | ||||
| 487 | /* | |||
| 488 | * np_finished - a network protocol has finished using the link. | |||
| 489 | */ | |||
| 490 | void | |||
| 491 | np_finished(unit, proto) | |||
| 492 | int unit, proto; | |||
| 493 | { | |||
| 494 | if (--num_np_open <= 0) { | |||
| 495 | /* no further use for the link: shut up shop. */ | |||
| 496 | lcp_close(0, "No network protocols running"); | |||
| 497 | } | |||
| 498 | } | |||
| 499 | ||||
| 500 | /* | |||
| 501 | * check_idle - check whether the link has been idle for long | |||
| 502 | * enough that we can shut it down. | |||
| 503 | */ | |||
| 504 | static void | |||
| 505 | check_idle(arg) | |||
| 506 | void *arg; | |||
| 507 | { | |||
| 508 | struct ppp_idle idle; | |||
| 509 | time_t itime; | |||
| 510 | ||||
| 511 | if (!get_idle_time(0, &idle)) | |||
| 512 | return; | |||
| 513 | itime = MIN(idle.xmit_idle, idle.recv_idle)((idle.xmit_idle) < (idle.recv_idle)? (idle.xmit_idle): (idle .recv_idle)); | |||
| 514 | if (itime >= idle_time_limit) { | |||
| 515 | /* link is idle: shut it down. */ | |||
| 516 | syslog(LOG_INFO6, "Terminating connection due to lack of activity."); | |||
| 517 | lcp_close(0, "Link inactive"); | |||
| 518 | } else { | |||
| 519 | TIMEOUT(check_idle, NULL, idle_time_limit - itime)timeout((check_idle), (((void*)0)), (idle_time_limit - itime) ); | |||
| 520 | } | |||
| 521 | } | |||
| 522 | ||||
| 523 | /* | |||
| 524 | * connect_time_expired - log a message and close the connection. | |||
| 525 | */ | |||
| 526 | static void | |||
| 527 | connect_time_expired(arg) | |||
| 528 | void *arg; | |||
| 529 | { | |||
| 530 | syslog(LOG_INFO6, "Connect time expired"); | |||
| 531 | lcp_close(0, "Connect time expired"); /* Close connection */ | |||
| 532 | } | |||
| 533 | ||||
| 534 | /* | |||
| 535 | * auth_check_options - called to check authentication options. | |||
| 536 | */ | |||
| 537 | void | |||
| 538 | auth_check_options() | |||
| 539 | { | |||
| 540 | lcp_options *wo = &lcp_wantoptions[0]; | |||
| 541 | int can_auth; | |||
| 542 | ipcp_options *ipwo = &ipcp_wantoptions[0]; | |||
| 543 | u_int32_t remote; | |||
| 544 | ||||
| 545 | /* Default our_name to hostname, and user to our_name */ | |||
| 546 | if (our_name[0] == 0 || usehostname) | |||
| 547 | strlcpy(our_name, hostname, HOST_NAME_MAX255+1); | |||
| 548 | if (user[0] == 0) | |||
| 549 | strlcpy(user, our_name, MAXNAMELEN256); | |||
| 550 | ||||
| 551 | /* If authentication is required, ask peer for CHAP or PAP. */ | |||
| 552 | if (auth_required && !wo->neg_chap && !wo->neg_upap) { | |||
| 553 | wo->neg_chap = 1; | |||
| 554 | wo->neg_upap = 1; | |||
| 555 | } | |||
| 556 | ||||
| 557 | /* | |||
| 558 | * Check whether we have appropriate secrets to use | |||
| 559 | * to authenticate the peer. | |||
| 560 | */ | |||
| 561 | can_auth = wo->neg_upap && (uselogin || have_pap_secret()); | |||
| 562 | if (!can_auth && wo->neg_chap) { | |||
| 563 | remote = ipwo->accept_remote? 0: ipwo->hisaddr; | |||
| 564 | can_auth = have_chap_secret(remote_name, our_name, remote); | |||
| 565 | } | |||
| 566 | ||||
| 567 | if (auth_required && !can_auth) { | |||
| 568 | option_error("peer authentication required but no suitable secret(s) found\n"); | |||
| 569 | if (remote_name[0] == 0) | |||
| 570 | option_error("for authenticating any peer to us (%s)\n", our_name); | |||
| 571 | else | |||
| 572 | option_error("for authenticating peer %s to us (%s)\n", | |||
| 573 | remote_name, our_name); | |||
| 574 | exit(1); | |||
| 575 | } | |||
| 576 | ||||
| 577 | /* | |||
| 578 | * Check whether the user tried to override certain values | |||
| 579 | * set by root. | |||
| 580 | */ | |||
| 581 | if (!auth_required && auth_req_info.priv > 0) { | |||
| 582 | if (!default_device && devnam_info.priv == 0) { | |||
| 583 | option_error("can't override device name when noauth option used"); | |||
| 584 | exit(1); | |||
| 585 | } | |||
| 586 | if ((connector != NULL((void*)0) && connector_info.priv == 0) | |||
| 587 | || (disconnector != NULL((void*)0) && disconnector_info.priv == 0) | |||
| 588 | || (welcomer != NULL((void*)0) && welcomer_info.priv == 0)) { | |||
| 589 | option_error("can't override connect, disconnect or welcome"); | |||
| 590 | option_error("option values when noauth option used"); | |||
| 591 | exit(1); | |||
| 592 | } | |||
| 593 | } | |||
| 594 | } | |||
| 595 | ||||
| 596 | /* | |||
| 597 | * auth_reset - called when LCP is starting negotiations to recheck | |||
| 598 | * authentication options, i.e. whether we have appropriate secrets | |||
| 599 | * to use for authenticating ourselves and/or the peer. | |||
| 600 | */ | |||
| 601 | void | |||
| 602 | auth_reset(unit) | |||
| 603 | int unit; | |||
| 604 | { | |||
| 605 | lcp_options *go = &lcp_gotoptions[unit]; | |||
| 606 | lcp_options *ao = &lcp_allowoptions[0]; | |||
| 607 | ipcp_options *ipwo = &ipcp_wantoptions[0]; | |||
| 608 | u_int32_t remote; | |||
| 609 | ||||
| 610 | ao->neg_upap = !refuse_pap && (passwd[0] != 0 || get_pap_passwd(NULL((void*)0))); | |||
| 611 | ao->neg_chap = !refuse_chap | |||
| 612 | && have_chap_secret(user, remote_name, (u_int32_t)0); | |||
| 613 | ||||
| 614 | if (go->neg_upap && !uselogin && !have_pap_secret()) | |||
| 615 | go->neg_upap = 0; | |||
| 616 | if (go->neg_chap) { | |||
| 617 | remote = ipwo->accept_remote? 0: ipwo->hisaddr; | |||
| 618 | if (!have_chap_secret(remote_name, our_name, remote)) | |||
| 619 | go->neg_chap = 0; | |||
| 620 | } | |||
| 621 | } | |||
| 622 | ||||
| 623 | ||||
| 624 | /* | |||
| 625 | * check_passwd - Check the user name and passwd against the PAP secrets | |||
| 626 | * file. If requested, also check against the system password database, | |||
| 627 | * and login the user if OK. | |||
| 628 | * | |||
| 629 | * returns: | |||
| 630 | * UPAP_AUTHNAK: Authentication failed. | |||
| 631 | * UPAP_AUTHACK: Authentication succeeded. | |||
| 632 | * In either case, msg points to an appropriate message. | |||
| 633 | */ | |||
| 634 | int | |||
| 635 | check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen) | |||
| 636 | int unit; | |||
| 637 | char *auser; | |||
| 638 | int userlen; | |||
| 639 | char *apasswd; | |||
| 640 | int passwdlen; | |||
| 641 | char **msg; | |||
| 642 | int *msglen; | |||
| 643 | { | |||
| 644 | int ret; | |||
| 645 | char *filename; | |||
| 646 | FILE *f; | |||
| 647 | struct wordlist *addrs; | |||
| 648 | u_int32_t remote; | |||
| 649 | ipcp_options *ipwo = &ipcp_wantoptions[unit]; | |||
| 650 | char passwd[256], user[256]; | |||
| 651 | char secret[MAXWORDLEN1024]; | |||
| 652 | static int attempts = 0; | |||
| 653 | ||||
| 654 | /* | |||
| 655 | * Make copies of apasswd and auser, then null-terminate them. | |||
| 656 | */ | |||
| 657 | BCOPY(apasswd, passwd, passwdlen)memcpy(passwd, apasswd, passwdlen); | |||
| 658 | passwd[passwdlen] = '\0'; | |||
| 659 | BCOPY(auser, user, userlen)memcpy(user, auser, userlen); | |||
| 660 | user[userlen] = '\0'; | |||
| 661 | *msg = (char *) 0; | |||
| 662 | ||||
| 663 | /* | |||
| 664 | * Open the file of pap secrets and scan for a suitable secret | |||
| 665 | * for authenticating this user. | |||
| 666 | */ | |||
| 667 | filename = _PATH_UPAPFILE"/etc/ppp/pap-secrets"; | |||
| 668 | addrs = NULL((void*)0); | |||
| 669 | ret = UPAP_AUTHACK2; | |||
| 670 | f = fopen(filename, "r"); | |||
| 671 | if (f == NULL((void*)0)) { | |||
| ||||
| 672 | syslog(LOG_ERR3, "Can't open PAP password file %s: %m", filename); | |||
| 673 | ret = UPAP_AUTHNAK3; | |||
| 674 | } else { | |||
| 675 | check_access(f, filename); | |||
| 676 | remote = ipwo->accept_remote? 0: ipwo->hisaddr; | |||
| 677 | if (scan_authfile(f, user, our_name, remote, | |||
| 678 | secret, &addrs, filename) < 0 | |||
| 679 | || (secret[0] != 0 && (cryptpap || strcmp(passwd, secret) != 0) | |||
| 680 | && strcmp(crypt(passwd, secret), secret) != 0)) { | |||
| 681 | syslog(LOG_WARNING4, "PAP authentication failure for %s", user); | |||
| 682 | ret = UPAP_AUTHNAK3; | |||
| 683 | } | |||
| 684 | fclose(f); | |||
| 685 | } | |||
| 686 | ||||
| 687 | if (uselogin && ret
| |||
| 688 | ret = plogin(user, passwd, msg, msglen); | |||
| 689 | if (ret == UPAP_AUTHNAK3) { | |||
| 690 | syslog(LOG_WARNING4, "PAP login failure for %s", user); | |||
| 691 | } | |||
| 692 | } | |||
| 693 | ||||
| 694 | if (ret == UPAP_AUTHNAK3) { | |||
| 695 | if (*msg == (char *) 0) | |||
| 696 | *msg = "Login incorrect"; | |||
| 697 | *msglen = strlen(*msg); | |||
| 698 | /* | |||
| 699 | * Frustrate passwd stealer programs. | |||
| 700 | * Allow 10 tries, but start backing off after 3 (stolen from login). | |||
| 701 | * On 10'th, drop the connection. | |||
| 702 | */ | |||
| 703 | if (attempts++ >= 10) { | |||
| 704 | syslog(LOG_WARNING4, "%d LOGIN FAILURES ON %s, %s", | |||
| 705 | attempts, devnam, user); | |||
| 706 | quit(); | |||
| 707 | } | |||
| 708 | if (attempts > 3) | |||
| 709 | sleep((u_int) (attempts - 3) * 5); | |||
| 710 | if (addrs != NULL((void*)0)) | |||
| 711 | free_wordlist(addrs); | |||
| 712 | ||||
| 713 | } else { | |||
| 714 | attempts = 0; /* Reset count */ | |||
| 715 | if (*msg == (char *) 0) | |||
| 716 | *msg = "Login ok"; | |||
| 717 | *msglen = strlen(*msg); | |||
| 718 | set_allowed_addrs(unit, addrs); | |||
| 719 | } | |||
| 720 | ||||
| 721 | EXPLICIT_BZERO(passwd, sizeof(passwd))explicit_bzero(passwd, sizeof(passwd)); | |||
| 722 | EXPLICIT_BZERO(secret, sizeof(secret))explicit_bzero(secret, sizeof(secret)); | |||
| 723 | ||||
| 724 | return ret; | |||
| 725 | } | |||
| 726 | ||||
| 727 | /* | |||
| 728 | * plogin - Check the user name and password against the system | |||
| 729 | * password database, and login the user if OK. | |||
| 730 | * | |||
| 731 | * returns: | |||
| 732 | * UPAP_AUTHNAK: Login failed. | |||
| 733 | * UPAP_AUTHACK: Login succeeded. | |||
| 734 | * In either case, msg points to an appropriate message. | |||
| 735 | */ | |||
| 736 | ||||
| 737 | static int | |||
| 738 | plogin(user, passwd, msg, msglen) | |||
| 739 | char *user; | |||
| 740 | char *passwd; | |||
| 741 | char **msg; | |||
| 742 | int *msglen; | |||
| 743 | { | |||
| 744 | struct passwd *pw; | |||
| 745 | char *tty; | |||
| 746 | ||||
| 747 | pw = getpwnam_shadow(user); | |||
| 748 | if (crypt_checkpass(passwd, pw ? pw->pw_passwd : NULL((void*)0))) | |||
| 749 | return UPAP_AUTHNAK3; | |||
| 750 | ||||
| 751 | /* | |||
| 752 | * Write a wtmp entry for this user. | |||
| 753 | */ | |||
| 754 | ||||
| 755 | tty = devnam; | |||
| 756 | if (strncmp(tty, "/dev/", 5) == 0) | |||
| 757 | tty += 5; | |||
| 758 | logwtmp(tty, user, remote_name); /* Add wtmp login entry */ | |||
| 759 | ||||
| 760 | #if defined(_PATH_LASTLOG"/var/log/lastlog") | |||
| 761 | { | |||
| 762 | struct lastlog ll; | |||
| 763 | int fd; | |||
| 764 | ||||
| 765 | if ((fd = open(_PATH_LASTLOG"/var/log/lastlog", O_RDWR0x0002)) >= 0) { | |||
| 766 | memset(&ll, 0, sizeof(ll)); | |||
| 767 | (void)time(&ll.ll_time); | |||
| 768 | (void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); | |||
| 769 | (void)pwrite(fd, &ll, sizeof(ll), (off_t)pw->pw_uid * | |||
| ||||
| 770 | sizeof(ll)); | |||
| 771 | (void)close(fd); | |||
| 772 | } | |||
| 773 | } | |||
| 774 | #endif | |||
| 775 | ||||
| 776 | ||||
| 777 | syslog(LOG_INFO6, "user %s logged in", user); | |||
| 778 | logged_in = TRUE1; | |||
| 779 | ||||
| 780 | return (UPAP_AUTHACK2); | |||
| 781 | } | |||
| 782 | ||||
| 783 | /* | |||
| 784 | * plogout - Logout the user. | |||
| 785 | */ | |||
| 786 | static void | |||
| 787 | plogout() | |||
| 788 | { | |||
| 789 | char *tty; | |||
| 790 | ||||
| 791 | tty = devnam; | |||
| 792 | if (strncmp(tty, "/dev/", 5) == 0) | |||
| 793 | tty += 5; | |||
| 794 | logwtmp(tty, "", ""); /* Wipe out utmp logout entry */ | |||
| 795 | ||||
| 796 | logged_in = FALSE0; | |||
| 797 | } | |||
| 798 | ||||
| 799 | ||||
| 800 | /* | |||
| 801 | * null_login - Check if a username of "" and a password of "" are | |||
| 802 | * acceptable, and iff so, set the list of acceptable IP addresses | |||
| 803 | * and return 1. | |||
| 804 | */ | |||
| 805 | static int | |||
| 806 | null_login(unit) | |||
| 807 | int unit; | |||
| 808 | { | |||
| 809 | char *filename; | |||
| 810 | FILE *f; | |||
| 811 | int i, ret; | |||
| 812 | struct wordlist *addrs; | |||
| 813 | char secret[MAXWORDLEN1024]; | |||
| 814 | ||||
| 815 | /* | |||
| 816 | * Open the file of pap secrets and scan for a suitable secret. | |||
| 817 | * We don't accept a wildcard client. | |||
| 818 | */ | |||
| 819 | filename = _PATH_UPAPFILE"/etc/ppp/pap-secrets"; | |||
| 820 | addrs = NULL((void*)0); | |||
| 821 | f = fopen(filename, "r"); | |||
| 822 | if (f == NULL((void*)0)) | |||
| 823 | return 0; | |||
| 824 | check_access(f, filename); | |||
| 825 | ||||
| 826 | i = scan_authfile(f, "", our_name, (u_int32_t)0, secret, &addrs, filename); | |||
| 827 | ret = i >= 0 && (i & NONWILD_CLIENT2) != 0 && secret[0] == 0; | |||
| 828 | EXPLICIT_BZERO(secret, sizeof(secret))explicit_bzero(secret, sizeof(secret)); | |||
| 829 | ||||
| 830 | if (ret) | |||
| 831 | set_allowed_addrs(unit, addrs); | |||
| 832 | else | |||
| 833 | free_wordlist(addrs); | |||
| 834 | ||||
| 835 | fclose(f); | |||
| 836 | return ret; | |||
| 837 | } | |||
| 838 | ||||
| 839 | ||||
| 840 | /* | |||
| 841 | * get_pap_passwd - get a password for authenticating ourselves with | |||
| 842 | * our peer using PAP. Returns 1 on success, 0 if no suitable password | |||
| 843 | * could be found. | |||
| 844 | */ | |||
| 845 | static int | |||
| 846 | get_pap_passwd(passwd) | |||
| 847 | char *passwd; | |||
| 848 | { | |||
| 849 | char *filename; | |||
| 850 | FILE *f; | |||
| 851 | int ret; | |||
| 852 | char secret[MAXWORDLEN1024]; | |||
| 853 | ||||
| 854 | filename = _PATH_UPAPFILE"/etc/ppp/pap-secrets"; | |||
| 855 | f = fopen(filename, "r"); | |||
| 856 | if (f == NULL((void*)0)) | |||
| 857 | return 0; | |||
| 858 | check_access(f, filename); | |||
| 859 | ret = scan_authfile(f, user, | |||
| 860 | remote_name[0]? remote_name: NULL((void*)0), | |||
| 861 | (u_int32_t)0, secret, NULL((void*)0), filename); | |||
| 862 | fclose(f); | |||
| 863 | if (ret < 0) | |||
| 864 | return 0; | |||
| 865 | if (passwd != NULL((void*)0)) | |||
| 866 | strlcpy(passwd, secret, MAXSECRETLEN256); | |||
| 867 | EXPLICIT_BZERO(secret, sizeof(secret))explicit_bzero(secret, sizeof(secret)); | |||
| 868 | return 1; | |||
| 869 | } | |||
| 870 | ||||
| 871 | ||||
| 872 | /* | |||
| 873 | * have_pap_secret - check whether we have a PAP file with any | |||
| 874 | * secrets that we could possibly use for authenticating the peer. | |||
| 875 | */ | |||
| 876 | static int | |||
| 877 | have_pap_secret() | |||
| 878 | { | |||
| 879 | FILE *f; | |||
| 880 | int ret; | |||
| 881 | char *filename; | |||
| 882 | ipcp_options *ipwo = &ipcp_wantoptions[0]; | |||
| 883 | u_int32_t remote; | |||
| 884 | ||||
| 885 | filename = _PATH_UPAPFILE"/etc/ppp/pap-secrets"; | |||
| 886 | f = fopen(filename, "r"); | |||
| 887 | if (f == NULL((void*)0)) | |||
| 888 | return 0; | |||
| 889 | ||||
| 890 | remote = ipwo->accept_remote? 0: ipwo->hisaddr; | |||
| 891 | ret = scan_authfile(f, NULL((void*)0), our_name, remote, NULL((void*)0), NULL((void*)0), filename); | |||
| 892 | fclose(f); | |||
| 893 | if (ret < 0) | |||
| 894 | return 0; | |||
| 895 | ||||
| 896 | return 1; | |||
| 897 | } | |||
| 898 | ||||
| 899 | ||||
| 900 | /* | |||
| 901 | * have_chap_secret - check whether we have a CHAP file with a | |||
| 902 | * secret that we could possibly use for authenticating `client' | |||
| 903 | * on `server'. Either can be the null string, meaning we don't | |||
| 904 | * know the identity yet. | |||
| 905 | */ | |||
| 906 | static int | |||
| 907 | have_chap_secret(client, server, remote) | |||
| 908 | char *client; | |||
| 909 | char *server; | |||
| 910 | u_int32_t remote; | |||
| 911 | { | |||
| 912 | FILE *f; | |||
| 913 | int ret; | |||
| 914 | char *filename; | |||
| 915 | ||||
| 916 | filename = _PATH_CHAPFILE"/etc/ppp/chap-secrets"; | |||
| 917 | f = fopen(filename, "r"); | |||
| 918 | if (f == NULL((void*)0)) | |||
| 919 | return 0; | |||
| 920 | ||||
| 921 | if (client[0] == 0) | |||
| 922 | client = NULL((void*)0); | |||
| 923 | else if (server[0] == 0) | |||
| 924 | server = NULL((void*)0); | |||
| 925 | ||||
| 926 | ret = scan_authfile(f, client, server, remote, NULL((void*)0), NULL((void*)0), filename); | |||
| 927 | fclose(f); | |||
| 928 | if (ret < 0) | |||
| 929 | return 0; | |||
| 930 | ||||
| 931 | return 1; | |||
| 932 | } | |||
| 933 | ||||
| 934 | ||||
| 935 | /* | |||
| 936 | * get_secret - open the CHAP secret file and return the secret | |||
| 937 | * for authenticating the given client on the given server. | |||
| 938 | * (We could be either client or server). | |||
| 939 | */ | |||
| 940 | int | |||
| 941 | get_secret(unit, client, server, secret, secret_len, save_addrs) | |||
| 942 | int unit; | |||
| 943 | char *client; | |||
| 944 | char *server; | |||
| 945 | char *secret; | |||
| 946 | int *secret_len; | |||
| 947 | int save_addrs; | |||
| 948 | { | |||
| 949 | FILE *f; | |||
| 950 | int ret, len; | |||
| 951 | char *filename; | |||
| 952 | struct wordlist *addrs; | |||
| 953 | char secbuf[MAXWORDLEN1024]; | |||
| 954 | ||||
| 955 | filename = _PATH_CHAPFILE"/etc/ppp/chap-secrets"; | |||
| 956 | addrs = NULL((void*)0); | |||
| 957 | secbuf[0] = 0; | |||
| 958 | ||||
| 959 | f = fopen(filename, "r"); | |||
| 960 | if (f == NULL((void*)0)) { | |||
| 961 | syslog(LOG_ERR3, "Can't open chap secret file %s: %m", filename); | |||
| 962 | return 0; | |||
| 963 | } | |||
| 964 | check_access(f, filename); | |||
| 965 | ||||
| 966 | ret = scan_authfile(f, client, server, (u_int32_t)0, | |||
| 967 | secbuf, &addrs, filename); | |||
| 968 | fclose(f); | |||
| 969 | if (ret < 0) | |||
| 970 | return 0; | |||
| 971 | ||||
| 972 | if (save_addrs) | |||
| 973 | set_allowed_addrs(unit, addrs); | |||
| 974 | ||||
| 975 | len = strlen(secbuf); | |||
| 976 | if (len > MAXSECRETLEN256) { | |||
| 977 | syslog(LOG_ERR3, "Secret for %s on %s is too long", client, server); | |||
| 978 | len = MAXSECRETLEN256; | |||
| 979 | } | |||
| 980 | BCOPY(secbuf, secret, len)memcpy(secret, secbuf, len); | |||
| 981 | EXPLICIT_BZERO(secbuf, sizeof(secbuf))explicit_bzero(secbuf, sizeof(secbuf)); | |||
| 982 | *secret_len = len; | |||
| 983 | ||||
| 984 | return 1; | |||
| 985 | } | |||
| 986 | ||||
| 987 | /* | |||
| 988 | * set_allowed_addrs() - set the list of allowed addresses. | |||
| 989 | */ | |||
| 990 | static void | |||
| 991 | set_allowed_addrs(unit, addrs) | |||
| 992 | int unit; | |||
| 993 | struct wordlist *addrs; | |||
| 994 | { | |||
| 995 | if (addresses[unit] != NULL((void*)0)) | |||
| 996 | free_wordlist(addresses[unit]); | |||
| 997 | addresses[unit] = addrs; | |||
| 998 | ||||
| 999 | /* | |||
| 1000 | * If there's only one authorized address we might as well | |||
| 1001 | * ask our peer for that one right away | |||
| 1002 | */ | |||
| 1003 | if (addrs != NULL((void*)0) && addrs->next == NULL((void*)0)) { | |||
| 1004 | char *p = addrs->word; | |||
| 1005 | struct ipcp_options *wo = &ipcp_wantoptions[unit]; | |||
| 1006 | struct in_addr ina; | |||
| 1007 | struct hostent *hp; | |||
| 1008 | ||||
| 1009 | if (*p != '!' && *p != '-' && !ISWILD(p)(p[0] == '*' && p[1] == 0) && strchr(p, '/') == NULL((void*)0)) { | |||
| 1010 | hp = gethostbyname(p); | |||
| 1011 | if (hp != NULL((void*)0) && hp->h_addrtype == AF_INET2) | |||
| 1012 | wo->hisaddr = *(u_int32_t *)hp->h_addrh_addr_list[0]; | |||
| 1013 | else if (inet_aton(p, &ina) == 1) | |||
| 1014 | wo->hisaddr = ina.s_addr; | |||
| 1015 | } | |||
| 1016 | } | |||
| 1017 | } | |||
| 1018 | ||||
| 1019 | /* | |||
| 1020 | * auth_ip_addr - check whether the peer is authorized to use | |||
| 1021 | * a given IP address. Returns 1 if authorized, 0 otherwise. | |||
| 1022 | */ | |||
| 1023 | int | |||
| 1024 | auth_ip_addr(unit, addr) | |||
| 1025 | int unit; | |||
| 1026 | u_int32_t addr; | |||
| 1027 | { | |||
| 1028 | return ip_addr_check(addr, addresses[unit]); | |||
| 1029 | } | |||
| 1030 | ||||
| 1031 | static int | |||
| 1032 | ip_addr_check(addr, addrs) | |||
| 1033 | u_int32_t addr; | |||
| 1034 | struct wordlist *addrs; | |||
| 1035 | { | |||
| 1036 | u_int32_t mask, ah; | |||
| 1037 | struct in_addr ina; | |||
| 1038 | int accept, r = 1; | |||
| 1039 | char *ptr_word, *ptr_mask; | |||
| 1040 | struct hostent *hp; | |||
| 1041 | ||||
| 1042 | /* don't allow loopback or multicast address */ | |||
| 1043 | if (bad_ip_adrs(addr)) | |||
| 1044 | return 0; | |||
| 1045 | ||||
| 1046 | if (addrs == NULL((void*)0)) | |||
| 1047 | return !auth_required; /* no addresses authorized */ | |||
| 1048 | ||||
| 1049 | for (; addrs != NULL((void*)0); addrs = addrs->next) { | |||
| 1050 | /* "-" means no addresses authorized, "*" means any address allowed */ | |||
| 1051 | ptr_word = addrs->word; | |||
| 1052 | if (strcmp(ptr_word, "-") == 0) | |||
| 1053 | break; | |||
| 1054 | if (strcmp(ptr_word, "*") == 0) | |||
| 1055 | return 1; | |||
| 1056 | ||||
| 1057 | accept = 1; | |||
| 1058 | if (*ptr_word == '!') { | |||
| 1059 | accept = 0; | |||
| 1060 | ++ptr_word; | |||
| 1061 | } | |||
| 1062 | ||||
| 1063 | mask = ~ (u_int32_t) 0; | |||
| 1064 | ptr_mask = strchr (ptr_word, '/'); | |||
| 1065 | if (ptr_mask != NULL((void*)0)) { | |||
| 1066 | int bit_count; | |||
| 1067 | ||||
| 1068 | bit_count = (int) strtol (ptr_mask+1, (char **) 0, 10); | |||
| 1069 | if (bit_count <= 0 || bit_count > 32) { | |||
| 1070 | syslog (LOG_WARNING4, | |||
| 1071 | "invalid address length %s in auth. address list", | |||
| 1072 | ptr_mask); | |||
| 1073 | continue; | |||
| 1074 | } | |||
| 1075 | *ptr_mask = '\0'; | |||
| 1076 | mask <<= 32 - bit_count; | |||
| 1077 | } | |||
| 1078 | ||||
| 1079 | hp = gethostbyname(ptr_word); | |||
| 1080 | if (hp != NULL((void*)0) && hp->h_addrtype == AF_INET2) { | |||
| 1081 | ina.s_addr = *(u_int32_t *)hp->h_addrh_addr_list[0]; | |||
| 1082 | } else { | |||
| 1083 | r = inet_aton (ptr_word, &ina); | |||
| 1084 | if (ptr_mask == NULL((void*)0)) { | |||
| 1085 | /* calculate appropriate mask for net */ | |||
| 1086 | ah = ntohl(ina.s_addr)(__uint32_t)(__builtin_constant_p(ina.s_addr) ? (__uint32_t)( ((__uint32_t)(ina.s_addr) & 0xff) << 24 | ((__uint32_t )(ina.s_addr) & 0xff00) << 8 | ((__uint32_t)(ina.s_addr ) & 0xff0000) >> 8 | ((__uint32_t)(ina.s_addr) & 0xff000000) >> 24) : __swap32md(ina.s_addr)); | |||
| 1087 | if (IN_CLASSA(ah)(((u_int32_t)(ah) & ((u_int32_t)(0x80000000))) == ((u_int32_t )(0x00000000)))) | |||
| 1088 | mask = IN_CLASSA_NET((u_int32_t)(0xff000000)); | |||
| 1089 | else if (IN_CLASSB(ah)(((u_int32_t)(ah) & ((u_int32_t)(0xc0000000))) == ((u_int32_t )(0x80000000)))) | |||
| 1090 | mask = IN_CLASSB_NET((u_int32_t)(0xffff0000)); | |||
| 1091 | else if (IN_CLASSC(ah)(((u_int32_t)(ah) & ((u_int32_t)(0xe0000000))) == ((u_int32_t )(0xc0000000)))) | |||
| 1092 | mask = IN_CLASSC_NET((u_int32_t)(0xffffff00)); | |||
| 1093 | } | |||
| 1094 | } | |||
| 1095 | ||||
| 1096 | if (ptr_mask != NULL((void*)0)) | |||
| 1097 | *ptr_mask = '/'; | |||
| 1098 | ||||
| 1099 | if (r == 0) | |||
| 1100 | syslog (LOG_WARNING4, | |||
| 1101 | "unknown host %s in auth. address list", | |||
| 1102 | addrs->word); | |||
| 1103 | else | |||
| 1104 | /* Here ina.s_addr and addr are in network byte order, | |||
| 1105 | and mask is in host order. */ | |||
| 1106 | if (((addr ^ ina.s_addr) & htonl(mask)(__uint32_t)(__builtin_constant_p(mask) ? (__uint32_t)(((__uint32_t )(mask) & 0xff) << 24 | ((__uint32_t)(mask) & 0xff00 ) << 8 | ((__uint32_t)(mask) & 0xff0000) >> 8 | ((__uint32_t)(mask) & 0xff000000) >> 24) : __swap32md (mask))) == 0) | |||
| 1107 | return accept; | |||
| 1108 | } | |||
| 1109 | return 0; /* not in list => can't have it */ | |||
| 1110 | } | |||
| 1111 | ||||
| 1112 | /* | |||
| 1113 | * bad_ip_adrs - return 1 if the IP address is one we don't want | |||
| 1114 | * to use, such as an address in the loopback net or a multicast address. | |||
| 1115 | * addr is in network byte order. | |||
| 1116 | */ | |||
| 1117 | int | |||
| 1118 | bad_ip_adrs(addr) | |||
| 1119 | u_int32_t addr; | |||
| 1120 | { | |||
| 1121 | addr = ntohl(addr)(__uint32_t)(__builtin_constant_p(addr) ? (__uint32_t)(((__uint32_t )(addr) & 0xff) << 24 | ((__uint32_t)(addr) & 0xff00 ) << 8 | ((__uint32_t)(addr) & 0xff0000) >> 8 | ((__uint32_t)(addr) & 0xff000000) >> 24) : __swap32md (addr)); | |||
| 1122 | return (addr >> IN_CLASSA_NSHIFT24) == IN_LOOPBACKNET127 | |||
| 1123 | || IN_MULTICAST(addr)(((u_int32_t)(addr) & ((u_int32_t)(0xf0000000))) == ((u_int32_t )(0xe0000000))) || IN_BADCLASS(addr)(((u_int32_t)(addr) & ((u_int32_t)(0xf0000000))) == ((u_int32_t )(0xf0000000))); | |||
| 1124 | } | |||
| 1125 | ||||
| 1126 | /* | |||
| 1127 | * check_access - complain if a secret file has too-liberal permissions. | |||
| 1128 | */ | |||
| 1129 | void | |||
| 1130 | check_access(f, filename) | |||
| 1131 | FILE *f; | |||
| 1132 | char *filename; | |||
| 1133 | { | |||
| 1134 | struct stat sbuf; | |||
| 1135 | ||||
| 1136 | if (fstat(fileno(f)(!__isthreaded ? ((f)->_file) : (fileno)(f)), &sbuf) < 0) { | |||
| 1137 | syslog(LOG_WARNING4, "cannot stat secret file %s: %m", filename); | |||
| 1138 | } else if ((sbuf.st_mode & (S_IRWXG0000070 | S_IRWXO0000007)) != 0) { | |||
| 1139 | syslog(LOG_WARNING4, "Warning - secret file %s has world and/or group access", filename); | |||
| 1140 | } | |||
| 1141 | } | |||
| 1142 | ||||
| 1143 | ||||
| 1144 | /* | |||
| 1145 | * scan_authfile - Scan an authorization file for a secret suitable | |||
| 1146 | * for authenticating `client' on `server'. The return value is -1 | |||
| 1147 | * if no secret is found, otherwise >= 0. The return value has | |||
| 1148 | * NONWILD_CLIENT set if the secret didn't have "*" for the client, and | |||
| 1149 | * NONWILD_SERVER set if the secret didn't have "*" for the server. | |||
| 1150 | * Any following words on the line (i.e. address authorization | |||
| 1151 | * info) are placed in a wordlist and returned in *addrs. | |||
| 1152 | */ | |||
| 1153 | static int | |||
| 1154 | scan_authfile(f, client, server, ipaddr, secret, addrs, filename) | |||
| 1155 | FILE *f; | |||
| 1156 | char *client; | |||
| 1157 | char *server; | |||
| 1158 | u_int32_t ipaddr; | |||
| 1159 | char *secret; | |||
| 1160 | struct wordlist **addrs; | |||
| 1161 | char *filename; | |||
| 1162 | { | |||
| 1163 | int newline, xxx; | |||
| 1164 | int got_flag, best_flag; | |||
| 1165 | FILE *sf; | |||
| 1166 | struct wordlist *ap, *addr_list, *alist, *alast; | |||
| 1167 | char word[MAXWORDLEN1024]; | |||
| 1168 | char atfile[MAXWORDLEN1024]; | |||
| 1169 | char lsecret[MAXWORDLEN1024]; | |||
| 1170 | ||||
| 1171 | if (addrs != NULL((void*)0)) | |||
| 1172 | *addrs = NULL((void*)0); | |||
| 1173 | addr_list = NULL((void*)0); | |||
| 1174 | if (!getword(f, word, &newline, filename)) | |||
| 1175 | return -1; /* file is empty??? */ | |||
| 1176 | newline = 1; | |||
| 1177 | best_flag = -1; | |||
| 1178 | for (;;) { | |||
| 1179 | /* | |||
| 1180 | * Skip until we find a word at the start of a line. | |||
| 1181 | */ | |||
| 1182 | while (!newline && getword(f, word, &newline, filename)) | |||
| 1183 | ; | |||
| 1184 | if (!newline) | |||
| 1185 | break; /* got to end of file */ | |||
| 1186 | ||||
| 1187 | /* | |||
| 1188 | * Got a client - check if it's a match or a wildcard. | |||
| 1189 | */ | |||
| 1190 | got_flag = 0; | |||
| 1191 | if (client != NULL((void*)0) && strcmp(word, client) != 0 && !ISWILD(word)(word[0] == '*' && word[1] == 0)) { | |||
| 1192 | newline = 0; | |||
| 1193 | continue; | |||
| 1194 | } | |||
| 1195 | if (!ISWILD(word)(word[0] == '*' && word[1] == 0)) | |||
| 1196 | got_flag = NONWILD_CLIENT2; | |||
| 1197 | ||||
| 1198 | /* | |||
| 1199 | * Now get a server and check if it matches. | |||
| 1200 | */ | |||
| 1201 | if (!getword(f, word, &newline, filename)) | |||
| 1202 | break; | |||
| 1203 | if (newline) | |||
| 1204 | continue; | |||
| 1205 | if (server != NULL((void*)0) && strcmp(word, server) != 0 && !ISWILD(word)(word[0] == '*' && word[1] == 0)) | |||
| 1206 | continue; | |||
| 1207 | if (!ISWILD(word)(word[0] == '*' && word[1] == 0)) | |||
| 1208 | got_flag |= NONWILD_SERVER1; | |||
| 1209 | ||||
| 1210 | /* | |||
| 1211 | * Got some sort of a match - see if it's better than what | |||
| 1212 | * we have already. | |||
| 1213 | */ | |||
| 1214 | if (got_flag <= best_flag) | |||
| 1215 | continue; | |||
| 1216 | ||||
| 1217 | /* | |||
| 1218 | * Get the secret. | |||
| 1219 | */ | |||
| 1220 | if (!getword(f, word, &newline, filename)) | |||
| 1221 | break; | |||
| 1222 | if (newline) | |||
| 1223 | continue; | |||
| 1224 | ||||
| 1225 | /* | |||
| 1226 | * Special syntax: @filename means read secret from file. | |||
| 1227 | */ | |||
| 1228 | if (word[0] == '@') { | |||
| 1229 | strlcpy(atfile, word+1, sizeof atfile); | |||
| 1230 | if ((sf = fopen(atfile, "r")) == NULL((void*)0)) { | |||
| 1231 | syslog(LOG_WARNING4, "can't open indirect secret file %s", | |||
| 1232 | atfile); | |||
| 1233 | continue; | |||
| 1234 | } | |||
| 1235 | check_access(sf, atfile); | |||
| 1236 | if (!getword(sf, word, &xxx, atfile)) { | |||
| 1237 | syslog(LOG_WARNING4, "no secret in indirect secret file %s", | |||
| 1238 | atfile); | |||
| 1239 | fclose(sf); | |||
| 1240 | continue; | |||
| 1241 | } | |||
| 1242 | fclose(sf); | |||
| 1243 | } | |||
| 1244 | if (secret != NULL((void*)0)) | |||
| 1245 | strlcpy(lsecret, word, sizeof lsecret); | |||
| 1246 | ||||
| 1247 | /* | |||
| 1248 | * Now read address authorization info and make a wordlist. | |||
| 1249 | */ | |||
| 1250 | alist = alast = NULL((void*)0); | |||
| 1251 | for (;;) { | |||
| 1252 | size_t wordlen; | |||
| 1253 | ||||
| 1254 | if (!getword(f, word, &newline, filename) || newline) | |||
| 1255 | break; | |||
| 1256 | wordlen = strlen(word); /* NUL in struct wordlist */ | |||
| 1257 | ap = (struct wordlist *) malloc(sizeof(struct wordlist) + | |||
| 1258 | wordlen); | |||
| 1259 | ||||
| 1260 | if (ap == NULL((void*)0)) | |||
| 1261 | novm("authorized addresses"); | |||
| 1262 | ap->next = NULL((void*)0); | |||
| 1263 | strlcpy(ap->word, word, wordlen + 1); | |||
| 1264 | if (alist == NULL((void*)0)) | |||
| 1265 | alist = ap; | |||
| 1266 | else | |||
| 1267 | alast->next = ap; | |||
| 1268 | alast = ap; | |||
| 1269 | } | |||
| 1270 | ||||
| 1271 | /* | |||
| 1272 | * Check if the given IP address is allowed by the wordlist. | |||
| 1273 | */ | |||
| 1274 | if (ipaddr != 0 && !ip_addr_check(ipaddr, alist)) { | |||
| 1275 | free_wordlist(alist); | |||
| 1276 | continue; | |||
| 1277 | } | |||
| 1278 | ||||
| 1279 | /* | |||
| 1280 | * This is the best so far; remember it. | |||
| 1281 | */ | |||
| 1282 | best_flag = got_flag; | |||
| 1283 | if (addr_list) | |||
| 1284 | free_wordlist(addr_list); | |||
| 1285 | addr_list = alist; | |||
| 1286 | if (secret != NULL((void*)0)) | |||
| 1287 | strlcpy(secret, lsecret, MAXWORDLEN1024); | |||
| 1288 | ||||
| 1289 | if (!newline) | |||
| 1290 | break; | |||
| 1291 | } | |||
| 1292 | ||||
| 1293 | if (addrs != NULL((void*)0)) | |||
| 1294 | *addrs = addr_list; | |||
| 1295 | else if (addr_list != NULL((void*)0)) | |||
| 1296 | free_wordlist(addr_list); | |||
| 1297 | ||||
| 1298 | return best_flag; | |||
| 1299 | } | |||
| 1300 | ||||
| 1301 | /* | |||
| 1302 | * free_wordlist - release memory allocated for a wordlist. | |||
| 1303 | */ | |||
| 1304 | static void | |||
| 1305 | free_wordlist(wp) | |||
| 1306 | struct wordlist *wp; | |||
| 1307 | { | |||
| 1308 | struct wordlist *next; | |||
| 1309 | ||||
| 1310 | while (wp != NULL((void*)0)) { | |||
| 1311 | next = wp->next; | |||
| 1312 | free(wp); | |||
| 1313 | wp = next; | |||
| 1314 | } | |||
| 1315 | } | |||
| 1316 | ||||
| 1317 | /* | |||
| 1318 | * auth_script - execute a script with arguments | |||
| 1319 | * interface-name peer-name real-user tty speed | |||
| 1320 | */ | |||
| 1321 | static void | |||
| 1322 | auth_script(script) | |||
| 1323 | char *script; | |||
| 1324 | { | |||
| 1325 | char strspeed[32]; | |||
| 1326 | struct passwd *pw; | |||
| 1327 | char struid[32]; | |||
| 1328 | char *user_name; | |||
| 1329 | char *argv[8]; | |||
| 1330 | ||||
| 1331 | if ((pw = getpwuid(getuid())) != NULL((void*)0) && pw->pw_name != NULL((void*)0)) | |||
| 1332 | user_name = pw->pw_name; | |||
| 1333 | else { | |||
| 1334 | snprintf(struid, sizeof struid, "%u", getuid()); | |||
| 1335 | user_name = struid; | |||
| 1336 | } | |||
| 1337 | snprintf(strspeed, sizeof strspeed, "%d", baud_rate); | |||
| 1338 | ||||
| 1339 | argv[0] = script; | |||
| 1340 | argv[1] = ifname; | |||
| 1341 | argv[2] = peer_authname; | |||
| 1342 | argv[3] = user_name; | |||
| 1343 | argv[4] = devnam; | |||
| 1344 | argv[5] = strspeed; | |||
| 1345 | argv[6] = NULL((void*)0); | |||
| 1346 | ||||
| 1347 | run_program(script, argv, 0); | |||
| 1348 | } |