示例#1
0
/**
 * nsm_update_kernel_state - attempt to post new NSM state to kernel
 * @state: NSM state number
 *
 */
void
nsm_update_kernel_state(const int state)
{
	ssize_t result;
	char buf[20];
	int fd, len;

	fd = open(NSM_KERNEL_STATE_FILE, O_WRONLY);
	if (fd == -1) {
		xlog(D_GENERAL, "Failed to open " NSM_KERNEL_STATE_FILE ": %m");
		return;
	}

	len = snprintf(buf, sizeof(buf), "%d", state);
	if (error_check(len, sizeof(buf))) {
		xlog_warn("Failed to form NSM state number string");
		return;
	}

	result = write(fd, buf, strlen(buf));
	if (exact_error_check(result, strlen(buf)))
		xlog_warn("Failed to write NSM state number: %m");

	if (close(fd) == -1)
		xlog(L_ERROR, "Failed to close NSM state file "
				NSM_KERNEL_STATE_FILE ": %m");
}
示例#2
0
/**
 * nsm_retire_monitored_hosts - back up all hosts from "sm/" to "sm.bak/"
 *
 * Returns the count of host records that were moved.
 *
 * Note that if any error occurs during this process, some monitor
 * records may be left in the "sm" directory.
 */
unsigned int
nsm_retire_monitored_hosts(void)
{
	unsigned int count = 0;
	struct dirent *de;
	char *path;
	DIR *dir;

	path = nsm_make_pathname(NSM_MONITOR_DIR);
	if (path == NULL) {
		xlog(L_ERROR, "Failed to allocate path for " NSM_MONITOR_DIR);
		return count;
	}

	dir = opendir(path);
	free(path);
	if (dir == NULL) {
		xlog_warn("Failed to open " NSM_MONITOR_DIR ": %m");
		return count;
	}

	while ((de = readdir(dir)) != NULL) {
		char *src, *dst;

		if (de->d_type != (unsigned char)DT_REG)
			continue;
		if (de->d_name[0] == '.')
			continue;

		src = nsm_make_record_pathname(NSM_MONITOR_DIR, de->d_name);
		if (src == NULL) {
			xlog_warn("Bad monitor file name, skipping");
			continue;
		}

		dst = nsm_make_record_pathname(NSM_NOTIFY_DIR, de->d_name);
		if (dst == NULL) {
			free(src);
			xlog_warn("Bad notify file name, skipping");
			continue;
		}

		if (rename(src, dst) == -1)
			xlog_warn("Failed to rename %s -> %s: %m",
				src, dst);
		else {
			xlog(D_GENERAL, "Retired record for mon_name %s",
					de->d_name);
			count++;
		}

		free(dst);
		free(src);
	}

	(void)closedir(dir);
	return count;
}
示例#3
0
/* find_local - find all IP addresses for this host */
static int
find_local(void)
{
    struct ifconf ifc;
    struct ifreq ifreq;
    struct ifreq *ifr;
    struct ifreq *the_end;
    int     sock;
    char    buf[BUFSIZ];

    /*
     * Get list of network interfaces. We use a huge buffer to allow for the
     * presence of non-IP interfaces.
     */

    if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
	xlog_warn("%s: socket(2): %m", __func__);
	return (0);
    }
    ifc.ifc_len = sizeof(buf);
    ifc.ifc_buf = buf;
    if (ioctl(sock, SIOCGIFCONF, (char *) &ifc) < 0) {
	xlog_warn("%s: ioctl(SIOCGIFCONF): %m", __func__);
	(void) close(sock);
	return (0);
    }
    /* Get IP address of each active IP network interface. */

    the_end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
    num_local = 0;
    for (ifr = ifc.ifc_req; ifr < the_end; ifr++) {
	if (ifr->ifr_addr.sa_family == AF_INET) {	/* IP net interface */
	    ifreq = *ifr;
	    if (ioctl(sock, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
		xlog_warn("%s: ioctl(SIOCGIFFLAGS): %m", __func__);
	    } else if (ifreq.ifr_flags & IFF_UP) {	/* active interface */
		if (ioctl(sock, SIOCGIFADDR, (char *) &ifreq) < 0) {
		    xlog_warn("%s: ioctl(SIOCGIFADDR): %m", __func__);
		} else {
		    if (num_local >= num_addrs)
			if (grow_addrs() == 0)
			    break;
		    addrs[num_local++] = ((struct sockaddr_in *)
					  & ifreq.ifr_addr)->sin_addr;
		}
	    }
	}
	/* Support for variable-length addresses. */
#ifdef HAS_SA_LEN
	ifr = (struct ifreq *) ((caddr_t) ifr
		      + ifr->ifr_addr.sa_len - sizeof(struct sockaddr));
#endif
    }
    (void) close(sock);
    return (num_local);
}
示例#4
0
文件: rmtcall.c 项目: KunX/nfs-utils
static notify_list *
recv_rply(u_long *portp)
{
	char			msgbuf[NSM_MAXMSGSIZE];
	ssize_t			msglen;
	notify_list		*lp = NULL;
	XDR			xdr;
	struct sockaddr_in	sin;
	socklen_t		alen = (socklen_t)sizeof(sin);
	uint32_t		xid;

	memset(msgbuf, 0, sizeof(msgbuf));
	msglen = recvfrom(sockfd, msgbuf, sizeof(msgbuf), 0,
				(struct sockaddr *)(char *)&sin, &alen);
	if (msglen == (ssize_t)-1) {
		xlog_warn("%s: recvfrom failed: %m", __func__);
		return NULL;
	}

	memset(&xdr, 0, sizeof(xdr));
	xdrmem_create(&xdr, msgbuf, (unsigned int)msglen, XDR_DECODE);
	xid = nsm_parse_reply(&xdr);
	if (xid == 0)
		goto done;
	if (sin.sin_addr.s_addr != htonl(INADDR_LOOPBACK)) {
		struct in_addr addr = sin.sin_addr;
		char buf[INET_ADDRSTRLEN];

		xlog_warn("%s: Unrecognized reply from %s", __func__,
				inet_ntop(AF_INET, &addr, buf,
						(socklen_t)sizeof(buf)));
		goto done;
	}

	for (lp = notify; lp != NULL; lp = lp->next) {
		/* LH - this was a bug... it should have been checking
		 * the xid from the response message from the client,
		 * not the static, internal xid */
		if (lp->xid != xid)
			continue;
		if (lp->port == 0)
			*portp = nsm_recv_getport(&xdr);
		break;
	}

done:
	xdr_destroy(&xdr);
	return lp;
}
示例#5
0
static int grow_addrs(void)
{
    struct in_addr *new_addrs;
    int     new_num;

    /*
     * Keep the previous result if we run out of memory. The system would
     * really get hosed if we simply give up.
     */
    new_num = (addrs == 0) ? 1 : num_addrs + num_addrs;
    new_addrs = (struct in_addr *) malloc(sizeof(*addrs) * new_num);
    if (new_addrs == 0) {
	xlog_warn("%s: out of memory", __func__);
	return (0);
    } else {
	if (addrs != 0) {
	    memcpy((char *) new_addrs, (char *) addrs,
		   sizeof(*addrs) * num_addrs);
	    free((char *) addrs);
	}
	num_addrs = new_num;
	addrs = new_addrs;
	return (1);
    }
}
示例#6
0
文件: rmtcall.c 项目: KunX/nfs-utils
/*
 * Process a datagram received on the notify socket
 */
