Revert "Remove Secure RPC DES authentication"

This reverts commit 7ac276298b.

Requested by:	kib
This commit is contained in:
Lexi Winter 2025-08-15 16:56:46 +01:00
parent 429152cb04
commit 837b13af68
32 changed files with 3141 additions and 108 deletions

View file

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

View file

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

View file

@ -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.

View file

@ -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_ */

View file

@ -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;

View file

@ -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"
static AUTH *
__authdes_seccreate(const char *servername, const u_int win,
#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 **);
/*
* 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);
}
__sym_compat(authdes_seccreate, __authdes_seccreate, FBSD_1.0);
u_char pkey_data[1024];
netobj pkey;
AUTH *dummy;
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)
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);
}
/*
* 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);
}

View file

@ -42,16 +42,44 @@
#include <rpc/auth_des.h>
#include "un-namespace.h"
static bool_t
__xdr_authdes_cred(XDR *xdrs, void *cred)
{
return (FALSE);
}
__sym_compat(xdr_authdes_cred, __xdr_authdes_cred, FBSD_1.0);
#define ATTEMPT(xdr_op) if (!(xdr_op)) return (FALSE)
static bool_t
__xdr_authdes_verf(XDR *xdrs, void *verf)
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);
}
}
bool_t
xdr_authdes_verf(XDR *xdrs, struct authdes_verf *verf)
{
/*
* 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);

View file

@ -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)
{
return (-1);
}
__sym_compat(key_setsecret, __key_setsecret, FBSD_1.0);
static int
__key_secretkey_is_set(void)
#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)
{
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_secretkey_is_set, __key_secretkey_is_set, FBSD_1.0);
/* 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);
}
int
key_encryptsession_pk(char *remotename, netobj *remotekey, des_block *deskey)
{
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);
}
int
key_decryptsession_pk(char *remotename, netobj *remotekey, des_block *deskey)
{
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);
}
int
key_encryptsession(const char *remotename, des_block *deskey)
{
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);
}
int
key_decryptsession(const char *remotename, des_block *deskey)
{
cryptkeyarg arg;
cryptkeyres res;
arg.remotename = (char *) remotename;
arg.deskey = *deskey;
if (!key_call((u_long)KEY_DECRYPT, (xdrproc_t)xdr_cryptkeyarg, &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);
}
int
key_gendes(des_block *key)
{
if (!key_call((u_long)KEY_GEN, (xdrproc_t)xdr_void, NULL,
(xdrproc_t)xdr_des_block, key)) {
return (-1);
}
return (0);
}
int
key_setnet(struct key_netstarg *arg)
{
keystatus status;
if (!key_call((u_long) KEY_NET_PUT, (xdrproc_t)xdr_key_netstarg, arg,
(xdrproc_t)xdr_keystatus, &status)){
return (-1);
}
if (status != KEY_SUCCESS) {
debug("key_setnet status is nonzero");
return (-1);
}
return (1);
}
int
key_get_conv(char *pkey, des_block *deskey)
{
cryptkeyres res;
if (!key_call((u_long) KEY_GET_CONV, (xdrproc_t)xdr_keybuf, pkey,
(xdrproc_t)xdr_cryptkeyres, &res)) {
return (-1);
}
if (res.status != KEY_SUCCESS) {
debug("get_conv status is nonzero");
return (-1);
}
*deskey = res.cryptkeyres_u.deskey;
return (0);
}
struct key_call_private {
CLIENT *client; /* Client handle */
pid_t pid; /* process-id at moment of creation */
uid_t uid; /* user-id at last authorization */
};
static struct key_call_private *key_call_private_main = NULL;
static thread_key_t key_call_key;
static once_t key_call_once = ONCE_INITIALIZER;
static int key_call_key_error;
static void
key_call_destroy(void *vp)
{
struct key_call_private *kcp = (struct key_call_private *)vp;
if (kcp) {
if (kcp->client)
clnt_destroy(kcp->client);
free(kcp);
}
}
static void
key_call_init(void)
{
key_call_key_error = thr_keycreate(&key_call_key, key_call_destroy);
}
/*
* Keep the handle cached. This call may be made quite often.
*/
static CLIENT *
getkeyserv_handle(int vers)
{
void *localhandle;
struct netconfig *nconf;
struct netconfig *tpconf;
struct key_call_private *kcp;
struct timeval wait_time;
struct utsname u;
int main_thread;
int fd;
#define TOTAL_TIMEOUT 30 /* total timeout talking to keyserver */
#define TOTAL_TRIES 5 /* Number of tries */
if ((main_thread = thr_main())) {
kcp = key_call_private_main;
} else {
if (thr_once(&key_call_once, key_call_init) != 0 ||
key_call_key_error != 0)
return ((CLIENT *) NULL);
kcp = (struct key_call_private *)thr_getspecific(key_call_key);
}
if (kcp == (struct key_call_private *)NULL) {
kcp = (struct key_call_private *)malloc(sizeof (*kcp));
if (kcp == (struct key_call_private *)NULL) {
return ((CLIENT *) NULL);
}
if (main_thread)
key_call_private_main = kcp;
else
thr_setspecific(key_call_key, (void *) kcp);
kcp->client = NULL;
}
/* if pid has changed, destroy client and rebuild */
if (kcp->client != NULL && kcp->pid != getpid()) {
clnt_destroy(kcp->client);
kcp->client = NULL;
}
if (kcp->client != NULL) {
/* if uid has changed, build client handle again */
if (kcp->uid != geteuid()) {
kcp->uid = geteuid();
auth_destroy(kcp->client->cl_auth);
kcp->client->cl_auth =
authsys_create("", kcp->uid, 0, 0, NULL);
if (kcp->client->cl_auth == NULL) {
clnt_destroy(kcp->client);
kcp->client = NULL;
return ((CLIENT *) NULL);
}
}
/* Change the version number to the new one */
clnt_control(kcp->client, CLSET_VERS, (void *)&vers);
return (kcp->client);
}
if (!(localhandle = setnetconfig())) {
return ((CLIENT *) NULL);
}
tpconf = NULL;
#if defined(__FreeBSD__)
if (uname(&u) == -1)
#else
#if defined(i386)
if (_nuname(&u) == -1)
#elif defined(sparc)
if (_uname(&u) == -1)
#else
#error Unknown architecture!
#endif
#endif
{
endnetconfig(localhandle);
return ((CLIENT *) NULL);
}
while ((nconf = getnetconfig(localhandle)) != NULL) {
if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
/*
* We use COTS_ORD here so that the caller can
* find out immediately if the server is dead.
*/
if (nconf->nc_semantics == NC_TPI_COTS_ORD) {
kcp->client = clnt_tp_create(u.nodename,
KEY_PROG, vers, nconf);
if (kcp->client)
break;
} else {
tpconf = nconf;
}
}
}
if ((kcp->client == (CLIENT *) NULL) && (tpconf))
/* Now, try the CLTS or COTS loopback transport */
kcp->client = clnt_tp_create(u.nodename,
KEY_PROG, vers, tpconf);
endnetconfig(localhandle);
if (kcp->client == (CLIENT *) NULL) {
return ((CLIENT *) NULL);
}
kcp->uid = geteuid();
kcp->pid = getpid();
kcp->client->cl_auth = authsys_create("", kcp->uid, 0, 0, NULL);
if (kcp->client->cl_auth == NULL) {
clnt_destroy(kcp->client);
kcp->client = NULL;
return ((CLIENT *) NULL);
}
wait_time.tv_sec = TOTAL_TIMEOUT/TOTAL_TRIES;
wait_time.tv_usec = 0;
(void) clnt_control(kcp->client, CLSET_RETRY_TIMEOUT,
(char *)&wait_time);
if (clnt_control(kcp->client, CLGET_FD, (char *)&fd))
_fcntl(fd, F_SETFD, 1); /* make it "close on exec" */
return (kcp->client);
}
/* returns 0 on failure, 1 on success */
static int
__key_encryptsession_pk(char *remotename, netobj *remotekey, des_block *deskey)
key_call(u_long proc, xdrproc_t xdr_arg, void *arg, xdrproc_t xdr_rslt,
void *rslt)
{
return (-1);
}
__sym_compat(key_encryptsession_pk, __key_encryptsession_pk, FBSD_1.0);
CLIENT *clnt;
struct timeval wait_time;
static int
__key_decryptsession_pk(char *remotename, netobj *remotekey, des_block *deskey)
{
return (-1);
}
__sym_compat(key_decryptsession_pk, __key_decryptsession_pk, FBSD_1.0);
if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL) {
cryptkeyres *res;
res = (*__key_encryptsession_pk_LOCAL)(geteuid(), arg);
*(cryptkeyres*)rslt = *res;
return (1);
} else if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL) {
cryptkeyres *res;
res = (*__key_decryptsession_pk_LOCAL)(geteuid(), arg);
*(cryptkeyres*)rslt = *res;
return (1);
} else if (proc == KEY_GEN && __key_gendes_LOCAL) {
des_block *res;
res = (*__key_gendes_LOCAL)(geteuid(), 0);
*(des_block*)rslt = *res;
return (1);
}
static int
__key_encryptsession(const char *remotename, des_block *deskey)
{
return (-1);
}
__sym_compat(key_encryptsession, __key_encryptsession, FBSD_1.0);
if ((proc == KEY_ENCRYPT_PK) || (proc == KEY_DECRYPT_PK) ||
(proc == KEY_NET_GET) || (proc == KEY_NET_PUT) ||
(proc == KEY_GET_CONV))
clnt = getkeyserv_handle(2); /* talk to version 2 */
else
clnt = getkeyserv_handle(1); /* talk to version 1 */
static int
__key_decryptsession(const char *remotename, des_block *deskey)
{
return (-1);
}
__sym_compat(key_decryptsession, __key_decryptsession, FBSD_1.0);
if (clnt == NULL) {
return (0);
}
static int
__key_gendes(des_block *key)
{
return (-1);
}
__sym_compat(key_gendes, __key_gendes, FBSD_1.0);
wait_time.tv_sec = TOTAL_TIMEOUT;
wait_time.tv_usec = 0;
static int
__key_setnet(struct key_netstarg *arg)
{
return (-1);
if (clnt_call(clnt, proc, xdr_arg, arg, xdr_rslt, rslt,
wait_time) == RPC_SUCCESS) {
return (1);
} else {
return (0);
}
}
__sym_compat(key_setnet, __key_setnet, FBSD_1.0);
static int
__key_get_conv(char *pkey, des_block *deskey)
{
return (-1);
}
__sym_compat(key_get_conv, __key_get_conv, FBSD_1.0);

