diff mbox

cifs-utils: Handle cifs_idmap type of key to map a SID to either an uid or gid (try #17 repost)

Message ID 1303914990-7804-1-git-send-email-shirishpargaonkar@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Shirish Pargaonkar April 27, 2011, 2:36 p.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.cifs_idmap   *       *               /usr/sbin/cifs.upcall %k

is needed in the file /etc/request-key.conf.


Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
---
 Makefile.am   |    2 +-
 cifs.upcall.c |  117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 configure.ac  |   35 +++++++++++++++++
 3 files changed, 152 insertions(+), 2 deletions(-)

Comments

Jeff Layton May 2, 2011, 11:51 a.m. UTC | #1
On Wed, 27 Apr 2011 09:36:30 -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.cifs_idmap   *       *               /usr/sbin/cifs.upcall %k
> 
> is needed in the file /etc/request-key.conf.
> 
> 
> Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
> ---
>  Makefile.am   |    2 +-
>  cifs.upcall.c |  117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  configure.ac  |   35 +++++++++++++++++
>  3 files changed, 152 insertions(+), 2 deletions(-)
> 
> diff --git a/Makefile.am b/Makefile.am
> index 67a0190..13b6c16 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -11,7 +11,7 @@ man_MANS = mount.cifs.8
>  if CONFIG_CIFSUPCALL
>  sbin_PROGRAMS = cifs.upcall
>  cifs_upcall_SOURCES = cifs.upcall.c data_blob.c asn1.c spnego.c util.c
> -cifs_upcall_LDADD = -ltalloc -lkeyutils $(KRB5_LDADD)
> +cifs_upcall_LDADD = -ltalloc -lkeyutils $(KRB5_LDADD) $(WINB_LDADD)
>  man_MANS += cifs.upcall.8
>  
>  #
> diff --git a/cifs.upcall.c b/cifs.upcall.c
> index 479517c..6c2088b 100644
> --- a/cifs.upcall.c
> +++ b/cifs.upcall.c
> @@ -45,6 +45,15 @@
>  #include <time.h>
>  #include <netdb.h>
>  #include <arpa/inet.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 */
>  
>  #include "util.h"
>  #include "replace.h"
> @@ -653,7 +662,7 @@ static int cifs_resolver(const key_serial_t key, const char *key_descr)
>  	const char *keyend = key_descr;
>  	/* skip next 4 ';' delimiters to get to description */
>  	for (c = 1; c <= 4; c++) {
> -		keyend = index(keyend + 1, ';');
> +		keyend = rindex(keyend + 1, ';');
>  		if (!keyend) {
>  			syslog(LOG_ERR, "invalid key description: %s",
>  			       key_descr);
> @@ -695,6 +704,105 @@ static int cifs_resolver(const key_serial_t key, const char *key_descr)
>  	return 0;
>  }
>  
> +#ifdef HAVE_LIBWBCLIENT
> +static int
> +cifs_sid_resolver(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 */
> +
>  /*
>   * Older kernels sent IPv6 addresses without colons. Well, at least
>   * they're fixed-length strings. Convert these addresses to have colon
> @@ -832,6 +940,13 @@ int main(const int argc, char *const argv[])
>  		rc = cifs_resolver(key, buf);
>  		goto out;
>  	}
> +#ifdef HAVE_LIBWBCLIENT
> +	if ((strncmp(buf, "cifs.cifs_idmap", sizeof("cifs.cifs_idmap") - 1)
> +			== 0)) {
> +		rc = cifs_sid_resolver(key, buf);
> +		goto out;
> +	}
> +#endif /* HAVE_LIBWBCLIENT */
>  
>  	have = decode_key_description(buf, &arg);
>  	SAFE_FREE(buf);
> diff --git a/configure.ac b/configure.ac
> index e0e2a60..45800bd 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -89,6 +89,41 @@ if test $enable_cifsupcall != "no"; then
>  	AC_SUBST(KRB5_LDADD)
>  fi
>  
> +if test $enable_cifsupcall != "no"; then
> +	AC_CHECK_LIB([wbclient], [wbcStringToSid],
> +		[ WINB_LDADD='-lwbclient' ] [ AC_DEFINE(HAVE_LIBWBCLIENT, 1, ["define a var"]) ], AC_MSG_ERROR([no functioning wbclient library found!]))
> +	AC_SUBST(WINB_LDADD)
> +fi
> +
> +if test $enable_cifsupcall != "no"; then
> +	AC_CHECK_HEADERS([stdbool.h])
> +	AC_CHECK_HEADERS([stdio.h])
> +	AC_CHECK_HEADERS([errno.h])
> +	AC_CHECK_HEADERS([wbclient.h], , [AC_MSG_ERROR([wbclient.h not found, consider installing libwbclient-devel.])],
> +[#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

What on earth is the stuff above? configure.ac is at it's heart a shell
script, so I'm pretty sure the above will end up looking like a bunch
of comments wrapped in square brackets.

> +
> +# Checks for typedefs, structures, and compiler characteristics.
>  if test $enable_cifscreds = "yes"; then
>  	AC_CHECK_HEADERS([keyutils.h], , [AC_MSG_ERROR([keyutils.h not found, consider installing keyutils-libs-devel.])])
>  fi



I think this code should be a separate program. I realize that we have
precedent for making this part of the same binary since the SPNEGO and
DNS upcalls are that way, but I don't think that was a good choice in
retrospect.

These programs ought to be small and single-purpose. If you add this
in, then every time you do a SPENGO upcall, you'll get the wb_client
libs linked in. Vice versa for the idmapping upcall wrt to krb5 libs
(which is really a bigger problem). So, keeping them as part of the
same program has clear drawbacks. It also makes the code more messy.

The DNS part of this program should (eventually) go away now that it's
part of a unified kernel infrastructure. At that point cifs.upcall will
be a SPNEGO upcall only again. Let's foster that by making this a
separate program in its own right.

With that change too, I'd like to see a --enable-cifsidmap option or
something that allows the new program to be conditionally compiled.
That can default to "on" but should autodisable when libwbclient or
other needed libs aren't present.
Shirish Pargaonkar May 2, 2011, 12:35 p.m. UTC | #2
On Mon, May 2, 2011 at 6:51 AM, Jeff Layton <jlayton@redhat.com> wrote:
> On Wed, 27 Apr 2011 09:36:30 -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.cifs_idmap   *       *               /usr/sbin/cifs.upcall %k
>>
>> is needed in the file /etc/request-key.conf.
>>
>>
>> Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
>> ---
>>  Makefile.am   |    2 +-
>>  cifs.upcall.c |  117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>>  configure.ac  |   35 +++++++++++++++++
>>  3 files changed, 152 insertions(+), 2 deletions(-)
>>
>> diff --git a/Makefile.am b/Makefile.am
>> index 67a0190..13b6c16 100644
>> --- a/Makefile.am
>> +++ b/Makefile.am
>> @@ -11,7 +11,7 @@ man_MANS = mount.cifs.8
>>  if CONFIG_CIFSUPCALL
>>  sbin_PROGRAMS = cifs.upcall
>>  cifs_upcall_SOURCES = cifs.upcall.c data_blob.c asn1.c spnego.c util.c
>> -cifs_upcall_LDADD = -ltalloc -lkeyutils $(KRB5_LDADD)
>> +cifs_upcall_LDADD = -ltalloc -lkeyutils $(KRB5_LDADD) $(WINB_LDADD)
>>  man_MANS += cifs.upcall.8
>>
>>  #
>> diff --git a/cifs.upcall.c b/cifs.upcall.c
>> index 479517c..6c2088b 100644
>> --- a/cifs.upcall.c
>> +++ b/cifs.upcall.c
>> @@ -45,6 +45,15 @@
>>  #include <time.h>
>>  #include <netdb.h>
>>  #include <arpa/inet.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 */
>>
>>  #include "util.h"
>>  #include "replace.h"
>> @@ -653,7 +662,7 @@ static int cifs_resolver(const key_serial_t key, const char *key_descr)
>>       const char *keyend = key_descr;
>>       /* skip next 4 ';' delimiters to get to description */
>>       for (c = 1; c <= 4; c++) {
>> -             keyend = index(keyend + 1, ';');
>> +             keyend = rindex(keyend + 1, ';');
>>               if (!keyend) {
>>                       syslog(LOG_ERR, "invalid key description: %s",
>>                              key_descr);
>> @@ -695,6 +704,105 @@ static int cifs_resolver(const key_serial_t key, const char *key_descr)
>>       return 0;
>>  }
>>
>> +#ifdef HAVE_LIBWBCLIENT
>> +static int
>> +cifs_sid_resolver(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 */
>> +
>>  /*
>>   * Older kernels sent IPv6 addresses without colons. Well, at least
>>   * they're fixed-length strings. Convert these addresses to have colon
>> @@ -832,6 +940,13 @@ int main(const int argc, char *const argv[])
>>               rc = cifs_resolver(key, buf);
>>               goto out;
>>       }
>> +#ifdef HAVE_LIBWBCLIENT
>> +     if ((strncmp(buf, "cifs.cifs_idmap", sizeof("cifs.cifs_idmap") - 1)
>> +                     == 0)) {
>> +             rc = cifs_sid_resolver(key, buf);
>> +             goto out;
>> +     }
>> +#endif /* HAVE_LIBWBCLIENT */
>>
>>       have = decode_key_description(buf, &arg);
>>       SAFE_FREE(buf);
>> diff --git a/configure.ac b/configure.ac
>> index e0e2a60..45800bd 100644
>> --- a/configure.ac
>> +++ b/configure.ac
>> @@ -89,6 +89,41 @@ if test $enable_cifsupcall != "no"; then
>>       AC_SUBST(KRB5_LDADD)
>>  fi
>>
>> +if test $enable_cifsupcall != "no"; then
>> +     AC_CHECK_LIB([wbclient], [wbcStringToSid],
>> +             [ WINB_LDADD='-lwbclient' ] [ AC_DEFINE(HAVE_LIBWBCLIENT, 1, ["define a var"]) ], AC_MSG_ERROR([no functioning wbclient library found!]))
>> +     AC_SUBST(WINB_LDADD)
>> +fi
>> +
>> +if test $enable_cifsupcall != "no"; then
>> +     AC_CHECK_HEADERS([stdbool.h])
>> +     AC_CHECK_HEADERS([stdio.h])
>> +     AC_CHECK_HEADERS([errno.h])
>> +     AC_CHECK_HEADERS([wbclient.h], , [AC_MSG_ERROR([wbclient.h not found, consider installing libwbclient-devel.])],
>> +[#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
>
> What on earth is the stuff above? configure.ac is at it's heart a shell
> script, so I'm pretty sure the above will end up looking like a bunch
> of comments wrapped in square brackets.
>

Without it, I see following in config.log

checking wbclient.h usability... no
checking wbclient.h presence... yes
configure: WARNING: wbclient.h: present but cannot be compiled
configure: WARNING: wbclient.h:     check for missing prerequisite headers?
configure: WARNING: wbclient.h: see the Autoconf documentation
configure: WARNING: wbclient.h:     section "Present But Cannot Be Compiled"
configure: WARNING: wbclient.h: proceeding with the preprocessor's result
configure: WARNING: wbclient.h: in the future, the compiler will take precedence
configure: WARNING:     ## ----------------------------------- ##
configure: WARNING:     ## Report this to cifs-utils@samba.org ##
configure: WARNING:     ## ----------------------------------- ##
checking for wbclient.h... yes

With it, this

checking for wbcStringToSid in -lwbclient... yes
checking stdbool.h usability... yes
checking stdbool.h presence... yes
checking for stdbool.h... yes
checking stdio.h usability... yes
checking stdio.h presence... yes
checking for stdio.h... yes
checking errno.h usability... yes
checking errno.h presence... yes
checking for errno.h... yes
checking for wbclient.h... yes

>> +
>> +# Checks for typedefs, structures, and compiler characteristics.
>>  if test $enable_cifscreds = "yes"; then
>>       AC_CHECK_HEADERS([keyutils.h], , [AC_MSG_ERROR([keyutils.h not found, consider installing keyutils-libs-devel.])])
>>  fi
>
>
>
> I think this code should be a separate program. I realize that we have
> precedent for making this part of the same binary since the SPNEGO and
> DNS upcalls are that way, but I don't think that was a good choice in
> retrospect.
>
> These programs ought to be small and single-purpose. If you add this
> in, then every time you do a SPENGO upcall, you'll get the wb_client
> libs linked in. Vice versa for the idmapping upcall wrt to krb5 libs
> (which is really a bigger problem). So, keeping them as part of the
> same program has clear drawbacks. It also makes the code more messy.
>
> The DNS part of this program should (eventually) go away now that it's
> part of a unified kernel infrastructure. At that point cifs.upcall will
> be a SPNEGO upcall only again. Let's foster that by making this a
> separate program in its own right.
>
> With that change too, I'd like to see a --enable-cifsidmap option or
> something that allows the new program to be conditionally compiled.
> That can default to "on" but should autodisable when libwbclient or
> other needed libs aren't present.
>
> --
> 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..13b6c16 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -11,7 +11,7 @@  man_MANS = mount.cifs.8
 if CONFIG_CIFSUPCALL
 sbin_PROGRAMS = cifs.upcall
 cifs_upcall_SOURCES = cifs.upcall.c data_blob.c asn1.c spnego.c util.c
-cifs_upcall_LDADD = -ltalloc -lkeyutils $(KRB5_LDADD)
+cifs_upcall_LDADD = -ltalloc -lkeyutils $(KRB5_LDADD) $(WINB_LDADD)
 man_MANS += cifs.upcall.8
 
 #
diff --git a/cifs.upcall.c b/cifs.upcall.c
index 479517c..6c2088b 100644
--- a/cifs.upcall.c
+++ b/cifs.upcall.c
@@ -45,6 +45,15 @@ 
 #include <time.h>
 #include <netdb.h>
 #include <arpa/inet.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 */
 
 #include "util.h"
 #include "replace.h"
@@ -653,7 +662,7 @@  static int cifs_resolver(const key_serial_t key, const char *key_descr)
 	const char *keyend = key_descr;
 	/* skip next 4 ';' delimiters to get to description */
 	for (c = 1; c <= 4; c++) {
-		keyend = index(keyend + 1, ';');
+		keyend = rindex(keyend + 1, ';');
 		if (!keyend) {
 			syslog(LOG_ERR, "invalid key description: %s",
 			       key_descr);
@@ -695,6 +704,105 @@  static int cifs_resolver(const key_serial_t key, const char *key_descr)
 	return 0;
 }
 
+#ifdef HAVE_LIBWBCLIENT
+static int
+cifs_sid_resolver(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 */
+
 /*
  * Older kernels sent IPv6 addresses without colons. Well, at least
  * they're fixed-length strings. Convert these addresses to have colon
@@ -832,6 +940,13 @@  int main(const int argc, char *const argv[])
 		rc = cifs_resolver(key, buf);
 		goto out;
 	}
+#ifdef HAVE_LIBWBCLIENT
+	if ((strncmp(buf, "cifs.cifs_idmap", sizeof("cifs.cifs_idmap") - 1)
+			== 0)) {
+		rc = cifs_sid_resolver(key, buf);
+		goto out;
+	}
+#endif /* HAVE_LIBWBCLIENT */
 
 	have = decode_key_description(buf, &arg);
 	SAFE_FREE(buf);
diff --git a/configure.ac b/configure.ac
index e0e2a60..45800bd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -89,6 +89,41 @@  if test $enable_cifsupcall != "no"; then
 	AC_SUBST(KRB5_LDADD)
 fi
 
+if test $enable_cifsupcall != "no"; then
+	AC_CHECK_LIB([wbclient], [wbcStringToSid],
+		[ WINB_LDADD='-lwbclient' ] [ AC_DEFINE(HAVE_LIBWBCLIENT, 1, ["define a var"]) ], AC_MSG_ERROR([no functioning wbclient library found!]))
+	AC_SUBST(WINB_LDADD)
+fi
+
+if test $enable_cifsupcall != "no"; then
+	AC_CHECK_HEADERS([stdbool.h])
+	AC_CHECK_HEADERS([stdio.h])
+	AC_CHECK_HEADERS([errno.h])
+	AC_CHECK_HEADERS([wbclient.h], , [AC_MSG_ERROR([wbclient.h not found, consider installing libwbclient-devel.])],
+[#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
+
+# Checks for typedefs, structures, and compiler characteristics.
 if test $enable_cifscreds = "yes"; then
 	AC_CHECK_HEADERS([keyutils.h], , [AC_MSG_ERROR([keyutils.h not found, consider installing keyutils-libs-devel.])])
 fi