int
process_reply(FD_SET_TYPE *rfds)
{
	notify_list		*lp;
	u_long			port;

	if (sockfd == -1 || !FD_ISSET(sockfd, rfds))
		return 0;

	if (!(lp = recv_rply(&port)))
		return 1;

	if (lp->port == 0) {
		if (port != 0) {
			lp->port = htons((unsigned short) port);
			process_entry(lp);
			NL_WHEN(lp) = time(NULL) + NOTIFY_TIMEOUT;
			nlist_remove(&notify, lp);
			nlist_insert_timer(&notify, lp);
			return 1;
		}
		xlog_warn("%s: service %d not registered on localhost",
			__func__, NL_MY_PROG(lp));
	} else {
		xlog(D_GENERAL, "%s: Callback to %s (for %d) succeeded",
			__func__, NL_MY_NAME(lp), NL_MON_NAME(lp));
	}
	nlist_free(&notify, lp);
	return 1;
}
示例#7
0
/**
 * nsm_insert_monitored_host - write callback data for one host to disk
 * @hostname: C string containing a hostname
 * @sap: sockaddr containing NLM callback address
 * @mon: SM_MON arguments to save
 *
 * Returns true if successful, otherwise false if some error occurs.
 */
_Bool
nsm_insert_monitored_host(const char *hostname, const struct sockaddr *sap,
		const struct mon *m)
{
	static char buf[LINELEN + 1 + SM_MAXSTRLEN + 2];
	char *path;
	_Bool result = false;
	ssize_t len;
	size_t size;
	int fd;

	path = nsm_make_record_pathname(NSM_MONITOR_DIR, hostname);
	if (path == NULL) {
		xlog(L_ERROR, "Failed to insert: bad monitor hostname '%s'",
				hostname);
		return false;
	}

	size = nsm_create_monitor_record(buf, sizeof(buf), sap, m);
	if (size == 0) {
		xlog(L_ERROR, "Failed to insert: record too long");
		goto out;
	}

	/*
	 * If exclusive create fails, we're adding a new line to an
	 * existing file.
	 */
	fd = open(path, O_WRONLY | O_CREAT | O_EXCL | O_SYNC, S_IRUSR | S_IWUSR);
	if (fd == -1) {
		if (errno != EEXIST) {
			xlog(L_ERROR, "Failed to insert: creating %s: %m", path);
			goto out;
		}

		result = nsm_append_monitored_host(path, buf);
		goto out;
	}
	result = true;

	len = write(fd, buf, size);
	if (exact_error_check(len, size)) {
		xlog_warn("Failed to insert: writing %s: %m", path);
		(void)unlink(path);
		result = false;
	}

	if (close(fd) == -1) {
		xlog(L_ERROR, "Failed to insert: closing %s: %m", path);
		(void)unlink(path);
		result = false;
	}

out:
	free(path);
	return result;
}
示例#8
0
文件: monitor.c 项目: ANFS/ANFS-utils
struct sm_stat *
sm_unmon_all_1_svc(struct my_id *argp, struct svc_req *rqstp)
{
	short int       count = 0;
	static sm_stat  result;
	notify_list	*clnt;
	char		*my_name = argp->my_name;

	xlog(D_CALL, "Received SM_UNMON_ALL for %s", my_name);

	if (!caller_is_localhost(rqstp))
		goto failure;

	result.state = MY_STATE;

	if (rtnl == NULL) {
		xlog_warn("Received SM_UNMON_ALL request from %s "
			"while not monitoring any hosts", my_name);
		return (&result);
	}
	clnt = rtnl;

	while ((clnt = nlist_gethost(clnt, my_name, 1))) {
		if (NL_MY_PROC(clnt) == argp->my_proc &&
			NL_MY_PROG(clnt) == argp->my_prog &&
			NL_MY_VERS(clnt) == argp->my_vers) {
			/* Watch stack! */
			char            mon_name[SM_MAXSTRLEN + 1];
			notify_list	*temp;

			xlog(D_GENERAL,
				"UNMONITORING (SM_UNMON_ALL) %s for %s",
				NL_MON_NAME(clnt), NL_MY_NAME(clnt));
			strncpy(mon_name, NL_MON_NAME(clnt),
				sizeof (mon_name) - 1);
			mon_name[sizeof (mon_name) - 1] = '\0';
			temp = NL_NEXT(clnt);
			/* PRC: do the HA callout: */
			ha_callout("del-client", mon_name, my_name, -1);
			nsm_delete_monitored_host(clnt->dns_name,
							mon_name, my_name);
			nlist_free(&rtnl, clnt);
			++count;
			clnt = temp;
		} else
			clnt = NL_NEXT(clnt);
	}

	if (!count) {
		xlog(D_GENERAL, "SM_UNMON_ALL request from %s with no "
			"SM_MON requests from it", my_name);
	}

 failure:
	return (&result);
}
示例#9
0
/**
 * nsm_get_state - retrieve on-disk NSM state number
 *
 * Returns an odd NSM state number read from disk, or an initial
 * state number.  Zero is returned if some error occurs.
 */