40
lib/libc/rpc/publickey.5 Normal file
View file

@ -0,0 +1,40 @@
.Dd October 19, 1987
.Dt PUBLICKEY 5
.Os
.Sh NAME
.Nm publickey
.Nd "public key database"
.Sh SYNOPSIS
.Pa /etc/publickey
.Sh DESCRIPTION
.Pa /etc/publickey
is the public key database used for secure
RPC (Remote Procedure Calls).
Each entry in
the database consists of a network user
name (which may either refer to
a user or a hostname), followed by the user's
public key (in hex
notation), a colon, and then the user's
secret key encrypted with
its login password (also in hex notation).
.Pp
This file is altered either by the user through the
.Xr chkey 1
command or by the system administrator through the
.Xr newkey 8
command.
The file
.Pa /etc/publickey
should only contain data on the
.Tn NIS
master machine, where it
is converted into the
.Tn NIS
database
.Pa publickey.byname .
.Sh SEE ALSO
.Xr chkey 1 ,
.Xr publickey 3 ,
.Xr newkey 8 ,
.Xr ypupdated 8

View file

@ -1,17 +1,34 @@
.\"
.Dd August 10, 2025
.Dt RPC_SECURE 3
.Dd February 16, 1988
.Dt RPC 3
.Os
.Sh NAME
.Nm rpc_secure
.Nd library routines for secure remote procedure calls
.Sh SYNOPSIS
.In rpc/rpc.h
.Ft AUTH *
.Fo authdes_create
.Fa "char *name"
.Fa "unsigned window"
.Fa "struct sockaddr *addr"
.Fa "des_block *ckey"
.Fc
.Ft int
.Fn authdes_getucred "struct authdes_cred *adc" "uid_t *uid" "gid_t *gid" "int *grouplen" "gid_t *groups"
.Ft int
.Fn getnetname "char *name"
.Ft int
.Fn host2netname "char *name" "const char *host" "const char *domain"
.Ft int
.Fn key_decryptsession "const char *remotename" "des_block *deskey"
.Ft int
.Fn key_encryptsession "const char *remotename" "des_block *deskey"
.Ft int
.Fn key_gendes "des_block *deskey"
.Ft int
.Fn key_setsecret "const char *key"
.Ft int
.Fn netname2host "char *name" "char *host" "int hostlen"
.Ft int
.Fn netname2user "char *name" "uid_t *uidp" "gid_t *gidp" "int *gidlenp" "gid_t *gidlist"
@ -21,11 +38,101 @@
These routines are part of the
.Tn RPC
library.
They implement
.Tn DES
Authentication.
See
.Xr rpc 3
for further details about
.Tn RPC .
.Pp
The
.Fn authdes_create
is the first of two routines which interface to the
.Tn RPC
secure authentication system, known as
.Tn DES
authentication.
The second is
.Fn authdes_getucred ,
below.
.Pp
Note: the keyserver daemon
.Xr keyserv 8
must be running for the
.Tn DES
authentication system to work.
.Pp
The
.Fn authdes_create
function,
used on the client side, returns an authentication handle that
will enable the use of the secure authentication system.
The first argument
.Fa name
is the network name, or
.Fa netname ,
of the owner of the server process.
This field usually
represents a
.Fa hostname
derived from the utility routine
.Fn host2netname ,
but could also represent a user name using
.Fn user2netname .
The second field is window on the validity of
the client credential, given in seconds.
A small
window is more secure than a large one, but choosing
too small of a window will increase the frequency of
resynchronizations because of clock drift.
The third
argument
.Fa addr
is optional.
If it is
.Dv NULL ,
then the authentication system will assume
that the local clock is always in sync with the server's
clock, and will not attempt resynchronizations.
If an address
is supplied, however, then the system will use the address
for consulting the remote time service whenever
resynchronization
is required.
This argument is usually the
address of the
.Tn RPC
server itself.
The final argument
.Fa ckey
is also optional.
If it is
.Dv NULL ,
then the authentication system will
generate a random
.Tn DES
key to be used for the encryption of credentials.
If it is supplied, however, then it will be used instead.
.Pp
The
.Fn authdes_getucred
function,
the second of the two
.Tn DES
authentication routines,
is used on the server side for converting a
.Tn DES
credential, which is
operating system independent, into a
.Ux
credential.
This routine differs from utility routine
.Fn netname2user
in that
.Fn authdes_getucred
pulls its information from a cache, and does not have to do a
Yellow Pages lookup every time it is called to get its information.
.Pp
The
.Fn getnetname
@ -54,6 +161,72 @@ Inverse of
.Fn netname2host .
.Pp
The
.Fn key_decryptsession
function
is an interface to the keyserver daemon, which is associated
with
.Tn RPC Ns 's
secure authentication system
.Tn ( DES
authentication).
User programs rarely need to call it, or its associated routines
.Fn key_encryptsession ,
.Fn key_gendes
and
.Fn key_setsecret .
System commands such as
.Xr login 1
and the
.Tn RPC
library are the main clients of these four routines.
.Pp
The
.Fn key_decryptsession
function
takes a server netname and a
.Tn DES
key, and decrypts the key by
using the public key of the server and the secret key
associated with the effective uid of the calling process.
It
is the inverse of
.Fn key_encryptsession .
.Pp
The
.Fn key_encryptsession
function
is a keyserver interface routine.
It
takes a server netname and a des key, and encrypts
it using the public key of the server and the secret key
associated with the effective uid of the calling process.
It
is the inverse of
.Fn key_decryptsession .
.Pp
The
.Fn key_gendes
function
is a keyserver interface routine.
It
is used to ask the keyserver for a secure conversation key.
Choosing one
.Qq random
is usually not good enough,
because
the common ways of choosing random numbers, such as using the
current time, are very easy to guess.
.Pp
The
.Fn key_setsecret
function
is a keyserver interface routine.
It is used to set the key for
the effective
.Fa uid
of the calling process.
.Pp
The
.Fn netname2host
function
converts from an operating-system independent netname to a

View file

@ -1,6 +1,6 @@
.\" $NetBSD: rpc_soc.3,v 1.2 2000/06/07 13:39:43 simonb Exp $
.\"
.Dd August 10, 2025
.Dd February 16, 1988
.Dt RPC_SOC 3
.Os
.Sh NAME
@ -100,6 +100,16 @@ to perform the requested service, and then sends back a
reply.
Finally, the procedure call returns to the client.
.Pp
Routines that are used for Secure
.Tn RPC ( DES
authentication) are described in
.Xr rpc_secure 3 .
Secure
.Tn RPC
can be used only if
.Tn DES
encryption is available.
.Pp
.Bl -tag -width indent -compact
.It Xo
.Ft void
@ -1691,6 +1701,7 @@ This routine modifies the global variable
Service implementors usually do not need this routine.
.El
.Sh SEE ALSO
.Xr rpc_secure 3 ,
.Xr xdr 3
.Rs
.%T "Remote Procedure Calls: Protocol Specification"

View file

