diff --git a/distrib/miniroot/install.sub b/distrib/miniroot/install.sub index 701b0e3de..655515781 100644 --- a/distrib/miniroot/install.sub +++ b/distrib/miniroot/install.sub @@ -1,5 +1,5 @@ #!/bin/ksh -# $OpenBSD: install.sub,v 1.1265 2024/06/15 15:05:15 florian Exp $ +# $OpenBSD: install.sub,v 1.1266 2024/07/09 14:47:21 krw Exp $ # # Copyright (c) 1997-2015 Todd Miller, Theo de Raadt, Ken Westerback # Copyright (c) 2015, Robert Peichaer @@ -2675,10 +2675,9 @@ start_cgiinfo() { # # In addition, # -# 1) delete 'softdep' options (no soft updates in ramdisk kernels), -# 2) mount non-ffs filesystems read only, -# 3) prepend '/mnt' to all mount points, -# 4) delete any trailing '/' from the mount point (e.g. root), +# 1) mount non-ffs filesystems read only, +# 2) prepend '/mnt' to all mount points, +# 3) delete any trailing '/' from the mount point (e.g. root), # # If no /etc/fstab is created, do not proceed with install/upgrade. munge_fstab() { @@ -2692,10 +2691,6 @@ munge_fstab() { $_opt == *noauto* || $_opt == *xx* ]] && continue - # Remove any softdep options, as soft updates are not - # available in the ramdisk kernels. - _opt=$(echo $_opt | sed 's/softdep//') - # Change read-only ffs to read-write since we'll potentially # write to these filesystems. # Mount non-ffs filesystems read only. diff --git a/lib/libcrypto/Makefile b/lib/libcrypto/Makefile index 7b926db11..96a0f197c 100644 --- a/lib/libcrypto/Makefile +++ b/lib/libcrypto/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.196 2024/06/24 06:43:22 tb Exp $ +# $OpenBSD: Makefile,v 1.199 2024/07/09 16:41:44 tb Exp $ LIB= crypto LIBREBUILD=y @@ -19,9 +19,9 @@ CFLAGS+= -Wall -Wundef CFLAGS+= -Werror -Wshadow .endif CFLAGS+= -DLIBRESSL_INTERNAL -.ifdef NAMESPACE + CFLAGS+= -DLIBRESSL_NAMESPACE -DLIBRESSL_CRYPTO_NAMESPACE -.endif + CFLAGS+= -DHAVE_FUNOPEN CFLAGS+= -I${LCRYPTO_SRC} @@ -391,6 +391,7 @@ SRCS+= idea.c # kdf/ SRCS+= hkdf_evp.c SRCS+= kdf_err.c +SRCS+= tls1_prf.c # lhash/ SRCS+= lhash.c @@ -745,18 +746,11 @@ includes: prereq echo $$j; \ eval "$$j"; \ done; -.ifdef NAMESPACE ${VERSION_SCRIPT}: ${SYMBOL_LIST} ${SYMBOL_NAMESPACE} { printf '{\n\tglobal:\n'; \ sed '/^[._a-zA-Z]/s/$$/;/; s/^/ /' ${SYMBOL_NAMESPACE}; \ sed '/^[._a-zA-Z]/s/$$/;/; s/^/ /' ${SYMBOL_LIST}; \ printf '\n\tlocal:\n\t\t*;\n};\n'; } >$@.tmp && mv $@.tmp $@ -.else -${VERSION_SCRIPT}: ${SYMBOL_LIST} - { printf '{\n\tglobal:\n'; \ - sed '/^[._a-zA-Z]/s/$$/;/; s/^/ /' ${SYMBOL_LIST}; \ - printf '\n\tlocal:\n\t\t*;\n};\n'; } >$@.tmp && mv $@.tmp $@ -.endif # generated CFLAGS+= -I${.OBJDIR} diff --git a/lib/libcrypto/Symbols.namespace b/lib/libcrypto/Symbols.namespace index 32c172990..48ee1b981 100644 --- a/lib/libcrypto/Symbols.namespace +++ b/lib/libcrypto/Symbols.namespace @@ -1856,10 +1856,6 @@ _libre_idea_cbc_encrypt _libre_idea_cfb64_encrypt _libre_idea_ofb64_encrypt _libre_idea_encrypt -_libre_OCSP_RESPID_new -_libre_OCSP_RESPID_free -_libre_d2i_OCSP_RESPID -_libre_i2d_OCSP_RESPID _libre_OCSP_CERTID_dup _libre_OCSP_sendreq_bio _libre_OCSP_sendreq_new @@ -3231,7 +3227,6 @@ _libre_POLICYQUALINFO_it _libre_USERNOTICE_it _libre_NOTICEREF_it _libre_CRL_DIST_POINTS_it -_libre_DIST_POINT_it _libre_DIST_POINT_NAME_it _libre_DIST_POINT_it _libre_ISSUING_DIST_POINT_it @@ -3294,7 +3289,6 @@ _libre_ASN1_GENERALSTRING_it _libre_ASN1_UTCTIME_it _libre_ASN1_GENERALIZEDTIME_it _libre_ASN1_TIME_it -_libre_OCSP_RESPID_it _libre_OCSP_SINGLERESP_it _libre_OCSP_CERTSTATUS_it _libre_OCSP_REVOKEDINFO_it @@ -3334,6 +3328,27 @@ _libre_RSA_OAEP_PARAMS_it _libre_DSAPublicKey_it _libre_DSAPrivateKey_it _libre_DSAparams_it +_libre_CMS_ContentInfo_it +_libre_CMS_ReceiptRequest_it +_libre_PKCS12_it +_libre_PKCS12_SAFEBAG_it +_libre_BIO_get_ex_new_index +_libre_BIO_new_bio_pair +_libre_ASN1_UTCTIME_cmp_time_t +_libre_ASN1_dup +_libre_CMS_get0_content +_libre_PKCS7_add_attribute +_libre_UI_method_get_prompt_constructor +_libre_UI_null +_libre_X509_STORE_CTX_get_check_issued +_libre_X509_STORE_get_check_issued +_libre_X509_STORE_set_check_issued +_libre_lh_error +_libre_DES_check_key +_libre_DES_rw_mode +_libre_CRYPTO_get_dynlock_create_callback +_libre_ERR_add_error_data +_libre_ERR_add_error_vdata _libre_RSAPublicKey_it _libre_RSAPrivateKey_it _libre_RSA_PSS_PARAMS_it diff --git a/lib/libcrypto/bio/bio_lib.c b/lib/libcrypto/bio/bio_lib.c index ba7153922..463d2ad23 100644 --- a/lib/libcrypto/bio/bio_lib.c +++ b/lib/libcrypto/bio/bio_lib.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bio_lib.c,v 1.53 2024/03/27 01:22:30 tb Exp $ */ +/* $OpenBSD: bio_lib.c,v 1.54 2024/07/09 06:14:59 beck Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -851,6 +851,7 @@ BIO_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_BIO, argl, argp, new_func, dup_func, free_func); } +LCRYPTO_ALIAS(BIO_get_ex_new_index); int BIO_set_ex_data(BIO *bio, int idx, void *data) diff --git a/lib/libcrypto/bio/bss_bio.c b/lib/libcrypto/bio/bss_bio.c index fa3d4c051..b66c13757 100644 --- a/lib/libcrypto/bio/bss_bio.c +++ b/lib/libcrypto/bio/bss_bio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bss_bio.c,v 1.28 2023/07/28 10:13:50 tb Exp $ */ +/* $OpenBSD: bss_bio.c,v 1.29 2024/07/09 06:14:59 beck Exp $ */ /* ==================================================================== * Copyright (c) 1998-2003 The OpenSSL Project. All rights reserved. * @@ -617,6 +617,7 @@ BIO_new_bio_pair(BIO **bio1_p, size_t writebuf1, BIO **bio2_p, size_t writebuf2) *bio2_p = bio2; return ret; } +LCRYPTO_ALIAS(BIO_new_bio_pair); size_t BIO_ctrl_get_write_guarantee(BIO *bio) diff --git a/lib/libcrypto/cms/cms_asn1.c b/lib/libcrypto/cms/cms_asn1.c index 531b8c587..8f2e12236 100644 --- a/lib/libcrypto/cms/cms_asn1.c +++ b/lib/libcrypto/cms/cms_asn1.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cms_asn1.c,v 1.23 2023/07/08 08:26:26 beck Exp $ */ +/* $OpenBSD: cms_asn1.c,v 1.24 2024/07/09 06:12:45 beck Exp $ */ /* * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL * project. @@ -1390,6 +1390,7 @@ const ASN1_ITEM CMS_ContentInfo_it = { .size = sizeof(CMS_ContentInfo), .sname = "CMS_ContentInfo", }; +LCRYPTO_ALIAS(CMS_ContentInfo_it); /* Specials for signed attributes */ @@ -1501,6 +1502,7 @@ const ASN1_ITEM CMS_ReceiptRequest_it = { .size = sizeof(CMS_ReceiptRequest), .sname = "CMS_ReceiptRequest", }; +LCRYPTO_ALIAS(CMS_ReceiptRequest_it); static const ASN1_TEMPLATE CMS_Receipt_seq_tt[] = { { diff --git a/lib/libcrypto/cryptlib.c b/lib/libcrypto/cryptlib.c index dc62d8208..b9ea39285 100644 --- a/lib/libcrypto/cryptlib.c +++ b/lib/libcrypto/cryptlib.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cryptlib.c,v 1.51 2024/04/21 13:41:14 tb Exp $ */ +/* $OpenBSD: cryptlib.c,v 1.52 2024/07/09 07:16:44 beck Exp $ */ /* ==================================================================== * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. * @@ -281,6 +281,7 @@ struct CRYPTO_dynlock_value * { return NULL; } +LCRYPTO_ALIAS(CRYPTO_get_dynlock_create_callback); void (*CRYPTO_get_dynlock_lock_callback(void))(int mode, diff --git a/lib/libcrypto/des/enc_read.c b/lib/libcrypto/des/enc_read.c index 35704315e..32f7547a3 100644 --- a/lib/libcrypto/des/enc_read.c +++ b/lib/libcrypto/des/enc_read.c @@ -1,4 +1,4 @@ -/* $OpenBSD: enc_read.c,v 1.19 2024/05/24 19:16:53 tb Exp $ */ +/* $OpenBSD: enc_read.c,v 1.20 2024/07/09 07:16:13 beck Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -67,6 +67,7 @@ */ int DES_rw_mode = DES_PCBC_MODE; +LCRYPTO_ALIAS(DES_rw_mode); int DES_enc_read(int fd, void *buf, int len, DES_key_schedule *sched, diff --git a/lib/libcrypto/des/set_key.c b/lib/libcrypto/des/set_key.c index 0e7aab688..9a9dcf7c5 100644 --- a/lib/libcrypto/des/set_key.c +++ b/lib/libcrypto/des/set_key.c @@ -1,4 +1,4 @@ -/* $OpenBSD: set_key.c,v 1.27 2024/03/29 01:47:29 joshua Exp $ */ +/* $OpenBSD: set_key.c,v 1.28 2024/07/09 07:16:13 beck Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -63,6 +63,7 @@ #include "des_local.h" int DES_check_key = 0; /* defaults to false */ +LCRYPTO_ALIAS(DES_check_key); static const unsigned char odd_parity[256] = { 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14, diff --git a/lib/libcrypto/err/err.c b/lib/libcrypto/err/err.c index 583293e79..e40b52f5e 100644 --- a/lib/libcrypto/err/err.c +++ b/lib/libcrypto/err/err.c @@ -1,4 +1,4 @@ -/* $OpenBSD: err.c,v 1.61 2024/06/24 06:43:22 tb Exp $ */ +/* $OpenBSD: err.c,v 1.62 2024/07/09 07:17:13 beck Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -1149,6 +1149,7 @@ ERR_add_error_vdata(int num, va_list args) else ERR_set_error_data(errbuf, ERR_TXT_MALLOCED|ERR_TXT_STRING); } +LCRYPTO_ALIAS(ERR_add_error_vdata); void ERR_add_error_data(int num, ...) @@ -1158,6 +1159,7 @@ ERR_add_error_data(int num, ...) ERR_add_error_vdata(num, args); va_end(args); } +LCRYPTO_ALIAS(ERR_add_error_data); int ERR_set_mark(void) diff --git a/lib/libcrypto/err/err.h b/lib/libcrypto/err/err.h index 8beab1487..9f64dd279 100644 --- a/lib/libcrypto/err/err.h +++ b/lib/libcrypto/err/err.h @@ -1,4 +1,4 @@ -/* $OpenBSD: err.h,v 1.33 2024/03/02 10:32:26 tb Exp $ */ +/* $OpenBSD: err.h,v 1.34 2024/07/09 07:17:13 beck Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -374,10 +374,8 @@ void ERR_print_errors_fp(FILE *fp); void ERR_print_errors(BIO *bp); #endif void ERR_asprintf_error_data(char * format, ...); -#ifndef LIBRESSL_INTERNAL void ERR_add_error_data(int num, ...); void ERR_add_error_vdata(int num, va_list args); -#endif void ERR_load_strings(int lib, ERR_STRING_DATA *str); void ERR_unload_strings(int lib, ERR_STRING_DATA *str); void ERR_load_ERR_strings(void); diff --git a/lib/libcrypto/evp/evp.h b/lib/libcrypto/evp/evp.h index 5059c0aff..2db8acfa0 100644 --- a/lib/libcrypto/evp/evp.h +++ b/lib/libcrypto/evp/evp.h @@ -1,4 +1,4 @@ -/* $OpenBSD: evp.h,v 1.134 2024/04/14 14:14:14 tb Exp $ */ +/* $OpenBSD: evp.h,v 1.135 2024/07/09 16:15:37 tb Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -113,6 +113,7 @@ #define EVP_PKEY_HMAC NID_hmac #define EVP_PKEY_CMAC NID_cmac #define EVP_PKEY_HKDF NID_hkdf +#define EVP_PKEY_TLS1_PRF NID_tls1_prf #define EVP_PKEY_GOSTR12_256 NID_id_tc26_gost3410_2012_256 #define EVP_PKEY_GOSTR12_512 NID_id_tc26_gost3410_2012_512 #define EVP_PKEY_ED25519 NID_ED25519 diff --git a/lib/libcrypto/evp/pmeth_lib.c b/lib/libcrypto/evp/pmeth_lib.c index a0a193da7..1aa2fda28 100644 --- a/lib/libcrypto/evp/pmeth_lib.c +++ b/lib/libcrypto/evp/pmeth_lib.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pmeth_lib.c,v 1.40 2024/04/09 13:52:41 beck Exp $ */ +/* $OpenBSD: pmeth_lib.c,v 1.41 2024/07/09 17:02:29 tb Exp $ */ /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL * project 2006. */ @@ -80,6 +80,7 @@ extern const EVP_PKEY_METHOD hkdf_pkey_meth; extern const EVP_PKEY_METHOD hmac_pkey_meth; extern const EVP_PKEY_METHOD rsa_pkey_meth; extern const EVP_PKEY_METHOD rsa_pss_pkey_meth; +extern const EVP_PKEY_METHOD tls1_prf_pkey_meth; extern const EVP_PKEY_METHOD x25519_pkey_meth; static const EVP_PKEY_METHOD *pkey_methods[] = { @@ -92,6 +93,7 @@ static const EVP_PKEY_METHOD *pkey_methods[] = { &hmac_pkey_meth, &rsa_pkey_meth, &rsa_pss_pkey_meth, + &tls1_prf_pkey_meth, &x25519_pkey_meth, }; diff --git a/lib/libcrypto/hidden/openssl/bio.h b/lib/libcrypto/hidden/openssl/bio.h index 425d1e294..03da75a79 100644 --- a/lib/libcrypto/hidden/openssl/bio.h +++ b/lib/libcrypto/hidden/openssl/bio.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bio.h,v 1.7 2024/03/02 09:22:41 tb Exp $ */ +/* $OpenBSD: bio.h,v 1.8 2024/07/09 06:14:59 beck Exp $ */ /* * Copyright (c) 2023 Bob Beck * @@ -136,5 +136,7 @@ LCRYPTO_USED(BIO_new_accept); LCRYPTO_USED(BIO_copy_next_retry); LCRYPTO_USED(BIO_printf); LCRYPTO_USED(ERR_load_BIO_strings); +LCRYPTO_USED(BIO_get_ex_new_index); +LCRYPTO_USED(BIO_new_bio_pair); #endif /* _LIBCRYPTO_BIO_H */ diff --git a/lib/libcrypto/hidden/openssl/cms.h b/lib/libcrypto/hidden/openssl/cms.h index 430b2c535..a99c97775 100644 --- a/lib/libcrypto/hidden/openssl/cms.h +++ b/lib/libcrypto/hidden/openssl/cms.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cms.h,v 1.3 2024/03/30 01:53:05 joshua Exp $ */ +/* $OpenBSD: cms.h,v 1.4 2024/07/09 06:12:45 beck Exp $ */ /* * Copyright (c) 2023 Bob Beck * @@ -153,5 +153,9 @@ LCRYPTO_USED(CMS_RecipientInfo_kari_get0_ctx); LCRYPTO_USED(CMS_RecipientInfo_kari_decrypt); LCRYPTO_USED(CMS_SharedInfo_encode); LCRYPTO_USED(ERR_load_CMS_strings); +#if defined(LIBRESSL_NAMESPACE) +extern LCRYPTO_USED(CMS_ContentInfo_it); +extern LCRYPTO_USED(CMS_ReceiptRequest_it); +#endif #endif /* _LIBCRYPTO_CMS_H */ diff --git a/lib/libcrypto/hidden/openssl/crypto.h b/lib/libcrypto/hidden/openssl/crypto.h index fb1b215b9..1b2d8cbbe 100644 --- a/lib/libcrypto/hidden/openssl/crypto.h +++ b/lib/libcrypto/hidden/openssl/crypto.h @@ -1,4 +1,4 @@ -/* $OpenBSD: crypto.h,v 1.7 2024/04/10 14:51:02 beck Exp $ */ +/* $OpenBSD: crypto.h,v 1.8 2024/07/09 07:16:44 beck Exp $ */ /* * Copyright (c) 2023 Bob Beck * @@ -69,6 +69,7 @@ LCRYPTO_UNUSED(CRYPTO_set_dynlock_lock_callback); LCRYPTO_UNUSED(CRYPTO_set_dynlock_destroy_callback); LCRYPTO_UNUSED(CRYPTO_get_dynlock_lock_callback); LCRYPTO_UNUSED(CRYPTO_get_dynlock_destroy_callback); +LCRYPTO_UNUSED(CRYPTO_get_dynlock_create_callback); LCRYPTO_UNUSED(CRYPTO_malloc); LCRYPTO_UNUSED(CRYPTO_strdup); LCRYPTO_UNUSED(CRYPTO_free); diff --git a/lib/libcrypto/hidden/openssl/des.h b/lib/libcrypto/hidden/openssl/des.h index 9f6ea9c10..e632de4b1 100644 --- a/lib/libcrypto/hidden/openssl/des.h +++ b/lib/libcrypto/hidden/openssl/des.h @@ -1,4 +1,4 @@ -/* $OpenBSD: des.h,v 1.1 2024/03/29 01:47:29 joshua Exp $ */ +/* $OpenBSD: des.h,v 1.2 2024/07/09 07:16:13 beck Exp $ */ /* * Copyright (c) 2024 Joshua Sing * @@ -60,5 +60,9 @@ LCRYPTO_USED(DES_string_to_key); LCRYPTO_USED(DES_string_to_2keys); LCRYPTO_USED(DES_cfb64_encrypt); LCRYPTO_USED(DES_ofb64_encrypt); +#if defined(LIBRESSL_NAMESPACE) +extern LCRYPTO_USED(DES_check_key); +extern LCRYPTO_USED(DES_rw_mode); +#endif #endif /* _LIBCRYPTO_DES_H */ diff --git a/lib/libcrypto/hidden/openssl/err.h b/lib/libcrypto/hidden/openssl/err.h index 08f97e1c5..5a5893f81 100644 --- a/lib/libcrypto/hidden/openssl/err.h +++ b/lib/libcrypto/hidden/openssl/err.h @@ -1,4 +1,4 @@ -/* $OpenBSD: err.h,v 1.5 2024/03/02 10:30:48 tb Exp $ */ +/* $OpenBSD: err.h,v 1.6 2024/07/09 07:17:13 beck Exp $ */ /* * Copyright (c) 2023 Bob Beck * @@ -56,5 +56,7 @@ LCRYPTO_USED(ERR_remove_state); LCRYPTO_USED(ERR_get_next_error_library); LCRYPTO_USED(ERR_set_mark); LCRYPTO_USED(ERR_pop_to_mark); +LCRYPTO_UNUSED(ERR_add_error_data); +LCRYPTO_UNUSED(ERR_add_error_vdata); #endif /* _LIBCRYPTO_ERR_H */ diff --git a/lib/libcrypto/hidden/openssl/pkcs12.h b/lib/libcrypto/hidden/openssl/pkcs12.h index 4c37e73cc..0144ba4e3 100644 --- a/lib/libcrypto/hidden/openssl/pkcs12.h +++ b/lib/libcrypto/hidden/openssl/pkcs12.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pkcs12.h,v 1.3 2024/03/02 10:15:16 tb Exp $ */ +/* $OpenBSD: pkcs12.h,v 1.4 2024/07/09 06:13:22 beck Exp $ */ /* * Copyright (c) 2022 Bob Beck * @@ -67,5 +67,9 @@ LCRYPTO_USED(d2i_PKCS12_bio); LCRYPTO_USED(d2i_PKCS12_fp); LCRYPTO_USED(PKCS12_newpass); LCRYPTO_USED(ERR_load_PKCS12_strings); +#if defined(LIBRESSL_NAMESPACE) +extern LCRYPTO_USED(PKCS12_it); +extern LCRYPTO_USED(PKCS12_SAFEBAG_it); +#endif #endif /* _LIBCRYPTO_PKCS12_H */ diff --git a/lib/libcrypto/hmac/hmac.h b/lib/libcrypto/hmac/hmac.h index abdd19450..0f39009c9 100644 --- a/lib/libcrypto/hmac/hmac.h +++ b/lib/libcrypto/hmac/hmac.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hmac.h,v 1.18 2024/06/01 07:36:16 tb Exp $ */ +/* $OpenBSD: hmac.h,v 1.19 2024/07/09 07:57:57 tb Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -60,6 +60,10 @@ #include +#if !defined(HAVE_ATTRIBUTE__BOUNDED__) && !defined(__OpenBSD__) +#define __bounded__(x, y, z) +#endif + #ifdef OPENSSL_NO_HMAC #error HMAC is disabled. #endif @@ -78,14 +82,18 @@ HMAC_CTX *HMAC_CTX_new(void); void HMAC_CTX_free(HMAC_CTX *ctx); int HMAC_CTX_reset(HMAC_CTX *ctx); -int HMAC_Init(HMAC_CTX *ctx, const void *key, int len, - const EVP_MD *md); /* deprecated */ +int HMAC_Init(HMAC_CTX *ctx, const void *key, int len, const EVP_MD *md) + __attribute__ ((__bounded__(__buffer__, 2, 3))); int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len, const EVP_MD *md, - ENGINE *impl); -int HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, size_t len); + ENGINE *impl) + __attribute__ ((__bounded__(__buffer__, 2, 3))); +int HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, size_t len) + __attribute__ ((__bounded__(__buffer__, 2, 3))); int HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len); unsigned char *HMAC(const EVP_MD *evp_md, const void *key, int key_len, const unsigned char *d, size_t n, unsigned char *md, unsigned int *md_len) + __attribute__ ((__bounded__(__buffer__, 2, 3))) + __attribute__ ((__bounded__(__buffer__, 4, 5))) __attribute__((__nonnull__ (6))); int HMAC_CTX_copy(HMAC_CTX *dctx, HMAC_CTX *sctx); diff --git a/lib/libcrypto/kdf/kdf.h b/lib/libcrypto/kdf/kdf.h index f823bf99e..578949cb5 100644 --- a/lib/libcrypto/kdf/kdf.h +++ b/lib/libcrypto/kdf/kdf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: kdf.h,v 1.8 2022/07/12 14:42:49 kn Exp $ */ +/* $OpenBSD: kdf.h,v 1.9 2024/07/09 16:20:17 tb Exp $ */ /* * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL * project. @@ -59,6 +59,10 @@ extern "C" { #endif +# define EVP_PKEY_CTRL_TLS_MD (EVP_PKEY_ALG_CTRL + 0) +# define EVP_PKEY_CTRL_TLS_SECRET (EVP_PKEY_ALG_CTRL + 1) +# define EVP_PKEY_CTRL_TLS_SEED (EVP_PKEY_ALG_CTRL + 2) + # define EVP_PKEY_CTRL_HKDF_MD (EVP_PKEY_ALG_CTRL + 3) # define EVP_PKEY_CTRL_HKDF_SALT (EVP_PKEY_ALG_CTRL + 4) # define EVP_PKEY_CTRL_HKDF_KEY (EVP_PKEY_ALG_CTRL + 5) @@ -69,6 +73,20 @@ extern "C" { # define EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY 1 # define EVP_PKEY_HKDEF_MODE_EXPAND_ONLY 2 + +# define EVP_PKEY_CTX_set_tls1_prf_md(pctx, md) \ + EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_TLS_MD, 0, (void *)(md)) + +# define EVP_PKEY_CTX_set1_tls1_prf_secret(pctx, sec, seclen) \ + EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_TLS_SECRET, seclen, (void *)(sec)) + +# define EVP_PKEY_CTX_add1_tls1_prf_seed(pctx, seed, seedlen) \ + EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE, \ + EVP_PKEY_CTRL_TLS_SEED, seedlen, (void *)(seed)) + + # define EVP_PKEY_CTX_set_hkdf_md(pctx, md) \ EVP_PKEY_CTX_ctrl(pctx, -1, EVP_PKEY_OP_DERIVE, \ EVP_PKEY_CTRL_HKDF_MD, 0, (void *)(md)) @@ -97,13 +115,21 @@ int ERR_load_KDF_strings(void); # define KDF_F_PKEY_HKDF_CTRL_STR 103 # define KDF_F_PKEY_HKDF_DERIVE 102 # define KDF_F_PKEY_HKDF_INIT 108 +# define KDF_F_PKEY_TLS1_PRF_CTRL_STR 100 +# define KDF_F_PKEY_TLS1_PRF_DERIVE 101 +# define KDF_F_PKEY_TLS1_PRF_INIT 110 +# define KDF_F_TLS1_PRF_ALG 111 /* * KDF reason codes. */ +# define KDF_R_INVALID_DIGEST 100 # define KDF_R_MISSING_KEY 104 # define KDF_R_MISSING_MESSAGE_DIGEST 105 +# define KDF_R_MISSING_SECRET 107 +# define KDF_R_MISSING_SEED 106 # define KDF_R_UNKNOWN_PARAMETER_TYPE 103 +# define KDF_R_VALUE_MISSING 102 # ifdef __cplusplus } diff --git a/lib/libcrypto/kdf/kdf_err.c b/lib/libcrypto/kdf/kdf_err.c index fc38e0813..f0dfd2127 100644 --- a/lib/libcrypto/kdf/kdf_err.c +++ b/lib/libcrypto/kdf/kdf_err.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kdf_err.c,v 1.10 2024/06/24 06:43:22 tb Exp $ */ +/* $OpenBSD: kdf_err.c,v 1.11 2024/07/09 16:20:17 tb Exp $ */ /* ==================================================================== * Copyright (c) 1999-2018 The OpenSSL Project. All rights reserved. * @@ -64,15 +64,23 @@ static const ERR_STRING_DATA KDF_str_functs[] = { {ERR_PACK(ERR_LIB_KDF, KDF_F_PKEY_HKDF_CTRL_STR, 0), "pkey_hkdf_ctrl_str"}, {ERR_PACK(ERR_LIB_KDF, KDF_F_PKEY_HKDF_DERIVE, 0), "pkey_hkdf_derive"}, {ERR_PACK(ERR_LIB_KDF, KDF_F_PKEY_HKDF_INIT, 0), "pkey_hkdf_init"}, + {ERR_PACK(ERR_LIB_KDF, KDF_F_PKEY_TLS1_PRF_CTRL_STR, 0), "pkey_tls1_prf_ctrl_str"}, + {ERR_PACK(ERR_LIB_KDF, KDF_F_PKEY_TLS1_PRF_DERIVE, 0), "pkey_tls1_prf_derive"}, + {ERR_PACK(ERR_LIB_KDF, KDF_F_PKEY_TLS1_PRF_INIT, 0), "pkey_tls1_prf_init"}, + {ERR_PACK(ERR_LIB_KDF, KDF_F_TLS1_PRF_ALG, 0), "pkey_tls1_prf_alg"}, {0, NULL}, }; static const ERR_STRING_DATA KDF_str_reasons[] = { + {ERR_PACK(ERR_LIB_KDF, 0, KDF_R_INVALID_DIGEST), "invalid digest"}, {ERR_PACK(ERR_LIB_KDF, 0, KDF_R_MISSING_KEY), "missing key"}, {ERR_PACK(ERR_LIB_KDF, 0, KDF_R_MISSING_MESSAGE_DIGEST), "missing message digest"}, + {ERR_PACK(ERR_LIB_KDF, 0, KDF_R_MISSING_SECRET), "missing secret"}, + {ERR_PACK(ERR_LIB_KDF, 0, KDF_R_MISSING_SEED), "missing seed"}, {ERR_PACK(ERR_LIB_KDF, 0, KDF_R_UNKNOWN_PARAMETER_TYPE), "unknown parameter type"}, + {ERR_PACK(ERR_LIB_KDF, 0, KDF_R_VALUE_MISSING), "value missing"}, {0, NULL}, }; diff --git a/lib/libcrypto/kdf/tls1_prf.c b/lib/libcrypto/kdf/tls1_prf.c new file mode 100644 index 000000000..9d2f77719 --- /dev/null +++ b/lib/libcrypto/kdf/tls1_prf.c @@ -0,0 +1,348 @@ +/* $OpenBSD: tls1_prf.c,v 1.39 2024/07/09 17:58:36 tb Exp $ */ +/* + * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project + * 2016. + */ +/* ==================================================================== + * Copyright (c) 2015 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include +#include + +#include +#include +#include + +#include "evp_local.h" + +#define TLS1_PRF_MAXBUF 1024 + +struct tls1_prf_ctx { + const EVP_MD *md; + unsigned char *secret; + size_t secret_len; + unsigned char seed[TLS1_PRF_MAXBUF]; + size_t seed_len; +}; + +static int +pkey_tls1_prf_init(EVP_PKEY_CTX *ctx) +{ + struct tls1_prf_ctx *kctx; + + if ((kctx = calloc(1, sizeof(*kctx))) == NULL) { + KDFerror(ERR_R_MALLOC_FAILURE); + return 0; + } + ctx->data = kctx; + + return 1; +} + +static void +pkey_tls1_prf_cleanup(EVP_PKEY_CTX *ctx) +{ + struct tls1_prf_ctx *kctx = ctx->data; + + freezero(kctx->secret, kctx->secret_len); + freezero(kctx, sizeof(*kctx)); +} + +static int +pkey_tls1_prf_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) +{ + struct tls1_prf_ctx *kctx = ctx->data; + + switch (type) { + case EVP_PKEY_CTRL_TLS_MD: + kctx->md = p2; + return 1; + + case EVP_PKEY_CTRL_TLS_SECRET: + if (p1 < 0) + return 0; + + freezero(kctx->secret, kctx->secret_len); + kctx->secret = NULL; + kctx->secret_len = 0; + + explicit_bzero(kctx->seed, kctx->seed_len); + kctx->seed_len = 0; + + if (p1 == 0 || p2 == NULL) + return 0; + + if ((kctx->secret = calloc(1, p1)) == NULL) + return 0; + memcpy(kctx->secret, p2, p1); + kctx->secret_len = p1; + + return 1; + + case EVP_PKEY_CTRL_TLS_SEED: + if (p1 == 0 || p2 == NULL) + return 1; + if (p1 < 0 || p1 > (int)(TLS1_PRF_MAXBUF - kctx->seed_len)) + return 0; + memcpy(kctx->seed + kctx->seed_len, p2, p1); + kctx->seed_len += p1; + return 1; + + default: + return -2; + } +} + +static int +pkey_tls1_prf_ctrl_str(EVP_PKEY_CTX *ctx, + const char *type, const char *value) +{ + if (value == NULL) { + KDFerror(KDF_R_VALUE_MISSING); + return 0; + } + if (strcmp(type, "md") == 0) { + struct tls1_prf_ctx *kctx = ctx->data; + + const EVP_MD *md = EVP_get_digestbyname(value); + if (md == NULL) { + KDFerror(KDF_R_INVALID_DIGEST); + return 0; + } + kctx->md = md; + return 1; + } + if (strcmp(type, "secret") == 0) + return EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_TLS_SECRET, value); + if (strcmp(type, "hexsecret") == 0) + return EVP_PKEY_CTX_hex2ctrl(ctx, EVP_PKEY_CTRL_TLS_SECRET, value); + if (strcmp(type, "seed") == 0) + return EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_TLS_SEED, value); + if (strcmp(type, "hexseed") == 0) + return EVP_PKEY_CTX_hex2ctrl(ctx, EVP_PKEY_CTRL_TLS_SEED, value); + + KDFerror(KDF_R_UNKNOWN_PARAMETER_TYPE); + return -2; +} + +static int +tls1_prf_P_hash(const EVP_MD *md, + const unsigned char *secret, size_t secret_len, + const unsigned char *seed, size_t seed_len, + unsigned char *out, size_t out_len) +{ + int chunk; + EVP_MD_CTX *ctx = NULL, *ctx_tmp = NULL, *ctx_init = NULL; + EVP_PKEY *mac_key = NULL; + unsigned char A1[EVP_MAX_MD_SIZE]; + size_t A1_len; + int ret = 0; + + if ((chunk = EVP_MD_size(md)) < 0) + goto err; + + if ((ctx = EVP_MD_CTX_new()) == NULL) + goto err; + if ((ctx_tmp = EVP_MD_CTX_new()) == NULL) + goto err; + if ((ctx_init = EVP_MD_CTX_new()) == NULL) + goto err; + + EVP_MD_CTX_set_flags(ctx_init, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); + + if ((mac_key = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL, + secret, secret_len)) == NULL) + goto err; + + if (!EVP_DigestSignInit(ctx_init, NULL, md, NULL, mac_key)) + goto err; + if (!EVP_MD_CTX_copy_ex(ctx, ctx_init)) + goto err; + if (seed != NULL && !EVP_DigestSignUpdate(ctx, seed, seed_len)) + goto err; + if (!EVP_DigestSignFinal(ctx, A1, &A1_len)) + goto err; + + for (;;) { + /* Reinit mac contexts */ + if (!EVP_MD_CTX_copy_ex(ctx, ctx_init)) + goto err; + if (!EVP_DigestSignUpdate(ctx, A1, A1_len)) + goto err; + if (out_len > (size_t)chunk && !EVP_MD_CTX_copy_ex(ctx_tmp, ctx)) + goto err; + if (seed != NULL && !EVP_DigestSignUpdate(ctx, seed, seed_len)) + goto err; + + if (out_len > (size_t)chunk) { + size_t mac_len; + if (!EVP_DigestSignFinal(ctx, out, &mac_len)) + goto err; + out += mac_len; + out_len -= mac_len; + if (!EVP_DigestSignFinal(ctx_tmp, A1, &A1_len)) + goto err; + } else { + if (!EVP_DigestSignFinal(ctx, A1, &A1_len)) + goto err; + memcpy(out, A1, out_len); + break; + } + } + + ret = 1; + + err: + EVP_PKEY_free(mac_key); + EVP_MD_CTX_free(ctx); + EVP_MD_CTX_free(ctx_tmp); + EVP_MD_CTX_free(ctx_init); + explicit_bzero(A1, sizeof(A1)); + + return ret; +} + +static int +tls1_prf_alg(const EVP_MD *md, const unsigned char *secret, size_t secret_len, + const unsigned char *seed, size_t seed_len, unsigned char *out, size_t out_len) +{ + unsigned char *tmp = NULL; + size_t half_len; + size_t i; + int ret = 0; + + if (EVP_MD_type(md) != NID_md5_sha1) + return tls1_prf_P_hash(md, secret, secret_len, seed, seed_len, + out, out_len); + + half_len = secret_len - secret_len / 2; + if (!tls1_prf_P_hash(EVP_md5(), secret, half_len, seed, seed_len, + out, out_len)) + goto err; + + if ((tmp = calloc(1, out_len)) == NULL) { + KDFerror(ERR_R_MALLOC_FAILURE); + goto err; + } + secret += secret_len - half_len; + if (!tls1_prf_P_hash(EVP_sha1(), secret, half_len, seed, seed_len, + tmp, out_len)) + goto err; + for (i = 0; i < out_len; i++) + out[i] ^= tmp[i]; + + ret = 1; + + err: + freezero(tmp, out_len); + + return ret; +} + +static int +pkey_tls1_prf_derive(EVP_PKEY_CTX *ctx, unsigned char *key, size_t *key_len) +{ + struct tls1_prf_ctx *kctx = ctx->data; + + if (kctx->md == NULL) { + KDFerror(KDF_R_MISSING_MESSAGE_DIGEST); + return 0; + } + if (kctx->secret == NULL) { + KDFerror(KDF_R_MISSING_SECRET); + return 0; + } + if (kctx->seed_len == 0) { + KDFerror(KDF_R_MISSING_SEED); + return 0; + } + + return tls1_prf_alg(kctx->md, kctx->secret, kctx->secret_len, + kctx->seed, kctx->seed_len, key, *key_len); +} + +const EVP_PKEY_METHOD tls1_prf_pkey_meth = { + .pkey_id = EVP_PKEY_TLS1_PRF, + .flags = 0, + + .init = pkey_tls1_prf_init, + .copy = NULL, + .cleanup = pkey_tls1_prf_cleanup, + + .paramgen = NULL, + + .keygen = NULL, + + .sign_init = NULL, + .sign = NULL, + + .verify_init = NULL, + .verify = NULL, + + .verify_recover = NULL, + + .signctx_init = NULL, + .signctx = NULL, + + .encrypt = NULL, + + .decrypt = NULL, + + .derive_init = NULL, + .derive = pkey_tls1_prf_derive, + + .ctrl = pkey_tls1_prf_ctrl, + .ctrl_str = pkey_tls1_prf_ctrl_str, +}; diff --git a/lib/libcrypto/objects/obj_mac.num b/lib/libcrypto/objects/obj_mac.num index 348f3c4a6..728bf0240 100644 --- a/lib/libcrypto/objects/obj_mac.num +++ b/lib/libcrypto/objects/obj_mac.num @@ -1052,3 +1052,4 @@ RSA_SHA3_384 1051 RSA_SHA3_512 1052 acmeIdentifier 1053 id_ct_rpkiSignedPrefixList 1054 +tls1_prf 1055 diff --git a/lib/libcrypto/objects/objects.txt b/lib/libcrypto/objects/objects.txt index 8f339d563..16e53beea 100644 --- a/lib/libcrypto/objects/objects.txt +++ b/lib/libcrypto/objects/objects.txt @@ -1404,6 +1404,8 @@ secg-scheme 14 3 : dhSinglePass-cofactorDH-sha512kdf-scheme 1 3 6 1 4 1 11129 2 4 4 : ct_precert_signer : CT Precertificate Signer 1 3 6 1 4 1 11129 2 4 5 : ct_cert_scts : CT Certificate SCTs +# NID for TLS1 PRF + : TLS1-PRF : tls1-prf # NID for HKDF : HKDF : hkdf diff --git a/lib/libcrypto/pkcs12/p12_asn.c b/lib/libcrypto/pkcs12/p12_asn.c index d34947e92..6abc8f6c6 100644 --- a/lib/libcrypto/pkcs12/p12_asn.c +++ b/lib/libcrypto/pkcs12/p12_asn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: p12_asn.c,v 1.15 2024/03/02 10:15:16 tb Exp $ */ +/* $OpenBSD: p12_asn.c,v 1.16 2024/07/09 06:13:22 beck Exp $ */ /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL * project 1999. */ @@ -98,6 +98,7 @@ const ASN1_ITEM PKCS12_it = { .size = sizeof(PKCS12), .sname = "PKCS12", }; +LCRYPTO_ALIAS(PKCS12_it); PKCS12 * @@ -413,6 +414,7 @@ const ASN1_ITEM PKCS12_SAFEBAG_it = { .size = sizeof(PKCS12_SAFEBAG), .sname = "PKCS12_SAFEBAG", }; +LCRYPTO_ALIAS(PKCS12_SAFEBAG_it); PKCS12_SAFEBAG * diff --git a/lib/libssl/Makefile b/lib/libssl/Makefile index a2b710922..7d3b221db 100644 --- a/lib/libssl/Makefile +++ b/lib/libssl/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.82 2024/06/25 14:10:45 jsing Exp $ +# $OpenBSD: Makefile,v 1.83 2024/07/09 09:39:14 beck Exp $ .include .ifndef NOMAN @@ -16,9 +16,9 @@ CFLAGS+= -Wall -Wundef CFLAGS+= -Werror -Wshadow .endif CFLAGS+= -DLIBRESSL_INTERNAL -.ifdef NAMESPACE + CFLAGS+= -DLIBRESSL_NAMESPACE -.endif + .ifdef TLS1_3_DEBUG CFLAGS+= -DTLS13_DEBUG .endif diff --git a/lib/libssl/ssl_sigalgs.c b/lib/libssl/ssl_sigalgs.c index 9876e82a6..18d71f6b9 100644 --- a/lib/libssl/ssl_sigalgs.c +++ b/lib/libssl/ssl_sigalgs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_sigalgs.c,v 1.49 2024/02/03 15:58:34 beck Exp $ */ +/* $OpenBSD: ssl_sigalgs.c,v 1.50 2024/07/09 13:43:57 beck Exp $ */ /* * Copyright (c) 2018-2020 Bob Beck * Copyright (c) 2021 Joel Sing @@ -337,7 +337,6 @@ ssl_sigalg_select(SSL *s, EVP_PKEY *pkey) return sigalg; } - SSLerror(s, SSL_R_UNKNOWN_PKEY_TYPE); return NULL; } diff --git a/lib/libssl/ssl_tlsext.c b/lib/libssl/ssl_tlsext.c index d0d67598d..08bf5593e 100644 --- a/lib/libssl/ssl_tlsext.c +++ b/lib/libssl/ssl_tlsext.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_tlsext.c,v 1.153 2024/06/26 03:41:10 tb Exp $ */ +/* $OpenBSD: ssl_tlsext.c,v 1.154 2024/07/09 12:27:27 beck Exp $ */ /* * Copyright (c) 2016, 2017, 2019 Joel Sing * Copyright (c) 2017 Doug Hogan @@ -1573,6 +1573,10 @@ tlsext_keyshare_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert) if (!CBS_get_u16_length_prefixed(&client_shares, &key_exchange)) return 0; + /* Ignore this client share if we're using earlier than TLSv1.3 */ + if (s->s3->hs.our_max_tls_version < TLS1_3_VERSION) + continue; + /* * Ensure the client share group was sent in supported groups, * and was sent in the same order as supported groups. The @@ -1590,12 +1594,7 @@ tlsext_keyshare_server_process(SSL *s, uint16_t msg_type, CBS *cbs, int *alert) return 0; } - /* - * Ignore this client share if we're using earlier than TLSv1.3 - * or we've already selected a key share. - */ - if (s->s3->hs.our_max_tls_version < TLS1_3_VERSION) - continue; + /* Ignore this client share if we have already selected a key share */ if (s->s3->hs.key_share != NULL) continue; diff --git a/lib/libz/zconf.h b/lib/libz/zconf.h index 7c289a500..99066348c 100644 --- a/lib/libz/zconf.h +++ b/lib/libz/zconf.h @@ -504,7 +504,7 @@ typedef uLong FAR uLongf; #endif #ifndef z_off_t -# define z_off_t long +# define z_off_t long long #endif #if !defined(_WIN32) && defined(Z_LARGE64) diff --git a/regress/lib/libcrypto/evp/evp_test.c b/regress/lib/libcrypto/evp/evp_test.c index eebbd50b0..a699832c4 100644 --- a/regress/lib/libcrypto/evp/evp_test.c +++ b/regress/lib/libcrypto/evp/evp_test.c @@ -1,7 +1,7 @@ -/* $OpenBSD: evp_test.c,v 1.18 2024/03/24 14:00:11 jca Exp $ */ +/* $OpenBSD: evp_test.c,v 1.20 2024/07/09 17:24:12 tb Exp $ */ /* - * Copyright (c) 2022 Joel Sing - * Copyright (c) 2023 Theo Buehler + * Copyright (c) 2017, 2022 Joel Sing + * Copyright (c) 2023, 2024 Theo Buehler * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,11 +17,13 @@ */ #include +#include #include #include #include #include +#include #include #include @@ -759,6 +761,270 @@ evp_get_digestbyname_test(void) return failure; } +static void +hexdump(const unsigned char *buf, int len) +{ + int i; + + if (len <= 0) { + fprintf(stderr, "\n", len); + return; + } + + for (i = 1; i <= len; i++) + fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n"); + + fprintf(stderr, "\n"); +} + +static int +kdf_compare_bytes(const char *label, const unsigned char *d1, int len1, + const unsigned char *d2, int len2) +{ + if (len1 != len2) { + fprintf(stderr, "FAIL: %s - byte lengths differ " + "(%d != %d)\n", label, len1, len2); + fprintf(stderr, "Got:\n"); + hexdump(d1, len1); + fprintf(stderr, "Want:\n"); + hexdump(d2, len2); + return 0; + } + if (memcmp(d1, d2, len1) != 0) { + fprintf(stderr, "FAIL: %s - bytes differ\n", label); + fprintf(stderr, "Got:\n"); + hexdump(d1, len1); + fprintf(stderr, "Want:\n"); + hexdump(d2, len2); + return 0; + } + return 1; +} + +static int +evp_kdf_tls1_prf_basic(void) +{ + EVP_PKEY_CTX *pctx; + unsigned char got[16]; + size_t got_len = sizeof(got); + unsigned char want[16] = { + 0x8e, 0x4d, 0x93, 0x25, 0x30, 0xd7, 0x65, 0xa0, + 0xaa, 0xe9, 0x74, 0xc3, 0x04, 0x73, 0x5e, 0xcc, + }; + int failed = 1; + + if ((pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_TLS1_PRF, NULL)) == NULL) { + fprintf(stderr, "FAIL: EVP_PKEY_CTX_new_id\n"); + goto err; + } + + if (EVP_PKEY_derive_init(pctx) <= 0) { + fprintf(stderr, "FAIL: EVP_PKEY_derive_init\n"); + goto err; + } + + if (EVP_PKEY_CTX_set_tls1_prf_md(pctx, EVP_sha256()) <= 0) { + fprintf(stderr, "FAIL: EVP_PKEY_CTX_set1_tls1_prf_md\n"); + goto err; + } + + if (EVP_PKEY_CTX_set1_tls1_prf_secret(pctx, "secret", 6) <= 0) { + fprintf(stderr, "FAIL: EVP_PKEY_CTX_set1_tls1_prf_secret\n"); + goto err; + } + + if (EVP_PKEY_CTX_add1_tls1_prf_seed(pctx, "seed", 4) <= 0) { + fprintf(stderr, "FAIL: EVP_PKEY_CTX_set1_tls1_prf_seed\n"); + goto err; + } + + if (EVP_PKEY_derive(pctx, got, &got_len) <= 0) { + fprintf(stderr, "FAIL: EVP_PKEY_derive\n"); + goto err; + } + + if (!kdf_compare_bytes("kdf test", got, got_len, want, sizeof(want))) + goto err; + + failed = 0; + + err: + EVP_PKEY_CTX_free(pctx); + + return failed; +} + +#define TLS_PRF_OUT_LEN 128 + +static const struct tls_prf_test { + const unsigned char *desc; + const EVP_MD *(*md)(void); + const uint16_t cipher_value; + const unsigned char out[TLS_PRF_OUT_LEN]; +} tls_prf_tests[] = { + { + .desc = "MD5+SHA1", + .md = EVP_md5_sha1, + .cipher_value = 0x0033, + .out = { + 0x03, 0xa1, 0xc1, 0x7d, 0x2c, 0xa5, 0x3d, 0xe8, + 0x9d, 0x59, 0x5e, 0x30, 0xf5, 0x71, 0xbb, 0x96, + 0xde, 0x5c, 0x8e, 0xdc, 0x25, 0x8a, 0x7c, 0x05, + 0x9f, 0x7d, 0x35, 0x29, 0x45, 0xae, 0x56, 0xad, + 0x9f, 0x57, 0x15, 0x5c, 0xdb, 0x83, 0x3a, 0xac, + 0x19, 0xa8, 0x2b, 0x40, 0x72, 0x38, 0x1e, 0xed, + 0xf3, 0x25, 0xde, 0x84, 0x84, 0xd8, 0xd1, 0xfc, + 0x31, 0x85, 0x81, 0x12, 0x55, 0x4d, 0x12, 0xb5, + 0xed, 0x78, 0x5e, 0xba, 0xc8, 0xec, 0x8d, 0x28, + 0xa1, 0x21, 0x1e, 0x6e, 0x07, 0xf1, 0xfc, 0xf5, + 0xbf, 0xe4, 0x8e, 0x8e, 0x97, 0x15, 0x93, 0x85, + 0x75, 0xdd, 0x87, 0x09, 0xd0, 0x4e, 0xe5, 0xd5, + 0x9e, 0x1f, 0xd6, 0x1c, 0x3b, 0xe9, 0xad, 0xba, + 0xe0, 0x16, 0x56, 0x62, 0x90, 0xd6, 0x82, 0x84, + 0xec, 0x8a, 0x22, 0xbe, 0xdc, 0x6a, 0x5e, 0x05, + 0x12, 0x44, 0xec, 0x60, 0x61, 0xd1, 0x8a, 0x66, + }, + }, + { + .desc = "SHA256 (via TLSv1.2)", + .md = EVP_sha256, + .cipher_value = 0x0033, + .out = { + 0x37, 0xa7, 0x06, 0x71, 0x6e, 0x19, 0x19, 0xda, + 0x23, 0x8c, 0xcc, 0xb4, 0x2f, 0x31, 0x64, 0x9d, + 0x05, 0x29, 0x1c, 0x33, 0x7e, 0x09, 0x1b, 0x0c, + 0x0e, 0x23, 0xc1, 0xb0, 0x40, 0xcc, 0x31, 0xf7, + 0x55, 0x66, 0x68, 0xd9, 0xa8, 0xae, 0x74, 0x75, + 0xf3, 0x46, 0xe9, 0x3a, 0x54, 0x9d, 0xe0, 0x8b, + 0x7e, 0x6c, 0x63, 0x1c, 0xfa, 0x2f, 0xfd, 0xc9, + 0xd3, 0xf1, 0xd3, 0xfe, 0x7b, 0x9e, 0x14, 0x95, + 0xb5, 0xd0, 0xad, 0x9b, 0xee, 0x78, 0x8c, 0x83, + 0x18, 0x58, 0x7e, 0xa2, 0x23, 0xc1, 0x8b, 0x62, + 0x94, 0x12, 0xcb, 0xb6, 0x60, 0x69, 0x32, 0xfe, + 0x98, 0x0e, 0x93, 0xb0, 0x8e, 0x5c, 0xfb, 0x6e, + 0xdb, 0x9a, 0xc2, 0x9f, 0x8c, 0x5c, 0x43, 0x19, + 0xeb, 0x4a, 0x52, 0xad, 0x62, 0x2b, 0xdd, 0x9f, + 0xa3, 0x74, 0xa6, 0x96, 0x61, 0x4d, 0x98, 0x40, + 0x63, 0xa6, 0xd4, 0xbb, 0x17, 0x11, 0x75, 0xed, + }, + }, + { + .desc = "SHA384", + .md = EVP_sha384, + .cipher_value = 0x009d, + .out = { + 0x00, 0x93, 0xc3, 0xfd, 0xa7, 0xbb, 0xdc, 0x5b, + 0x13, 0x3a, 0xe6, 0x8b, 0x1b, 0xac, 0xf3, 0xfb, + 0x3c, 0x9a, 0x78, 0xf6, 0x19, 0xf0, 0x13, 0x0f, + 0x0d, 0x01, 0x9d, 0xdf, 0x0a, 0x28, 0x38, 0xce, + 0x1a, 0x9b, 0x43, 0xbe, 0x56, 0x12, 0xa7, 0x16, + 0x58, 0xe1, 0x8a, 0xe4, 0xc5, 0xbb, 0x10, 0x4c, + 0x3a, 0xf3, 0x7f, 0xd3, 0xdb, 0xe4, 0xe0, 0x3d, + 0xcc, 0x83, 0xca, 0xf0, 0xf9, 0x69, 0xcc, 0x70, + 0x83, 0x32, 0xf6, 0xfc, 0x81, 0x80, 0x02, 0xe8, + 0x31, 0x1e, 0x7c, 0x3b, 0x34, 0xf7, 0x34, 0xd1, + 0xcf, 0x2a, 0xc4, 0x36, 0x2f, 0xe9, 0xaa, 0x7f, + 0x6d, 0x1f, 0x5e, 0x0e, 0x39, 0x05, 0x15, 0xe1, + 0xa2, 0x9a, 0x4d, 0x97, 0x8c, 0x62, 0x46, 0xf1, + 0x87, 0x65, 0xd8, 0xe9, 0x14, 0x11, 0xa6, 0x48, + 0xd7, 0x0e, 0x6e, 0x70, 0xad, 0xfb, 0x3f, 0x36, + 0x05, 0x76, 0x4b, 0xe4, 0x28, 0x50, 0x4a, 0xf2, + }, + }, +}; + +#define N_TLS_PRF_TESTS \ + (sizeof(tls_prf_tests) / sizeof(*tls_prf_tests)) + +#define TLS_PRF_SEED1 "tls prf seed 1" +#define TLS_PRF_SEED2 "tls prf seed 2" +#define TLS_PRF_SEED3 "tls prf seed 3" +#define TLS_PRF_SEED4 "tls prf seed 4" +#define TLS_PRF_SEED5 "tls prf seed 5" +#define TLS_PRF_SECRET "tls prf secretz" + +static int +do_tls_prf_evp_test(int test_no, const struct tls_prf_test *test) +{ + EVP_PKEY_CTX *pkey_ctx = NULL; + unsigned char *out; + size_t len, out_len; + int failed = 1; + + if ((pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_TLS1_PRF, NULL)) == NULL) + errx(1, "EVP_PKEY_CTX_new_id"); + + if ((out = malloc(TLS_PRF_OUT_LEN)) == NULL) + errx(1, "malloc"); + + for (len = 1; len <= TLS_PRF_OUT_LEN; len++) { + if (EVP_PKEY_derive_init(pkey_ctx) <= 0) + errx(1, "EVP_PKEY_derive_init"); + + if (EVP_PKEY_CTX_set_tls1_prf_md(pkey_ctx, test->md()) <= 0) + errx(1, "EVP_PKEY_CTX_set_tls1_prf_md"); + + if (EVP_PKEY_CTX_set1_tls1_prf_secret(pkey_ctx, TLS_PRF_SECRET, + sizeof(TLS_PRF_SECRET)) <= 0) + errx(1, "EVP_PKEY_CTX_set1_tls1_prf_secret"); + if (EVP_PKEY_CTX_add1_tls1_prf_seed(pkey_ctx, TLS_PRF_SEED1, + sizeof(TLS_PRF_SEED1)) <= 0) + errx(1, "EVP_PKEY_CTX_add1_tls1_prf_seed 1"); + if (EVP_PKEY_CTX_add1_tls1_prf_seed(pkey_ctx, TLS_PRF_SEED2, + sizeof(TLS_PRF_SEED2)) <= 0) + errx(1, "EVP_PKEY_CTX_add1_tls1_prf_seed 2"); + if (EVP_PKEY_CTX_add1_tls1_prf_seed(pkey_ctx, TLS_PRF_SEED3, + sizeof(TLS_PRF_SEED3)) <= 0) + errx(1, "EVP_PKEY_CTX_add1_tls1_prf_seed 3"); + if (EVP_PKEY_CTX_add1_tls1_prf_seed(pkey_ctx, TLS_PRF_SEED4, + sizeof(TLS_PRF_SEED4)) <= 0) + errx(1, "EVP_PKEY_CTX_add1_tls1_prf_seed 4"); + if (EVP_PKEY_CTX_add1_tls1_prf_seed(pkey_ctx, TLS_PRF_SEED5, + sizeof(TLS_PRF_SEED5)) <= 0) + errx(1, "EVP_PKEY_CTX_add1_tls1_prf_seed 5"); + + out_len = len; + if (EVP_PKEY_derive(pkey_ctx, out, &out_len) <= 0) + errx(1, "EVP_PKEY_derive"); + + if (out_len != len) { + fprintf(stderr, "FAIL: %s: length %zu != %zu\n", + __func__, out_len, len); + goto err; + } + + if (memcmp(test->out, out, out_len) != 0) { + fprintf(stderr, "FAIL: tls_PRF output differs for " + "len %zu\n", len); + fprintf(stderr, "output:\n"); + hexdump(out, out_len); + fprintf(stderr, "test data:\n"); + hexdump(test->out, len); + goto err; + } + } + + failed = 0; + + err: + EVP_PKEY_CTX_free(pkey_ctx); + free(out); + + return failed; +} + +static int +evp_kdf_tls1_prf(void) +{ + size_t i; + int failed = 0; + + for (i = 0; i < N_TLS_PRF_TESTS; i++) + failed |= do_tls_prf_evp_test(i, &tls_prf_tests[i]); + + return failed; +} + int main(int argc, char **argv) { @@ -772,6 +1038,8 @@ main(int argc, char **argv) failed |= obj_name_do_all_test(); failed |= evp_get_cipherbyname_test(); failed |= evp_get_digestbyname_test(); + failed |= evp_kdf_tls1_prf_basic(); + failed |= evp_kdf_tls1_prf(); OPENSSL_cleanup(); diff --git a/sbin/dhcp6leased/engine.c b/sbin/dhcp6leased/engine.c index 12663506c..5ab075416 100644 --- a/sbin/dhcp6leased/engine.c +++ b/sbin/dhcp6leased/engine.c @@ -1,4 +1,4 @@ -/* $OpenBSD: engine.c,v 1.14 2024/06/19 07:42:44 florian Exp $ */ +/* $OpenBSD: engine.c,v 1.17 2024/07/09 16:24:57 florian Exp $ */ /* * Copyright (c) 2017, 2021, 2024 Florian Obser @@ -106,6 +106,7 @@ struct dhcp6leased_iface { int serverid_len; uint8_t serverid[SERVERID_SIZE]; struct prefix pds[MAX_IA]; + struct prefix new_pds[MAX_IA]; struct timespec request_time; struct timespec elapsed_time_start; uint32_t lease_time; @@ -134,10 +135,9 @@ void request_dhcp_discover(struct dhcp6leased_iface *); void request_dhcp_request(struct dhcp6leased_iface *); void configure_interfaces(struct dhcp6leased_iface *); void deconfigure_interfaces(struct dhcp6leased_iface *); +int prefixcmp(struct prefix *, struct prefix *, int); void send_reconfigure_interface(struct iface_pd_conf *, struct prefix *, enum reconfigure_action); -void parse_lease_xxx(struct dhcp6leased_iface *, - struct imsg_ifinfo *); int engine_imsg_compose_main(int, pid_t, void *, uint16_t); const char *dhcp_message_type2str(uint8_t); const char *dhcp_option_type2str(uint16_t); @@ -709,7 +709,6 @@ parse_dhcp(struct dhcp6leased_iface *iface, struct imsg_dhcp *dhcp) struct dhcp_hdr hdr; struct dhcp_option_hdr opt_hdr; struct dhcp_iapd iapd; - struct prefix *pds = NULL; size_t rem; uint32_t t1, t2, lease_time; int serverid_len, rapid_commit = 0; @@ -733,11 +732,8 @@ parse_dhcp(struct dhcp6leased_iface *iface, struct imsg_dhcp *dhcp) log_debug("%s: %s ia_count: %d", __func__, if_name, iface_conf->ia_count); - pds = calloc(iface_conf->ia_count, sizeof(struct prefix)); - if (pds == NULL) - fatal("%s: calloc", __func__); - serverid_len = t1 = t2 = lease_time = 0; + memset(iface->new_pds, 0, sizeof(iface->new_pds)); p = dhcp->packet; rem = dhcp->len; @@ -821,7 +817,7 @@ parse_dhcp(struct dhcp6leased_iface *iface, struct imsg_dhcp *dhcp) parse_ia_pd_options(p + sizeof(struct dhcp_iapd), opt_hdr.len - sizeof(struct dhcp_iapd), - &pds[ntohl(iapd.iaid)]); + &iface->new_pds[ntohl(iapd.iaid)]); break; case DHO_RAPID_COMMIT: if (opt_hdr.len != 0) { @@ -848,7 +844,7 @@ parse_dhcp(struct dhcp6leased_iface *iface, struct imsg_dhcp *dhcp) SIMPLEQ_FOREACH(ia_conf, &iface_conf->iface_ia_list, entry) { - struct prefix *pd = &pds[ia_conf->id]; + struct prefix *pd = &iface->new_pds[ia_conf->id]; if (pd->prefix_len == 0) { log_warnx("%s: no IA for IAID %d found", __func__, @@ -895,9 +891,7 @@ parse_dhcp(struct dhcp6leased_iface *iface, struct imsg_dhcp *dhcp) } iface->serverid_len = serverid_len; memcpy(iface->serverid, serverid, SERVERID_SIZE); - memset(iface->pds, 0, sizeof(iface->pds)); - memcpy(iface->pds, pds, - iface_conf->ia_count * sizeof(struct prefix)); + memcpy(iface->pds, iface->new_pds, sizeof(iface->pds)); state_transition(iface, IF_REQUESTING); break; case DHCPREPLY: @@ -918,9 +912,7 @@ parse_dhcp(struct dhcp6leased_iface *iface, struct imsg_dhcp *dhcp) } iface->serverid_len = serverid_len; memcpy(iface->serverid, serverid, SERVERID_SIZE); - memset(iface->pds, 0, sizeof(iface->pds)); - memcpy(iface->pds, pds, - iface_conf->ia_count * sizeof(struct prefix)); + /* XXX handle t1 = 0 or t2 = 0 */ iface->t1 = t1; iface->t2 = t2; @@ -938,7 +930,7 @@ parse_dhcp(struct dhcp6leased_iface *iface, struct imsg_dhcp *dhcp) break; } out: - free(pds); + return; } void @@ -979,18 +971,25 @@ parse_ia_pd_options(uint8_t *p, size_t len, struct prefix *prefix) ntohl(iaprefix.vltime), inet_ntop(AF_INET6, &iaprefix.prefix, ntopbuf, INET6_ADDRSTRLEN), iaprefix.prefix_len); + if (ntohl(iaprefix.vltime) < ntohl(iaprefix.pltime)) { log_warnx("%s: vltime < pltime, ignoring IA_PD", __func__); break; } + if (ntohl(iaprefix.vltime) == 0) { + log_debug("%s: vltime == 0, ignoring IA_PD", + __func__); + break; + } + prefix->prefix = iaprefix.prefix; prefix->prefix_len = iaprefix.prefix_len; prefix->vltime = ntohl(iaprefix.vltime); prefix->pltime = ntohl(iaprefix.pltime); - /* make sure prefix is mask correctly */ + /* make sure prefix is masked correctly */ memset(&mask, 0, sizeof(mask)); in6_prefixlen2mask(&mask, prefix->prefix_len); for (i = 0; i < 16; i++) @@ -1288,17 +1287,37 @@ configure_interfaces(struct dhcp6leased_iface *iface) memset(&imsg_lease_info, 0, sizeof(imsg_lease_info)); imsg_lease_info.if_index = iface->if_index; - memcpy(imsg_lease_info.pds, iface->pds, sizeof(iface->pds)); + memcpy(imsg_lease_info.pds, iface->new_pds, sizeof(iface->new_pds)); engine_imsg_compose_main(IMSG_WRITE_LEASE, 0, &imsg_lease_info, sizeof(imsg_lease_info)); SIMPLEQ_FOREACH(ia_conf, &iface_conf->iface_ia_list, entry) { - struct prefix *pd = &iface->pds[ia_conf->id]; + struct prefix *pd = &iface->new_pds[ia_conf->id]; SIMPLEQ_FOREACH(pd_conf, &ia_conf->iface_pd_list, entry) { send_reconfigure_interface(pd_conf, pd, CONFIGURE); } } + + if (prefixcmp(iface->pds, iface->new_pds, iface_conf->ia_count) != 0) { + uint32_t i; + char ntopbuf[INET6_ADDRSTRLEN]; + + log_warnx("IA_PDs changed"); + for (i = 0; i < iface_conf->ia_count; i++) { + log_debug("%s: iface->pds [%d]: %s/%d", __func__, i, + inet_ntop(AF_INET6, &iface->pds[i].prefix, ntopbuf, + INET6_ADDRSTRLEN), iface->pds[i].prefix_len); + log_debug("%s: pds [%d]: %s/%d", __func__, i, + inet_ntop(AF_INET6, &iface->new_pds[i].prefix, + ntopbuf, INET6_ADDRSTRLEN), + iface->new_pds[i].prefix_len); + } + deconfigure_interfaces(iface); + } + + memcpy(iface->pds, iface->new_pds, sizeof(iface->pds)); + memset(iface->new_pds, 0, sizeof(iface->new_pds)); } void @@ -1331,6 +1350,21 @@ deconfigure_interfaces(struct dhcp6leased_iface *iface) } } +int +prefixcmp(struct prefix *a, struct prefix *b, int count) +{ + int i; + + for (i = 0; i < count; i++) { + if (a[i].prefix_len != b[i].prefix_len) + return 1; + if (memcmp(&a[i].prefix, &b[i].prefix, + sizeof(struct in6_addr)) != 0) + return 1; + } + return 0; +} + void send_reconfigure_interface(struct iface_pd_conf *pd_conf, struct prefix *pd, enum reconfigure_action action) diff --git a/sbin/swapctl/swapctl.8 b/sbin/swapctl/swapctl.8 index 8a7336542..6a71a4dfc 100644 --- a/sbin/swapctl/swapctl.8 +++ b/sbin/swapctl/swapctl.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: swapctl.8,v 1.36 2021/08/24 13:15:07 jmc Exp $ +.\" $OpenBSD: swapctl.8,v 1.37 2024/07/09 05:19:41 jmc Exp $ .\" $NetBSD: swapctl.8,v 1.14 1998/05/22 18:27:52 msaitoh Exp $ .\" .\" Copyright (c) 1997 Matthew R. Green @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd $Mdocdate: August 24 2021 $ +.Dd $Mdocdate: July 9 2024 $ .Dt SWAPCTL 8 .Os .Sh NAME @@ -181,7 +181,7 @@ This option is useful for swapping to NFS files. It specifies the local mount point to mount an NFS filesystem. Typically, once this mount has succeeded, the file to be used for swapping on will -be available under this point mount. +be available under this mount point. For example: .Bd -literal server:/export/swap/client none swap sw,nfsmntpt=/swap diff --git a/share/man/man5/port-modules.5 b/share/man/man5/port-modules.5 index 06c6d2401..eab225998 100644 --- a/share/man/man5/port-modules.5 +++ b/share/man/man5/port-modules.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: port-modules.5,v 1.268 2024/04/15 16:11:01 bentley Exp $ +.\" $OpenBSD: port-modules.5,v 1.269 2024/07/09 13:05:15 bentley Exp $ .\" .\" Copyright (c) 2008 Marc Espie .\" @@ -24,7 +24,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: April 15 2024 $ +.Dd $Mdocdate: July 9 2024 $ .Dt PORT-MODULES 5 .Os .Sh NAME @@ -698,6 +698,8 @@ it sets should be set to the name of the font family. This sets .Ev MODFONT_DIR +and +.Ev MODFONT_DOCDIR using said family name. A .Cm do-install @@ -709,6 +711,12 @@ If one or more file extensions are listed in .Ev MODFONT_TYPES , files of those types will be used. Otherwise, otf files are preferred, with a fallback to ttf. +If filenames (relative to +.Ev WRKSRC ) +are listed in +.Ev MODFONT_DOCFILES , +they will be installed to +.Ev MODFONT_DOCDIR . .It fortran Sets .Ev MODFORTRAN_LIB_DEPENDS , diff --git a/share/man/man9/mbuf.9 b/share/man/man9/mbuf.9 index 724d7dd18..ded14b87d 100644 --- a/share/man/man9/mbuf.9 +++ b/share/man/man9/mbuf.9 @@ -1,4 +1,4 @@ -.\" $OpenBSD: mbuf.9,v 1.125 2023/07/04 03:56:07 jsg Exp $ +.\" $OpenBSD: mbuf.9,v 1.126 2024/07/09 18:56:54 jan Exp $ .\" .\" Copyright (c) 2001 Jean-Jacques Bernard-Gundol .\" All rights reserved. @@ -25,7 +25,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: July 4 2023 $ +.Dd $Mdocdate: July 9 2024 $ .Dt MGET 9 .Os .Sh NAME @@ -155,14 +155,14 @@ #define mtod(m,t) ((t)((m)->m_data)) struct m_hdr { - struct mbuf *mh_next; - struct mbuf *mh_nextpkt; - caddr_t mh_data; - u_int mh_len; - short mh_type; - u_short mh_flags; + struct mbuf *mh_next; + struct mbuf *mh_nextpkt; + caddr_t mh_data; + u_int mh_len; + short mh_type; + u_short mh_flags; #ifndef __LP64__ - u_int mh_pad; + u_int mh_pad; #endif }; @@ -171,48 +171,50 @@ struct pkthdr { SLIST_HEAD(, m_tag) ph_tags; int64_t ph_timestamp; int len; + u_int ph_rtableid; + u_int ph_ifidx; u_int16_t ph_tagsset; u_int16_t ph_flowid; u_int16_t csum_flags; u_int16_t ether_vtag; - u_int ph_rtableid; - u_int ph_ifidx; + u_int16_t ph_mss; u_int8_t ph_loopcnt; + u_int8_t ph_family; struct pkthdr_pf pf; }; struct pkthdr_pf { - struct pf_state_key *statekey; - struct inpcb *inp; - u_int32_t qid; - u_int16_t tag; - u_int8_t flags; - u_int8_t routed; - u_int8_t prio; - u_int8_t pad[3]; + struct pf_state_key *statekey; + struct inpcb *inp; + u_int32_t qid; + u_int16_t tag; + u_int8_t flags; + u_int8_t routed; + u_int8_t prio; + u_int8_t pad[3]; }; struct mbuf_ext { - caddr_t ext_buf; - void *ext_arg; - u_int ext_free_fn; - u_int ext_size; - struct mbuf *ext_nextref; - struct mbuf *ext_prevref; + caddr_t ext_buf; + void *ext_arg; + u_int ext_free_fn; + u_int ext_size; + struct mbuf *ext_nextref; + struct mbuf *ext_prevref; }; struct mbuf { - struct m_hdr m_hdr; - union { - struct { - struct pkthdr MH_pkthdr; - union { - struct mbuf_ext MH_ext; - char MH_databuf[MHLEN]; - } MH_dat; - } MH; - char M_databuf[MLEN]; - } M_dat; + struct m_hdr m_hdr; + union { + struct { + struct pkthdr MH_pkthdr; + union { + struct mbuf_ext MH_ext; + char MH_databuf[MHLEN]; + } MH_dat; + } MH; + char M_databuf[MLEN]; + } M_dat; }; #define m_next m_hdr.mh_next @@ -382,6 +384,16 @@ ICMP/ICMPv6 checksum verified. ICMP/ICMPv6 checksum bad. .It Dv M_IPV6_DF_OUT Do not fragment IPv6 on output. +.It M_TIMESTAMP +.Fa m_pkthdr.ph_timestamp +is valid. +.It M_FLOWID +.Fa m_pkthdr.ph_flowid +is valid. +.It M_TCP_TSO +TCP Segmentation Offload needed and +.Fa m_pkthdr.ph_mss +is valid. .El .Pp The diff --git a/share/misc/airport b/share/misc/airport index 14e53e889..555507c74 100644 --- a/share/misc/airport +++ b/share/misc/airport @@ -1,4 +1,4 @@ -# $OpenBSD: airport,v 1.94 2024/07/08 14:15:33 op Exp $ +# $OpenBSD: airport,v 1.95 2024/07/09 03:21:47 jsg Exp $ # @(#)airport 8.1 (Berkeley) 6/8/93 # # Some of this information from the Airport Search Engine at @@ -115,7 +115,7 @@ ASP:Alice Springs, Alice Springs, Northern Territory, Australia ASU:Silvio Pettirossi, Asuncion, Paraguay ASW:Aswan International, Aswan, Egypt ATC:Arthurs Town, Bahamas -ATH:Athens Eleftherios Venizelos Internationa, Athens, Greece +ATH:Athens Eleftherios Venizelos International, Athens, Greece ATL:Atlanta William B. Hartsfield International, Georgia, USA ATW:Outagamie County Regional, Appleton, Wisconsin, USA ATY:Watertown Regional, South Dakota, USA @@ -344,7 +344,7 @@ CLD:Carlsbad/Palomar, California, USA CLE:Cleveland-Hopkins International, Ohio, USA CLJ:Cluj, Cluj, Romania CLL:College Station, Texas, USA -CLM:Wm Fairchild Internatinal, Port Angeles, Washington, USA +CLM:Wm Fairchild International, Port Angeles, Washington, USA CLO:Alfonso Bonilla Aragon, Cali, Colombia CLQ:Colima, Colima, Mexico CLT:Charlotte/Douglas International, North Carolina, USA @@ -1102,7 +1102,7 @@ MHK:Manhattan Municipal, Kansas, USA MHQ:Mariehamn, Aland Island, Finland MHT:Manchester, New Hampshire, USA MIA:Miami International, Florida, USA -MID:Merida Internationl, Merida, Yucatan, Mexico +MID:Merida International, Merida, Yucatan, Mexico MIE:Delaware County, Muncie, Indiana, USA MIL:All Airports around Milano, Italy MIR:Skanes, Monastir, Tunisia @@ -1136,7 +1136,7 @@ MNI:Montserrat, Leeward Islands MNL:Ninoy Aquino International, Manila, Philippines MNM:Twin County, Menominee, Michigan, USA MOB:Mobile Municipal/Bates Field, Alabama, USA -MOD:Harry Sham Feild, Modesto, California, USA +MOD:Harry Sham Field, Modesto, California, USA MOL:Aro, Molde, Norway MOT:Minot, North Dakota, USA MOW:All Airports around Moscow, Russia @@ -1195,7 +1195,7 @@ NAS:Nassau, Bahamas NAT:Agusto Severo, Natal, Rio Grande Do Norte, Brazil NAV:Nevsehir Kapadokya Airport, Nevsehir, Turkey NAY:Beijing, China -NBO:Jomo Kenyatta Internatonal, Nairobi, Kenya +NBO:Jomo Kenyatta International, Nairobi, Kenya NCA:North Caicos, Turks And Caicos Islands NCE:Cote D'azur, Nice, France NCL:Newcastle International, England, United Kingdom diff --git a/sys/arch/amd64/amd64/db_disasm.c b/sys/arch/amd64/amd64/db_disasm.c index 02d831256..e88fde839 100644 --- a/sys/arch/amd64/amd64/db_disasm.c +++ b/sys/arch/amd64/amd64/db_disasm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: db_disasm.c,v 1.25 2024/06/06 12:36:41 bluhm Exp $ */ +/* $OpenBSD: db_disasm.c,v 1.26 2024/07/09 01:21:19 jsg Exp $ */ /* $NetBSD: db_disasm.c,v 1.11 1996/05/03 19:41:58 christos Exp $ */ /* @@ -409,8 +409,8 @@ struct finst db_Esca[] = { /*1*/ { "fimul", LONG, 0, 0 }, /*2*/ { "ficom", LONG, 0, 0 }, /*3*/ { "ficomp", LONG, 0, 0 }, -/*4*/ { "fisub", LONG, op1(X), 0 }, -/*5*/ { "fisubr", LONG, 0, 0 }, +/*4*/ { "fisub", LONG, 0, 0 }, +/*5*/ { "fisubr", LONG, op1(X), db_Esca5 }, /*6*/ { "fidiv", LONG, 0, 0 }, /*7*/ { "fidivr", LONG, 0, 0 } }; diff --git a/sys/arch/amd64/amd64/pmap.c b/sys/arch/amd64/amd64/pmap.c index 3a980ba1c..0c3fe07cd 100644 --- a/sys/arch/amd64/amd64/pmap.c +++ b/sys/arch/amd64/amd64/pmap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pmap.c,v 1.168 2024/06/03 20:53:00 dv Exp $ */ +/* $OpenBSD: pmap.c,v 1.169 2024/07/09 19:11:06 bluhm Exp $ */ /* $NetBSD: pmap.c,v 1.3 2003/05/08 18:13:13 thorpej Exp $ */ /* @@ -235,6 +235,11 @@ pt_entry_t pg_g_kern = 0; /* pg_xo: XO PTE bits, set to PKU key1 (if cpu supports PKU) */ pt_entry_t pg_xo; +/* pg_crypt, pg_frame, pg_lgframe: will be derived from CPUID */ +pt_entry_t pg_crypt = 0; +pt_entry_t pg_frame = PG_FRAME; +pt_entry_t pg_lgframe = PG_LGFRAME; + /* * pmap_pg_wc: if our processor supports PAT then we set this * to be the pte bits for Write Combining. Else we fall back to @@ -465,7 +470,7 @@ pmap_find_pte_direct(struct pmap *pm, vaddr_t va, pt_entry_t **pd, int *offs) if ((pde & (PG_PS|PG_V)) != PG_V) return (lev - 1); - pdpa = ((*pd)[*offs] & PG_FRAME); + pdpa = ((*pd)[*offs] & pg_frame); /* 4096/8 == 512 == 2^9 entries per level */ shift -= 9; mask >>= 9; @@ -498,7 +503,8 @@ pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot) npte = (pa & PMAP_PA_MASK) | ((prot & PROT_WRITE) ? PG_RW : PG_RO) | ((pa & PMAP_NOCACHE) ? PG_N : 0) | - ((pa & PMAP_WC) ? pmap_pg_wc : 0) | PG_V; + ((pa & PMAP_WC) ? pmap_pg_wc : 0) | PG_V | + ((pa & PMAP_NOCRYPT) ? 0 : pg_crypt); /* special 1:1 mappings in the first 2MB must not be global */ if (va >= (vaddr_t)NBPD_L2) @@ -513,7 +519,8 @@ pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot) panic("%s: PG_PS", __func__); #endif if (pmap_valid_entry(opte)) { - if (pa & PMAP_NOCACHE && (opte & PG_N) == 0) + if ((pa & PMAP_NOCACHE && (opte & PG_N) == 0) || + (pa & PMAP_NOCRYPT)) wbinvd_on_all_cpus(); /* This shouldn't happen */ pmap_tlb_shootpage(pmap_kernel(), va, 1); @@ -582,7 +589,8 @@ pmap_set_pml4_early(paddr_t pa) vaddr_t va; pml4e = (pt_entry_t *)(proc0.p_addr->u_pcb.pcb_cr3 + KERNBASE); - pml4e[PDIR_SLOT_EARLY] = (pd_entry_t)early_pte_pages | PG_V | PG_RW; + pml4e[PDIR_SLOT_EARLY] = (pd_entry_t)early_pte_pages | PG_V | PG_RW | + pg_crypt; off = pa & PAGE_MASK_L2; curpa = pa & L2_FRAME; @@ -590,15 +598,16 @@ pmap_set_pml4_early(paddr_t pa) pte = (pt_entry_t *)PMAP_DIRECT_MAP(early_pte_pages); memset(pte, 0, 3 * NBPG); - pte[0] = (early_pte_pages + NBPG) | PG_V | PG_RW; - pte[1] = (early_pte_pages + 2 * NBPG) | PG_V | PG_RW; + pte[0] = (early_pte_pages + NBPG) | PG_V | PG_RW | pg_crypt; + pte[1] = (early_pte_pages + 2 * NBPG) | PG_V | PG_RW | pg_crypt; pte = (pt_entry_t *)PMAP_DIRECT_MAP(early_pte_pages + NBPG); for (i = 0; i < 2; i++) { /* 2 early pages of mappings */ for (j = 0; j < 512; j++) { /* j[0..511] : 2MB mappings per page */ - pte[(i * 512) + j] = curpa | PG_V | PG_RW | PG_PS; + pte[(i * 512) + j] = curpa | PG_V | PG_RW | PG_PS | + pg_crypt; curpa += (2 * 1024 * 1024); } } @@ -777,7 +786,7 @@ pmap_bootstrap(paddr_t first_avail, paddr_t max_pa) if (ndmpdp > 512) ndmpdp = 512; /* At most 512GB */ - dmpdp = kpm->pm_pdir[PDIR_SLOT_DIRECT] & PG_FRAME; + dmpdp = kpm->pm_pdir[PDIR_SLOT_DIRECT] & pg_frame; dmpd = first_avail; first_avail += ndmpdp * PAGE_SIZE; @@ -790,7 +799,7 @@ pmap_bootstrap(paddr_t first_avail, paddr_t max_pa) *((pd_entry_t *)va) = ((paddr_t)i << L2_SHIFT); *((pd_entry_t *)va) |= PG_RW | PG_V | PG_PS | pg_g_kern | PG_U | - PG_M | pg_nx; + PG_M | pg_nx | pg_crypt; } for (i = NDML2_ENTRIES; i < ndmpdp; i++) { @@ -801,11 +810,12 @@ pmap_bootstrap(paddr_t first_avail, paddr_t max_pa) va = PMAP_DIRECT_MAP(pdp); *((pd_entry_t *)va) = dmpd + (i << PAGE_SHIFT); - *((pd_entry_t *)va) |= PG_RW | PG_V | PG_U | PG_M | pg_nx; + *((pd_entry_t *)va) |= PG_RW | PG_V | PG_U | PG_M | pg_nx | + pg_crypt; } kpm->pm_pdir[PDIR_SLOT_DIRECT] = dmpdp | PG_V | PG_KW | PG_U | - PG_M | pg_nx; + PG_M | pg_nx | pg_crypt; /* Map any remaining physical memory > 512GB */ for (curslot = 1 ; curslot < NUM_L4_SLOT_DIRECT ; curslot++) { @@ -818,7 +828,7 @@ pmap_bootstrap(paddr_t first_avail, paddr_t max_pa) dmpd = first_avail; first_avail += PAGE_SIZE; pml3 = (pt_entry_t *)PMAP_DIRECT_MAP(dmpd); kpm->pm_pdir[PDIR_SLOT_DIRECT + curslot] = dmpd | - PG_KW | PG_V | PG_U | PG_M | pg_nx; + PG_KW | PG_V | PG_U | PG_M | pg_nx | pg_crypt; /* Calculate full 1GB pages in this 512GB region */ p = ((max_pa - start_cur) >> L3_SHIFT); @@ -839,7 +849,8 @@ pmap_bootstrap(paddr_t first_avail, paddr_t max_pa) dmpd = first_avail; first_avail += PAGE_SIZE; pml2 = (pt_entry_t *)PMAP_DIRECT_MAP(dmpd); pml3[i] = dmpd | - PG_RW | PG_V | PG_U | PG_M | pg_nx; + PG_RW | PG_V | PG_U | PG_M | pg_nx | + pg_crypt; cur_pa = start_cur + (i << L3_SHIFT); j = 0; @@ -849,7 +860,8 @@ pmap_bootstrap(paddr_t first_avail, paddr_t max_pa) (uint64_t)i * NBPD_L3 + (uint64_t)j * NBPD_L2; pml2[j] |= PG_RW | PG_V | pg_g_kern | - PG_U | PG_M | pg_nx | PG_PS; + PG_U | PG_M | pg_nx | PG_PS | + pg_crypt; cur_pa += NBPD_L2; j++; } @@ -949,14 +961,14 @@ pmap_randomize(void) proc0.p_addr->u_pcb.pcb_cr3 = pml4pa; /* Fixup recursive PTE PML4E slot. We are only changing the PA */ - pml4va[PDIR_SLOT_PTE] = pml4pa | (pml4va[PDIR_SLOT_PTE] & ~PG_FRAME); + pml4va[PDIR_SLOT_PTE] = pml4pa | (pml4va[PDIR_SLOT_PTE] & ~pg_frame); for (i = 0; i < NPDPG; i++) { /* PTE slot already handled earlier */ if (i == PDIR_SLOT_PTE) continue; - if (pml4va[i] & PG_FRAME) + if (pml4va[i] & pg_frame) pmap_randomize_level(&pml4va[i], 3); } @@ -985,11 +997,11 @@ pmap_randomize_level(pd_entry_t *pde, int level) panic("%s: cannot allocate page for L%d page directory", __func__, level); - old_pd_pa = *pde & PG_FRAME; + old_pd_pa = *pde & pg_frame; old_pd_va = PMAP_DIRECT_MAP(old_pd_pa); pmap_extract(pmap_kernel(), (vaddr_t)new_pd_va, &new_pd_pa); memcpy(new_pd_va, (void *)old_pd_va, PAGE_SIZE); - *pde = new_pd_pa | (*pde & ~PG_FRAME); + *pde = new_pd_pa | (*pde & ~pg_frame); tlbflush(); memset((void *)old_pd_va, 0, PAGE_SIZE); @@ -1003,7 +1015,7 @@ pmap_randomize_level(pd_entry_t *pde, int level) } for (i = 0; i < NPDPG; i++) - if (new_pd_va[i] & PG_FRAME) + if (new_pd_va[i] & pg_frame) pmap_randomize_level(&new_pd_va[i], level - 1); } @@ -1023,7 +1035,8 @@ pmap_prealloc_lowmem_ptps(paddr_t first_avail) for (;;) { newp = first_avail; first_avail += PAGE_SIZE; memset((void *)PMAP_DIRECT_MAP(newp), 0, PAGE_SIZE); - pdes[pl_i(0, level)] = (newp & PG_FRAME) | PG_V | PG_RW; + pdes[pl_i(0, level)] = + (newp & pg_frame) | PG_V | PG_RW | pg_crypt; level--; if (level <= 1) break; @@ -1203,7 +1216,7 @@ pmap_get_ptp(struct pmap *pmap, vaddr_t va) pva = normal_pdes[i - 2]; if (pmap_valid_entry(pva[index])) { - ppa = pva[index] & PG_FRAME; + ppa = pva[index] & pg_frame; ptp = NULL; continue; } @@ -1219,7 +1232,7 @@ pmap_get_ptp(struct pmap *pmap, vaddr_t va) ptp->wire_count = 1; pmap->pm_ptphint[i - 2] = ptp; pa = VM_PAGE_TO_PHYS(ptp); - pva[index] = (pd_entry_t) (pa | PG_u | PG_RW | PG_V); + pva[index] = (pd_entry_t) (pa | PG_u | PG_RW | PG_V | pg_crypt); /* * Meltdown Special case - if we are adding a new PML4e for @@ -1292,7 +1305,7 @@ pmap_pdp_ctor(pd_entry_t *pdir) memset(pdir, 0, PDIR_SLOT_PTE * sizeof(pd_entry_t)); /* put in recursive PDE to map the PTEs */ - pdir[PDIR_SLOT_PTE] = pdirpa | PG_V | PG_KW | pg_nx; + pdir[PDIR_SLOT_PTE] = pdirpa | PG_V | PG_KW | pg_nx | pg_crypt; npde = nkptp[PTP_LEVELS - 1]; @@ -1359,7 +1372,7 @@ pmap_create(void) pmap->pm_pdir = pool_get(&pmap_pdp_pool, PR_WAITOK); pmap_pdp_ctor(pmap->pm_pdir); - pmap->pm_pdirpa = pmap->pm_pdir[PDIR_SLOT_PTE] & PG_FRAME; + pmap->pm_pdirpa = pmap->pm_pdir[PDIR_SLOT_PTE] & pg_frame; /* * Intel CPUs need a special page table to be used during usermode @@ -1557,12 +1570,12 @@ pmap_extract(struct pmap *pmap, vaddr_t va, paddr_t *pap) if (__predict_true(level == 0 && pmap_valid_entry(pte))) { if (pap != NULL) - *pap = (pte & PG_FRAME) | (va & PAGE_MASK); + *pap = (pte & pg_frame) | (va & PAGE_MASK); return 1; } if (level == 1 && (pte & (PG_PS|PG_V)) == (PG_PS|PG_V)) { if (pap != NULL) - *pap = (pte & PG_LGFRAME) | (va & PAGE_MASK_L2); + *pap = (pte & pg_lgframe) | (va & PAGE_MASK_L2); return 1; } @@ -1661,7 +1674,7 @@ pmap_remove_ptes(struct pmap *pmap, struct vm_page *ptp, vaddr_t ptpva, if (ptp != NULL) ptp->wire_count--; /* dropping a PTE */ - pg = PHYS_TO_VM_PAGE(opte & PG_FRAME); + pg = PHYS_TO_VM_PAGE(opte & pg_frame); /* * if we are not on a pv list we are done. @@ -1728,7 +1741,7 @@ pmap_remove_pte(struct pmap *pmap, struct vm_page *ptp, pt_entry_t *pte, if (ptp != NULL) ptp->wire_count--; /* dropping a PTE */ - pg = PHYS_TO_VM_PAGE(opte & PG_FRAME); + pg = PHYS_TO_VM_PAGE(opte & pg_frame); /* * if we are not on a pv list we are done. @@ -1808,7 +1821,7 @@ pmap_do_remove(struct pmap *pmap, vaddr_t sva, vaddr_t eva, int flags) if (pmap_pdes_valid(sva, &pde)) { /* PA of the PTP */ - ptppa = pde & PG_FRAME; + ptppa = pde & pg_frame; /* get PTP if non-kernel mapping */ @@ -1876,7 +1889,7 @@ pmap_do_remove(struct pmap *pmap, vaddr_t sva, vaddr_t eva, int flags) continue; /* PA of the PTP */ - ptppa = pde & PG_FRAME; + ptppa = pde & pg_frame; /* get PTP if non-kernel mapping */ if (pmap == pmap_kernel()) { @@ -1974,12 +1987,12 @@ pmap_page_remove(struct vm_page *pg) #ifdef DIAGNOSTIC if (pve->pv_ptp != NULL && pmap_pdes_valid(pve->pv_va, &pde) && - (pde & PG_FRAME) != VM_PAGE_TO_PHYS(pve->pv_ptp)) { + (pde & pg_frame) != VM_PAGE_TO_PHYS(pve->pv_ptp)) { printf("%s: pg=%p: va=%lx, pv_ptp=%p\n", __func__, pg, pve->pv_va, pve->pv_ptp); printf("%s: PTP's phys addr: " "actual=%lx, recorded=%lx\n", __func__, - (unsigned long)(pde & PG_FRAME), + (unsigned long)(pde & pg_frame), VM_PAGE_TO_PHYS(pve->pv_ptp)); panic("%s: mapped managed page has " "invalid pv_ptp field", __func__); @@ -2140,8 +2153,8 @@ pmap_write_protect(struct pmap *pmap, vaddr_t sva, vaddr_t eva, vm_prot_t prot) shootself = (scr3 == 0); /* should be ok, but just in case ... */ - sva &= PG_FRAME; - eva &= PG_FRAME; + sva &= pg_frame; + eva &= pg_frame; if (!(prot & PROT_READ)) set |= pg_xo; @@ -2314,7 +2327,7 @@ pmap_enter_special(vaddr_t va, paddr_t pa, vm_prot_t prot) if (!pmap_extract(pmap, (vaddr_t)ptp, &npa)) panic("%s: can't locate PDPT page", __func__); - pd[l4idx] = (npa | PG_RW | PG_V); + pd[l4idx] = (npa | PG_RW | PG_V | pg_crypt); DPRINTF("%s: allocated new PDPT page at phys 0x%llx, " "setting PML4e[%lld] = 0x%llx\n", __func__, @@ -2338,7 +2351,7 @@ pmap_enter_special(vaddr_t va, paddr_t pa, vm_prot_t prot) if (!pmap_extract(pmap, (vaddr_t)ptp, &npa)) panic("%s: can't locate PD page", __func__); - pd[l3idx] = (npa | PG_RW | PG_V); + pd[l3idx] = (npa | PG_RW | PG_V | pg_crypt); DPRINTF("%s: allocated new PD page at phys 0x%llx, " "setting PDPTe[%lld] = 0x%llx\n", __func__, @@ -2362,7 +2375,7 @@ pmap_enter_special(vaddr_t va, paddr_t pa, vm_prot_t prot) if (!pmap_extract(pmap, (vaddr_t)ptp, &npa)) panic("%s: can't locate PT page", __func__); - pd[l2idx] = (npa | PG_RW | PG_V); + pd[l2idx] = (npa | PG_RW | PG_V | pg_crypt); DPRINTF("%s: allocated new PT page at phys 0x%llx, " "setting PDE[%lld] = 0x%llx\n", __func__, @@ -2378,7 +2391,7 @@ pmap_enter_special(vaddr_t va, paddr_t pa, vm_prot_t prot) "0x%llx was 0x%llx\n", __func__, (uint64_t)npa, (uint64_t)pd, (uint64_t)prot, (uint64_t)pd[l1idx]); - pd[l1idx] = pa | protection_codes[prot] | PG_V | PG_W; + pd[l1idx] = pa | protection_codes[prot] | PG_V | PG_W | pg_crypt; /* * Look up the corresponding U+K entry. If we're installing the @@ -2387,7 +2400,7 @@ pmap_enter_special(vaddr_t va, paddr_t pa, vm_prot_t prot) */ level = pmap_find_pte_direct(pmap, va, &ptes, &offs); if (__predict_true(level == 0 && pmap_valid_entry(ptes[offs]))) { - if (((pd[l1idx] ^ ptes[offs]) & PG_FRAME) == 0) { + if (((pd[l1idx] ^ ptes[offs]) & pg_frame) == 0) { pd[l1idx] |= PG_G | (ptes[offs] & (PG_N | PG_WT)); ptes[offs] |= PG_G; } else { @@ -2701,6 +2714,7 @@ pmap_enter(struct pmap *pmap, vaddr_t va, paddr_t pa, vm_prot_t prot, int flags) struct pv_entry *pve, *opve = NULL; int ptpdelta, wireddelta, resdelta; int wired = (flags & PMAP_WIRED) != 0; + int crypt = (flags & PMAP_NOCRYPT) == 0; int nocache = (pa & PMAP_NOCACHE) != 0; int wc = (pa & PMAP_WC) != 0; int error, shootself; @@ -2778,7 +2792,7 @@ pmap_enter(struct pmap *pmap, vaddr_t va, paddr_t pa, vm_prot_t prot, int flags) * want to map? */ - if ((opte & PG_FRAME) == pa) { + if ((opte & pg_frame) == pa) { /* if this is on the PVLIST, sync R/M bit */ if (opte & PG_PVLIST) { @@ -2813,7 +2827,7 @@ pmap_enter(struct pmap *pmap, vaddr_t va, paddr_t pa, vm_prot_t prot, int flags) */ if (opte & PG_PVLIST) { - pg = PHYS_TO_VM_PAGE(opte & PG_FRAME); + pg = PHYS_TO_VM_PAGE(opte & pg_frame); #ifdef DIAGNOSTIC if (pg == NULL) panic("%s: PG_PVLIST mapping with unmanaged " @@ -2887,6 +2901,8 @@ enter_now: npte |= (PG_u | PG_RW); /* XXXCDC: no longer needed? */ if (pmap == pmap_kernel()) npte |= pg_g_kern; + if (crypt) + npte |= pg_crypt; /* * If the old entry wasn't valid, we can just update it and @@ -2998,7 +3014,7 @@ pmap_alloc_level(vaddr_t kva, int lvl, long *needed_ptps) for (i = index; i <= endindex; i++) { pmap_get_physpage(va, level - 1, &pa); - pdep[i] = pa | PG_RW | PG_V | pg_nx; + pdep[i] = pa | PG_RW | PG_V | pg_nx | pg_crypt; nkptp[level - 1]++; va += nbpd[level - 1]; } diff --git a/sys/arch/amd64/amd64/vmm_support.S b/sys/arch/amd64/amd64/vmm_support.S index 9c0286306..30c1b7583 100644 --- a/sys/arch/amd64/amd64/vmm_support.S +++ b/sys/arch/amd64/amd64/vmm_support.S @@ -1,4 +1,4 @@ -/* $OpenBSD: vmm_support.S,v 1.27 2024/04/01 05:11:49 guenther Exp $ */ +/* $OpenBSD: vmm_support.S,v 1.28 2024/07/09 11:15:58 deraadt Exp $ */ /* * Copyright (c) 2014 Mike Larkin * @@ -57,6 +57,7 @@ vmm_dispatch_intr: pushq %rax cli callq *%rdi + movq $0,-8(%rsp) ret lfence diff --git a/sys/arch/amd64/include/pmap.h b/sys/arch/amd64/include/pmap.h index e59037aa3..40808ff41 100644 --- a/sys/arch/amd64/include/pmap.h +++ b/sys/arch/amd64/include/pmap.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pmap.h,v 1.88 2023/12/29 13:23:28 jca Exp $ */ +/* $OpenBSD: pmap.h,v 1.89 2024/07/09 19:11:06 bluhm Exp $ */ /* $NetBSD: pmap.h,v 1.1 2003/04/26 18:39:46 fvdl Exp $ */ /* @@ -320,6 +320,7 @@ struct pmap { }; #define PMAP_EFI PMAP_MD0 +#define PMAP_NOCRYPT PMAP_MD1 /* * MD flags that we use for pmap_enter (in the pa): diff --git a/sys/arch/amd64/include/pte.h b/sys/arch/amd64/include/pte.h index 03c65f4db..abb1115ff 100644 --- a/sys/arch/amd64/include/pte.h +++ b/sys/arch/amd64/include/pte.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pte.h,v 1.17 2023/01/20 16:01:04 deraadt Exp $ */ +/* $OpenBSD: pte.h,v 1.18 2024/07/09 19:11:06 bluhm Exp $ */ /* $NetBSD: pte.h,v 1.1 2003/04/26 18:39:47 fvdl Exp $ */ /* @@ -164,6 +164,7 @@ typedef u_int64_t pt_entry_t; /* PTE */ #ifdef _KERNEL extern pt_entry_t pg_xo; /* XO pte bits using PKU key1 */ extern pt_entry_t pg_nx; /* NX pte bit */ +extern pt_entry_t pg_crypt; /* C pte bit */ extern pt_entry_t pg_g_kern; /* PG_G if glbl mappings can be used in kern */ #endif /* _KERNEL */ diff --git a/sys/arch/amd64/include/vmmvar.h b/sys/arch/amd64/include/vmmvar.h index 8426a5d94..50c1f15b0 100644 --- a/sys/arch/amd64/include/vmmvar.h +++ b/sys/arch/amd64/include/vmmvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vmmvar.h,v 1.101 2024/04/29 14:47:05 dv Exp $ */ +/* $OpenBSD: vmmvar.h,v 1.102 2024/07/09 09:31:37 dv Exp $ */ /* * Copyright (c) 2014 Mike Larkin * @@ -23,14 +23,6 @@ #define VMM_HV_SIGNATURE "OpenBSDVMM58" -#define VMM_MAX_MEM_RANGES 16 -#define VMM_MAX_DISKS_PER_VM 4 -#define VMM_MAX_NAME_LEN 64 -#define VMM_MAX_VCPUS 512 -#define VMM_MAX_VCPUS_PER_VM 64 -#define VMM_MAX_VM_MEM_SIZE 128L * 1024 * 1024 * 1024 -#define VMM_MAX_NICS_PER_VM 4 - #define VMM_PCI_MMIO_BAR_BASE 0xF0000000ULL #define VMM_PCI_MMIO_BAR_END 0xFFDFFFFFULL /* 2 MiB below 4 GiB */ @@ -474,21 +466,6 @@ struct vm_exit { int cpl; }; -struct vm_run_params { - /* Input parameters to VMM_IOC_RUN */ - uint32_t vrp_vm_id; - uint32_t vrp_vcpu_id; - struct vcpu_inject_event vrp_inject; - uint8_t vrp_intr_pending; /* Additional intrs pending? */ - - /* Input/output parameter to VMM_IOC_RUN */ - struct vm_exit *vrp_exit; /* updated exit data */ - - /* Output parameter from VMM_IOC_RUN */ - uint16_t vrp_exit_reason; /* exit reason */ - uint8_t vrp_irqready; /* ready for IRQ on entry */ -}; - struct vm_intr_params { /* Input parameters to VMM_IOC_INTR */ uint32_t vip_vm_id; @@ -961,7 +938,6 @@ int vcpu_init(struct vcpu *); void vcpu_deinit(struct vcpu *); int vm_rwvmparams(struct vm_rwvmparams_params *, int); int vm_rwregs(struct vm_rwregs_params *, int); -int vm_run(struct vm_run_params *); int vcpu_reset_regs(struct vcpu *, struct vcpu_reg_state *); #endif /* _KERNEL */ diff --git a/sys/arch/i386/i386/db_disasm.c b/sys/arch/i386/i386/db_disasm.c index e822088fc..20023ea90 100644 --- a/sys/arch/i386/i386/db_disasm.c +++ b/sys/arch/i386/i386/db_disasm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: db_disasm.c,v 1.24 2020/09/11 09:27:10 mpi Exp $ */ +/* $OpenBSD: db_disasm.c,v 1.25 2024/07/09 01:21:19 jsg Exp $ */ /* $NetBSD: db_disasm.c,v 1.11 1996/05/03 19:41:58 christos Exp $ */ /* @@ -410,8 +410,8 @@ struct finst db_Esca[] = { /*1*/ { "fimul", LONG, 0, 0 }, /*2*/ { "ficom", LONG, 0, 0 }, /*3*/ { "ficomp", LONG, 0, 0 }, -/*4*/ { "fisub", LONG, op1(X), 0 }, -/*5*/ { "fisubr", LONG, 0, 0 }, +/*4*/ { "fisub", LONG, 0, 0 }, +/*5*/ { "fisubr", LONG, op1(X), db_Esca5 }, /*6*/ { "fidiv", LONG, 0, 0 }, /*7*/ { "fidivr", LONG, 0, 0 } }; diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c index abb46f435..a15b37a78 100644 --- a/sys/arch/i386/i386/machdep.c +++ b/sys/arch/i386/i386/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.672 2024/06/07 16:53:35 kettenis Exp $ */ +/* $OpenBSD: machdep.c,v 1.673 2024/07/09 07:28:12 mlarkin Exp $ */ /* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */ /*- diff --git a/sys/dev/fdt/dwpcie.c b/sys/dev/fdt/dwpcie.c index f9877af26..169b530fd 100644 --- a/sys/dev/fdt/dwpcie.c +++ b/sys/dev/fdt/dwpcie.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dwpcie.c,v 1.55 2024/07/05 22:52:25 patrick Exp $ */ +/* $OpenBSD: dwpcie.c,v 1.56 2024/07/09 08:47:10 kettenis Exp $ */ /* * Copyright (c) 2018 Mark Kettenis * @@ -60,9 +60,9 @@ #define PCIE_MSI_ADDR_LO 0x820 #define PCIE_MSI_ADDR_HI 0x824 -#define PCIE_MSI_INTR0_ENABLE 0x828 -#define PCIE_MSI_INTR0_MASK 0x82c -#define PCIE_MSI_INTR0_STATUS 0x830 +#define PCIE_MSI_INTR_ENABLE(x) (0x828 + (x) * 12) +#define PCIE_MSI_INTR_MASK(x) (0x82c + (x) * 12) +#define PCIE_MSI_INTR_STATUS(x) (0x830 + (x) * 12) #define MISC_CONTROL_1 0x8bc #define MISC_CONTROL_1_DBI_RO_WR_EN (1 << 0) @@ -215,7 +215,7 @@ struct dwpcie_intx { TAILQ_ENTRY(dwpcie_intx) di_next; }; -#define DWPCIE_NUM_MSI 32 +#define DWPCIE_MAX_MSI 64 struct dwpcie_msi { int (*dm_func)(void *); @@ -223,6 +223,7 @@ struct dwpcie_msi { int dm_ipl; int dm_flags; int dm_vec; + int dm_nvec; struct evcount dm_count; char *dm_name; }; @@ -280,8 +281,11 @@ struct dwpcie_softc { struct interrupt_controller sc_ic; TAILQ_HEAD(,dwpcie_intx) sc_intx[4]; + void *sc_msi_ih[2]; uint64_t sc_msi_addr; - struct dwpcie_msi sc_msi[DWPCIE_NUM_MSI]; + uint64_t sc_msi_mask; + struct dwpcie_msi sc_msi[DWPCIE_MAX_MSI]; + int sc_num_msi; }; struct dwpcie_intr_handle { @@ -727,12 +731,20 @@ dwpcie_attach_deferred(struct device *self) pba.pba_pc = &sc->sc_pc; pba.pba_domain = pci_ndomains++; pba.pba_bus = sc->sc_bus; + if (OF_is_compatible(sc->sc_node, "baikal,bm1000-pcie") || OF_is_compatible(sc->sc_node, "marvell,armada8k-pcie") || OF_getproplen(sc->sc_node, "msi-map") > 0 || sc->sc_msi_addr) pba.pba_flags |= PCI_FLAGS_MSI_ENABLED; - if (OF_getproplen(sc->sc_node, "msi-map") > 0) + + /* + * Only support mutiple MSI vectors if we have enough MSI + * interrupts (or are using an external interrupt controller + * that hopefully suppors plenty of MSI interripts). + */ + if (OF_getproplen(sc->sc_node, "msi-map") > 0 || + sc->sc_num_msi > 32) pba.pba_flags |= PCI_FLAGS_MSIVEC_ENABLED; pci_dopm = 1; @@ -786,23 +798,22 @@ dwpcie_link_config(struct dwpcie_softc *sc) } int -dwpcie_msi_intr(void *arg) +dwpcie_msi_intr(struct dwpcie_softc *sc, int idx) { - struct dwpcie_softc *sc = arg; struct dwpcie_msi *dm; uint32_t status; int vec, s; - status = HREAD4(sc, PCIE_MSI_INTR0_STATUS); + status = HREAD4(sc, PCIE_MSI_INTR_STATUS(idx)); if (status == 0) return 0; - HWRITE4(sc, PCIE_MSI_INTR0_STATUS, status); + HWRITE4(sc, PCIE_MSI_INTR_STATUS(idx), status); while (status) { vec = ffs(status) - 1; status &= ~(1U << vec); - dm = &sc->sc_msi[vec]; + dm = &sc->sc_msi[idx * 32 + vec]; if (dm->dm_func == NULL) continue; @@ -819,6 +830,18 @@ dwpcie_msi_intr(void *arg) return 1; } +int +dwpcie_msi0_intr(void *arg) +{ + return dwpcie_msi_intr(arg, 0); +} + +int +dwpcie_msi1_intr(void *arg) +{ + return dwpcie_msi_intr(arg, 1); +} + int dwpcie_msi_init(struct dwpcie_softc *sc) { @@ -826,6 +849,7 @@ dwpcie_msi_init(struct dwpcie_softc *sc) bus_dmamap_t map; uint64_t addr; int error, rseg; + int idx; /* * Allocate some DMA memory such that we have a "safe" target @@ -861,19 +885,46 @@ dwpcie_msi_init(struct dwpcie_softc *sc) bus_dmamap_unload(sc->sc_dmat, map); bus_dmamap_destroy(sc->sc_dmat, map); - /* Enable, mask and clear all MSIs. */ - HWRITE4(sc, PCIE_MSI_INTR0_ENABLE, 0xffffffff); - HWRITE4(sc, PCIE_MSI_INTR0_MASK, 0xffffffff); - HWRITE4(sc, PCIE_MSI_INTR0_STATUS, 0xffffffff); + /* + * See if the device tree indicates that the hardware supports + * more than 32 vectors. Some hardware supports more than 64, + * but 64 is good enough for now. + */ + idx = OF_getindex(sc->sc_node, "msi1", "interrupt-names"); + if (idx == -1) + sc->sc_num_msi = 32; + else + sc->sc_num_msi = 64; + KASSERT(sc->sc_num_msi <= DWPCIE_MAX_MSI); - KASSERT(sc->sc_ih == NULL); - sc->sc_ih = fdt_intr_establish(sc->sc_node, IPL_BIO | IPL_MPSAFE, - dwpcie_msi_intr, sc, sc->sc_dev.dv_xname); - if (sc->sc_ih == NULL) { + /* Enable, mask and clear all MSIs. */ + for (idx = 0; idx < sc->sc_num_msi / 32; idx++) { + HWRITE4(sc, PCIE_MSI_INTR_ENABLE(idx), 0xffffffff); + HWRITE4(sc, PCIE_MSI_INTR_MASK(idx), 0xffffffff); + HWRITE4(sc, PCIE_MSI_INTR_STATUS(idx), 0xffffffff); + } + + idx = OF_getindex(sc->sc_node, "msi0", "interrupt-names"); + if (idx == -1) + idx = 0; + + sc->sc_msi_ih[0] = fdt_intr_establish_idx(sc->sc_node, idx, + IPL_BIO | IPL_MPSAFE, dwpcie_msi0_intr, sc, sc->sc_dev.dv_xname); + if (sc->sc_msi_ih[0] == NULL) { bus_dmamem_free(sc->sc_dmat, &seg, 1); return EINVAL; } + idx = OF_getindex(sc->sc_node, "msi1", "interrupt-names"); + if (idx == -1) + goto finish; + + sc->sc_msi_ih[1] = fdt_intr_establish_idx(sc->sc_node, idx, + IPL_BIO | IPL_MPSAFE, dwpcie_msi1_intr, sc, sc->sc_dev.dv_xname); + if (sc->sc_msi_ih[1] == NULL) + sc->sc_num_msi = 32; + +finish: /* * Hold on to the DMA memory such that nobody can use it to * actually do DMA transfers. @@ -1781,31 +1832,81 @@ dwpcie_intr_string(void *v, pci_intr_handle_t ih) } struct dwpcie_msi * -dwpcie_msi_establish(struct dwpcie_softc *sc, int level, - int (*func)(void *), void *arg, char *name) +dwpcie_msi_establish(struct dwpcie_softc *sc, pci_intr_handle_t *ihp, + int level, int (*func)(void *), void *arg, char *name) { + pci_chipset_tag_t pc = ihp->ih_pc; + pcitag_t tag = ihp->ih_tag; struct dwpcie_msi *dm; - int vec; + uint64_t msi_mask; + int vec = ihp->ih_intrpin; + int base, mme, nvec, off; + pcireg_t reg; - for (vec = 0; vec < DWPCIE_NUM_MSI; vec++) { - dm = &sc->sc_msi[vec]; - if (dm->dm_func == NULL) - break; + if (ihp->ih_type == PCI_MSI) { + if (pci_get_capability(pc, tag, PCI_CAP_MSI, &off, ®) == 0) + panic("%s: no msi capability", __func__); + + reg = pci_conf_read(ihp->ih_pc, ihp->ih_tag, off); + mme = ((reg & PCI_MSI_MC_MME_MASK) >> PCI_MSI_MC_MME_SHIFT); + if (vec >= (1 << mme)) + return NULL; + if (reg & PCI_MSI_MC_C64) + base = pci_conf_read(pc, tag, off + PCI_MSI_MD64); + else + base = pci_conf_read(pc, tag, off + PCI_MSI_MD32); + } else { + mme = 0; + base = 0; } - if (vec == DWPCIE_NUM_MSI) + + if (vec == 0) { + /* + * Pre-allocate all the requested vectors. Remember + * the number of requested vectors such that we can + * deallocate them in one go. + */ + msi_mask = (1ULL << (1 << mme)) - 1; + while (vec <= sc->sc_num_msi - (1 << mme)) { + if ((sc->sc_msi_mask & (msi_mask << vec)) == 0) { + sc->sc_msi_mask |= (msi_mask << vec); + break; + } + vec += (1 << mme); + } + base = vec; + nvec = (1 << mme); + } else { + KASSERT(ihp->ih_type == PCI_MSI); + vec += base; + nvec = 0; + } + + if (vec >= sc->sc_num_msi) return NULL; + if (ihp->ih_type == PCI_MSI) { + if (reg & PCI_MSI_MC_C64) + pci_conf_write(pc, tag, off + PCI_MSI_MD64, base); + else + pci_conf_write(pc, tag, off + PCI_MSI_MD32, base); + } + + dm = &sc->sc_msi[vec]; + KASSERT(dm->dm_func == NULL); + dm->dm_func = func; dm->dm_arg = arg; dm->dm_ipl = level & IPL_IRQMASK; dm->dm_flags = level & IPL_FLAGMASK; dm->dm_vec = vec; + dm->dm_nvec = nvec; dm->dm_name = name; if (name != NULL) evcount_attach(&dm->dm_count, name, &dm->dm_vec); /* Unmask the MSI. */ - HCLR4(sc, PCIE_MSI_INTR0_MASK, (1U << vec)); + HCLR4(sc, PCIE_MSI_INTR_MASK(vec / 32), (1U << (vec % 32))); return dm; } @@ -1813,12 +1914,21 @@ dwpcie_msi_establish(struct dwpcie_softc *sc, int level, void dwpcie_msi_disestablish(struct dwpcie_softc *sc, struct dwpcie_msi *dm) { + uint64_t msi_mask = (1ULL << dm->dm_nvec) - 1; + /* Mask the MSI. */ - HSET4(sc, PCIE_MSI_INTR0_MASK, (1U << dm->dm_vec)); + HSET4(sc, PCIE_MSI_INTR_MASK(dm->dm_vec / 32), + (1U << (dm->dm_vec % 32))); if (dm->dm_name) evcount_detach(&dm->dm_count); dm->dm_func = NULL; + + /* + * Unallocate all allocated vetcors if this is the first + * vector for the device. + */ + sc->sc_msi_mask &= ~(msi_mask << dm->dm_vec); } void * @@ -1839,9 +1949,7 @@ dwpcie_intr_establish(void *v, pci_intr_handle_t ih, int level, uint64_t addr, data; if (sc->sc_msi_addr) { - if (ih.ih_type == PCI_MSI && ih.ih_intrpin > 0) - return NULL; - dm = dwpcie_msi_establish(sc, level, func, arg, name); + dm = dwpcie_msi_establish(sc, &ih, level, func, arg, name); if (dm == NULL) return NULL; addr = sc->sc_msi_addr; diff --git a/sys/dev/pci/if_iavf.c b/sys/dev/pci/if_iavf.c index 97d832123..afd6b09da 100644 --- a/sys/dev/pci/if_iavf.c +++ b/sys/dev/pci/if_iavf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iavf.c,v 1.13 2024/05/24 06:02:53 jsg Exp $ */ +/* $OpenBSD: if_iavf.c,v 1.14 2024/07/09 16:04:15 jmatthew Exp $ */ /* * Copyright (c) 2013-2015, Intel Corporation @@ -954,7 +954,7 @@ iavf_media_status(struct ifnet *ifp, struct ifmediareq *ifm) { struct iavf_softc *sc = ifp->if_softc; - NET_ASSERT_LOCKED(); + KERNEL_ASSERT_LOCKED(); ifm->ifm_status = sc->sc_media_status; ifm->ifm_active = sc->sc_media_active; diff --git a/sys/dev/vmm/vmm.h b/sys/dev/vmm/vmm.h index 47f5e12cf..3ec2d20fe 100644 --- a/sys/dev/vmm/vmm.h +++ b/sys/dev/vmm/vmm.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vmm.h,v 1.4 2024/01/11 17:13:48 jan Exp $ */ +/* $OpenBSD: vmm.h,v 1.5 2024/07/09 09:31:37 dv Exp $ */ /* * Copyright (c) 2014-2023 Mike Larkin * @@ -20,9 +20,19 @@ #include +#include + #ifndef DEV_VMM_H #define DEV_VMM_H +#define VMM_MAX_MEM_RANGES 16 +#define VMM_MAX_DISKS_PER_VM 4 +#define VMM_MAX_NAME_LEN 64 +#define VMM_MAX_VCPUS 512 +#define VMM_MAX_VCPUS_PER_VM 64 +#define VMM_MAX_VM_MEM_SIZE 128L * 1024 * 1024 * 1024 +#define VMM_MAX_NICS_PER_VM 4 + struct vm_mem_range { paddr_t vmr_gpa; vaddr_t vmr_va; @@ -83,6 +93,21 @@ struct vm_sharemem_params { struct vm_mem_range vsp_memranges[VMM_MAX_MEM_RANGES]; }; +struct vm_run_params { + /* Input parameters to VMM_IOC_RUN */ + uint32_t vrp_vm_id; + uint32_t vrp_vcpu_id; + struct vcpu_inject_event vrp_inject; + uint8_t vrp_intr_pending; /* Additional intrs pending? */ + + /* Input/output parameter to VMM_IOC_RUN */ + struct vm_exit *vrp_exit; /* updated exit data */ + + /* Output parameter from VMM_IOC_RUN */ + uint16_t vrp_exit_reason; /* exit reason */ + uint8_t vrp_irqready; /* ready for IRQ on entry */ +}; + /* IOCTL definitions */ #define VMM_IOC_CREATE _IOWR('V', 1, struct vm_create_params) /* Create VM */ #define VMM_IOC_RUN _IOWR('V', 2, struct vm_run_params) /* Run VCPU */ @@ -202,6 +227,7 @@ int vm_terminate(struct vm_terminate_params *); int vm_resetcpu(struct vm_resetcpu_params *); int vcpu_must_stop(struct vcpu *); int vm_share_mem(struct vm_sharemem_params *, struct proc *); +int vm_run(struct vm_run_params *); #ifdef VMM_DEBUG void dump_vcpu(struct vcpu *); diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c index c45d9a844..4b4cf75cc 100644 --- a/sys/kern/kern_resource.c +++ b/sys/kern/kern_resource.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_resource.c,v 1.85 2024/07/08 13:17:12 claudio Exp $ */ +/* $OpenBSD: kern_resource.c,v 1.86 2024/07/09 15:20:15 claudio Exp $ */ /* $NetBSD: kern_resource.c,v 1.38 1996/10/23 07:19:38 matthias Exp $ */ /*- @@ -432,7 +432,6 @@ void tuagg_add_process(struct process *pr, struct proc *p) { MUTEX_ASSERT_LOCKED(&pr->ps_mtx); - splassert(IPL_STATCLOCK); KASSERT(curproc == p || p->p_stat == SDEAD); tu_enter(&pr->ps_tu); diff --git a/sys/kern/kern_sched.c b/sys/kern/kern_sched.c index bb92ded02..4fe5b2e7e 100644 --- a/sys/kern/kern_sched.c +++ b/sys/kern/kern_sched.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sched.c,v 1.99 2024/07/08 16:15:42 mpi Exp $ */ +/* $OpenBSD: kern_sched.c,v 1.100 2024/07/09 08:44:36 claudio Exp $ */ /* * Copyright (c) 2007, 2008 Artur Grabowski * @@ -261,8 +261,9 @@ sched_toidle(void) idle->p_stat = SRUN; uvmexp.swtch++; - TRACEPOINT(sched, off__cpu, idle->p_tid + THREAD_PID_OFFSET, - idle->p_p->ps_pid); + if (curproc != NULL) + TRACEPOINT(sched, off__cpu, idle->p_tid + THREAD_PID_OFFSET, + idle->p_p->ps_pid); cpu_switchto(NULL, idle); panic("cpu_switchto returned"); } diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 7089d7446..422afa832 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sig.c,v 1.330 2024/06/03 12:48:25 claudio Exp $ */ +/* $OpenBSD: kern_sig.c,v 1.331 2024/07/09 09:22:50 claudio Exp $ */ /* $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $ */ /* @@ -1065,6 +1065,73 @@ ptsignal(struct proc *p, int signum, enum signal_type type) switch (p->p_stat) { + case SSTOP: + /* + * If traced process is already stopped, + * then no further action is necessary. + */ + if (pr->ps_flags & PS_TRACED) + goto out; + + /* + * Kill signal always sets processes running. + */ + if (signum == SIGKILL) { + atomic_clearbits_int(&p->p_flag, P_SUSPSIG); + goto runfast; + } + + if (prop & SA_CONT) { + /* + * If SIGCONT is default (or ignored), we continue the + * process but don't leave the signal in p_siglist, as + * it has no further action. If SIGCONT is held, we + * continue the process and leave the signal in + * p_siglist. If the process catches SIGCONT, let it + * handle the signal itself. If it isn't waiting on + * an event, then it goes back to run state. + * Otherwise, process goes back to sleep state. + */ + atomic_setbits_int(&p->p_flag, P_CONTINUED); + atomic_clearbits_int(&p->p_flag, P_SUSPSIG); + wakeparent = 1; + if (action == SIG_DFL) + mask = 0; + if (action == SIG_CATCH) + goto runfast; + if (p->p_wchan == NULL) + goto run; + atomic_clearbits_int(&p->p_flag, P_WSLEEP); + p->p_stat = SSLEEP; + goto out; + } + + /* + * Defer further processing for signals which are held, + * except that stopped processes must be continued by SIGCONT. + */ + if (action == SIG_HOLD) + goto out; + + if (prop & SA_STOP) { + /* + * Already stopped, don't need to stop again. + * (If we did the shell could get confused.) + */ + mask = 0; + goto out; + } + + /* + * If process is sleeping interruptibly, then simulate a + * wakeup so that when it is continued, it will be made + * runnable and can look at the signal. But don't make + * the process runnable, leave it stopped. + */ + if (p->p_flag & P_SINTR) + unsleep(p); + goto out; + case SSLEEP: /* * If process is sleeping uninterruptibly @@ -1143,73 +1210,6 @@ ptsignal(struct proc *p, int signum, enum signal_type type) goto runfast; /* NOTREACHED */ - case SSTOP: - /* - * If traced process is already stopped, - * then no further action is necessary. - */ - if (pr->ps_flags & PS_TRACED) - goto out; - - /* - * Kill signal always sets processes running. - */ - if (signum == SIGKILL) { - atomic_clearbits_int(&p->p_flag, P_SUSPSIG); - goto runfast; - } - - if (prop & SA_CONT) { - /* - * If SIGCONT is default (or ignored), we continue the - * process but don't leave the signal in p_siglist, as - * it has no further action. If SIGCONT is held, we - * continue the process and leave the signal in - * p_siglist. If the process catches SIGCONT, let it - * handle the signal itself. If it isn't waiting on - * an event, then it goes back to run state. - * Otherwise, process goes back to sleep state. - */ - atomic_setbits_int(&p->p_flag, P_CONTINUED); - atomic_clearbits_int(&p->p_flag, P_SUSPSIG); - wakeparent = 1; - if (action == SIG_DFL) - mask = 0; - if (action == SIG_CATCH) - goto runfast; - if (p->p_wchan == NULL) - goto run; - atomic_clearbits_int(&p->p_flag, P_WSLEEP); - p->p_stat = SSLEEP; - goto out; - } - - /* - * Defer further processing for signals which are held, - * except that stopped processes must be continued by SIGCONT. - */ - if (action == SIG_HOLD) - goto out; - - if (prop & SA_STOP) { - /* - * Already stopped, don't need to stop again. - * (If we did the shell could get confused.) - */ - mask = 0; - goto out; - } - - /* - * If process is sleeping interruptibly, then simulate a - * wakeup so that when it is continued, it will be made - * runnable and can look at the signal. But don't make - * the process runnable, leave it stopped. - */ - if (p->p_flag & P_SINTR) - unsleep(p); - goto out; - case SONPROC: if (action == SIG_HOLD) goto out; @@ -2160,8 +2160,12 @@ single_thread_set(struct proc *p, int flags) SCHED_LOCK(); atomic_setbits_int(&q->p_flag, P_SUSPSINGLE); switch (q->p_stat) { - case SIDL: - case SDEAD: + case SSTOP: + if (mode == SINGLE_EXIT) { + unsleep(q); + setrunnable(q); + } else + --pr->ps_singlecnt; break; case SSLEEP: /* if it's not interruptible, then just have to wait */ @@ -2177,17 +2181,12 @@ single_thread_set(struct proc *p, int flags) setrunnable(q); } break; - case SSTOP: - if (mode == SINGLE_EXIT) { - unsleep(q); - setrunnable(q); - } else - --pr->ps_singlecnt; - break; case SONPROC: signotify(q); - /* FALLTHROUGH */ + break; case SRUN: + case SIDL: + case SDEAD: break; } SCHED_UNLOCK(); diff --git a/sys/kern/sysv_sem.c b/sys/kern/sysv_sem.c index 88804fe2c..75861fadb 100644 --- a/sys/kern/sysv_sem.c +++ b/sys/kern/sysv_sem.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sysv_sem.c,v 1.63 2022/09/28 13:21:13 mbuhl Exp $ */ +/* $OpenBSD: sysv_sem.c,v 1.64 2024/07/09 04:42:48 jsg Exp $ */ /* $NetBSD: sysv_sem.c,v 1.26 1996/02/09 19:00:25 christos Exp $ */ /* @@ -564,7 +564,7 @@ sys_semop(struct proc *p, void *v, register_t *retval) sops = mallocarray(nsops, sizeof(struct sembuf), M_SEM, M_WAITOK); error = copyin(SCARG(uap, sops), sops, nsops * sizeof(struct sembuf)); if (error != 0) { - DPRINTF(("error = %d from copyin(%p, %p, %u)\n", error, + DPRINTF(("error = %d from copyin(%p, %p, %zu)\n", error, SCARG(uap, sops), &sops, nsops * sizeof(struct sembuf))); goto done2; } @@ -593,7 +593,7 @@ sys_semop(struct proc *p, void *v, register_t *retval) semptr = &semaptr->sem_base[sopptr->sem_num]; - DPRINTF(("semop: semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n", + DPRINTF(("semop: semaptr=%p, sem_base=%p, semptr=%p, sem[%d]=%d : op=%d, flag=%s\n", semaptr, semaptr->sem_base, semptr, sopptr->sem_num, semptr->semval, sopptr->sem_op, (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait")); @@ -634,7 +634,7 @@ sys_semop(struct proc *p, void *v, register_t *retval) /* * No ... rollback anything that we've already done */ - DPRINTF(("semop: rollback 0 through %d\n", i - 1)); + DPRINTF(("semop: rollback 0 through %zu\n", i - 1)); for (j = 0; j < i; j++) semaptr->sem_base[sops[j].sem_num].semval -= sops[j].sem_op; diff --git a/sys/lib/libz/zconf.h b/sys/lib/libz/zconf.h index 22475032d..1a3d41ebb 100644 --- a/sys/lib/libz/zconf.h +++ b/sys/lib/libz/zconf.h @@ -434,6 +434,9 @@ typedef uLong FAR uLongf; #ifdef _KERNEL # define Z_HAVE_UNISTD_H #endif +#ifdef _STANDALONE +# define z_off_t long +#endif #ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ # define Z_HAVE_UNISTD_H @@ -508,7 +511,7 @@ typedef uLong FAR uLongf; #endif #ifndef z_off_t -# define z_off_t long +# define z_off_t long long #endif #if !defined(_WIN32) && defined(Z_LARGE64) diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c index c706c32c5..14c295690 100644 --- a/sys/netinet6/ip6_forward.c +++ b/sys/netinet6/ip6_forward.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_forward.c,v 1.120 2024/07/04 12:50:08 bluhm Exp $ */ +/* $OpenBSD: ip6_forward.c,v 1.121 2024/07/09 09:33:13 bluhm Exp $ */ /* $KAME: ip6_forward.c,v 1.75 2001/06/29 12:42:13 jinmei Exp $ */ /* @@ -89,8 +89,16 @@ ip6_forward(struct mbuf *m, struct route *ro, int flags) struct rtentry *rt; struct sockaddr *dst; struct ifnet *ifp = NULL; - int error = 0, type = 0, code = 0, destmtu = 0; + u_int rtableid = m->m_pkthdr.ph_rtableid; + u_int ifidx = m->m_pkthdr.ph_ifidx; + u_int8_t loopcnt = m->m_pkthdr.ph_loopcnt; + u_int icmp_len; + char icmp_buf[MHLEN]; + CTASSERT(sizeof(struct ip6_hdr) + sizeof(struct tcphdr) + + MAX_TCPOPTLEN <= sizeof(icmp_buf)); + u_short mflags, pfflags; struct mbuf *mcopy; + int error = 0, type = 0, code = 0, destmtu = 0; #ifdef IPSEC struct tdb *tdb = NULL; #endif /* IPSEC */ @@ -117,9 +125,7 @@ ip6_forward(struct mbuf *m, struct route *ro, int flags) log(LOG_DEBUG, "cannot forward " "from %s to %s nxt %d received on interface %u\n", - src6, dst6, - ip6->ip6_nxt, - m->m_pkthdr.ph_ifidx); + src6, dst6, ip6->ip6_nxt, ifidx); } m_freem(m); goto done; @@ -137,12 +143,21 @@ ip6_forward(struct mbuf *m, struct route *ro, int flags) * size of IPv6 + ICMPv6 headers) bytes of the packet in case * we need to generate an ICMP6 message to the src. * Thanks to M_EXT, in most cases copy will not occur. + * For small packets copy original onto stack instead of mbuf. * * It is important to save it before IPsec processing as IPsec * processing may modify the mbuf. */ - mcopy = m_copym(m, 0, imin(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN), - M_NOWAIT); + icmp_len = min(m->m_pkthdr.len, ICMPV6_PLD_MAXLEN); + if (icmp_len <= sizeof(icmp_buf)) { + mflags = m->m_flags; + pfflags = m->m_pkthdr.pf.flags; + m_copydata(m, 0, icmp_len, icmp_buf); + mcopy = NULL; + } else { + mcopy = m_copym(m, 0, icmp_len, M_NOWAIT); + icmp_len = 0; + } #if NPF > 0 reroute: @@ -174,12 +189,10 @@ reroute: m->m_pkthdr.ph_rtableid); if (rt == NULL) { ip6stat_inc(ip6s_noroute); - if (mcopy != NULL) { - icmp6_error(mcopy, ICMP6_DST_UNREACH, - ICMP6_DST_UNREACH_NOROUTE, 0); - } + type = ICMP6_DST_UNREACH; + code = ICMP6_DST_UNREACH_NOROUTE; m_freem(m); - goto done; + goto icmperror; } dst = &ro->ro_dstsa; @@ -190,7 +203,7 @@ reroute: * unreachable error with Code 2 (beyond scope of source address). * [draft-ietf-ipngwg-icmp-v3-00.txt, Section 3.1] */ - if (in6_addr2scopeid(m->m_pkthdr.ph_ifidx, &ip6->ip6_src) != + if (in6_addr2scopeid(ifidx, &ip6->ip6_src) != in6_addr2scopeid(rt->rt_ifidx, &ip6->ip6_src)) { time_t uptime; @@ -205,15 +218,12 @@ reroute: log(LOG_DEBUG, "cannot forward " "src %s, dst %s, nxt %d, rcvif %u, outif %u\n", - src6, dst6, - ip6->ip6_nxt, - m->m_pkthdr.ph_ifidx, rt->rt_ifidx); + src6, dst6, ip6->ip6_nxt, ifidx, rt->rt_ifidx); } - if (mcopy != NULL) - icmp6_error(mcopy, ICMP6_DST_UNREACH, - ICMP6_DST_UNREACH_BEYONDSCOPE, 0); + type = ICMP6_DST_UNREACH; + code = ICMP6_DST_UNREACH_BEYONDSCOPE; m_freem(m); - goto done; + goto icmperror; } #ifdef IPSEC @@ -248,7 +258,7 @@ reroute: m_freem(m); goto freecopy; } - if (rt->rt_ifidx == m->m_pkthdr.ph_ifidx && + if (rt->rt_ifidx == ifidx && ip6_sendredirects && !ISSET(flags, IPV6_REDIRECT) && (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0) { if ((ifp->if_flags & IFF_POINTOPOINT) && @@ -268,11 +278,10 @@ reroute: * type/code is based on suggestion by Rich Draves. * not sure if it is the best pick. */ - if (mcopy != NULL) - icmp6_error(mcopy, ICMP6_DST_UNREACH, - ICMP6_DST_UNREACH_ADDR, 0); + type = ICMP6_DST_UNREACH; + code = ICMP6_DST_UNREACH_ADDR; m_freem(m); - goto done; + goto icmperror; } type = ND_REDIRECT; } @@ -332,27 +341,41 @@ reroute: if (error || m == NULL) goto senderr; - if (mcopy != NULL) - icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu); + type = ICMP6_PACKET_TOO_BIG; + destmtu = ifp->if_mtu; m_freem(m); - goto done; + goto icmperror; senderr: - if (mcopy == NULL) + if (mcopy == NULL && icmp_len == 0) goto done; switch (error) { case 0: if (type == ND_REDIRECT) { - icmp6_redirect_output(mcopy, rt); - ip6stat_inc(ip6s_redirectsent); + if (icmp_len != 0) { + mcopy = m_gethdr(M_DONTWAIT, MT_DATA); + if (mcopy == NULL) + goto done; + mcopy->m_len = mcopy->m_pkthdr.len = icmp_len; + mcopy->m_flags |= (mflags & M_COPYFLAGS); + mcopy->m_pkthdr.ph_rtableid = rtableid; + mcopy->m_pkthdr.ph_ifidx = ifidx; + mcopy->m_pkthdr.ph_loopcnt = loopcnt; + mcopy->m_pkthdr.pf.flags |= + (pfflags & PF_TAG_GENERATED); + memcpy(mcopy->m_data, icmp_buf, icmp_len); + } + if (mcopy != NULL) { + icmp6_redirect_output(mcopy, rt); + ip6stat_inc(ip6s_redirectsent); + } goto done; } goto freecopy; case EMSGSIZE: type = ICMP6_PACKET_TOO_BIG; - code = 0; if (rt != NULL) { if (rt->rt_mtu) { destmtu = rt->rt_mtu; @@ -390,7 +413,21 @@ senderr: code = ICMP6_DST_UNREACH_ADDR; break; } - icmp6_error(mcopy, type, code, destmtu); + icmperror: + if (icmp_len != 0) { + mcopy = m_gethdr(M_DONTWAIT, MT_DATA); + if (mcopy == NULL) + goto done; + mcopy->m_len = mcopy->m_pkthdr.len = icmp_len; + mcopy->m_flags |= (mflags & M_COPYFLAGS); + mcopy->m_pkthdr.ph_rtableid = rtableid; + mcopy->m_pkthdr.ph_ifidx = ifidx; + mcopy->m_pkthdr.ph_loopcnt = loopcnt; + mcopy->m_pkthdr.pf.flags |= (pfflags & PF_TAG_GENERATED); + memcpy(mcopy->m_data, icmp_buf, icmp_len); + } + if (mcopy != NULL) + icmp6_error(mcopy, type, code, destmtu); goto done; freecopy: diff --git a/usr.bin/mg/mg.1 b/usr.bin/mg/mg.1 index ca684157d..7afbd733b 100644 --- a/usr.bin/mg/mg.1 +++ b/usr.bin/mg/mg.1 @@ -1,7 +1,7 @@ -.\" $OpenBSD: mg.1,v 1.137 2024/06/04 06:48:34 op Exp $ +.\" $OpenBSD: mg.1,v 1.138 2024/07/09 14:51:37 op Exp $ .\" This file is in the public domain. .\" -.Dd $Mdocdate: June 4 2024 $ +.Dd $Mdocdate: July 9 2024 $ .Dt MG 1 .Os .Sh NAME @@ -938,8 +938,12 @@ Set the tab width for the current buffer, or the default for new buffers if called with a prefix argument or from the startup file. .It Ic shell-command Execute external command from mini-buffer. +With an universal argument it inserts the command output into the current +buffer. .It Ic shell-command-on-region Provide the text in region to the shell command as input. +With an universal argument it replaces the region with the command +output. .It Ic shrink-window Shrink current window by one line. The window immediately below is expanded to pick up the slack. diff --git a/usr.bin/mg/region.c b/usr.bin/mg/region.c index afed531eb..4f3cc0b82 100644 --- a/usr.bin/mg/region.c +++ b/usr.bin/mg/region.c @@ -1,4 +1,4 @@ -/* $OpenBSD: region.c,v 1.44 2023/03/28 14:47:28 op Exp $ */ +/* $OpenBSD: region.c,v 1.45 2024/07/09 14:46:17 op Exp $ */ /* This file is in the public domain. */ @@ -27,14 +27,13 @@ #define TIMEOUT 10000 -static char leftover[BUFSIZ]; - static int getregion(struct region *); -static int iomux(int, char * const, int, struct buffer *); -static int preadin(int, struct buffer *); +static int iomux(int, char * const, int); +static int preadin(int); static void pwriteout(int, char **, int *); static int setsize(struct region *, RSIZE); -static int shellcmdoutput(char * const, char * const, int); +static int shellcmdoutput(char * const, char * const, int, + struct buffer *); /* * Kill the region. Ask "getregion" to figure out the bounds of the region. @@ -413,13 +412,10 @@ int piperegion(int f, int n) { struct region region; + struct buffer *bp = NULL; int len; char *cmd, cmdbuf[NFILEN], *text; - /* C-u M-| is not supported yet */ - if (n > 1) - return (ABORT); - if (curwp->w_markp == NULL) { dobeep(); ewprintf("The mark is not set now, so there is no region"); @@ -443,7 +439,14 @@ piperegion(int f, int n) region_get_data(®ion, text, len); - return shellcmdoutput(cmd, text, len); + if (n > 1) { + bp = curbp; + undo_boundary_enable(FFRAND, 0); + killregion(FFRAND, 1); + kdelete(); + } + + return (shellcmdoutput(cmd, text, len, bp)); } /* @@ -452,33 +455,51 @@ piperegion(int f, int n) int shellcommand(int f, int n) { + struct buffer *bp = NULL; char *cmd, cmdbuf[NFILEN]; if (n > 1) - return (ABORT); + bp = curbp; if ((cmd = eread("Shell command: ", cmdbuf, sizeof(cmdbuf), EFNEW | EFCR)) == NULL || (cmd[0] == '\0')) return (ABORT); - return shellcmdoutput(cmd, NULL, 0); + return (shellcmdoutput(cmd, NULL, 0, bp)); } int -shellcmdoutput(char* const cmd, char* const text, int len) +shellcmdoutput(char* const cmd, char* const text, int len, + struct buffer *bp) { - struct buffer *bp; + struct mgwin *wp; + struct line *tlp; char *argv[] = {NULL, "-c", cmd, NULL}; char *shellp; - int ret; + int tbo, ret, special = 0; - bp = bfind("*Shell Command Output*", TRUE); - bp->b_flag |= BFREADONLY; - if (bclear(bp) != TRUE) { - free(text); + if (bp == NULL) { + special = 1; + bp = bfind("*Shell Command Output*", TRUE); + bp->b_flag &= ~BFREADONLY; /* disable read-only */ + wp = popbuf(bp, WNONE); + if (wp == NULL || bclear(bp) != TRUE) { + free(text); + return (FALSE); + } + curbp = bp; + curwp = wp; + } + + if (bp->b_flag & BFREADONLY) { + dobeep(); + ewprintf("Buffer is read-only"); return (FALSE); } + tlp = curwp->w_dotp; /* save current position */ + tbo = curwp->w_doto; + if ((shellp = getenv("SHELL")) == NULL) shellp = _PATH_BSHELL; @@ -488,14 +509,21 @@ shellcmdoutput(char* const cmd, char* const text, int len) argv[0] = shellp; ret = pipeio(shellp, argv, text, len, bp); - if (ret == TRUE) { eerase(); - if (lforw(bp->b_headp) == bp->b_headp) + if (special && lforw(bp->b_headp) == bp->b_headp) addline(bp, "(Shell command succeeded with no output)"); } free(text); + + if (special) { + bp->b_flag |= BFREADONLY; /* restore read-only */ + gotobob(0, 0); + } else { + curwp->w_dotp = tlp; /* return to old position */ + curwp->w_doto = tbo; + } return (ret); } @@ -540,7 +568,11 @@ pipeio(const char* const path, char* const argv[], char* const text, int len, default: /* Parent process */ close(s[1]); - ret = iomux(s[0], text, len, outbp); + + undo_boundary_enable(FFRAND, 0); + ret = iomux(s[0], text, len); + undo_boundary_enable(FFRAND, 1); + waitpid(pid, NULL, 0); /* Collect child to prevent zombies */ return (ret); @@ -553,7 +585,7 @@ pipeio(const char* const path, char* const argv[], char* const text, int len, * Poll on the fd for both read and write readiness. */ int -iomux(int fd, char* const text, int len, struct buffer *outbp) +iomux(int fd, char* const text, int len) { struct pollfd pfd[1]; int nfds; @@ -578,20 +610,13 @@ iomux(int fd, char* const text, int len, struct buffer *outbp) if (pfd[0].revents & POLLOUT && len > 0) pwriteout(fd, &textcopy, &len); else if (pfd[0].revents & POLLIN) - if (preadin(fd, outbp) == FALSE) + if (preadin(fd) == FALSE) break; if (len == 0 && pfd[0].events & POLLOUT) pfd[0].events = POLLIN; } close(fd); - /* In case if last line doesn't have a '\n' add the leftover - * characters to buffer. - */ - if (leftover[0] != '\0') { - addline(outbp, leftover); - leftover[0] = '\0'; - } if (nfds == 0) { dobeep(); ewprintf("poll timed out"); @@ -601,7 +626,7 @@ iomux(int fd, char* const text, int len, struct buffer *outbp) ewprintf("poll error"); return (FALSE); } - return (popbuftop(outbp, WNONE)); + return (TRUE); } /* @@ -630,42 +655,17 @@ pwriteout(int fd, char **text, int *len) } /* - * Read some data from socket fd, break on '\n' and add - * to buffer. If couldn't break on newline hold leftover - * characters and append in next iteration. + * Read some data from socket fd and add to buffer. */ int -preadin(int fd, struct buffer *bp) +preadin(int fd) { - int len; - char buf[BUFSIZ], *p, *q; + char buf[BUFSIZ]; + ssize_t len; - if ((len = read(fd, buf, BUFSIZ - 1)) <= 0) + if ((len = read(fd, buf, BUFSIZ)) <= 0) return (FALSE); - buf[len] = '\0'; - p = q = buf; - if (leftover[0] != '\0' && ((q = strchr(p, *bp->b_nlchr)) != NULL)) { - *q++ = '\0'; - if (strlcat(leftover, p, sizeof(leftover)) >= - sizeof(leftover)) { - dobeep(); - ewprintf("line too long"); - return (FALSE); - } - addline(bp, leftover); - leftover[0] = '\0'; - p = q; - } - while ((q = strchr(p, *bp->b_nlchr)) != NULL) { - *q++ = '\0'; - addline(bp, p); - p = q; - } - if (strlcpy(leftover, p, sizeof(leftover)) >= sizeof(leftover)) { - dobeep(); - ewprintf("line too long"); - return (FALSE); - } + region_put_data(buf, len); return (TRUE); } diff --git a/usr.bin/openssl/speed.c b/usr.bin/openssl/speed.c index 84ecb9b3b..f1916efe1 100644 --- a/usr.bin/openssl/speed.c +++ b/usr.bin/openssl/speed.c @@ -1,4 +1,4 @@ -/* $OpenBSD: speed.c,v 1.35 2024/07/01 18:52:22 deraadt Exp $ */ +/* $OpenBSD: speed.c,v 1.37 2024/07/09 11:21:44 deraadt Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -150,7 +150,7 @@ #include "./testrsa.h" #define BUFSIZE (1024*8+64) -volatile sig_atomic_t run = 0; +volatile sig_atomic_t run; static int mr = 0; static int usertime = 1; @@ -718,13 +718,11 @@ speed_main(int argc, char **argv) rsa_doit[R_RSA_1024] = 1; rsa_doit[R_RSA_2048] = 1; rsa_doit[R_RSA_4096] = 1; - } else - if (strcmp(*argv, "dsa") == 0) { + } else if (strcmp(*argv, "dsa") == 0) { dsa_doit[R_DSA_512] = 1; dsa_doit[R_DSA_1024] = 1; dsa_doit[R_DSA_2048] = 1; - } else - if (strcmp(*argv, "ecdsap160") == 0) + } else if (strcmp(*argv, "ecdsap160") == 0) ecdsa_doit[R_EC_P160] = 2; else if (strcmp(*argv, "ecdsap192") == 0) ecdsa_doit[R_EC_P192] = 2; @@ -739,8 +737,7 @@ speed_main(int argc, char **argv) else if (strcmp(*argv, "ecdsa") == 0) { for (i = 0; i < EC_NUM; i++) ecdsa_doit[i] = 1; - } else - if (strcmp(*argv, "ecdhp160") == 0) + } else if (strcmp(*argv, "ecdhp160") == 0) ecdh_doit[R_EC_P160] = 2; else if (strcmp(*argv, "ecdhp192") == 0) ecdh_doit[R_EC_P192] = 2; @@ -755,8 +752,7 @@ speed_main(int argc, char **argv) else if (strcmp(*argv, "ecdh") == 0) { for (i = 0; i < EC_NUM; i++) ecdh_doit[i] = 1; - } else - { + } else { BIO_printf(bio_err, "Error: bad option or value\n"); BIO_printf(bio_err, "\n"); BIO_printf(bio_err, "Available values:\n"); @@ -2041,8 +2037,7 @@ do_multi(int multi) rsa_results[k][1] = 1 / (1 / rsa_results[k][1] + 1 / d); else rsa_results[k][1] = d; - } - else if (!strncmp(buf, "+F3:", 4)) { + } else if (!strncmp(buf, "+F3:", 4)) { int k; double d; @@ -2062,8 +2057,7 @@ do_multi(int multi) dsa_results[k][1] = 1 / (1 / dsa_results[k][1] + 1 / d); else dsa_results[k][1] = d; - } - else if (!strncmp(buf, "+F4:", 4)) { + } else if (!strncmp(buf, "+F4:", 4)) { int k; double d; @@ -2083,9 +2077,7 @@ do_multi(int multi) ecdsa_results[k][1] = 1 / (1 / ecdsa_results[k][1] + 1 / d); else ecdsa_results[k][1] = d; - } - - else if (!strncmp(buf, "+F5:", 4)) { + } else if (!strncmp(buf, "+F5:", 4)) { int k; double d; @@ -2100,9 +2092,7 @@ do_multi(int multi) else ecdh_results[k][0] = d; - } - - else if (!strncmp(buf, "+H:", 3)) { + } else if (!strncmp(buf, "+H:", 3)) { } else fprintf(stderr, "Unknown type '%s' from child %d\n", buf, n); } diff --git a/usr.sbin/btrace/btrace.c b/usr.sbin/btrace/btrace.c index a66949cda..aa75a12f6 100644 --- a/usr.sbin/btrace/btrace.c +++ b/usr.sbin/btrace/btrace.c @@ -1,4 +1,4 @@ -/* $OpenBSD: btrace.c,v 1.91 2024/05/21 05:00:48 jsg Exp $ */ +/* $OpenBSD: btrace.c,v 1.92 2024/07/09 16:08:30 mpi Exp $ */ /* * Copyright (c) 2019 - 2023 Martin Pieuchot @@ -421,7 +421,7 @@ rules_do(int fd) ssize_t rlen; size_t i; - rlen = read(fd, devtbuf, sizeof(devtbuf) - 1); + rlen = read(fd, devtbuf, sizeof(devtbuf)); if (rlen == -1) { if (errno == EINTR && quit_pending) { printf("\n"); diff --git a/usr.sbin/radiusctl/Makefile b/usr.sbin/radiusctl/Makefile index 48cec71af..c83db4875 100644 --- a/usr.sbin/radiusctl/Makefile +++ b/usr.sbin/radiusctl/Makefile @@ -1,9 +1,10 @@ -# $OpenBSD: Makefile,v 1.3 2020/02/24 07:07:11 dlg Exp $ +# $OpenBSD: Makefile,v 1.4 2024/07/09 17:26:14 yasuoka Exp $ PROG= radiusctl -SRCS= radiusctl.c parser.c chap_ms.c +SRCS= radiusctl.c parser.c chap_ms.c json.c MAN= radiusctl.8 CFLAGS+= -Wall -Wextra -Wno-unused-parameter -LDADD+= -lradius -lcrypto -levent -DPADD+= ${LIBRADIUS} ${LIBCRYPTO} ${LIBEVENT} +CFLAGS+= -I${.CURDIR}/../radiusd +LDADD+= -lradius -lcrypto -levent -lutil +DPADD+= ${LIBRADIUS} ${LIBCRYPTO} ${LIBEVENT} ${LIBUTIL} .include diff --git a/usr.sbin/radiusctl/json.c b/usr.sbin/radiusctl/json.c new file mode 100644 index 000000000..1a653ac55 --- /dev/null +++ b/usr.sbin/radiusctl/json.c @@ -0,0 +1,324 @@ +/* $OpenBSD: json.c,v 1.1 2024/07/09 17:26:14 yasuoka Exp $ */ + +/* + * Copyright (c) 2020 Claudio Jeker + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "json.h" + +#define JSON_MAX_STACK 16 + +enum json_type { + NONE, + START, + ARRAY, + OBJECT +}; + +static struct json_stack { + const char *name; + unsigned int count; + int compact; + enum json_type type; +} stack[JSON_MAX_STACK]; + +static char indent[JSON_MAX_STACK + 1]; +static int level; +static int eb; +static FILE *jsonfh; + +static void +do_comma_indent(void) +{ + char sp = '\n'; + + if (stack[level].compact) + sp = ' '; + + if (stack[level].count++ > 0) { + if (!eb) + eb = fprintf(jsonfh, ",%c", sp) < 0; + } + + if (stack[level].compact) + return; + if (!eb) + eb = fprintf(jsonfh, "\t%.*s", level, indent) < 0; +} + +static void +do_name(const char *name) +{ + if (stack[level].type == ARRAY) + return; + if (!eb) + eb = fprintf(jsonfh, "\"%s\": ", name) < 0; +} + +static int +do_find(enum json_type type, const char *name) +{ + int i; + + for (i = level; i > 0; i--) + if (type == stack[i].type && + strcmp(name, stack[i].name) == 0) + return i; + + /* not found */ + return -1; +} + +void +json_do_start(FILE *fh) +{ + memset(indent, '\t', JSON_MAX_STACK); + memset(stack, 0, sizeof(stack)); + level = 0; + stack[level].type = START; + jsonfh = fh; + eb = 0; + + eb = fprintf(jsonfh, "{\n") < 0; +} + +int +json_do_finish(void) +{ + while (level > 0) + json_do_end(); + if (!eb) + eb = fprintf(jsonfh, "\n}\n") < 0; + + return -eb; +} + +void +json_do_array(const char *name) +{ + int i, l; + char sp = '\n'; + + if ((l = do_find(ARRAY, name)) > 0) { + /* array already in use, close element and move on */ + for (i = level - l; i > 0; i--) + json_do_end(); + return; + } + /* Do not stack arrays, while allowed this is not needed */ + if (stack[level].type == ARRAY) + json_do_end(); + + if (stack[level].compact) + sp = ' '; + do_comma_indent(); + do_name(name); + if (!eb) + eb = fprintf(jsonfh, "[%c", sp) < 0; + + if (++level >= JSON_MAX_STACK) + errx(1, "json stack too deep"); + + stack[level].name = name; + stack[level].type = ARRAY; + stack[level].count = 0; + /* inherit compact setting from above level */ + stack[level].compact = stack[level - 1].compact; +} + +void +json_do_object(const char *name, int compact) +{ + int i, l; + char sp = '\n'; + + if ((l = do_find(OBJECT, name)) > 0) { + /* roll back to that object and close it */ + for (i = level - l; i >= 0; i--) + json_do_end(); + } + + if (compact) + sp = ' '; + do_comma_indent(); + do_name(name); + if (!eb) + eb = fprintf(jsonfh, "{%c", sp) < 0; + + if (++level >= JSON_MAX_STACK) + errx(1, "json stack too deep"); + + stack[level].name = name; + stack[level].type = OBJECT; + stack[level].count = 0; + stack[level].compact = compact; +} + +void +json_do_end(void) +{ + char c; + + if (stack[level].type == ARRAY) + c = ']'; + else if (stack[level].type == OBJECT) + c = '}'; + else + errx(1, "json bad stack state"); + + if (!stack[level].compact) { + if (!eb) + eb = fprintf(jsonfh, "\n%.*s%c", level, indent, c) < 0; + } else { + if (!eb) + eb = fprintf(jsonfh, " %c", c) < 0; + } + + stack[level].name = NULL; + stack[level].type = NONE; + stack[level].count = 0; + stack[level].compact = 0; + + if (level-- <= 0) + errx(1, "json stack underflow"); + + stack[level].count++; +} + +void +json_do_printf(const char *name, const char *fmt, ...) +{ + va_list ap; + char *str; + + va_start(ap, fmt); + if (!eb) { + if (vasprintf(&str, fmt, ap) == -1) + errx(1, "json printf failed"); + json_do_string(name, str); + free(str); + } + va_end(ap); +} + +void +json_do_string(const char *name, const char *v) +{ + unsigned char c; + + do_comma_indent(); + do_name(name); + if (!eb) + eb = fprintf(jsonfh, "\"") < 0; + while ((c = *v++) != '\0' && !eb) { + /* skip escaping '/' since our use case does not require it */ + switch (c) { + case '"': + eb = fprintf(jsonfh, "\\\"") < 0; + break; + case '\\': + eb = fprintf(jsonfh, "\\\\") < 0; + break; + case '\b': + eb = fprintf(jsonfh, "\\b") < 0; + break; + case '\f': + eb = fprintf(jsonfh, "\\f") < 0; + break; + case '\n': + eb = fprintf(jsonfh, "\\n") < 0; + break; + case '\r': + eb = fprintf(jsonfh, "\\r") < 0; + break; + case '\t': + eb = fprintf(jsonfh, "\\t") < 0; + break; + default: + if (iscntrl(c)) + errx(1, "bad control character in string"); + eb = putc(c, jsonfh) == EOF; + break; + } + } + if (!eb) + eb = fprintf(jsonfh, "\"") < 0; +} + +void +json_do_hexdump(const char *name, void *buf, size_t len) +{ + uint8_t *data = buf; + size_t i; + + do_comma_indent(); + do_name(name); + if (!eb) + eb = fprintf(jsonfh, "\"") < 0; + for (i = 0; i < len; i++) + if (!eb) + eb = fprintf(jsonfh, "%02x", *(data + i)) < 0; + if (!eb) + eb = fprintf(jsonfh, "\"") < 0; +} + +void +json_do_bool(const char *name, int v) +{ + do_comma_indent(); + do_name(name); + if (v) { + if (!eb) + eb = fprintf(jsonfh, "true") < 0; + } else { + if (!eb) + eb = fprintf(jsonfh, "false") < 0; + } +} + +void +json_do_uint(const char *name, unsigned long long v) +{ + do_comma_indent(); + do_name(name); + if (!eb) + eb = fprintf(jsonfh, "%llu", v) < 0; +} + +void +json_do_int(const char *name, long long v) +{ + do_comma_indent(); + do_name(name); + if (!eb) + eb = fprintf(jsonfh, "%lld", v) < 0; +} + +void +json_do_double(const char *name, double v) +{ + do_comma_indent(); + do_name(name); + if (!eb) + eb = fprintf(jsonfh, "%f", v) < 0; +} diff --git a/usr.sbin/radiusctl/json.h b/usr.sbin/radiusctl/json.h new file mode 100644 index 000000000..2c134311d --- /dev/null +++ b/usr.sbin/radiusctl/json.h @@ -0,0 +1,34 @@ +/* $OpenBSD: json.h,v 1.1 2024/07/09 17:26:14 yasuoka Exp $ */ + +/* + * Copyright (c) 2020 Claudio Jeker + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +void json_do_start(FILE *); +int json_do_finish(void); +void json_do_array(const char *); +void json_do_object(const char *, int); +void json_do_end(void); +void json_do_printf(const char *, const char *, ...) + __attribute__((__format__ (printf, 2, 3))); +void json_do_string(const char *, const char *); +void json_do_hexdump(const char *, void *, size_t); +void json_do_bool(const char *, int); +void json_do_uint(const char *, unsigned long long); +void json_do_int(const char *, long long); +void json_do_double(const char *, double); diff --git a/usr.sbin/radiusctl/parser.c b/usr.sbin/radiusctl/parser.c index 3b97790c5..c43d7e42f 100644 --- a/usr.sbin/radiusctl/parser.c +++ b/usr.sbin/radiusctl/parser.c @@ -1,4 +1,4 @@ -/* $OpenBSD: parser.c,v 1.2 2020/02/24 07:07:11 dlg Exp $ */ +/* $OpenBSD: parser.c,v 1.3 2024/07/09 17:26:14 yasuoka Exp $ */ /* * Copyright (c) 2010 Reyk Floeter @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include "parser.h" @@ -40,6 +42,8 @@ enum token_type { TRIES, INTERVAL, MAXWAIT, + FLAGS, + SESSION_SEQ, ENDTOKEN }; @@ -67,9 +71,13 @@ static const struct token t_nas_port[]; static const struct token t_tries[]; static const struct token t_interval[]; static const struct token t_maxwait[]; +static const struct token t_ipcp[]; +static const struct token t_ipcp_flags[]; +static const struct token t_ipcp_session_seq[]; static const struct token t_main[] = { { KEYWORD, "test", TEST, t_test }, + { KEYWORD, "ipcp", NONE, t_ipcp }, { ENDTOKEN, "", NONE, NULL } }; @@ -135,6 +143,24 @@ static const struct token t_maxwait[] = { { ENDTOKEN, "", NONE, NULL } }; +static const struct token t_ipcp[] = { + { KEYWORD, "show", IPCP_SHOW, NULL }, + { KEYWORD, "dump", IPCP_DUMP, t_ipcp_flags }, + { KEYWORD, "monitor", IPCP_MONITOR, t_ipcp_flags }, + { KEYWORD, "disconnect", IPCP_DISCONNECT,t_ipcp_session_seq }, + { ENDTOKEN, "", NONE, NULL } +}; + +static const struct token t_ipcp_flags[] = { + { NOTOKEN, "", NONE, NULL }, + { FLAGS, "-json", FLAGS_JSON, NULL }, + { ENDTOKEN, "", NONE, NULL } +}; + +static const struct token t_ipcp_session_seq[] = { + { SESSION_SEQ, "", NONE, NULL }, + { ENDTOKEN, "", NONE, NULL } +}; static const struct token *match_token(char *, const struct token []); static void show_valid_args(const struct token []); @@ -182,6 +208,10 @@ match_token(char *word, const struct token table[]) const struct token *t = NULL; long long num; const char *errstr; + size_t wordlen = 0; + + if (word != NULL) + wordlen = strlen(word); for (i = 0; table[i].type != ENDTOKEN; i++) { switch (table[i].type) { @@ -193,7 +223,7 @@ match_token(char *word, const struct token table[]) break; case KEYWORD: if (word != NULL && strncmp(word, table[i].keyword, - strlen(word)) == 0) { + wordlen) == 0) { match++; t = &table[i]; if (t->value) @@ -317,7 +347,24 @@ match_token(char *word, const struct token table[]) res.maxwait.tv_sec = num; t = &table[i]; break; - + case FLAGS: + if (word != NULL && wordlen >= 2 && + strncmp(word, table[i].keyword, wordlen) == 0) { + match++; + t = &table[i]; + if (t->value) + res.flags |= t->value; + } + break; + case SESSION_SEQ: + if (word == NULL) + break; + match++; + res.session_seq = strtonum(word, 1, UINT_MAX, &errstr); + if (errstr != NULL) + printf("invalid argument: %s is %s for " + "\"session-id\"", word, errstr); + t = &table[i]; case ENDTOKEN: break; } @@ -383,6 +430,12 @@ show_valid_args(const struct token table[]) fprintf(stderr, " \n", TEST_MAXWAIT_MIN, TEST_MAXWAIT_MAX); break; + case FLAGS: + fprintf(stderr, " %s\n", table[i].keyword); + break; + case SESSION_SEQ: + fprintf(stderr, " \n"); + break; case ENDTOKEN: break; } diff --git a/usr.sbin/radiusctl/parser.h b/usr.sbin/radiusctl/parser.h index 6fd0a6c30..3f5e271bf 100644 --- a/usr.sbin/radiusctl/parser.h +++ b/usr.sbin/radiusctl/parser.h @@ -1,4 +1,4 @@ -/* $OpenBSD: parser.h,v 1.2 2020/02/24 07:07:11 dlg Exp $ */ +/* $OpenBSD: parser.h,v 1.3 2024/07/09 17:26:14 yasuoka Exp $ */ /* This file is derived from OpenBSD:src/usr.sbin/ikectl/parser.h 1.9 */ /* @@ -20,9 +20,16 @@ #ifndef _RADIUSCTL_PARSER_H #define _RADIUSCTL_PARSER_H +#include +#include + enum actions { NONE, - TEST + TEST, + IPCP_SHOW, + IPCP_DUMP, + IPCP_MONITOR, + IPCP_DISCONNECT }; enum auth_method { @@ -43,6 +50,8 @@ enum auth_method { #define TEST_MAXWAIT_MAX 60 #define TEST_MAXWAIT_DEFAULT 8 +#define FLAGS_JSON 0x01 + struct parse_result { enum actions action; const char *hostname; @@ -59,6 +68,9 @@ struct parse_result { struct timeval interval; /* overall process wait time for a reply */ struct timeval maxwait; + + unsigned flags; + unsigned session_seq; }; struct parse_result *parse(int, char *[]); diff --git a/usr.sbin/radiusctl/radiusctl.8 b/usr.sbin/radiusctl/radiusctl.8 index 9bebe4c9b..c9970aa6d 100644 --- a/usr.sbin/radiusctl/radiusctl.8 +++ b/usr.sbin/radiusctl/radiusctl.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: radiusctl.8,v 1.5 2020/02/25 06:57:36 jmc Exp $ +.\" $OpenBSD: radiusctl.8,v 1.6 2024/07/09 17:26:14 yasuoka Exp $ .\" .\" Copyright (c) YASUOKA Masahiko .\" @@ -15,7 +15,7 @@ .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" .\" -.Dd $Mdocdate: February 25 2020 $ +.Dd $Mdocdate: July 9 2024 $ .Dt RADIUSCTL 8 .Os .Sh NAME @@ -87,6 +87,46 @@ the default port number 1812 is used. Specifies the number of packets to try sending. The default is 3. .El +.It Cm ipcp show +Show all ipcp sessions in the database of +.Xr radiusd_ipcp 8 +briefly. +.It Cm ipcp dump Op Cm -json +Dump all ipcp sessions in the database of +.Xr radiusd_ipcp 8 . +When +.Cm -json +is specified, +.Nm +shows the sessions in JSON format. +.It Cm ipcp monitor Op Cm -json +Monitor the database of +.Xr radiusd_ipcp 8 , +show newly created sessions and deleted sessions. +When +.Cm -json +is specified, +.Nm +shows the sessions in JSON format. +.It Cm ipcp disconnect Ar sequence +Request to disconnect the session specfied by the +.Ar sequence . +.Xc .El +.Sh EXAMPLES +.Bd -literal -offset indent +(show all sessions) +$ doas radiusctl ipcp show +Seq Assigned Username Start Tunnel From +--- --------------- ---------------------- -------- ------------------------- + 21 192.168.1.99 mifune@example.jp 11:35AM 203.0.113.32:34859 + 22 192.168.1.103 nakadai@example.jp 11:56AM 192.0.2.4:61794 +$ + +(disconnect Nakadai's session) +$ doas radiusctl ipcp disconnect 22 +$ +.Ed .Sh SEE ALSO -.Xr radiusd 8 +.Xr radiusd 8 , +.Xr radiusd_ipcp 8 diff --git a/usr.sbin/radiusctl/radiusctl.c b/usr.sbin/radiusctl/radiusctl.c index ed6e5cded..8c46815c0 100644 --- a/usr.sbin/radiusctl/radiusctl.c +++ b/usr.sbin/radiusctl/radiusctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: radiusctl.c,v 1.8 2020/02/24 07:07:11 dlg Exp $ */ +/* $OpenBSD: radiusctl.c,v 1.9 2024/07/09 17:26:14 yasuoka Exp $ */ /* * Copyright (c) 2015 YASUOKA Masahiko * @@ -15,33 +15,73 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include +#include #include +#include +#include +#include #include - #include -#include + #include +#include +#include +#include +#include #include #include +#include #include +#include +#include #include #include #include +#include +#include #include -#include - -#include - #include "parser.h" +#include "radiusd.h" +#include "radiusd_ipcp.h" #include "chap_ms.h" +#include "json.h" +#ifndef MAXIMUM +#define MAXIMUM(_a, _b) (((_a) > (_b))? (_a) : (_b)) +#endif -static int radius_test (struct parse_result *); -static void radius_dump (FILE *, RADIUS_PACKET *, bool, +static int radius_test(struct parse_result *); +static void radius_dump(FILE *, RADIUS_PACKET *, bool, const char *); -static const char *radius_code_str (int code); + +static int ipcp_handle_imsg(struct parse_result *, struct imsg *, + int); +static void ipcp_handle_show(struct radiusd_ipcp_db_dump *, + size_t, int); +static void ipcp_handle_dumps(struct radiusd_ipcp_db_dump *, + size_t, int); +static void ipcp_handle_dump(struct radiusd_ipcp_db_dump *, + size_t, int); +static void ipcp_handle_dump0(struct radiusd_ipcp_db_dump *, + size_t, struct timespec *, struct timespec *, + struct timespec *, int); +static void ipcp_handle_stat(struct radiusd_ipcp_statistics *); +static void ipcp_handle_jsons(struct radiusd_ipcp_db_dump *, + size_t, int); +static void ipcp_handle_json(struct radiusd_ipcp_db_dump *, + size_t, struct radiusd_ipcp_statistics *, int); +static void ipcp_handle_json0(struct radiusd_ipcp_db_dump *, + size_t, struct timespec *, struct timespec *, + struct timespec *, int); + +static const char *radius_code_str(int code); static const char *hexstr(const u_char *, int, char *, int); +static const char *sockaddr_str(struct sockaddr *, char *, size_t); +static const char *time_long_str(struct timespec *, char *, size_t); +static const char *time_short_str(struct timespec *, struct timespec *, + char *, size_t); +static const char *humanize_seconds(long, char *, size_t); static void usage(void) @@ -54,9 +94,15 @@ usage(void) int main(int argc, char *argv[]) { - int ch; - struct parse_result *result; - int ecode = EXIT_SUCCESS; + int ch, sock, done = 0; + ssize_t n; + struct parse_result *res; + struct sockaddr_un sun; + struct imsgbuf ibuf; + struct imsg imsg; + struct iovec iov[5]; + int niov = 0, cnt = 0; + char module_name[RADIUSD_MODULE_NAME_LEN + 1]; while ((ch = getopt(argc, argv, "")) != -1) switch (ch) { @@ -67,22 +113,112 @@ main(int argc, char *argv[]) argc -= optind; argv += optind; - if ((result = parse(argc, argv)) == NULL) - return (EXIT_FAILURE); + if (unveil(RADIUSD_SOCK, "rw") == -1) + err(EX_OSERR, "unveil"); + if (pledge("stdio unix rpath dns inet", NULL) == -1) + err(EX_OSERR, "pledge"); - switch (result->action) { + res = parse(argc, argv); + if (res == NULL) + exit(EX_USAGE); + + switch (res->action) { + default: + break; case NONE: + exit(EXIT_SUCCESS); break; case TEST: if (pledge("stdio dns inet", NULL) == -1) err(EXIT_FAILURE, "pledge"); - ecode = radius_test(result); + exit(radius_test(res)); break; } - return (ecode); + if (pledge("stdio unix rpath", NULL) == -1) + err(EX_OSERR, "pledge"); + + memset(&sun, 0, sizeof(sun)); + sun.sun_family = AF_UNIX; + sun.sun_len = sizeof(sun); + strlcpy(sun.sun_path, RADIUSD_SOCK, sizeof(sun.sun_path)); + + if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + err(EX_OSERR, "socket"); + if (connect(sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) + err(EX_OSERR, "connect"); + imsg_init(&ibuf, sock); + + res = parse(argc, argv); + if (res == NULL) + exit(EX_USAGE); + + switch (res->action) { + case TEST: + case NONE: + abort(); + break; + case IPCP_SHOW: + case IPCP_DUMP: + case IPCP_MONITOR: + memset(module_name, 0, sizeof(module_name)); + strlcpy(module_name, "ipcp", + sizeof(module_name)); + iov[niov].iov_base = module_name; + iov[niov++].iov_len = RADIUSD_MODULE_NAME_LEN; + imsg_composev(&ibuf, (res->action == IPCP_MONITOR)? + IMSG_RADIUSD_MODULE_IPCP_MONITOR : + IMSG_RADIUSD_MODULE_IPCP_DUMP, 0, 0, -1, iov, niov); + break; + case IPCP_DISCONNECT: + memset(module_name, 0, sizeof(module_name)); + strlcpy(module_name, "ipcp", + sizeof(module_name)); + iov[niov].iov_base = module_name; + iov[niov++].iov_len = RADIUSD_MODULE_NAME_LEN; + iov[niov].iov_base = &res->session_seq; + iov[niov++].iov_len = sizeof(res->session_seq); + imsg_composev(&ibuf, IMSG_RADIUSD_MODULE_IPCP_DISCONNECT, 0, 0, + -1, iov, niov); + done = 1; + break; + } + while (ibuf.w.queued) { + if (msgbuf_write(&ibuf.w) <= 0 && errno != EAGAIN) + err(1, "ibuf_ctl: msgbuf_write error"); + } + while (!done) { + if (((n = imsg_read(&ibuf)) == -1 && errno != EAGAIN) || n == 0) + break; + for (;;) { + if ((n = imsg_get(&ibuf, &imsg)) <= 0) { + if (n != 0) + done = 1; + break; + } + switch (res->action) { + case IPCP_SHOW: + case IPCP_DUMP: + case IPCP_MONITOR: + done = ipcp_handle_imsg(res, &imsg, cnt++); + break; + default: + break; + } + imsg_free(&imsg); + if (done) + break; + + } + } + close(sock); + + exit(EXIT_SUCCESS); } +/*********************************************************************** + * "test" + ***********************************************************************/ struct radius_test { const struct parse_result *res; int ecode; @@ -443,7 +579,6 @@ radius_dump(FILE *out, RADIUS_PACKET *pkt, bool resp, const char *secret) fprintf(out, " MS-MPPE-Encryption-Policy = 0x%08x\n", ntohl(*(u_long *)buf)); - memset(buf, 0, sizeof(buf)); len = sizeof(buf); if (radius_get_vs_raw_attr(pkt, RADIUS_VENDOR_MICROSOFT, @@ -476,7 +611,315 @@ radius_dump(FILE *out, RADIUS_PACKET *pkt, bool resp, const char *secret) } -static const char * +/*********************************************************************** + * ipcp + ***********************************************************************/ +int +ipcp_handle_imsg(struct parse_result *res, struct imsg *imsg, int cnt) +{ + ssize_t datalen; + struct radiusd_ipcp_db_dump *dump; + struct radiusd_ipcp_statistics *stat; + int done = 0; + + datalen = imsg->hdr.len - IMSG_HEADER_SIZE; + switch (imsg->hdr.type) { + case IMSG_NG: + if (datalen > 0 && *((char *)imsg->data + datalen - 1) == '\0') + fprintf(stderr, "error: %s\n", (char *)imsg->data); + else + fprintf(stderr, "error\n"); + exit(EXIT_FAILURE); + case IMSG_RADIUSD_MODULE_IPCP_DUMP: + if ((size_t)datalen < sizeof(struct + radiusd_ipcp_db_dump)) + errx(1, "received a message which size is invalid"); + dump = imsg->data; + if (res->action == IPCP_SHOW) + ipcp_handle_show(dump, datalen, (cnt++ == 0)? 1 : 0); + else { + if (res->flags & FLAGS_JSON) + ipcp_handle_jsons(dump, datalen, + (cnt++ == 0)? 1 : 0); + else + ipcp_handle_dumps(dump, datalen, + (cnt++ == 0)? 1 : 0); + } + if (dump->islast && + (res->action == IPCP_SHOW || res->action == IPCP_DUMP)) + done = 1; + break; + case IMSG_RADIUSD_MODULE_IPCP_START: + if ((size_t)datalen < offsetof(struct + radiusd_ipcp_db_dump, records[1])) + errx(1, "received a message which size is invalid"); + dump = imsg->data; + if (res->flags & FLAGS_JSON) + ipcp_handle_json(dump, datalen, NULL, 0); + else { + printf("Start\n"); + ipcp_handle_dump(dump, datalen, 0); + } + break; + case IMSG_RADIUSD_MODULE_IPCP_STOP: + if ((size_t)datalen < offsetof( + struct radiusd_ipcp_db_dump, + records[1]) + + sizeof(struct + radiusd_ipcp_statistics)) + errx(1, "received a message which size is invalid"); + dump = imsg->data; + stat = (struct radiusd_ipcp_statistics *) + ((char *)imsg->data + offsetof( + struct radiusd_ipcp_db_dump, records[1])); + if (res->flags & FLAGS_JSON) + ipcp_handle_json(dump, datalen, stat, 0); + else { + printf("Stop\n"); + ipcp_handle_dump(dump, datalen, 0); + ipcp_handle_stat(stat); + } + break; + } + + return (done); +} + +static void +ipcp_handle_show(struct radiusd_ipcp_db_dump *dump, size_t dumpsiz, int first) +{ + int i, width; + uint32_t maxseq = 999; + char buf0[128], buf1[NI_MAXHOST + NI_MAXSERV + 4], buf2[80]; + struct timespec upt, now, dif, start; + + clock_gettime(CLOCK_BOOTTIME, &upt); + clock_gettime(CLOCK_REALTIME, &now); + timespecsub(&now, &upt, &upt); + + for (i = 0; ; i++) { + if (offsetof(struct radiusd_ipcp_db_dump, records[i]) + >= dumpsiz) + break; + maxseq = MAXIMUM(maxseq, dump->records[i].rec.seq); + } + for (width = 0; maxseq != 0; maxseq /= 10, width++) + ; + + for (i = 0; ; i++) { + if (offsetof(struct radiusd_ipcp_db_dump, records[i]) + >= dumpsiz) + break; + if (i == 0 && first) + printf("%-*s Assigned Username " + "Start Tunnel From\n" + "%.*s --------------- ---------------------- " + "-------- %.*s\n", width, "Seq", width, + "----------", 28 - width, + "-------------------------"); + timespecadd(&upt, &dump->records[i].rec.start, &start); + timespecsub(&now, &start, &dif); + printf("%*d %-15s %-22s %-8s %s\n", + width, dump->records[i].rec.seq, + inet_ntop(dump->records[i].af, &dump->records[i].addr, + buf0, sizeof(buf0)), dump->records[i].rec.username, + time_short_str(&start, &dif, buf2, sizeof(buf2)), + sockaddr_str( + (struct sockaddr *)&dump->records[i].rec.tun_client, buf1, + sizeof(buf1))); + } +} +static void +ipcp_handle_dump(struct radiusd_ipcp_db_dump *dump, size_t dumpsiz, int idx) +{ + struct timespec upt, now, dif, start, timeout; + + clock_gettime(CLOCK_BOOTTIME, &upt); + clock_gettime(CLOCK_REALTIME, &now); + timespecsub(&now, &upt, &upt); + + timespecadd(&upt, &dump->records[idx].rec.start, &start); + timespecsub(&now, &start, &dif); + + if (dump->records[idx].rec.start.tv_sec == 0) + ipcp_handle_dump0(dump, dumpsiz, &dif, &start, NULL, idx); + else { + timespecadd(&upt, &dump->records[idx].rec.timeout, &timeout); + ipcp_handle_dump0(dump, dumpsiz, &dif, &start, &timeout, idx); + } +} + +static void +ipcp_handle_dump0(struct radiusd_ipcp_db_dump *dump, size_t dumpsiz, + struct timespec *dif, struct timespec *start, struct timespec *timeout, + int idx) +{ + char buf0[128], buf1[NI_MAXHOST + NI_MAXSERV + 4], buf2[80]; + + printf( + " Sequence Number : %u\n" + " Session Id : %s\n" + " Username : %s\n" + " Auth Method : %s\n" + " Assigned IP Address : %s\n" + " Start Time : %s\n" + " Elapsed Time : %lld second%s%s\n", + dump->records[idx].rec.seq, dump->records[idx].rec.session_id, + dump->records[idx].rec.username, dump->records[idx].rec.auth_method, + inet_ntop(dump->records[idx].af, &dump->records[idx].addr, buf0, + sizeof(buf0)), time_long_str(start, buf1, sizeof(buf1)), + (long long)dif->tv_sec, (dif->tv_sec == 0)? "" : "s", + humanize_seconds(dif->tv_sec, buf2, sizeof(buf2))); + if (timeout != NULL) + printf(" Timeout : %s\n", + time_long_str(timeout, buf0, sizeof(buf0))); + printf( + " NAS Identifier : %s\n" + " Tunnel Type : %s\n" + " Tunnel From : %s\n", + dump->records[idx].rec.nas_id, dump->records[idx].rec.tun_type, + sockaddr_str((struct sockaddr *) + &dump->records[idx].rec.tun_client, buf1, sizeof(buf1))); +} + +void +ipcp_handle_stat(struct radiusd_ipcp_statistics *stat) +{ + printf( + " Terminate Cause : %s\n" + " Input Packets : %"PRIu32"\n" + " Output Packets : %"PRIu32"\n" + " Input Bytes : %"PRIu64"\n" + " Output Bytes : %"PRIu64"\n", + stat->cause, stat->ipackets, stat->opackets, stat->ibytes, + stat->obytes); +} + +static void +ipcp_handle_jsons(struct radiusd_ipcp_db_dump *dump, size_t dumpsiz, int first) +{ + int i; + struct timespec upt, now, dif, start, timeout; + + clock_gettime(CLOCK_BOOTTIME, &upt); + clock_gettime(CLOCK_REALTIME, &now); + timespecsub(&now, &upt, &upt); + + for (i = 0; ; i++) { + if (offsetof(struct radiusd_ipcp_db_dump, records[i]) + >= dumpsiz) + break; + timespecadd(&upt, &dump->records[i].rec.start, &start); + timespecsub(&now, &start, &dif); + json_do_start(stdout); + json_do_string("action", "start"); + if (dump->records[i].rec.timeout.tv_sec == 0) + ipcp_handle_json0(dump, dumpsiz, &dif, &start, NULL, i); + else { + timespecadd(&upt, &dump->records[i].rec.timeout, + &timeout); + ipcp_handle_json0(dump, dumpsiz, &dif, &start, &timeout, + i); + } + json_do_finish(); + } + fflush(stdout); +} + +static void +ipcp_handle_json(struct radiusd_ipcp_db_dump *dump, size_t dumpsiz, + struct radiusd_ipcp_statistics *stat, int idx) +{ + struct timespec upt, now, dif, start, timeout; + + json_do_start(stdout); + clock_gettime(CLOCK_BOOTTIME, &upt); + clock_gettime(CLOCK_REALTIME, &now); + timespecsub(&now, &upt, &upt); + timespecadd(&upt, &dump->records[idx].rec.start, &start); + timespecsub(&now, &start, &dif); + + if (stat == NULL) + json_do_string("action", "start"); + else + json_do_string("action", "stop"); + if (dump->records[idx].rec.timeout.tv_sec == 0) + ipcp_handle_json0(dump, dumpsiz, &dif, &start, NULL, idx); + else { + timespecadd(&upt, &dump->records[idx].rec.timeout, &timeout); + ipcp_handle_json0(dump, dumpsiz, &dif, &start, &timeout, idx); + } + if (stat != NULL) { + json_do_string("terminate-cause", stat->cause); + json_do_uint("input-packets", stat->ipackets); + json_do_uint("output-packets", stat->opackets); + json_do_uint("input-bytes", stat->ibytes); + json_do_uint("output-bytes", stat->obytes); + } + json_do_finish(); + fflush(stdout); +} + +static void +ipcp_handle_json0(struct radiusd_ipcp_db_dump *dump, size_t dumpsiz, + struct timespec *dif, struct timespec *start, struct timespec *timeout, + int idx) +{ + char buf[128]; + + json_do_uint("sequence-number", dump->records[idx].rec.seq); + json_do_string("session-id", dump->records[idx].rec.session_id); + json_do_string("username", dump->records[idx].rec.username); + json_do_string("auth-method", dump->records[idx].rec.auth_method); + json_do_string("assigned-ip-address", inet_ntop(dump->records[idx].af, + &dump->records[idx].addr, buf, sizeof(buf))); + json_do_uint("start", start->tv_sec); + json_do_uint("elapsed", dif->tv_sec); + if (timeout != NULL) + json_do_uint("timeout", timeout->tv_sec); + json_do_string("nas-identifier", dump->records[idx].rec.nas_id); + json_do_string("tunnel-type", dump->records[idx].rec.tun_type); + json_do_string("tunnel-from", + sockaddr_str((struct sockaddr *)&dump->records[idx].rec.tun_client, + buf, sizeof(buf))); +} + +static void +ipcp_handle_dumps(struct radiusd_ipcp_db_dump *dump, size_t dumpsiz, int first) +{ + static int cnt = 0; + int i; + struct timespec upt, now, dif, start, timeout; + + clock_gettime(CLOCK_BOOTTIME, &upt); + clock_gettime(CLOCK_REALTIME, &now); + timespecsub(&now, &upt, &upt); + + if (first) + cnt = 0; + for (i = 0; ; i++, cnt++) { + if (offsetof(struct radiusd_ipcp_db_dump, records[i]) + >= dumpsiz) + break; + timespecadd(&upt, &dump->records[i].rec.start, &start); + timespecsub(&now, &start, &dif); + printf("#%d\n", cnt + 1); + if (dump->records[i].rec.timeout.tv_sec == 0) + ipcp_handle_dump0(dump, dumpsiz, &dif, &start, NULL, i); + else { + timespecadd(&upt, &dump->records[i].rec.timeout, + &timeout); + ipcp_handle_dump0(dump, dumpsiz, &dif, &start, + &timeout, i); + } + } +} + + +/*********************************************************************** + * Miscellaneous functions + ***********************************************************************/ +const char * radius_code_str(int code) { int i; @@ -523,3 +966,90 @@ hexstr(const u_char *data, int len, char *str, int strsiz) return (str); } + +const char * +sockaddr_str(struct sockaddr *sa, char *buf, size_t bufsiz) +{ + int noport, ret; + char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; + + if (ntohs(((struct sockaddr_in *)sa)->sin_port) == 0) { + noport = 1; + ret = getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0, + NI_NUMERICHOST); + } else { + noport = 0; + ret = getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), sbuf, + sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV); + } + if (ret != 0) + return ""; + if (noport) + strlcpy(buf, hbuf, bufsiz); + else if (sa->sa_family == AF_INET6) + snprintf(buf, bufsiz, "[%s]:%s", hbuf, sbuf); + else + snprintf(buf, bufsiz, "%s:%s", hbuf, sbuf); + + return (buf); +} + +const char * +time_long_str(struct timespec *tim, char *buf, size_t bufsiz) +{ + struct tm tm; + + localtime_r(&tim->tv_sec, &tm); + strftime(buf, bufsiz, "%F %T", &tm); + + return (buf); +} + +const char * +time_short_str(struct timespec *tim, struct timespec *dif, char *buf, + size_t bufsiz) +{ + struct tm tm; + + localtime_r(&tim->tv_sec, &tm); + if (dif->tv_sec < 12 * 60 * 60) + strftime(buf, bufsiz, "%l:%M%p", &tm); + else if (dif->tv_sec < 7 * 24 * 60 * 60) + strftime(buf, bufsiz, "%e%b%y", &tm); + else + strftime(buf, bufsiz, "%m/%d", &tm); + + return (buf); +} + +const char * +humanize_seconds(long seconds, char *buf, size_t bufsiz) +{ + char fbuf[80]; + int hour, min; + + hour = seconds / 3600; + min = (seconds % 3600) / 60; + + if (bufsiz == 0) + return NULL; + buf[0] = '\0'; + if (hour != 0 || min != 0) { + strlcat(buf, " (", bufsiz); + if (hour != 0) { + snprintf(fbuf, sizeof(fbuf), "%d hour%s", hour, + (hour == 1)? "" : "s"); + strlcat(buf, fbuf, bufsiz); + } + if (hour != 0 && min != 0) + strlcat(buf, " and ", bufsiz); + if (min != 0) { + snprintf(fbuf, sizeof(fbuf), "%d minute%s", min, + (min == 1)? "" : "s"); + strlcat(buf, fbuf, bufsiz); + } + strlcat(buf, ")", bufsiz); + } + + return (buf); +} diff --git a/usr.sbin/radiusd/Makefile b/usr.sbin/radiusd/Makefile index 437b7e28d..61ba31825 100644 --- a/usr.sbin/radiusd/Makefile +++ b/usr.sbin/radiusd/Makefile @@ -1,7 +1,8 @@ -# $OpenBSD: Makefile,v 1.3 2024/07/02 16:18:11 deraadt Exp $ +# $OpenBSD: Makefile,v 1.4 2024/07/09 17:26:14 yasuoka Exp $ SUBDIR= radiusd SUBDIR+= radiusd_bsdauth +SUBDIR+= radiusd_ipcp SUBDIR+= radiusd_radius SUBDIR+= radiusd_standard diff --git a/usr.sbin/radiusd/control.c b/usr.sbin/radiusd/control.c new file mode 100644 index 000000000..45c243afe --- /dev/null +++ b/usr.sbin/radiusd/control.c @@ -0,0 +1,337 @@ +/* $OpenBSD: control.c,v 1.1 2024/07/09 17:26:14 yasuoka Exp $ */ + +/* + * Copyright (c) 2003, 2004 Henning Brauer + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "radiusd.h" +#include "radiusd_local.h" +#include "log.h" +#include "control.h" + +static TAILQ_HEAD(, ctl_conn) ctl_conns = TAILQ_HEAD_INITIALIZER(ctl_conns); + +#define CONTROL_BACKLOG 5 +static int idseq = 0; + +struct ctl_conn *control_connbyfd(int); +struct ctl_conn *control_connbyid(uint32_t); +void control_close(int); +void control_connfree(struct ctl_conn *); +void control_event_add(struct ctl_conn *); + +struct { + struct event ev; + struct event evt; + int fd; +} control_state; + +int +control_init(const char *path) +{ + struct sockaddr_un sun; + int fd; + mode_t old_umask; + + if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, + 0)) == -1) { + log_warn("control_init: socket"); + return (-1); + } + + memset(&sun, 0, sizeof(sun)); + sun.sun_family = AF_UNIX; + strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); + + if (unlink(path) == -1) + if (errno != ENOENT) { + log_warn("control_init: unlink %s", path); + close(fd); + return (-1); + } + + old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); + if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) { + log_warn("control_init: bind: %s", path); + close(fd); + umask(old_umask); + return (-1); + } + umask(old_umask); + + if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) { + log_warn("control_init: chmod"); + close(fd); + (void)unlink(path); + return (-1); + } + + control_state.fd = fd; + + return (0); +} + +int +control_listen(void) +{ + + if (listen(control_state.fd, CONTROL_BACKLOG) == -1) { + log_warn("control_listen: listen"); + return (-1); + } + + event_set(&control_state.ev, control_state.fd, EV_READ, + control_accept, NULL); + event_add(&control_state.ev, NULL); + evtimer_set(&control_state.evt, control_accept, NULL); + + return (0); +} + +void +control_cleanup(void) +{ + struct ctl_conn *c, *t; + + TAILQ_FOREACH_SAFE(c, &ctl_conns, entry, t) { + TAILQ_REMOVE(&ctl_conns, c, entry); + control_connfree(c); + } + event_del(&control_state.ev); + event_del(&control_state.evt); +} + +/* ARGSUSED */ +void +control_accept(int listenfd, short event, void *bula) +{ + int connfd; + socklen_t len; + struct sockaddr_un sun; + struct ctl_conn *c; + + event_add(&control_state.ev, NULL); + if ((event & EV_TIMEOUT)) + return; + + len = sizeof(sun); + if ((connfd = accept4(listenfd, (struct sockaddr *)&sun, &len, + SOCK_CLOEXEC | SOCK_NONBLOCK)) == -1) { + /* + * Pause accept if we are out of file descriptors, or + * libevent will haunt us here too. + */ + if (errno == ENFILE || errno == EMFILE) { + struct timeval evtpause = { 1, 0 }; + + event_del(&control_state.ev); + evtimer_add(&control_state.evt, &evtpause); + } else if (errno != EWOULDBLOCK && errno != EINTR && + errno != ECONNABORTED) + log_warn("control_accept: accept"); + return; + } + + if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { + log_warn("control_accept"); + close(connfd); + return; + } + + if (idseq == 0) /* don't use zero. See radiusd_module_imsg */ + ++idseq; + c->id = idseq++; + imsg_init(&c->iev.ibuf, connfd); + c->iev.handler = control_dispatch_imsg; + c->iev.events = EV_READ; + event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events, c->iev.handler, c); + event_add(&c->iev.ev, NULL); + + TAILQ_INSERT_TAIL(&ctl_conns, c, entry); +} + +struct ctl_conn * +control_connbyfd(int fd) +{ + struct ctl_conn *c; + + TAILQ_FOREACH(c, &ctl_conns, entry) { + if (c->iev.ibuf.fd == fd) + break; + } + + return (c); +} + +struct ctl_conn * +control_connbyid(uint32_t id) +{ + struct ctl_conn *c; + + TAILQ_FOREACH(c, &ctl_conns, entry) { + if (c->id == id) + break; + } + + return (c); +} + +void +control_close(int fd) +{ + struct ctl_conn *c; + + if ((c = control_connbyfd(fd)) == NULL) { + log_warn("control_close: fd %d: not found", fd); + return; + } + if (c->modulename[0] != '\0') + radiusd_imsg_compose_module(radiusd_s, c->modulename, + IMSG_RADIUSD_MODULE_CTRL_UNBIND, c->id, -1, -1, NULL, 0); + + control_connfree(c); +} + +void +control_connfree(struct ctl_conn *c) +{ + msgbuf_clear(&c->iev.ibuf.w); + TAILQ_REMOVE(&ctl_conns, c, entry); + + event_del(&c->iev.ev); + close(c->iev.ibuf.fd); + + /* Some file descriptors are available again. */ + if (evtimer_pending(&control_state.evt, NULL)) { + evtimer_del(&control_state.evt); + event_add(&control_state.ev, NULL); + } + + free(c); +} + +/* ARGSUSED */ +void +control_dispatch_imsg(int fd, short event, void *bula) +{ + struct ctl_conn *c; + struct imsg imsg; + ssize_t n, datalen; + char modulename[RADIUSD_MODULE_NAME_LEN + 1], msg[128]; + + if ((c = control_connbyfd(fd)) == NULL) { + log_warn("control_dispatch_imsg: fd %d: not found", fd); + return; + } + + if (event & EV_READ) { + if (((n = imsg_read(&c->iev.ibuf)) == -1 && errno != EAGAIN) || + n == 0) { + control_close(fd); + return; + } + } + if (event & EV_WRITE) { + if (msgbuf_write(&c->iev.ibuf.w) <= 0 && errno != EAGAIN) { + control_close(fd); + return; + } + } + + for (;;) { + if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { + control_close(fd); + return; + } + + if (n == 0) + break; + + datalen = imsg.hdr.len - IMSG_HEADER_SIZE; + switch (imsg.hdr.type) { + default: + if (imsg.hdr.type >= IMSG_RADIUSD_MODULE_MIN) { + if (datalen < RADIUSD_MODULE_NAME_LEN) { + log_warnx( "%s: received an invalid " + "imsg %d: too small", __func__, + imsg.hdr.type); + break; + } + memset(modulename, 0, sizeof(modulename)); + memcpy(modulename, imsg.data, + RADIUSD_MODULE_NAME_LEN); + if (radiusd_imsg_compose_module(radiusd_s, + modulename, imsg.hdr.type, c->id, -1, -1, + (caddr_t)imsg.data + + RADIUSD_MODULE_NAME_LEN, datalen - + RADIUSD_MODULE_NAME_LEN) != 0) { + snprintf(msg, sizeof(msg), + "module `%s' is not loaded or not " + "capable for control command", + modulename); + imsg_compose_event(&c->iev, + IMSG_NG, c->id, -1, -1, msg, + strlen(msg) + 1); + } + } else + log_debug("control_dispatch_imsg: " + "error handling imsg %d", imsg.hdr.type); + break; + } + imsg_free(&imsg); + } + imsg_event_add(&c->iev); +} + +int +control_imsg_relay(struct imsg *imsg) +{ + struct ctl_conn *c; + + if ((c = control_connbyid(imsg->hdr.peerid)) == NULL) + return (0); + + return (imsg_compose_event(&c->iev, imsg->hdr.type, 0, imsg->hdr.pid, + -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE)); +} + +void +control_conn_bind(uint32_t peerid, const char *modulename) +{ + struct ctl_conn *c; + + if ((c = control_connbyid(peerid)) == NULL) + return; + + if (c->modulename[0] != '\0') + radiusd_imsg_compose_module(radiusd_s, c->modulename, + IMSG_RADIUSD_MODULE_CTRL_UNBIND, c->id, -1, -1, NULL, 0); + strlcpy(c->modulename, modulename, sizeof(c->modulename)); +} diff --git a/usr.sbin/radiusd/control.h b/usr.sbin/radiusd/control.h new file mode 100644 index 000000000..72f8d3f88 --- /dev/null +++ b/usr.sbin/radiusd/control.h @@ -0,0 +1,45 @@ +/* $OpenBSD: control.h,v 1.1 2024/07/09 17:26:14 yasuoka Exp $ */ + +/* + * Copyright (c) 2003, 2004 Henning Brauer + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _CONTROL_H_ +#define _CONTROL_H_ + +#include +#include +#include +#include + +#include "radiusd_local.h" + +struct ctl_conn { + uint32_t id; + TAILQ_ENTRY(ctl_conn) entry; + struct imsgev iev; + char modulename[RADIUSD_MODULE_NAME_LEN + 1]; +}; + +int control_check(char *); +int control_init(const char *); +int control_listen(void); +void control_accept(int, short, void *); +void control_dispatch_imsg(int, short, void *); +int control_imsg_relay(struct imsg *); +void control_cleanup(void); +void control_conn_bind(uint32_t, const char *); + +#endif /* _CONTROL_H_ */ diff --git a/usr.sbin/radiusd/parse.y b/usr.sbin/radiusd/parse.y index 6513ca5c4..435482ca1 100644 --- a/usr.sbin/radiusd/parse.y +++ b/usr.sbin/radiusd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.20 2024/07/02 00:33:51 yasuoka Exp $ */ +/* $OpenBSD: parse.y,v 1.21 2024/07/09 17:26:14 yasuoka Exp $ */ /* * Copyright (c) 2002, 2003, 2004 Henning Brauer @@ -1011,6 +1011,7 @@ default_module_path(const char *name) const char *path; } module_paths[] = { { "bsdauth", "/usr/libexec/radiusd/radiusd_bsdauth" }, + { "ipcp", "/usr/libexec/radiusd/radiusd_ipcp" }, { "radius", "/usr/libexec/radiusd/radiusd_radius" }, { "standard", "/usr/libexec/radiusd/radiusd_standard" } }; diff --git a/usr.sbin/radiusd/radiusd.c b/usr.sbin/radiusd/radiusd.c index e9202ba28..ec1cf51fa 100644 --- a/usr.sbin/radiusd/radiusd.c +++ b/usr.sbin/radiusd/radiusd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: radiusd.c,v 1.44 2024/07/02 00:33:51 yasuoka Exp $ */ +/* $OpenBSD: radiusd.c,v 1.45 2024/07/09 17:26:14 yasuoka Exp $ */ /* * Copyright (c) 2013, 2023 Internet Initiative Japan Inc. @@ -50,6 +50,7 @@ #include "log.h" #include "util.h" #include "imsg_subr.h" +#include "control.h" static int radiusd_start(struct radiusd *); static void radiusd_stop(struct radiusd *); @@ -101,6 +102,7 @@ static void close_stdio(void); static u_int radius_query_id_seq = 0; int debug = 0; +struct radiusd *radiusd_s = NULL; static __dead void usage(void) @@ -148,6 +150,7 @@ main(int argc, char *argv[]) if ((radiusd = calloc(1, sizeof(*radiusd))) == NULL) err(1, "calloc"); + radiusd_s = radiusd; TAILQ_INIT(&radiusd->listen); TAILQ_INIT(&radiusd->query); @@ -165,6 +168,9 @@ main(int argc, char *argv[]) if (debug == 0) close_stdio(); /* close stdio files now */ + if (control_init(RADIUSD_SOCK) == -1) + exit(EXIT_FAILURE); + event_init(); if ((pw = getpwnam(RADIUSD_USER)) == NULL) @@ -191,16 +197,22 @@ main(int argc, char *argv[]) if (radiusd_start(radiusd) != 0) errx(EXIT_FAILURE, "start failed"); + if (control_listen() == -1) + exit(EXIT_FAILURE); if (pledge("stdio inet", NULL) == -1) err(EXIT_FAILURE, "pledge"); - if (event_loop(0) < 0) - radiusd_stop(radiusd); + event_loop(0); if (radiusd->error != 0) log_warnx("exiting on error"); + radiusd_stop(radiusd); + control_cleanup(); + + event_loop(0); + radiusd_free(radiusd); event_base_free(NULL); @@ -275,7 +287,7 @@ radiusd_start(struct radiusd *radiusd) return (0); on_error: radiusd->error++; - radiusd_stop(radiusd); + event_loopbreak(); return (-1); } @@ -795,19 +807,15 @@ radiusd_access_request_aborted(struct radius_query *q) static void radiusd_on_sigterm(int fd, short evmask, void *ctx) { - struct radiusd *radiusd = ctx; - log_info("Received SIGTERM"); - radiusd_stop(radiusd); + event_loopbreak(); } static void radiusd_on_sigint(int fd, short evmask, void *ctx) { - struct radiusd *radiusd = ctx; - log_info("Received SIGINT"); - radiusd_stop(radiusd); + event_loopbreak(); } static void @@ -1063,6 +1071,29 @@ radiusd_find_query(struct radiusd *radiusd, u_int q_id) return (NULL); } +int +radiusd_imsg_compose_module(struct radiusd *radiusd, const char *module_name, + uint32_t type, uint32_t id, pid_t pid, int fd, void *data, size_t datalen) +{ + struct radiusd_module *module; + + TAILQ_FOREACH(module, &radiusd_s->module, next) { + if (strcmp(module->name, module_name) == 0) + break; + } + if (module == NULL || + (module->capabilities & RADIUSD_MODULE_CAP_CONTROL) == 0 || + module->fd < 0) + return (-1); + + if (imsg_compose(&module->ibuf, type, id, pid, fd, data, + datalen) == -1) + return (-1); + radiusd_module_reset_ev_handler(module); + + return (0); +} + /*********************************************************************** * radiusd module handling ***********************************************************************/ @@ -1493,9 +1524,15 @@ radiusd_module_imsg(struct radiusd_module *module, struct imsg *imsg) radiusd_access_request_aborted(q); break; } + case IMSG_RADIUSD_MODULE_CTRL_BIND: + control_conn_bind(imsg->hdr.peerid, module->name); + break; default: - RADIUSD_DBG(("Unhandled imsg type=%d from %s", imsg->hdr.type, - module->name)); + if (imsg->hdr.peerid != 0) + control_imsg_relay(imsg); + else + RADIUSD_DBG(("Unhandled imsg type=%d from %s", + imsg->hdr.type, module->name)); } } @@ -1811,3 +1848,44 @@ close_stdio(void) close(fd); } } + +/*********************************************************************** + * imsg_event + ***********************************************************************/ +struct iovec; + +void +imsg_event_add(struct imsgev *iev) +{ + iev->events = EV_READ; + if (iev->ibuf.w.queued) + iev->events |= EV_WRITE; + + event_del(&iev->ev); + event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); + event_add(&iev->ev, NULL); +} + +int +imsg_compose_event(struct imsgev *iev, uint32_t type, uint32_t peerid, + pid_t pid, int fd, void *data, size_t datalen) +{ + int ret; + + if ((ret = imsg_compose(&iev->ibuf, type, peerid, + pid, fd, data, datalen)) != -1) + imsg_event_add(iev); + return (ret); +} + +int +imsg_composev_event(struct imsgev *iev, uint32_t type, uint32_t peerid, + pid_t pid, int fd, struct iovec *iov, int niov) +{ + int ret; + + if ((ret = imsg_composev(&iev->ibuf, type, peerid, + pid, fd, iov, niov)) != -1) + imsg_event_add(iev); + return (ret); +} diff --git a/usr.sbin/radiusd/radiusd.conf.5 b/usr.sbin/radiusd/radiusd.conf.5 index 1e0f0e7ef..b5068fee9 100644 --- a/usr.sbin/radiusd/radiusd.conf.5 +++ b/usr.sbin/radiusd/radiusd.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: radiusd.conf.5,v 1.27 2024/07/04 13:14:26 sobrado Exp $ +.\" $OpenBSD: radiusd.conf.5,v 1.28 2024/07/09 17:26:14 yasuoka Exp $ .\" .\" Copyright (c) 2014 Esdenera Networks GmbH .\" Copyright (c) 2014, 2023 Internet Initiative Japan Inc. @@ -15,7 +15,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: July 4 2024 $ +.Dd $Mdocdate: July 9 2024 $ .Dt RADIUSD.CONF 5 .Os .Sh NAME @@ -83,6 +83,13 @@ provides authentication from the local system's interface. See .Xr radiusd_bsdauth 8 . +.It Do ipcp Dc module +The +.Dq ipcp +module provides IP configuration and manages IP address pool. +Also provides session-timeout and disconnection feature. +See +.Xr radiusd_ipcp 8 . .It Do radius Dc module The .Dq radius @@ -211,5 +218,6 @@ account * to standard .Sh SEE ALSO .Xr radiusd 8 , .Xr radiusd_bsdauth 8 , +.Xr radiusd_ipcp 8 , .Xr radiusd_radius 8 , .Xr radiusd_standard 8 diff --git a/usr.sbin/radiusd/radiusd.h b/usr.sbin/radiusd/radiusd.h index 3d7241760..047311aa0 100644 --- a/usr.sbin/radiusd/radiusd.h +++ b/usr.sbin/radiusd/radiusd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: radiusd.h,v 1.7 2024/07/02 00:33:51 yasuoka Exp $ */ +/* $OpenBSD: radiusd.h,v 1.8 2024/07/09 17:26:14 yasuoka Exp $ */ #ifndef RADIUSD_H #define RADIUSD_H 1 @@ -23,6 +23,7 @@ #define RADIUSD_MODULE_NAME_LEN 32 #define RADIUSD_SECRET_MAX 128 +#define RADIUSD_SOCK "/var/run/radiusd.sock" #define RADIUSD_USER "_radiusd" enum imsg_type { @@ -46,7 +47,10 @@ enum imsg_type { IMSG_RADIUSD_MODULE_RESDECO, IMSG_RADIUSD_MODULE_RESDECO_DONE, IMSG_RADIUSD_MODULE_ACCTREQ, + IMSG_RADIUSD_MODULE_CTRL_BIND, /* request by module */ + IMSG_RADIUSD_MODULE_CTRL_UNBIND, /* notice by control */ IMSG_RADIUSD_MODULE_STOP, + IMSG_RADIUSD_MODULE_MIN = 10000 }; /* Module sends LOAD when it becomes ready */ @@ -57,6 +61,7 @@ struct radiusd_module_load_arg { #define RADIUSD_MODULE_CAP_REQDECO 0x04 #define RADIUSD_MODULE_CAP_RESDECO 0x08 #define RADIUSD_MODULE_CAP_ACCTREQ 0x10 +#define RADIUSD_MODULE_CAP_CONTROL 0x20 }; struct radiusd_module_object { diff --git a/usr.sbin/radiusd/radiusd/Makefile b/usr.sbin/radiusd/radiusd/Makefile index bc228c47d..1598e9ed3 100644 --- a/usr.sbin/radiusd/radiusd/Makefile +++ b/usr.sbin/radiusd/radiusd/Makefile @@ -1,8 +1,8 @@ -# $OpenBSD: Makefile,v 1.1 2015/07/21 04:06:04 yasuoka Exp $ +# $OpenBSD: Makefile,v 1.2 2024/07/09 17:26:14 yasuoka Exp $ PROG= radiusd BINDIR= /usr/sbin MAN= radiusd.8 radiusd.conf.5 -SRCS= radiusd.c parse.y log.c util.c imsg_subr.c +SRCS= radiusd.c parse.y log.c util.c imsg_subr.c control.c LDADD+= -lradius -lcrypto -levent -lutil DPADD= ${LIBRADIUS} ${LIBCRYPTO} ${LIBEVENT} ${LIBUTIL} diff --git a/usr.sbin/radiusd/radiusd_ipcp.8 b/usr.sbin/radiusd/radiusd_ipcp.8 new file mode 100644 index 000000000..80cb6ba88 --- /dev/null +++ b/usr.sbin/radiusd/radiusd_ipcp.8 @@ -0,0 +1,195 @@ +.\" $OpenBSD: radiusd_ipcp.8,v 1.2 2024/07/09 17:34:10 yasuoka Exp $ +.\" +.\" Copyright (c) 2024 Internet Initiative Japan Inc. +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.\" The following requests are required for all man pages. +.\" +.Dd $Mdocdate: July 9 2024 $ +.Dt RADIUSD_IPCP 8 +.Os +.Sh NAME +.Nm radiusd_ipcp +.Nd provides IP configuration and manages IP address pool +.Sh SYNOPSIS +.Nm radiusd_ipcp +.Sh DESCRIPTION +The +.Nm +module is executed by +.Xr radiusd 8 +as a module to provide IP configuration through RADIUS Access-Accept messages +and manages IP address pool through RADIUS accounting messages. +The internal sessions can be shown or monitored by +.Xr radiusctl 8 . +Also +.Nm +provides session timeouts and disconnects requested by +.Xr radiusctl 8 +through the Dynamic Authorization Extension +.Po DAE, RFC 5176 Pc . +.Sh CONFIGURATIONS +To use the +.Nm +module, +it should be configure as a decoration module of the authentication +and as an accouting module. +.Bd -literal -offset indent +authenticate * by (any auth module) decorate-by ipcp +account * to ipcp +.Ed +.Pp +The +.Nm +module supports the following configuration key and value: +.Pp +.Bl -tag -width Ds +.It Ic address pool Ar address-space ... +Specify the IP address spaces that is pooled. +The +.Ar address-space +can be specified by a address range +.Pq e.g. 192.168.1.1-192.168.1.199 +or a address mask +.Pq e.g. 192.168.1.0/24 . +The pooled addresses are used for dynamic assignment. +.It Ic address static Ar address-space ... +Specify the IP address spaces that is pooled for static assignment. +The +.Ar address-space +is the same syntax of +.Ic address pool , +see the description for +.Ic address pool +for detail. +.It Ic name-server Ar primary-address Op Ar secondary-address +Specify the DNS servers' IP addresses. +.It Ic netbios-server Ar primary-address Op Ar secondary-address +Specify the NetBIOS name servers' IP addresses. +.It Ic session-timeout Ar seconds | Do radius Dc +Specify the session-timeout in seconds, +or +.Dq radius . +.Nm +disconnects the session through DAE at the specified time after starting. +When +.Dq radius +is specified, +the value of the Session-Timeout attribute in Access-Accepted is used for +the timeout. +Configure +.Ic dae server +to use this option. +.It Ic dae server Ar address Ns Oo Ar :port Oc Ar secret Op Ar nas-id +Configure a DAE server which +.Nm +requests disconnection for sessions. +Specify the +.Ar address , +optionally the +.Ar port +number, +and the +.Ar secret . +If the optional +.Ar nas-id +is specified, +the server is selected only for the session which NAS-Identifier is +matched the specified value. +The default port number is 3799. +.It Ic max-sessions Ar number +Specify the maxinum number of sessions. +.Sq 0 +means no limit. +The default value is 0. +.It Ic user-max-sessions Ar number +Specify the maxinum number of sessions per a user. +.Sq 0 +means no limit. +The default value is 0. +.It Ic start-wait Ar seconds +Specify the seconds waiting for the RADIUS Accounting Start for the +session after Access-Accept. +.Nm +preserves the assigned IP address for that period. +The default value is 60 seconds. +.El +.Sh EXAMPLES +An example which +.Nm +works with +.Xr npppd 8 . +.Pp +.Pa /etc/radiusd.conf: +.Bd -literal -offset indent +listen on 127.0.0.1 +listen on 127.0.0.1 accounting + +client 127.0.0.1/32 { + secret "SECRET" +} + +module radius { + set secret "SECRET2" + set server 192.168.0.4:1812 +} + +module ipcp { + set address pool 192.168.1.0/24 + set name-server 192.168.0.4 + set max-sessions 128 + set user-max-sessions 2 + #set dae server 127.0.0.1 "SECRET3" +} + +authenticate * by radius decorate-by ipcp +account * to ipcp +.Ed +.Pp +.Pa /etc/npppd/npppd.conf: +.Bd -literal -offset indent +tunnel L2TP protocol l2tp { + listen on 192.0.2.51 +} +ipcp IPCP { + pool-address 192.168.1.2-192.168.1.255 for dynamic +} +interface pppac0 address 192.168.1.1 ipcp IPCP +authentication RADIUS type radius { + authentication-server { + address 127.0.0.1 secret "SECRET" + } + accounting-server { + address 127.0.0.1 secret "SECRET" + } +} +bind tunnel from L2TP authenticated by RADIUS to pppac0 +.Ed +.Sh FILES +.Bl -tag -width "/usr/libexec/radiusd/radiusd_ipcp" -compact +.It Pa /usr/libexec/radiusd/radiusd_ipcp +.Dq ipcp +module executable. +.El +.Sh SEE ALSO +.Xr radiusctl 8 , +.Xr authenticate 3 , +.Xr radiusd 8 , +.Xr radiusd.conf 5 , +.Xr npppd 8 +.Sh HISTORY +The +.Nm +daemon first appeared in +.Ox 7.6 . diff --git a/usr.sbin/radiusd/radiusd_ipcp.c b/usr.sbin/radiusd/radiusd_ipcp.c new file mode 100644 index 000000000..bc73ee652 --- /dev/null +++ b/usr.sbin/radiusd/radiusd_ipcp.c @@ -0,0 +1,1899 @@ +/* $OpenBSD: radiusd_ipcp.c,v 1.1 2024/07/09 17:26:14 yasuoka Exp $ */ + +/* + * Copyright (c) 2024 Internet Initiative Japan Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "radiusd.h" +#include "radiusd_module.h" +#include "radiusd_ipcp.h" +#include "log.h" + +#define RADIUSD_IPCP_START_WAIT 60 + +enum ipcp_address_type { + ADDRESS_TYPE_POOL, + ADDRESS_TYPE_STATIC +}; + +struct ipcp_address { + enum ipcp_address_type type; + struct in_addr start; + struct in_addr end; + int naddrs; + TAILQ_ENTRY(ipcp_address) next; +}; + +struct user { + TAILQ_HEAD(, assigned_ipv4) ipv4s; + RB_ENTRY(user) tree; + char name[0]; +}; + +struct module_ipcp_dae; + +struct assigned_ipv4 { + struct in_addr ipv4; + unsigned seq; + char session_id[256]; + char auth_method[16]; + struct user *user; + uint32_t session_timeout; + struct timespec start; + struct timespec timeout; + struct in_addr nas_ipv4; + struct in6_addr nas_ipv6; + char nas_id[256]; + const char *tun_type; + union { + struct sockaddr_in sin4; + struct sockaddr_in6 sin6; + } tun_client; + + struct timespec authtime; + RB_ENTRY(assigned_ipv4) tree; + TAILQ_ENTRY(assigned_ipv4) next; + + /* RFC 5176 Dynamic Authorization Extensions for RADIUS */ + struct module_ipcp_dae *dae; + RADIUS_PACKET *dae_reqpkt; + TAILQ_ENTRY(assigned_ipv4) dae_next; + int dae_ntry; + struct event dae_evtimer; +}; + +struct module_ipcp_ctrlconn { + uint32_t peerid; + TAILQ_ENTRY(module_ipcp_ctrlconn) + next; +}; + +struct module_ipcp_dae { + struct module_ipcp *ipcp; + int sock; + char nas_id[256]; + char secret[80]; + union { + struct sockaddr_in sin4; + struct sockaddr_in6 sin6; + } nas_addr; + struct event ev_sock; + TAILQ_ENTRY(module_ipcp_dae) next; + TAILQ_HEAD(, assigned_ipv4) reqs; +}; + +struct module_ipcp { + struct module_base *base; + int nsessions; + unsigned seq; + int max_sessions; + int user_max_sessions; + int start_wait; + int session_timeout; + bool no_session_timeout; + struct timespec uptime; + struct in_addr name_server[2]; + struct in_addr netbios_server[2]; + RB_HEAD(assigned_ipv4_tree, assigned_ipv4) + ipv4s; + RB_HEAD(user_tree, user) users; + int npools; + TAILQ_HEAD(,ipcp_address) addrs; + TAILQ_HEAD(,module_ipcp_ctrlconn) + ctrls; + TAILQ_HEAD(,module_ipcp_dae) daes; + struct event ev_timer; +}; + +#ifndef nitems +#define nitems(_x) (sizeof((_x)) / sizeof((_x)[0])) +#endif + +#ifndef MAXIMUM +#define MAXIMUM(_a, _b) (((_a) > (_b))? (_a) : (_b)) +#endif + +static void ipcp_init(struct module_ipcp *); +static void ipcp_start(void *); +static void ipcp_stop(void *); +static void ipcp_fini(struct module_ipcp *); +static void ipcp_config_set(void *, const char *, int, char * const *); +static void ipcp_dispatch_control(void *, struct imsg *); +static int ipcp_notice_startstop(struct module_ipcp *, + struct assigned_ipv4 *, int, + struct radiusd_ipcp_statistics *); +static void ipcp_resdeco(void *, u_int, const u_char *, size_t reqlen, + const u_char *, size_t reslen); +static void ipcp_reject(struct module_ipcp *, RADIUS_PACKET *, + unsigned int, RADIUS_PACKET *, int); +static void ipcp_accounting_request(void *, u_int, const u_char *, + size_t); + +struct assigned_ipv4 + *ipcp_ipv4_assign(struct module_ipcp *, struct user *, + struct in_addr); +static struct assigned_ipv4 + *ipcp_ipv4_find(struct module_ipcp *, struct in_addr); +static void ipcp_ipv4_release(struct module_ipcp *, + struct assigned_ipv4 *); +static int assigned_ipv4_compar(struct assigned_ipv4 *, + struct assigned_ipv4 *); +static struct user + *ipcp_user_get(struct module_ipcp *, const char *); +static int user_compar(struct user *, struct user *); +static int ipcp_prepare_db(void); +static int ipcp_restore_from_db(struct module_ipcp *); +static void ipcp_put_db(struct module_ipcp *, struct assigned_ipv4 *); +static void ipcp_del_db(struct module_ipcp *, struct assigned_ipv4 *); +static void ipcp_db_dump_fill_record(struct radiusd_ipcp_db_dump *, int, + struct assigned_ipv4 *); +static void ipcp_on_timer(int, short, void *); +static void ipcp_schedule_timer(struct module_ipcp *); +static void ipcp_dae_send_disconnect_request(struct assigned_ipv4 *); +static void ipcp_dae_request_on_timeout(int, short, void *); +static void ipcp_dae_on_event(int, short, void *); +static struct ipcp_address + *parse_address_range(const char *); +static const char + *radius_tunnel_type_string(unsigned, const char *); +static const char + *radius_terminate_cause_string(unsigned); +static const char + *radius_error_cause_string(unsigned); +static int parse_addr(const char *, int, struct sockaddr *, socklen_t); +static const char + *print_addr(struct sockaddr *, char *, size_t); + +RB_PROTOTYPE_STATIC(assigned_ipv4_tree, assigned_ipv4, tree, + assigned_ipv4_compar); +RB_PROTOTYPE_STATIC(user_tree, user, tree, user_compar); + +int +main(int argc, char *argv[]) +{ + struct module_ipcp module_ipcp; + struct module_handlers handlers = { + .start = ipcp_start, + .stop = ipcp_stop, + .config_set = ipcp_config_set, + .response_decoration = ipcp_resdeco, + .accounting_request = ipcp_accounting_request, + .dispatch_control = ipcp_dispatch_control + }; + + ipcp_init(&module_ipcp); + + if ((module_ipcp.base = module_create(STDIN_FILENO, &module_ipcp, + &handlers)) == NULL) + err(1, "Could not create a module instance"); + + if (ipcp_prepare_db() == -1) + err(1, "ipcp_prepare_db"); + + module_drop_privilege(module_ipcp.base, 1); + if (unveil(_PATH_RADIUSD_IPCP_DB, "rw") == -1) + err(1, "unveil"); + if (pledge("stdio inet rpath wpath flock", NULL) == -1) + err(1, "pledge"); + setproctitle("[main]"); + + module_load(module_ipcp.base); + log_init(0); + event_init(); + + module_start(module_ipcp.base); + event_loop(0); + + ipcp_fini(&module_ipcp); + + event_loop(0); + + exit(EXIT_SUCCESS); +} + +void +ipcp_init(struct module_ipcp *self) +{ + memset(self, 0, sizeof(struct module_ipcp)); + TAILQ_INIT(&self->addrs); + RB_INIT(&self->ipv4s); + RB_INIT(&self->users); + TAILQ_INIT(&self->ctrls); + TAILQ_INIT(&self->daes); + self->seq = 1; + self->no_session_timeout = true; +} + +void +ipcp_start(void *ctx) +{ + struct module_ipcp *self = ctx; + struct ipcp_address *addr; + struct module_ipcp_dae *dae; + int sock; + + if (self->start_wait == 0) + self->start_wait = RADIUSD_IPCP_START_WAIT; + + /* count pool address*/ + TAILQ_FOREACH(addr, &self->addrs, next) { + if (addr->type == ADDRESS_TYPE_POOL) + self->npools += addr->naddrs; + } + log_info("number of pooled IP addresses = %d", self->npools); + + if (ipcp_restore_from_db(self) == -1) { + module_send_message(self->base, IMSG_NG, + "Restoring the database failed: %s", strerror(errno)); + module_stop(self->base); + return; + } + ipcp_schedule_timer(self); + + /* prepare socket for DAE */ + TAILQ_FOREACH(dae, &self->daes, next) { + if ((sock = socket(dae->nas_addr.sin4.sin_family, + SOCK_DGRAM, IPPROTO_UDP)) == -1) { + log_warn("could not start dae: %s", strerror(errno)); + return; + } + if (connect(sock, (struct sockaddr *)&dae->nas_addr, + dae->nas_addr.sin4.sin_len) == -1) { + log_warn("could not start dae: %s", strerror(errno)); + return; + } + dae->sock = sock; + event_set(&dae->ev_sock, sock, EV_READ | EV_PERSIST, + ipcp_dae_on_event, dae); + event_add(&dae->ev_sock, NULL); + } + + module_send_message(self->base, IMSG_OK, NULL); +} + +void +ipcp_stop(void *ctx) +{ + struct module_ipcp *self = ctx; + struct module_ipcp_dae *dae; + + /* stop the sockets for DAE */ + TAILQ_FOREACH(dae, &self->daes, next) { + if (dae->sock >= 0) { + event_del(&dae->ev_sock); + close(dae->sock); + dae->sock = -1; + } + } + if (evtimer_pending(&self->ev_timer, NULL)) + evtimer_del(&self->ev_timer); +} + +void +ipcp_fini(struct module_ipcp *self) +{ + struct assigned_ipv4 *assign, *assignt; + struct user *user, *usert; + struct module_ipcp_ctrlconn *ctrl, *ctrlt; + struct module_ipcp_dae *dae, *daet; + + RB_FOREACH_SAFE(assign, assigned_ipv4_tree, &self->ipv4s, assignt) + ipcp_ipv4_release(self, assign); + RB_FOREACH_SAFE(user, user_tree, &self->users, usert) + free(user); + TAILQ_FOREACH_SAFE(ctrl, &self->ctrls, next, ctrlt) + free(ctrl); + TAILQ_FOREACH_SAFE(dae, &self->daes, next, daet) { + if (dae->sock >= 0) { + event_del(&dae->ev_sock); + close(dae->sock); + } + free(dae); + } + if (evtimer_pending(&self->ev_timer, NULL)) + evtimer_del(&self->ev_timer); + module_destroy(self->base); +} + +void +ipcp_config_set(void *ctx, const char *name, int argc, char * const * argv) +{ + struct module_ipcp *module = ctx; + const char *errmsg = "none"; + int i; + struct ipcp_address *addr; + struct in_addr ina; + struct module_ipcp_dae dae, *dae0; + + if (strcmp(name, "address") == 0) { + SYNTAX_ASSERT(argc >= 1, + "specify one of pool, server, nas-select, or user-select"); + if (strcmp(argv[0], "pool") == 0) { + SYNTAX_ASSERT(argc >= 2, + "`address pool' must have one address range at " + "least"); + addr = TAILQ_FIRST(&module->addrs); + for (i = 0; i < argc - 1; i++) { + if ((addr = parse_address_range(argv[i + 1])) + == NULL) { + module_send_message(module->base, + IMSG_NG, "Invalid address range: " + "%s", argv[i + 1]); + return; + } + addr->type = ADDRESS_TYPE_POOL; + TAILQ_INSERT_TAIL(&module->addrs, addr, next); + } + } else if (strcmp(argv[0], "static") == 0) { + SYNTAX_ASSERT(argc >= 2, + "`address static' must have one address range at " + "least"); + addr = TAILQ_FIRST(&module->addrs); + for (i = 0; i < argc - 1; i++) { + if ((addr = parse_address_range(argv[i + 1])) + == NULL) { + module_send_message(module->base, + IMSG_NG, "Invalid address range: " + "%s", argv[i + 1]); + return; + } + addr->type = ADDRESS_TYPE_STATIC; + TAILQ_INSERT_TAIL(&module->addrs, addr, next); + } + } else + SYNTAX_ASSERT(0, "specify pool or static"); + } else if (strcmp(name, "max-sessions") == 0) { + SYNTAX_ASSERT(argc == 1, + "`max-sessions' must have an argument"); + module->max_sessions = strtonum(argv[0], 0, INT_MAX, &errmsg); + if (errmsg != NULL) { + module_send_message(module->base, IMSG_NG, + "could not parse `max-sessions': %s", errmsg); + return; + } + } else if (strcmp(name, "user-max-sessions") == 0) { + SYNTAX_ASSERT(argc == 1, "`max-session' must have an argument"); + module->user_max_sessions = strtonum(argv[0], 0, INT_MAX, + &errmsg); + if (errmsg != NULL) { + module_send_message(module->base, IMSG_NG, + "could not parse `user-max-session': %s", errmsg); + return; + } + } else if (strcmp(name, "start-wait") == 0) { + SYNTAX_ASSERT(argc == 1, "`start-wait' must have an argument"); + module->start_wait = strtonum(argv[0], 1, INT_MAX, &errmsg); + if (errmsg != NULL) { + module_send_message(module->base, IMSG_NG, + "could not parse `start-wait': %s", errmsg); + return; + } + } else if (strcmp(name, "name-server") == 0) { + SYNTAX_ASSERT(argc == 1 || argc == 2, + "specify 1 or 2 addresses for `name-server'"); + for (i = 0; i < argc; i++) { + if (inet_aton(argv[i], &ina) != 1) { + module_send_message(module->base, IMSG_NG, + "Invalid IP address: %s", argv[i]); + return; + } + if (module->name_server[0].s_addr == 0) + module->name_server[0] = ina; + else if (module->name_server[1].s_addr == 0) + module->name_server[1] = ina; + else + SYNTAX_ASSERT(0, + "too many `name-server' is configured"); + } + } else if (strcmp(name, "netbios-server") == 0) { + SYNTAX_ASSERT(argc == 1 || argc == 2, + "specify 1 or 2 addresses for `name-server'"); + for (i = 0; i < argc; i++) { + if (inet_aton(argv[i], &ina) != 1) { + module_send_message(module->base, IMSG_NG, + "Invalid IP address: %s", argv[i]); + return; + } + if (module->netbios_server[0].s_addr == 0) + module->netbios_server[0] = ina; + else if (module->netbios_server[1].s_addr == 0) + module->netbios_server[1] = ina; + else + SYNTAX_ASSERT(0, + "too many `name-server' is configured"); + } + } else if (strcmp(name, "session-timeout") == 0) { + SYNTAX_ASSERT(argc == 1, + "`session-timeout' must have an argument"); + if (strcmp(argv[0], "radius") == 0) { + module->no_session_timeout = false; + module->session_timeout = 0; + } else { + module->no_session_timeout = false; + module->session_timeout = strtonum(argv[0], 1, INT_MAX, + &errmsg); + if (errmsg != NULL) { + module_send_message(module->base, IMSG_NG, + "could not parse `session-timeout': %s", + errmsg); + return; + } + } + } else if (strcmp(name, "dae") == 0) { + if (!(argc >= 1 || strcmp(argv[1], "server") == 0)) { + module_send_message(module->base, IMSG_NG, + "`%s' is unknown", argv[1]); + return; + } + i = 1; + SYNTAX_ASSERT(i < argc, "no address[:port] for dae server"); + if (i < argc && + parse_addr(argv[i], AF_UNSPEC, (struct sockaddr *) + &dae.nas_addr, sizeof(dae.nas_addr)) == -1) { + module_send_message(module->base, IMSG_NG, + "failed to parse dae server's address, %s", + argv[i]); + return; + } + if (ntohs(dae.nas_addr.sin4.sin_port) == 0) + dae.nas_addr.sin4.sin_port = + htons(RADIUS_DAE_DEFAULT_PORT); + i++; + SYNTAX_ASSERT(i < argc, "no secret for dae server"); + if (strlcpy(dae.secret, argv[i++], sizeof(dae.secret)) >= + sizeof(dae.secret)) { + module_send_message(module->base, IMSG_NG, + "dae server's secret must be < %d bytes", + (int)sizeof(dae.secret) - 1); + return; + } + if (i < argc) + strlcpy(dae.nas_id, argv[i++], sizeof(dae.nas_id)); + if ((dae0 = calloc(1, sizeof(struct module_ipcp_dae))) == NULL) + { + module_send_message(module->base, IMSG_NG, + "%s", strerror(errno)); + return; + } + *dae0 = dae; + TAILQ_INIT(&dae0->reqs); + TAILQ_INSERT_TAIL(&module->daes, dae0, next); + } else if (strcmp(name, "_debug") == 0) + log_init(1); + else if (strncmp(name, "_", 1) == 0) + /* ignore */; + else { + module_send_message(module->base, IMSG_NG, + "Unknown config parameter name `%s'", name); + return; + } + module_send_message(module->base, IMSG_OK, NULL); + + return; + syntax_error: + module_send_message(module->base, IMSG_NG, "%s", errmsg); +} + +void +ipcp_dispatch_control(void *ctx, struct imsg *imsg) +{ + struct module_ipcp *self = ctx; + struct assigned_ipv4 *assign; + struct radiusd_ipcp_db_dump *dump; + struct module_ipcp_ctrlconn *ctrl, *ctrlt; + int i; + size_t dumpsiz; + u_int datalen; + unsigned seq; + + datalen = imsg->hdr.len - IMSG_HEADER_SIZE; + switch (imsg->hdr.type) { + case IMSG_RADIUSD_MODULE_CTRL_UNBIND: + TAILQ_FOREACH_SAFE(ctrl, &self->ctrls, next, ctrlt) { + if (ctrl->peerid == imsg->hdr.peerid) { + TAILQ_REMOVE(&self->ctrls, ctrl, next); + free(ctrl); + break; + } + } + break; + case IMSG_RADIUSD_MODULE_IPCP_MONITOR: + case IMSG_RADIUSD_MODULE_IPCP_DUMP_AND_MONITOR: + if ((ctrl = calloc(1, sizeof(struct module_ipcp_ctrlconn))) + == NULL) { + log_warn("%s: calloc()", __func__); + goto fail; + } + ctrl->peerid = imsg->hdr.peerid; + TAILQ_INSERT_TAIL(&self->ctrls, ctrl, next); + module_imsg_compose(self->base, IMSG_RADIUSD_MODULE_CTRL_BIND, + imsg->hdr.peerid, 0, -1, NULL, 0); + if (imsg->hdr.type == IMSG_RADIUSD_MODULE_IPCP_MONITOR) + break; + /* FALLTROUGH */ + case IMSG_RADIUSD_MODULE_IPCP_DUMP: + dumpsiz = MAX_IMSGSIZE; + if ((dump = calloc(1, dumpsiz)) == NULL) { + log_warn("%s: calloc()", __func__); + goto fail; + } + i = 0; + RB_FOREACH(assign, assigned_ipv4_tree, &self->ipv4s) { + if (!timespecisset(&assign->start)) + /* not started yet */ + continue; + ipcp_db_dump_fill_record(dump, i++, assign); + if (RB_NEXT(assigned_ipv4_tree, &self->ipv4s, assign) + == NULL) + break; + if (offsetof(struct radiusd_ipcp_db_dump, + records[i + 1]) >= dumpsiz) { + module_imsg_compose(self->base, + IMSG_RADIUSD_MODULE_IPCP_DUMP, + imsg->hdr.peerid, 0, -1, + dump, offsetof(struct radiusd_ipcp_db_dump, + records[i])); + i = 0; + } + } + dump->islast = 1; + module_imsg_compose(self->base, IMSG_RADIUSD_MODULE_IPCP_DUMP, + imsg->hdr.peerid, 0, -1, dump, offsetof( + struct radiusd_ipcp_db_dump, records[i])); + freezero(dump ,dumpsiz); + break; + case IMSG_RADIUSD_MODULE_IPCP_DISCONNECT: + if (datalen < sizeof(unsigned)) { + log_warn("%s: received " + "IMSG_RADIUSD_MODULE_IPCP_DISCONNECT message size " + "is wrong", __func__); + goto fail; + } + seq = *(unsigned *)imsg->data; + RB_FOREACH(assign, assigned_ipv4_tree, &self->ipv4s) { + if (!timespecisset(&assign->start)) + /* not started yet */ + continue; + if (assign->seq == seq) + break; + } + if (assign == NULL) + log_warnx("Disconnect seq=%u requested, but the " + "session is not found", seq); + else { + if (assign->dae == NULL) + log_warnx("Disconnect seq=%u requested, but " + "DAE is not configured", assign->seq); + else { + log_info("Disconnect id=%u requested", + assign->seq); + ipcp_dae_send_disconnect_request(assign); + } + } + break; + } + return; + fail: + module_stop(self->base); +} + +int +ipcp_notice_startstop(struct module_ipcp *self, struct assigned_ipv4 *assign, + int start, struct radiusd_ipcp_statistics *stat) +{ + struct module_ipcp_ctrlconn *ctrl; + struct radiusd_ipcp_db_dump *dump; + size_t dumpsiz; + struct iovec iov[2]; + int niov = 0; + + dumpsiz = offsetof(struct radiusd_ipcp_db_dump, records[1]); + if ((dump = calloc(1, dumpsiz)) == NULL) { + log_warn("%s: calloc()", __func__); + return (-1); + } + dump->islast = 1; + ipcp_db_dump_fill_record(dump, 0, assign); + + iov[niov].iov_base = dump; + iov[niov].iov_len = dumpsiz; + if (start == 0) { + iov[++niov].iov_base = stat; + iov[niov].iov_len = sizeof(struct radiusd_ipcp_statistics); + } + TAILQ_FOREACH(ctrl, &self->ctrls, next) + module_imsg_composev(self->base, + (start)? IMSG_RADIUSD_MODULE_IPCP_START : + IMSG_RADIUSD_MODULE_IPCP_STOP, ctrl->peerid, 0, -1, iov, + niov + 1); + freezero(dump, dumpsiz); + return (0); +} + +void +ipcp_resdeco(void *ctx, u_int q_id, const u_char *req, size_t reqlen, + const u_char *res, size_t reslen) +{ + struct module_ipcp *self = ctx; + RADIUS_PACKET *radres = NULL, *radreq = NULL; + struct in_addr addr4; + const struct in_addr mask4 = { .s_addr = 0xffffffffUL }; + int res_code, msraserr = 935; + struct ipcp_address *addr; + int i, j, n; + bool found = false; + char username[256], buf[128]; + struct user *user = NULL; + struct assigned_ipv4 *assigned = NULL, *assign; + + clock_gettime(CLOCK_BOOTTIME, &self->uptime); + + if ((radres = radius_convert_packet(res, reslen)) == NULL) { + log_warn("%s: radius_convert_packet() failed", __func__); + goto fatal; + } + res_code = radius_get_code(radres); + if (res_code != RADIUS_CODE_ACCESS_ACCEPT) + goto accept; + + if ((radreq = radius_convert_packet(req, reqlen)) == NULL) { + log_warn("%s: radius_convert_packet() failed", __func__); + goto fatal; + } + + /* + * prefer User-Name of the response rather than the request, + * since it must be the authenticated user. + */ + if (radius_get_string_attr(radres, RADIUS_TYPE_USER_NAME, username, + sizeof(username)) != 0 && + radius_get_string_attr(radreq, RADIUS_TYPE_USER_NAME, username, + sizeof(username)) != 0) { + log_warnx("q=%u unexpected request: no user-name", q_id); + goto fatal; + } + + if ((addr = TAILQ_FIRST(&self->addrs)) != NULL) { + /* The address assignment is configured */ + + if ((user = ipcp_user_get(self, username)) == NULL) { + log_warn("%s: ipcp_user_get()", __func__); + goto fatal; + } + + msraserr = 935; + if (self->max_sessions != 0) { + if (self->nsessions >= self->max_sessions) { + log_info("q=%u rejected: number of " + "sessions reached the limit(%d)", q_id, + self->max_sessions); + goto reject; + } + } + if (self->user_max_sessions != 0) { + n = 0; + TAILQ_FOREACH(assign, &user->ipv4s, next) + n++; + if (n >= self->user_max_sessions) { + log_info("q=%u rejected: number of " + "sessions per a user reached the limit(%d)", + q_id, self->user_max_sessions); + goto reject; + } + } + + msraserr = 716; + if (radius_get_ipv4_attr(radres, + RADIUS_TYPE_FRAMED_IP_ADDRESS, &addr4) == 0) { + if (ipcp_ipv4_find(self, addr4) != NULL) + log_info("q=%u rejected: server requested IP " + "address is busy", q_id); + else { + /* compare in host byte order */ + addr4.s_addr = ntohl(addr4.s_addr); + TAILQ_FOREACH(addr, &self->addrs, next) { + if (addr->type != ADDRESS_TYPE_STATIC && + addr->type != ADDRESS_TYPE_POOL) + continue; + if (addr->start.s_addr <= addr4.s_addr + && addr4.s_addr <= addr->end.s_addr) + break; + } + if (addr == NULL) + log_info("q=%u rejected: server " + "requested IP address is out of " + "the range", q_id); + else + found = true; + /* revert the addr to the network byte order */ + addr4.s_addr = htonl(addr4.s_addr); + } + if (!found) + goto reject; + } else { + n = arc4random() % self->npools; + i = 0; + TAILQ_FOREACH(addr, &self->addrs, next) { + if (addr->type == ADDRESS_TYPE_POOL) { + if (i <= n && n < i + addr->naddrs) { + j = n - i; + break; + } + i += addr->naddrs; + } + } + for (i = 0; i < self->npools; i++, j++) { + if (addr == NULL) + break; + if (j >= addr->naddrs) { /* next pool */ + if ((addr = TAILQ_NEXT(addr, next)) + == NULL) + addr = TAILQ_FIRST( + &self->addrs); + j = 0; + } + addr4.s_addr = htonl(addr->start.s_addr + j); + if (ipcp_ipv4_find(self, addr4) == NULL) { + found = true; + break; + } + } + if (!found) { + log_info("q=%u rejected: ran out of the " + "address pool", q_id); + goto reject; + } + } + if ((assigned = ipcp_ipv4_assign(self, user, addr4)) == NULL) { + log_warn("%s: ipcp_ipv4_assign()", __func__); + goto fatal; + } + radius_set_ipv4_attr(radres, RADIUS_TYPE_FRAMED_IP_NETMASK, + mask4); + radius_del_attr_all(radres, RADIUS_TYPE_FRAMED_IP_ADDRESS); + radius_put_ipv4_attr(radres, RADIUS_TYPE_FRAMED_IP_ADDRESS, + addr4); + log_info("q=%u Assign %s for %s", q_id, + inet_ntop(AF_INET, &addr4, buf, sizeof(buf)), username); + if (radius_has_attr(radreq, RADIUS_TYPE_USER_PASSWORD)) + strlcpy(assigned->auth_method, "PAP", + sizeof(assigned->auth_method)); + else if (radius_has_attr(radreq, RADIUS_TYPE_CHAP_PASSWORD)) + strlcpy(assigned->auth_method, "CHAP", + sizeof(assigned->auth_method)); + else if (radius_has_vs_attr(radreq, RADIUS_VENDOR_MICROSOFT, + RADIUS_VTYPE_MS_CHAP_RESPONSE)) + strlcpy(assigned->auth_method, "MS-CHAP", + sizeof(assigned->auth_method)); + else if (radius_has_vs_attr(radreq, RADIUS_VENDOR_MICROSOFT, + RADIUS_VTYPE_MS_CHAP2_RESPONSE)) + strlcpy(assigned->auth_method, "MS-CHAP-V2", + sizeof(assigned->auth_method)); + else if (radius_has_attr(radreq, RADIUS_TYPE_EAP_MESSAGE)) + strlcpy(assigned->auth_method, "EAP", + sizeof(assigned->auth_method)); + } + + if (self->name_server[0].s_addr != 0) { + addr4.s_addr = htonl(self->name_server[0].s_addr); + radius_del_vs_attr_all(radres, + RADIUS_VENDOR_MICROSOFT, + RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER); + radius_put_vs_ipv4_attr(radres, + RADIUS_VENDOR_MICROSOFT, + RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER, self->name_server[0]); + } + if (self->name_server[1].s_addr != 0) { + addr4.s_addr = htonl(self->name_server[1].s_addr); + radius_del_vs_attr_all(radres, + RADIUS_VENDOR_MICROSOFT, + RADIUS_VTYPE_MS_SECONDARY_DNS_SERVER); + radius_put_vs_ipv4_attr(radres, + RADIUS_VENDOR_MICROSOFT, + RADIUS_VTYPE_MS_SECONDARY_DNS_SERVER, self->name_server[1]); + } + if (self->netbios_server[0].s_addr != 0) { + addr4.s_addr = htonl(self->netbios_server[0].s_addr); + radius_del_vs_attr_all(radres, + RADIUS_VENDOR_MICROSOFT, + RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER); + radius_put_vs_ipv4_attr(radres, + RADIUS_VENDOR_MICROSOFT, + RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER, + self->netbios_server[0]); + } + if (self->netbios_server[1].s_addr != 0) { + addr4.s_addr = htonl(self->netbios_server[1].s_addr); + radius_del_vs_attr_all(radres, + RADIUS_VENDOR_MICROSOFT, + RADIUS_VTYPE_MS_SECONDARY_NBNS_SERVER); + radius_put_vs_ipv4_attr(radres, + RADIUS_VENDOR_MICROSOFT, + RADIUS_VTYPE_MS_SECONDARY_NBNS_SERVER, + self->netbios_server[1]); + } + if (!self->no_session_timeout && + radius_has_attr(radres, RADIUS_TYPE_SESSION_TIMEOUT)) { + radius_get_uint32_attr(radres, RADIUS_TYPE_SESSION_TIMEOUT, + &assigned->session_timeout); + /* we handle this session-timeout */ + radius_del_attr_all(radres, RADIUS_TYPE_SESSION_TIMEOUT); + } + + accept: + if (module_resdeco_done(self->base, q_id, radius_get_data(radres), + radius_get_length(radres)) == -1) { + log_warn("%s: module_resdeco_done() failed", __func__); + module_stop(self->base); + } + if (radreq != NULL) + radius_delete_packet(radreq); + radius_delete_packet(radres); + return; + reject: + ipcp_reject(self, radreq, q_id, radres, msraserr); + radius_delete_packet(radreq); + radius_delete_packet(radres); + return; + fatal: + if (radreq != NULL) + radius_delete_packet(radreq); + if (radres != NULL) + radius_delete_packet(radres); + module_stop(self->base); +} + +void +ipcp_reject(struct module_ipcp *self, RADIUS_PACKET *reqp, unsigned int q_id, + RADIUS_PACKET *orig_resp, int mserr) +{ + bool is_eap, is_mschap, is_mschap2; + uint8_t attr[256]; + size_t attrlen; + RADIUS_PACKET *resp; + struct { + uint8_t code; + uint8_t id; + uint16_t length; + } __packed eap; + + resp = radius_new_response_packet(RADIUS_CODE_ACCESS_REJECT, reqp); + if (resp == NULL) { + log_warn("%s: radius_new_response_packet() failed", __func__); + module_accsreq_aborted(self->base, q_id); + return; + } + + is_eap = radius_has_attr(reqp, RADIUS_TYPE_EAP_MESSAGE); + if (radius_get_vs_raw_attr(reqp, RADIUS_VENDOR_MICROSOFT, + RADIUS_VTYPE_MS_CHAP_RESPONSE, attr, &attrlen) == 0) + is_mschap = true; + else if (radius_get_vs_raw_attr(reqp, RADIUS_VENDOR_MICROSOFT, + RADIUS_VTYPE_MS_CHAP2_RESPONSE, attr, &attrlen) == 0) + is_mschap2 = true; + + if (is_eap) { + memset(&eap, 0, sizeof(eap)); /* just in case */ + eap.code = 1; /* EAP Request */ + attrlen = sizeof(attr); + if (orig_resp != NULL && radius_get_raw_attr(orig_resp, + RADIUS_TYPE_EAP_MESSAGE, &attr, &attrlen) == 0) + eap.id = attr[1]; + else + eap.id = 0; + eap.length = htons(sizeof(eap)); + radius_put_raw_attr(resp, RADIUS_TYPE_EAP_MESSAGE, &eap, + ntohs(eap.length)); + } else if (is_mschap || is_mschap2) { + attr[0] = attr[1]; /* Copy the ident of the request */ + snprintf(attr + 1, sizeof(attr) - 1, "E=%d R=0 V=3", mserr); + radius_put_vs_raw_attr(resp, RADIUS_VENDOR_MICROSOFT, + RADIUS_VTYPE_MS_CHAP_ERROR, attr, strlen(attr + 1) + 1); + } + + module_resdeco_done(self->base, q_id, radius_get_data(resp), + radius_get_length(resp)); + radius_delete_packet(resp); +} + +/*********************************************************************** + * RADIUS Accounting + ***********************************************************************/ +void +ipcp_accounting_request(void *ctx, u_int q_id, const u_char *pkt, + size_t pktlen) +{ + RADIUS_PACKET *radpkt = NULL; + int code, af; + uint32_t type, delay, uval; + struct in_addr addr4, nas_ipv4; + struct in6_addr nas_ipv6, ipv6_zero; + struct module_ipcp *self = ctx; + struct assigned_ipv4 *assign, *assignt; + char username[256], nas_id[256], buf[256], + buf1[80]; + struct timespec dur; + struct radiusd_ipcp_statistics + stat; + struct module_ipcp_dae *dae; + + clock_gettime(CLOCK_BOOTTIME, &self->uptime); + + if ((radpkt = radius_convert_packet(pkt, pktlen)) == NULL) { + log_warn("%s: radius_convert_packet() failed", __func__); + module_stop(self->base); + return; + } + code = radius_get_code(radpkt); + if (code != RADIUS_CODE_ACCOUNTING_REQUEST && + code != RADIUS_CODE_ACCOUNTING_RESPONSE) + goto out; + + if (radius_get_uint32_attr(radpkt, RADIUS_TYPE_ACCT_STATUS_TYPE, &type) + != 0) + goto out; + + /* identifier for the NAS */ + memset(&ipv6_zero, 0, sizeof(ipv6_zero)); + memset(&nas_ipv4, 0, sizeof(nas_ipv4)); + memset(&nas_ipv6, 0, sizeof(nas_ipv6)); + memset(&nas_id, 0, sizeof(nas_id)); + + radius_get_ipv4_attr(radpkt, RADIUS_TYPE_NAS_IP_ADDRESS, &nas_ipv4); + radius_get_ipv6_attr(radpkt, RADIUS_TYPE_NAS_IPV6_ADDRESS, &nas_ipv6); + radius_get_string_attr(radpkt, RADIUS_TYPE_NAS_IDENTIFIER, nas_id, + sizeof(nas_id)); + + if (nas_ipv4.s_addr == 0 && IN6_ARE_ADDR_EQUAL(&nas_ipv6, &ipv6_zero) && + nas_id[0] == '\0') { + log_warnx("q=%u no NAS-IP-Address, NAS-IPV6-Address, or " + "NAS-Identifier", q_id); + goto out; + } + + if (type == RADIUS_ACCT_STATUS_TYPE_ACCT_ON || + type == RADIUS_ACCT_STATUS_TYPE_ACCT_OFF) { + /* + * NAS or daemon is restarted. Delete all assigned records + * from it + */ + RB_FOREACH_SAFE(assign, assigned_ipv4_tree, &self->ipv4s, + assignt) { + if (assign->nas_ipv4.s_addr != nas_ipv4.s_addr || + !IN6_ARE_ADDR_EQUAL(&assign->nas_ipv6, &nas_ipv6) || + strcmp(assign->nas_id, nas_id) != 0) + continue; + log_info("Delete record for %s", inet_ntop(AF_INET, + &assign->ipv4, buf, sizeof(buf))); + ipcp_del_db(self, assign); + ipcp_ipv4_release(self, assign); + } + return; + } + + if (radius_get_ipv4_attr(radpkt, RADIUS_TYPE_FRAMED_IP_ADDRESS, &addr4) + != 0) + goto out; + if (radius_get_string_attr(radpkt, RADIUS_TYPE_USER_NAME, username, + sizeof(username)) != 0) + goto out; + if ((assign = ipcp_ipv4_find(self, addr4)) == NULL) + /* not assigned by this */ + goto out; + + if (radius_get_uint32_attr(radpkt, RADIUS_TYPE_ACCT_DELAY_TIME, &delay) + != 0) + delay = 0; + + if (type == RADIUS_ACCT_STATUS_TYPE_START) { + assign->start = self->uptime; + assign->start.tv_sec -= delay; + + if (!self->no_session_timeout && (self->session_timeout > 0 || + assign->session_timeout > 0)) { + assign->timeout = assign->start; + if (self->session_timeout > 0) + assign->timeout.tv_sec += self->session_timeout; + else + assign->timeout.tv_sec += + assign->session_timeout; + } + assign->nas_ipv4 = nas_ipv4; + assign->nas_ipv4 = nas_ipv4; + strlcpy(assign->nas_id, nas_id, sizeof(assign->nas_id)); + + if (radius_get_string_attr(radpkt, RADIUS_TYPE_ACCT_SESSION_ID, + assign->session_id, sizeof(assign->session_id)) != 0) + assign->session_id[0] = '\0'; + if (radius_get_uint32_attr(radpkt, RADIUS_TYPE_TUNNEL_TYPE, + &uval) == 0) + assign->tun_type = radius_tunnel_type_string(uval, + NULL); + if (assign->tun_type == NULL) + assign->tun_type = ""; + + /* + * Get "tunnel from" from Tunnel-Client-Endpoint or Calling- + * Station-Id + */ + af = AF_UNSPEC; + if (radius_get_string_attr(radpkt, + RADIUS_TYPE_TUNNEL_CLIENT_ENDPOINT, buf, sizeof(buf)) == 0) + { + if (radius_get_uint32_attr(radpkt, + RADIUS_TYPE_TUNNEL_MEDIUM_TYPE, &uval) == 0) { + if (uval == RADIUS_TUNNEL_MEDIUM_TYPE_IPV4) + af = AF_INET; + else if (uval == RADIUS_TUNNEL_MEDIUM_TYPE_IPV6) + af = AF_INET6; + } + parse_addr(buf, af, (struct sockaddr *) + &assign->tun_client, sizeof(assign->tun_client)); + } + if (assign->tun_client.sin4.sin_family == 0 && + radius_get_string_attr(radpkt, + RADIUS_TYPE_CALLING_STATION_ID, buf, sizeof(buf)) == 0) + parse_addr(buf, af, (struct sockaddr *) + &assign->tun_client, sizeof(assign->tun_client)); + + TAILQ_FOREACH(dae, &self->daes, next) { + if (dae->nas_id[0] == '\0' || + strcmp(dae->nas_id, assign->nas_id) == 0) + break; + } + assign->dae = dae; + + ipcp_put_db(self, assign); + ipcp_schedule_timer(self); + + if (ipcp_notice_startstop(self, assign, 1, NULL) != 0) + goto fail; + log_info("Start seq=%u user=%s duration=%dsec session=%s " + "tunnel=%s from=%s auth=%s ip=%s", assign->seq, + assign->user->name, delay, assign->session_id, + assign->tun_type, print_addr((struct sockaddr *) + &assign->tun_client, buf1, sizeof(buf1)), + assign->auth_method, inet_ntop(AF_INET, &addr4, buf, + sizeof(buf))); + } else if (type == RADIUS_ACCT_STATUS_TYPE_STOP) { + memset(&stat, 0, sizeof(stat)); + + dur = self->uptime; + dur.tv_sec -= delay; + timespecsub(&dur, &assign->start, &dur); + + if (radius_get_uint32_attr(radpkt, + RADIUS_TYPE_ACCT_INPUT_OCTETS, &uval) == 0) + stat.ibytes = uval; + if (radius_get_uint32_attr(radpkt, + RADIUS_TYPE_ACCT_INPUT_GIGAWORDS, &uval) == 0) + stat.ibytes = ((uint64_t)uval << 32) | stat.ibytes; + if (radius_get_uint32_attr(radpkt, + RADIUS_TYPE_ACCT_OUTPUT_OCTETS, &uval) == 0) + stat.obytes = uval; + if (radius_get_uint32_attr(radpkt, + RADIUS_TYPE_ACCT_OUTPUT_GIGAWORDS, &uval) == 0) + stat.obytes = ((uint64_t)uval << 32) | stat.obytes; + radius_get_uint32_attr(radpkt, RADIUS_TYPE_ACCT_INPUT_PACKETS, + &stat.ipackets); + radius_get_uint32_attr(radpkt, RADIUS_TYPE_ACCT_OUTPUT_PACKETS, + &stat.opackets); + + if (radius_get_uint32_attr(radpkt, + RADIUS_TYPE_ACCT_TERMINATE_CAUSE, &uval) == 0) + strlcpy(stat.cause, radius_terminate_cause_string(uval), + sizeof(stat.cause)); + + log_info("Stop seq=%u user=%s duration=%lldsec session=%s " + "tunnel=%s from=%s auth=%s ip=%s datain=%"PRIu64"bytes,%" + PRIu32"packets dataout=%"PRIu64"bytes,%"PRIu32"packets " + "cause=\"%s\"", + assign->seq, assign->user->name, dur.tv_sec, + assign->session_id, assign->tun_type, print_addr( + (struct sockaddr *)&assign->tun_client, buf1, sizeof(buf1)), + assign->auth_method, inet_ntop(AF_INET, &addr4, buf, + sizeof(buf)), stat.ibytes, stat.ipackets, stat.obytes, + stat.opackets, stat.cause); + + ipcp_del_db(self, assign); + if (ipcp_notice_startstop(self, assign, 0, &stat) != 0) + goto fail; + ipcp_ipv4_release(self, ipcp_ipv4_find(self, addr4)); + } + out: + radius_delete_packet(radpkt); + return; + fail: + module_stop(self->base); + radius_delete_packet(radpkt); + return; +} + +/*********************************************************************** + * On memory database to manage IP address assignment + ***********************************************************************/ +struct assigned_ipv4 * +ipcp_ipv4_assign(struct module_ipcp *self, struct user *user, + struct in_addr ina) +{ + struct assigned_ipv4 *ip; + + ip = calloc(1, sizeof(struct assigned_ipv4)); + if (ip == NULL) { + log_warn("%s: calloc()", __func__); + return (NULL); + } + ip->ipv4 = ina; + ip->user = user; + ip->authtime = self->uptime; + RB_INSERT(assigned_ipv4_tree, &self->ipv4s, ip); + TAILQ_INSERT_TAIL(&user->ipv4s, ip, next); + self->nsessions++; + ip->seq = self->seq++; + + return (ip); +} + +struct assigned_ipv4 * +ipcp_ipv4_find(struct module_ipcp *self, struct in_addr ina) +{ + struct assigned_ipv4 key, *ret; + struct timespec dif; + + key.ipv4 = ina; + ret = RB_FIND(assigned_ipv4_tree, &self->ipv4s, &key); + if (ret != NULL && ret->start.tv_sec == 0) { + /* not yet assigned */ + timespecsub(&self->uptime, &ret->authtime, &dif); + if (dif.tv_sec >= self->start_wait) { + /* assumed NAS finally didn't use the address */ + TAILQ_REMOVE(&ret->user->ipv4s, ret, next); + RB_REMOVE(assigned_ipv4_tree, &self->ipv4s, ret); + free(ret); + ret = NULL; + self->nsessions--; + } + } + return (ret); +} + +void +ipcp_ipv4_release(struct module_ipcp *self, struct assigned_ipv4 *assign) +{ + if (assign != NULL) { + TAILQ_REMOVE(&assign->user->ipv4s, assign, next); + RB_REMOVE(assigned_ipv4_tree, &self->ipv4s, assign); + self->nsessions--; + if (assign->dae != NULL) { + if (assign->dae_ntry > 0) { + TAILQ_REMOVE(&assign->dae->reqs, assign, + dae_next); + if (evtimer_pending(&assign->dae_evtimer, NULL)) + evtimer_del(&assign->dae_evtimer); + } + } + if (assign->dae_reqpkt != NULL) + radius_delete_packet(assign->dae_reqpkt); + if (evtimer_pending(&assign->dae_evtimer, NULL)) + evtimer_del(&assign->dae_evtimer); + free(assign); + } +} + +int +assigned_ipv4_compar(struct assigned_ipv4 *a, struct assigned_ipv4 *b) +{ + return (b->ipv4.s_addr - a->ipv4.s_addr); +} + +struct user * +ipcp_user_get(struct module_ipcp *self, const char *username) +{ + struct { + struct user user; + char name[256]; + } key; + struct user *elm; + + strlcpy(key.user.name, username, 256); + elm = RB_FIND(user_tree, &self->users, &key.user); + if (elm == NULL) { + if ((elm = calloc(1, offsetof(struct user, name[ + strlen(username) + 1]))) == NULL) + return (NULL); + memcpy(elm->name, username, strlen(username)); + RB_INSERT(user_tree, &self->users, elm); + TAILQ_INIT(&elm->ipv4s); + } + + return (elm); +} + +int +user_compar(struct user *a, struct user *b) +{ + return (strcmp(a->name, b->name)); +} + +RB_GENERATE_STATIC(assigned_ipv4_tree, assigned_ipv4, tree, + assigned_ipv4_compar); +RB_GENERATE_STATIC(user_tree, user, tree, user_compar); + +/*********************************************************************** + * DB for the persistent over processes + ***********************************************************************/ +int +ipcp_prepare_db(void) +{ + struct passwd *pw; + DB *db; + + if ((db = dbopen(_PATH_RADIUSD_IPCP_DB, O_CREAT | O_RDWR | O_EXLOCK, + 0600, DB_BTREE, NULL)) == NULL) + return (-1); + if ((pw = getpwnam(RADIUSD_USER)) == NULL) + return (-1); + fchown(db->fd(db), pw->pw_uid, pw->pw_gid); + db->close(db); + + return (0); +} + +int +ipcp_restore_from_db(struct module_ipcp *self) +{ + DB *db; + DBT key, val; + char keybuf[128]; + struct user *user; + struct radiusd_ipcp_db_record + *record; + struct assigned_ipv4 *assigned; + struct in_addr ipv4; + struct module_ipcp_dae *dae; + + if ((db = dbopen(_PATH_RADIUSD_IPCP_DB, O_RDONLY | O_SHLOCK, 0600, + DB_BTREE, NULL)) == NULL) + return (-1); + + key.data = "ipv4/"; + key.size = 5; + if (db->seq(db, &key, &val, R_CURSOR) == 0) { + do { + if (key.size >= sizeof(keybuf)) + break; + memcpy(keybuf, key.data, key.size); + keybuf[key.size] = '\0'; + if (strncmp(keybuf, "ipv4/", 5) != 0) + break; + inet_pton(AF_INET, keybuf + 5, &ipv4); + record = (struct radiusd_ipcp_db_record *)val.data; + if ((user = ipcp_user_get(self, record->username)) + == NULL) + return (-1); + if ((assigned = ipcp_ipv4_assign(self, user, ipv4)) + == NULL) + return (-1); + self->seq = MAXIMUM(assigned->seq + 1, self->seq); + assigned->seq = record->seq; + strlcpy(assigned->auth_method, record->auth_method, + sizeof(assigned->auth_method)); + strlcpy(assigned->session_id, record->session_id, + sizeof(assigned->session_id)); + assigned->start = record->start; + assigned->timeout = record->timeout; + assigned->nas_ipv4 = record->nas_ipv4; + assigned->nas_ipv6 = record->nas_ipv6; + strlcpy(assigned->nas_id, record->nas_id, + sizeof(assigned->nas_id)); + assigned->tun_type = radius_tunnel_type_string(0, + record->tun_type); + memcpy(&assigned->tun_client, &record->tun_client, + sizeof(assigned->tun_client)); + + TAILQ_FOREACH(dae, &self->daes, next) { + if (dae->nas_id[0] == '\0' || + strcmp(dae->nas_id, assigned->nas_id) == 0) + break; + } + assigned->dae = dae; + } while (db->seq(db, &key, &val, R_NEXT) == 0); + } + db->close(db); + + return (0); +} + +void +ipcp_put_db(struct module_ipcp *self, struct assigned_ipv4 *assigned) +{ + DB *db; + DBT key, val; + char keybuf[128]; + struct radiusd_ipcp_db_record + record; + + strlcpy(keybuf, "ipv4/", sizeof(keybuf)); + inet_ntop(AF_INET, &assigned->ipv4, keybuf + 5, sizeof(keybuf) - 5); + key.data = keybuf; + key.size = strlen(keybuf); + strlcpy(record.session_id, assigned->session_id, + sizeof(record.session_id)); + strlcpy(record.auth_method, assigned->auth_method, + sizeof(record.auth_method)); + strlcpy(record.username, assigned->user->name, sizeof(record.username)); + record.seq = assigned->seq; + record.start = assigned->start; + record.timeout = assigned->timeout; + record.nas_ipv4 = assigned->nas_ipv4; + record.nas_ipv6 = assigned->nas_ipv6; + strlcpy(record.nas_id, assigned->nas_id, sizeof(record.nas_id)); + if (assigned->tun_type != NULL) + strlcpy(record.tun_type, assigned->tun_type, + sizeof(record.tun_type)); + memcpy(&record.tun_client, &assigned->tun_client, + sizeof(record.tun_client)); + + val.data = &record; + val.size = sizeof(record); + if ((db = dbopen(_PATH_RADIUSD_IPCP_DB, O_RDWR | O_EXLOCK, 0600, + DB_BTREE, NULL)) == NULL) + return; + db->put(db, &key, &val, 0); + db->close(db); +} + +void +ipcp_del_db(struct module_ipcp *self, struct assigned_ipv4 *assigned) +{ + DB *db; + DBT key; + char keybuf[128]; + + strlcpy(keybuf, "ipv4/", sizeof(keybuf)); + inet_ntop(AF_INET, &assigned->ipv4, keybuf + 5, sizeof(keybuf) - 5); + key.data = keybuf; + key.size = strlen(keybuf); + + if ((db = dbopen(_PATH_RADIUSD_IPCP_DB, O_RDWR | O_EXLOCK, 0600, + DB_BTREE, NULL)) == NULL) + return; + db->del(db, &key, 0); + db->close(db); +} + +void +ipcp_db_dump_fill_record(struct radiusd_ipcp_db_dump *dump, int idx, + struct assigned_ipv4 *assign) +{ + dump->records[idx].af = AF_INET; + dump->records[idx].addr.ipv4 = assign->ipv4; + dump->records[idx].rec.seq = assign->seq; + strlcpy(dump->records[idx].rec.session_id, assign->session_id, + sizeof(dump->records[idx].rec.session_id)); + strlcpy(dump->records[idx].rec.auth_method, assign->auth_method, + sizeof(dump->records[idx].rec.auth_method)); + strlcpy(dump->records[idx].rec.username, assign->user->name, + sizeof(dump->records[idx].rec.username)); + dump->records[idx].rec.start = assign->start; + dump->records[idx].rec.timeout = assign->timeout; + dump->records[idx].rec.nas_ipv4 = assign->nas_ipv4; + dump->records[idx].rec.nas_ipv6 = assign->nas_ipv6; + strlcpy(dump->records[idx].rec.nas_id, assign->nas_id, + sizeof(dump->records[idx].rec.nas_id)); + if (assign->tun_type != NULL) + strlcpy(dump->records[idx].rec.tun_type, assign->tun_type, + sizeof(dump->records[idx].rec.tun_type)); + memcpy(&dump->records[idx].rec.tun_client, &assign->tun_client, + sizeof(dump->records[idx].rec.tun_client)); +} + +/*********************************************************************** + * Timer + ***********************************************************************/ +void +ipcp_on_timer(int fd, short ev, void *ctx) +{ + struct module_ipcp *self = ctx; + + clock_gettime(CLOCK_BOOTTIME, &self->uptime); + ipcp_schedule_timer(self); +} + +void +ipcp_schedule_timer(struct module_ipcp *self) +{ + struct assigned_ipv4 *assign, *min_assign = NULL; + struct timespec tsd; + struct timeval tv; + + /* check session timeout */ + RB_FOREACH(assign, assigned_ipv4_tree, &self->ipv4s) { + if (assign->timeout.tv_sec == 0) + continue; + if (timespeccmp(&assign->timeout, &self->uptime, <=)) { + log_info("Reached session timeout seq=%u", assign->seq); + ipcp_dae_send_disconnect_request(assign); + memset(&assign->timeout, 0, sizeof(assign->timeout)); + ipcp_put_db(self, assign); + } + if (min_assign == NULL || + timespeccmp(&min_assign->timeout, &assign->timeout, >)) + min_assign = assign; + } + if (evtimer_pending(&self->ev_timer, NULL)) + evtimer_del(&self->ev_timer); + + if (min_assign != NULL) { + timespecsub(&min_assign->timeout, &self->uptime, &tsd); + TIMESPEC_TO_TIMEVAL(&tv, &tsd); + evtimer_set(&self->ev_timer, ipcp_on_timer, self); + evtimer_add(&self->ev_timer, &tv); + } +} + +/*********************************************************************** + * Dynamic Authorization Extension for RAIDUS (RFC 5176) + ***********************************************************************/ +static const int dae_request_timeouts[] = { 2, 4, 8, 8 }; + +void +ipcp_dae_send_disconnect_request(struct assigned_ipv4 *assign) +{ + RADIUS_PACKET *reqpkt = NULL; + struct timeval tv; + char buf[80]; + + if (assign->dae == NULL) + return; /* DAE is not configured */ + + if (assign->dae_ntry == 0) + + if (assign->dae_reqpkt != NULL) { + radius_delete_packet(assign->dae_reqpkt); + assign->dae_reqpkt = NULL; + } + + reqpkt = radius_new_request_packet(RADIUS_CODE_DISCONNECT_REQUEST); + + radius_put_string_attr(reqpkt, RADIUS_TYPE_ACCT_SESSION_ID, + assign->session_id); + + radius_set_accounting_request_authenticator(reqpkt, + assign->dae->secret); + + if (radius_send(assign->dae->sock, reqpkt, 0) < 0) + log_warn("%s: sendto: %m", __func__); + + if (assign->dae_ntry == 0) + log_info("Sending Disconnect-Request seq=%u to %s", + assign->seq, print_addr((struct sockaddr *) + &assign->dae->nas_addr, buf, sizeof(buf))); + + assign->dae_reqpkt = reqpkt; + tv.tv_sec = dae_request_timeouts[assign->dae_ntry]; + tv.tv_usec = 0; + evtimer_set(&assign->dae_evtimer, ipcp_dae_request_on_timeout, assign); + evtimer_add(&assign->dae_evtimer, &tv); + + if (assign->dae_ntry++ == 0) + TAILQ_INSERT_TAIL(&assign->dae->reqs, assign, dae_next); +} + +void +ipcp_dae_request_on_timeout(int fd, short ev, void *ctx) +{ + struct assigned_ipv4 *assign = ctx; + char buf[80]; + + if (assign->dae_ntry >= (int)nitems(dae_request_timeouts)) + log_warnx("No answer for Disconnect-Request seq=%u from %s", + assign->seq, print_addr((struct sockaddr *) + &assign->dae->nas_addr, buf, sizeof(buf))); + else + ipcp_dae_send_disconnect_request(assign); +} + +void +ipcp_dae_on_event(int fd, short ev, void *ctx) +{ + struct module_ipcp_dae *dae = ctx; + RADIUS_PACKET *radres = NULL; + int code; + uint32_t u32; + struct assigned_ipv4 *assign; + char buf[80], causestr[80]; + const char *cause; + + if ((ev & EV_READ) == 0) + return; + + if ((radres = radius_recv(dae->sock, 0)) == NULL) { + if (errno == EAGAIN) + return; + log_warn("Failed to receive from %s", print_addr( + (struct sockaddr *)&dae->nas_addr, buf, sizeof(buf))); + return; + } + TAILQ_FOREACH(assign, &dae->reqs, dae_next) { + if (radius_get_id(assign->dae_reqpkt) == radius_get_id(radres)) + break; + } + if (assign == NULL) { + log_warnx("Received RADIUS packet from %s has unknown id=%d", + print_addr((struct sockaddr *)&dae->nas_addr, buf, + sizeof(buf)), radius_get_id(radres)); + return; + } + + radius_set_request_packet(radres, assign->dae_reqpkt); + if ((radius_check_response_authenticator(radres, dae->secret)) != 0) { + log_warnx("Received RADIUS packet for seq=%u from %s has a bad " + "authenticator", assign->seq, print_addr( + (struct sockaddr *)&dae->nas_addr, buf, + sizeof(buf))); + return; + } + causestr[0] = '\0'; + if (radius_get_uint32_attr(radres, RADIUS_TYPE_ERROR_CAUSE, &u32) == 0){ + cause = radius_error_cause_string(u32); + if (cause != NULL) + snprintf(causestr, sizeof(causestr), " cause=%u(%s)", + u32, cause); + else + snprintf(causestr, sizeof(causestr), " cause=%u", u32); + } + + code = radius_get_code(radres); + switch (code) { + case RADIUS_CODE_DISCONNECT_ACK: + log_info("Received Disconnect-ACK for seq=%u from %s%s", + assign->seq, print_addr((struct sockaddr *) + &dae->nas_addr, buf, sizeof(buf)), cause); + evtimer_del(&assign->dae_evtimer); + break; + case RADIUS_CODE_DISCONNECT_NAK: + log_warnx("Received Disconnect-NAK for seq=%u from %s%s", + assign->seq, print_addr((struct sockaddr *) + &dae->nas_addr, buf, sizeof(buf)), cause); + evtimer_del(&assign->dae_evtimer); + break; + default: + log_warn("Received unknown code=%d for id=%u from %s", + code, assign->seq, print_addr((struct sockaddr *) + &dae->nas_addr, buf, sizeof(buf))); + break; + } +} + +/*********************************************************************** + * Miscellaneous functions + ***********************************************************************/ +struct ipcp_address * +parse_address_range(const char *range) +{ + char *buf, *sep; + int masklen; + uint32_t mask; + struct in_addr start, end; + struct ipcp_address *ret; + const char *errstr; + + buf = strdup(range); + if (buf == NULL) + goto error; + if ((sep = strchr(buf, '-')) != NULL) { + *sep = '\0'; + if (inet_aton(buf, &start) != 1) + goto error; + else if (inet_aton(++sep, &end) != 1) + goto error; + start.s_addr = ntohl(start.s_addr); + end.s_addr = ntohl(end.s_addr); + } else { + if ((sep = strchr(buf, '/')) != NULL) { + *sep = '\0'; + if (inet_aton(buf, &start) != 1) + goto error; + masklen = strtonum(++sep, 0, 32, &errstr); + if (errstr != NULL) + goto error; + } else { + if (inet_aton(buf, &start) != 1) + goto error; + masklen = 32; + } + mask = 0xFFFFFFFFUL; + if (masklen < 32) + mask <<= (32 - masklen); + start.s_addr = ntohl(start.s_addr) & mask; + if (masklen == 32) + end = start; + else if (masklen == 31) + end.s_addr = start.s_addr + 1; + else { + end.s_addr = start.s_addr + (1 << (32 - masklen)) - 2; + start.s_addr = start.s_addr + 1; + } + } + free(buf); + if ((ret = calloc(1, sizeof(struct ipcp_address))) == NULL) + return (NULL); + ret->start = start; + ret->end = end; + ret->naddrs = end.s_addr - start.s_addr + 1; + return (ret); + error: + free(buf); + return (NULL); +} + +const char * +radius_tunnel_type_string(unsigned val, const char *label) +{ + unsigned int i; + struct { + const unsigned constval; + const char *label; + } tunnel_types[] = { + { RADIUS_TUNNEL_TYPE_PPTP, "PPTP" }, + { RADIUS_TUNNEL_TYPE_L2F, "L2F" }, + { RADIUS_TUNNEL_TYPE_L2TP, "L2TP" }, + { RADIUS_TUNNEL_TYPE_ATMP, "ATMP" }, + { RADIUS_TUNNEL_TYPE_VTP, "VTP" }, + { RADIUS_TUNNEL_TYPE_AH, "AH" }, + { RADIUS_TUNNEL_TYPE_IP, "IP" }, + { RADIUS_TUNNEL_TYPE_MOBILE, "MIN-IP-IP" }, + { RADIUS_TUNNEL_TYPE_ESP, "ESP" }, + { RADIUS_TUNNEL_TYPE_GRE, "GRE" }, + { RADIUS_TUNNEL_TYPE_VDS, "DVS" }, + /* [MS-RNAS] 3.3.5.1.9 Tunnel-Type */ + { RADIUS_VENDOR_MICROSOFT << 8 | 1, + "SSTP" } + }; + + if (label != NULL) { /* for conversion to the const value */ + for (i = 0; i < nitems(tunnel_types); i++) { + if (strcmp(tunnel_types[i].label, label) == 0) + return (tunnel_types[i].label); + } + } + + for (i = 0; i < nitems(tunnel_types); i++) { + if (tunnel_types[i].constval == val) + return (tunnel_types[i].label); + } + + return (NULL); +} + +const char * +radius_terminate_cause_string(unsigned val) +{ + unsigned int i; + struct { + const unsigned constval; + const char *label; + } terminate_causes[] = { + { RADIUS_TERMNATE_CAUSE_USER_REQUEST, "User Request" }, + { RADIUS_TERMNATE_CAUSE_LOST_CARRIER, "Lost Carrier" }, + { RADIUS_TERMNATE_CAUSE_LOST_SERVICE, "Lost Service" }, + { RADIUS_TERMNATE_CAUSE_IDLE_TIMEOUT, "Idle Timeout" }, + { RADIUS_TERMNATE_CAUSE_SESSION_TIMEOUT, "Session Timeout" }, + { RADIUS_TERMNATE_CAUSE_ADMIN_RESET, "Admin Reset" }, + { RADIUS_TERMNATE_CAUSE_ADMIN_REBOOT, "Admin Reboot" }, + { RADIUS_TERMNATE_CAUSE_PORT_ERROR, "Port Error" }, + { RADIUS_TERMNATE_CAUSE_NAS_ERROR, "NAS Error" }, + { RADIUS_TERMNATE_CAUSE_NAS_RESET, "NAS Request" }, + { RADIUS_TERMNATE_CAUSE_NAS_REBOOT, "NAS Reboot" }, + { RADIUS_TERMNATE_CAUSE_PORT_UNNEEDED, "Port Unneeded" }, + { RADIUS_TERMNATE_CAUSE_PORT_PREEMPTED, "Port Preempted" }, + { RADIUS_TERMNATE_CAUSE_PORT_SUSPENDED, "Port Suspended" }, + { RADIUS_TERMNATE_CAUSE_SERVICE_UNAVAIL, "Service Unavailable" }, + { RADIUS_TERMNATE_CAUSE_CALLBACK, "Callback" }, + { RADIUS_TERMNATE_CAUSE_USER_ERROR, "User Error" }, + { RADIUS_TERMNATE_CAUSE_HOST_REQUEST, "Host Request" }, + }; + + for (i = 0; i < nitems(terminate_causes); i++) { + if (terminate_causes[i].constval == val) + return (terminate_causes[i].label); + } + + return (NULL); +} + +const char * +radius_error_cause_string(unsigned val) +{ + unsigned int i; + struct { + const unsigned constval; + const char *label; + } error_causes[] = { + { RADIUS_ERROR_CAUSE_RESIDUAL_SESSION_REMOVED, + "Residual Session Context Removed" }, + { RADIUS_ERROR_CAUSE_INVALID_EAP_PACKET, + "Invalid EAP Packet (Ignored)" }, + { RADIUS_ERROR_CAUSE_UNSUPPORTED_ATTRIBUTE, + "Unsupported Attribute" }, + { RADIUS_ERROR_CAUSE_MISSING_ATTRIBUTE, + "Missing Attribute" }, + { RADIUS_ERROR_CAUSE_NAS_IDENTIFICATION_MISMATCH, + "NAS Identification Mismatch" }, + { RADIUS_ERROR_CAUSE_INVALID_REQUEST, + "Invalid Request" }, + { RADIUS_ERROR_CAUSE_UNSUPPORTED_SERVICE, + "Unsupported Service" }, + { RADIUS_ERROR_CAUSE_UNSUPPORTED_EXTENSION, + "Unsupported Extension" }, + { RADIUS_ERROR_CAUSE_INVALID_ATTRIBUTE_VALUE, + "Invalid Attribute Valu" }, + { RADIUS_ERROR_CAUSE_ADMINISTRATIVELY_PROHIBITED, + "Administratively Prohibited" }, + { RADIUS_ERROR_CAUSE_REQUEST_NOT_ROUTABLE, + "Request Not Routable (Proxy)" }, + { RADIUS_ERROR_CAUSE_SESSION_NOT_FOUND, + "Session Context Not Found" }, + { RADIUS_ERROR_CAUSE_SESSION_NOT_REMOVABLE, + "Session Context Not Removable" }, + { RADIUS_ERROR_CAUSE_OTHER_PROXY_PROCESSING_ERROR, + "Other Proxy Processing Error" }, + { RADIUS_ERROR_CAUSE_RESOURCES_UNAVAILABLE, + "Resources Unavailable" }, + { RADIUS_ERROR_CAUSE_REQUEST_INITIATED, + "equest Initiated" }, + { RADIUS_ERROR_CAUSE_MULTI_SELECTION_UNSUPPORTED, + "Multiple Session Selection Unsupported" } + }; + + for (i = 0; i < nitems(error_causes); i++) { + if (error_causes[i].constval == val) + return (error_causes[i].label); + } + + return (NULL); +} + +int +parse_addr(const char *str0, int af, struct sockaddr *sa, socklen_t salen) +{ + int error; + char *str, *end, *colon, *colon0, *addr = NULL, *port = NULL; + char *sb, *sb0; + struct addrinfo hints, *ai; + + if ((str = strdup(str0)) == NULL) + return (-1); + if (*str == '[' && (end = strchr(str + 1, ']')) != NULL) { + addr = str + 1; + *end = '\0'; + if (*(end + 1) == ':') + port = end + 2; + else if (*(end + 1) == '[' && (sb = strrchr(end + 2, ']')) + != NULL) { + port = end + 2; + *sb = '\0'; + } + } else if ((sb0 = strchr(str, '[')) != NULL && + (sb = strrchr(sb0 + 1, ']')) != NULL && sb0 < sb) { + addr = str; + *sb0 = '\0'; + port = sb0 + 1; + *sb = '\0'; + } else if ((colon0 = strchr(str, ':')) != NULL && + (colon = strrchr(str, ':')) != NULL && colon0 == colon) { + /* has one : */ + addr = str; + *colon = '\0'; + port = colon + 1; + } else { + addr = str; + port = NULL; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = af; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_NUMERICHOST; + if (port != NULL) + hints.ai_flags |= AI_NUMERICSERV; + if ((error = getaddrinfo(addr, port, &hints, &ai)) != 0) { + free(str); + return (-1); + } + if (salen < ai->ai_addrlen) { + freeaddrinfo(ai); + free(str); + return (-1); + } + memcpy(sa, ai->ai_addr, ai->ai_addrlen); + freeaddrinfo(ai); + + return (0); +} + +const char * +print_addr(struct sockaddr *sa, char *buf, size_t bufsiz) +{ + int noport, ret; + char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; + + if (ntohs(((struct sockaddr_in *)sa)->sin_port) == 0) { + noport = 1; + ret = getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0, + NI_NUMERICHOST); + } else { + noport = 0; + ret = getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), sbuf, + sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV); + } + if (ret != 0) + return ""; + if (noport) + strlcpy(buf, hbuf, bufsiz); + else if (sa->sa_family == AF_INET6) + snprintf(buf, bufsiz, "[%s]:%s", hbuf, sbuf); + else + snprintf(buf, bufsiz, "%s:%s", hbuf, sbuf); + + return (buf); +} diff --git a/usr.sbin/radiusd/radiusd_ipcp.h b/usr.sbin/radiusd/radiusd_ipcp.h new file mode 100644 index 000000000..e86bbd09e --- /dev/null +++ b/usr.sbin/radiusd/radiusd_ipcp.h @@ -0,0 +1,75 @@ +/* $OpenBSD: radiusd_ipcp.h,v 1.1 2024/07/09 17:26:14 yasuoka Exp $ */ + +/* + * Copyright (c) 2024 Internet Initiative Japan Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef RADIUSD_IPCP_H +#define RADIUSD_IPCP_H 1 + +#include +#include + +#include "radiusd.h" + +enum imsg_module_ipcp_type { + IMSG_RADIUSD_MODULE_IPCP_DUMP = IMSG_RADIUSD_MODULE_MIN, + IMSG_RADIUSD_MODULE_IPCP_MONITOR, + IMSG_RADIUSD_MODULE_IPCP_DUMP_AND_MONITOR, + IMSG_RADIUSD_MODULE_IPCP_START, + IMSG_RADIUSD_MODULE_IPCP_STOP, + IMSG_RADIUSD_MODULE_IPCP_DISCONNECT +}; + +#define _PATH_RADIUSD_IPCP_DB "/var/run/radiusd_ipcp.db" + +struct radiusd_ipcp_db_record { + unsigned seq; + char session_id[256]; + char auth_method[16]; + char username[256]; + struct timespec start; /* Start time in boottime */ + struct timespec timeout;/* Timeout time in boottime */ + struct in_addr nas_ipv4; + struct in6_addr nas_ipv6; + char nas_id[256]; + char tun_type[8]; + union { + struct sockaddr_in sin4; + struct sockaddr_in6 sin6; + } tun_client; +}; + +struct radiusd_ipcp_db_dump { + int islast; + struct { + int af; + union { + struct in_addr ipv4; + struct in6_addr ipv6; + } addr; + struct radiusd_ipcp_db_record + rec; + } records[0]; +}; + +struct radiusd_ipcp_statistics { + uint32_t ipackets; + uint32_t opackets; + uint64_t ibytes; + uint64_t obytes; + char cause[80]; +}; +#endif diff --git a/usr.sbin/radiusd/radiusd_ipcp/Makefile b/usr.sbin/radiusd/radiusd_ipcp/Makefile new file mode 100644 index 000000000..81d90b915 --- /dev/null +++ b/usr.sbin/radiusd/radiusd_ipcp/Makefile @@ -0,0 +1,11 @@ +# $OpenBSD: Makefile,v 1.1 2024/07/09 17:26:14 yasuoka Exp $ + +PROG= radiusd_ipcp +BINDIR= /usr/libexec/radiusd +SRCS= radiusd_ipcp.c radiusd_module.c log.c +CFLAGS+= -DUSE_LIBEVENT +LDADD+= -lradius -lcrypto -lutil -levent +DPADD+= ${LIBRADIUS} ${LIBCRYPTO} ${LIBUTIL} ${LIBEVENT} +MAN= radiusd_ipcp.8 + +.include diff --git a/usr.sbin/radiusd/radiusd_local.h b/usr.sbin/radiusd/radiusd_local.h index a36373c82..4fed590c0 100644 --- a/usr.sbin/radiusd/radiusd_local.h +++ b/usr.sbin/radiusd/radiusd_local.h @@ -1,4 +1,4 @@ -/* $OpenBSD: radiusd_local.h,v 1.11 2024/07/02 00:33:51 yasuoka Exp $ */ +/* $OpenBSD: radiusd_local.h,v 1.12 2024/07/09 17:26:14 yasuoka Exp $ */ /* * Copyright (c) 2013 Internet Initiative Japan Inc. @@ -16,6 +16,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#ifndef RADIUSD_LOCAL_H +#define RADIUSD_LOCAL_H 1 + #include /* for struct sockaddr_storage */ #include /* for TAILQ_* */ #include /* for struct sockaddr_in* */ @@ -30,6 +33,7 @@ #define MODULE_IO_TIMEOUT 2000 #define CONFFILE "/etc/radiusd.conf" + struct radius_query; /* forward declaration */ struct radiusd_addr { @@ -136,6 +140,16 @@ struct radius_query { TAILQ_ENTRY(radius_query) next; struct radiusd_module_ref *deco; }; + +struct imsgev { + struct imsgbuf ibuf; + void (*handler)(int, short, void *); + struct event ev; + short events; +}; + +extern struct radiusd *radiusd_s; + #ifndef nitems #define nitems(_x) (sizeof((_x)) / sizeof((_x)[0])) #endif @@ -182,9 +196,20 @@ void radiusd_module_unload(struct radiusd_module *); void radiusd_access_request_answer(struct radius_query *); void radiusd_access_request_aborted(struct radius_query *); +int radiusd_imsg_compose_module(struct radiusd *, const char *, + uint32_t, uint32_t, pid_t, int, void *, size_t); void radius_attr_hide(const char *, const char *, const u_char *, u_char *, int); void radius_attr_unhide(const char *, const char *, const u_char *, u_char *, int); -int radiusd_module_set(struct radiusd_module *, const char *, int, char * const *); +int radiusd_module_set(struct radiusd_module *, const char *, int, + char * const *); + +void imsg_event_add(struct imsgev *); +int imsg_compose_event(struct imsgev *, uint32_t, uint32_t, pid_t, + int, void *, size_t); +int imsg_composev_event (struct imsgev *, uint32_t, uint32_t, + pid_t, int, struct iovec *, int); + +#endif diff --git a/usr.sbin/radiusd/radiusd_module.c b/usr.sbin/radiusd/radiusd_module.c index 9a2b63606..33fe54763 100644 --- a/usr.sbin/radiusd/radiusd_module.c +++ b/usr.sbin/radiusd/radiusd_module.c @@ -1,4 +1,4 @@ -/* $OpenBSD: radiusd_module.c,v 1.17 2024/07/02 00:33:51 yasuoka Exp $ */ +/* $OpenBSD: radiusd_module.c,v 1.18 2024/07/09 17:26:14 yasuoka Exp $ */ /* * Copyright (c) 2015 YASUOKA Masahiko @@ -52,6 +52,7 @@ static void (*module_response_decoration) (void *, u_int, const u_char *, size_t, const u_char *, size_t) = NULL; static void (*module_accounting_request) (void *, u_int, const u_char *, size_t) = NULL; +static void (*module_dispatch_control) (void *, struct imsg *) = NULL; struct module_base { void *ctx; @@ -103,6 +104,7 @@ module_create(int sock, void *ctx, struct module_handlers *handler) module_accounting_request = handler->accounting_request; module_start_module = handler->start; module_stop_module = handler->stop; + module_dispatch_control = handler->dispatch_control; return (base); } @@ -161,6 +163,8 @@ module_load(struct module_base *base) load.cap |= RADIUSD_MODULE_CAP_RESDECO; if (module_accounting_request != NULL) load.cap |= RADIUSD_MODULE_CAP_ACCTREQ; + if (module_dispatch_control != NULL) + load.cap |= RADIUSD_MODULE_CAP_CONTROL; imsg_compose(&base->ibuf, IMSG_RADIUSD_MODULE_LOAD, 0, 0, -1, &load, sizeof(load)); imsg_flush(&base->ibuf); @@ -564,6 +568,20 @@ module_imsg_handler(struct module_base *base, struct imsg *imsg) accsreq_out: break; } + case IMSG_RADIUSD_MODULE_CTRL_UNBIND: + goto forward_msg; + break; + default: + if (imsg->hdr.type >= IMSG_RADIUSD_MODULE_MIN) { + forward_msg: + if (module_dispatch_control == NULL) { + const char msg[] = + "the module doesn't handle any controls"; + imsg_compose(&base->ibuf, IMSG_NG, + imsg->hdr.peerid, 0, -1, msg, sizeof(msg)); + } else + module_dispatch_control(base->ctx, imsg); + } } return (0); @@ -638,3 +656,29 @@ module_reset_event(struct module_base *base) syslog(LOG_ERR, "event_add() failed in %s()", __func__); #endif } + +int +module_imsg_compose(struct module_base *base, uint32_t type, uint32_t id, + pid_t pid, int fd, const void *data, size_t datalen) +{ + int ret; + + if ((ret = imsg_compose(&base->ibuf, type, id, pid, fd, data, datalen)) + != -1) + module_reset_event(base); + + return (ret); +} + +int +module_imsg_composev(struct module_base *base, uint32_t type, uint32_t id, + pid_t pid, int fd, const struct iovec *iov, int iovcnt) +{ + int ret; + + if ((ret = imsg_composev(&base->ibuf, type, id, pid, fd, iov, iovcnt)) + != -1) + module_reset_event(base); + + return (ret); +} diff --git a/usr.sbin/vmctl/vmctl.c b/usr.sbin/vmctl/vmctl.c index e08f032c0..50135adc4 100644 --- a/usr.sbin/vmctl/vmctl.c +++ b/usr.sbin/vmctl/vmctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmctl.c,v 1.90 2024/05/02 15:46:10 mlarkin Exp $ */ +/* $OpenBSD: vmctl.c,v 1.91 2024/07/09 15:51:11 mlarkin Exp $ */ /* * Copyright (c) 2014 Mike Larkin @@ -691,6 +691,7 @@ check_info_id(const char *name, uint32_t id) * 0 : Message successfully processed * EINVAL: Invalid or unexpected response from vmd * ENOMEM: memory allocation failure + * ENOENT: no entries */ int add_info(struct imsg *imsg, int *ret) @@ -698,6 +699,8 @@ add_info(struct imsg *imsg, int *ret) static size_t ct = 0; static struct vmop_info_result *vir = NULL; + *ret = 0; + if (imsg->hdr.type == IMSG_VMDOP_GET_INFO_VM_DATA) { vir = reallocarray(vir, ct + 1, sizeof(struct vmop_info_result)); @@ -707,7 +710,6 @@ add_info(struct imsg *imsg, int *ret) } memcpy(&vir[ct], imsg->data, sizeof(struct vmop_info_result)); ct++; - *ret = 0; return (0); } else if (imsg->hdr.type == IMSG_VMDOP_GET_INFO_VM_END_DATA) { switch (info_action) { @@ -718,11 +720,10 @@ add_info(struct imsg *imsg, int *ret) terminate_all(vir, ct, info_flags); break; default: - print_vm_info(vir, ct); + *ret = print_vm_info(vir, ct); break; } free(vir); - *ret = 0; return (1); } else { *ret = EINVAL; @@ -766,8 +767,12 @@ vm_state(unsigned int mask) * Parameters * list: the vm information (consolidated) returned from vmd via imsg * ct : the size (number of elements in 'list') of the result + * + * Return values: + * 0: no error + * ENOENT: no entries printed */ -void +int print_vm_info(struct vmop_info_result *list, size_t ct) { struct vm_info_result *vir; @@ -778,9 +783,11 @@ print_vm_info(struct vmop_info_result *list, size_t ct) char maxmem[FMT_SCALED_STRSIZE]; char user[16], group[16]; const char *name; - int running; + int running, found_running; extern int stat_rflag; + found_running = 0; + printf("%5s %5s %5s %7s %7s %7s %12s %8s %s\n", "ID", "PID", "VCPUS", "MAXMEM", "CURMEM", "TTY", "OWNER", "STATE", "NAME"); @@ -790,6 +797,9 @@ print_vm_info(struct vmop_info_result *list, size_t ct) running = (vir->vir_creator_pid != 0 && vir->vir_id != 0); if (!running && stat_rflag) continue; + + found_running++; + if (check_info_id(vir->vir_name, vir->vir_id)) { /* get user name */ name = user_from_uid(vmi->vir_uid, 1); @@ -841,6 +851,11 @@ print_vm_info(struct vmop_info_result *list, size_t ct) } } } + + if (found_running) + return (0); + else + return (ENOENT); } /* diff --git a/usr.sbin/vmctl/vmctl.h b/usr.sbin/vmctl/vmctl.h index 94a05168e..897b1d2b9 100644 --- a/usr.sbin/vmctl/vmctl.h +++ b/usr.sbin/vmctl/vmctl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vmctl.h,v 1.38 2024/05/18 06:45:00 jsg Exp $ */ +/* $OpenBSD: vmctl.h,v 1.39 2024/07/09 15:51:11 mlarkin Exp $ */ /* * Copyright (c) 2015 Reyk Floeter @@ -108,7 +108,7 @@ void get_info_vm(uint32_t, const char *, enum actions, unsigned int); int add_info(struct imsg *, int *); const char *vm_state(unsigned int); -void print_vm_info(struct vmop_info_result *, size_t); +int print_vm_info(struct vmop_info_result *, size_t); void terminate_all(struct vmop_info_result *, size_t, unsigned int); __dead void vm_console(struct vmop_info_result *, size_t); diff --git a/usr.sbin/vmd/fw_cfg.c b/usr.sbin/vmd/fw_cfg.c index 3e9459bae..be84dc183 100644 --- a/usr.sbin/vmd/fw_cfg.c +++ b/usr.sbin/vmd/fw_cfg.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fw_cfg.c,v 1.8 2024/02/04 14:53:12 dv Exp $ */ +/* $OpenBSD: fw_cfg.c,v 1.9 2024/07/09 09:31:37 dv Exp $ */ /* * Copyright (c) 2018 Claudio Jeker * @@ -17,8 +17,8 @@ #include #include #include /* bios_memmap_t */ -#include #include +#include #include #include diff --git a/usr.sbin/vmd/i8253.c b/usr.sbin/vmd/i8253.c index 100dd0891..ac9855e38 100644 --- a/usr.sbin/vmd/i8253.c +++ b/usr.sbin/vmd/i8253.c @@ -1,4 +1,4 @@ -/* $OpenBSD: i8253.c,v 1.39 2024/02/09 14:35:47 dv Exp $ */ +/* $OpenBSD: i8253.c,v 1.40 2024/07/09 09:31:37 dv Exp $ */ /* * Copyright (c) 2016 Mike Larkin * @@ -19,8 +19,7 @@ #include #include - -#include +#include #include #include diff --git a/usr.sbin/vmd/i8259.c b/usr.sbin/vmd/i8259.c index 189598965..2de484815 100644 --- a/usr.sbin/vmd/i8259.c +++ b/usr.sbin/vmd/i8259.c @@ -1,4 +1,4 @@ -/* $OpenBSD: i8259.c,v 1.22 2023/09/01 19:42:26 dv Exp $ */ +/* $OpenBSD: i8259.c,v 1.23 2024/07/09 09:31:37 dv Exp $ */ /* * Copyright (c) 2016 Mike Larkin * @@ -20,8 +20,7 @@ #include #include - -#include +#include #include #include diff --git a/usr.sbin/vmd/i8259.h b/usr.sbin/vmd/i8259.h index 47fae8bbc..0390d8250 100644 --- a/usr.sbin/vmd/i8259.h +++ b/usr.sbin/vmd/i8259.h @@ -1,4 +1,4 @@ -/* $OpenBSD: i8259.h,v 1.6 2024/05/18 06:45:00 jsg Exp $ */ +/* $OpenBSD: i8259.h,v 1.7 2024/07/09 09:31:37 dv Exp $ */ /* * Copyright (c) 2016 Mike Larkin * @@ -17,8 +17,6 @@ #include -#include - #define MASTER 0 #define SLAVE 1 diff --git a/usr.sbin/vmd/loadfile_elf.c b/usr.sbin/vmd/loadfile_elf.c index 864344c88..166aa04c5 100644 --- a/usr.sbin/vmd/loadfile_elf.c +++ b/usr.sbin/vmd/loadfile_elf.c @@ -1,5 +1,5 @@ /* $NetBSD: loadfile.c,v 1.10 2000/12/03 02:53:04 tsutsui Exp $ */ -/* $OpenBSD: loadfile_elf.c,v 1.47 2023/04/25 12:46:13 dv Exp $ */ +/* $OpenBSD: loadfile_elf.c,v 1.48 2024/07/09 09:31:37 dv Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -96,7 +96,8 @@ #include #include -#include +#include + #include #include #include diff --git a/usr.sbin/vmd/mc146818.c b/usr.sbin/vmd/mc146818.c index 78139f691..660c625eb 100644 --- a/usr.sbin/vmd/mc146818.c +++ b/usr.sbin/vmd/mc146818.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mc146818.c,v 1.27 2023/10/25 12:44:28 dv Exp $ */ +/* $OpenBSD: mc146818.c,v 1.28 2024/07/09 09:31:37 dv Exp $ */ /* * Copyright (c) 2016 Mike Larkin * @@ -19,8 +19,7 @@ #include #include - -#include +#include #include #include diff --git a/usr.sbin/vmd/mmio.h b/usr.sbin/vmd/mmio.h index 8acf97a84..b3f3fa40c 100644 --- a/usr.sbin/vmd/mmio.h +++ b/usr.sbin/vmd/mmio.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mmio.h,v 1.1 2022/11/10 11:46:39 dv Exp $ */ +/* $OpenBSD: mmio.h,v 1.2 2024/07/09 09:31:37 dv Exp $ */ /* * Copyright (c) 2022 Dave Voutila @@ -20,7 +20,6 @@ #define _MMIO_H_ #include -#include /* Code segment bits */ #define CS_L (1 << 13) diff --git a/usr.sbin/vmd/ns8250.c b/usr.sbin/vmd/ns8250.c index 425531cf6..bcb48ef95 100644 --- a/usr.sbin/vmd/ns8250.c +++ b/usr.sbin/vmd/ns8250.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ns8250.c,v 1.38 2023/10/25 12:44:28 dv Exp $ */ +/* $OpenBSD: ns8250.c,v 1.39 2024/07/09 09:31:37 dv Exp $ */ /* * Copyright (c) 2016 Mike Larkin * @@ -19,8 +19,7 @@ #include #include - -#include +#include #include #include diff --git a/usr.sbin/vmd/parse.y b/usr.sbin/vmd/parse.y index 2ee988972..aacfd6351 100644 --- a/usr.sbin/vmd/parse.y +++ b/usr.sbin/vmd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.68 2023/07/13 18:31:59 dv Exp $ */ +/* $OpenBSD: parse.y,v 1.69 2024/07/09 09:31:37 dv Exp $ */ /* * Copyright (c) 2007-2016 Reyk Floeter @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include diff --git a/usr.sbin/vmd/pci.c b/usr.sbin/vmd/pci.c index 5309449b3..1722baa9e 100644 --- a/usr.sbin/vmd/pci.c +++ b/usr.sbin/vmd/pci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pci.c,v 1.31 2023/02/06 20:33:34 dv Exp $ */ +/* $OpenBSD: pci.c,v 1.32 2024/07/09 09:31:37 dv Exp $ */ /* * Copyright (c) 2015 Mike Larkin @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include diff --git a/usr.sbin/vmd/vionet.c b/usr.sbin/vmd/vionet.c index f4bb1a9dc..4e4e2d98b 100644 --- a/usr.sbin/vmd/vionet.c +++ b/usr.sbin/vmd/vionet.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vionet.c,v 1.14 2024/02/22 02:38:53 dv Exp $ */ +/* $OpenBSD: vionet.c,v 1.15 2024/07/09 18:49:05 jan Exp $ */ /* * Copyright (c) 2023 Dave Voutila @@ -839,9 +839,11 @@ vionet_tx(struct virtio_dev *dev) if (vionet->local) { dhcpsz = dhcp_request(dev, iov->iov_base, iov->iov_len, &dhcppkt); - if (dhcpsz > 0) + if (dhcpsz > 0) { log_debug("%s: detected dhcp request of %zu bytes", - __func__, dhcpsz); + __func__, dhcpsz); + goto drop; + } } /* Write our packet to the tap(4). */ diff --git a/usr.sbin/vmd/virtio.c b/usr.sbin/vmd/virtio.c index 536c7733a..80d035ef6 100644 --- a/usr.sbin/vmd/virtio.c +++ b/usr.sbin/vmd/virtio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: virtio.c,v 1.113 2024/02/20 21:40:37 dv Exp $ */ +/* $OpenBSD: virtio.c,v 1.114 2024/07/09 09:31:37 dv Exp $ */ /* * Copyright (c) 2015 Mike Larkin @@ -20,13 +20,13 @@ #include #include -#include #include #include #include #include #include #include +#include #include #include diff --git a/usr.sbin/vmd/vm.c b/usr.sbin/vmd/vm.c index 6fbd1fe7a..078e9b517 100644 --- a/usr.sbin/vmd/vm.c +++ b/usr.sbin/vmd/vm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vm.c,v 1.101 2024/06/20 15:33:44 dv Exp $ */ +/* $OpenBSD: vm.c,v 1.103 2024/07/09 09:31:37 dv Exp $ */ /* * Copyright (c) 2015 Mike Larkin @@ -31,11 +31,11 @@ #include #include #include +#include #include #include #include -#include #include @@ -1809,7 +1809,6 @@ vcpu_exit_eptviolation(struct vm_run_params *vrp) #endif /* MMIO_NOTYET */ switch (ve->vee.vee_fault_type) { case VEE_FAULT_HANDLED: - log_debug("%s: fault already handled", __func__); break; #if MMIO_NOTYET diff --git a/usr.sbin/vmd/vmd.c b/usr.sbin/vmd/vmd.c index 4662f76bc..3c053ae08 100644 --- a/usr.sbin/vmd/vmd.c +++ b/usr.sbin/vmd/vmd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmd.c,v 1.157 2024/05/18 06:45:00 jsg Exp $ */ +/* $OpenBSD: vmd.c,v 1.158 2024/07/09 09:31:37 dv Exp $ */ /* * Copyright (c) 2015 Reyk Floeter @@ -40,8 +40,8 @@ #include #include +#include #include -#include #include "proc.h" #include "atomicio.h" diff --git a/usr.sbin/vmd/vmd.h b/usr.sbin/vmd/vmd.h index b62945483..4f1b05e70 100644 --- a/usr.sbin/vmd/vmd.h +++ b/usr.sbin/vmd/vmd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vmd.h,v 1.125 2024/02/20 21:40:37 dv Exp $ */ +/* $OpenBSD: vmd.h,v 1.126 2024/07/09 09:31:37 dv Exp $ */ /* * Copyright (c) 2015 Mike Larkin @@ -21,8 +21,6 @@ #include #include -#include - #include #include diff --git a/usr.sbin/vmd/vmm.c b/usr.sbin/vmd/vmm.c index dcd9a91fe..70c94c0df 100644 --- a/usr.sbin/vmd/vmm.c +++ b/usr.sbin/vmd/vmm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vmm.c,v 1.119 2024/02/05 21:58:09 dv Exp $ */ +/* $OpenBSD: vmm.c,v 1.120 2024/07/09 09:31:37 dv Exp $ */ /* * Copyright (c) 2015 Mike Larkin @@ -28,10 +28,10 @@ #include #include #include +#include #include #include -#include #include