int
nsm_get_state(_Bool update)
{
	int fd, state = 0;
	ssize_t result;
	char *path = NULL;

	path = nsm_make_pathname(NSM_STATE_FILE);
	if (path == NULL) {
		xlog(L_ERROR, "Failed to allocate path for " NSM_STATE_FILE);
		goto out;
	}

	fd = open(path, O_RDONLY);
	if (fd == -1) {
		if (errno != ENOENT) {
			xlog(L_ERROR, "Failed to open %s: %m", path);
			goto out;
		}

		xlog(L_NOTICE, "Initializing NSM state");
		state = 1;
		update = true;
		goto update;
	}

	result = read(fd, &state, sizeof(state));
	if (exact_error_check(result, sizeof(state))) {
		xlog_warn("Failed to read %s: %m", path);

		xlog(L_NOTICE, "Initializing NSM state");
		state = 1;
		update = true;
		goto update;
	}

	if ((state & 1) == 0)
		state++;

update:
	if(fd >= 0)
		(void)close(fd);

	if (update) {
		state += 2;
		if (!nsm_atomic_write(path, &state, sizeof(state)))
			state = 0;
	}

out:
	free(path);
	return state;
}
示例#10
0
/*
 * Services SM_NOTIFY requests.
 *
 * When NLM uses an SM_MON request to tell statd to monitor a remote,
 * the request contains a "mon_name" argument.  This is usually the
 * "caller_name" argument of an NLMPROC_LOCK request.  On Linux, the
 * NLM can send statd the remote's IP address instead of its
 * caller_name.  The NSM protocol does not allow both the remote's
 * caller_name and it's IP address to be sent in the same SM_MON
 * request.
 *
 * The remote's caller_name is useful because it makes it simple
 * to identify rebooting remotes by matching the "mon_name" argument
 * they sent via an SM_NOTIFY request.
 *
 * The caller_name string may not be a fully qualified domain name,
 * or even registered in the DNS database, however.  Having the
 * remote's IP address is useful because then there is no ambiguity
 * about where to send an SM_NOTIFY after the local system reboots.
 *
 * Without the actual caller_name, however, statd must use an
 * heuristic to match an incoming SM_NOTIFY request to one of the
 * hosts it is currently monitoring.  The incoming mon_name in an
 * SM_NOTIFY address is converted to a list of IP addresses using
 * DNS.  Each mon_name on statd's monitor list is also converted to
 * an address list, and the two lists are checked to see if there is
 * a matching address.
 *
 * There are some risks to this strategy:
 *
 *   1.  The external DNS database is not reliable.  It can change
 *       over time, or the forward and reverse mappings could be
 *       inconsistent.
 *
 *   2.  If statd's monitor list becomes substantial, finding a match
 *       can generate a not inconsequential amount of DNS traffic.
 *
 *   3.  statd is a single-threaded service.  When DNS becomes slow or
 *       unresponsive, statd also becomes slow or unresponsive.
 *
 *   4.  If the remote does not have a DNS entry at all (or if the
 *       remote can resolve itself, but the local host can't resolve
 *       the remote's hostname), the remote cannot be monitored, and
 *       therefore NLM locking cannot be provided for that host.
 *
 *   5.  Local DNS resolution can produce different results for the
 *       mon_name than the results the remote might see for the same
 *       query, especially if the remote did not send a caller_name
 *       or mon_name that is a fully qualified domain name.
 *
 *       Note that a caller_name is passed from NFS client to server,
 *       but the client never knows what mon_name the server might use
 *       to notify it of a reboot.  On Linux, the client extracts the
 *       server's name from the devname it was passed by the mount
 *       command.  This is often not a fully-qualified domain name.
 */
