Implement credential handling
authorSimo Sorce <idra@samba.org>
Tue, 9 Jul 2013 03:27:39 +0000 (23:27 -0400)
committerSimo Sorce <simo@redhat.com>
Fri, 19 Jul 2013 02:37:25 +0000 (22:37 -0400)
Makefile.am
src/gss_creds.c [new file with mode: 0644]
src/gss_ntlmssp.c
src/gss_spi.c
src/ntlm.c
src/ntlm.h
src/ntlm_crypto.c

index b66c61afd9056db27f959c03259f778e1990f536..4b5554dda909f14860c522e6713821ad2f4c4ec2 100644 (file)
@@ -73,6 +73,7 @@ GN_MECHGLUE_OBJ = \
     src/ntlm_crypto.c \
     src/ntlm.c \
     src/gss_spi.c \
+    src/gss_creds.c \
     src/gss_sec_ctx.c \
     src/gss_ntlmssp.c
 
diff --git a/src/gss_creds.c b/src/gss_creds.c
new file mode 100644 (file)
index 0000000..b16f9ca
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+   Copyright (C) 2013 Simo Sorce <simo@samba.org>
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 3 of the License, or (at your option) any later version.
+
+   This library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_ext.h>
+
+#include "gss_ntlmssp.h"
+
+
+static int get_initial_creds(struct gssntlm_name *name,
+                             struct gssntlm_cred **creds)
+{
+    struct gssntlm_cred *cred = NULL;
+    const char *envvar;
+    char line[1024];
+    char *dom, *usr, *pwd;
+    char *p;
+    bool found = false;
+    FILE *f;
+    int ret;
+
+    /* use the same var used by Heimdal */
+    envvar = getenv("NTLM_USER_FILE");
+    if (envvar != NULL) {
+        /* Use the same file format used by Heimdal in hope to achieve
+         * some compatibility between implementations:
+         * Each line is one entry like the following:
+         * DOMAIN:USERNAME:PASSWORD */
+        f = fopen(envvar, "r");
+        if (!f) return errno;
+
+        while(fgets(line, 1024, f)) {
+            p = line;
+            if (*p == '#') continue;
+            dom = p;
+            p = strchr(dom, ':');
+            if (!p) continue;
+            *p++ = '\0';
+            usr = p;
+            p = strchr(usr, ':');
+            if (!p) continue;
+            *p++ = '\0';
+            pwd = p;
+            strsep(&p, "\r\n");
+
+            /* if no name is specified user the first found */
+            if (name == NULL) {
+                found = true;
+                break;
+            }
+
+            if (name->data.user.domain) {
+                if (!ntlm_casecmp(dom, name->data.user.domain)) continue;
+            }
+            if (name->data.user.name) {
+                if (!ntlm_casecmp(usr, name->data.user.name)) continue;
+            }
+            /* all matched (NULLs in name are wildcards) */
+            found = true;
+            break;
+        }
+
+        fclose(f);
+
+        if (found) {
+            cred = calloc(1, sizeof(struct gssntlm_cred));
+            if (!cred) return errno;
+
+            cred->type = GSSNTLM_CRED_USER;
+            cred->cred.user.user.type = GSSNTLM_NAME_USER;
+            cred->cred.user.user.data.user.domain = strdup(dom);
+            if (!cred->cred.user.user.data.user.domain) {
+                ret = ENOMEM;
+                goto done;
+            }
+            cred->cred.user.user.data.user.name = strdup(usr);
+            if (!cred->cred.user.user.data.user.name) {
+                ret = ENOMEM;
+                goto done;
+            }
+            cred->cred.user.nt_hash.length = 16;
+            ret = ntlm_pwd_to_nt_hash(pwd, &cred->cred.user.nt_hash);
+
+            goto done;
+        }
+    }
+
+    ret = ENOENT;
+
+done:
+    if (ret) {
+        gssntlm_int_release_cred(cred);
+    } else {
+        *creds = cred;
+    }
+    return ret;
+}
+
+static void gssntlm_copy_key(struct ntlm_key *dest, struct ntlm_key *src)
+{
+    memcpy(dest->data, src->data, src->length);
+    dest->length = src->length;
+}
+
+int gssntlm_copy_creds(struct gssntlm_cred *in, struct gssntlm_cred *out)
+{
+    char *dom = NULL, *usr = NULL;
+    int ret = 0;
+
+    out->type = GSSNTLM_CRED_NONE;
+
+    switch (in->type) {
+    case GSSNTLM_CRED_NONE:
+        break;
+    case GSSNTLM_CRED_ANON:
+        out->cred.anon.dummy = 1;
+        break;
+    case GSSNTLM_CRED_USER:
+        dom = strdup(in->cred.user.user.data.user.domain);
+        if (!dom) {
+            ret = ENOMEM;
+            goto done;
+        }
+        usr = strdup(in->cred.user.user.data.user.name);
+        if (!usr) {
+            ret = ENOMEM;
+            goto done;
+        }
+        out->cred.user.user.data.user.domain = dom;
+        out->cred.user.user.data.user.name = usr;
+        gssntlm_copy_key(&out->cred.user.nt_hash,
+                         &in->cred.user.nt_hash);
+        gssntlm_copy_key(&out->cred.user.lm_hash,
+                         &in->cred.user.lm_hash);
+        break;
+    case GSSNTLM_CRED_SERVER:
+        out->cred.server.dummy = 1;
+        break;
+    }
+    out->type = in->type;
+
+    out->lm_compatibility_level = in->lm_compatibility_level;
+
+done:
+    if (ret) {
+        safefree(dom);
+        safefree(usr);
+    }
+    return ret;
+}
+
+void gssntlm_int_release_cred(struct gssntlm_cred *cred)
+{
+    if (!cred) return;
+
+    switch (cred->type) {
+    case GSSNTLM_CRED_NONE:
+        break;
+    case GSSNTLM_CRED_ANON:
+        cred->cred.anon.dummy = 0;
+        break;
+    case GSSNTLM_CRED_USER:
+        safefree(cred->cred.user.user.data.user.domain);
+        safefree(cred->cred.user.user.data.user.name);
+        safezero(cred->cred.user.nt_hash.data, 16);
+        cred->cred.user.nt_hash.length = 0;
+        safezero(cred->cred.user.lm_hash.data, 16);
+        cred->cred.user.lm_hash.length = 0;
+        break;
+    case GSSNTLM_CRED_SERVER:
+        cred->cred.server.dummy = 0;
+        break;
+    }
+}
+
+uint32_t gssntlm_acquire_cred(uint32_t *minor_status,
+                              gss_name_t desired_name,
+                              uint32_t time_req,
+                              gss_OID_set desired_mechs,
+                              gss_cred_usage_t cred_usage,
+                              gss_cred_id_t *output_cred_handle,
+                              gss_OID_set *actual_mechs,
+                              uint32_t *time_rec)
+{
+    struct gssntlm_cred *cred;
+    struct gssntlm_name *name;
+    uint32_t retmaj = GSS_S_COMPLETE;
+    uint32_t retmin = 0;
+
+    name = (struct gssntlm_name *)desired_name;
+
+    if (cred_usage == GSS_C_BOTH || cred_usage == GSS_C_INITIATE) {
+        if (name != NULL && name->type != GSSNTLM_NAME_USER) {
+            retmin = EINVAL;
+            retmaj = GSS_S_CRED_UNAVAIL;
+            goto done;
+        }
+
+        retmin = get_initial_creds(name, &cred);
+        if (retmin) {
+            retmaj = GSS_S_CRED_UNAVAIL;
+        }
+    } else {
+        retmin = EINVAL;
+        retmaj = GSS_S_CRED_UNAVAIL;
+    }
+
+done:
+    if (retmaj) {
+        uint32_t tmpmin;
+        gssntlm_release_cred(&tmpmin, (gss_cred_id_t *)&cred);
+    } else {
+        *output_cred_handle = (gss_cred_id_t)cred;
+    }
+    *minor_status = retmin;
+    return retmaj;
+}
+
+uint32_t gssntlm_release_cred(uint32_t *minor_status,
+                              gss_cred_id_t *cred_handle)
+{
+    *minor_status = 0;
+
+    if (!cred_handle) return GSS_S_COMPLETE;
+
+    gssntlm_int_release_cred((struct gssntlm_cred *)*cred_handle);
+    safefree(*cred_handle);
+
+    return GSS_S_COMPLETE;
+}
+
index d9ebe8077b70bd9e56a29036aa9c6690e0853dbf..a2d2e18cf8f1ca3b1df454bb1a61cb88d76fbdc0 100644 (file)
@@ -66,95 +66,3 @@ uint8_t gssntlm_required_security(int security_level,
 
     return resp;
 }
