1/* $OpenBSD: npppd_auth.c,v 1.23 2024/02/26 10:42:05 yasuoka Exp $ */ 2 3/*- 4 * Copyright (c) 2009 Internet Initiative Japan Inc. 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/**@file authentication realm */ 29/* $Id: npppd_auth.c,v 1.23 2024/02/26 10:42:05 yasuoka Exp $ */ 30#include <sys/types.h> 31#include <sys/stat.h> 32#include <sys/socket.h> 33#include <netinet/in.h> 34#include <net/if_dl.h> 35#include <arpa/inet.h> 36#include <stdio.h> 37#include <syslog.h> 38#include <string.h> 39#include <time.h> 40#include <event.h> 41#include <stdarg.h> 42#include <stdlib.h> 43#include <netdb.h> 44#include <errno.h> 45 46#include "debugutil.h" 47#include "npppd_local.h" 48#include "npppd_auth.h" 49#include "net_utils.h" 50 51#include "npppd_auth_local.h" 52#include "npppd_radius.h" 53 54/** 55 * Create a npppd_auth_base object. 56 * @param auth_type the authentication type. 57 * specify {@link ::NPPPD_AUTH_TYPE_LOCAL} to authenticate by the local 58 * file, or specify {@link ::NPPPD_AUTH_TYPE_RADIUS} for RADIUS 59 * authentication. 60 * @param name the configuration name 61 * @param _npppd the parent {@link ::npppd} object 62 * @see ::NPPPD_AUTH_TYPE_LOCAL 63 * @see ::NPPPD_AUTH_TYPE_RADIUS 64 * @return The pointer to the {@link ::npppd_auth_base} object will be returned 65 * in case success otherwise NULL will be returned. 66 */ 67npppd_auth_base * 68npppd_auth_create(int auth_type, const char *name, void *_npppd) 69{ 70 npppd_auth_base *base; 71 72 NPPPD_AUTH_ASSERT(name != NULL); 73 74 switch (auth_type) { 75 case NPPPD_AUTH_TYPE_LOCAL: 76 if ((base = calloc(1, sizeof(npppd_auth_local))) != NULL) { 77 base->type = NPPPD_AUTH_TYPE_LOCAL; 78 strlcpy(base->name, name, sizeof(base->name)); 79 base->npppd = _npppd; 80 81 return base; 82 } 83 break; 84 85#ifdef USE_NPPPD_RADIUS 86 case NPPPD_AUTH_TYPE_RADIUS: 87 if ((base = calloc(1, sizeof(npppd_auth_radius))) != NULL) { 88 npppd_auth_radius *_this = (npppd_auth_radius *)base; 89 base->type = NPPPD_AUTH_TYPE_RADIUS; 90 strlcpy(base->name, name, sizeof(base->name)); 91 base->npppd = _npppd; 92 if ((_this->rad_auth_setting = 93 radius_req_setting_create()) == NULL) 94 goto radius_fail; 95 if ((_this->rad_acct_setting = 96 radius_req_setting_create()) == NULL) 97 goto radius_fail; 98 99 return base; 100radius_fail: 101 if (_this->rad_auth_setting != NULL) 102 radius_req_setting_destroy( 103 _this->rad_auth_setting); 104 if (_this->rad_acct_setting != NULL) 105 radius_req_setting_destroy( 106 _this->rad_acct_setting); 107 free(base); 108 return NULL; 109 } 110 111 break; 112#endif 113 114 default: 115 NPPPD_AUTH_ASSERT(0); 116 break; 117 } 118 119 return NULL; 120} 121 122/** 123 * Call this function to make the object unusable. 124 * <p> 125 * {@link ::npppd_auth_base} objects is referred by the {@link ::npppd_ppp} 126 * object. After this function is called, npppd will disconnect the PPP 127 * links that refers the object, it will call {@link ::npppd_auth_destroy()} 128 * when all the references to the object are released.</p> 129 */ 130void 131npppd_auth_dispose(npppd_auth_base *base) 132{ 133 134 base->disposing = 1; 135 136 return; 137} 138 139/** Destroy the {@link ::npppd_auth_base} object. */ 140void 141npppd_auth_destroy(npppd_auth_base *base) 142{ 143 144 if (base->disposing == 0) 145 npppd_auth_dispose(base); 146 147 npppd_auth_base_log(base, LOG_INFO, "Finalized"); 148 149 switch(base->type) { 150 case NPPPD_AUTH_TYPE_LOCAL: 151 memset(base, 0, sizeof(npppd_auth_local)); 152 break; 153 154#ifdef USE_NPPPD_RADIUS 155 case NPPPD_AUTH_TYPE_RADIUS: 156 { 157 npppd_auth_radius *_this = (npppd_auth_radius *)base; 158 if (_this->rad_auth_setting != NULL) 159 radius_req_setting_destroy(_this->rad_auth_setting); 160 _this->rad_auth_setting = NULL; 161 if (_this->rad_acct_setting != NULL) 162 radius_req_setting_destroy(_this->rad_acct_setting); 163 _this->rad_acct_setting = NULL; 164 memset(base, 0, sizeof(npppd_auth_local)); 165 break; 166 } 167#endif 168 } 169 free(base); 170 171 return; 172} 173 174/** Reload the configuration */ 175int 176npppd_auth_reload(npppd_auth_base *base) 177{ 178 struct authconf *auth; 179 180 TAILQ_FOREACH(auth, &base->npppd->conf.authconfs, entry) { 181 if (strcmp(auth->name, base->name) == 0) 182 break; 183 } 184 if (auth == NULL) 185 return 1; 186 187 base->pppsuffix[0] = '\0'; 188 if (auth->username_suffix != NULL) 189 strlcpy(base->pppsuffix, auth->username_suffix, 190 sizeof(base->pppsuffix)); 191 base->eap_capable = auth->eap_capable; 192 base->strip_nt_domain = auth->strip_nt_domain; 193 base->strip_atmark_realm = auth->strip_atmark_realm; 194 base->has_users_file = 0; 195 base->radius_ready = 0; 196 base->user_max_session = auth->user_max_session; 197 198 if (strlen(auth->users_file_path) > 0) { 199 strlcpy(base->users_file_path, auth->users_file_path, 200 sizeof(base->users_file_path)); 201 base->has_users_file = 1; 202 } else { 203 if (base->type == NPPPD_AUTH_TYPE_LOCAL) { 204 npppd_auth_base_log(base, 205 LOG_WARNING, "missing users_file property."); 206 goto fail; 207 } 208 } 209 210 switch (base->type) { 211#ifdef USE_NPPPD_RADIUS 212 case NPPPD_AUTH_TYPE_RADIUS: 213 if (npppd_auth_radius_reload(base, auth) != 0) 214 goto fail; 215 break; 216#endif 217 } 218 base->initialized = 1; 219 220 return 0; 221 222fail: 223 base->initialized = 0; 224 base->has_users_file = 0; 225 base->radius_ready = 0; 226 227 return 1; 228} 229 230/** 231 * This function gets specified user's password. The value 0 is returned 232 * if the call succeeds. 233 * 234 * @param username username which gets the password 235 * @param password buffers which stores the password 236 * Specify NULL if you want to known the length of 237 * the password only. 238 * @param lppassword pointer which indicates the length of 239 * the buffer which stores the password. 240 * @return A value 1 is returned if user is unknown. A value 2 is returned 241 * if password buffer is sufficient. A negative value is 242 * returned if other error occurred. 243 */ 244int 245npppd_auth_get_user_password(npppd_auth_base *base, 246 const char *username, char *password, int *plpassword) 247{ 248 int retval, sz, lpassword; 249 npppd_auth_user *user; 250 251 NPPPD_AUTH_ASSERT(base != NULL); 252 NPPPD_AUTH_DBG((base, LOG_DEBUG, "%s(%s)", __func__, username)); 253 254 user = NULL; 255 retval = 0; 256 if (base->has_users_file == 0) { 257 retval = -1; 258 goto out; 259 } 260 if ((user = npppd_auth_get_user(base, username)) == NULL) { 261 retval = 1; 262 goto out; 263 } 264 if (password == NULL && plpassword == NULL) { 265 retval = 0; 266 goto out; 267 } 268 if (plpassword == NULL) { 269 retval = -1; 270 goto out; 271 } 272 lpassword = strlen(user->password) + 1; 273 sz = *plpassword; 274 *plpassword = lpassword; 275 if (password == NULL) { 276 retval = 0; 277 goto out; 278 } 279 if (sz < lpassword) { 280 retval = 2; 281 goto out; 282 } 283 strlcpy(password, user->password, sz); 284out: 285 free(user); 286 287 return retval; 288} 289 290/** 291 * This function gets specified users' Framed-IP-{Address,Netmask}. 292 * The value 0 is returned if the call succeeds. 293 * <p> 294 * Because authentication database is updated at any time, the password is 295 * possible to be inconsistent if this function is not called immediately 296 * after authentication. So this function is called immediately after 297 * authentication. </p> 298 * @param username username which gets the password 299 * @param ip4address pointer which indicates struct in_addr which 300 * stores the Framed-IP-Address 301 * @param ip4netmask pointer which indicates struct in_addr which 302 * stores Framed-IP-Netmask 303 */ 304int 305npppd_auth_get_framed_ip(npppd_auth_base *base, const char *username, 306 struct in_addr *ip4address, struct in_addr *ip4netmask) 307{ 308 npppd_auth_user *user; 309 310 NPPPD_AUTH_ASSERT(base != NULL); 311 NPPPD_AUTH_DBG((base, LOG_DEBUG, "%s(%s)", __func__, username)); 312 if (base->has_users_file == 0) 313 return -1; 314 315 if ((user = npppd_auth_get_user(base, username)) == NULL) 316 return 1; 317 318 if (user->framed_ip_address.s_addr != 0) { 319 *ip4address = user->framed_ip_address; 320 if (ip4netmask != NULL) 321 *ip4netmask = user->framed_ip_netmask; 322 323 free(user); 324 return 0; 325 } 326 free(user); 327 328 return 1; 329} 330 331/** 332 * Retribute "Calling-Number" attribute of the user from the realm. 333 * 334 * @param username Username. 335 * @param number Pointer to the space for the Calling-Number. This 336 * can be NULL in case retributing the Calling-Number only. 337 * @param plnumber Pointer to the length of the space for the 338 * Calling-Number. 339 * @return 0 if the Calling-Number attribute is successfully retributed. 340 * 1 if the user has no Calling-Number attribute. return -1 if the realm 341 * doesn't have user attributes or other errors. return 2 if the space 342 * is not enough. 343 */ 344int 345npppd_auth_get_calling_number(npppd_auth_base *base, const char *username, 346 char *number, int *plnumber) 347{ 348 int retval, lcallnum, sz; 349 npppd_auth_user *user; 350 351 user = NULL; 352 retval = 0; 353 if (base->has_users_file == 0) 354 return -1; 355 356 if ((user = npppd_auth_get_user(base, username)) == NULL) 357 return 1; 358 359 if (number == NULL && plnumber == NULL) { 360 retval = 0; 361 goto out; 362 } 363 if (plnumber == NULL) { 364 retval = -1; 365 goto out; 366 } 367 lcallnum = strlen(user->calling_number) + 1; 368 sz = *plnumber; 369 *plnumber = lcallnum; 370 if (sz < lcallnum) { 371 retval = 2; 372 goto out; 373 } 374 strlcpy(number, user->calling_number, sz); 375 376out: 377 free(user); 378 379 return retval; 380} 381 382int 383npppd_auth_get_type(npppd_auth_base *base) 384{ 385 return base->type; 386} 387 388int 389npppd_auth_is_usable(npppd_auth_base *base) 390{ 391 return (base->initialized != 0 && base->disposing == 0)? 1 : 0; 392} 393 394int 395npppd_auth_is_ready(npppd_auth_base *base) 396{ 397 if (!npppd_auth_is_usable(base)) 398 return 0; 399 400 switch(base->type) { 401 case NPPPD_AUTH_TYPE_LOCAL: 402 return (base->has_users_file)? 1 : 0; 403 /* NOTREACHED */ 404 405 case NPPPD_AUTH_TYPE_RADIUS: 406 return (base->has_users_file != 0 || 407 base->radius_ready != 0)? 1 : 0; 408 /* NOTREACHED */ 409 } 410 NPPPD_AUTH_ASSERT(0); 411 412 return 0; 413} 414 415int 416npppd_auth_is_disposing(npppd_auth_base *base) 417{ 418 return (base->disposing != 0)? 1 : 0; 419} 420 421int 422npppd_auth_is_eap_capable(npppd_auth_base *base) 423{ 424 return (base->eap_capable != 0)? 1 : 0; 425} 426 427const char * 428npppd_auth_get_name(npppd_auth_base *base) 429{ 430 return base->name; 431} 432 433const char * 434npppd_auth_get_suffix(npppd_auth_base *base) 435{ 436 return base->pppsuffix; 437} 438 439const char * 440npppd_auth_username_for_auth(npppd_auth_base *base, const char *username, 441 char *username_buffer) 442{ 443 const char *u0; 444 char *atmark, *u1; 445 446 u0 = NULL; 447 if (base->strip_nt_domain != 0) { 448 if ((u0 = strchr(username, '\\')) != NULL) 449 u0++; 450 } 451 if (u0 == NULL) 452 u0 = username; 453 u1 = username_buffer; 454 if (username_buffer != u0) 455 memmove(username_buffer, u0, MINIMUM(strlen(u0) + 1, 456 MAX_USERNAME_LENGTH)); 457 if (base->strip_atmark_realm != 0) { 458 if ((atmark = strrchr(u1, '@')) != NULL) 459 *atmark = '\0'; 460 } 461 462 return username_buffer; 463} 464 465int 466npppd_auth_user_session_unlimited(npppd_auth_base *_this) 467{ 468 return (_this->user_max_session == 0) ? 1 : 0; 469} 470 471int 472npppd_check_auth_user_max_session(npppd_auth_base *_this, int count) 473{ 474 if (!npppd_auth_user_session_unlimited(_this) && 475 _this->user_max_session <= count) 476 return 1; 477 else 478 return 0; 479} 480 481/*********************************************************************** 482 * Account list related functions 483 ***********************************************************************/ 484static npppd_auth_user * 485npppd_auth_get_user(npppd_auth_base *base, const char *username) 486{ 487 int lsuffix, lusername; 488 const char *un; 489 char buf[MAX_USERNAME_LENGTH]; 490 npppd_auth_user *u; 491 492 un = username; 493 lsuffix = strlen(base->pppsuffix); 494 lusername = strlen(username); 495 if (lsuffix > 0 && lusername > lsuffix && 496 strcmp(username + lusername - lsuffix, base->pppsuffix) == 0 && 497 lusername - lsuffix < sizeof(buf)) { 498 memcpy(buf, username, lusername - lsuffix); 499 buf[lusername - lsuffix] = '\0'; 500 un = buf; 501 } 502 503 if (priv_get_user_info(base->users_file_path, un, &u) == 0) 504 return u; 505 506 return NULL; 507} 508 509#ifdef USE_NPPPD_RADIUS 510/*********************************************************************** 511 * RADIUS 512 ***********************************************************************/ 513/** reload the configuration of RADIUS authentication realm */ 514static int 515npppd_auth_radius_reload(npppd_auth_base *base, struct authconf *auth) 516{ 517 npppd_auth_radius *_this = (npppd_auth_radius *)base; 518 radius_req_setting *rad; 519 struct radserver *server; 520 int i, nauth, nacct; 521 522 _this->rad_auth_setting->timeout = 523 (auth->data.radius.auth.timeout == 0) 524 ? DEFAULT_RADIUS_TIMEOUT : auth->data.radius.auth.timeout; 525 _this->rad_acct_setting->timeout = 526 (auth->data.radius.acct.timeout == 0) 527 ? DEFAULT_RADIUS_TIMEOUT : auth->data.radius.acct.timeout; 528 529 530 _this->rad_auth_setting->max_tries = 531 (auth->data.radius.auth.max_tries == 0) 532 ? DEFAULT_RADIUS_MAX_TRIES : auth->data.radius.auth.max_tries; 533 _this->rad_acct_setting->max_tries = 534 (auth->data.radius.acct.max_tries == 0) 535 ? DEFAULT_RADIUS_MAX_TRIES : auth->data.radius.acct.max_tries; 536 537 _this->rad_auth_setting->max_failovers = 538 (auth->data.radius.auth.max_failovers == 0) 539 ? DEFAULT_RADIUS_MAX_FAILOVERS 540 : auth->data.radius.auth.max_failovers; 541 _this->rad_acct_setting->max_failovers = 542 (auth->data.radius.acct.max_failovers == 0) 543 ? DEFAULT_RADIUS_MAX_FAILOVERS 544 : auth->data.radius.acct.max_failovers; 545 546 _this->rad_acct_setting->curr_server = 547 _this->rad_auth_setting->curr_server = 0; 548 549 /* load configs for authentication server */ 550 rad = _this->rad_auth_setting; 551 for (i = 0; i < countof(rad->server); i++) 552 memset(&rad->server[i], 0, sizeof(rad->server[0])); 553 i = 0; 554 TAILQ_FOREACH(server, &auth->data.radius.auth.servers, entry) { 555 if (i >= countof(rad->server)) 556 break; 557 memcpy(&rad->server[i].peer, &server->address, 558 server->address.ss_len); 559 if (((struct sockaddr_in *)&rad->server[i].peer)->sin_port 560 == 0) 561 ((struct sockaddr_in *)&rad->server[i].peer)->sin_port 562 = htons(DEFAULT_RADIUS_AUTH_PORT); 563 strlcpy(rad->server[i].secret, server->secret, 564 sizeof(rad->server[i].secret)); 565 rad->server[i].enabled = 1; 566 i++; 567 } 568 nauth = i; 569 570 /* load configs for accounting server */ 571 rad = _this->rad_acct_setting; 572 for (i = 0; i < countof(rad->server); i++) 573 memset(&rad->server[i], 0, sizeof(rad->server[0])); 574 i = 0; 575 TAILQ_FOREACH(server, &auth->data.radius.acct.servers, entry) { 576 if (i >= countof(rad->server)) 577 break; 578 memcpy(&rad->server[i].peer, &server->address, 579 server->address.ss_len); 580 if (((struct sockaddr_in *)&rad->server[i].peer)->sin_port 581 == 0) 582 ((struct sockaddr_in *)&rad->server[i].peer)->sin_port 583 = htons(DEFAULT_RADIUS_ACCT_PORT); 584 strlcpy(rad->server[i].secret, server->secret, 585 sizeof(rad->server[i].secret)); 586 rad->server[i].enabled = 1; 587 i++; 588 } 589 nacct = i; 590 591 for (i = 0; i < countof(_this->rad_auth_setting->server); i++) { 592 if (_this->rad_auth_setting->server[i].enabled) 593 base->radius_ready = 1; 594 } 595 596 npppd_auth_base_log(&_this->nar_base, LOG_INFO, 597 "Loaded configuration. %d authentication server%s, %d accounting " 598 "server%s.", 599 nauth, (nauth > 1)? "s" : "", nacct, (nacct > 1)? "s" : ""); 600 601 if (nacct > 0 && _this->rad_acct_on == 0) { 602 radius_acct_on(base->npppd, _this->rad_acct_setting); 603 _this->rad_acct_on = 1; 604 } 605 606 return 0; 607} 608 609/** 610 * Get {@link ::radius_req_setting} for RADIUS authentication of specified 611 * {@link ::npppd_auth_base} object. 612 */ 613void * 614npppd_auth_radius_get_radius_auth_setting(npppd_auth_radius *_this) 615{ 616 return _this->rad_auth_setting; 617} 618 619/** 620 * Get {@link ::radius_req_setting} for RADIUS accounting of specified 621 * {@link ::npppd_auth_base} object. 622 */ 623void * 624npppd_auth_radius_get_radius_acct_setting(npppd_auth_radius *_this) 625{ 626 return _this->rad_acct_setting; 627} 628 629#endif 630 631/*********************************************************************** 632 * Helper functions 633 ***********************************************************************/ 634/** Log it which starts the label based on this instance. */ 635static int 636npppd_auth_base_log(npppd_auth_base *_this, int prio, const char *fmt, ...) 637{ 638 int status; 639 char logbuf[BUFSIZ]; 640 va_list ap; 641 642 NPPPD_AUTH_ASSERT(_this != NULL); 643 va_start(ap, fmt); 644 snprintf(logbuf, sizeof(logbuf), "realm name=%s %s", 645 _this->name, fmt); 646 status = vlog_printf(prio, logbuf, ap); 647 va_end(ap); 648 649 return status; 650} 651