void *
sm_notify_1_svc(struct stat_chge *argp, struct svc_req *rqstp)
{
	notify_list    *lp, *call;
	static char    *result = NULL;
	struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
	char		ip_addr[INET6_ADDRSTRLEN];

	xlog(D_CALL, "Received SM_NOTIFY from %s, state: %d",
				argp->mon_name, argp->state);

	/* quick check - don't bother if we're not monitoring anyone */
	if (rtnl == NULL) {
		xlog_warn("SM_NOTIFY from %s while not monitoring any hosts",
				argp->mon_name);
		return ((void *) &result);
	}

	if (!statd_present_address(sap, ip_addr, sizeof(ip_addr))) {
		xlog_warn("Unrecognized sender address");
		return ((void *) &result);
	}

	/* okir change: statd doesn't remove the remote host from its
	 * internal monitor list when receiving an SM_NOTIFY call from
	 * it. Lockd will want to continue monitoring the remote host
	 * until it issues an SM_UNMON call.
	 */
	for (lp = rtnl ; lp ; lp = lp->next)
		if (NL_STATE(lp) != argp->state &&
		    (statd_matchhostname(argp->mon_name, lp->dns_name) ||
		     statd_matchhostname(ip_addr, lp->dns_name))) {
			NL_STATE(lp) = argp->state;
			call = nlist_clone(lp);
			nlist_insert(&notify, call);
		}


	return ((void *) &result);
}
示例#11
0
文件: monitor.c 项目: ANFS/ANFS-utils
/*
 * Reject requests from non-loopback addresses in order
 * to prevent attack described in CERT CA-99.05.
 *
 * Although the kernel contacts the statd service via only IPv4
 * transports, the statd service can receive other requests, such
 * as SM_NOTIFY, from remote peers via IPv6.
 */
static _Bool
caller_is_localhost(struct svc_req *rqstp)
{
	struct sockaddr *sap = nfs_getrpccaller(rqstp->rq_xprt);
	char buf[INET6_ADDRSTRLEN];

	if (!nfs_is_v4_loopback(sap))
		goto out_nonlocal;
	return true;

out_nonlocal:
	if (!statd_present_address(sap, buf, sizeof(buf)))
		buf[0] = '\0';
	xlog_warn("SM_MON/SM_UNMON call from non-local host %s", buf);
	return false;
}
示例#12
0
文件: rmtcall.c 项目: KunX/nfs-utils
/*
 * Notify operation for a single list entry
 */
static int
process_entry(notify_list *lp)
{
	struct sockaddr_in	sin;

	if (NL_TIMES(lp) == 0) {
		xlog(D_GENERAL, "%s: Cannot notify localhost, giving up",
				__func__);
		return 0;
	}

	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port   = lp->port;
	/* LH - moved address into switch */

	/* __FORCE__ loopback for callbacks to lockd ... */
	/* Just in case we somehow ignored it thus far */
	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);

	if (sin.sin_port == 0)
		lp->xid = nsm_xmit_getport(sockfd, &sin,
					(rpcprog_t)NL_MY_PROG(lp),
					(rpcvers_t)NL_MY_VERS(lp));
	else {
		struct mon m;

		memcpy(m.priv, NL_PRIV(lp), SM_PRIV_SIZE);

		m.mon_id.mon_name = NL_MON_NAME(lp);
		m.mon_id.my_id.my_name = NULL;
		m.mon_id.my_id.my_prog = NL_MY_PROG(lp);
		m.mon_id.my_id.my_vers = NL_MY_VERS(lp);
		m.mon_id.my_id.my_proc = NL_MY_PROC(lp);

		lp->xid = nsm_xmit_nlmcall(sockfd,
				(struct sockaddr *)(char *)&sin,
				(socklen_t)sizeof(sin), &m, NL_STATE(lp));
	}
	if (lp->xid == 0) {
		xlog_warn("%s: failed to notify port %d",
				__func__, ntohs(lp->port));
	}
	NL_TIMES(lp) -= 1;

	return 1;
}
示例#13
0
/*
 * Clear all the keys on the given keyring
 */
static int keyring_clear(const char *keyring)
{
	key_serial_t key;

	key = find_key_by_type_and_desc("keyring", keyring, 0);
	if (key == -1) {
		xlog_err("'%s' keyring was not found.", keyring);
		return EXIT_FAILURE;
	}

	if (keyctl_clear(key) < 0) {
		xlog_err("keyctl_clear(0x%x) failed: %m",
				(unsigned int)key);
		return EXIT_FAILURE;
	}
	
	if (verbose)
		xlog_warn("'%s' cleared", keyring);

	return EXIT_SUCCESS;
}
示例#14
0
/*
 * Clear all the keys on the given keyring
 */
static int keyring_clear(char *keyring)
{
	FILE *fp;
	char buf[BUFSIZ];
	key_serial_t key;

	if (keyring == NULL)
		keyring = DEFAULT_KEYRING;

	if ((fp = fopen(PROCKEYS, "r")) == NULL) {
		xlog_err("fopen(%s) failed: %m", PROCKEYS);
		return 1;
	}

	while(fgets(buf, BUFSIZ, fp) != NULL) {
		if (strstr(buf, "keyring") == NULL)
			continue;
		if (strstr(buf, keyring) == NULL)
			continue;
		if (verbose) {
			*(strchr(buf, '\n')) = '\0';
			xlog_warn("clearing '%s'", buf);
		}
		/*
		 * The key is the first arugment in the string
		 */
		*(strchr(buf, ' ')) = '\0';
		sscanf(buf, "%x", &key);
		if (keyctl_clear(key) < 0) {
			xlog_err("keyctl_clear(0x%x) failed: %m", key);
			fclose(fp);
			return 1;
		}
		fclose(fp);
		return 0;
	}
	xlog_err("'%s' keyring was not found.", keyring);
	fclose(fp);
	return 1;
}
示例#15
0
/**
 * nsm_retire_monitored_hosts - back up all hosts from "sm/" to "sm.bak/"
 *
 * Returns the count of host records that were moved.
 *
 * Note that if any error occurs during this process, some monitor
 * records may be left in the "sm" directory.
 */
