diff mbox

cifs-utils: Create new binary cifs.idmap for sid to uid/gid mapping

Message ID 1304667239-29127-1-git-send-email-shirishp@linux.vnet.ibm.com (mailing list archive)
State New, archived
Headers show

Commit Message

Shirish Pargaonkar May 6, 2011, 7:33 a.m. UTC
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

Comments

Jeff Layton May 17, 2011, 4:09 p.m. UTC | #1
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
>
Shirish Pargaonkar May 17, 2011, 5:01 p.m. UTC | #2
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
Jeff Layton May 17, 2011, 5:14 p.m. UTC | #3
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.
Shirish Pargaonkar May 17, 2011, 5:47 p.m. UTC | #4
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
Jeff Layton May 17, 2011, 5:56 p.m. UTC | #5
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.
Jeff Layton May 18, 2011, 12:25 p.m. UTC | #6
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
Shirish Pargaonkar May 18, 2011, 6:32 p.m. UTC | #7
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 mbox

Patch

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