Bug 29171

Summary: [PATCH] keyserv and rpc.yppasswd
Product: Base System Reporter: mb <mb>
Component: binAssignee: freebsd-bugs (Nobody) <bugs>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 5.0-CURRENT   
Hardware: Any   
OS: Any   

Description mb 2001-07-23 22:00:01 UTC
Local AF-LOCAL support is currently broken in CURRENT since 3 month. I post
the URL's here so the patches don't get lost.

Fix: 

Add my patches:

http://home.teleport.ch/freebsd/userland/keyserv.diff
http://home.teleport.ch/freebsd/userland/rpc.yppasswdd.diff

http://home.teleport.ch/freebsd/userland/local_transp_clnt_create.diff
http://home.teleport.ch/freebsd/userland/local_transp_compat.diff
http://home.teleport.ch/freebsd/userland/local_transp_getaddrinfo-fix.diff
How-To-Repeat: 
Use yppasswd as root to change a users password on the ypserver itself.
Normally you shouln't be asked for the old password. With these fixes, the
old behaviour works again.
Comment 1 dima 2001-07-24 06:34:47 UTC
Martin Blapp <mb@imp.ch> writes:
> >Description:
> 
> [...] I post
> the URL's here so the patches don't get lost.

It would be better if you also attached the actual patches to your PRs
so that somebody looking at this PR in three years, after you've
removed them from your web server or the latter is no longer
available, would have access to them.  The PR database should be a
self-contained as possible.

Thanks.
Comment 2 mb 2001-10-04 22:13:52 UTC
Hi,

I just updated my patches to the latest CURRENT.

Unfortunatly this patchset is still outstanding and should be reviewed
and comitted.

Also the following patch should be comitted, cause it fixes a additional
part:

http://home.teleport.ch/freebsd/userland/local_transp_svc_vc.c.diff

Everything is commented inside the patches ...

Martin
Comment 3 mb 2001-10-07 01:40:51 UTC
One part:

http://home.teleport.ch/freebsd/userland/local_transp_compat.diff

has been comitted by Bill Paul. Thanks !

Here are the other patches:

usr.sbin/keyserv/keyserv.c

Fix the breakage in keyserv, Readded the svc_create() and
the registering of the "unix" transport, now it is fixed.

--- usr.sbin/keyserv/keyserv.c  Thu Mar 22 05:31:29 2001
+++ usr.sbin/keyserv/keyserv.c  Fri Apr  6 23:41:56 2001
@@ -117,6 +117,8 @@
 	int sock = RPC_ANYSOCK;
 	int warn = 0;
 	char *path = NULL;
+	void *localhandle;
+	struct netconfig *nconf = NULL;

 	__key_encryptsession_pk_LOCAL = &key_encrypt_pk_2_svc_prog;
 	__key_decryptsession_pk_LOCAL = &key_decrypt_pk_2_svc_prog;
@@ -155,12 +157,15 @@
 	/*
 	 * Initialize
 	 */
-	(void) umask(066);	/* paranoia */
+	(void) umask(S_IXUSR|S_IXGRP|S_IXOTH);
 	if (geteuid() != 0)
 		errx(1, "keyserv must be run as root");
 	setmodulus(HEXMODULUS);
 	getrootkey(&masterkey, nflag);

+	rpcb_unset(KEY_PROG, KEY_VERS, NULL);
+	rpcb_unset(KEY_PROG, KEY_VERS2, NULL);
+
 	if (svc_create(keyprogram, KEY_PROG, KEY_VERS,
 		"netpath") == 0) {
 		(void) fprintf(stderr,
@@ -174,6 +179,32 @@
 			"%s: unable to create service\n", argv[0]);
 		exit(1);
 	}