unsigned int
nsm_retire_monitored_hosts(void)
{
	unsigned int count = 0;
	struct dirent *de;
	char *path;
	DIR *dir;

	path = nsm_make_pathname(NSM_MONITOR_DIR);
	if (path == NULL) {
		xlog(L_ERROR, "Failed to allocate path for " NSM_MONITOR_DIR);
		return count;
	}

	dir = opendir(path);
	free(path);
	if (dir == NULL) {
		xlog_warn("Failed to open " NSM_MONITOR_DIR ": %m");
		return count;
	}

	while ((de = readdir(dir)) != NULL) {
		char *src, *dst;
		struct stat stb;

		if (de->d_name[0] == '.')
			continue;

		src = nsm_make_record_pathname(NSM_MONITOR_DIR, de->d_name);
		if (src == NULL) {
			xlog_warn("Bad monitor file name, skipping");
			continue;
		}

		/* NB: not all file systems fill in d_type correctly */
		if (lstat(src, &stb) == -1) {
			xlog_warn("Bad monitor file %s, skipping: %m",
					de->d_name);
			free(src);
			continue;
		}
		if (!S_ISREG(stb.st_mode)) {
			xlog(D_GENERAL, "Skipping non-regular file %s",
					de->d_name);
			free(src);
			continue;
		}

		dst = nsm_make_record_pathname(NSM_NOTIFY_DIR, de->d_name);
		if (dst == NULL) {
			free(src);
			xlog_warn("Bad notify file name, skipping");
			continue;
		}

		if (rename(src, dst) == -1)
			xlog_warn("Failed to rename %s -> %s: %m",
				src, dst);
		else {
			xlog(D_GENERAL, "Retired record for mon_name %s",
					de->d_name);
			count++;
		}

		free(dst);
		free(src);
	}

	(void)closedir(dir);
	return count;
}
示例#16
0
/*
 * Revoke a key 
 */
static int key_invalidate(char *keystr, int keymask)
{
	FILE *fp;
	char buf[BUFSIZ], *ptr;
	key_serial_t key;
	int mask;

	xlog_syslog(0);

	if ((fp = fopen(PROCKEYS, "r")) == NULL) {
		xlog_err("fopen(%s) failed: %m", PROCKEYS);
		return EXIT_FAILURE;
	}

	while(fgets(buf, BUFSIZ, fp) != NULL) {
		if (strstr(buf, "keyring") != NULL)
			continue;

		mask = 0;
		if ((ptr = strstr(buf, "uid:")) != NULL)
			mask = UIDKEYS;
		else if ((ptr = strstr(buf, "gid:")) != NULL)
			mask = GIDKEYS;
		else 
			continue;

		if ((keymask & mask) == 0)
			continue;

		if (strncmp(ptr+4, keystr, strlen(keystr)) != 0)
			continue;

		if (verbose) {
			*(strchr(buf, '\n')) = '\0';
			xlog_warn("invalidating '%s'", buf);
		}
		/*
		 * The key is the first arugment in the string
		 */
		*(strchr(buf, ' ')) = '\0';
		sscanf(buf, "%x", &key);

/* older libkeyutils compatibility */
#ifndef KEYCTL_INVALIDATE
#define KEYCTL_INVALIDATE 21      /* invalidate a key */
#endif
		if (keyctl(KEYCTL_INVALIDATE, key) < 0) {
			if (errno != EOPNOTSUPP) {
				xlog_err("keyctl_invalidate(0x%x) failed: %m", key);
				fclose(fp);
				return EXIT_FAILURE;
			} else {
				/* older kernel compatibility attempt: */
				if (keyctl_revoke(key) < 0) {
					xlog_err("keyctl_revoke(0x%x) failed: %m", key);
					fclose(fp);
					return EXIT_FAILURE;
				}
			}
		}

		keymask &= ~mask;
		if (keymask == 0) {
			fclose(fp);
			return EXIT_SUCCESS;
		}
	}
	xlog_err("'%s' key was not found.", keystr);
	fclose(fp);
	return EXIT_FAILURE;
}
示例#17
0
/**
 * nsm_drop_privileges - drop root privileges
 * @pidfd: file descriptor of a pid file
 *
 * Returns true if successful, or false if some error occurred.
 *
 * Set our effective UID and GID to that of our on-disk database.
 */
