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