1/* $OpenBSD: pap.c,v 1.13 2024/02/26 08:47:28 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/* $Id: pap.c,v 1.13 2024/02/26 08:47:28 yasuoka Exp $ */ 29/**@file 30 * This file provides Password Authentication Protocol (PAP) handlers. 31 * @author Yasuoka Masahiko 32 */ 33#include <sys/types.h> 34#include <sys/socket.h> 35#include <sys/time.h> 36#include <net/if_dl.h> 37#include <netinet/in.h> 38 39#include <event.h> 40#include <md5.h> 41#include <stdarg.h> 42#include <stdio.h> 43#include <stdlib.h> 44#include <string.h> 45#include <syslog.h> 46#include <errno.h> 47#include <vis.h> 48 49#include "npppd.h" 50#include "ppp.h" 51 52#ifdef USE_NPPPD_RADIUS 53#include <radius.h> 54#include "radius_chap_const.h" 55#include "npppd_radius.h" 56#endif 57 58#include "debugutil.h" 59 60#define AUTHREQ 0x01 61#define AUTHACK 0x02 62#define AUTHNAK 0x03 63 64#define PAP_STATE_INITIAL 0 65#define PAP_STATE_STARTING 1 66#define PAP_STATE_AUTHENTICATING 2 67#define PAP_STATE_SENT_RESPONSE 3 68#define PAP_STATE_STOPPED 4 69#define PAP_STATE_PROXY_AUTHENTICATION 5 70 71#define DEFAULT_SUCCESS_MESSAGE "OK" 72#define DEFAULT_FAILURE_MESSAGE "Unknown username or password" 73#define DEFAULT_ERROR_MESSAGE "Unknown failure" 74 75#ifdef PAP_DEBUG 76#define PAP_DBG(x) pap_log x 77#define PAP_ASSERT(cond) \ 78 if (!(cond)) { \ 79 fprintf(stderr, \ 80 "\nASSERT(" #cond ") failed on %s() at %s:%d.\n"\ 81 , __func__, __FILE__, __LINE__); \ 82 abort(); \ 83 } 84#else 85#define PAP_ASSERT(cond) 86#define PAP_DBG(x) 87#endif 88 89static void pap_log (pap *, uint32_t, const char *, ...) __printflike(3,4); 90static void pap_response (pap *, int, const char *); 91static void pap_authenticate(pap *, const char *); 92static void pap_local_authenticate (pap *, const char *, const char *); 93#ifdef USE_NPPPD_RADIUS 94static void pap_radius_authenticate (pap *, const char *, const char *); 95static void pap_radius_response (void *, RADIUS_PACKET *, int, RADIUS_REQUEST_CTX); 96#endif 97 98#ifdef __cplusplus 99extern "C" { 100#endif 101 102void pap_init (pap *, npppd_ppp *); 103int pap_start (pap *); 104int pap_stop (pap *); 105int pap_input (pap *, u_char *, int); 106 107#ifdef __cplusplus 108} 109#endif 110 111void 112pap_init(pap *_this, npppd_ppp *ppp) 113{ 114 _this->ppp = ppp; 115 _this->state = PAP_STATE_INITIAL; 116 _this->auth_id = -1; 117} 118 119int 120pap_start(pap *_this) 121{ 122 pap_log(_this, LOG_DEBUG, "%s", __func__); 123 124 if (_this->state == PAP_STATE_PROXY_AUTHENTICATION) { 125 _this->state = PAP_STATE_AUTHENTICATING; 126 pap_authenticate(_this, _this->ppp->proxy_authen_resp); 127 return 0; 128 } 129 130 _this->state = PAP_STATE_STARTING; 131 return 0; 132} 133 134int 135pap_stop(pap *_this) 136{ 137 _this->state = PAP_STATE_STOPPED; 138 _this->auth_id = -1; 139 140#ifdef USE_NPPPD_RADIUS 141 if (_this->radctx != NULL) { 142 radius_cancel_request(_this->radctx); 143 _this->radctx = NULL; 144 } 145#endif 146 return 0; 147} 148 149/** Receiving PAP packet */ 150int 151pap_input(pap *_this, u_char *pktp, int lpktp) 152{ 153 int code, id, length, len; 154 u_char *pktp1; 155 char name[MAX_USERNAME_LENGTH], password[MAX_PASSWORD_LENGTH]; 156 157 if (_this->state == PAP_STATE_STOPPED || 158 _this->state == PAP_STATE_INITIAL) { 159 pap_log(_this, LOG_ERR, "Received pap packet. But pap is " 160 "not started."); 161 return -1; 162 } 163 pktp1 = pktp; 164 165 GETCHAR(code, pktp1); 166 GETCHAR(id, pktp1); 167 GETSHORT(length, pktp1); 168 169 if (code != AUTHREQ) { 170 pap_log(_this, LOG_ERR, "%s: Received unknown code=%d", 171 __func__, code); 172 return -1; 173 } 174 if (lpktp < length) { 175 pap_log(_this, LOG_ERR, "%s: Received broken packet.", 176 __func__); 177 return -1; 178 } 179 180 /* retribute the username */ 181#define remlen (lpktp - (pktp1 - pktp)) 182 if (remlen < 1) 183 goto fail; 184 GETCHAR(len, pktp1); 185 if (len <= 0) 186 goto fail; 187 if (remlen < len) 188 goto fail; 189 if (len > 0) 190 memcpy(name, pktp1, len); 191 name[len] = '\0'; 192 pktp1 += len; 193 194 if (_this->state != PAP_STATE_STARTING) { 195 /* 196 * Receiving identical message again, it must be the message 197 * retransmit by the peer. Continue if the username is same. 198 */ 199 if ((_this->state == PAP_STATE_AUTHENTICATING || 200 _this->state == PAP_STATE_SENT_RESPONSE) && 201 strcmp(_this->name, name) == 0) { 202 /* continue */ 203 } else { 204 pap_log(_this, LOG_ERR, 205 "Received AuthReq is not same as before. " 206 "(%d,%s) != (%d,%s)", id, name, _this->auth_id, 207 _this->name); 208 _this->auth_id = id; 209 goto fail; 210 } 211 } 212 if (_this->state == PAP_STATE_AUTHENTICATING) 213 return 0; 214 _this->auth_id = id; 215 strlcpy(_this->name, name, sizeof(_this->name)); 216 217 _this->state = PAP_STATE_AUTHENTICATING; 218 219 /* retribute the password */ 220 if (remlen < 1) 221 goto fail; 222 GETCHAR(len, pktp1); 223 if (remlen < len) 224 goto fail; 225 if (len > 0) 226 memcpy(password, pktp1, len); 227 228 password[len] = '\0'; 229 pap_authenticate(_this, password); 230 231 return 0; 232fail: 233 pap_response(_this, 0, DEFAULT_FAILURE_MESSAGE); 234 return -1; 235} 236 237static void 238pap_authenticate(pap *_this, const char *password) 239{ 240 if (npppd_ppp_bind_realm(_this->ppp->pppd, _this->ppp, _this->name, 0) 241 == 0) { 242 if (!npppd_ppp_is_realm_ready(_this->ppp->pppd, _this->ppp)) { 243 pap_log(_this, LOG_INFO, 244 "username=\"%s\" realm is not ready.", _this->name); 245 goto fail; 246 /* NOTREACHED */ 247 } 248#if USE_NPPPD_RADIUS 249 if (npppd_ppp_is_realm_radius(_this->ppp->pppd, _this->ppp)) { 250 pap_radius_authenticate(_this, _this->name, password); 251 return; 252 /* NOTREACHED */ 253 } else 254#endif 255 if (npppd_ppp_is_realm_local(_this->ppp->pppd, _this->ppp)) { 256 pap_local_authenticate(_this, _this->name, password); 257 return; 258 /* NOTREACHED */ 259 } 260 } 261fail: 262 pap_response(_this, 0, DEFAULT_FAILURE_MESSAGE); 263} 264 265static void 266pap_log(pap *_this, uint32_t prio, const char *fmt, ...) 267{ 268 char logbuf[BUFSIZ]; 269 va_list ap; 270 271 va_start(ap, fmt); 272 snprintf(logbuf, sizeof(logbuf), "ppp id=%u layer=pap %s", 273 _this->ppp->id, fmt); 274 vlog_printf(prio, logbuf, ap); 275 va_end(ap); 276} 277 278static void 279pap_response(pap *_this, int authok, const char *mes) 280{ 281 int lpktp, lmes; 282 u_char *pktp, *pktp1; 283 const char *realm; 284 285 pktp = ppp_packetbuf(_this->ppp, PPP_PROTO_PAP) + HEADERLEN; 286 lpktp = _this->ppp->mru - HEADERLEN; 287 realm = npppd_ppp_get_realm_name(_this->ppp->pppd, _this->ppp); 288 289 pktp1 = pktp; 290 if (mes == NULL) 291 lmes = 0; 292 else 293 lmes = strlen(mes); 294 lmes = MINIMUM(lmes, lpktp - 1); 295 296 PUTCHAR(lmes, pktp1); 297 if (lmes > 0) 298 memcpy(pktp1, mes, lmes); 299 lpktp = lmes + 1; 300 301 if (authok) 302 ppp_output(_this->ppp, PPP_PROTO_PAP, AUTHACK, _this->auth_id, 303 pktp, lpktp); 304 else 305 ppp_output(_this->ppp, PPP_PROTO_PAP, AUTHNAK, _this->auth_id, 306 pktp, lpktp); 307 308 if (!authok) { 309 pap_log(_this, LOG_ALERT, 310 "logtype=Failure username=\"%s\" realm=%s", _this->name, 311 realm); 312 pap_stop(_this); 313 ppp_set_disconnect_cause(_this->ppp, 314 PPP_DISCON_AUTH_FAILED, PPP_PROTO_PAP, 1 /* peer */, NULL); 315 ppp_stop(_this->ppp, "Authentication Required"); 316 } else { 317 strlcpy(_this->ppp->username, _this->name, 318 sizeof(_this->ppp->username)); 319 pap_log(_this, LOG_INFO, 320 "logtype=Success username=\"%s\" realm=%s", _this->name, 321 realm); 322 pap_stop(_this); 323 ppp_auth_ok(_this->ppp); 324 /* reset the state to response request of retransmision. */ 325 _this->state = PAP_STATE_SENT_RESPONSE; 326 } 327} 328 329static void 330pap_local_authenticate(pap *_this, const char *username, const char *password) 331{ 332 int lpassword0; 333 char password0[MAX_PASSWORD_LENGTH]; 334 335 lpassword0 = sizeof(password0); 336 337 if (npppd_get_user_password(_this->ppp->pppd, _this->ppp, username, 338 password0, &lpassword0) == 0) { 339 if (!strcmp(password0, password)) { 340 pap_response(_this, 1, DEFAULT_SUCCESS_MESSAGE); 341 return; 342 } 343 } 344 pap_response(_this, 0, DEFAULT_FAILURE_MESSAGE); 345} 346 347/*********************************************************************** 348 * Proxy Authentication 349 ***********************************************************************/ 350int 351pap_proxy_authen_prepare(pap *_this, dialin_proxy_info *dpi) 352{ 353 354 PAP_ASSERT(dpi->auth_type == PPP_AUTH_PAP); 355 PAP_ASSERT(_this->state == PAP_STATE_INITIAL); 356 357 _this->auth_id = dpi->auth_id; 358 if (strlen(dpi->username) >= sizeof(_this->name)) { 359 pap_log(_this, LOG_NOTICE, 360 "\"Proxy Authen Name\" is too long."); 361 return -1; 362 } 363 364 /* copy the authentication properties */ 365 PAP_ASSERT(_this->ppp->proxy_authen_resp == NULL); 366 if ((_this->ppp->proxy_authen_resp = malloc(dpi->lauth_resp + 1)) == 367 NULL) { 368 pap_log(_this, LOG_ERR, "malloc() failed in %s(): %m", 369 __func__); 370 return -1; 371 } 372 memcpy(_this->ppp->proxy_authen_resp, dpi->auth_resp, 373 dpi->lauth_resp); 374 _this->ppp->proxy_authen_resp[dpi->lauth_resp] = '\0'; 375 strlcpy(_this->name, dpi->username, sizeof(_this->name)); 376 377 _this->state = PAP_STATE_PROXY_AUTHENTICATION; 378 379 return 0; 380} 381 382#ifdef USE_NPPPD_RADIUS 383static void 384pap_radius_authenticate(pap *_this, const char *username, const char *password) 385{ 386 void *radctx; 387 RADIUS_PACKET *radpkt; 388 MD5_CTX md5ctx; 389 int i, j, s_len, passlen; 390 u_char ra[16], digest[16], pass[128]; 391 const char *s; 392 radius_req_setting *rad_setting = NULL; 393 char buf0[MAX_USERNAME_LENGTH]; 394 395 if ((rad_setting = npppd_get_radius_auth_setting(_this->ppp->pppd, 396 _this->ppp)) == NULL) 397 goto fail; 398 399 if ((radpkt = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST)) 400 == NULL) 401 goto fail; 402 403 if (radius_prepare(rad_setting, _this, &radctx, pap_radius_response) 404 != 0) { 405 radius_delete_packet(radpkt); 406 goto fail; 407 } 408 409 if (ppp_set_radius_attrs_for_authreq(_this->ppp, rad_setting, radpkt) 410 != 0) 411 goto fail; 412 413 if (radius_put_string_attr(radpkt, RADIUS_TYPE_USER_NAME, 414 npppd_ppp_get_username_for_auth(_this->ppp->pppd, _this->ppp, 415 username, buf0)) != 0) 416 goto fail; 417 418 if (_this->radctx != NULL) 419 radius_cancel_request(_this->radctx); 420 421 _this->radctx = radctx; 422 423 /* Create RADIUS User-Password Attribute (RFC 2865, 5.2.) */ 424 s = radius_get_server_secret(_this->radctx); 425 s_len = strlen(s); 426 427 memset(pass, 0, sizeof(pass)); /* null padding */ 428 passlen = MINIMUM(strlen(password), sizeof(pass)); 429 memcpy(pass, password, passlen); 430 if ((passlen % 16) != 0) 431 passlen += 16 - (passlen % 16); 432 433 radius_get_authenticator(radpkt, ra); 434 435 MD5Init(&md5ctx); 436 MD5Update(&md5ctx, s, s_len); 437 MD5Update(&md5ctx, ra, 16); 438 MD5Final(digest, &md5ctx); 439 440 for (i = 0; i < 16; i++) 441 pass[i] ^= digest[i]; 442 443 while (i < passlen) { 444 MD5Init(&md5ctx); 445 MD5Update(&md5ctx, s, s_len); 446 MD5Update(&md5ctx, &pass[i - 16], 16); 447 MD5Final(digest, &md5ctx); 448 449 for (j = 0; j < 16; j++, i++) 450 pass[i] ^= digest[j]; 451 } 452 453 if (radius_put_raw_attr(radpkt, RADIUS_TYPE_USER_PASSWORD, pass, 454 passlen) != 0) 455 goto fail; 456 457 radius_request(_this->radctx, radpkt); 458 459 return; 460fail: 461 if (_this->radctx != NULL) 462 radius_cancel_request(_this->radctx); 463 pap_log(_this, LOG_ERR, "%s() failed: %m", __func__); 464 pap_response(_this, 0, DEFAULT_ERROR_MESSAGE); 465 466 return; 467} 468 469static void 470pap_radius_response(void *context, RADIUS_PACKET *pkt, int flags, 471 RADIUS_REQUEST_CTX reqctx) 472{ 473 int code = -1; 474 const char *reason = NULL; 475 RADIUS_REQUEST_CTX radctx; 476 pap *_this; 477 478 _this = context; 479 radctx = _this->radctx; 480 _this->radctx = NULL; /* important */ 481 482 if (pkt == NULL) { 483 if (flags & RADIUS_REQUEST_TIMEOUT) 484 reason = "timeout"; 485 else if (flags & RADIUS_REQUEST_ERROR) 486 reason = strerror(errno); 487 else 488 reason = "error"; 489 goto auth_failed; 490 } 491 code = radius_get_code(pkt); 492 if (code == RADIUS_CODE_ACCESS_REJECT) { 493 reason="reject"; 494 goto auth_failed; 495 } else if (code != RADIUS_CODE_ACCESS_ACCEPT) { 496 reason="error"; 497 goto auth_failed; 498 } 499 if ((flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_OK) == 0 && 500 (flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_NO_CHECK) == 0) { 501 reason="bad_authenticator"; 502 goto auth_failed; 503 } 504 if ((flags & RADIUS_REQUEST_CHECK_MSG_AUTHENTICATOR_OK) == 0 && 505 (flags & RADIUS_REQUEST_CHECK_NO_MSG_AUTHENTICATOR) == 0) { 506 reason="bad_authenticator"; 507 goto auth_failed; 508 } 509 /* Authentication succeeded */ 510 pap_response(_this, 1, DEFAULT_SUCCESS_MESSAGE); 511 ppp_process_radius_framed_ip(_this->ppp, pkt); 512 513 return; 514auth_failed: 515 /* Authentication failure */ 516 pap_log(_this, LOG_WARNING, "Radius authentication request failed: %s", 517 reason); 518 /* log reply messages from radius server */ 519 if (pkt != NULL) { 520 char radmsg[255], vissed[1024]; 521 size_t rmlen = 0; 522 if ((radius_get_raw_attr(pkt, RADIUS_TYPE_REPLY_MESSAGE, 523 radmsg, &rmlen)) == 0) { 524 if (rmlen != 0) { 525 strvisx(vissed, radmsg, rmlen, VIS_WHITE); 526 pap_log(_this, LOG_WARNING, 527 "Radius reply message: %s", vissed); 528 } 529 } 530 } 531 532 pap_response(_this, 0, DEFAULT_FAILURE_MESSAGE); 533} 534#endif 535