_Bool
nsm_drop_privileges(const int pidfd)
{
	struct stat st;

	(void)umask(S_IRWXO);

	/*
	 * XXX: If we can't stat dirname, or if dirname is owned by
	 *      root, we should use "statduser" instead, which is set up
	 *      by configure.ac.  Nothing in nfs-utils seems to use
	 *      "statduser," though.
	 */
	if (lstat(nsm_base_dirname, &st) == -1) {
		xlog(L_ERROR, "Failed to stat %s: %m", nsm_base_dirname);
		return false;
	}

	if (chdir(nsm_base_dirname) == -1) {
		xlog(L_ERROR, "Failed to change working directory to %s: %m",
				nsm_base_dirname);
		return false;
	}

	if (!prune_bounding_set())
		return false;

	if (st.st_uid == 0) {
		xlog_warn("Running as root.  "
			"chown %s to choose different user", nsm_base_dirname);
		return true;
	}

	/*
	 * If the pidfile happens to reside on NFS, dropping privileges
	 * will probably cause us to lose access, even though we are
	 * holding it open.  Chown it to prevent this.
	 */
	if (pidfd >= 0)
		if (fchown(pidfd, st.st_uid, st.st_gid) == -1)
			xlog_warn("Failed to change owner of pidfile: %m");

	/*
	 * Don't clear capabilities when dropping root.
	 */
        if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) {
                xlog(L_ERROR, "prctl(PR_SET_KEEPCAPS) failed: %m");
		return false;
	}

	if (setgroups(0, NULL) == -1) {
		xlog(L_ERROR, "Failed to drop supplementary groups: %m");
		return false;
	}

	/*
	 * ORDER
	 *
	 * setgid(2) first, as setuid(2) may remove privileges needed
	 * to set the group id.
	 */
	if (setgid(st.st_gid) == -1 || setuid(st.st_uid) == -1) {
		xlog(L_ERROR, "Failed to drop privileges: %m");
		return false;
	}

	xlog(D_CALL, "Effective UID, GID: %u, %u", st.st_uid, st.st_gid);

	return nsm_clear_capabilities();
}
示例#18
0
文件: monitor.c 项目: ANFS/ANFS-utils
/*
 * Services SM_MON requests.
 */
struct sm_stat_res *
sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp)
{
	static sm_stat_res result;
	char		*mon_name = argp->mon_id.mon_name,
			*my_name  = argp->mon_id.my_id.my_name;
	struct my_id	*id = &argp->mon_id.my_id;
	char		*cp;
	notify_list	*clnt;
	struct sockaddr_in my_addr = {
		.sin_family		= AF_INET,
		.sin_addr.s_addr	= htonl(INADDR_LOOPBACK),
	};
	char *dnsname = NULL;

	xlog(D_CALL, "Received SM_MON for %s from %s", mon_name, my_name);

	/* Assume that we'll fail. */
	result.res_stat = STAT_FAIL;
	result.state = -1;	/* State is undefined for STAT_FAIL. */

	/* 1.	Reject any remote callers.
	 *	Ignore the my_name specified by the caller, and
	 *	use "127.0.0.1" instead.
	 */
	if (!caller_is_localhost(rqstp))
		goto failure;

	/* 2.	Reject any registrations for non-lockd services.
	 *
	 *	This is specific to the linux kernel lockd, which
	 *	makes the callback procedure part of the lockd interface.
	 *	It is also prone to break when lockd changes its callback
	 *	procedure number -- which, in fact, has now happened once.
	 *	There must be a better way....   XXX FIXME
	 */
	if (id->my_prog != 100021 ||
	    (id->my_proc != 16 && id->my_proc != 24))
	{
		xlog_warn("Attempt to register callback to %d/%d",
			id->my_prog, id->my_proc);
		goto failure;
	}

	/*
	 * Check hostnames.  If I can't look them up, I won't monitor.  This
	 * might not be legal, but it adds a little bit of safety and sanity.
	 */

	/* must check for /'s in hostname!  See CERT's CA-96.09 for details. */
	if (strchr(mon_name, '/') || mon_name[0] == '.') {
		xlog(L_ERROR, "SM_MON request for hostname containing '/' "
		     "or starting '.': %s", mon_name);
		xlog(L_ERROR, "POSSIBLE SPOOF/ATTACK ATTEMPT!");
		goto failure;
	}

	/* my_name must not have white space */
	for (cp=my_name ; *cp ; cp++)
		if (*cp == ' ' || *cp == '\t' || *cp == '\r' || *cp == '\n')
			*cp = '_';

	/*
	 * Hostnames checked OK.
	 * Now choose a hostname to use for matching.  We cannot
	 * really trust much in the incoming NOTIFY, so to make
	 * sure that multi-homed hosts work nicely, we get an
	 * FQDN now, and use that for matching.
	 */
	dnsname = statd_canonical_name(mon_name);
	if (dnsname == NULL) {
		xlog(L_WARNING, "No canonical hostname found for %s", mon_name);
		goto failure;
	}

	/* Now check to see if this is a duplicate, and warn if so.
	 * I will also return STAT_FAIL. (I *think* this is how I should
	 * handle it.)
	 *
	 * Olaf requests that I allow duplicate SM_MON requests for
	 * hosts due to the way he is coding lockd. No problem,
	 * I'll just do a quickie success return and things should
	 * be happy.
	 */
	clnt = rtnl;

	while ((clnt = nlist_gethost(clnt, mon_name, 0))) {
		if (statd_matchhostname(NL_MY_NAME(clnt), my_name) &&
		    NL_MY_PROC(clnt) == id->my_proc &&
		    NL_MY_PROG(clnt) == id->my_prog &&
		    NL_MY_VERS(clnt) == id->my_vers &&
		    memcmp(NL_PRIV(clnt), argp->priv, SM_PRIV_SIZE) == 0) {
			/* Hey!  We already know you guys! */
			xlog(D_GENERAL,
				"Duplicate SM_MON request for %s "
				"from procedure on %s",
				mon_name, my_name);

			/* But we'll let you pass anyway. */
			free(dnsname);
			goto success;
		}
		clnt = NL_NEXT(clnt);
	}

	/*
	 * We're committed...ignoring errors.  Let's hope that a malloc()
	 * doesn't fail.  (I should probably fix this assumption.)
	 */
	if (!(clnt = nlist_new(my_name, mon_name, 0))) {
		free(dnsname);
		xlog_warn("out of memory");
		goto failure;
	}

	NL_MY_PROG(clnt) = id->my_prog;
	NL_MY_VERS(clnt) = id->my_vers;
	NL_MY_PROC(clnt) = id->my_proc;
	memcpy(NL_PRIV(clnt), argp->priv, SM_PRIV_SIZE);
	clnt->dns_name = dnsname;

	/*
	 * Now, Create file on stable storage for host.
	 */
	if (!nsm_insert_monitored_host(dnsname,
				(struct sockaddr *)(char *)&my_addr, argp)) {
		nlist_free(NULL, clnt);
		goto failure;
	}

	/* PRC: do the HA callout: */
	ha_callout("add-client", mon_name, my_name, -1);
	nlist_insert(&rtnl, clnt);
	xlog(D_GENERAL, "MONITORING %s for %s", mon_name, my_name);
 success:
	result.res_stat = STAT_SUCC;
	/* SUN's sm_inter.x says this should be "state number of local site".
	 * X/Open says '"state" will be contain the state of the remote NSM.'
	 * href=http://www.opengroup.org/onlinepubs/9629799/SM_MON.htm
	 * Linux lockd currently (2.6.21 and prior) ignores whatever is
	 * returned, and given the above contraction, it probably always will..
	 * So we just return what we always returned.  If possible, we
	 * have already told lockd about our state number via a sysctl.
	 * If lockd wants the remote state, it will need to
	 * use SM_STAT (and prayer).
	 */
	result.state = MY_STATE;
	return (&result);

failure:
	xlog_warn("STAT_FAIL to %s for SM_MON of %s", my_name, mon_name);
	return (&result);
}

