This is a multi-part message in MIME format.
--------------020808090104020706010006
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 7bit

0001-Fix-cifs-upcall-key-name-for-DNS-resolving.patch - corrects key name for cifs dns upcall

0002-Adds-support-for-using-krb5.keytab-for-non-interacti.patch - adds support for non interactive mount using keytab

Some notes:
It uses default keytab (as it defined in kerberos libs or in krb5.conf).
Mount options should look like this:
user=my_krb5_username,password=fake,sec=krb5i

option: 'password' is just for mount.cifs to be happy and not ask for password.

Entry to keytab added with ktutil command:

'addent -password -p my_krb5_username -k 1 -e rc4-hmac'

PS:
In my case only 'rc4-hmac' encryption worked (a krb5 libs' issue I think).
You could check with 'kinit -k' if added entry works.

--

Best regards,

-------------------------
Igor Mammedov,
niallain "at" gmail.com





--------------020808090104020706010006
Content-Type: text/x-patch;
name="0001-Fix-cifs-upcall-key-name-for-DNS-resolving.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="0001-Fix-cifs-upcall-key-name-for-DNS-resolving.patch"

>From fbc1e88fbb09623dd9ab5c957582e5af50fa4e1b Mon Sep 17 00:00:00 2001

From: Igor Mammedov
Date: Wed, 2 Apr 2008 17:21:12 +0400
Subject: [PATCH] Fix cifs upcall key name for DNS resolving

Signed-off-by: Igor Mammedov
---
source/client/cifs.spnego.c | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/source/client/cifs.spnego.c b/source/client/cifs.spnego.c
index d10d19d..ece0ad7 100644
--- a/source/client/cifs.spnego.c
+++ b/source/client/cifs.spnego.c
@@ -9,7 +9,7 @@
* /etc/request-key.conf file

create cifs.spnego * * /usr/local/sbin/cifs.spnego [-v][-c] %k
-create cifs.resolver * * /usr/local/sbin/cifs.spnego [-v] %k
+create dns_resolver * * /usr/local/sbin/cifs.spnego [-v] %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
@@ -36,6 +36,8 @@ typedef enum _secType {
MS_KRB5
} secType_t;

+const char *CIFSDNSRESOLVER_KEYTYPE = "dns_resolver";
+
/*
* Prepares AP-REQ data for mechToken and gets session key
* Uses credentials from cache. It will not ask for password
@@ -253,7 +255,7 @@ int main(const int argc, char *const argv[])
goto out;
}

- if (strncmp(buf, "cifs.resolver", sizeof("cifs.resolver")-1) == 0) {
+ if (strncmp(buf, CIFSDNSRESOLVER_KEYTYPE, sizeof(CIFSDNSRESOLVER_KEYTYPE)-1) == 0) {
rc = cifs_resolver(key, buf);
goto out;
}
--
1.5.3.7


--------------020808090104020706010006
Content-Type: text/x-patch;
name="0002-Adds-support-for-using-krb5.keytab-for-non-interacti.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename*0="0002-Adds-support-for-using-krb5.keytab-for-non-interacti.pa";
filename*1="tch"

>From 811c97e00c336d23239033929a098ed543a47963 Mon Sep 17 00:00:00 2001

From: Igor Mammedov
Date: Wed, 2 Apr 2008 17:23:43 +0400
Subject: [PATCH] Adds support for using krb5.keytab for non interactive cifs mount

Signed-off-by: Igor Mammedov
---
source/client/cifs.spnego.c | 175 +++++++++++++++++++++++++++++++++++--------
1 files changed, 143 insertions(+), 32 deletions(-)

diff --git a/source/client/cifs.spnego.c b/source/client/cifs.spnego.c
index ece0ad7..58be941 100644
--- a/source/client/cifs.spnego.c
+++ b/source/client/cifs.spnego.c
@@ -29,7 +29,7 @@ create dns_resolver * * /usr/local/sbin/cifs.spnego [-v] %k

#include "cifs_spnego.h"

-const char *CIFSSPNEGO_VERSION = "1.1";
+const char *CIFSSPNEGO_VERSION = "1.2";
static const char *prog = "cifs.spnego";
typedef enum _secType {
KRB5,
@@ -59,7 +59,7 @@ const char *CIFSDNSRESOLVER_KEYTYPE = "dns_resolver";
* ret: 0 - success, others - failure
*/
int handle_krb5_mech(const char *oid, const char *principal,
- DATA_BLOB * secblob, DATA_BLOB * sess_key)
+ DATA_BLOB *secblob, DATA_BLOB *sess_key)
{
int retval;
DATA_BLOB tkt, tkt_wrapped;
@@ -82,16 +82,45 @@ int handle_krb5_mech(const char *oid, const char *principal,
return retval;
}

+static char *keyd_copy_param(const char *start, const char *end)
+{
+ int len;
+ char *buf;
+
+ if (end == NULL)
+ len = strlen(start);
+ else
+ len = end - start;
+
+ len += 1;
+ buf = SMB_XMALLOC_ARRAY(char, len);
+ strlcpy(buf, start, len);
+ return buf;
+}
+
#define DKD_HAVE_HOSTNAME 1
#define DKD_HAVE_VERSION 2
#define DKD_HAVE_SEC 4
#define DKD_HAVE_IPV4 8
#define DKD_HAVE_IPV6 16
#define DKD_HAVE_UID 32
+#define DKD_HAVE_KEYTAB 64
+#define DKD_HAVE_USERNAME 128
#define DKD_MUSTHAVE_SET (DKD_HAVE_HOSTNAME|DKD_HAVE_VERSION|DKD_HAVE_SEC)

-int decode_key_description(const char *desc, int *ver, secType_t * sec,
- char **hostname, uid_t * uid)
+/* decode_key_description - parse key description from the cifs spnego upcall
+ * in:
+ * desc - key description from keyctl_describe_alloc
+ * out:
+ * ver - upcall version
+ * sec - type of kerberos mech
+ * uid - UID of user who mounted the share
+ * keytab - name of keytab file
+ * user - principal of the user to authenticate as
+ */
+int decode_key_description(const char *desc, int *ver, secType_t *sec,
+ char **hostname, uid_t *uid,
+ char **keytab, char **user)
{
int retval = 0;
char *pos;
@@ -100,17 +129,7 @@ int decode_key_description(const char *desc, int *ver, secType_t * sec,
do {
pos = index(tkn, ';');
if (strncmp(tkn, "host=", 5) == 0) {
- int len;
-
- if (pos == NULL) {
- len = strlen(tkn);
- } else {
- len = pos - tkn;
- }
- len -= 4;
- SAFE_FREE(*hostname);
- *hostname = SMB_XMALLOC_ARRAY(char, len);
- strlcpy(*hostname, tkn + 5, len);
+ *hostname = keyd_copy_param(tkn+5, pos);
retval |= DKD_HAVE_HOSTNAME;
} else if (strncmp(tkn, "ipv4=", 5) == 0) {
/* BB: do we need it if we have hostname already? */
@@ -142,6 +161,12 @@ int decode_key_description(const char *desc, int *ver, secType_t * sec,
} else {
retval |= DKD_HAVE_VERSION;
}
+ } else if (strncmp(tkn, "cred=", 5) == 0) {
+ *keytab = keyd_copy_param(tkn+5, pos);
+ retval |= DKD_HAVE_KEYTAB;
+ } else if (strncmp(tkn, "user=", 5) == 0) {
+ *user = keyd_copy_param(tkn+5, pos);
+ retval |= DKD_HAVE_USERNAME;
}
if (pos == NULL)
break;
@@ -177,14 +202,14 @@ int cifs_resolver(const key_serial_t key, const char *key_descr)
}

/* conver ip to string form */
- if (addr->ai_family == AF_INET) {
+ if (addr->ai_family == AF_INET)
p = &(((struct sockaddr_in *)addr->ai_addr)->sin_addr);
- } else {
+ else
p = &(((struct sockaddr_in6 *)addr->ai_addr)->sin6_addr);
- }
+
if (!inet_ntop(addr->ai_family, p, ip, sizeof(ip))) {
syslog(LOG_WARNING, "%s: inet_ntop: %s",
- __FUNCTION__, strerror(errno));
+ __func__, strerror(errno));
freeaddrinfo(addr);
return 1;
}
@@ -193,7 +218,7 @@ int cifs_resolver(const key_serial_t key, const char *key_descr)
c = keyctl_instantiate(key, ip, strlen(ip)+1, 0);
if (c == -1) {
syslog(LOG_WARNING, "%s: keyctl_instantiate: %s",
- __FUNCTION__, strerror(errno));
+ __func__, strerror(errno));
freeaddrinfo(addr);
return 1;
}
@@ -202,6 +227,80 @@ int cifs_resolver(const key_serial_t key, const char *key_descr)
return 0;
}