@ -379,13 +379,36 @@ clnt_broadcast(u_long prog, u_long vers, u_long proc, xdrproc_t xargs,
* Create the client des authentication object. Obsoleted by
* authdes_seccreate().
*/
static AUTH *
__authdes_create(char *servername, u_int window, struct sockaddr *syncaddr,
AUTH *
authdes_create(char *servername, u_int window, struct sockaddr *syncaddr,
des_block *ckey)
/*
* char *servername; // network name of server
* u_int window; // time to live
* struct sockaddr *syncaddr; // optional hostaddr to sync with
* des_block *ckey; // optional conversation key to use
*/
{
return (NULL);
AUTH *dummy;
AUTH *nauth;
char hostname[NI_MAXHOST];
if (syncaddr) {
/*
* Change addr to hostname, because that is the way
* new interface takes it.
*/
if (getnameinfo(syncaddr, syncaddr->sa_len, hostname,
sizeof hostname, NULL, 0, 0) != 0)
goto fallback;
nauth = authdes_seccreate(servername, window, hostname, ckey);
return (nauth);
}
fallback:
dummy = authdes_seccreate(servername, window, NULL, ckey);
return (dummy);
}
__sym_compat(authdes_create, __authdes_create, FBSD_1.0);
/*
* Create a client handle for a unix connection. Obsoleted by clnt_vc_create()

View file

@ -114,6 +114,11 @@ _authenticate(struct svc_req *rqst, struct rpc_msg *msg)
case AUTH_SHORT:
dummy = _svcauth_short(rqst, msg);
return (dummy);
#ifdef DES_BUILTIN
case AUTH_DES:
dummy = _svcauth_des(rqst, msg);
return (dummy);
#endif
default:
break;
}
@ -181,6 +186,9 @@ svc_auth_reg(int cred_flavor,
case AUTH_NULL:
case AUTH_SYS:
case AUTH_SHORT:
#ifdef DES_BUILTIN
case AUTH_DES:
#endif
/* already registered */
return (1);

View file

@ -34,8 +34,17 @@
*/
/*
* svcauth_des.c, server-side des authentication.
* This functionality was removed in FreeBSD 15.0.
* svcauth_des.c, server-side des authentication
*
* We insure for the service the following:
* (1) The timestamp microseconds do not exceed 1 million.
* (2) The timestamp plus the window is less than the current time.
* (3) The timestamp is not less than the one previously
* seen in the current session.
*
* It is up to the server to determine if the window size is
* too small .
*
*/
#include "namespace.h"
@ -56,16 +65,384 @@
#include <rpc/svc_auth.h>
#include "libc_private.h"
extern int key_decryptsession_pk(const char *, netobj *, des_block *);
#define debug(msg) printf("svcauth_des: %s\n", msg)
#define USEC_PER_SEC ((u_long) 1000000L)
#define BEFORE(t1, t2) timercmp(t1, t2, <)
/*
* LRU cache of conversation keys and some other useful items.
*/
#define AUTHDES_CACHESZ 64
struct cache_entry {
des_block key; /* conversation key */
char *rname; /* client's name */
u_int window; /* credential lifetime window */
struct timeval laststamp; /* detect replays of creds */
char *localcred; /* generic local credential */
};
static struct cache_entry *authdes_cache/* [AUTHDES_CACHESZ] */;
static short *authdes_lru/* [AUTHDES_CACHESZ] */;
static void cache_init(void); /* initialize the cache */
static short cache_spot(des_block *, char *, struct timeval *); /* find an entry in the cache */
static void cache_ref(short sid); /* note that sid was ref'd */
static void invalidate(char *); /* invalidate entry in cache */
/*
* cache statistics
*/
static struct {
u_long ncachehits; /* times cache hit, and is not replay */
u_long ncachereplays; /* times cache hit, and is replay */
u_long ncachemisses; /* times cache missed */
} svcauthdes_stats;
/*
* Service side authenticator for AUTH_DES
*/
static enum auth_stat
__svcauth_des(struct svc_req *rqst, struct rpc_msg *msg)
enum auth_stat
_svcauth_des(struct svc_req *rqst, struct rpc_msg *msg)
{
return (AUTH_FAILED);
}
__sym_compat(_svcauth_des, __svcauth_des, FBSD_1.0);
long *ixdr;
des_block cryptbuf[2];
struct authdes_cred *cred;
struct authdes_verf verf;
int status;
struct cache_entry *entry;
short sid = 0;
des_block *sessionkey;
des_block ivec;
u_int window;
struct timeval timestamp;
u_long namelen;
struct area {
struct authdes_cred area_cred;
char area_netname[MAXNETNAMELEN+1];
} *area;
if (authdes_cache == NULL) {
cache_init();
}
area = (struct area *)rqst->rq_clntcred;
cred = (struct authdes_cred *)&area->area_cred;
/*
* Get the credential
*/
ixdr = (long *)msg->rm_call.cb_cred.oa_base;
cred->adc_namekind = IXDR_GET_ENUM(ixdr, enum authdes_namekind);
switch (cred->adc_namekind) {
case ADN_FULLNAME:
namelen = IXDR_GET_U_LONG(ixdr);
if (namelen > MAXNETNAMELEN) {
return (AUTH_BADCRED);
}
cred->adc_fullname.name = area->area_netname;
bcopy((char *)ixdr, cred->adc_fullname.name,
(u_int)namelen);
cred->adc_fullname.name[namelen] = 0;
ixdr += (RNDUP(namelen) / BYTES_PER_XDR_UNIT);
cred->adc_fullname.key.key.high = (u_long)*ixdr++;
cred->adc_fullname.key.key.low = (u_long)*ixdr++;
cred->adc_fullname.window = (u_long)*ixdr++;
break;
case ADN_NICKNAME:
cred->adc_nickname = (u_long)*ixdr++;
break;
default:
return (AUTH_BADCRED);
}
/*
* Get the verifier
*/
ixdr = (long *)msg->rm_call.cb_verf.oa_base;
verf.adv_xtimestamp.key.high = (u_long)*ixdr++;
verf.adv_xtimestamp.key.low = (u_long)*ixdr++;
verf.adv_int_u = (u_long)*ixdr++;
/*
* Get the conversation key
*/
if (cred->adc_namekind == ADN_FULLNAME) {
netobj pkey;
char pkey_data[1024];
sessionkey = &cred->adc_fullname.key;
if (! getpublickey(cred->adc_fullname.name, pkey_data)) {
debug("getpublickey");
return(AUTH_BADCRED);
}
pkey.n_bytes = pkey_data;
pkey.n_len = strlen(pkey_data) + 1;
if (key_decryptsession_pk(cred->adc_fullname.name, &pkey,
sessionkey) < 0) {
debug("decryptsessionkey");
return (AUTH_BADCRED); /* key not found */
}
} else { /* ADN_NICKNAME */
sid = (short)cred->adc_nickname;
if (sid < 0 || sid >= AUTHDES_CACHESZ) {
debug("bad nickname");
return (AUTH_BADCRED); /* garbled credential */
}
sessionkey = &authdes_cache[sid].key;
}
/*
* Decrypt the timestamp
*/
cryptbuf[0] = verf.adv_xtimestamp;
if (cred->adc_namekind == ADN_FULLNAME) {
cryptbuf[1].key.high = cred->adc_fullname.window;
cryptbuf[1].key.low = verf.adv_winverf;
ivec.key.high = ivec.key.low = 0;
status = cbc_crypt((char *)sessionkey, (char *)cryptbuf,
2*sizeof(des_block), DES_DECRYPT | DES_HW,
(char *)&ivec);
} else {
status = ecb_crypt((char *)sessionkey, (char *)cryptbuf,
sizeof(des_block), DES_DECRYPT | DES_HW);
}
if (DES_FAILED(status)) {
debug("decryption failure");
return (AUTH_FAILED); /* system error */
}
/*
* XDR the decrypted timestamp
*/
ixdr = (long *)cryptbuf;
timestamp.tv_sec = IXDR_GET_LONG(ixdr);
timestamp.tv_usec = IXDR_GET_LONG(ixdr);
/*
* Check for valid credentials and verifiers.
* They could be invalid because the key was flushed
* out of the cache, and so a new session should begin.
* Be sure and send AUTH_REJECTED{CRED, VERF} if this is the case.
*/
{
struct timeval current;
int nick;
int winverf;
if (cred->adc_namekind == ADN_FULLNAME) {
window = IXDR_GET_U_LONG(ixdr);
winverf = IXDR_GET_U_LONG(ixdr);
if (winverf != window - 1) {
debug("window verifier mismatch");
return (AUTH_BADCRED); /* garbled credential */
}
sid = cache_spot(sessionkey, cred->adc_fullname.name,
&timestamp);
if (sid < 0) {
debug("replayed credential");
return (AUTH_REJECTEDCRED); /* replay */
}
nick = 0;
} else { /* ADN_NICKNAME */
window = authdes_cache[sid].window;
nick = 1;
}
if ((u_long)timestamp.tv_usec >= USEC_PER_SEC) {
debug("invalid usecs");
/* cached out (bad key), or garbled verifier */
return (nick ? AUTH_REJECTEDVERF : AUTH_BADVERF);
}
if (nick && BEFORE(&timestamp,
&authdes_cache[sid].laststamp)) {
debug("timestamp before last seen");
return (AUTH_REJECTEDVERF); /* replay */
}
(void)gettimeofday(&current, NULL);
current.tv_sec -= window; /* allow for expiration */
if (!BEFORE(&current, &timestamp)) {
debug("timestamp expired");
/* replay, or garbled credential */
return (nick ? AUTH_REJECTEDVERF : AUTH_BADCRED);
}
}
/*
* Set up the reply verifier
*/
verf.adv_nickname = (u_long)sid;
/*
* xdr the timestamp before encrypting
*/
ixdr = (long *)cryptbuf;
IXDR_PUT_LONG(ixdr, timestamp.tv_sec - 1);
IXDR_PUT_LONG(ixdr, timestamp.tv_usec);
/*
* encrypt the timestamp
*/
status = ecb_crypt((char *)sessionkey, (char *)cryptbuf,
sizeof(des_block), DES_ENCRYPT | DES_HW);
if (DES_FAILED(status)) {
debug("encryption failure");
return (AUTH_FAILED); /* system error */
}
verf.adv_xtimestamp = cryptbuf[0];
/*
* Serialize the reply verifier, and update rqst
*/
ixdr = (long *)msg->rm_call.cb_verf.oa_base;
*ixdr++ = (long)verf.adv_xtimestamp.key.high;
*ixdr++ = (long)verf.adv_xtimestamp.key.low;
*ixdr++ = (long)verf.adv_int_u;
rqst->rq_xprt->xp_verf.oa_flavor = AUTH_DES;
rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base;
rqst->rq_xprt->xp_verf.oa_length =
(char *)ixdr - msg->rm_call.cb_verf.oa_base;
/*
* We succeeded, commit the data to the cache now and
* finish cooking the credential.
*/
entry = &authdes_cache[sid];
entry->laststamp = timestamp;
cache_ref(sid);
if (cred->adc_namekind == ADN_FULLNAME) {
cred->adc_fullname.window = window;
cred->adc_nickname = (u_long)sid; /* save nickname */
if (entry->rname != NULL) {
mem_free(entry->rname, strlen(entry->rname) + 1);
}
entry->rname = (char *)mem_alloc((u_int)strlen(cred->adc_fullname.name)
+ 1);
if (entry->rname != NULL) {
(void) strcpy(entry->rname, cred->adc_fullname.name);
} else {
debug("out of memory");
}
entry->key = *sessionkey;
entry->window = window;
invalidate(entry->localcred); /* mark any cached cred invalid */
} else { /* ADN_NICKNAME */
/*
* nicknames are cooked into fullnames
*/
cred->adc_namekind = ADN_FULLNAME;
cred->adc_fullname.name = entry->rname;
cred->adc_fullname.key = entry->key;
cred->adc_fullname.window = entry->window;
}
return (AUTH_OK); /* we made it!*/
}
/*
* Initialize the cache
*/
static void
cache_init(void)
{
int i;
authdes_cache = (struct cache_entry *)
mem_alloc(sizeof(struct cache_entry) * AUTHDES_CACHESZ);
bzero((char *)authdes_cache,
sizeof(struct cache_entry) * AUTHDES_CACHESZ);
authdes_lru = (short *)mem_alloc(sizeof(short) * AUTHDES_CACHESZ);
/*
* Initialize the lru list
*/
for (i = 0; i < AUTHDES_CACHESZ; i++) {
authdes_lru[i] = i;
}
}
/*
* Find the lru victim
*/
static short
cache_victim(void)
{
return (authdes_lru[AUTHDES_CACHESZ-1]);
}
/*
* Note that sid was referenced
*/
static void
cache_ref(short sid)
{
int i;
short curr;
short prev;
prev = authdes_lru[0];
authdes_lru[0] = sid;
for (i = 1; prev != sid; i++) {
curr = authdes_lru[i];
authdes_lru[i] = prev;
prev = curr;
}
}
/*
* Find a spot in the cache for a credential containing
* the items given. Return -1 if a replay is detected, otherwise
* return the spot in the cache.
*/
static short
cache_spot(des_block *key, char *name, struct timeval *timestamp)
{
struct cache_entry *cp;
int i;
u_long hi;
hi = key->key.high;
for (cp = authdes_cache, i = 0; i < AUTHDES_CACHESZ; i++, cp++) {
if (cp->key.key.high == hi &&
cp->key.key.low == key->key.low &&
cp->rname != NULL &&
bcmp(cp->rname, name, strlen(name) + 1) == 0) {
if (BEFORE(timestamp, &cp->laststamp)) {
svcauthdes_stats.ncachereplays++;
return (-1); /* replay */
}
svcauthdes_stats.ncachehits++;
return (i); /* refresh */
}
}
svcauthdes_stats.ncachemisses++;
return (cache_victim()); /* new credential */
}
#if (defined(sun) || defined(vax) || defined(__FreeBSD__))
/*
* Local credential handling stuff.
* NOTE: bsd unix dependent.
* Other operating systems should put something else here.
*/
#define UNKNOWN -2 /* grouplen, if cached cred is unknown user */
#define INVALID -1 /* grouplen, if cache entry is invalid */
struct bsdcred {
uid_t uid; /* cached uid */
gid_t gid; /* cached gid */
int grouplen; /* length of cached groups */
gid_t groups[NGRPS]; /* cached groups */
};
/*
* Map a des credential into a unix cred.
@ -73,10 +450,73 @@ __sym_compat(_svcauth_des, __svcauth_des, FBSD_1.0);
* not have to make an rpc call every time to interpret
* the credential.
*/
static int
__authdes_getucred(void *adc, uid_t *uid, gid_t *gid,
int
authdes_getucred(struct authdes_cred *adc, uid_t *uid, gid_t *gid,
int *grouplen, gid_t *groups)
{
return (0);
unsigned sid;
int i;
uid_t i_uid;
gid_t i_gid;
int i_grouplen;
struct bsdcred *cred;
sid = adc->adc_nickname;
if (sid >= AUTHDES_CACHESZ) {
debug("invalid nickname");
return (0);
}
cred = (struct bsdcred *)authdes_cache[sid].localcred;
if (cred == NULL) {
cred = (struct bsdcred *)mem_alloc(sizeof(struct bsdcred));
authdes_cache[sid].localcred = (char *)cred;
cred->grouplen = INVALID;
}
if (cred->grouplen == INVALID) {
/*
* not in cache: lookup
*/
if (!netname2user(adc->adc_fullname.name, &i_uid, &i_gid,
&i_grouplen, groups))
{
debug("unknown netname");
cred->grouplen = UNKNOWN; /* mark as lookup up, but not found */
return (0);
}
debug("missed ucred cache");
*uid = cred->uid = i_uid;
*gid = cred->gid = i_gid;
*grouplen = cred->grouplen = i_grouplen;
for (i = i_grouplen - 1; i >= 0; i--) {
cred->groups[i] = groups[i]; /* int to short */
}
return (1);
} else if (cred->grouplen == UNKNOWN) {
/*
* Already lookup up, but no match found
*/
return (0);
}
/*
* cached credentials
*/
*uid = cred->uid;
*gid = cred->gid;
*grouplen = cred->grouplen;
for (i = cred->grouplen - 1; i >= 0; i--) {
groups[i] = cred->groups[i]; /* short to int */
}
return (1);
}
__sym_compat(authdes_getucred, __authdes_getucred, FBSD_1.0);
static void
invalidate(char *cred)
{
if (cred == NULL) {
return;
}
((struct bsdcred *)cred)->grouplen = INVALID;
}
#endif

View file

@ -14,7 +14,7 @@ OTHERSRCS= rnusers.c rstat.c rwall.c
SECRPCSRCS= secretkey.c xcrypt.c
.if ${MK_NIS} != "no"
OTHERSRCS+= yp_passwd.c
OTHERSRCS+= yp_passwd.c yp_update.c
.endif
RPCCOM= RPCGEN_CPP=${CPP:Q} rpcgen -C

199
lib/librpcsvc/yp_update.c Normal file
View file

@ -0,0 +1,199 @@
/*-
* SPDX-License-Identifier: BSD-4-Clause
*
* Copyright (c) 1995, 1996
* Bill Paul <wpaul@ctr.columbia.edu>. 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 acknowledgement:
* This product includes software developed by Bill Paul.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS 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 Bill Paul OR 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.
*
* ypupdate client-side library function.
*
* Written by Bill Paul <wpaul@ctr.columbia.edu>
* Center for Telecommunications Research
* Columbia University, New York City
*/
#include <sys/cdefs.h>
#include <stdlib.h>
#include <rpc/rpc.h>
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
#include <rpcsvc/ypupdate_prot.h>
#include <rpc/key_prot.h>
#ifndef WINDOW
#define WINDOW (60*60)
#endif
#ifndef TIMEOUT
#define TIMEOUT 300
#endif
int
yp_update(char *domain, char *map, unsigned int ypop, char *key, int keylen,
char *data, int datalen)
{
char *master;
int rval;
unsigned int res;
struct ypupdate_args upargs;
struct ypdelete_args delargs;
CLIENT *clnt;
char netname[MAXNETNAMELEN+1];
des_block des_key;
struct timeval timeout;
/* Get the master server name for 'domain.' */
if ((rval = yp_master(domain, map, &master)))
return(rval);
/* Check that ypupdated is running there. */
if (getrpcport(master, YPU_PROG, YPU_VERS, ypop))
return(YPERR_DOMAIN);
/* Get a handle. */
if ((clnt = clnt_create(master, YPU_PROG, YPU_VERS, "tcp")) == NULL)
return(YPERR_RPC);
/*
* Assemble netname of server.
* NOTE: It's difficult to discern from the documentation, but
* when you make a Secure RPC call, the netname you pass should
* be the netname of the guy on the other side, not your own
* netname. This is how the client side knows what public key
* to use for the initial exchange. Passing your own netname
* only works if the server on the other side is running under
* your UID.
*/
if (!host2netname(netname, master, domain)) {
clnt_destroy(clnt);
return(YPERR_BADARGS);
}
/* Make up a DES session key. */
key_gendes(&des_key);
/* Set up DES authentication. */
if ((clnt->cl_auth = (AUTH *)authdes_create(netname, WINDOW, NULL,
&des_key)) == NULL) {
clnt_destroy(clnt);
return(YPERR_RESRC);
}
/* Set a timeout for clnt_call(). */
timeout.tv_usec = 0;
timeout.tv_sec = TIMEOUT;
/*
* Make the call. Note that we use clnt_call() here rather than
* the rpcgen-erated client stubs. We could use those stubs, but
* then we'd have to do some gymnastics to get at the error
* information to figure out what error code to send back to the
* caller. With clnt_call(), we get the error status returned to
* us right away, and we only have to exert a small amount of
* extra effort.
*/
switch (ypop) {
case YPOP_CHANGE:
upargs.mapname = map;
upargs.key.yp_buf_len = keylen;
upargs.key.yp_buf_val = key;
upargs.datum.yp_buf_len = datalen;
upargs.datum.yp_buf_val = data;
if ((rval = clnt_call(clnt, YPU_CHANGE,
(xdrproc_t)xdr_ypupdate_args, &upargs,
(xdrproc_t)xdr_u_int, &res, timeout)) != RPC_SUCCESS) {
if (rval == RPC_AUTHERROR)
res = YPERR_ACCESS;
else
res = YPERR_RPC;
}
break;
case YPOP_INSERT:
upargs.mapname = map;
upargs.key.yp_buf_len = keylen;
upargs.key.yp_buf_val = key;
upargs.datum.yp_buf_len = datalen;
upargs.datum.yp_buf_val = data;
if ((rval = clnt_call(clnt, YPU_INSERT,
(xdrproc_t)xdr_ypupdate_args, &upargs,
(xdrproc_t)xdr_u_int, &res, timeout)) != RPC_SUCCESS) {
if (rval == RPC_AUTHERROR)
res = YPERR_ACCESS;
else
res = YPERR_RPC;
}
break;
case YPOP_DELETE:
delargs.mapname = map;
delargs.key.yp_buf_len = keylen;
delargs.key.yp_buf_val = key;
if ((rval = clnt_call(clnt, YPU_DELETE,
(xdrproc_t)xdr_ypdelete_args, &delargs,
(xdrproc_t)xdr_u_int, &res, timeout)) != RPC_SUCCESS) {
if (rval == RPC_AUTHERROR)
res = YPERR_ACCESS;
else
res = YPERR_RPC;
}
break;
case YPOP_STORE:
upargs.mapname = map;
upargs.key.yp_buf_len = keylen;
upargs.key.yp_buf_val = key;
upargs.datum.yp_buf_len = datalen;
upargs.datum.yp_buf_val = data;
if ((rval = clnt_call(clnt, YPU_STORE,
(xdrproc_t)xdr_ypupdate_args, &upargs,
(xdrproc_t)xdr_u_int, &res, timeout)) != RPC_SUCCESS) {
if (rval == RPC_AUTHERROR)
res = YPERR_ACCESS;
else
res = YPERR_RPC;
}
break;
default:
res = YPERR_BADARGS;
break;
}
/* All done: tear down the connection. */
auth_destroy(clnt->cl_auth);
clnt_destroy(clnt);
free(master);
return(res);
}

View file

@ -396,6 +396,7 @@ rpc_statd_flags="" # Flags to rpc.statd (if enabled).
rpcbind_enable="NO" # Run the portmapper service (YES/NO).
rpcbind_program="/usr/sbin/rpcbind" # path to rpcbind, if you want a different one.
rpcbind_flags="" # Flags to rpcbind (if enabled).
rpc_ypupdated_enable="NO" # Run if NIS master and SecureRPC (or NO).
nfsv4_server_enable="NO" # Enable support for NFSv4
nfsv4_server_only="NO" # Set NFS server to NFSv4 only
nfscbd_enable="NO" # NFSv4 client side callback daemon

View file

@ -318,6 +318,7 @@ YP= ypbind \
yppasswdd \
ypserv \
ypset \
ypupdated \
ypxfrd \
nisdomain
YPPACKAGE= yp

35
libexec/rc/rc.d/ypupdated Executable file
View file

@ -0,0 +1,35 @@
#!/bin/sh
#
#
# PROVIDE: ypupdated
# REQUIRE: rpcbind ypserv
# KEYWORD: shutdown
. /etc/rc.subr
name="ypupdated"
rcvar="rpc_ypupdated_enable"
: ${ypupdated_svcj_options:="net_basic"}
load_rc_config $name
command="/usr/sbin/rpc.${name}"
start_precmd="rpc_ypupdated_precmd"
rpc_ypupdated_precmd()
{
local _domain
force_depend rpcbind || return 1
force_depend ypserv nis_server || return 1
_domain=`domainname`
if [ -z "$_domain" ]; then
warn "NIS domainname(1) is not set."
return 1
fi
}
run_rc_command "$1"

View file

@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd August 10, 2025
.Dd July 15, 2025
.Dt RC.CONF 5
.Os
.Sh NAME
@ -2932,6 +2932,13 @@ is set to
these are the flags to pass to the
.Xr rpc.yppasswdd 8
daemon.
.It Va rpc_ypupdated_enable
.Pq Vt bool
If set to
.Dq Li YES ,
run the
.Nm rpc.ypupdated
daemon at system boot time.
.It Va bsnmpd_enable
.Pq Vt bool
If set to

View file

@ -246,6 +246,19 @@ extern AUTH *authunix_create_default(void); /* takes no parameters */
extern AUTH *authnone_create(void); /* takes no parameters */
extern AUTH *authtls_create(void); /* takes no parameters */
__END_DECLS
/*
* DES style authentication
* AUTH *authsecdes_create(servername, window, timehost, ckey)
* char *servername; - network name of server
* u_int window; - time to live
* const char *timehost; - optional hostname to sync with
* des_block *ckey; - optional conversation key to use
*/
__BEGIN_DECLS
extern AUTH *authdes_create (char *, u_int, struct sockaddr *, des_block *);
extern AUTH *authdes_seccreate (const char *, const u_int, const char *,
const des_block *);
__END_DECLS
__BEGIN_DECLS
extern bool_t xdr_opaque_auth (XDR *, struct opaque_auth *);
@ -266,6 +279,19 @@ extern int netname2host(char *, char *, const int);
extern void passwd2des ( char *, char * );
__END_DECLS
/*
*
* These routines interface to the keyserv daemon
*
*/
__BEGIN_DECLS
extern int key_decryptsession(const char *, des_block *);
extern int key_encryptsession(const char *, des_block *);
extern int key_gendes(des_block *);
extern int key_setsecret(const char *);
extern int key_secretkey_is_set(void);
__END_DECLS
/*
* Publickey routines.
*/

View file

@ -8874,6 +8874,7 @@ OLD_FILES+=etc/rc.d/ypldap
OLD_FILES+=etc/rc.d/yppasswdd
OLD_FILES+=etc/rc.d/ypserv
OLD_FILES+=etc/rc.d/ypset
OLD_FILES+=etc/rc.d/ypupdated
OLD_FILES+=etc/rc.d/ypxfrd
OLD_FILES+=usr/bin/ypcat
OLD_FILES+=usr/bin/ypchfn
@ -8891,6 +8892,7 @@ OLD_FILES+=usr/libexec/mknetid
OLD_FILES+=usr/libexec/yppwupdate
OLD_FILES+=usr/libexec/ypxfr
OLD_FILES+=usr/sbin/rpc.yppasswdd
OLD_FILES+=usr/sbin/rpc.ypupdated
OLD_FILES+=usr/sbin/rpc.ypxfrd
OLD_FILES+=usr/sbin/yp_mkdb
OLD_FILES+=usr/sbin/ypbind

View file

@ -174,6 +174,7 @@ SUBDIR.${MK_NETGRAPH}+= flowctl
SUBDIR.${MK_NETGRAPH}+= ngctl
SUBDIR.${MK_NETGRAPH}+= nghook
SUBDIR.${MK_NIS}+= rpc.yppasswdd
SUBDIR.${MK_NIS}+= rpc.ypupdated
SUBDIR.${MK_NIS}+= rpc.ypxfrd
SUBDIR.${MK_NIS}+= ypbind
SUBDIR.${MK_NIS}+= ypldap

View file

@ -0,0 +1,32 @@
.PATH: ${SRCTOP}/usr.sbin/ypserv ${SRCTOP}/libexec/ypxfr
PACKAGE=yp
PROG= rpc.ypupdated
MAN=
SRCS= ypupdate_prot_svc.c ypupdate_prot.h ypupdated_main.c \
yp_error.c update.c ypupdated_server.c \
yp_dblookup.c yp_dbwrite.c yp_dbdelete.c yp_dbupdate.c
#CFLAGS+= -DYP
CFLAGS+= -I${SRCTOP}/usr.sbin/ypserv -I. -I${SRCTOP}/libexec/ypxfr
WARNS?= 1
LIBADD= rpcsvc
CLEANFILES= ypupdate_prot_svc.c ypupdate_prot.h
RPCDIR= ${SYSROOT:U${DESTDIR}}/usr/include/rpcsvc
RPCGEN= RPCGEN_CPP=${CPP:Q} rpcgen -I -C
# We need to remove the 'static' keyword from _rpcsvcstate so that
# ypupdated_main.c can see it.
ypupdate_prot_svc.c: ${RPCDIR}/ypupdate_prot.x
rm -f ${.TARGET}
${RPCGEN} -m ${.ALLSRC} | \
sed s/"static int _rpcsvcstate"/"int _rpcsvcstate"/g > ${.TARGET}
ypupdate_prot.h: ${RPCDIR}/ypupdate_prot.x
${RPCGEN} -h -o ${.TARGET} ${.ALLSRC}
.include <bsd.prog.mk>

View file

@ -0,0 +1,18 @@
# Autogenerated - do NOT edit!
DIRDEPS = \
include \
include/rpc \
include/rpcsvc \
include/xlocale \
lib/${CSU_DIR} \
lib/libc \
lib/libcompiler_rt \
lib/librpcsvc \
.include <dirdeps.mk>
.if ${DEP_RELDIR} == ${_DEP_RELDIR}
# local dependencies - needed for -jN in clean tree
.endif

View file

@ -0,0 +1,328 @@
/*
* Sun RPC is a product of Sun Microsystems, Inc. and is provided for
* unrestricted use provided that this legend is included on all tape
* media and as a part of the software program in whole or part. Users
* may copy or modify Sun RPC without charge, but are not authorized
* to license or distribute it to anyone else except as part of a product or
* program developed by the user or with the express written consent of
* Sun Microsystems, Inc.
*
* SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
* WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* Sun RPC is provided with no support and without any obligation on the
* part of Sun Microsystems, Inc. to assist in its use, correction,
* modification or enhancement.
*
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
* OR ANY PART THEREOF.
*
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Sun has been advised of the possibility of such damages.
*
* Sun Microsystems, Inc.
* 2550 Garcia Avenue
* Mountain View, California 94043
*/
/*
* Copyright (C) 1986, 1989, Sun Microsystems, Inc.
*/
/*
* Administrative tool to add a new user to the publickey database
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <rpc/rpc.h>
#include <rpc/key_prot.h>
#ifdef YP
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
#include <sys/wait.h>
#include <netdb.h>
#endif /* YP */
#include <pwd.h>
#include <string.h>
#include <sys/resource.h>
#include "ypupdated_extern.h"
#ifdef YP
#define MAXMAPNAMELEN 256
#else
#define YPOP_CHANGE 1 /* change, do not add */
#define YPOP_INSERT 2 /* add, do not change */
#define YPOP_DELETE 3 /* delete this entry */
#define YPOP_STORE 4 /* add, or change */
#endif
#ifdef YP
static char SHELL[] = "/bin/sh";
static char YPDBPATH[]="/var/yp"; /* This is defined but not used! */
static char PKMAP[] = "publickey.byname";
static char UPDATEFILE[] = "updaters";
static char PKFILE[] = "/etc/publickey";
#endif /* YP */
#ifdef YP
static int _openchild(char *, FILE **, FILE **);
/*
* Determine if requester is allowed to update the given map,
* and update it if so. Returns the yp status, which is zero
* if there is no access violation.
*/
int
mapupdate(char *requester, char *mapname, u_int op, u_int keylen, char *key,
u_int datalen, char *data)
{
char updater[MAXMAPNAMELEN + 40];
FILE *childargs;
FILE *childrslt;
#ifdef WEXITSTATUS
int status;
#else
union wait status;
#endif
pid_t pid;
u_int yperrno;
#ifdef DEBUG
printf("%s %s\n", key, data);
#endif
(void)sprintf(updater, "make -s -f %s/%s %s", YPDBPATH, /* !!! */
UPDATEFILE, mapname);
pid = _openchild(updater, &childargs, &childrslt);
if (pid < 0) {
return (YPERR_YPERR);
}
/*
* Write to child
*/
(void)fprintf(childargs, "%s\n", requester);
(void)fprintf(childargs, "%u\n", op);
(void)fprintf(childargs, "%u\n", keylen);
(void)fwrite(key, (int)keylen, 1, childargs);
(void)fprintf(childargs, "\n");
(void)fprintf(childargs, "%u\n", datalen);
(void)fwrite(data, (int)datalen, 1, childargs);
(void)fprintf(childargs, "\n");
(void)fclose(childargs);
/*
* Read from child
*/
(void)fscanf(childrslt, "%d", &yperrno);
(void)fclose(childrslt);
(void)wait(&status);
#ifdef WEXITSTATUS
if (WEXITSTATUS(status) != 0)
#else
if (status.w_retcode != 0)
#endif
return (YPERR_YPERR);
return (yperrno);
}
/*
* returns pid, or -1 for failure
*/
static int
_openchild(char *command, FILE **fto, FILE **ffrom)
{
int i;
pid_t pid;
int pdto[2];
int pdfrom[2];
char *com;
struct rlimit rl;
if (pipe(pdto) < 0) {
goto error1;
}
if (pipe(pdfrom) < 0) {
goto error2;
}
switch (pid = fork()) {
case -1:
goto error3;
case 0:
/*
* child: read from pdto[0], write into pdfrom[1]
*/
(void)close(0);
(void)dup(pdto[0]);
(void)close(1);
(void)dup(pdfrom[1]);
getrlimit(RLIMIT_NOFILE, &rl);
for (i = rl.rlim_max - 1; i >= 3; i--) {
(void) close(i);
}
com = malloc((unsigned) strlen(command) + 6);
if (com == NULL) {
_exit(~0);
}
(void)sprintf(com, "exec %s", command);
execl(SHELL, basename(SHELL), "-c", com, (char *)NULL);
_exit(~0);
default:
/*
* parent: write into pdto[1], read from pdfrom[0]
*/
*fto = fdopen(pdto[1], "w");
(void)close(pdto[0]);
*ffrom = fdopen(pdfrom[0], "r");
(void)close(pdfrom[1]);
break;
}
return (pid);
/*
* error cleanup and return
*/
error3:
(void)close(pdfrom[0]);
(void)close(pdfrom[1]);
error2:
(void)close(pdto[0]);
(void)close(pdto[1]);
error1:
return (-1);
}
static char *
basename(char *path)
{
char *p;
p = strrchr(path, '/');
if (p == NULL) {
return (path);
} else {
return (p + 1);
}
}
#else /* YP */
static int match(char *, char *);
/*
* Determine if requester is allowed to update the given map,
* and update it if so. Returns the status, which is zero
* if there is no access violation. This function updates
* the local file and then shuts up.
*/
int
localupdate(char *name, char *filename, u_int op, u_int keylen __unused,
char *key, u_int datalen __unused, char *data)
{
char line[256];
FILE *rf;
FILE *wf;
char *tmpname;
int err;
/*
* Check permission
*/
if (strcmp(name, key) != 0) {
return (ERR_ACCESS);
}
if (strcmp(name, "nobody") == 0) {
/*
* Can't change "nobody"s key.
*/
return (ERR_ACCESS);
}
/*
* Open files
*/
tmpname = malloc(strlen(filename) + 4);
if (tmpname == NULL) {
return (ERR_MALLOC);
}
sprintf(tmpname, "%s.tmp", filename);
rf = fopen(filename, "r");
if (rf == NULL) {
err = ERR_READ;
goto cleanup;
}
wf = fopen(tmpname, "w");
if (wf == NULL) {
fclose(rf);
err = ERR_WRITE;
goto cleanup;
}
err = -1;
while (fgets(line, sizeof (line), rf)) {
if (err < 0 && match(line, name)) {
switch (op) {
case YPOP_INSERT:
err = ERR_KEY;
break;
case YPOP_STORE:
case YPOP_CHANGE:
fprintf(wf, "%s %s\n", key, data);
err = 0;
break;
case YPOP_DELETE:
/* do nothing */
err = 0;
break;
}
} else {
fputs(line, wf);
}
}
if (err < 0) {
switch (op) {
case YPOP_CHANGE:
case YPOP_DELETE:
err = ERR_KEY;
break;
case YPOP_INSERT:
case YPOP_STORE:
err = 0;
fprintf(wf, "%s %s\n", key, data);
break;
}
}
fclose(wf);
fclose(rf);
if (err == 0) {
if (rename(tmpname, filename) < 0) {
err = ERR_DBASE;
goto cleanup;
}
} else {
if (unlink(tmpname) < 0) {
err = ERR_DBASE;
goto cleanup;
}
}
cleanup:
free(tmpname);
return (err);
}
static int
match(char *line, char *name)
{
int len;
len = strlen(name);
return (strncmp(line, name, len) == 0 &&
(line[len] == ' ' || line[len] == '\t'));
}
#endif /* !YP */

View file

@ -0,0 +1,68 @@
/*-
* SPDX-License-Identifier: BSD-4-Clause
*
* Copyright (c) 1995, 1996
* Bill Paul <wpaul@ctr.columbia.edu>. 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 acknowledgement:
* This product includes software developed by Bill Paul.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS 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 Bill Paul OR 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.
*/
#include <sys/cdefs.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <limits.h>
#include <unistd.h>
#include <db.h>
#include <sys/stat.h>
#include <errno.h>
#include <paths.h>
#include <rpcsvc/yp.h>
#include "ypxfr_extern.h"
int
yp_del_record(DB *dbp, DBT *key)
{
int rval;
if ((rval = (dbp->del)(dbp,key,0))) {
switch (rval) {
case 1:
return(YP_FALSE);
break;
case -1:
default:
(void)(dbp->close)(dbp);
return(YP_BADDB);
break;
}
}
return(YP_TRUE);
}

View file

@ -0,0 +1,147 @@
/*-
* SPDX-License-Identifier: BSD-4-Clause
*
* Copyright (c) 1996
* Bill Paul <wpaul@ctr.columbia.edu>. 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 acknowledgement:
* This product includes software developed by Bill Paul.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS 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 Bill Paul OR 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.
*/
#include <sys/cdefs.h>
#include <sys/fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <db.h>
#include <unistd.h>
#include <rpcsvc/ypclnt.h>
#include <rpcsvc/ypupdate_prot.h>
#include "ypxfr_extern.h"
#include "ypupdated_extern.h"
static int
yp_domake(char *map, char *domain)
{
int pid;
switch ((pid = fork())) {
case 0:
execlp(MAP_UPDATE_PATH, MAP_UPDATE, map, domain, (char *)NULL);
yp_error("couldn't exec map update process: %s",
strerror(errno));
exit(1);
break;
case -1:
yp_error("fork() failed: %s", strerror(errno));
return(YPERR_YPERR);
break;
default:
children++;
break;
}
return(0);
}
int
ypmap_update(char *netname, char *map, unsigned int op, unsigned int keylen,
char *keyval, unsigned int datlen, char *datval)
{
DB *dbp;
DBT key = { NULL, 0 }, data = { NULL, 0 };
char *yp_last = "YP_LAST_MODIFIED";
char yplastbuf[32];
char *domptr;
int rval = 0;
if ((domptr = strchr(netname, '@')) == NULL)
return(ERR_ACCESS);
domptr++;
dbp = yp_open_db_rw(domptr, map, O_RDWR);
if (dbp == NULL)
return(ERR_DBASE);
key.data = keyval;
key.size = keylen;
data.data = datval;
data.size = datlen;
switch (op) {
case YPOP_DELETE: /* delete this entry */
rval = yp_del_record(dbp, &key);
if (rval == YP_TRUE)
rval = 0;
break;
case YPOP_INSERT: /* add, do not change */
rval = yp_put_record(dbp, &key, &data, 0);
if (rval == YP_TRUE)
rval = 0;
break;
case YPOP_STORE: /* add, or change */
rval = yp_put_record(dbp, &key, &data, 1);
if (rval == YP_TRUE)
rval = 0;
break;
case YPOP_CHANGE: /* change, do not add */
if (yp_get_record(domptr, map, &key, &data, 0) != YP_TRUE) {
rval = ERR_KEY;
break;
}
rval = yp_put_record(dbp, &key, &data, 1);
if (rval == YP_TRUE)
rval = 0;
break;
default:
yp_error("unknown update command: (%d)", op);
}
if (rval) {
(void)(dbp->close)(dbp);
return(rval);
}
snprintf(yplastbuf, sizeof(yplastbuf), "%jd", (intmax_t)time(NULL));
key.data = yp_last;
key.size = strlen(yp_last);
data.data = (char *)&yplastbuf;
data.size = strlen(yplastbuf);
if (yp_put_record(dbp, &key, &data, 1) != YP_TRUE) {
yp_error("failed to update timestamp in %s/%s", domptr, map);
(void)(dbp->close)(dbp);
return(ERR_DBASE);
}
(void)(dbp->close)(dbp);
return(yp_domake(map, domptr));
}

32
usr.sbin/rpc.ypupdated/ypupdate Executable file
View file

@ -0,0 +1,32 @@
#!/bin/sh
#
# This script is invoked by rpc.ypupdatedd to propagate NIS maps
# after the master map databases have been modified. It expects
# to be passed two arguments: the name of the map that was updated
# and the name of the domain where the map resides.
# These are passed to /var/yp/Makefile.
#
# Comment out the LOG=yes line to disable logging.
#
#
LOG=yes
LOGFILE=/var/yp/ypupdate.log
umask 077
if [ ! -f $LOGFILE ];
then
/usr/bin/touch $LOGFILE
echo "# Edit /usr/libexec/yppwupdate to disable" >> $LOGFILE
echo "# logging to this file from yppasswdd." >> $LOGFILE
echo -n "# Log started on: " >> $LOGFILE
/bin/date >> $LOGFILE
fi
if [ ! $LOG ];
then
cd /var/yp/$2; /usr/bin/make -f ../Makefile $1 2>&1
else
cd /var/yp/$2; /usr/bin/make -f ../Makefile $1 >> $LOGFILE
fi

View file

@ -0,0 +1,32 @@
/*
*/
#include <db.h>
#define YPOP_CHANGE 1 /* change, do not add */
#define YPOP_INSERT 2 /* add, do not change */
#define YPOP_DELETE 3 /* delete this entry */
#define YPOP_STORE 4 /* add, or change */
#define ERR_ACCESS 1
#define ERR_MALLOC 2
#define ERR_READ 3
#define ERR_WRITE 4
#define ERR_DBASE 5
#define ERR_KEY 6
#ifndef YPLIBDIR
#define YPLIBDIR "/usr/libexec/"
#endif
#ifndef MAP_UPPATE
#define MAP_UPDATE "ypupdate"
#endif
#define MAP_UPDATE_PATH YPLIBDIR MAP_UPDATE
extern int children;
extern void ypu_prog_1(struct svc_req *, register SVCXPRT *);
extern int localupdate(char *, char *, u_int, u_int, char *, u_int, char *);
extern int ypmap_update(char *, char *, u_int, u_int, char *, u_int, char *);
extern int yp_del_record(DB *, DBT *);

View file

@ -0,0 +1,287 @@
/*-
* SPDX-License-Identifier: BSD-4-Clause
*
* Copyright (c) 1995, 1996
* Bill Paul <wpaul@ctr.columbia.edu>. 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 acknowledgement:
* This product includes software developed by Bill Paul.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS 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 Bill Paul OR 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.
*/
#include <sys/cdefs.h>
#include "ypupdate_prot.h"
#include <stdio.h>
#include <stdlib.h> /* getenv, exit */
#include <rpc/pmap_clnt.h> /* for pmap_unset */
#include <rpc/rpc_com.h>
#include <string.h> /* strcmp */
#include <signal.h>
#ifdef __cplusplus
#include <sysent.h> /* getdtablesize, open */
#endif /* __cplusplus */
#include <memory.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <syslog.h>
#include <sys/wait.h>
#include <errno.h>
#include <err.h>
#include <unistd.h>
#include "ypupdated_extern.h"
#include "yp_extern.h"
#ifndef SIG_PF
#define SIG_PF void(*)(int)
#endif
#ifdef DEBUG
#define RPC_SVC_FG
#endif
#define _RPCSVC_CLOSEDOWN 120
int _rpcpmstart; /* Started by a port monitor ? */
static int _rpcfdtype;
/* Whether Stream or Datagram ? */
/* States a server can be in wrt request */
#define _IDLE 0
#define _SERVED 1
#define _SERVING 2
extern int _rpcsvcstate; /* Set when a request is serviced */
int debug;
char *progname = "rpc.ypupdated";
char *yp_dir = "/var/yp/";
static void
_msgout(char* msg)
{
#ifdef RPC_SVC_FG
if (_rpcpmstart)
syslog(LOG_ERR, "%s", msg);
else
warnx("%s", msg);
#else
syslog(LOG_ERR, "%s", msg);
#endif
}
static void
closedown(int sig)
{
if (_rpcsvcstate == _IDLE) {
extern fd_set svc_fdset;
static int size;
int i, openfd;
if (_rpcfdtype == SOCK_DGRAM)
exit(0);
if (size == 0) {
size = getdtablesize();
}
for (i = 0, openfd = 0; i < size && openfd < 2; i++)
if (FD_ISSET(i, &svc_fdset))
openfd++;
if (openfd <= 1)
exit(0);
}
if (_rpcsvcstate == _SERVED)
_rpcsvcstate = _IDLE;
(void) signal(SIGALRM, (SIG_PF) closedown);
(void) alarm(_RPCSVC_CLOSEDOWN/2);
}
static void
ypupdated_svc_run(void)
{
#ifdef FD_SETSIZE
fd_set readfds;
#else
int readfds;
#endif /* def FD_SETSIZE */
extern int forked;
int pid;
int fd_setsize = _rpc_dtablesize();
/* Establish the identity of the parent ypupdated process. */
pid = getpid();
for (;;) {
#ifdef FD_SETSIZE
readfds = svc_fdset;
#else
readfds = svc_fds;
#endif /* def FD_SETSIZE */
switch (select(fd_setsize, &readfds, NULL, NULL,
(struct timeval *)0)) {
case -1:
if (errno == EINTR) {
continue;
}
warn("svc_run: - select failed");
return;
case 0:
continue;
default:
svc_getreqset(&readfds);
if (forked && pid != getpid())
exit(0);
}
}
}
static void
reaper(int sig)
{
int status;
if (sig == SIGHUP) {
#ifdef foo
load_securenets();
#endif
return;
}
if (sig == SIGCHLD) {
while (wait3(&status, WNOHANG, NULL) > 0)
children--;
} else {
(void) pmap_unset(YPU_PROG, YPU_VERS);
exit(0);
}
}
void
usage(void)
{
fprintf(stderr, "rpc.ypupdatedd [-p path]\n");
exit(0);
}
int
main(int argc, char *argv[])
{
register SVCXPRT *transp = NULL;
int sock;
int proto = 0;
struct sockaddr_in saddr;
int asize = sizeof (saddr);
int ch;
while ((ch = getopt(argc, argv, "p:h")) != -1) {
switch (ch) {
case 'p':
yp_dir = optarg;
break;
default:
usage();
break;
}
}
#ifdef foo
load_securenets();
#endif
if (svc_auth_reg(AUTH_DES, _svcauth_des) == -1) {
yp_error("failed to register AUTH_DES flavor");
exit(1);
}
if (getsockname(0, (struct sockaddr *)&saddr, &asize) == 0) {
int ssize = sizeof (int);
if (saddr.sin_family != AF_INET)
exit(1);
if (getsockopt(0, SOL_SOCKET, SO_TYPE,
(char *)&_rpcfdtype, &ssize) == -1)
exit(1);
sock = 0;
_rpcpmstart = 1;
proto = 0;
openlog("rpc.ypupdatedd", LOG_PID, LOG_DAEMON);
} else {
#ifndef RPC_SVC_FG
if (daemon(0,0)) {
err(1, "cannot fork");
}
openlog("rpc.ypupdated", LOG_PID, LOG_DAEMON);
#endif
sock = RPC_ANYSOCK;
(void) pmap_unset(YPU_PROG, YPU_VERS);
}
if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_DGRAM)) {
transp = svcudp_create(sock);
if (transp == NULL) {
_msgout("cannot create udp service.");
exit(1);
}
if (!_rpcpmstart)
proto = IPPROTO_UDP;
if (!svc_register(transp, YPU_PROG, YPU_VERS, ypu_prog_1, proto)) {
_msgout("unable to register (YPU_PROG, YPU_VERS, udp).");
exit(1);
}
}
if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_STREAM)) {
transp = svctcp_create(sock, 0, 0);
if (transp == NULL) {
_msgout("cannot create tcp service.");
exit(1);
}
if (!_rpcpmstart)
proto = IPPROTO_TCP;
if (!svc_register(transp, YPU_PROG, YPU_VERS, ypu_prog_1, proto)) {
_msgout("unable to register (YPU_PROG, YPU_VERS, tcp).");
exit(1);
}
}
if (transp == (SVCXPRT *)NULL) {
_msgout("could not create a handle");
exit(1);
}
if (_rpcpmstart) {
(void) signal(SIGALRM, (SIG_PF) closedown);
(void) alarm(_RPCSVC_CLOSEDOWN/2);
}
(void) signal(SIGPIPE, SIG_IGN);
(void) signal(SIGCHLD, (SIG_PF) reaper);
(void) signal(SIGTERM, (SIG_PF) reaper);
(void) signal(SIGINT, (SIG_PF) reaper);
(void) signal(SIGHUP, (SIG_PF) reaper);
ypupdated_svc_run();
_msgout("svc_run returned");
exit(1);
/* NOTREACHED */
}

