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 ***

Reply via email to