cifs.upcall: bump SPNEGO msg version number and don't reject old versions
[ira/wip.git] / source / client / cifs.upcall.c
index 5a2a22a73cac02e66b20ea57d7f1491104c58ebb..7cb51660d7ea0a5f3978c17a789626697d2ab8bc 100644 (file)
@@ -29,7 +29,7 @@ create dns_resolver * * /usr/local/sbin/cifs.upcall %k
 
 #include "cifs_spnego.h"
 
-const char *CIFSSPNEGO_VERSION = "1.1";
+const char *CIFSSPNEGO_VERSION = "1.2";
 static const char *prog = "cifs.upcall";
 typedef enum _secType {
        KRB5,
@@ -73,7 +73,7 @@ int handle_krb5_mech(const char *oid, const char *principal,
        tkt_wrapped = spnego_gen_krb5_wrap(tkt, TOK_ID_KRB_AP_REQ);
 
        /* and wrap that in a shiny SPNEGO wrapper */
-       *secblob = gen_negTokenInit(OID_KERBEROS5, tkt_wrapped);
+       *secblob = gen_negTokenInit(oid, tkt_wrapped);
 
        data_blob_free(&tkt_wrapped);
        data_blob_free(&tkt);
@@ -118,6 +118,9 @@ int decode_key_description(const char *desc, int *ver, secType_t * sec,
                        if (strncmp(tkn + 4, "krb5", 4) == 0) {
                                retval |= DKD_HAVE_SEC;
                                *sec = KRB5;
+                       } else if (strncmp(tkn + 4, "mskrb5", 6) == 0) {
+                               retval |= DKD_HAVE_SEC;
+                               *sec = MS_KRB5;
                        }
                } else if (strncmp(tkn, "uid=", 4) == 0) {
                        errno = 0;
@@ -213,13 +216,14 @@ int main(const int argc, char *const argv[])
        DATA_BLOB secblob = data_blob_null;
        DATA_BLOB sess_key = data_blob_null;
        secType_t sectype;
-       key_serial_t key;
+       key_serial_t key = 0;
        size_t datalen;
        long rc = 1;
        uid_t uid;
        int kernel_upcall_version;
        int c, use_cifs_service_prefix = 0;
        char *buf, *hostname = NULL;
+       const char *oid;
 
        openlog(prog, 0, LOG_DAEMON);
 
@@ -250,6 +254,7 @@ int main(const int argc, char *const argv[])
        errno = 0;
        key = strtol(argv[optind], NULL, 10);
        if (errno != 0) {
+               key = 0;
                syslog(LOG_WARNING, "Invalid key format: %s", strerror(errno));
                goto out;
        }
@@ -279,7 +284,7 @@ int main(const int argc, char *const argv[])
        }
        SAFE_FREE(buf);
 
-       if (kernel_upcall_version != CIFS_SPNEGO_UPCALL_VERSION) {
+       if (kernel_upcall_version > CIFS_SPNEGO_UPCALL_VERSION) {
                syslog(LOG_WARNING,
                       "incompatible kernel upcall version: 0x%x",
                       kernel_upcall_version);
@@ -300,6 +305,7 @@ int main(const int argc, char *const argv[])
 
        // do mech specific authorization
        switch (sectype) {
+       case MS_KRB5:
        case KRB5:{
                        char *princ;
                        size_t len;
@@ -318,8 +324,12 @@ int main(const int argc, char *const argv[])
                        }
                        strlcpy(princ + 5, hostname, len - 5);
 
-                       rc = handle_krb5_mech(OID_KERBEROS5, princ,
-                                             &secblob, &sess_key);
+                       if (sectype == MS_KRB5)
+                               oid = OID_KERBEROS5_OLD;
+                       else
+                               oid = OID_KERBEROS5;
+
+                       rc = handle_krb5_mech(oid, princ, &secblob, &sess_key);
                        SAFE_FREE(princ);
                        break;
                }
@@ -343,7 +353,7 @@ int main(const int argc, char *const argv[])
                rc = 1;
                goto out;
        }
-       keydata->version = CIFS_SPNEGO_UPCALL_VERSION;
+       keydata->version = kernel_upcall_version;
        keydata->flags = 0;
        keydata->sesskey_len = sess_key.length;
        keydata->secblob_len = secblob.length;
@@ -361,7 +371,14 @@ 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:
+       /*
+        * 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);
        data_blob_free(&secblob);
        data_blob_free(&sess_key);
        SAFE_FREE(hostname);