View file

@ -0,0 +1,227 @@
/*-
* SPDX-License-Identifier: BSD-4-Clause
*
* Copyright (c) 1995, 1996
* Bill Paul <wpaul@ctr.columbia.edu>. 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 acknowledgement:
* This product includes software developed by Bill Paul.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS 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 Bill Paul OR 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.
*
* ypupdate server implementation
*
* Written by Bill Paul <wpaul@ctr.columbia.edu>
* Center for Telecommunications Research
* Columbia University, New York City
*/
#include <sys/cdefs.h>
#include <stdio.h>
#include <rpc/rpc.h>
#include <rpc/key_prot.h>
#include <sys/param.h>
#include <rpcsvc/yp.h>
#include "ypupdate_prot.h"
#include "ypupdated_extern.h"
#include "yp_extern.h"
#include "ypxfr_extern.h"
int children = 0;
int forked = 0;
/*
* Try to avoid spoofing: if a client chooses to use a very large
* window and then tries a bunch of randomly chosen encrypted timestamps,
* there's a chance he might stumble onto a valid combination.
* We therefore reject any RPCs with a window size larger than a preset
* value.
*/
#ifndef WINDOW
#define WINDOW (60*60)
#endif
static enum auth_stat
yp_checkauth(struct svc_req *svcreq)
{
struct authdes_cred *des_cred;
switch (svcreq->rq_cred.oa_flavor) {
case AUTH_DES:
des_cred = (struct authdes_cred *) svcreq->rq_clntcred;
if (des_cred->adc_fullname.window > WINDOW) {
yp_error("warning: client-specified window size \
was too large -- possible spoof attempt");
return(AUTH_BADCRED);
}
return(AUTH_OK);
break;
case AUTH_UNIX:
case AUTH_NONE:
yp_error("warning: client didn't use DES authentication");
return(AUTH_TOOWEAK);
break;
default:
yp_error("client used unknown auth flavor");
return(AUTH_REJECTEDCRED);
break;
}
}
unsigned int *
ypu_change_1_svc(struct ypupdate_args *args, struct svc_req *svcreq)
{
struct authdes_cred *des_cred;
static int res;
char *netname;
enum auth_stat astat;
res = 0;
astat = yp_checkauth(svcreq);
if (astat != AUTH_OK) {
svcerr_auth(svcreq->rq_xprt, astat);
return(&res);
}
des_cred = (struct authdes_cred *) svcreq->rq_clntcred;
netname = des_cred->adc_fullname.name;
res = localupdate(netname, "/etc/publickey", YPOP_CHANGE,
args->key.yp_buf_len, args->key.yp_buf_val,
args->datum.yp_buf_len, args->datum.yp_buf_val);
if (res)
return (&res);
res = ypmap_update(netname, args->mapname, YPOP_CHANGE,
args->key.yp_buf_len, args->key.yp_buf_val,
args->datum.yp_buf_len, args->datum.yp_buf_val);
return (&res);
}
unsigned int *
ypu_insert_1_svc(struct ypupdate_args *args, struct svc_req *svcreq)
{
struct authdes_cred *des_cred;
static int res;
char *netname;
enum auth_stat astat;
res = 0;
astat = yp_checkauth(svcreq);
if (astat != AUTH_OK) {
svcerr_auth(svcreq->rq_xprt, astat);
return(&res);
}
des_cred = (struct authdes_cred *) svcreq->rq_clntcred;
netname = des_cred->adc_fullname.name;
res = localupdate(netname, "/etc/publickey", YPOP_INSERT,
args->key.yp_buf_len, args->key.yp_buf_val,
args->datum.yp_buf_len, args->datum.yp_buf_val);
if (res)
return (&res);
res = ypmap_update(netname, args->mapname, YPOP_INSERT,
args->key.yp_buf_len, args->key.yp_buf_val,
args->datum.yp_buf_len, args->datum.yp_buf_val);
return (&res);
}
unsigned int *
ypu_delete_1_svc(struct ypdelete_args *args, struct svc_req *svcreq)
{
struct authdes_cred *des_cred;
static int res;
char *netname;
enum auth_stat astat;
res = 0;
astat = yp_checkauth(svcreq);
if (astat != AUTH_OK) {
svcerr_auth(svcreq->rq_xprt, astat);
return(&res);
}
des_cred = (struct authdes_cred *) svcreq->rq_clntcred;
netname = des_cred->adc_fullname.name;
res = localupdate(netname, "/etc/publickey", YPOP_DELETE,
args->key.yp_buf_len, args->key.yp_buf_val,
0, NULL);
if (res)
return (&res);
res = ypmap_update(netname, args->mapname, YPOP_DELETE,
args->key.yp_buf_len, args->key.yp_buf_val,
0, NULL);
return (&res);
}
unsigned int *
ypu_store_1_svc(struct ypupdate_args *args, struct svc_req *svcreq)
{
struct authdes_cred *des_cred;
static int res;
char *netname;
enum auth_stat astat;
res = 0;
astat = yp_checkauth(svcreq);
if (astat != AUTH_OK) {
svcerr_auth(svcreq->rq_xprt, astat);
return(&res);
}
des_cred = (struct authdes_cred *) svcreq->rq_clntcred;
netname = des_cred->adc_fullname.name;
res = localupdate(netname, "/etc/publickey", YPOP_STORE,
args->key.yp_buf_len, args->key.yp_buf_val,
args->datum.yp_buf_len, args->datum.yp_buf_val);
if (res)
return (&res);
res = ypmap_update(netname, args->mapname, YPOP_STORE,
args->key.yp_buf_len, args->key.yp_buf_val,
args->datum.yp_buf_len, args->datum.yp_buf_val);
return (&res);
}