+
+	localhandle = setnetconfig();
+	while ((nconf = getnetconfig(localhandle)) != NULL) {
+		if (nconf->nc_protofmly != NULL &&
+		    strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
+			break;
+	}
+
+	if (nconf == NULL)
+		errx(1, "getnetconfig: %s", nc_sperror());
+
+	unlink(KEYSERVSOCK);
+	rpcb_unset(CRYPT_PROG, CRYPT_VERS, nconf);
+	transp = svcunix_create(RPC_ANYSOCK, 0, 0, KEYSERVSOCK);
+	if (transp == NULL)
+		errx(1, "cannot create AF_LOCAL service");
+	if (!svc_reg(transp, KEY_PROG, KEY_VERS, keyprogram, nconf))
+		errx(1, "unable to register (KEY_PROG, KEY_VERS, unix)");
+	if (!svc_reg(transp, KEY_PROG, KEY_VERS2, keyprogram, nconf))
+		errx(1, "unable to register (KEY_PROG, KEY_VERS2, unix)");
+	if (!svc_reg(transp, CRYPT_PROG, CRYPT_VERS, crypt_prog_1, nconf))
+		errx(1, "unable to register (CRYPT_PROG, CRYPT_VERS, unix)");
+
+	endnetconfig(localhandle);
+
+	(void) umask(066);	/* paranoia */

 	if (!debugging) {
 		daemon(0,0);

usr.sbin/rpc.yppasswdd/yppasswdd_main.c
usr.sbin/rpc.yppasswdd/yppasswdd_server.c

Fix the breakage in rpc.yppasswd. Readded the svc_create() and
the registering of the "unix" transport, now it is fixed.

Everywhere, rq_cred is taken to look what authentification we have.
We can not bu sure that transp>xp_verf.oa_flavor is also filled in.
This seems to be the same for all sun source. they take the flavor
of rq_cred, instead of transp.

- transp>xp_verf.oa_flavor != AUTH_UNIX) {
+ rqstp->rq_cred.oa_flavor != AUTH_UNIX) {

Please look at my other fix: local_transp_svc_vc.c.diff to have
a better explanation.

--- usr.sbin/rpc.yppasswdd/yppasswdd_main.c	Mon Mar 19 13:50:10 2001
+++ usr.sbin/rpc.yppasswdd/yppasswdd_main.c	Thu Apr 19 13:55:29 2001
@@ -100,8 +100,8 @@
 static void terminate(sig)
 	int sig;
 {
-	svc_unregister(YPPASSWDPROG, YPPASSWDVERS);
-	svc_unregister(MASTER_YPPASSWDPROG, MASTER_YPPASSWDVERS);
+	rpcb_unset(YPPASSWDPROG, YPPASSWDVERS, NULL);
+	rpcb_unset(MASTER_YPPASSWDPROG, MASTER_YPPASSWDVERS, NULL);
 	unlink(sockname);
 	exit(0);
 }
@@ -156,13 +156,14 @@
 	char *argv[];
 {
 	register SVCXPRT *transp = NULL;
-	int sock;
-	int proto = 0;
 	struct sockaddr_in saddr;
 	int asize = sizeof (saddr);
+	struct netconfig *nconf;
+	void *localhandle;
 	int ch;
 	char *mastername;
 	char myname[MAXHOSTNAMELEN + 2];
+
 	extern int debug;

 	debug = 1;
@@ -246,78 +247,59 @@

 	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)
+		    (char *)&_rpcfdtype, &ssize) == -1)
 			exit(1);
-		sock = 0;
 		_rpcpmstart = 1;
