Message ID | 1304667239-29127-1-git-send-email-shirishp@linux.vnet.ibm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Fri, 6 May 2011 02:33:59 -0500 shirishpargaonkar@gmail.com wrote: > From: Shirish Pargaonkar <shirishpargaonkar@gmail.com> > > Handle cifs.idmap type of key. Extract a SID string from the description > and map it to either an uid or gid using winbind APIs. > If that fails (e.g. because winbind is not installed/running or winbind returns > an error), try to obtain uid of 'nobody' and gid of 'nogroup'. > And if that fails, kernel assigns uid and gid (from mount superblock). > > Enable including winbind header files and idmapping code conditional > to winbind devel rpms (header and library). > > An entry such as this > > create cifs.idmap * * /usr/sbin/cifs.idmap %k > > is needed in the file /etc/request-key.conf. > > > Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com> > --- > Makefile.am | 8 ++ > cifs.idmap.c | 215 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > configure.ac | 58 +++++++++++++++- > 3 files changed, 280 insertions(+), 1 deletions(-) > create mode 100644 cifs.idmap.c > > diff --git a/Makefile.am b/Makefile.am > index 67a0190..ad33914 100644 > --- a/Makefile.am > +++ b/Makefile.am > @@ -30,3 +30,11 @@ bin_PROGRAMS = cifscreds > cifscreds_SOURCES = cifscreds.c resolve_host.c util.c > cifscreds_LDADD = -lkeyutils > endif > + > +if CONFIG_CIFSIDMAP > +cifs_idmap_sbindir = /usr/local/sbin ^^^^^^^^^ That looks wrong. If I configure with --prefix=/usr then this is still going to go in /usr/local/sbin, right? I think you instead want to append cifs.idmap to sbin_PROGRAMS. > +cifs_idmap_sbin_PROGRAMS = cifs.idmap > +cifs_idmap_SOURCES = cifs.idmap.c > +cifs_idmap_LDADD = -lkeyutils $(WINB_LDADD) > +endif > + > diff --git a/cifs.idmap.c b/cifs.idmap.c > new file mode 100644 > index 0000000..0f76873 > --- /dev/null > +++ b/cifs.idmap.c > @@ -0,0 +1,215 @@ > +/* > +* 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> > +#ifdef HAVE_KEYUTILS_H > +#include <keyutils.h> > +#endif /* HAVE_KEYUTILS_H */ ^^^^^^^^^^ This can't be built w/o keyutils, right? So I don't think we need the #ifdefs. > +#include <stdint.h> > +#include <stdbool.h> > +#include <stdio.h> > +#include <stdlib.h> > +#include <errno.h> > +#include <limits.h> > +#ifdef HAVE_WBCLIENT_H > +#include <wbclient.h> > +#endif /* HAVE_WBCLIENT_H */ > + > +static const char *prog = "cifs.idmap"; > + > +static void usage(void) > +{ > + syslog(LOG_INFO, "Usage: %s [-t] [-v] [-l] key_serial", prog); > + fprintf(stderr, "Usage: %s [-t] [-v] [-l] key_serial\n", prog); > +} > + > +#ifdef HAVE_LIBWBCLIENT > +static int > +cifs_idmap(const key_serial_t key, const char *key_descr) > +{ > + int i; > + uid_t uid = 0; > + gid_t gid = 0;; > + wbcErr rc = 1; > + const char *keyend = key_descr; > + struct wbcDomainSid sid; > + struct passwd *pw; > + struct group *gr; > + > + /* skip next 4 ';' delimiters to get to description */ > + for (i = 1; i <= 4; ++i) { > + keyend = index(keyend + 1, ';'); > + if (!keyend) { > + syslog(LOG_ERR, "invalid key description: %s", > + key_descr); > + return 1; > + } > + } > + keyend++; > + No real bounds checking here. It seems unlikely, but a buggy kernel could send a garbled string and you could walk off the end of it here. > + /* > + * 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, use system calls to obtain > + * uid of user "nobody". If winbind fails to map a SID to an UID > + * and there is no user named "nobody", return error to the > + * upcall caller. Otherwise instanticate a key using that uid. > + * > + * The same applies to SID and gid mapping. Instead of a > + * user "nobody", user "nogroup" is looked up if winbind > + * fails to map a SID to a gid. > + */ > + if (strncmp(keyend, "os", 2) == 0) { > + keyend = index(keyend + 1, ':'); > + keyend++; ^^^^^^^^^ ditto on the bounds checks > + rc = wbcStringToSid(keyend, &sid); > + if (rc) > + syslog(LOG_DEBUG, "O strtosid: %s, rc: %d", keyend, rc); > + else { > + rc = wbcSidToUid(&sid, &uid); > + if (rc) > + syslog(LOG_DEBUG, "SID %s to uid wbc error: %d", > + keyend, rc); > + } > + if (rc) { /* either of the two wbcSid functions failed */ > + pw = getpwnam("nobody"); > + if (!pw) > + syslog(LOG_DEBUG, "SID %s to uid pw error: %d", > + keyend, rc); > + else { > + uid = pw->pw_uid; > + rc = 0; > + } > + } > + if (!rc) { /* SID has been mapped to a uid */ > + rc = keyctl_instantiate(key, &uid, sizeof(uid_t), 0); > + if (rc) > + syslog(LOG_ERR, "%s: key inst: %s", > + __func__, strerror(errno)); > + } > + } else if (strncmp(keyend, "gs", 2) == 0) { > + keyend = index(keyend + 1, ':'); > + keyend++; > + rc = wbcStringToSid(keyend, &sid); > + if (rc) > + syslog(LOG_DEBUG, "O strtosid: %s, rc: %d", keyend, rc); > + else { > + rc = wbcSidToGid(&sid, &gid); > + if (rc) > + syslog(LOG_DEBUG, "SID %s to gid wbc error: %d", > + keyend, rc); > + } > + if (rc) { /* either of the two wbcSid functions failed */ > + gr = getgrnam("nogroup"); > + if (!gr) > + syslog(LOG_DEBUG, "SID %s to gid pw error: %d", > + keyend, rc); > + else { > + gid = gr->gr_gid; > + rc = 0; > + } > + } > + 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)); > + } > + } else > + syslog(LOG_DEBUG, "Invalid SID: %s", keyend); > + > + return rc; > +} > +#endif /* HAVE_LIBWBCLIENT */ > + > +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); > + > +#ifdef HAVE_LIBWBCLIENT > + if ((strncmp(buf, "cifs.idmap", sizeof("cifs.idmap") - 1) == 0)) > + rc = cifs_idmap(key, buf); > +#endif /* HAVE_LIBWBCLIENT */ > + Doesn't this program require libwbclient? If so, then why the #ifdef's? > +out: > + /* > + * on error, negatively instantiate the key ourselves so that we can > + * make sure the kernel doesn't hang it off of a searchable keyring > + * and interfere with the next attempt to instantiate the key. > + */ > + if (rc != 0 && key == 0) > + keyctl_negate(key, 1, KEY_REQKEY_DEFL_DEFAULT); ^^^^^^^ Is a 1s timeout appropriate here? > + return rc; > +} > diff --git a/configure.ac b/configure.ac > index e0e2a60..d9eaead 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -22,13 +22,19 @@ AC_ARG_ENABLE(cifscreds, > enable_cifscreds=$enableval, > enable_cifscreds="no") > > +AC_ARG_ENABLE(cifsidmap, > + [AC_HELP_STRING([--enable-cifsidmap], > + [Create cifs.idmap binary @<:@default=yes@:>@])], > + enable_cifsidmap=$enableval, > + enable_cifsidmap="maybe") > + > # Checks for programs. > AC_PROG_CC > AC_PROG_SED > AC_GNU_SOURCE > > # Checks for header files. > -AC_CHECK_HEADERS([arpa/inet.h ctype.h fcntl.h inttypes.h limits.h mntent.h netdb.h stddef.h stdint.h stdlib.h string.h strings.h sys/mount.h sys/param.h sys/socket.h sys/time.h syslog.h unistd.h], , [AC_MSG_ERROR([necessary header(s) not found])]) > +AC_CHECK_HEADERS([arpa/inet.h ctype.h fcntl.h inttypes.h limits.h mntent.h netdb.h stddef.h stdint.h stdbool.h stdlib.h stdio.h errno.h string.h strings.h sys/mount.h sys/param.h sys/socket.h sys/time.h syslog.h unistd.h], , [AC_MSG_ERROR([necessary header(s) not found])]) > > if test $enable_cifsupcall != "no"; then > AC_CHECK_HEADERS([krb5.h krb5/krb5.h]) > @@ -89,6 +95,55 @@ if test $enable_cifsupcall != "no"; then > AC_SUBST(KRB5_LDADD) > fi > > +if test $enable_cifsidmap != "no"; then > + AC_CHECK_HEADERS([keyutils.h], , [ > + if test "$enable_cifsidmap" = "yes"; then > + AC_MSG_ERROR([keyutils.h not found, consider installing keyutils-libs-devel.]) > + else > + AC_MSG_WARN([keyutils.h not found, consider installing keyutils-libs-devel. Disabling cifs.idmap.]) > + enable_cifsidmap="no" > + fi > + ]) > +fi > + We're already doing a AC_CHECK_HEADERS for keyutils.h -- I don't think we want to do it again. Just use the same check for both cifs.upcall and cifs.idmap. > +if test $enable_cifsidmap != "no"; then > + AC_CHECK_HEADERS([wbclient.h], , [ > + if test "$enable_cifsidmap" = "yes"; then > + AC_MSG_ERROR([wbclient.h not found, consider installing libwbclient-devel..]) > + else > + AC_MSG_WARN([keyutils.h not found, consider installing libwbclient-devel. Disabling cifs.idmap.]) > + enable_cifsidmap="no" > + fi > + ], > +[#ifdef HAVE_STDINT_H > +#include <stdint.h> > +#endif > +] > +[#ifdef HAVE_STDBOOL_H > +#include <stdbool.h> > +#endif > +] > +[#ifdef HAVE_STDIO_H > +#include <stdio.h> > +#endif > +] > +[#ifdef HAVE_STDLIB_H > +#include <stdlib.h> > +#endif > +] > +[#ifdef HAVE_ERRNO_H > +#include <errno.h> > +#endif > +] > +) > +fi > + > +if test $enable_cifsidmap != "no"; then > + AC_CHECK_LIB([wbclient], [wbcStringToSid], > + [ WINB_LDADD='-lwbclient' ] [ AC_DEFINE(HAVE_LIBWBCLIENT, 1, ["define var have_libwbclient"]) ], [AC_MSG_ERROR([no functioning wbclient library found!])]) > + AC_SUBST(WINB_LDADD) > +fi > + Bleh, that's pretty messy. Maybe this should go into a separate file/function in aclocal/ ? > if test $enable_cifscreds = "yes"; then > AC_CHECK_HEADERS([keyutils.h], , [AC_MSG_ERROR([keyutils.h not found, consider installing keyutils-libs-devel.])]) > fi > @@ -140,6 +195,7 @@ LIBS=$cu_saved_libs > > AM_CONDITIONAL(CONFIG_CIFSUPCALL, [test "$enable_cifsupcall" != "no"]) > AM_CONDITIONAL(CONFIG_CIFSCREDS, [test "$enable_cifscreds" = "yes"]) > +AM_CONDITIONAL(CONFIG_CIFSIDMAP, [test "$enable_cifsidmap" != "no"]) > > LIBCAP_NG_PATH >
On Tue, May 17, 2011 at 11:09 AM, Jeff Layton <jlayton@redhat.com> wrote: > On Fri, 6 May 2011 02:33:59 -0500 > shirishpargaonkar@gmail.com wrote: > >> From: Shirish Pargaonkar <shirishpargaonkar@gmail.com> >> >> Handle cifs.idmap type of key. Extract a SID string from the description >> and map it to either an uid or gid using winbind APIs. >> If that fails (e.g. because winbind is not installed/running or winbind returns >> an error), try to obtain uid of 'nobody' and gid of 'nogroup'. >> And if that fails, kernel assigns uid and gid (from mount superblock). >> >> Enable including winbind header files and idmapping code conditional >> to winbind devel rpms (header and library). >> >> An entry such as this >> >> create cifs.idmap * * /usr/sbin/cifs.idmap %k >> >> is needed in the file /etc/request-key.conf. >> >> >> Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com> >> --- >> Makefile.am | 8 ++ >> cifs.idmap.c | 215 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ >> configure.ac | 58 +++++++++++++++- >> 3 files changed, 280 insertions(+), 1 deletions(-) >> create mode 100644 cifs.idmap.c >> >> diff --git a/Makefile.am b/Makefile.am >> index 67a0190..ad33914 100644 >> --- a/Makefile.am >> +++ b/Makefile.am >> @@ -30,3 +30,11 @@ bin_PROGRAMS = cifscreds >> cifscreds_SOURCES = cifscreds.c resolve_host.c util.c >> cifscreds_LDADD = -lkeyutils >> endif >> + >> +if CONFIG_CIFSIDMAP >> +cifs_idmap_sbindir = /usr/local/sbin > > ^^^^^^^^^ > That looks wrong. If I configure with --prefix=/usr then this is still > going to go in /usr/local/sbin, right? I think you instead want to > append cifs.idmap to sbin_PROGRAMS. > >> +cifs_idmap_sbin_PROGRAMS = cifs.idmap >> +cifs_idmap_SOURCES = cifs.idmap.c >> +cifs_idmap_LDADD = -lkeyutils $(WINB_LDADD) >> +endif >> + >> diff --git a/cifs.idmap.c b/cifs.idmap.c >> new file mode 100644 >> index 0000000..0f76873 >> --- /dev/null >> +++ b/cifs.idmap.c >> @@ -0,0 +1,215 @@ >> +/* >> +* 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> >> +#ifdef HAVE_KEYUTILS_H >> +#include <keyutils.h> >> +#endif /* HAVE_KEYUTILS_H */ > ^^^^^^^^^^ > This can't be built w/o keyutils, right? So I don't think we need the > #ifdefs. > >> +#include <stdint.h> >> +#include <stdbool.h> >> +#include <stdio.h> >> +#include <stdlib.h> >> +#include <errno.h> >> +#include <limits.h> >> +#ifdef HAVE_WBCLIENT_H >> +#include <wbclient.h> >> +#endif /* HAVE_WBCLIENT_H */ >> + >> +static const char *prog = "cifs.idmap"; >> + >> +static void usage(void) >> +{ >> + syslog(LOG_INFO, "Usage: %s [-t] [-v] [-l] key_serial", prog); >> + fprintf(stderr, "Usage: %s [-t] [-v] [-l] key_serial\n", prog); >> +} >> + >> +#ifdef HAVE_LIBWBCLIENT >> +static int >> +cifs_idmap(const key_serial_t key, const char *key_descr) >> +{ >> + int i; >> + uid_t uid = 0; >> + gid_t gid = 0;; >> + wbcErr rc = 1; >> + const char *keyend = key_descr; >> + struct wbcDomainSid sid; >> + struct passwd *pw; >> + struct group *gr; >> + >> + /* skip next 4 ';' delimiters to get to description */ >> + for (i = 1; i <= 4; ++i) { >> + keyend = index(keyend + 1, ';'); >> + if (!keyend) { >> + syslog(LOG_ERR, "invalid key description: %s", >> + key_descr); >> + return 1; >> + } >> + } >> + keyend++; >> + > > No real bounds checking here. It seems unlikely, but a buggy kernel > could send a garbled string and you could walk off the end of it here. > >> + /* >> + * 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, use system calls to obtain >> + * uid of user "nobody". If winbind fails to map a SID to an UID >> + * and there is no user named "nobody", return error to the >> + * upcall caller. Otherwise instanticate a key using that uid. >> + * >> + * The same applies to SID and gid mapping. Instead of a >> + * user "nobody", user "nogroup" is looked up if winbind >> + * fails to map a SID to a gid. >> + */ >> + if (strncmp(keyend, "os", 2) == 0) { >> + keyend = index(keyend + 1, ':'); >> + keyend++; > ^^^^^^^^^ > ditto on the bounds checks > >> + rc = wbcStringToSid(keyend, &sid); >> + if (rc) >> + syslog(LOG_DEBUG, "O strtosid: %s, rc: %d", keyend, rc); >> + else { >> + rc = wbcSidToUid(&sid, &uid); >> + if (rc) >> + syslog(LOG_DEBUG, "SID %s to uid wbc error: %d", >> + keyend, rc); >> + } >> + if (rc) { /* either of the two wbcSid functions failed */ >> + pw = getpwnam("nobody"); >> + if (!pw) >> + syslog(LOG_DEBUG, "SID %s to uid pw error: %d", >> + keyend, rc); >> + else { >> + uid = pw->pw_uid; >> + rc = 0; >> + } >> + } >> + if (!rc) { /* SID has been mapped to a uid */ >> + rc = keyctl_instantiate(key, &uid, sizeof(uid_t), 0); >> + if (rc) >> + syslog(LOG_ERR, "%s: key inst: %s", >> + __func__, strerror(errno)); >> + } >> + } else if (strncmp(keyend, "gs", 2) == 0) { >> + keyend = index(keyend + 1, ':'); >> + keyend++; >> + rc = wbcStringToSid(keyend, &sid); >> + if (rc) >> + syslog(LOG_DEBUG, "O strtosid: %s, rc: %d", keyend, rc); >> + else { >> + rc = wbcSidToGid(&sid, &gid); >> + if (rc) >> + syslog(LOG_DEBUG, "SID %s to gid wbc error: %d", >> + keyend, rc); >> + } >> + if (rc) { /* either of the two wbcSid functions failed */ >> + gr = getgrnam("nogroup"); >> + if (!gr) >> + syslog(LOG_DEBUG, "SID %s to gid pw error: %d", >> + keyend, rc); >> + else { >> + gid = gr->gr_gid; >> + rc = 0; >> + } >> + } >> + 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)); >> + } >> + } else >> + syslog(LOG_DEBUG, "Invalid SID: %s", keyend); >> + >> + return rc; >> +} >> +#endif /* HAVE_LIBWBCLIENT */ >> + >> +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); >> + >> +#ifdef HAVE_LIBWBCLIENT >> + if ((strncmp(buf, "cifs.idmap", sizeof("cifs.idmap") - 1) == 0)) >> + rc = cifs_idmap(key, buf); >> +#endif /* HAVE_LIBWBCLIENT */ >> + > > Doesn't this program require libwbclient? If so, then why the #ifdef's? > >> +out: >> + /* >> + * on error, negatively instantiate the key ourselves so that we can >> + * make sure the kernel doesn't hang it off of a searchable keyring >> + * and interfere with the next attempt to instantiate the key. >> + */ >> + if (rc != 0 && key == 0) >> + keyctl_negate(key, 1, KEY_REQKEY_DEFL_DEFAULT); > > ^^^^^^^ > Is a 1s timeout appropriate here? > >> + return rc; >> +} >> diff --git a/configure.ac b/configure.ac >> index e0e2a60..d9eaead 100644 >> --- a/configure.ac >> +++ b/configure.ac >> @@ -22,13 +22,19 @@ AC_ARG_ENABLE(cifscreds, >> enable_cifscreds=$enableval, >> enable_cifscreds="no") >> >> +AC_ARG_ENABLE(cifsidmap, >> + [AC_HELP_STRING([--enable-cifsidmap], >> + [Create cifs.idmap binary @<:@default=yes@:>@])], >> + enable_cifsidmap=$enableval, >> + enable_cifsidmap="maybe") >> + >> # Checks for programs. >> AC_PROG_CC >> AC_PROG_SED >> AC_GNU_SOURCE >> >> # Checks for header files. >> -AC_CHECK_HEADERS([arpa/inet.h ctype.h fcntl.h inttypes.h limits.h mntent.h netdb.h stddef.h stdint.h stdlib.h string.h strings.h sys/mount.h sys/param.h sys/socket.h sys/time.h syslog.h unistd.h], , [AC_MSG_ERROR([necessary header(s) not found])]) >> +AC_CHECK_HEADERS([arpa/inet.h ctype.h fcntl.h inttypes.h limits.h mntent.h netdb.h stddef.h stdint.h stdbool.h stdlib.h stdio.h errno.h string.h strings.h sys/mount.h sys/param.h sys/socket.h sys/time.h syslog.h unistd.h], , [AC_MSG_ERROR([necessary header(s) not found])]) >> >> if test $enable_cifsupcall != "no"; then >> AC_CHECK_HEADERS([krb5.h krb5/krb5.h]) >> @@ -89,6 +95,55 @@ if test $enable_cifsupcall != "no"; then >> AC_SUBST(KRB5_LDADD) >> fi >> >> +if test $enable_cifsidmap != "no"; then >> + AC_CHECK_HEADERS([keyutils.h], , [ >> + if test "$enable_cifsidmap" = "yes"; then >> + AC_MSG_ERROR([keyutils.h not found, consider installing keyutils-libs-devel.]) >> + else >> + AC_MSG_WARN([keyutils.h not found, consider installing keyutils-libs-devel. Disabling cifs.idmap.]) >> + enable_cifsidmap="no" >> + fi >> + ]) >> +fi >> + > > We're already doing a AC_CHECK_HEADERS for keyutils.h -- I don't think > we want to do it again. Just use the same check for both cifs.upcall > and cifs.idmap. Could someone build just cifs.idmap and not cifs.upcall? > >> +if test $enable_cifsidmap != "no"; then >> + AC_CHECK_HEADERS([wbclient.h], , [ >> + if test "$enable_cifsidmap" = "yes"; then >> + AC_MSG_ERROR([wbclient.h not found, consider installing libwbclient-devel..]) >> + else >> + AC_MSG_WARN([keyutils.h not found, consider installing libwbclient-devel. Disabling cifs.idmap.]) >> + enable_cifsidmap="no" >> + fi >> + ], >> +[#ifdef HAVE_STDINT_H >> +#include <stdint.h> >> +#endif >> +] >> +[#ifdef HAVE_STDBOOL_H >> +#include <stdbool.h> >> +#endif >> +] >> +[#ifdef HAVE_STDIO_H >> +#include <stdio.h> >> +#endif >> +] >> +[#ifdef HAVE_STDLIB_H >> +#include <stdlib.h> >> +#endif >> +] >> +[#ifdef HAVE_ERRNO_H >> +#include <errno.h> >> +#endif >> +] >> +) >> +fi >> + >> +if test $enable_cifsidmap != "no"; then >> + AC_CHECK_LIB([wbclient], [wbcStringToSid], >> + [ WINB_LDADD='-lwbclient' ] [ AC_DEFINE(HAVE_LIBWBCLIENT, 1, ["define var have_libwbclient"]) ], [AC_MSG_ERROR([no functioning wbclient library found!])]) >> + AC_SUBST(WINB_LDADD) >> +fi >> + > > > Bleh, that's pretty messy. Maybe this should go into a separate > file/function in aclocal/ ? > > >> if test $enable_cifscreds = "yes"; then >> AC_CHECK_HEADERS([keyutils.h], , [AC_MSG_ERROR([keyutils.h not found, consider installing keyutils-libs-devel.])]) >> fi >> @@ -140,6 +195,7 @@ LIBS=$cu_saved_libs >> >> AM_CONDITIONAL(CONFIG_CIFSUPCALL, [test "$enable_cifsupcall" != "no"]) >> AM_CONDITIONAL(CONFIG_CIFSCREDS, [test "$enable_cifscreds" = "yes"]) >> +AM_CONDITIONAL(CONFIG_CIFSIDMAP, [test "$enable_cifsidmap" != "no"]) >> >> LIBCAP_NG_PATH >> > > > -- > Jeff Layton <jlayton@redhat.com> > -- To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tue, 17 May 2011 12:01:12 -0500 Shirish Pargaonkar <shirishpargaonkar@gmail.com> wrote: [...] > >> +if test $enable_cifsidmap != "no"; then > >> + AC_CHECK_HEADERS([keyutils.h], , [ > >> + if test "$enable_cifsidmap" = "yes"; then > >> + AC_MSG_ERROR([keyutils.h not found, consider installing keyutils-libs-devel.]) > >> + else > >> + AC_MSG_WARN([keyutils.h not found, consider installing keyutils-libs-devel. Disabling cifs.idmap.]) > >> + enable_cifsidmap="no" > >> + fi > >> + ]) > >> +fi > >> + > > > > We're already doing a AC_CHECK_HEADERS for keyutils.h -- I don't think > > we want to do it again. Just use the same check for both cifs.upcall > > and cifs.idmap. > > Could someone build just cifs.idmap and not cifs.upcall? > Sure, I don't see why not.
On Tue, May 17, 2011 at 12:14 PM, Jeff Layton <jlayton@redhat.com> wrote: > On Tue, 17 May 2011 12:01:12 -0500 > Shirish Pargaonkar <shirishpargaonkar@gmail.com> wrote: > > [...] > >> >> +if test $enable_cifsidmap != "no"; then >> >> + AC_CHECK_HEADERS([keyutils.h], , [ >> >> + if test "$enable_cifsidmap" = "yes"; then >> >> + AC_MSG_ERROR([keyutils.h not found, consider installing keyutils-libs-devel.]) >> >> + else >> >> + AC_MSG_WARN([keyutils.h not found, consider installing keyutils-libs-devel. Disabling cifs.idmap.]) >> >> + enable_cifsidmap="no" >> >> + fi >> >> + ]) >> >> +fi >> >> + >> > >> > We're already doing a AC_CHECK_HEADERS for keyutils.h -- I don't think >> > we want to do it again. Just use the same check for both cifs.upcall >> > and cifs.idmap. >> >> Could someone build just cifs.idmap and not cifs.upcall? >> > > Sure, I don't see why not. > > -- > Jeff Layton <jlayton@redhat.com> > Then would not we need AC_CHECK_HEADERS for keyutils.h for cifs.idmap in case cifs.upcall is not being built i.e. do would not we need both these checks? if test $enable_cifsupcall != "no"; then AC_CHECK_HEADERS([keyutils.h], , [ if test $enable_cifsidmap != "no"; then AC_CHECK_HEADERS([keyutils.h], , [ -- To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tue, 17 May 2011 12:47:35 -0500 Shirish Pargaonkar <shirishpargaonkar@gmail.com> wrote: > On Tue, May 17, 2011 at 12:14 PM, Jeff Layton <jlayton@redhat.com> wrote: > > On Tue, 17 May 2011 12:01:12 -0500 > > Shirish Pargaonkar <shirishpargaonkar@gmail.com> wrote: > > > > [...] > > > >> >> +if test $enable_cifsidmap != "no"; then > >> >> + AC_CHECK_HEADERS([keyutils.h], , [ > >> >> + if test "$enable_cifsidmap" = "yes"; then > >> >> + AC_MSG_ERROR([keyutils.h not found, consider installing keyutils-libs-devel.]) > >> >> + else > >> >> + AC_MSG_WARN([keyutils.h not found, consider installing keyutils-libs-devel. Disabling cifs.idmap.]) > >> >> + enable_cifsidmap="no" > >> >> + fi > >> >> + ]) > >> >> +fi > >> >> + > >> > > >> > We're already doing a AC_CHECK_HEADERS for keyutils.h -- I don't think > >> > we want to do it again. Just use the same check for both cifs.upcall > >> > and cifs.idmap. > >> > >> Could someone build just cifs.idmap and not cifs.upcall? > >> > > > > Sure, I don't see why not. > > > > -- > > Jeff Layton <jlayton@redhat.com> > > > > Then would not we need AC_CHECK_HEADERS for keyutils.h for cifs.idmap > in case cifs.upcall is not being built i.e. do would not we need both > these checks? > > if test ; then > AC_CHECK_HEADERS([keyutils.h], , [ > > > if test $enable_cifsidmap != "no"; then > AC_CHECK_HEADERS([keyutils.h], , [ No, I think you just want to do a single AC_CHECK_HEADERS under: if test $enable_cifsupcall != "no" -o $enable_cifsidmap != "no" ...and then handle both cases correctly. OTOH, I think autoconf might cache the results of AC_CHECK_HEADERS and won't re-do the test, so you may be alright without doing that. I'd verify that by inspecting the log to be sure though.
On Tue, 17 May 2011 21:06:53 -0500 Shirish Pargaonkar <shirishpargaonkar@gmail.com> wrote: > On Tue, May 17, 2011 at 11:09 AM, Jeff Layton <jlayton@redhat.com> wrote: > > On Fri, 6 May 2011 02:33:59 -0500 > > shirishpargaonkar@gmail.com wrote: > > > >> From: Shirish Pargaonkar <shirishpargaonkar@gmail.com> > >> > >> Handle cifs.idmap type of key. Extract a SID string from the description > >> and map it to either an uid or gid using winbind APIs. > >> If that fails (e.g. because winbind is not installed/running or winbind returns > >> an error), try to obtain uid of 'nobody' and gid of 'nogroup'. > >> And if that fails, kernel assigns uid and gid (from mount superblock). > >> > >> Enable including winbind header files and idmapping code conditional > >> to winbind devel rpms (header and library). > >> > >> An entry such as this > >> > >> create cifs.idmap * * /usr/sbin/cifs.idmap %k > >> > >> is needed in the file /etc/request-key.conf. > >> > >> > >> Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com> > >> --- > >> Makefile.am | 8 ++ > >> cifs.idmap.c | 215 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > >> configure.ac | 58 +++++++++++++++- > >> 3 files changed, 280 insertions(+), 1 deletions(-) > >> create mode 100644 cifs.idmap.c > >> > >> diff --git a/Makefile.am b/Makefile.am > >> index 67a0190..ad33914 100644 > >> --- a/Makefile.am > >> +++ b/Makefile.am > >> @@ -30,3 +30,11 @@ bin_PROGRAMS = cifscreds > >> cifscreds_SOURCES = cifscreds.c resolve_host.c util.c > >> cifscreds_LDADD = -lkeyutils > >> endif > >> + > >> +if CONFIG_CIFSIDMAP > >> +cifs_idmap_sbindir = /usr/local/sbin > > > > ^^^^^^^^^ > > That looks wrong. If I configure with --prefix=/usr then this is still > > going to go in /usr/local/sbin, right? I think you instead want to > > append cifs.idmap to sbin_PROGRAMS. > > > >> +cifs_idmap_sbin_PROGRAMS = cifs.idmap > >> +cifs_idmap_SOURCES = cifs.idmap.c > >> +cifs_idmap_LDADD = -lkeyutils $(WINB_LDADD) > >> +endif > >> + > >> diff --git a/cifs.idmap.c b/cifs.idmap.c > >> new file mode 100644 > >> index 0000000..0f76873 > >> --- /dev/null > >> +++ b/cifs.idmap.c > >> @@ -0,0 +1,215 @@ > >> +/* > >> +* 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> > >> +#ifdef HAVE_KEYUTILS_H > >> +#include <keyutils.h> > >> +#endif /* HAVE_KEYUTILS_H */ > > ^^^^^^^^^^ > > This can't be built w/o keyutils, right? So I don't think we need the > > #ifdefs. > > > >> +#include <stdint.h> > >> +#include <stdbool.h> > >> +#include <stdio.h> > >> +#include <stdlib.h> > >> +#include <errno.h> > >> +#include <limits.h> > >> +#ifdef HAVE_WBCLIENT_H > >> +#include <wbclient.h> > >> +#endif /* HAVE_WBCLIENT_H */ > >> + > >> +static const char *prog = "cifs.idmap"; > >> + > >> +static void usage(void) > >> +{ > >> + syslog(LOG_INFO, "Usage: %s [-t] [-v] [-l] key_serial", prog); > >> + fprintf(stderr, "Usage: %s [-t] [-v] [-l] key_serial\n", prog); > >> +} > >> + > >> +#ifdef HAVE_LIBWBCLIENT > >> +static int > >> +cifs_idmap(const key_serial_t key, const char *key_descr) > >> +{ > >> + int i; > >> + uid_t uid = 0; > >> + gid_t gid = 0;; > >> + wbcErr rc = 1; > >> + const char *keyend = key_descr; > >> + struct wbcDomainSid sid; > >> + struct passwd *pw; > >> + struct group *gr; > >> + > >> + /* skip next 4 ';' delimiters to get to description */ > >> + for (i = 1; i <= 4; ++i) { > >> + keyend = index(keyend + 1, ';'); > >> + if (!keyend) { > >> + syslog(LOG_ERR, "invalid key description: %s", > >> + key_descr); > >> + return 1; > >> + } > >> + } > >> + keyend++; > >> + > > > > No real bounds checking here. It seems unlikely, but a buggy kernel > > could send a garbled string and you could walk off the end of it here. > > > >> + /* > >> + * 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, use system calls to obtain > >> + * uid of user "nobody". If winbind fails to map a SID to an UID > >> + * and there is no user named "nobody", return error to the > >> + * upcall caller. Otherwise instanticate a key using that uid. > >> + * > >> + * The same applies to SID and gid mapping. Instead of a > >> + * user "nobody", user "nogroup" is looked up if winbind > >> + * fails to map a SID to a gid. > >> + */ > >> + if (strncmp(keyend, "os", 2) == 0) { > >> + keyend = index(keyend + 1, ':'); > >> + keyend++; > > ^^^^^^^^^ > > ditto on the bounds checks > > > >> + rc = wbcStringToSid(keyend, &sid); > >> + if (rc) > >> + syslog(LOG_DEBUG, "O strtosid: %s, rc: %d", keyend, rc); > >> + else { > >> + rc = wbcSidToUid(&sid, &uid); > >> + if (rc) > >> + syslog(LOG_DEBUG, "SID %s to uid wbc error: %d", > >> + keyend, rc); > >> + } > >> + if (rc) { /* either of the two wbcSid functions failed */ > >> + pw = getpwnam("nobody"); > >> + if (!pw) > >> + syslog(LOG_DEBUG, "SID %s to uid pw error: %d", > >> + keyend, rc); > >> + else { > >> + uid = pw->pw_uid; > >> + rc = 0; > >> + } > >> + } > >> + if (!rc) { /* SID has been mapped to a uid */ > >> + rc = keyctl_instantiate(key, &uid, sizeof(uid_t), 0); > >> + if (rc) > >> + syslog(LOG_ERR, "%s: key inst: %s", > >> + __func__, strerror(errno)); > >> + } > >> + } else if (strncmp(keyend, "gs", 2) == 0) { > >> + keyend = index(keyend + 1, ':'); > >> + keyend++; > >> + rc = wbcStringToSid(keyend, &sid); > >> + if (rc) > >> + syslog(LOG_DEBUG, "O strtosid: %s, rc: %d", keyend, rc); > >> + else { > >> + rc = wbcSidToGid(&sid, &gid); > >> + if (rc) > >> + syslog(LOG_DEBUG, "SID %s to gid wbc error: %d", > >> + keyend, rc); > >> + } > >> + if (rc) { /* either of the two wbcSid functions failed */ > >> + gr = getgrnam("nogroup"); > >> + if (!gr) > >> + syslog(LOG_DEBUG, "SID %s to gid pw error: %d", > >> + keyend, rc); > >> + else { > >> + gid = gr->gr_gid; > >> + rc = 0; > >> + } > >> + } > >> + 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)); > >> + } > >> + } else > >> + syslog(LOG_DEBUG, "Invalid SID: %s", keyend); > >> + > >> + return rc; > >> +} > >> +#endif /* HAVE_LIBWBCLIENT */ > >> + > >> +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); > >> + > >> +#ifdef HAVE_LIBWBCLIENT > >> + if ((strncmp(buf, "cifs.idmap", sizeof("cifs.idmap") - 1) == 0)) > >> + rc = cifs_idmap(key, buf); > >> +#endif /* HAVE_LIBWBCLIENT */ > >> + > > > > Doesn't this program require libwbclient? If so, then why the #ifdef's? > > > >> +out: > >> + /* > >> + * on error, negatively instantiate the key ourselves so that we can > >> + * make sure the kernel doesn't hang it off of a searchable keyring > >> + * and interfere with the next attempt to instantiate the key. > >> + */ > >> + if (rc != 0 && key == 0) > >> + keyctl_negate(key, 1, KEY_REQKEY_DEFL_DEFAULT); > > > > ^^^^^^^ > > Is a 1s timeout appropriate here? > > Not sure about the value? Would 30s or 60s timeout be appropriate? > Once a key request was fulfilled successfully, cifs module is not likely > to re-request that at key since it caches for an hour or so. > And if key request was unsuccessful, cifs module will not re-request > that key for another five minutes. > > Perhaps we can negatively instantiate it for 60 seconds and be ready > to handle any requests after that? > I think any value such as 1, 30, 60 seconds would work? > If that's the case, then there's probably no reason to negatively instantiate it at all. The kernel will do that on its own with a 60s timeout (I think). > > > >> + return rc; > >> +} > >> diff --git a/configure.ac b/configure.ac > >> index e0e2a60..d9eaead 100644 > >> --- a/configure.ac > >> +++ b/configure.ac > >> @@ -22,13 +22,19 @@ AC_ARG_ENABLE(cifscreds, > >> enable_cifscreds=$enableval, > >> enable_cifscreds="no") > >> > >> +AC_ARG_ENABLE(cifsidmap, > >> + [AC_HELP_STRING([--enable-cifsidmap], > >> + [Create cifs.idmap binary @<:@default=yes@:>@])], > >> + enable_cifsidmap=$enableval, > >> + enable_cifsidmap="maybe") > >> + > >> # Checks for programs. > >> AC_PROG_CC > >> AC_PROG_SED > >> AC_GNU_SOURCE > >> > >> # Checks for header files. > >> -AC_CHECK_HEADERS([arpa/inet.h ctype.h fcntl.h inttypes.h limits.h mntent.h netdb.h stddef.h stdint.h stdlib.h string.h strings.h sys/mount.h sys/param.h sys/socket.h sys/time.h syslog.h unistd.h], , [AC_MSG_ERROR([necessary header(s) not found])]) > >> +AC_CHECK_HEADERS([arpa/inet.h ctype.h fcntl.h inttypes.h limits.h mntent.h netdb.h stddef.h stdint.h stdbool.h stdlib.h stdio.h errno.h string.h strings.h sys/mount.h sys/param.h sys/socket.h sys/time.h syslog.h unistd.h], , [AC_MSG_ERROR([necessary header(s) not found])]) > >> > >> if test $enable_cifsupcall != "no"; then > >> AC_CHECK_HEADERS([krb5.h krb5/krb5.h]) > >> @@ -89,6 +95,55 @@ if test $enable_cifsupcall != "no"; then > >> AC_SUBST(KRB5_LDADD) > >> fi > >> > >> +if test $enable_cifsidmap != "no"; then > >> + AC_CHECK_HEADERS([keyutils.h], , [ > >> + if test "$enable_cifsidmap" = "yes"; then > >> + AC_MSG_ERROR([keyutils.h not found, consider installing keyutils-libs-devel.]) > >> + else > >> + AC_MSG_WARN([keyutils.h not found, consider installing keyutils-libs-devel. Disabling cifs.idmap.]) > >> + enable_cifsidmap="no" > >> + fi > >> + ]) > >> +fi > >> + > > > > We're already doing a AC_CHECK_HEADERS for keyutils.h -- I don't think > > we want to do it again. Just use the same check for both cifs.upcall > > and cifs.idmap. > > > >> +if test $enable_cifsidmap != "no"; then > >> + AC_CHECK_HEADERS([wbclient.h], , [ > >> + if test "$enable_cifsidmap" = "yes"; then > >> + AC_MSG_ERROR([wbclient.h not found, consider installing libwbclient-devel..]) > >> + else > >> + AC_MSG_WARN([keyutils.h not found, consider installing libwbclient-devel. Disabling cifs.idmap.]) > >> + enable_cifsidmap="no" > >> + fi > >> + ], > >> +[#ifdef HAVE_STDINT_H > >> +#include <stdint.h> > >> +#endif > >> +] > >> +[#ifdef HAVE_STDBOOL_H > >> +#include <stdbool.h> > >> +#endif > >> +] > >> +[#ifdef HAVE_STDIO_H > >> +#include <stdio.h> > >> +#endif > >> +] > >> +[#ifdef HAVE_STDLIB_H > >> +#include <stdlib.h> > >> +#endif > >> +] > >> +[#ifdef HAVE_ERRNO_H > >> +#include <errno.h> > >> +#endif > >> +] > >> +) > >> +fi > >> + > >> +if test $enable_cifsidmap != "no"; then > >> + AC_CHECK_LIB([wbclient], [wbcStringToSid], > >> + [ WINB_LDADD='-lwbclient' ] [ AC_DEFINE(HAVE_LIBWBCLIENT, 1, ["define var have_libwbclient"]) ], [AC_MSG_ERROR([no functioning wbclient library found!])]) > >> + AC_SUBST(WINB_LDADD) > >> +fi > >> + > > > > > > Bleh, that's pretty messy. Maybe this should go into a separate > > file/function in aclocal/ ? > > > > > >> if test $enable_cifscreds = "yes"; then > >> AC_CHECK_HEADERS([keyutils.h], , [AC_MSG_ERROR([keyutils.h not found, consider installing keyutils-libs-devel.])]) > >> fi > >> @@ -140,6 +195,7 @@ LIBS=$cu_saved_libs > >> > >> AM_CONDITIONAL(CONFIG_CIFSUPCALL, [test "$enable_cifsupcall" != "no"]) > >> AM_CONDITIONAL(CONFIG_CIFSCREDS, [test "$enable_cifscreds" = "yes"]) > >> +AM_CONDITIONAL(CONFIG_CIFSIDMAP, [test "$enable_cifsidmap" != "no"]) > >> > >> LIBCAP_NG_PATH > >> > > > > > > -- > > Jeff Layton <jlayton@redhat.com> > > > -- > To unsubscribe from this list: send the line "unsubscribe linux-cifs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tue, May 17, 2011 at 11:09 AM, Jeff Layton <jlayton@redhat.com> wrote: > On Fri, 6 May 2011 02:33:59 -0500 > shirishpargaonkar@gmail.com wrote: > >> From: Shirish Pargaonkar <shirishpargaonkar@gmail.com> >> >> Handle cifs.idmap type of key. Extract a SID string from the description >> and map it to either an uid or gid using winbind APIs. >> If that fails (e.g. because winbind is not installed/running or winbind returns >> an error), try to obtain uid of 'nobody' and gid of 'nogroup'. >> And if that fails, kernel assigns uid and gid (from mount superblock). >> >> Enable including winbind header files and idmapping code conditional >> to winbind devel rpms (header and library). >> >> An entry such as this >> >> create cifs.idmap * * /usr/sbin/cifs.idmap %k >> >> is needed in the file /etc/request-key.conf. >> >> >> Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com> >> --- >> Makefile.am | 8 ++ >> cifs.idmap.c | 215 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ >> configure.ac | 58 +++++++++++++++- >> 3 files changed, 280 insertions(+), 1 deletions(-) >> create mode 100644 cifs.idmap.c >> >> diff --git a/Makefile.am b/Makefile.am >> index 67a0190..ad33914 100644 >> --- a/Makefile.am >> +++ b/Makefile.am >> @@ -30,3 +30,11 @@ bin_PROGRAMS = cifscreds >> cifscreds_SOURCES = cifscreds.c resolve_host.c util.c >> cifscreds_LDADD = -lkeyutils >> endif >> + >> +if CONFIG_CIFSIDMAP >> +cifs_idmap_sbindir = /usr/local/sbin > > ^^^^^^^^^ > That looks wrong. If I configure with --prefix=/usr then this is still > going to go in /usr/local/sbin, right? I think you instead want to > append cifs.idmap to sbin_PROGRAMS. > >> +cifs_idmap_sbin_PROGRAMS = cifs.idmap >> +cifs_idmap_SOURCES = cifs.idmap.c >> +cifs_idmap_LDADD = -lkeyutils $(WINB_LDADD) >> +endif >> + >> diff --git a/cifs.idmap.c b/cifs.idmap.c >> new file mode 100644 >> index 0000000..0f76873 >> --- /dev/null >> +++ b/cifs.idmap.c >> @@ -0,0 +1,215 @@ >> +/* >> +* 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> >> +#ifdef HAVE_KEYUTILS_H >> +#include <keyutils.h> >> +#endif /* HAVE_KEYUTILS_H */ > ^^^^^^^^^^ > This can't be built w/o keyutils, right? So I don't think we need the > #ifdefs. > >> +#include <stdint.h> >> +#include <stdbool.h> >> +#include <stdio.h> >> +#include <stdlib.h> >> +#include <errno.h> >> +#include <limits.h> >> +#ifdef HAVE_WBCLIENT_H >> +#include <wbclient.h> >> +#endif /* HAVE_WBCLIENT_H */ >> + >> +static const char *prog = "cifs.idmap"; >> + >> +static void usage(void) >> +{ >> + syslog(LOG_INFO, "Usage: %s [-t] [-v] [-l] key_serial", prog); >> + fprintf(stderr, "Usage: %s [-t] [-v] [-l] key_serial\n", prog); >> +} >> + >> +#ifdef HAVE_LIBWBCLIENT >> +static int >> +cifs_idmap(const key_serial_t key, const char *key_descr) >> +{ >> + int i; >> + uid_t uid = 0; >> + gid_t gid = 0;; >> + wbcErr rc = 1; >> + const char *keyend = key_descr; >> + struct wbcDomainSid sid; >> + struct passwd *pw; >> + struct group *gr; >> + >> + /* skip next 4 ';' delimiters to get to description */ >> + for (i = 1; i <= 4; ++i) { >> + keyend = index(keyend + 1, ';'); >> + if (!keyend) { >> + syslog(LOG_ERR, "invalid key description: %s", >> + key_descr); >> + return 1; >> + } >> + } >> + keyend++; >> + > > No real bounds checking here. It seems unlikely, but a buggy kernel > could send a garbled string and you could walk off the end of it here. > >> + /* >> + * 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, use system calls to obtain >> + * uid of user "nobody". If winbind fails to map a SID to an UID >> + * and there is no user named "nobody", return error to the >> + * upcall caller. Otherwise instanticate a key using that uid. >> + * >> + * The same applies to SID and gid mapping. Instead of a >> + * user "nobody", user "nogroup" is looked up if winbind >> + * fails to map a SID to a gid. >> + */ >> + if (strncmp(keyend, "os", 2) == 0) { >> + keyend = index(keyend + 1, ':'); >> + keyend++; > ^^^^^^^^^ > ditto on the bounds checks > >> + rc = wbcStringToSid(keyend, &sid); >> + if (rc) >> + syslog(LOG_DEBUG, "O strtosid: %s, rc: %d", keyend, rc); >> + else { >> + rc = wbcSidToUid(&sid, &uid); >> + if (rc) >> + syslog(LOG_DEBUG, "SID %s to uid wbc error: %d", >> + keyend, rc); >> + } >> + if (rc) { /* either of the two wbcSid functions failed */ >> + pw = getpwnam("nobody"); >> + if (!pw) >> + syslog(LOG_DEBUG, "SID %s to uid pw error: %d", >> + keyend, rc); >> + else { >> + uid = pw->pw_uid; >> + rc = 0; >> + } >> + } >> + if (!rc) { /* SID has been mapped to a uid */ >> + rc = keyctl_instantiate(key, &uid, sizeof(uid_t), 0); >> + if (rc) >> + syslog(LOG_ERR, "%s: key inst: %s", >> + __func__, strerror(errno)); >> + } >> + } else if (strncmp(keyend, "gs", 2) == 0) { >> + keyend = index(keyend + 1, ':'); >> + keyend++; >> + rc = wbcStringToSid(keyend, &sid); >> + if (rc) >> + syslog(LOG_DEBUG, "O strtosid: %s, rc: %d", keyend, rc); >> + else { >> + rc = wbcSidToGid(&sid, &gid); >> + if (rc) >> + syslog(LOG_DEBUG, "SID %s to gid wbc error: %d", >> + keyend, rc); >> + } >> + if (rc) { /* either of the two wbcSid functions failed */ >> + gr = getgrnam("nogroup"); >> + if (!gr) >> + syslog(LOG_DEBUG, "SID %s to gid pw error: %d", >> + keyend, rc); >> + else { >> + gid = gr->gr_gid; >> + rc = 0; >> + } >> + } >> + 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)); >> + } >> + } else >> + syslog(LOG_DEBUG, "Invalid SID: %s", keyend); >> + >> + return rc; >> +} >> +#endif /* HAVE_LIBWBCLIENT */ >> + >> +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); >> + >> +#ifdef HAVE_LIBWBCLIENT >> + if ((strncmp(buf, "cifs.idmap", sizeof("cifs.idmap") - 1) == 0)) >> + rc = cifs_idmap(key, buf); >> +#endif /* HAVE_LIBWBCLIENT */ >> + > > Doesn't this program require libwbclient? If so, then why the #ifdef's? > >> +out: >> + /* >> + * on error, negatively instantiate the key ourselves so that we can >> + * make sure the kernel doesn't hang it off of a searchable keyring >> + * and interfere with the next attempt to instantiate the key. >> + */ >> + if (rc != 0 && key == 0) >> + keyctl_negate(key, 1, KEY_REQKEY_DEFL_DEFAULT); > > ^^^^^^^ > Is a 1s timeout appropriate here? > >> + return rc; >> +} >> diff --git a/configure.ac b/configure.ac >> index e0e2a60..d9eaead 100644 >> --- a/configure.ac >> +++ b/configure.ac >> @@ -22,13 +22,19 @@ AC_ARG_ENABLE(cifscreds, >> enable_cifscreds=$enableval, >> enable_cifscreds="no") >> >> +AC_ARG_ENABLE(cifsidmap, >> + [AC_HELP_STRING([--enable-cifsidmap], >> + [Create cifs.idmap binary @<:@default=yes@:>@])], >> + enable_cifsidmap=$enableval, >> + enable_cifsidmap="maybe") >> + >> # Checks for programs. >> AC_PROG_CC >> AC_PROG_SED >> AC_GNU_SOURCE >> >> # Checks for header files. >> -AC_CHECK_HEADERS([arpa/inet.h ctype.h fcntl.h inttypes.h limits.h mntent.h netdb.h stddef.h stdint.h stdlib.h string.h strings.h sys/mount.h sys/param.h sys/socket.h sys/time.h syslog.h unistd.h], , [AC_MSG_ERROR([necessary header(s) not found])]) >> +AC_CHECK_HEADERS([arpa/inet.h ctype.h fcntl.h inttypes.h limits.h mntent.h netdb.h stddef.h stdint.h stdbool.h stdlib.h stdio.h errno.h string.h strings.h sys/mount.h sys/param.h sys/socket.h sys/time.h syslog.h unistd.h], , [AC_MSG_ERROR([necessary header(s) not found])]) >> >> if test $enable_cifsupcall != "no"; then >> AC_CHECK_HEADERS([krb5.h krb5/krb5.h]) >> @@ -89,6 +95,55 @@ if test $enable_cifsupcall != "no"; then >> AC_SUBST(KRB5_LDADD) >> fi >> >> +if test $enable_cifsidmap != "no"; then >> + AC_CHECK_HEADERS([keyutils.h], , [ >> + if test "$enable_cifsidmap" = "yes"; then >> + AC_MSG_ERROR([keyutils.h not found, consider installing keyutils-libs-devel.]) >> + else >> + AC_MSG_WARN([keyutils.h not found, consider installing keyutils-libs-devel. Disabling cifs.idmap.]) >> + enable_cifsidmap="no" >> + fi >> + ]) >> +fi >> + > > We're already doing a AC_CHECK_HEADERS for keyutils.h -- I don't think > we want to do it again. Just use the same check for both cifs.upcall > and cifs.idmap. > >> +if test $enable_cifsidmap != "no"; then >> + AC_CHECK_HEADERS([wbclient.h], , [ >> + if test "$enable_cifsidmap" = "yes"; then >> + AC_MSG_ERROR([wbclient.h not found, consider installing libwbclient-devel..]) >> + else >> + AC_MSG_WARN([keyutils.h not found, consider installing libwbclient-devel. Disabling cifs.idmap.]) >> + enable_cifsidmap="no" >> + fi >> + ], >> +[#ifdef HAVE_STDINT_H >> +#include <stdint.h> >> +#endif >> +] >> +[#ifdef HAVE_STDBOOL_H >> +#include <stdbool.h> >> +#endif >> +] >> +[#ifdef HAVE_STDIO_H >> +#include <stdio.h> >> +#endif >> +] >> +[#ifdef HAVE_STDLIB_H >> +#include <stdlib.h> >> +#endif >> +] >> +[#ifdef HAVE_ERRNO_H >> +#include <errno.h> >> +#endif >> +] >> +) >> +fi >> + >> +if test $enable_cifsidmap != "no"; then >> + AC_CHECK_LIB([wbclient], [wbcStringToSid], >> + [ WINB_LDADD='-lwbclient' ] [ AC_DEFINE(HAVE_LIBWBCLIENT, 1, ["define var have_libwbclient"]) ], [AC_MSG_ERROR([no functioning wbclient library found!])]) >> + AC_SUBST(WINB_LDADD) >> +fi >> + > > > Bleh, that's pretty messy. Maybe this should go into a separate > file/function in aclocal/ ? > Jeff, this is what the documentation http://www.gnu.org/s/hello/manual/autoconf/Present-But-Cannot-Be-Compiled.html says configure: WARNING: pi.h: present but cannot be compiled configure: WARNING: pi.h: check for missing prerequisite headers? configure: WARNING: pi.h: see the Autoconf documentation configure: WARNING: pi.h: section "Present But Cannot Be Compiled" configure: WARNING: pi.h: proceeding with the compiler's result configure: WARNING: ## -------------------------------------- ## configure: WARNING: ## Report this to bug-example@example.org ## configure: WARNING: ## -------------------------------------- ## checking for pi.h... yes The proper way the handle this case is using the fourth argument (see Generic Headers): $ cat configure.ac AC_INIT([Example], [1.0], [bug-example@example.org]) AC_CHECK_HEADERS([number.h pi.h], [], [], [[#ifdef HAVE_NUMBER_H # include <number.h> #endif ]]) Looking for any other way to handle prereq headers to check whether a header file inclusion compiles or not. Regards, Shirish > >> if test $enable_cifscreds = "yes"; then >> AC_CHECK_HEADERS([keyutils.h], , [AC_MSG_ERROR([keyutils.h not found, consider installing keyutils-libs-devel.])]) >> fi >> @@ -140,6 +195,7 @@ LIBS=$cu_saved_libs >> >> AM_CONDITIONAL(CONFIG_CIFSUPCALL, [test "$enable_cifsupcall" != "no"]) >> AM_CONDITIONAL(CONFIG_CIFSCREDS, [test "$enable_cifscreds" = "yes"]) >> +AM_CONDITIONAL(CONFIG_CIFSIDMAP, [test "$enable_cifsidmap" != "no"]) >> >> LIBCAP_NG_PATH >> > > > -- > Jeff Layton <jlayton@redhat.com> > -- To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/Makefile.am b/Makefile.am index 67a0190..ad33914 100644 --- a/Makefile.am +++ b/Makefile.am @@ -30,3 +30,11 @@ bin_PROGRAMS = cifscreds cifscreds_SOURCES = cifscreds.c resolve_host.c util.c cifscreds_LDADD = -lkeyutils endif + +if CONFIG_CIFSIDMAP +cifs_idmap_sbindir = /usr/local/sbin +cifs_idmap_sbin_PROGRAMS = cifs.idmap +cifs_idmap_SOURCES = cifs.idmap.c +cifs_idmap_LDADD = -lkeyutils $(WINB_LDADD) +endif + diff --git a/cifs.idmap.c b/cifs.idmap.c new file mode 100644 index 0000000..0f76873 --- /dev/null +++ b/cifs.idmap.c @@ -0,0 +1,215 @@ +/* +* 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> +#ifdef HAVE_KEYUTILS_H +#include <keyutils.h> +#endif /* HAVE_KEYUTILS_H */ +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <limits.h> +#ifdef HAVE_WBCLIENT_H +#include <wbclient.h> +#endif /* HAVE_WBCLIENT_H */ + +static const char *prog = "cifs.idmap"; + +static void usage(void) +{ + syslog(LOG_INFO, "Usage: %s [-t] [-v] [-l] key_serial", prog); + fprintf(stderr, "Usage: %s [-t] [-v] [-l] key_serial\n", prog); +} + +#ifdef HAVE_LIBWBCLIENT +static int +cifs_idmap(const key_serial_t key, const char *key_descr) +{ + int i; + uid_t uid = 0; + gid_t gid = 0;; + wbcErr rc = 1; + const char *keyend = key_descr; + struct wbcDomainSid sid; + struct passwd *pw; + struct group *gr; + + /* skip next 4 ';' delimiters to get to description */ + for (i = 1; i <= 4; ++i) { + keyend = index(keyend + 1, ';'); + if (!keyend) { + syslog(LOG_ERR, "invalid key description: %s", + key_descr); + return 1; + } + } + keyend++; + + /* + * 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, use system calls to obtain + * uid of user "nobody". If winbind fails to map a SID to an UID + * and there is no user named "nobody", return error to the + * upcall caller. Otherwise instanticate a key using that uid. + * + * The same applies to SID and gid mapping. Instead of a + * user "nobody", user "nogroup" is looked up if winbind + * fails to map a SID to a gid. + */ + if (strncmp(keyend, "os", 2) == 0) { + keyend = index(keyend + 1, ':'); + keyend++; + rc = wbcStringToSid(keyend, &sid); + if (rc) + syslog(LOG_DEBUG, "O strtosid: %s, rc: %d", keyend, rc); + else { + rc = wbcSidToUid(&sid, &uid); + if (rc) + syslog(LOG_DEBUG, "SID %s to uid wbc error: %d", + keyend, rc); + } + if (rc) { /* either of the two wbcSid functions failed */ + pw = getpwnam("nobody"); + if (!pw) + syslog(LOG_DEBUG, "SID %s to uid pw error: %d", + keyend, rc); + else { + uid = pw->pw_uid; + rc = 0; + } + } + if (!rc) { /* SID has been mapped to a uid */ + rc = keyctl_instantiate(key, &uid, sizeof(uid_t), 0); + if (rc) + syslog(LOG_ERR, "%s: key inst: %s", + __func__, strerror(errno)); + } + } else if (strncmp(keyend, "gs", 2) == 0) { + keyend = index(keyend + 1, ':'); + keyend++; + rc = wbcStringToSid(keyend, &sid); + if (rc) + syslog(LOG_DEBUG, "O strtosid: %s, rc: %d", keyend, rc); + else { + rc = wbcSidToGid(&sid, &gid); + if (rc) + syslog(LOG_DEBUG, "SID %s to gid wbc error: %d", + keyend, rc); + } + if (rc) { /* either of the two wbcSid functions failed */ + gr = getgrnam("nogroup"); + if (!gr) + syslog(LOG_DEBUG, "SID %s to gid pw error: %d", + keyend, rc); + else { + gid = gr->gr_gid; + rc = 0; + } + } + 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)); + } + } else + syslog(LOG_DEBUG, "Invalid SID: %s", keyend); + + return rc; +} +#endif /* HAVE_LIBWBCLIENT */ + +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); + +#ifdef HAVE_LIBWBCLIENT + if ((strncmp(buf, "cifs.idmap", sizeof("cifs.idmap") - 1) == 0)) + rc = cifs_idmap(key, buf); +#endif /* HAVE_LIBWBCLIENT */ + +out: + /* + * on error, negatively instantiate the key ourselves so that we can + * make sure the kernel doesn't hang it off of a searchable keyring + * and interfere with the next attempt to instantiate the key. + */ + if (rc != 0 && key == 0) + keyctl_negate(key, 1, KEY_REQKEY_DEFL_DEFAULT); + return rc; +} diff --git a/configure.ac b/configure.ac index e0e2a60..d9eaead 100644 --- a/configure.ac +++ b/configure.ac @@ -22,13 +22,19 @@ AC_ARG_ENABLE(cifscreds, enable_cifscreds=$enableval, enable_cifscreds="no") +AC_ARG_ENABLE(cifsidmap, + [AC_HELP_STRING([--enable-cifsidmap], + [Create cifs.idmap binary @<:@default=yes@:>@])], + enable_cifsidmap=$enableval, + enable_cifsidmap="maybe") + # Checks for programs. AC_PROG_CC AC_PROG_SED AC_GNU_SOURCE # Checks for header files. -AC_CHECK_HEADERS([arpa/inet.h ctype.h fcntl.h inttypes.h limits.h mntent.h netdb.h stddef.h stdint.h stdlib.h string.h strings.h sys/mount.h sys/param.h sys/socket.h sys/time.h syslog.h unistd.h], , [AC_MSG_ERROR([necessary header(s) not found])]) +AC_CHECK_HEADERS([arpa/inet.h ctype.h fcntl.h inttypes.h limits.h mntent.h netdb.h stddef.h stdint.h stdbool.h stdlib.h stdio.h errno.h string.h strings.h sys/mount.h sys/param.h sys/socket.h sys/time.h syslog.h unistd.h], , [AC_MSG_ERROR([necessary header(s) not found])]) if test $enable_cifsupcall != "no"; then AC_CHECK_HEADERS([krb5.h krb5/krb5.h]) @@ -89,6 +95,55 @@ if test $enable_cifsupcall != "no"; then AC_SUBST(KRB5_LDADD) fi +if test $enable_cifsidmap != "no"; then + AC_CHECK_HEADERS([keyutils.h], , [ + if test "$enable_cifsidmap" = "yes"; then + AC_MSG_ERROR([keyutils.h not found, consider installing keyutils-libs-devel.]) + else + AC_MSG_WARN([keyutils.h not found, consider installing keyutils-libs-devel. Disabling cifs.idmap.]) + enable_cifsidmap="no" + fi + ]) +fi + +if test $enable_cifsidmap != "no"; then + AC_CHECK_HEADERS([wbclient.h], , [ + if test "$enable_cifsidmap" = "yes"; then + AC_MSG_ERROR([wbclient.h not found, consider installing libwbclient-devel..]) + else + AC_MSG_WARN([keyutils.h not found, consider installing libwbclient-devel. Disabling cifs.idmap.]) + enable_cifsidmap="no" + fi + ], +[#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif +] +[#ifdef HAVE_STDBOOL_H +#include <stdbool.h> +#endif +] +[#ifdef HAVE_STDIO_H +#include <stdio.h> +#endif +] +[#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +] +[#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +] +) +fi + +if test $enable_cifsidmap != "no"; then + AC_CHECK_LIB([wbclient], [wbcStringToSid], + [ WINB_LDADD='-lwbclient' ] [ AC_DEFINE(HAVE_LIBWBCLIENT, 1, ["define var have_libwbclient"]) ], [AC_MSG_ERROR([no functioning wbclient library found!])]) + AC_SUBST(WINB_LDADD) +fi + if test $enable_cifscreds = "yes"; then AC_CHECK_HEADERS([keyutils.h], , [AC_MSG_ERROR([keyutils.h not found, consider installing keyutils-libs-devel.])]) fi @@ -140,6 +195,7 @@ LIBS=$cu_saved_libs AM_CONDITIONAL(CONFIG_CIFSUPCALL, [test "$enable_cifsupcall" != "no"]) AM_CONDITIONAL(CONFIG_CIFSCREDS, [test "$enable_cifscreds" = "yes"]) +AM_CONDITIONAL(CONFIG_CIFSIDMAP, [test "$enable_cifsidmap" != "no"]) LIBCAP_NG_PATH