The branch main has been updated by ivy: URL: https://cgit.FreeBSD.org/src/commit/?id=837b13af68bde317414f6c0ce295df66308cc31b
commit 837b13af68bde317414f6c0ce295df66308cc31b Author: Lexi Winter <i...@freebsd.org> AuthorDate: 2025-08-15 15:56:46 +0000 Commit: Lexi Winter <i...@freebsd.org> CommitDate: 2025-08-15 16:59:18 +0000 Revert "Remove Secure RPC DES authentication" This reverts commit 7ac276298b72982189ac1a5b17461936dc00163e. Requested by: kib --- ObsoleteFiles.inc | 4 - RELNOTES | 6 - UPDATING | 4 + include/rpc/auth_des.h | 79 ++++- lib/libc/rpc/Symbol.map | 19 ++ lib/libc/rpc/auth_des.c | 455 ++++++++++++++++++++++++++++- lib/libc/rpc/authdes_prot.c | 44 ++- lib/libc/rpc/key_call.c | 424 ++++++++++++++++++++++++--- lib/libc/rpc/publickey.5 | 40 +++ lib/libc/rpc/rpc_secure.3 | 177 +++++++++++- lib/libc/rpc/rpc_soc.3 | 13 +- lib/libc/rpc/rpc_soc.c | 31 +- lib/libc/rpc/svc_auth.c | 8 + lib/libc/rpc/svc_auth_des.c | 460 +++++++++++++++++++++++++++++- lib/librpcsvc/Makefile | 2 +- lib/librpcsvc/yp_update.c | 199 +++++++++++++ libexec/rc/rc.conf | 1 + libexec/rc/rc.d/Makefile | 1 + libexec/rc/rc.d/ypupdated | 35 +++ share/man/man5/rc.conf.5 | 9 +- sys/rpc/auth.h | 26 ++ tools/build/mk/OptionalObsoleteFiles.inc | 2 + usr.sbin/Makefile | 1 + usr.sbin/rpc.ypupdated/Makefile | 32 +++ usr.sbin/rpc.ypupdated/Makefile.depend | 18 ++ usr.sbin/rpc.ypupdated/update.c | 328 +++++++++++++++++++++ usr.sbin/rpc.ypupdated/yp_dbdelete.c | 68 +++++ usr.sbin/rpc.ypupdated/yp_dbupdate.c | 147 ++++++++++ usr.sbin/rpc.ypupdated/ypupdate | 32 +++ usr.sbin/rpc.ypupdated/ypupdated_extern.h | 32 +++ usr.sbin/rpc.ypupdated/ypupdated_main.c | 287 +++++++++++++++++++ usr.sbin/rpc.ypupdated/ypupdated_server.c | 227 +++++++++++++++ 32 files changed, 3122 insertions(+), 89 deletions(-) diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc index 4db0704d88ef..aaec7ace84fc 100644 --- a/ObsoleteFiles.inc +++ b/ObsoleteFiles.inc @@ -54,10 +54,6 @@ # 20250812: Remove a bogus manlink OLD_FILES+=usr/share/man/man3/quota_statfs.3.gz -# 20250810: Removal of remaining Secure RPC (DES) bits -OLD_FILES+=usr/sbin/rpc.ypupdated -OLD_FILES+=etc/rc.d/ypupdated - # 20250808: nvmfd removed from base install OLD_FILES+=usr/sbin/nvmfd OLD_FILES+=usr/share/man/man8/nvmfd.8.gz diff --git a/RELNOTES b/RELNOTES index c11e8543746c..040c33b7b89c 100644 --- a/RELNOTES +++ b/RELNOTES @@ -16,12 +16,6 @@ cce64f2e6851: This only works for exported ZFS file systems that have block cloning enabled, at this time. -7ac276298b72, 7b8c9de17448, 1271b1d747a7, 9dcb984251b3: - Support for Secure RPC DES authentication has been removed. This - includes publickey(5), keyserv(8) and the rpc_secure(3) routines which - rely on keyserv. The libc symbols are still present for backward - compatibility, but all functions will unconditionally return an error. - 37b2cb5ecb0f: Add support to VOP_COPY_FILE_RANGE() for block cloning. At this time, ZFS is the only local file system that supports diff --git a/UPDATING b/UPDATING index 82399310d299..587ad2f93cf2 100644 --- a/UPDATING +++ b/UPDATING @@ -27,6 +27,10 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 15.x IS SLOW: world, or to merely disable the most expensive debugging functionality at runtime, run "ln -s 'abort:false,junk:false' /etc/malloc.conf".) +20250815: + The removal of Secure RPC DES authentication notced in 20250810 + has been reverted. (However, it is still non-functional.) + 20250813: Commit cce64f2e6851 changed the internal KAPI between the NFS modules. As such, all of them need to be rebuilt from sources. diff --git a/include/rpc/auth_des.h b/include/rpc/auth_des.h index 1b4943a74b8b..0ff43c13139b 100644 --- a/include/rpc/auth_des.h +++ b/include/rpc/auth_des.h @@ -33,14 +33,91 @@ * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. */ -/* Note, RPC DES authentication was removed in FreeBSD 15.0. */ +/* + * auth_des.h, Protocol for DES style authentication for RPC + */ #ifndef _AUTH_DES_ #define _AUTH_DES_ +/* + * There are two kinds of "names": fullnames and nicknames + */ +enum authdes_namekind { + ADN_FULLNAME, + ADN_NICKNAME +}; + +/* + * A fullname contains the network name of the client, + * a conversation key and the window + */ +struct authdes_fullname { + char *name; /* network name of client, up to MAXNETNAMELEN */ + des_block key; /* conversation key */ + u_long window; /* associated window */ +}; + + +/* + * A credential + */ +struct authdes_cred { + enum authdes_namekind adc_namekind; + struct authdes_fullname adc_fullname; + u_long adc_nickname; +}; + + + +/* + * A des authentication verifier + */ +struct authdes_verf { + union { + struct timeval adv_ctime; /* clear time */ + des_block adv_xtime; /* crypt time */ + } adv_time_u; + u_long adv_int_u; +}; + +/* + * des authentication verifier: client variety + * + * adv_timestamp is the current time. + * adv_winverf is the credential window + 1. + * Both are encrypted using the conversation key. + */ +#define adv_timestamp adv_time_u.adv_ctime +#define adv_xtimestamp adv_time_u.adv_xtime +#define adv_winverf adv_int_u + +/* + * des authentication verifier: server variety + * + * adv_timeverf is the client's timestamp + client's window + * adv_nickname is the server's nickname for the client. + * adv_timeverf is encrypted using the conversation key. + */ +#define adv_timeverf adv_time_u.adv_ctime +#define adv_xtimeverf adv_time_u.adv_xtime +#define adv_nickname adv_int_u + +/* + * Map a des credential into a unix cred. + * + */ +__BEGIN_DECLS +extern int authdes_getucred( struct authdes_cred *, uid_t *, gid_t *, int *, gid_t * ); +__END_DECLS + __BEGIN_DECLS +extern bool_t xdr_authdes_cred(XDR *, struct authdes_cred *); +extern bool_t xdr_authdes_verf(XDR *, struct authdes_verf *); extern int rtime(dev_t, struct netbuf *, int, struct timeval *, struct timeval *); +extern void kgetnetname(char *); +extern enum auth_stat _svcauth_des(struct svc_req *, struct rpc_msg *); __END_DECLS #endif /* ndef _AUTH_DES_ */ diff --git a/lib/libc/rpc/Symbol.map b/lib/libc/rpc/Symbol.map index 61e8e084b1e0..105d6fb6b54e 100644 --- a/lib/libc/rpc/Symbol.map +++ b/lib/libc/rpc/Symbol.map @@ -8,9 +8,13 @@ FBSD_1.0 { xdr_desargs; xdr_desresp; + authdes_seccreate; + authdes_pk_seccreate; authnone_create; authunix_create; authunix_create_default; + xdr_authdes_cred; + xdr_authdes_verf; xdr_authunix_parms; bindresvport; bindresvport_sa; @@ -54,6 +58,15 @@ FBSD_1.0 { endrpcent; getrpcent; getrpcport; + key_setsecret; + key_secretkey_is_set; + key_encryptsession_pk; + key_decryptsession_pk; + key_encryptsession; + key_decryptsession; + key_gendes; + key_setnet; + key_get_conv; xdr_keystatus; xdr_keybuf; xdr_netnamestr; @@ -117,6 +130,7 @@ FBSD_1.0 { callrpc; registerrpc; clnt_broadcast; + authdes_create; clntunix_create; svcunix_create; svcunixfd_create; @@ -166,6 +180,8 @@ FBSD_1.0 { _authenticate; _svcauth_null; svc_auth_reg; + _svcauth_des; + authdes_getucred; _svcauth_unix; _svcauth_short; svc_dg_create; @@ -189,6 +205,9 @@ FBSD_1.8 { FBSDprivate_1.0 { __des_crypt_LOCAL; + __key_encryptsession_pk_LOCAL; + __key_decryptsession_pk_LOCAL; + __key_gendes_LOCAL; __svc_clean_idle; __rpc_gss_unwrap; __rpc_gss_unwrap_stub; diff --git a/lib/libc/rpc/auth_des.c b/lib/libc/rpc/auth_des.c index 754d55cbed3e..c9b20de25cda 100644 --- a/lib/libc/rpc/auth_des.c +++ b/lib/libc/rpc/auth_des.c @@ -30,34 +30,463 @@ /* * Copyright (c) 1988 by Sun Microsystems, Inc. */ - /* - * Secure RPC DES authentication was removed in FreeBSD 15.0. - * These symbols are provided for backward compatibility, but provide no - * functionality and will always return an error. + * auth_des.c, client-side implementation of DES authentication */ #include "namespace.h" #include "reentrant.h" +#include <err.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <rpc/des_crypt.h> +#include <syslog.h> #include <rpc/types.h> #include <rpc/auth.h> #include <rpc/auth_des.h> +#include <rpc/clnt.h> +#include <rpc/xdr.h> +#include <sys/socket.h> +#undef NIS #include <rpcsvc/nis.h> #include "un-namespace.h" +#include "mt_misc.h" + +#define USEC_PER_SEC 1000000 +#define RTIME_TIMEOUT 5 /* seconds to wait for sync */ + +#define AUTH_PRIVATE(auth) (struct ad_private *) auth->ah_private +#define ALLOC(object_type) (object_type *) mem_alloc(sizeof(object_type)) +#define FREE(ptr, size) mem_free((char *)(ptr), (int) size) +#define ATTEMPT(xdr_op) if (!(xdr_op)) return (FALSE) + +extern bool_t xdr_authdes_cred( XDR *, struct authdes_cred *); +extern bool_t xdr_authdes_verf( XDR *, struct authdes_verf *); +extern int key_encryptsession_pk(char *, netobj *, des_block *); + +extern bool_t __rpc_get_time_offset(struct timeval *, nis_server *, char *, + char **, char **); -static AUTH * -__authdes_seccreate(const char *servername, const u_int win, +/* + * DES authenticator operations vector + */ +static void authdes_nextverf(AUTH *); +static bool_t authdes_marshal(AUTH *, XDR *); +static bool_t authdes_validate(AUTH *, struct opaque_auth *); +static bool_t authdes_refresh(AUTH *, void *); +static void authdes_destroy(AUTH *); + +static struct auth_ops *authdes_ops(void); + +/* + * This struct is pointed to by the ah_private field of an "AUTH *" + */ +struct ad_private { + char *ad_fullname; /* client's full name */ + u_int ad_fullnamelen; /* length of name, rounded up */ + char *ad_servername; /* server's full name */ + u_int ad_servernamelen; /* length of name, rounded up */ + u_int ad_window; /* client specified window */ + bool_t ad_dosync; /* synchronize? */ + struct netbuf ad_syncaddr; /* remote host to synch with */ + char *ad_timehost; /* remote host to synch with */ + struct timeval ad_timediff; /* server's time - client's time */ + u_int ad_nickname; /* server's nickname for client */ + struct authdes_cred ad_cred; /* storage for credential */ + struct authdes_verf ad_verf; /* storage for verifier */ + struct timeval ad_timestamp; /* timestamp sent */ + des_block ad_xkey; /* encrypted conversation key */ + u_char ad_pkey[1024]; /* Server's actual public key */ + char *ad_netid; /* Timehost netid */ + char *ad_uaddr; /* Timehost uaddr */ + nis_server *ad_nis_srvr; /* NIS+ server struct */ +}; + +AUTH *authdes_pk_seccreate(const char *, netobj *, u_int, const char *, + const des_block *, nis_server *); + +/* + * documented version of authdes_seccreate + */ +/* + servername: network name of server + win: time to live + timehost: optional hostname to sync with + ckey: optional conversation key to use +*/ + +AUTH * +authdes_seccreate(const char *servername, const u_int win, const char *timehost, const des_block *ckey) { - return (NULL); + u_char pkey_data[1024]; + netobj pkey; + AUTH *dummy; + + if (! getpublickey(servername, (char *) pkey_data)) { + syslog(LOG_ERR, + "authdes_seccreate: no public key found for %s", + servername); + return (NULL); + } + + pkey.n_bytes = (char *) pkey_data; + pkey.n_len = (u_int)strlen((char *)pkey_data) + 1; + dummy = authdes_pk_seccreate(servername, &pkey, win, timehost, + ckey, NULL); + return (dummy); } -__sym_compat(authdes_seccreate, __authdes_seccreate, FBSD_1.0); -static AUTH * -__authdes_pk_seccreate(const char *servername __unused, netobj *pkey __unused, - u_int window __unused, const char *timehost __unused, - const des_block *ckey __unused, nis_server *srvr __unused) +/* + * Slightly modified version of authdessec_create which takes the public key + * of the server principal as an argument. This spares us a call to + * getpublickey() which in the nameserver context can cause a deadlock. + */ +AUTH * +authdes_pk_seccreate(const char *servername, netobj *pkey, u_int window, + const char *timehost, const des_block *ckey, nis_server *srvr) { + AUTH *auth; + struct ad_private *ad; + char namebuf[MAXNETNAMELEN+1]; + + /* + * Allocate everything now + */ + auth = ALLOC(AUTH); + if (auth == NULL) { + syslog(LOG_ERR, "authdes_pk_seccreate: out of memory"); + return (NULL); + } + ad = ALLOC(struct ad_private); + if (ad == NULL) { + syslog(LOG_ERR, "authdes_pk_seccreate: out of memory"); + goto failed; + } + ad->ad_fullname = ad->ad_servername = NULL; /* Sanity reasons */ + ad->ad_timehost = NULL; + ad->ad_netid = NULL; + ad->ad_uaddr = NULL; + ad->ad_nis_srvr = NULL; + ad->ad_timediff.tv_sec = 0; + ad->ad_timediff.tv_usec = 0; + memcpy(ad->ad_pkey, pkey->n_bytes, pkey->n_len); + if (!getnetname(namebuf)) + goto failed; + ad->ad_fullnamelen = RNDUP((u_int) strlen(namebuf)); + ad->ad_fullname = (char *)mem_alloc(ad->ad_fullnamelen + 1); + ad->ad_servernamelen = strlen(servername); + ad->ad_servername = (char *)mem_alloc(ad->ad_servernamelen + 1); + + if (ad->ad_fullname == NULL || ad->ad_servername == NULL) { + syslog(LOG_ERR, "authdes_seccreate: out of memory"); + goto failed; + } + if (timehost != NULL) { + ad->ad_timehost = (char *)mem_alloc(strlen(timehost) + 1); + if (ad->ad_timehost == NULL) { + syslog(LOG_ERR, "authdes_seccreate: out of memory"); + goto failed; + } + memcpy(ad->ad_timehost, timehost, strlen(timehost) + 1); + ad->ad_dosync = TRUE; + } else if (srvr != NULL) { + ad->ad_nis_srvr = srvr; /* transient */ + ad->ad_dosync = TRUE; + } else { + ad->ad_dosync = FALSE; + } + memcpy(ad->ad_fullname, namebuf, ad->ad_fullnamelen + 1); + memcpy(ad->ad_servername, servername, ad->ad_servernamelen + 1); + ad->ad_window = window; + if (ckey == NULL) { + if (key_gendes(&auth->ah_key) < 0) { + syslog(LOG_ERR, + "authdes_seccreate: keyserv(1m) is unable to generate session key"); + goto failed; + } + } else { + auth->ah_key = *ckey; + } + + /* + * Set up auth handle + */ + auth->ah_cred.oa_flavor = AUTH_DES; + auth->ah_verf.oa_flavor = AUTH_DES; + auth->ah_ops = authdes_ops(); + auth->ah_private = (caddr_t)ad; + + if (!authdes_refresh(auth, NULL)) { + goto failed; + } + ad->ad_nis_srvr = NULL; /* not needed any longer */ + return (auth); + +failed: + if (auth) + FREE(auth, sizeof (AUTH)); + if (ad) { + if (ad->ad_fullname) + FREE(ad->ad_fullname, ad->ad_fullnamelen + 1); + if (ad->ad_servername) + FREE(ad->ad_servername, ad->ad_servernamelen + 1); + if (ad->ad_timehost) + FREE(ad->ad_timehost, strlen(ad->ad_timehost) + 1); + if (ad->ad_netid) + FREE(ad->ad_netid, strlen(ad->ad_netid) + 1); + if (ad->ad_uaddr) + FREE(ad->ad_uaddr, strlen(ad->ad_uaddr) + 1); + FREE(ad, sizeof (struct ad_private)); + } return (NULL); } -__sym_compat(authdes_pk_seccreate, __authdes_pk_seccreate, FBSD_1.0); + +/* + * Implement the five authentication operations + */ + + +/* + * 1. Next Verifier + */ +/*ARGSUSED*/ +static void +authdes_nextverf(AUTH *auth __unused) +{ + /* what the heck am I supposed to do??? */ +} + + +/* + * 2. Marshal + */ +static bool_t +authdes_marshal(AUTH *auth, XDR *xdrs) +{ +/* LINTED pointer alignment */ + struct ad_private *ad = AUTH_PRIVATE(auth); + struct authdes_cred *cred = &ad->ad_cred; + struct authdes_verf *verf = &ad->ad_verf; + des_block cryptbuf[2]; + des_block ivec; + int status; + int len; + rpc_inline_t *ixdr; + + /* + * Figure out the "time", accounting for any time difference + * with the server if necessary. + */ + (void)gettimeofday(&ad->ad_timestamp, NULL); + ad->ad_timestamp.tv_sec += ad->ad_timediff.tv_sec; + ad->ad_timestamp.tv_usec += ad->ad_timediff.tv_usec; + while (ad->ad_timestamp.tv_usec >= USEC_PER_SEC) { + ad->ad_timestamp.tv_usec -= USEC_PER_SEC; + ad->ad_timestamp.tv_sec++; + } + + /* + * XDR the timestamp and possibly some other things, then + * encrypt them. + */ + ixdr = (rpc_inline_t *)cryptbuf; + IXDR_PUT_INT32(ixdr, ad->ad_timestamp.tv_sec); + IXDR_PUT_INT32(ixdr, ad->ad_timestamp.tv_usec); + if (ad->ad_cred.adc_namekind == ADN_FULLNAME) { + IXDR_PUT_U_INT32(ixdr, ad->ad_window); + IXDR_PUT_U_INT32(ixdr, ad->ad_window - 1); + ivec.key.high = ivec.key.low = 0; + status = cbc_crypt((char *)&auth->ah_key, (char *)cryptbuf, + (u_int) 2 * sizeof (des_block), + DES_ENCRYPT | DES_HW, (char *)&ivec); + } else { + status = ecb_crypt((char *)&auth->ah_key, (char *)cryptbuf, + (u_int) sizeof (des_block), + DES_ENCRYPT | DES_HW); + } + if (DES_FAILED(status)) { + syslog(LOG_ERR, "authdes_marshal: DES encryption failure"); + return (FALSE); + } + ad->ad_verf.adv_xtimestamp = cryptbuf[0]; + if (ad->ad_cred.adc_namekind == ADN_FULLNAME) { + ad->ad_cred.adc_fullname.window = cryptbuf[1].key.high; + ad->ad_verf.adv_winverf = cryptbuf[1].key.low; + } else { + ad->ad_cred.adc_nickname = ad->ad_nickname; + ad->ad_verf.adv_winverf = 0; + } + + /* + * Serialize the credential and verifier into opaque + * authentication data. + */ + if (ad->ad_cred.adc_namekind == ADN_FULLNAME) { + len = ((1 + 1 + 2 + 1)*BYTES_PER_XDR_UNIT + ad->ad_fullnamelen); + } else { + len = (1 + 1)*BYTES_PER_XDR_UNIT; + } + + if ((ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT))) { + IXDR_PUT_INT32(ixdr, AUTH_DES); + IXDR_PUT_INT32(ixdr, len); + } else { + ATTEMPT(xdr_putint32(xdrs, (int *)&auth->ah_cred.oa_flavor)); + ATTEMPT(xdr_putint32(xdrs, &len)); + } + ATTEMPT(xdr_authdes_cred(xdrs, cred)); + + len = (2 + 1)*BYTES_PER_XDR_UNIT; + if ((ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT))) { + IXDR_PUT_INT32(ixdr, AUTH_DES); + IXDR_PUT_INT32(ixdr, len); + } else { + ATTEMPT(xdr_putint32(xdrs, (int *)&auth->ah_verf.oa_flavor)); + ATTEMPT(xdr_putint32(xdrs, &len)); + } + ATTEMPT(xdr_authdes_verf(xdrs, verf)); + return (TRUE); +} + + +/* + * 3. Validate + */ +static bool_t +authdes_validate(AUTH *auth, struct opaque_auth *rverf) +{ +/* LINTED pointer alignment */ + struct ad_private *ad = AUTH_PRIVATE(auth); + struct authdes_verf verf; + int status; + uint32_t *ixdr; + des_block buf; + + if (rverf->oa_length != (2 + 1) * BYTES_PER_XDR_UNIT) { + return (FALSE); + } +/* LINTED pointer alignment */ + ixdr = (uint32_t *)rverf->oa_base; + buf.key.high = (uint32_t)*ixdr++; + buf.key.low = (uint32_t)*ixdr++; + verf.adv_int_u = (uint32_t)*ixdr++; + + /* + * Decrypt the timestamp + */ + status = ecb_crypt((char *)&auth->ah_key, (char *)&buf, + (u_int)sizeof (des_block), DES_DECRYPT | DES_HW); + + if (DES_FAILED(status)) { + syslog(LOG_ERR, "authdes_validate: DES decryption failure"); + return (FALSE); + } + + /* + * xdr the decrypted timestamp + */ +/* LINTED pointer alignment */ + ixdr = (uint32_t *)buf.c; + verf.adv_timestamp.tv_sec = IXDR_GET_INT32(ixdr) + 1; + verf.adv_timestamp.tv_usec = IXDR_GET_INT32(ixdr); + + /* + * validate + */ + if (bcmp((char *)&ad->ad_timestamp, (char *)&verf.adv_timestamp, + sizeof(struct timeval)) != 0) { + syslog(LOG_DEBUG, "authdes_validate: verifier mismatch"); + return (FALSE); + } + + /* + * We have a nickname now, let's use it + */ + ad->ad_nickname = verf.adv_nickname; + ad->ad_cred.adc_namekind = ADN_NICKNAME; + return (TRUE); +} + +/* + * 4. Refresh + */ +/*ARGSUSED*/ +static bool_t +authdes_refresh(AUTH *auth, void *dummy __unused) +{ +/* LINTED pointer alignment */ + struct ad_private *ad = AUTH_PRIVATE(auth); + struct authdes_cred *cred = &ad->ad_cred; + int ok; + netobj pkey; + + if (ad->ad_dosync) { + ok = __rpc_get_time_offset(&ad->ad_timediff, ad->ad_nis_srvr, + ad->ad_timehost, &(ad->ad_uaddr), + &(ad->ad_netid)); + if (! ok) { + /* + * Hope the clocks are synced! + */ + ad->ad_dosync = 0; + syslog(LOG_DEBUG, + "authdes_refresh: unable to synchronize clock"); + } + } + ad->ad_xkey = auth->ah_key; + pkey.n_bytes = (char *)(ad->ad_pkey); + pkey.n_len = (u_int)strlen((char *)ad->ad_pkey) + 1; + if (key_encryptsession_pk(ad->ad_servername, &pkey, &ad->ad_xkey) < 0) { + syslog(LOG_INFO, + "authdes_refresh: keyserv(1m) is unable to encrypt session key"); + return (FALSE); + } + cred->adc_fullname.key = ad->ad_xkey; + cred->adc_namekind = ADN_FULLNAME; + cred->adc_fullname.name = ad->ad_fullname; + return (TRUE); +} + + +/* + * 5. Destroy + */ +static void +authdes_destroy(AUTH *auth) +{ +/* LINTED pointer alignment */ + struct ad_private *ad = AUTH_PRIVATE(auth); + + FREE(ad->ad_fullname, ad->ad_fullnamelen + 1); + FREE(ad->ad_servername, ad->ad_servernamelen + 1); + if (ad->ad_timehost) + FREE(ad->ad_timehost, strlen(ad->ad_timehost) + 1); + if (ad->ad_netid) + FREE(ad->ad_netid, strlen(ad->ad_netid) + 1); + if (ad->ad_uaddr) + FREE(ad->ad_uaddr, strlen(ad->ad_uaddr) + 1); + FREE(ad, sizeof (struct ad_private)); + FREE(auth, sizeof(AUTH)); +} + +static struct auth_ops * +authdes_ops(void) +{ + static struct auth_ops ops; + + /* VARIABLES PROTECTED BY ops_lock: ops */ + + mutex_lock(&authdes_ops_lock); + if (ops.ah_nextverf == NULL) { + ops.ah_nextverf = authdes_nextverf; + ops.ah_marshal = authdes_marshal; + ops.ah_validate = authdes_validate; + ops.ah_refresh = authdes_refresh; + ops.ah_destroy = authdes_destroy; + } + mutex_unlock(&authdes_ops_lock); + return (&ops); +} diff --git a/lib/libc/rpc/authdes_prot.c b/lib/libc/rpc/authdes_prot.c index 56b44daafe41..79a0e5baa084 100644 --- a/lib/libc/rpc/authdes_prot.c +++ b/lib/libc/rpc/authdes_prot.c @@ -42,16 +42,44 @@ #include <rpc/auth_des.h> #include "un-namespace.h" -static bool_t -__xdr_authdes_cred(XDR *xdrs, void *cred) +#define ATTEMPT(xdr_op) if (!(xdr_op)) return (FALSE) + +bool_t +xdr_authdes_cred(XDR *xdrs, struct authdes_cred *cred) { - return (FALSE); + enum authdes_namekind *padc_namekind = &cred->adc_namekind; + /* + * Unrolled xdr + */ + ATTEMPT(xdr_enum(xdrs, (enum_t *) padc_namekind)); + switch (cred->adc_namekind) { + case ADN_FULLNAME: + ATTEMPT(xdr_string(xdrs, &cred->adc_fullname.name, + MAXNETNAMELEN)); + ATTEMPT(xdr_opaque(xdrs, (caddr_t)&cred->adc_fullname.key, + sizeof(des_block))); + ATTEMPT(xdr_opaque(xdrs, (caddr_t)&cred->adc_fullname.window, + sizeof(cred->adc_fullname.window))); + return (TRUE); + case ADN_NICKNAME: + ATTEMPT(xdr_opaque(xdrs, (caddr_t)&cred->adc_nickname, + sizeof(cred->adc_nickname))); + return (TRUE); + default: + return (FALSE); + } } -__sym_compat(xdr_authdes_cred, __xdr_authdes_cred, FBSD_1.0); -static bool_t -__xdr_authdes_verf(XDR *xdrs, void *verf) + +bool_t +xdr_authdes_verf(XDR *xdrs, struct authdes_verf *verf) { - return (FALSE); + /* + * Unrolled xdr + */ + ATTEMPT(xdr_opaque(xdrs, (caddr_t)&verf->adv_xtimestamp, + sizeof(des_block))); + ATTEMPT(xdr_opaque(xdrs, (caddr_t)&verf->adv_int_u, + sizeof(verf->adv_int_u))); + return (TRUE); } -__sym_compat(xdr_authdes_verf, __xdr_authdes_verf, FBSD_1.0); diff --git a/lib/libc/rpc/key_call.c b/lib/libc/rpc/key_call.c index eb274fcfff36..5c87881c815c 100644 --- a/lib/libc/rpc/key_call.c +++ b/lib/libc/rpc/key_call.c @@ -32,78 +32,426 @@ */ /* - * Secure RPC keyserver support was removed in FreeBSD 15.0. - * These symbols are provided for backward compatibility, but provide no - * functionality and will always return an error. + * key_call.c, Interface to keyserver + * + * setsecretkey(key) - set your secret key + * encryptsessionkey(agent, deskey) - encrypt a session key to talk to agent + * decryptsessionkey(agent, deskey) - decrypt ditto + * gendeskey(deskey) - generate a secure des key */ #include "namespace.h" #include "reentrant.h" +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> #include <rpc/rpc.h> -#include <rpc/key_prot.h> #include <rpc/auth.h> +#include <rpc/auth_unix.h> +#include <rpc/key_prot.h> +#include <string.h> +#include <netconfig.h> +#include <sys/utsname.h> +#include <stdlib.h> +#include <signal.h> +#include <sys/wait.h> +#include <sys/fcntl.h> #include "un-namespace.h" #include "mt_misc.h" -static int -__key_setsecret(const char *secretkey) + +#define KEY_TIMEOUT 5 /* per-try timeout in seconds */ +#define KEY_NRETRY 12 /* number of retries */ + +#ifdef DEBUG +#define debug(msg) (void) fprintf(stderr, "%s\n", msg); +#else +#define debug(msg) +#endif /* DEBUG */ + +/* + * Hack to allow the keyserver to use AUTH_DES (for authenticated + * NIS+ calls, for example). The only functions that get called + * are key_encryptsession_pk, key_decryptsession_pk, and key_gendes. + * + * The approach is to have the keyserver fill in pointers to local + * implementations of these functions, and to call those in key_call(). + */ + +cryptkeyres *(*__key_encryptsession_pk_LOCAL)(uid_t, void *arg) = 0; +cryptkeyres *(*__key_decryptsession_pk_LOCAL)(uid_t, void *arg) = 0; +des_block *(*__key_gendes_LOCAL)(uid_t, void *) = 0; + +static int key_call( u_long, xdrproc_t, void *, xdrproc_t, void *); + +int +key_setsecret(const char *secretkey) { - return (-1); + keystatus status; + + if (!key_call((u_long) KEY_SET, (xdrproc_t)xdr_keybuf, + (void *)secretkey, + (xdrproc_t)xdr_keystatus, &status)) { + return (-1); + } + if (status != KEY_SUCCESS) { + debug("set status is nonzero"); + return (-1); + } + return (0); } -__sym_compat(key_setsecret, __key_setsecret, FBSD_1.0); -static int -__key_secretkey_is_set(void) + +/* key_secretkey_is_set() returns 1 if the keyserver has a secret key + * stored for the caller's effective uid; it returns 0 otherwise + * + * N.B.: The KEY_NET_GET key call is undocumented. Applications shouldn't + * be using it, because it allows them to get the user's secret key. + */ + +int +key_secretkey_is_set(void) { + struct key_netstres kres; + + memset((void*)&kres, 0, sizeof (kres)); + if (key_call((u_long) KEY_NET_GET, (xdrproc_t)xdr_void, NULL, + (xdrproc_t)xdr_key_netstres, &kres) && + (kres.status == KEY_SUCCESS) && + (kres.key_netstres_u.knet.st_priv_key[0] != 0)) { + /* avoid leaving secret key in memory */ + memset(kres.key_netstres_u.knet.st_priv_key, 0, HEXKEYBYTES); + return (1); + } return (0); } -__sym_compat(key_secretkey_is_set, __key_secretkey_is_set, FBSD_1.0); -static int -__key_encryptsession_pk(char *remotename, netobj *remotekey, des_block *deskey) +int +key_encryptsession_pk(char *remotename, netobj *remotekey, des_block *deskey) { - return (-1); + cryptkeyarg2 arg; + cryptkeyres res; + + arg.remotename = remotename; + arg.remotekey = *remotekey; + arg.deskey = *deskey; + if (!key_call((u_long)KEY_ENCRYPT_PK, (xdrproc_t)xdr_cryptkeyarg2, &arg, + (xdrproc_t)xdr_cryptkeyres, &res)) { + return (-1); + } + if (res.status != KEY_SUCCESS) { + debug("encrypt status is nonzero"); + return (-1); + } + *deskey = res.cryptkeyres_u.deskey; + return (0); } -__sym_compat(key_encryptsession_pk, __key_encryptsession_pk, FBSD_1.0); -static int -__key_decryptsession_pk(char *remotename, netobj *remotekey, des_block *deskey) +int +key_decryptsession_pk(char *remotename, netobj *remotekey, des_block *deskey) { - return (-1); + cryptkeyarg2 arg; + cryptkeyres res; + + arg.remotename = remotename; + arg.remotekey = *remotekey; + arg.deskey = *deskey; + if (!key_call((u_long)KEY_DECRYPT_PK, (xdrproc_t)xdr_cryptkeyarg2, &arg, + (xdrproc_t)xdr_cryptkeyres, &res)) { + return (-1); + } + if (res.status != KEY_SUCCESS) { + debug("decrypt status is nonzero"); + return (-1); + } + *deskey = res.cryptkeyres_u.deskey; + return (0); } -__sym_compat(key_decryptsession_pk, __key_decryptsession_pk, FBSD_1.0); -static int -__key_encryptsession(const char *remotename, des_block *deskey) +int +key_encryptsession(const char *remotename, des_block *deskey) { - return (-1); + cryptkeyarg arg; + cryptkeyres res; + + arg.remotename = (char *) remotename; + arg.deskey = *deskey; + if (!key_call((u_long)KEY_ENCRYPT, (xdrproc_t)xdr_cryptkeyarg, &arg, + (xdrproc_t)xdr_cryptkeyres, &res)) { + return (-1); + } + if (res.status != KEY_SUCCESS) { + debug("encrypt status is nonzero"); + return (-1); + } + *deskey = res.cryptkeyres_u.deskey; + return (0); } -__sym_compat(key_encryptsession, __key_encryptsession, FBSD_1.0); -static int -__key_decryptsession(const char *remotename, des_block *deskey) +int +key_decryptsession(const char *remotename, des_block *deskey) { *** 2748 LINES SKIPPED ***