-
-int gssntlm_copy_creds(struct gssntlm_cred *in, struct gssntlm_cred *out)
-{
-    char *dom = NULL, *usr = NULL;
-    int ret = 0;
-
-    out->type = GSSNTLM_CRED_NONE;
-
-    switch (in->type) {
-    case GSSNTLM_CRED_NONE:
-        break;
-    case GSSNTLM_CRED_ANON:
-        out->cred.anon.dummy = 1;
-        break;
-    case GSSNTLM_CRED_USER:
-        dom = strdup(in->cred.user.user.data.user.domain);
-        if (!dom) {
-            ret = ENOMEM;
-            goto done;
-        }
-        usr = strdup(in->cred.user.user.data.user.name);
-        if (!usr) {
-            ret = ENOMEM;
-            goto done;
-        }
-        out->cred.user.user.data.user.domain = dom;
-        out->cred.user.user.data.user.name = usr;
-        break;
-    case GSSNTLM_CRED_SERVER:
-        out->cred.server.dummy = 1;
-        break;
-    }
-
-    out->type = in->type;
-
-done:
-    if (ret) {
-        safefree(dom);
-        safefree(usr);
-    }
-    return ret;
-}
-
-void gssntlm_int_release_cred(struct gssntlm_cred *cred)
-{
-    switch (cred->type) {
-    case GSSNTLM_CRED_NONE:
-        break;
-    case GSSNTLM_CRED_ANON:
-        cred->cred.anon.dummy = 0;
-        break;
-    case GSSNTLM_CRED_USER:
-        safefree(cred->cred.user.user.data.user.domain);
-        safefree(cred->cred.user.user.data.user.name);
-        safezero(cred->cred.user.nt_hash.data, 16);
-        cred->cred.user.nt_hash.length = 0;
-        safezero(cred->cred.user.lm_hash.data, 16);
-        cred->cred.user.lm_hash.length = 0;
-        break;
-    case GSSNTLM_CRED_SERVER:
-        cred->cred.server.dummy = 0;
-        break;
-    }
-}
-
-uint32_t gssntlm_acquire_cred(uint32_t *minor_status,
-                              gss_name_t desired_name,
-                              uint32_t time_req,
-                              gss_OID_set desired_mechs,
-                              gss_cred_usage_t cred_usage,
-                              gss_cred_id_t *output_cred_handle,
-                              gss_OID_set *actual_mechs,
-                              uint32_t *time_rec)
-{
-    /* FIXME: Fecth creds from somewhere */
-    *minor_status = 0;
-    return GSS_S_CRED_UNAVAIL;
-}
-
-uint32_t gssntlm_release_cred(uint32_t *minor_status,
-                              gss_cred_id_t *cred_handle)
-{
-    *minor_status = 0;
-
-    if (!cred_handle) return GSS_S_COMPLETE;
-
-    gssntlm_int_release_cred((struct gssntlm_cred *)*cred_handle);
-    safefree(*cred_handle);
-
-    return GSS_S_COMPLETE;
-}
-
index 46fd1763556eaf8ce29f23c4015352266f2f0869..920dfe6a769f93db223c8d4fdb791fee5df1a551 100644 (file)
@@ -56,3 +56,28 @@ OM_uint32 gss_delete_sec_context(OM_uint32 *minor_status,
                                       context_handle,
                                       output_token);
 }