-		proto = 0;
-		openlog("rpc.yppasswdd", LOG_PID, LOG_DAEMON);
-	} else {
-		if (!debug) {
-			if (daemon(0,0)) {
-				err(1,"cannot fork");
-			}
-		}
-		openlog("rpc.yppasswdd", LOG_PID, LOG_DAEMON);
-		sock = RPC_ANYSOCK;
-		(void) pmap_unset(YPPASSWDPROG, YPPASSWDVERS);
-		(void) pmap_unset(MASTER_YPPASSWDPROG, MASTER_YPPASSWDVERS);
-		unlink(sockname);
-	}
-
-	if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_DGRAM)) {
-		transp = svcudp_create(sock);
-		if (transp == NULL) {
-			yp_error("cannot create udp service.");
-			exit(1);
-		}
-		if (!_rpcpmstart)
-			proto = IPPROTO_UDP;
-		if (!svc_register(transp, YPPASSWDPROG, YPPASSWDVERS, yppasswdprog_1, proto)) {
-			yp_error("unable to register (YPPASSWDPROG, YPPASSWDVERS, udp).");
-			exit(1);
-		}
 	}

-	if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_STREAM)) {
-		transp = svctcp_create(sock, 0, 0);
-		if (transp == NULL) {
-			yp_error("cannot create tcp service.");
-			exit(1);
-		}
-		if (!_rpcpmstart)
-			proto = IPPROTO_TCP;
-		if (!svc_register(transp, YPPASSWDPROG, YPPASSWDVERS, yppasswdprog_1, proto)) {
-			yp_error("unable to register (YPPASSWDPROG, YPPASSWDVERS, tcp).");
-			exit(1);
+	if (!debug && _rpcpmstart == 0) {
+		if (daemon(0,0)) {
+			err(1,"cannot fork");
 		}
 	}
+	openlog("rpc.yppasswdd", LOG_PID, LOG_DAEMON);

-	unlink(sockname);
-        if (svc_create(yppasswdprog_1, YPPASSWDPROG, YPPASSWDVERS,
-	    "netpath") == 0) {
-                (void) fprintf(stderr,
-                        "%s: unable to create service\n", argv[0]);
-                exit(1);
-        }
-        if (svc_create(master_yppasswdprog_1, MASTER_YPPASSWDPROG,
+	rpcb_unset(YPPASSWDPROG, YPPASSWDVERS, NULL);
+	rpcb_unset(MASTER_YPPASSWDPROG, MASTER_YPPASSWDVERS, NULL);
+
+	if (svc_create(yppasswdprog_1, YPPASSWDPROG, YPPASSWDVERS, "netpath") == 0) {
+		yp_error("cannot create yppasswd service.");
+		exit(1);
+	}
+	if (svc_create(master_yppasswdprog_1, MASTER_YPPASSWDPROG,
 	    MASTER_YPPASSWDVERS, "netpath") == 0) {
-                (void) fprintf(stderr,
-                        "%s: unable to create service\n", argv[0]);
-                exit(1);
-        }
+		yp_error("cannot create master_yppasswd service.");
+		exit(1);
+	}
+
+	nconf = NULL;
+	localhandle = setnetconfig();
+	while ((nconf = getnetconfig(localhandle)) != NULL) {
+		if (nconf->nc_protofmly != NULL &&
+		    strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
+			break;
+	}
+	if (nconf == NULL) {
+		yp_error("getnetconfigent unix: %s", nc_sperror());
+		exit(1);
+	}
+	unlink(sockname);
+	transp = svcunix_create(RPC_ANYSOCK, 0, 0, sockname);
 	if (transp == NULL) {
 		yp_error("cannot create AF_LOCAL service.");
 		exit(1);
 	}
-	if (!svc_register(transp, MASTER_YPPASSWDPROG, MASTER_YPPASSWDVERS, master_yppasswdprog_1, 0)) {
-		yp_error("unable to register (MASTER_YPPASSWDPROG, MASTER_YPPASSWDVERS, unix).");
+	if (!svc_reg(transp, MASTER_YPPASSWDPROG, MASTER_YPPASSWDVERS,
+	    master_yppasswdprog_1, nconf)) {
+		yp_error("unable to register (MASTER_YPPASSWDPROG,
+		    MASTER_YPPASSWDVERS, unix).");
 		exit(1);
 	}
+	endnetconfig(localhandle);
+
 	/* Only root may connect() to the AF_UNIX link. */
 	if (chmod(sockname, 0))
 		err(1, "chmod of %s failed", sockname);
--- usr.sbin/rpc.yppasswdd/yppasswdd_server.c	Thu Mar 22 21:43:13 2001
+++ usr.sbin/rpc.yppasswdd/yppasswdd_server.c	Wed Apr 18 18:54:22 2001
@@ -62,11 +62,6 @@
 #include "yppasswd.h"
 #include "yppasswd_private.h"

-struct cmessage {
-        struct cmsghdr cmsg;
-        struct cmsgcred cmcred;
-};
-
 char *tempname;

 void reaper(sig)
@@ -705,47 +700,43 @@
 	static int result;
 	int pfd, tfd;
 	int pid;
+	uid_t uid;
 	int rval = 0;
 	DBT key, data;
 	char *passfile_hold;
 	char passfile_buf[MAXPATHLEN + 2];
 	struct sockaddr_in *rqhost;
-	struct cmessage			*cm;
-	SVCXPRT				*transp;
+	SVCXPRT	*transp;

 	result = 1;
+	transp = rqstp->rq_xprt;

 	/*
 	 * NO AF_INET CONNETCIONS ALLOWED!
 	 */
-	rqhost = svc_getcaller(rqstp->rq_xprt);
+	rqhost = svc_getcaller(transp);
 	if (rqhost->sin_family != AF_UNIX) {
 		yp_error("Alert! %s/%d attempted to use superuser-only \
 procedure!\n", inet_ntoa(rqhost->sin_addr), rqhost->sin_port);
-		svcerr_auth(rqstp->rq_xprt, AUTH_BADCRED);
+		svcerr_auth(transp, AUTH_BADCRED);
 		return(&result);
 	}

-	transp = rqstp->rq_xprt;
-
-	if (transp->xp_verf.oa_length < sizeof(struct cmessage) ||
-		transp->xp_verf.oa_base == NULL ||
-		transp->xp_verf.oa_flavor != AUTH_UNIX) {
+	if (rqstp->rq_cred.oa_flavor != AUTH_SYS) {
 		yp_error("caller didn't send proper credentials");
-		svcerr_auth(rqstp->rq_xprt, AUTH_BADCRED);
+		svcerr_auth(transp, AUTH_BADCRED);
 		return(&result);
 	}

-	cm = (struct cmessage *)transp->xp_verf.oa_base;
-	if (cm->cmsg.cmsg_type != SCM_CREDS) {
+	if (__rpc_get_local_uid(transp, &uid) < 0) {
 		yp_error("caller didn't send proper credentials");
-		svcerr_auth(rqstp->rq_xprt, AUTH_BADCRED);
+		svcerr_auth(transp, AUTH_BADCRED);
 		return(&result);
 	}
-
- 	if (cm->cmcred.cmcred_euid) {
+
+	if (uid) {
 		yp_error("caller euid is %d, expecting 0 -- rejecting request",
-				cm->cmcred.cmcred_euid);
+		    uid);
 		svcerr_auth(rqstp->rq_xprt, AUTH_BADCRED);
 		return(&result);
 	}

Last modified:

2001-10-06 02:00

Changed files:

usr.bin/chpass/pw_yp.c
usr.bin/passwd/yp_passwd.c
lib/libc/rpc/crypt_client.c
usr.bin/rpcinfo/rpcinfo.c

Commment:

The clnt_create(KEYSERVSOCK, CRYPT_PROG, CRYPT_VERS, "unix") hacks were
removed and replaced them with clnt_tp_create, now the af_local support is fixed.
I also removed the hack how rpcinfo contacted rpcbind, now we can
relay on clnt_tp_create create the client-handle for us.  Only rpcbind itself
needs a hardcoded socket-path.

Index: lib/libc/rpc/crypt_client.c
===================================================================
RCS file: /usr/home/ncvs/src/lib/libc/rpc/crypt_client.c,v
retrieving revision 1.5
diff -u -r1.5 crypt_client.c
--- lib/libc/rpc/crypt_client.c	19 Mar 2001 12:49:50 -0000	1.5
+++ lib/libc/rpc/crypt_client.c	5 Oct 2001 23:47:51 -0000
@@ -42,10 +42,6 @@
 static const char rcsid[] = "$FreeBSD: src/lib/libc/rpc/crypt_client.c,v 1.5 2001/03/19 12:49:50 alfred Exp $";
 #endif

-#ifndef KEYSERVSOCK
-#define KEYSERVSOCK "/var/run/keyservsock"
-#endif
-
 int
 _des_crypt_call(buf, len, dparms)
 	char *buf;
@@ -55,12 +51,27 @@
 	CLIENT *clnt;
 	desresp  *result_1;
 	desargs  des_crypt_1_arg;
-	int	stat;
+	struct netconfig *nconf;
+	void *localhandle;
+	int stat;

-	clnt = clnt_create(KEYSERVSOCK, CRYPT_PROG, CRYPT_VERS, "unix");
+	nconf = NULL;
+	localhandle = setnetconfig();
+	while ((nconf = getnetconfig(localhandle)) != NULL) {
+		if (nconf->nc_protofmly != NULL &&
+		     strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
+			break;
+	}
+	if (nconf == NULL) {
+		warnx("getnetconfig: %s", nc_sperror());
+		return(DESERR_HWERROR);
+	}
+	clnt = clnt_tp_create(NULL, CRYPT_PROG, CRYPT_VERS, nconf);
 	if (clnt == (CLIENT *) NULL) {
+		endnetconfig(localhandle);
 		return(DESERR_HWERROR);
 	}
+	endnetconfig(localhandle);

 	des_crypt_1_arg.desbuf.desbuf_len = len;
 	des_crypt_1_arg.desbuf.desbuf_val = buf;
Index: usr.bin/chpass/pw_yp.c
===================================================================
RCS file: /usr/home/ncvs/src/usr.bin/chpass/pw_yp.c,v
retrieving revision 1.16
diff -u -r1.16 pw_yp.c
--- usr.bin/chpass/pw_yp.c	20 Oct 1999 15:20:00 -0000	1.16
+++ usr.bin/chpass/pw_yp.c	5 Oct 2001 23:47:51 -0000
@@ -354,7 +354,6 @@
 	char *mastername;
 	int rval, localport;
 	struct stat st;
-	char			*sockname = YP_SOCKNAME;

 	/*
 	 * Sometimes we are called just to probe for rpc.yppasswdd and
@@ -407,7 +406,7 @@
 	/* See if _we_ are the master server. */
 	if (!force_old && !getuid() && (localport = getrpcport("localhost",
 		YPPASSWDPROG, YPPASSWDPROC_UPDATE, IPPROTO_UDP)) != 0) {
-		if (localport == rval && stat(sockname, &st) != -1) {
+		if (localport == rval) {
 			suser_override = 1;
 			mastername = "localhost";
 		}
@@ -433,12 +432,14 @@
 {
 	struct yppasswd yppasswd;
 	struct master_yppasswd master_yppasswd;
+	struct netconfig *nconf;
+	void *localhandle;
 	CLIENT *clnt;
 	char *master, *password;
 	int *status = NULL;
 	struct rpc_err err;
-	char			*sockname = YP_SOCKNAME;

+	nconf = NULL;
 	_use_yp = 1;

 	/* Get NIS master server name */
@@ -490,13 +491,26 @@

 	if (suser_override) {
 		/* Talk to server via AF_UNIX socket. */
-		clnt = clnt_create(sockname, MASTER_YPPASSWDPROG,
-					MASTER_YPPASSWDVERS, "unix");
+		localhandle = setnetconfig();
+		while ((nconf = getnetconfig(localhandle)) != NULL) {
+			if (nconf->nc_protofmly != NULL &&
+			    strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
+				break;
+		}
+		if (nconf == NULL) {
+			warnx("getnetconfig: %s", nc_sperror());
+			pw_error(tempname, 0, 1);
+		}
+
+		clnt = clnt_tp_create(NULL, MASTER_YPPASSWDPROG,
+		   MASTER_YPPASSWDVERS, nconf);
 		if (clnt == NULL) {
 			warnx("failed to contact rpc.yppasswdd: %s",
 				clnt_spcreateerror(master));
+			endnetconfig(localhandle);
 			pw_error(tempname, 0, 1);
 		}
+		endnetconfig(localhandle);
 	} else {
 		/* Create a handle to yppasswdd. */

Index: usr.bin/passwd/yp_passwd.c
===================================================================
RCS file: /usr/home/ncvs/src/usr.bin/passwd/yp_passwd.c,v
retrieving revision 1.15
diff -u -r1.15 yp_passwd.c
--- usr.bin/passwd/yp_passwd.c	28 Sep 1997 08:51:02 -0000	1.15
+++ usr.bin/passwd/yp_passwd.c	5 Oct 2001 23:47:51 -0000
@@ -55,14 +55,16 @@
 {
 	struct yppasswd yppasswd;
 	struct master_yppasswd master_yppasswd;
+	struct netconfig *nconf;
+	void *localhandle;
 	struct passwd *pw;
 	CLIENT *clnt;
 	struct rpc_err err;
 	char   *master;
 	int    *status = NULL;
 	uid_t	uid;
-	char			*sockname = YP_SOCKNAME;

+	nconf = NULL;
 	_use_yp = 1;

 	uid = getuid();
@@ -144,12 +146,24 @@
 	}

 	if (suser_override) {
-		if ((clnt = clnt_create(sockname, MASTER_YPPASSWDPROG,
-				MASTER_YPPASSWDVERS, "unix")) == NULL) {
+		localhandle = setnetconfig();
+		while ((nconf = getnetconfig(localhandle)) != NULL) {
+			if (nconf->nc_protofmly != NULL &&
+			    strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
+				break;
+		}
+		if (nconf == NULL) {
+			warnx("getnetconfig: %s", nc_sperror());
+			return(1);
+		}
+		if ((clnt = clnt_tp_create(NULL, MASTER_YPPASSWDPROG,
+		    MASTER_YPPASSWDVERS, nconf)) == NULL) {
 			warnx("failed to contact rpc.yppasswdd on host %s: %s",
 				master, clnt_spcreateerror(""));
+			endnetconfig(localhandle);
 			return(1);
 		}
+		endnetconfig(localhandle);
 	} else {
 		if ((clnt = clnt_create(master, YPPASSWDPROG,
 				YPPASSWDVERS, "udp")) == NULL) {
Index: usr.bin/rpcinfo/rpcinfo.c
===================================================================
RCS file: /usr/home/ncvs/src/usr.bin/rpcinfo/rpcinfo.c,v
retrieving revision 1.11
diff -u -r1.11 rpcinfo.c
--- usr.bin/rpcinfo/rpcinfo.c	19 Mar 2001 12:50:04 -0000	1.11
+++ usr.bin/rpcinfo/rpcinfo.c	5 Oct 2001 23:47:51 -0000
@@ -321,22 +321,24 @@
 static CLIENT *
 local_rpcb(u_long prog, u_long vers)
 {
-	struct netbuf nbuf;
-	struct sockaddr_un sun;
-	int sock;
+	void *localhandle;
+	struct netconfig *nconf;
+	CLIENT *clnt;

-	memset(&sun, 0, sizeof sun);
-	sock = socket(AF_LOCAL, SOCK_STREAM, 0);
-	if (sock < 0)
-		return NULL;
+	localhandle = setnetconfig();
+	while ((nconf = getnetconfig(localhandle)) != NULL) {
+		if (nconf->nc_protofmly != NULL &&
+		    strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
+			break;
+	}
+	if (nconf == NULL) {
+		warnx("getnetconfig: %s", nc_sperror());
+		return (NULL);
+	}

-	sun.sun_family = AF_LOCAL;
-	strcpy(sun.sun_path, _PATH_RPCBINDSOCK);
-	nbuf.len = sun.sun_len = SUN_LEN(&sun);
-	nbuf.maxlen = sizeof (struct sockaddr_un);
-	nbuf.buf = &sun;
-
-	return clnt_vc_create(sock, &nbuf, prog, vers, 0, 0);
+	clnt = clnt_tp_create(NULL, prog, vers, nconf);
+	endnetconfig(localhandle);
+	return clnt;
 }

 #ifdef PORTMAP

Do not call addrinfo on local transport adresses, if returning a
server handle (for reuse or whatever). We just return now a handle
connected to the local rpcbind.

Do not try to call checkcache, if host = NULL;

For the local transport, fill in the adress of rpcbind.

--- lib/libc/rpc/rpcb_clnt.c	Mon Apr  2 23:41:43 2001
+++ lib/libc/rpc/rpcb_clnt.c	Sat Apr 21 12:54:25 2001
@@ -300,7 +300,9 @@
 	/* Get the address of the rpcbind.  Check cache first */
 	addr_to_delete.len = 0;
 	rwlock_rdlock(&rpcbaddr_cache_lock);
-	ad_cache = check_cache(host, nconf->nc_netid);
+	ad_cache = NULL;
+	if (host != NULL)
+		ad_cache = check_cache(host, nconf->nc_netid);
 	if (ad_cache != NULL) {
 		addr = ad_cache->ac_taddr;
 		client = clnt_tli_create(RPC_ANYFD, nconf, addr,
@@ -345,9 +347,26 @@
 	    nconf->nc_netid, si.si_af, si.si_proto, si.si_socktype);
 #endif

-	if (getaddrinfo(host, "sunrpc", &hints, &res) != 0) {
-		rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
-		return NULL;
+	if (nconf->nc_protofmly != NULL && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
+		client = local_rpcb();
+		if (! client) {
+#ifdef ND_DEBUG
+			clnt_pcreateerror("rpcbind clnt interface");
+#endif
+			return (NULL);
+		} else {
+			struct sockaddr_un sun;
+
+			*targaddr = malloc(sizeof(sun.sun_path));
+			strncpy(*targaddr, _PATH_RPCBINDSOCK,
+			    sizeof(sun.sun_path));
+			return (client);
+		}
+	} else {
+		if (getaddrinfo(host, "sunrpc", &hints, &res) != 0) {
+			rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
+			return NULL;
+		}
 	}

 	for (tres = res; tres != NULL; tres = tres->ai_next) {
@@ -392,7 +411,8 @@
 			break;
 		}
 	}
-	freeaddrinfo(res);
+	if (res)
+		freeaddrinfo(res);
 	return (client);
 }

lib/libc/rpc/svc_vc.c

Finally fix the credential stuff. I had to look at the code a long long
time before I've seen what exactly was the breakage.

In NetBSD, Solaris, xprt->xp_p2 pointed directly to the credentials,
in FreeBSD xprt->xp_verf.oa_base was a pointer to a struct cmessage,
which is defined as follow:

struct cmessage {
        struct cmsghdr cmsg;
        struct cmsgcred cmcred;
};

The credentials were submitted the right way and xprt->xp_p2 pointed to them.
But cb_verf.oa_flavor was still empty. There was an assignment missing
in svc_recv() in svc_vc.c:

msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;

Also

+       if (addr.ss_family == AF_LOCAL) {
+               xprt->xp_raddr = *(struct sockaddr_in *)xprt->xp_rtaddr.buf;
+               xprt->xp_addrlen = sizeof (struct sockaddr_in);
+       }

was missing. But the first seems not to be needed:

I guess in rpc.yppasswdd there was a typo:

- transp>xp_verf.oa_flavor != AUTH_UNIX) {
+ rqstp->rq_cred.oa_flavor != AUTH_UNIX) {

This little fix does fix the breakage in rpc.yppasswdd :-)

+       if (msg.msg_controllen == 0 ||
+           (msg.msg_flags & MSG_CTRUNC) != 0)
+               return (-1);

We cannot set the cb_verf.oa_length in svc_recv() of svc_vc.c, the credentials
get overwritten then, and that's bad.

diff -ruN lib/libc/rpc/svc_vc.c lib/libc/rpc/svc_vc.c
--- lib/libc/rpc/svc_vc.c.orig	Thu Oct  4 15:11:41 2001
+++ lib/libc/rpc/svc_vc.c	Thu Oct  4 20:55:17 2001
@@ -313,6 +313,10 @@
 		return (FALSE);
 	memcpy(xprt->xp_rtaddr.buf, &addr, len);
 	xprt->xp_rtaddr.len = len;
+	if (addr.ss_family == AF_LOCAL) {
+		xprt->xp_raddr = *(struct sockaddr_in *)xprt->xp_rtaddr.buf;
+		xprt->xp_addrlen = sizeof (struct sockaddr_in);
+	}
 #ifdef PORTMAP
 	if (addr.ss_family == AF_INET) {
 		xprt->xp_raddr = *(struct sockaddr_in *)xprt->xp_rtaddr.buf;
@@ -423,13 +427,15 @@
 		}
 	} while ((pollfd.revents & POLLIN) == 0);

+	cm = NULL;
 	sa = (struct sockaddr *)xprt->xp_rtaddr.buf;
 	if (sa->sa_family == AF_LOCAL) {
 		cm = (struct cmessage *)xprt->xp_verf.oa_base;
 		if ((len = __msgread_withcred(sock, buf, len, cm)) > 0) {
 			xprt->xp_p2 = &cm->cmcred;
 			return (len);
-		}
+		} else
+			goto fatal_err;
 	} else {
 		if ((len = _read(sock, buf, (size_t)len)) > 0)
 			return (len);
@@ -656,7 +663,12 @@
 	ret = _recvmsg(sock, &msg, 0);
 	bcopy(&cm.cmsg, &cmp->cmsg, sizeof(cmp->cmsg));
 	bcopy(CMSG_DATA(&cm), &cmp->cmcred, sizeof(cmp->cmcred));
-	return ret;
+
+	if (msg.msg_controllen == 0 ||
+	   (msg.msg_flags & MSG_CTRUNC) != 0)
+		return (-1);
+
+	return (ret);
 }

 static int
@@ -696,10 +708,21 @@
 __rpc_get_local_uid(SVCXPRT *transp, uid_t *uid)
 {
 	struct cmsgcred *cmcred;
+	struct cmessage *cm;
+	struct cmsghdr *cmp;
+
+	cm = (struct cmessage *)transp->xp_verf.oa_base;
+
+	if (cm == NULL)
+		return (-1);
+	cmp = &cm->cmsg;
+	if (cmp == NULL || cmp->cmsg_level != SOL_SOCKET ||
+	   cmp->cmsg_type != SCM_CREDS)
+		return (-1);

 	cmcred = __svc_getcallercreds(transp);
 	if (cmcred == NULL)
-		return(-1);
+		return (-1);
 	*uid = cmcred->cmcred_euid;
-	return(0);
+	return (0);
 }
Comment 4 Martin Blapp freebsd_committer freebsd_triage 2002-02-09 20:41:27 UTC
State Changed
From-To: open->closed

Alfred comitted my fixes. Thanks