static unsigned int
load_one_host(const char *hostname,
		__attribute__ ((unused)) const struct sockaddr *sap,
		const struct mon *m,
		__attribute__ ((unused)) const time_t timestamp)
{
	notify_list *clnt;

	clnt = nlist_new(m->mon_id.my_id.my_name,
				m->mon_id.mon_name, 0);
	if (clnt == NULL)
		return 0;

	clnt->dns_name = strdup(hostname);
	if (clnt->dns_name == NULL) {
		nlist_free(NULL, clnt);
		return 0;
	}

	xlog(D_GENERAL, "Adding record for %s to the monitor list...",
			hostname);

	NL_MY_PROG(clnt) = m->mon_id.my_id.my_prog;
	NL_MY_VERS(clnt) = m->mon_id.my_id.my_vers;
	NL_MY_PROC(clnt) = m->mon_id.my_id.my_proc;
	memcpy(NL_PRIV(clnt), m->priv, SM_PRIV_SIZE);

	nlist_insert(&rtnl, clnt);
	return 1;
}

void load_state(void)
{
	unsigned int count;

	count = nsm_load_monitor_list(load_one_host);
	if (count)
		xlog(D_GENERAL, "Loaded %u previously monitored hosts");
}
示例#19
0
文件: monitor.c 项目: ANFS/ANFS-utils
/*
 * Services SM_UNMON requests.
 *
 * There is no statement in the X/Open spec's about returning an error
 * for requests to unmonitor a host that we're *not* monitoring.  I just
 * return the state of the NSM when I get such foolish requests for lack
 * of any better ideas.  (I also log the "offense.")
 */
