summaryrefslogtreecommitdiff
path: root/cifs.idmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'cifs.idmap.c')
-rw-r--r--cifs.idmap.c197
1 files changed, 197 insertions, 0 deletions
diff --git a/cifs.idmap.c b/cifs.idmap.c
new file mode 100644
index 0000000..ea24824
--- /dev/null
+++ b/cifs.idmap.c
@@ -0,0 +1,197 @@
+/*
+* CIFS idmap helper.
+* Copyright (C) Shirish Pargaonkar (shirishp@us.ibm.com) 2011
+*
+* Used by /sbin/request-key.conf for handling
+* cifs upcall for SID to uig/gid and uid/gid to SID mapping.
+* You should have keyutils installed and add
+* this lines to /etc/request-key.conf file:
+
+ create cifs.idmap * * /usr/local/sbin/cifs.idmap %k
+
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <getopt.h>
+#include <syslog.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <keyutils.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <wbclient.h>
+
+static const char *prog = "cifs.idmap";
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: %s key_serial\n", prog);
+}
+
+char *strget(const char *str, char *substr)
+{
+ int len, sublen, retlen;
+ char *retstr, *substrptr;
+
+ sublen = strlen(substr);
+ substrptr = strstr(str, substr);
+ if (substrptr) {
+ len = strlen(substrptr);
+ substrptr += sublen;
+
+ retlen = len - sublen;
+ if (retlen > 0) {
+ retstr = malloc(retlen + 1);
+ if (retstr) {
+ strncpy(retstr, substrptr, retlen);
+ return retstr;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static int
+cifs_idmap(const key_serial_t key, const char *key_descr)
+{
+ uid_t uid = 0;
+ gid_t gid = 0;;
+ wbcErr rc = 1;
+ char *sidstr = NULL;
+ struct wbcDomainSid sid;
+ struct passwd *pw;
+ struct group *gr;
+
+ /*
+ * Use winbind to convert received string to a SID and lookup
+ * name and map that SID to an uid. If either of these
+ * function calls return with an error, return an error the
+ * upcall caller. Otherwise instanticate a key using that uid.
+ *
+ * The same applies to SID and gid mapping.
+ */
+ sidstr = strget(key_descr, "os:");
+ if (sidstr) {
+ rc = wbcStringToSid(sidstr, &sid);
+ if (rc)
+ syslog(LOG_DEBUG, "Invalid owner string: %s, rc: %d",
+ key_descr, rc);
+ else {
+ rc = wbcSidToUid(&sid, &uid);
+ if (rc)
+ syslog(LOG_DEBUG, "SID %s to uid wbc error: %d",
+ key_descr, rc);
+ }
+ if (!rc) { /* SID has been mapped to an uid */
+ rc = keyctl_instantiate(key, &uid, sizeof(uid_t), 0);
+ if (rc)
+ syslog(LOG_ERR, "%s: key inst: %s",
+ __func__, strerror(errno));
+ }
+
+ goto cifs_idmap_ret;
+ }
+
+ sidstr = strget(key_descr, "gs:");
+ if (sidstr) {
+ rc = wbcStringToSid(sidstr, &sid);
+ if (rc)
+ syslog(LOG_DEBUG, "Invalid group string: %s, rc: %d",
+ key_descr, rc);
+ else {
+ rc = wbcSidToGid(&sid, &gid);
+ if (rc)
+ syslog(LOG_DEBUG, "SID %s to gid wbc error: %d",
+ key_descr, rc);
+ }
+ if (!rc) { /* SID has been mapped to a gid */
+ rc = keyctl_instantiate(key, &gid, sizeof(gid_t), 0);
+ if (rc)
+ syslog(LOG_ERR, "%s: key inst: %s",
+ __func__, strerror(errno));
+ }
+
+ goto cifs_idmap_ret;
+ }
+
+ syslog(LOG_DEBUG, "Invalid key: %s", key_descr);
+
+cifs_idmap_ret:
+ if (sidstr)
+ free(sidstr);
+
+ return rc;
+}
+
+int main(const int argc, char *const argv[])
+{
+ int c;
+ long rc = 1;
+ key_serial_t key = 0;
+ char *buf;
+
+ openlog(prog, 0, LOG_DAEMON);
+
+ while ((c = getopt_long(argc, argv, "v", NULL, NULL)) != -1) {
+ switch (c) {
+ case 'v':
+ printf("version: %s\n", VERSION);
+ goto out;
+ default:
+ syslog(LOG_ERR, "unknown option: %c", c);
+ goto out;
+ }
+ }
+
+ /* is there a key? */
+ if (argc <= optind) {
+ usage();
+ goto out;
+ }
+
+ /* get key and keyring values */
+ errno = 0;
+ key = strtol(argv[optind], NULL, 10);
+ if (errno != 0) {
+ key = 0;
+ syslog(LOG_ERR, "Invalid key format: %s", strerror(errno));
+ goto out;
+ }
+
+ rc = keyctl_describe_alloc(key, &buf);
+ if (rc == -1) {
+ syslog(LOG_ERR, "keyctl_describe_alloc failed: %s",
+ strerror(errno));
+ rc = 1;
+ goto out;
+ }
+
+ syslog(LOG_DEBUG, "key description: %s", buf);
+
+ if ((strncmp(buf, "cifs.idmap", sizeof("cifs.idmap") - 1) == 0))
+ rc = cifs_idmap(key, buf);
+out:
+ return rc;
+}