+
+OM_uint32 gss_acquire_cred(OM_uint32 *minor_status,
+                           gss_name_t desired_name,
+                           OM_uint32 time_req,
+                           gss_OID_set desired_mechs,
+                           gss_cred_usage_t cred_usage,
+                           gss_cred_id_t *output_cred_handle,
+                           gss_OID_set *actual_mechs,
+                           OM_uint32 *time_rec)
+{
+    return gssntlm_acquire_cred(minor_status,
+                                desired_name,
+                                time_req,
+                                desired_mechs,
+                                cred_usage,
+                                output_cred_handle,
+                                actual_mechs,
+                                time_rec);
+}
+
+OM_uint32 gss_release_cred(OM_uint32 *minor_status,
+                           gss_cred_id_t *cred_handle)
+{
+    return gssntlm_release_cred(minor_status, cred_handle);
+}
index 97771bcd2e62aad7ed84f4e694dabe7b0e60b17e..9041a71c9805fc99a3b7261caee26777c7e3d75d 100644 (file)
@@ -31,6 +31,8 @@
 #include <string.h>
 #include <sys/time.h>
 
+#include <unicase.h>
+
 #include "ntlm.h"
 
 #pragma pack(push, 1)
@@ -247,6 +249,24 @@ uint64_t ntlm_timestamp_now(void)
     return filetime;
 }
 
+bool ntlm_casecmp(const char *s1, const char *s2)
+{
+    size_t s1_len, s2_len;
+    int ret, res;
+
+    if (s1 == s2) return true;
+    if (!s1 || !s2) return false;
+
+    s1_len = strlen(s1);
+    s2_len = strlen(s2);
+
+    ret = ulc_casecmp(s1, s1_len, s2, s2_len,
+                      uc_locale_language(), NULL, &res);
+    if (ret || res != 0) return false;
+    return true;
+}
+
+
 /**
  * @brief  Converts a string using the provided iconv context.
  *         This function is ok only to convert utf8<->ucs2
index 88fdc4109414d64e24d22093c62a22812a75532a..0acdbfc43734d468c8067ff9572c35405822e961 100644 (file)
@@ -95,6 +95,7 @@ void ntlm_free_buffer_data(struct ntlm_buffer *buf);
 
 uint64_t ntlm_timestamp_now(void);
 
+bool ntlm_casecmp(const char *s1, const char *s2);
 
 /* ############### CRYPTO FUNCTIONS ################ */
 
index 52e195a36ef39fbb8f7e5fe31dd577751018e8ea..c94ea7962da9cf995d6db663f5c4a6c379bff245 100644 (file)
@@ -99,7 +99,7 @@ int ntlm_pwd_to_nt_hash(const char *password, struct ntlm_key *result)
     payload.data = (uint8_t *)retstr;
     payload.length = out;
     hash.data = result->data;
-    hash.length= result->length;
+    hash.length = result->length;
 
     ret = MD4_HASH(&payload, &hash);
     free(retstr);