struct sm_stat *
sm_unmon_1_svc(struct mon_id *argp, struct svc_req *rqstp)
{
	static sm_stat  result;
	notify_list	*clnt;
	char		*mon_name = argp->mon_name,
			*my_name  = argp->my_id.my_name;
	struct my_id	*id = &argp->my_id;
	char		*cp;

	xlog(D_CALL, "Received SM_UNMON for %s from %s", mon_name, my_name);

	result.state = MY_STATE;

	if (!caller_is_localhost(rqstp))
		goto failure;

	/* my_name must not have white space */
	for (cp=my_name ; *cp ; cp++)
		if (*cp == ' ' || *cp == '\t' || *cp == '\r' || *cp == '\n')
			*cp = '_';


	/* Check if we're monitoring anyone. */
	if (rtnl == NULL) {
		xlog_warn("Received SM_UNMON request from %s for %s while not "
			"monitoring any hosts", my_name, argp->mon_name);
		return (&result);
	}
	clnt = rtnl;

	/*
	 * OK, we are.  Now look for appropriate entry in run-time list.
	 * There should only be *one* match on this, since I block "duplicate"
	 * SM_MON calls.  (Actually, duplicate calls are allowed, but only one
	 * entry winds up in the list the way I'm currently handling them.)
	 */
	while ((clnt = nlist_gethost(clnt, mon_name, 0))) {
		if (statd_matchhostname(NL_MY_NAME(clnt), my_name) &&
			NL_MY_PROC(clnt) == id->my_proc &&
			NL_MY_PROG(clnt) == id->my_prog &&
			NL_MY_VERS(clnt) == id->my_vers) {
			/* Match! */
			xlog(D_GENERAL, "UNMONITORING %s for %s",
					mon_name, my_name);

			/* PRC: do the HA callout: */
			ha_callout("del-client", mon_name, my_name, -1);

			nsm_delete_monitored_host(clnt->dns_name,
							mon_name, my_name);
			nlist_free(&rtnl, clnt);

			return (&result);
		} else
			clnt = NL_NEXT(clnt);
	}

 failure:
	xlog_warn("Received erroneous SM_UNMON request from %s for %s",
		my_name, mon_name);
	return (&result);
}
示例#20
0
int main(int argc, char **argv)
{
	char *arg;
	char *value;
	char *type;
	int rc = 1, opt;
	int timeout = 600;
	key_serial_t key;
	char *progname, *keystr = NULL;
	int clearing = 0, keymask = 0, display = 0, list = 0;

	/* Set the basename */
	if ((progname = strrchr(argv[0], '/')) != NULL)
		progname++;
	else
		progname = argv[0];

	xlog_open(progname);

	while ((opt = getopt(argc, argv, "du:g:r:ct:vl")) != -1) {
		switch (opt) {
		case 'd':
			display++;
			break;
		case 'l':
			list++;
			break;
		case 'u':
			keymask = UIDKEYS;
			keystr = strdup(optarg);
			break;
		case 'g':
			keymask = GIDKEYS;
			keystr = strdup(optarg);
			break;
		case 'r':
			keymask = GIDKEYS|UIDKEYS;
			keystr = strdup(optarg);
			break;
		case 'c':
			clearing++;
			break;
		case 'v':
			verbose++;
			break;
		case 't':
			timeout = atoi(optarg);
			break;
		default:
			xlog_warn(usage, progname);
			break;
		}
	}

	if ((rc = nfs4_init_name_mapping(PATH_IDMAPDCONF)))  {
		xlog_errno(rc, "Unable to create name to user id mappings.");
		return EXIT_FAILURE;
	}
	if (!verbose)
		verbose = conf_get_num("General", "Verbosity", 0);

	if (display)
		return display_default_domain();
	if (list)
		return list_keyring(DEFAULT_KEYRING);
	if (keystr) {
		return key_invalidate(keystr, keymask);
	}
	if (clearing) {
		xlog_syslog(0);
		return keyring_clear(DEFAULT_KEYRING);
	}

	xlog_stderr(0);
	if ((argc - optind) != 2) {
		xlog_err("Bad arg count. Check /etc/request-key.conf");
		xlog_warn(usage, progname);
		return EXIT_FAILURE;
	}

	if (verbose)
		nfs4_set_debug(verbose, NULL);

	key = strtol(argv[optind++], NULL, 10);

	arg = strdup(argv[optind]);
	if (arg == NULL) {
		xlog_err("strdup failed: %m");
		return EXIT_FAILURE;
	}
	type = strtok(arg, ":");
	value = strtok(NULL, ":");
	if (value == NULL) {
		free(arg);
		xlog_err("Error: Null uid/gid value.");
		return EXIT_FAILURE;
	}
	if (verbose) {
		xlog_warn("key: 0x%lx type: %s value: %s timeout %ld",
			key, type, value, timeout);
	}

	/* Become a possesor of the to-be-instantiated key to set the key's timeout */
	request_key("keyring", DEFAULT_KEYRING, NULL, KEY_SPEC_THREAD_KEYRING);

	if (strcmp(type, "uid") == 0)
		rc = id_lookup(value, key, USER);
	else if (strcmp(type, "gid") == 0)
		rc = id_lookup(value, key, GROUP);
	else if (strcmp(type, "user") == 0)
		rc = name_lookup(value, key, USER);
	else if (strcmp(type, "group") == 0)
		rc = name_lookup(value, key, GROUP);

	/* Set timeout to 10 (600 seconds) minutes */
	if (rc == EXIT_SUCCESS)
		keyctl_set_timeout(key, timeout);

	free(arg);
	return rc;
}
示例#21
0
/*
 * Revoke a key 
 */
static int key_invalidate(char *keystr, int keymask)
{
	FILE *fp;
	char buf[BUFSIZ], *ptr;
	key_serial_t key;
	int mask;

	xlog_syslog(0);

	if ((fp = fopen(PROCKEYS, "r")) == NULL) {
		xlog_err("fopen(%s) failed: %m", PROCKEYS);
		return 1;
	}

	while(fgets(buf, BUFSIZ, fp) != NULL) {
		if (strstr(buf, "keyring") != NULL)
			continue;

		mask = 0;
		if ((ptr = strstr(buf, "uid:")) != NULL)
			mask = UIDKEYS;
		else if ((ptr = strstr(buf, "gid:")) != NULL)
			mask = GIDKEYS;
		else 
			continue;

		if ((keymask & mask) == 0)
			continue;

		if (strncmp(ptr+4, keystr, strlen(keystr)) != 0)
			continue;

		if (verbose) {
			*(strchr(buf, '\n')) = '\0';
			xlog_warn("invalidating '%s'", buf);
		}
		/*
		 * The key is the first arugment in the string
		 */
		*(strchr(buf, ' ')) = '\0';
		sscanf(buf, "%x", &key);

#ifdef HAVE_KEYCTL_INVALIDATE
#warning Using keyctl-invalidate (yay!).
		if (keyctl_invalidate(key) < 0) {
			xlog_err("keyctl_invalidate(0x%x) failed: %m", key);
			fclose(fp);
			return 1;
		}
#else
#ifdef HAVE_KEYCTL_REVOKE
#warning Using keyctl-revoke because keyctl-invalidate is not available.
		if (keyctl_revoke(key) < 0) {
			xlog_err("keyctl_invalidate(0x%x) failed: %m", key);
			fclose(fp);
			return 1;
		}
#else
#error "Need keyctl_revoke or keyctl_invalidate."
#endif
#endif
		keymask &= ~mask;
		if (keymask == 0) {
			fclose(fp);
			return 0;
		}
	}
	xlog_err("'%s' key was not found.", keystr);
	fclose(fp);
	return 1;
}