+static int init_cc_from_keytab(const char *keytab_name, const char *user)
+{
+ krb5_context context = NULL;
+ krb5_error_code ret;
+ krb5_creds my_creds;
+ krb5_keytab keytab = NULL;
+ krb5_principal me = NULL;
+ krb5_ccache cc = NULL;
+
+ memset((char *) &my_creds, 0, sizeof(my_creds));
+
+ ret = krb5_init_context(&context);
+ if (ret) {
+ syslog(LOG_WARNING, "krb5_init_context: %s",
+ error_message(ret));
+ goto icfk_cleanup;
+ }
+
+ ret = smb_krb5_open_keytab(context, keytab_name, False, &keytab);
+ if (ret) {
+ syslog(LOG_WARNING, "smb_krb5_open_keytab: %s",
+ error_message(ret));
+ goto icfk_cleanup;
+ }
+
+ ret = krb5_parse_name(context, user, &me);
+ if (ret) {
+ syslog(LOG_WARNING, "krb5_parse_name: %s", error_message(ret));
+ goto icfk_cleanup;
+ }
+
+ ret = krb5_get_init_creds_keytab(context, &my_creds, me,
+ keytab, 0, NULL, NULL);
+ if (ret) {
+ syslog(LOG_WARNING, "krb5_get_init_creds_keytab: %s",
+ error_message(ret));
+ goto icfk_cleanup;
+ }
+
+ ret = krb5_cc_default(context, &cc);
+ if (ret) {
+ syslog(LOG_WARNING, "krb5_cc_default: %s", error_message(ret));
+ goto icfk_cleanup;
+ }
+
+ ret = krb5_cc_initialize(context, cc, me);
+ if (ret) {
+ syslog(LOG_WARNING, "krb5_cc_initialize: %s",
+ error_message(ret));
+ goto icfk_cleanup;
+ }
+
+ ret = krb5_cc_store_cred(context, cc, &my_creds);
+ if (ret) {
+ syslog(LOG_WARNING, "krb5_cc_store_cred: %s",
+ error_message(ret));
+ }
+
+icfk_cleanup:
+ my_creds.client = 0;
+ krb5_free_cred_contents(context, &my_creds);
+
+ if (me)
+ krb5_free_principal(context, me);
+ if (cc)
+ krb5_cc_close(context, cc);
+ if (keytab)
+ krb5_kt_close(context, keytab);
+ if (context)
+ krb5_free_context(context);
+ return 0;
+}
+
+
int main(const int argc, char *const argv[])
{
struct cifs_spnego_msg *keydata = NULL;
@@ -215,6 +314,7 @@ int main(const int argc, char *const argv[])
int kernel_upcall_version;
int c, use_cifs_service_prefix = 0;
char *buf, *hostname = NULL;
+ char *keytab, *user = NULL;

openlog(prog, 0, LOG_DAEMON);
if (argc < 1) {
@@ -230,7 +330,8 @@ int main(const int argc, char *const argv[])
}
case 'v':{
syslog(LOG_WARNING, "version: %s", CIFSSPNEGO_VERSION);
- fprintf(stderr, "version: %s", CIFSSPNEGO_VERSION);
+ fprintf(stderr, "version: %s\n", CIFSSPNEGO_VERSION);
+ return 0;
break;
}
default:{
@@ -255,13 +356,14 @@ int main(const int argc, char *const argv[])
goto out;
}

- if (strncmp(buf, CIFSDNSRESOLVER_KEYTYPE, sizeof(CIFSDNSRESOLVER_KEYTYPE)-1) == 0) {
+ if (strncmp(buf, CIFSDNSRESOLVER_KEYTYPE,
+ sizeof(CIFSDNSRESOLVER_KEYTYPE)-1) == 0) {
rc = cifs_resolver(key, buf);
goto out;
}

rc = decode_key_description(buf, &kernel_upcall_version, &sectype,
- &hostname, &uid);
+ &hostname, &uid, &keytab, &user);
if ((rc & DKD_MUSTHAVE_SET) != DKD_MUSTHAVE_SET) {
syslog(LOG_WARNING,
"unable to get from description necessary params");
@@ -290,11 +392,12 @@ int main(const int argc, char *const argv[])
/* BB: someday upcall SPNEGO blob could be checked here to decide
* what mech to use */

- // do mech specific authorization
+ /* do mech specific authorization */
switch (sectype) {
case KRB5:{
char *princ;
size_t len;
+ int keytab_done = 0;

/* for "cifs/" service name + terminating 0 */
len = strlen(hostname) + 5 + 1;
@@ -303,15 +406,20 @@ int main(const int argc, char *const argv[])
rc = 1;
break;
}
- if (use_cifs_service_prefix) {
+ if (use_cifs_service_prefix)
strlcpy(princ, "cifs/", len);
- } else {
+ else
strlcpy(princ, "host/", len);
- }
- strlcpy(princ + 5, hostname, len - 5);

+ strlcpy(princ + 5, hostname, len - 5);
+TRY_KRB5_AGAIN:
rc = handle_krb5_mech(OID_KERBEROS5, princ,
&secblob, &sess_key);
+ if (rc && user && !keytab_done) {
+ init_cc_from_keytab(keytab, user);
+ keytab_done = 1;
+ goto TRY_KRB5_AGAIN;
+ }
SAFE_FREE(princ);
break;
}
@@ -323,14 +431,14 @@ int main(const int argc, char *const argv[])
}
}

- if (rc) {
+ if (rc)
goto out;
- }
+

/* pack SecurityBLob and SessionKey into downcall packet */
datalen =
sizeof(struct cifs_spnego_msg) + secblob.length + sess_key.length;
- keydata = (struct cifs_spnego_msg*)SMB_XMALLOC_ARRAY(char, datalen);
+ keydata = (struct cifs_spnego_msg *)SMB_XMALLOC_ARRAY(char, datalen);
if (!keydata) {
rc = 1;
goto out;
@@ -353,10 +461,13 @@ int main(const int argc, char *const argv[])
/* BB: maybe we need use timeout for key: for example no more then
* ticket lifietime? */
/* keyctl_set_timeout( key, 60); */
- out:
+out:
data_blob_free(&secblob);
data_blob_free(&sess_key);
SAFE_FREE(hostname);
+ SAFE_FREE(keytab);
+ SAFE_FREE(user);
SAFE_FREE(keydata);
+ closelog();
return rc;
}
--
1.5.3.7


--------------020808090104020706010006--