Blame cifs.idmap.c

Packit Service 09cdfc
/*
Packit Service 09cdfc
* CIFS idmap helper.
Packit Service 09cdfc
* Copyright (C) Shirish Pargaonkar (shirishp@us.ibm.com) 2011
Packit Service 09cdfc
*
Packit Service 09cdfc
* Used by /sbin/request-key.conf for handling
Packit Service 09cdfc
* cifs upcall for SID to uig/gid and uid/gid to SID mapping.
Packit Service 09cdfc
* You should have keyutils installed and add
Packit Service 09cdfc
* this lines to /etc/request-key.conf file:
Packit Service 09cdfc
Packit Service 09cdfc
    create cifs.idmap * * /usr/local/sbin/cifs.idmap %k
Packit Service 09cdfc
Packit Service 09cdfc
* This program is free software; you can redistribute it and/or modify
Packit Service 09cdfc
* it under the terms of the GNU General Public License as published by
Packit Service 09cdfc
* the Free Software Foundation; either version 2 of the License, or
Packit Service 09cdfc
* (at your option) any later version.
Packit Service 09cdfc
* This program is distributed in the hope that it will be useful,
Packit Service 09cdfc
* but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 09cdfc
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Packit Service 09cdfc
* GNU General Public License for more details.
Packit Service 09cdfc
* You should have received a copy of the GNU General Public License
Packit Service 09cdfc
* along with this program; if not, write to the Free Software
Packit Service 09cdfc
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Packit Service 09cdfc
*/
Packit Service 09cdfc
Packit Service 09cdfc
#ifdef HAVE_CONFIG_H
Packit Service 09cdfc
#include "config.h"
Packit Service 09cdfc
#endif /* HAVE_CONFIG_H */
Packit Service 09cdfc
Packit Service 09cdfc
#include <string.h>
Packit Service 09cdfc
#include <getopt.h>
Packit Service 09cdfc
#include <syslog.h>
Packit Service 09cdfc
#include <dirent.h>
Packit Service 09cdfc
#include <sys/types.h>
Packit Service 09cdfc
#include <sys/stat.h>
Packit Service 09cdfc
#include <unistd.h>
Packit Service 09cdfc
#include <keyutils.h>
Packit Service 09cdfc
#include <stdint.h>
Packit Service 09cdfc
#include <stdbool.h>
Packit Service 09cdfc
#include <stdio.h>
Packit Service 09cdfc
#include <stdlib.h>
Packit Service 09cdfc
#include <errno.h>
Packit Service 09cdfc
#include <limits.h>
Packit Service 09cdfc
Packit Service 09cdfc
#include "cifsacl.h"
Packit Service 09cdfc
#include "idmap_plugin.h"
Packit Service 09cdfc
Packit Service 09cdfc
static void *plugin_handle;
Packit Service 09cdfc
Packit Service 09cdfc
static const char *prog = "cifs.idmap";
Packit Service 09cdfc
Packit Service 09cdfc
static const struct option long_options[] = {
Packit Service 09cdfc
	{"help", 0, NULL, 'h'},
Packit Service 09cdfc
	{"timeout", 1, NULL, 't'},
Packit Service 09cdfc
	{"version", 0, NULL, 'v'},
Packit Service 09cdfc
	{NULL, 0, NULL, 0}
Packit Service 09cdfc
};
Packit Service 09cdfc
Packit Service 09cdfc
static void usage(void)
Packit Service 09cdfc
{
Packit Service 09cdfc
	fprintf(stderr, "Usage: %s [-h] [-v] [-t timeout] key_serial\n", prog);
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static char *
Packit Service 09cdfc
strget(const char *str, const char *substr)
Packit Service 09cdfc
{
Packit Service 09cdfc
	int sublen;
Packit Service 09cdfc
	char *substrptr;
Packit Service 09cdfc
Packit Service 09cdfc
	/* find the prefix */
Packit Service 09cdfc
	substrptr = strstr(str, substr);
Packit Service 09cdfc
	if (!substrptr)
Packit Service 09cdfc
		return substrptr;
Packit Service 09cdfc
Packit Service 09cdfc
	/* skip over it */
Packit Service 09cdfc
	sublen = strlen(substr);
Packit Service 09cdfc
	substrptr += sublen;
Packit Service 09cdfc
Packit Service 09cdfc
	/* if there's nothing after the prefix, return NULL */
Packit Service 09cdfc
	if (*substrptr == '\0')
Packit Service 09cdfc
		return NULL;
Packit Service 09cdfc
Packit Service 09cdfc
	return substrptr;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
/*
Packit Service 09cdfc
 * Convert a string representation of unsigned int into a numeric one. Also
Packit Service 09cdfc
 * check for incomplete string conversion and overflow.
Packit Service 09cdfc
 */
Packit Service 09cdfc
static int
Packit Service 09cdfc
str_to_uint(const char *src, unsigned int *dst)
Packit Service 09cdfc
{
Packit Service 09cdfc
	unsigned long tmp;
Packit Service 09cdfc
	char *end;
Packit Service 09cdfc
Packit Service 09cdfc
	errno = 0;
Packit Service 09cdfc
	tmp = strtoul(src, &end, 0);
Packit Service 09cdfc
Packit Service 09cdfc
	if (*end != '\0')
Packit Service 09cdfc
		return EINVAL;
Packit Service 09cdfc
	if (tmp > UINT_MAX)
Packit Service 09cdfc
		return EOVERFLOW;
Packit Service 09cdfc
Packit Service 09cdfc
	*dst = (unsigned int)tmp;
Packit Service 09cdfc
	return 0;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
static int
Packit Service 09cdfc
cifs_idmap(const key_serial_t key, const char *key_descr)
Packit Service 09cdfc
{
Packit Service 09cdfc
	int rc = 1;
Packit Service 09cdfc
	char *sidstr = NULL;
Packit Service 09cdfc
	struct cifs_sid sid;
Packit Service 09cdfc
	struct cifs_uxid cuxid;
Packit Service 09cdfc
Packit Service 09cdfc
	/*
Packit Service 09cdfc
	 * Use winbind to convert received string to a SID and lookup
Packit Service 09cdfc
	 * name and map that SID to an uid.  If either of these
Packit Service 09cdfc
	 * function calls return with an error, return an error the
Packit Service 09cdfc
	 * upcall caller.  Otherwise instanticate a key using that uid.
Packit Service 09cdfc
	 *
Packit Service 09cdfc
	 * The same applies to SID and gid mapping.
Packit Service 09cdfc
	 */
Packit Service 09cdfc
	sidstr = strget(key_descr, "os:");
Packit Service 09cdfc
	if (sidstr) {
Packit Service 09cdfc
		rc = str_to_sid(plugin_handle, sidstr, &sid;;
Packit Service 09cdfc
		if (rc) {
Packit Service 09cdfc
			syslog(LOG_DEBUG, "Unable to convert owner string %s "
Packit Service 09cdfc
				"to SID: %s", key_descr, plugin_errmsg);
Packit Service 09cdfc
			goto cifs_idmap_ret;
Packit Service 09cdfc
		}
Packit Service 09cdfc
Packit Service 09cdfc
		rc = sids_to_ids(plugin_handle, &sid, 1, &cuxid);
Packit Service 09cdfc
		if (rc || (cuxid.type != CIFS_UXID_TYPE_UID &&
Packit Service 09cdfc
			   cuxid.type != CIFS_UXID_TYPE_BOTH)) {
Packit Service 09cdfc
			syslog(LOG_DEBUG, "Unable to convert %s to "
Packit Service 09cdfc
				"UID: %s", key_descr, plugin_errmsg);
Packit Service 09cdfc
			rc = rc ? rc : -EINVAL;
Packit Service 09cdfc
			goto cifs_idmap_ret;
Packit Service 09cdfc
		}
Packit Service 09cdfc
		rc = keyctl_instantiate(key, &cuxid.id.uid, sizeof(uid_t), 0);
Packit Service 09cdfc
		if (rc)
Packit Service 09cdfc
			syslog(LOG_ERR, "%s: key inst: %s", __func__,
Packit Service 09cdfc
					strerror(errno));
Packit Service 09cdfc
Packit Service 09cdfc
		goto cifs_idmap_ret;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	sidstr = strget(key_descr, "gs:");
Packit Service 09cdfc
	if (sidstr) {
Packit Service 09cdfc
		rc = str_to_sid(plugin_handle, sidstr, &sid;;
Packit Service 09cdfc
		if (rc) {
Packit Service 09cdfc
			syslog(LOG_DEBUG, "Unable to convert group string %s "
Packit Service 09cdfc
				"to SID: %s", key_descr, plugin_errmsg);
Packit Service 09cdfc
			goto cifs_idmap_ret;
Packit Service 09cdfc
		}
Packit Service 09cdfc
Packit Service 09cdfc
		rc = sids_to_ids(plugin_handle, &sid, 1, &cuxid);
Packit Service 09cdfc
		if (rc || (cuxid.type != CIFS_UXID_TYPE_GID &&
Packit Service 09cdfc
			   cuxid.type != CIFS_UXID_TYPE_BOTH)) {
Packit Service 09cdfc
			syslog(LOG_DEBUG, "Unable to convert %s to "
Packit Service 09cdfc
				"GID: %s", key_descr, plugin_errmsg);
Packit Service 09cdfc
			rc = rc ? rc : -EINVAL;
Packit Service 09cdfc
			goto cifs_idmap_ret;
Packit Service 09cdfc
		}
Packit Service 09cdfc
		rc = keyctl_instantiate(key, &cuxid.id.gid, sizeof(gid_t), 0);
Packit Service 09cdfc
		if (rc)
Packit Service 09cdfc
			syslog(LOG_ERR, "%s: key inst: %s", __func__,
Packit Service 09cdfc
					strerror(errno));
Packit Service 09cdfc
Packit Service 09cdfc
		goto cifs_idmap_ret;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	sidstr = strget(key_descr, "oi:");
Packit Service 09cdfc
	if (sidstr) {
Packit Service 09cdfc
		rc = str_to_uint(sidstr, (unsigned int *)&cuxid.id.uid);
Packit Service 09cdfc
		if (rc) {
Packit Service 09cdfc
			syslog(LOG_ERR, "Unable to convert %s to uid: %s",
Packit Service 09cdfc
				sidstr, strerror(rc));
Packit Service 09cdfc
			goto cifs_idmap_ret;
Packit Service 09cdfc
		}
Packit Service 09cdfc
		cuxid.type = CIFS_UXID_TYPE_UID;
Packit Service 09cdfc
Packit Service 09cdfc
		syslog(LOG_DEBUG, "SID: %s, uid: %u", sidstr, cuxid.id.uid);
Packit Service 09cdfc
		rc = ids_to_sids(plugin_handle, &cuxid, 1, &sid;;
Packit Service 09cdfc
		if (rc || sid.revision == 0) {
Packit Service 09cdfc
			syslog(LOG_DEBUG, "uid %u to SID error: %s",
Packit Service 09cdfc
				cuxid.id.uid, plugin_errmsg);
Packit Service 09cdfc
			goto cifs_idmap_ret;
Packit Service 09cdfc
		}
Packit Service 09cdfc
Packit Service 09cdfc
		rc = keyctl_instantiate(key, &sid, sizeof(struct cifs_sid), 0);
Packit Service 09cdfc
		if (rc)
Packit Service 09cdfc
			syslog(LOG_ERR, "%s: key inst: %s", __func__,
Packit Service 09cdfc
				strerror(errno));
Packit Service 09cdfc
Packit Service 09cdfc
		goto cifs_idmap_ret;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	sidstr = strget(key_descr, "gi:");
Packit Service 09cdfc
	if (sidstr) {
Packit Service 09cdfc
		rc = str_to_uint(sidstr, (unsigned int *)&cuxid.id.gid);
Packit Service 09cdfc
		if (rc) {
Packit Service 09cdfc
			syslog(LOG_ERR, "Unable to convert %s to gid: %s",
Packit Service 09cdfc
				sidstr, strerror(rc));
Packit Service 09cdfc
			goto cifs_idmap_ret;
Packit Service 09cdfc
		}
Packit Service 09cdfc
		cuxid.type = CIFS_UXID_TYPE_GID;
Packit Service 09cdfc
Packit Service 09cdfc
		syslog(LOG_DEBUG, "SID: %s, gid: %u", sidstr, cuxid.id.gid);
Packit Service 09cdfc
		rc = ids_to_sids(plugin_handle, &cuxid, 1, &sid;;
Packit Service 09cdfc
		if (rc || sid.revision == 0) {
Packit Service 09cdfc
			syslog(LOG_DEBUG, "gid %u to SID error: %s",
Packit Service 09cdfc
				cuxid.id.gid, plugin_errmsg);
Packit Service 09cdfc
			goto cifs_idmap_ret;
Packit Service 09cdfc
		}
Packit Service 09cdfc
Packit Service 09cdfc
		rc = keyctl_instantiate(key, &sid, sizeof(struct cifs_sid), 0);
Packit Service 09cdfc
		if (rc)
Packit Service 09cdfc
			syslog(LOG_ERR, "%s: key inst: %s", __func__,
Packit Service 09cdfc
				strerror(errno));
Packit Service 09cdfc
Packit Service 09cdfc
		goto cifs_idmap_ret;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	syslog(LOG_DEBUG, "Invalid key: %s", key_descr);
Packit Service 09cdfc
Packit Service 09cdfc
cifs_idmap_ret:
Packit Service 09cdfc
	return rc;
Packit Service 09cdfc
}
Packit Service 09cdfc
Packit Service 09cdfc
int main(const int argc, char *const argv[])
Packit Service 09cdfc
{
Packit Service 09cdfc
	int c;
Packit Service 09cdfc
	long rc;
Packit Service 09cdfc
	key_serial_t key = 0;
Packit Service 09cdfc
	char *buf;
Packit Service 09cdfc
	unsigned int timeout = 600; /* default idmap cache timeout */
Packit Service 09cdfc
Packit Service 09cdfc
	openlog(prog, 0, LOG_DAEMON);
Packit Service 09cdfc
Packit Service 09cdfc
	while ((c = getopt_long(argc, argv, "ht:v",
Packit Service 09cdfc
					long_options, NULL)) != -1) {
Packit Service 09cdfc
		switch (c) {
Packit Service 09cdfc
		case 'h':
Packit Service 09cdfc
			rc = 0;
Packit Service 09cdfc
			usage();
Packit Service 09cdfc
			goto out;
Packit Service 09cdfc
		case 't':
Packit Service 09cdfc
			rc = str_to_uint(optarg, &timeout);
Packit Service 09cdfc
			if (rc) {
Packit Service 09cdfc
				syslog(LOG_ERR, "bad timeout value %s: %s",
Packit Service 09cdfc
					optarg, strerror(rc));
Packit Service 09cdfc
				goto out;
Packit Service 09cdfc
			}
Packit Service 09cdfc
			break;
Packit Service 09cdfc
		case 'v':
Packit Service 09cdfc
			rc = 0;
Packit Service 09cdfc
			printf("version: %s\n", VERSION);
Packit Service 09cdfc
			goto out;
Packit Service 09cdfc
		default:
Packit Service 09cdfc
			rc = EINVAL;
Packit Service 09cdfc
			syslog(LOG_ERR, "unknown option: %c", c);
Packit Service 09cdfc
			goto out;
Packit Service 09cdfc
		}
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	rc = 1;
Packit Service 09cdfc
	/* is there a key? */
Packit Service 09cdfc
	if (argc <= optind) {
Packit Service 09cdfc
		usage();
Packit Service 09cdfc
		goto out;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	/* get key and keyring values */
Packit Service 09cdfc
	errno = 0;
Packit Service 09cdfc
	key = strtol(argv[optind], NULL, 10);
Packit Service 09cdfc
	if (errno != 0) {
Packit Service 09cdfc
		key = 0;
Packit Service 09cdfc
		syslog(LOG_ERR, "Invalid key format: %s", strerror(errno));
Packit Service 09cdfc
		goto out;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	if (init_plugin(&plugin_handle)) {
Packit Service 09cdfc
		plugin_handle = NULL;
Packit Service 09cdfc
		syslog(LOG_ERR, "Unable to initialize ID mapping plugin: %s",
Packit Service 09cdfc
			plugin_errmsg);
Packit Service 09cdfc
		goto out;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	/* set timeout on key */
Packit Service 09cdfc
	rc = keyctl_set_timeout(key, timeout);
Packit Service 09cdfc
	if (rc == -1) {
Packit Service 09cdfc
		syslog(LOG_ERR, "unable to set key timeout: %s",
Packit Service 09cdfc
			strerror(errno));
Packit Service 09cdfc
		goto out_exit_plugin;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	rc = keyctl_describe_alloc(key, &buf;;
Packit Service 09cdfc
	if (rc == -1) {
Packit Service 09cdfc
		syslog(LOG_ERR, "keyctl_describe_alloc failed: %s",
Packit Service 09cdfc
		       strerror(errno));
Packit Service 09cdfc
		goto out_exit_plugin;
Packit Service 09cdfc
	}
Packit Service 09cdfc
Packit Service 09cdfc
	syslog(LOG_DEBUG, "key description: %s", buf);
Packit Service 09cdfc
Packit Service 09cdfc
	rc = cifs_idmap(key, buf);
Packit Service 09cdfc
out_exit_plugin:
Packit Service 09cdfc
	exit_plugin(plugin_handle);
Packit Service 09cdfc
out:
Packit Service 09cdfc
	return rc;
Packit Service 09cdfc
}