Fix spelling mistakes
[bbaumbach/samba-autobuild/.git] / source3 / winbindd / winbindd_ccache_access.c
index 6a265ccaf07c5503b0c84618fb09d64190967c9d..a73f9362245f36e49ebea8baee68f1624008ddd4 100644 (file)
@@ -6,6 +6,7 @@
    Copyright (C) Robert O'Callahan 2006
    Copyright (C) Jeremy Allison 2006 (minor fixes to fit into Samba and
                                      protect against integer wrap).
+   Copyright (C) Andrew Bartlett 2011
 
    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
@@ -23,7 +24,8 @@
 
 #include "includes.h"
 #include "winbindd.h"
-#include "../libcli/auth/ntlmssp.h"
+#include "auth/gensec/gensec.h"
+#include "auth_generic.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
@@ -41,24 +43,22 @@ static bool client_can_access_ccache_entry(uid_t client_uid,
        return False;
 }
 
-static NTSTATUS do_ntlm_auth_with_hashes(const char *username,
-                                       const char *domain,
-                                       const unsigned char lm_hash[LM_HASH_LEN],
-                                       const unsigned char nt_hash[NT_HASH_LEN],
-                                       const DATA_BLOB initial_msg,
-                                       const DATA_BLOB challenge_msg,
-                                       DATA_BLOB *auth_msg,
-                                       uint8_t session_key[16])
+static NTSTATUS do_ntlm_auth_with_stored_pw(const char *namespace,
+                                           const char *domain,
+                                           const char *username,
+                                           const char *password,
+                                           const DATA_BLOB initial_msg,
+                                           const DATA_BLOB challenge_msg,
+                                           TALLOC_CTX *mem_ctx,
+                                           DATA_BLOB *auth_msg,
+                                           uint8_t session_key[16],
+                                           uint8_t *new_spnego)
 {
        NTSTATUS status;
-       struct ntlmssp_state *ntlmssp_state = NULL;
-       DATA_BLOB dummy_msg, reply;
+       struct auth_generic_state *auth_generic_state = NULL;
+       DATA_BLOB reply, session_key_blob;
 
-       status = ntlmssp_client_start(NULL,
-                                     global_myname(),
-                                     lp_workgroup(),
-                                     lp_client_ntlmv2_auth(),
-                                     &ntlmssp_state);
+       status = auth_generic_client_prepare(mem_ctx, &auth_generic_state);
 
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1, ("Could not start NTLMSSP client: %s\n",
@@ -66,7 +66,7 @@ static NTSTATUS do_ntlm_auth_with_hashes(const char *username,
                goto done;
        }
 
-       status = ntlmssp_set_username(ntlmssp_state, username);
+       status = auth_generic_set_username(auth_generic_state, username);
 
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1, ("Could not set username: %s\n",
@@ -74,7 +74,7 @@ static NTSTATUS do_ntlm_auth_with_hashes(const char *username,
                goto done;
        }
 
-       status = ntlmssp_set_domain(ntlmssp_state, domain);
+       status = auth_generic_set_domain(auth_generic_state, domain);
 
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1, ("Could not set domain: %s\n",
@@ -82,30 +82,34 @@ static NTSTATUS do_ntlm_auth_with_hashes(const char *username,
                goto done;
        }
 
-       status = ntlmssp_set_hashes(ntlmssp_state, lm_hash, nt_hash);
+       status = auth_generic_set_password(auth_generic_state, password);
 
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("Could not set hashes: %s\n",
+               DEBUG(1, ("Could not set password: %s\n",
                        nt_errstr(status)));
                goto done;
        }
 
-       ntlmssp_want_feature(ntlmssp_state, NTLMSSP_FEATURE_SESSION_KEY);
-
-       /* We need to get our protocol handler into the right state. So first
-          we ask it to generate the initial message. Actually the client has already
-          sent its own initial message, so we're going to drop this one on the floor.
-          The client might have sent a different message, for example with different
-          negotiation options, but as far as I can tell this won't hurt us. (Unless
-          the client sent a different username or domain, in which case that's their
-          problem for telling us the wrong username or domain.)
-          Since we have a copy of the initial message that the client sent, we could
-          resolve any discrepancies if we had to.
-       */
-       dummy_msg = data_blob_null;
+       if (initial_msg.length == 0) {
+               gensec_want_feature(auth_generic_state->gensec_security,
+                                   GENSEC_FEATURE_SESSION_KEY);
+       }
+
+       status = auth_generic_client_start_by_name(auth_generic_state,
+                                                  "ntlmssp_resume_ccache");
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("Could not start NTLMSSP resume mech: %s\n",
+                       nt_errstr(status)));
+               goto done;
+       }
+
+       /*
+        * We inject the initial NEGOTIATE message our caller used
+        * in order to get the state machine into the correct position.
+        */
        reply = data_blob_null;
-       status = ntlmssp_update(ntlmssp_state, dummy_msg, &reply);
-       data_blob_free(&dummy_msg);
+       status = gensec_update(auth_generic_state->gensec_security,
+                              talloc_tos(), initial_msg, &reply);
        data_blob_free(&reply);
 
        if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
@@ -115,8 +119,8 @@ static NTSTATUS do_ntlm_auth_with_hashes(const char *username,
        }
 
        /* Now we are ready to handle the server's actual response. */
-       status = ntlmssp_update(ntlmssp_state, challenge_msg, &reply);
-
+       status = gensec_update(auth_generic_state->gensec_security,
+                              mem_ctx, challenge_msg, &reply);
        if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
                DEBUG(1, ("We didn't get a response to the challenge! [%s]\n",
                        nt_errstr(status)));
@@ -124,19 +128,30 @@ static NTSTATUS do_ntlm_auth_with_hashes(const char *username,
                goto done;
        }
 
-       if (ntlmssp_state->session_key.length != 16) {
-               DEBUG(1, ("invalid session key length %d\n",
-                         (int)ntlmssp_state->session_key.length));
+       status = gensec_session_key(auth_generic_state->gensec_security,
+                                   talloc_tos(), &session_key_blob);
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
+               DEBUG(1, ("We didn't get the session key we requested! [%s]\n",
+                       nt_errstr(status)));
                data_blob_free(&reply);
                goto done;
        }
 
-       *auth_msg = data_blob(reply.data, reply.length);
-       memcpy(session_key, ntlmssp_state->session_key.data, 16);
+       if (session_key_blob.length != 16) {
+               DEBUG(1, ("invalid session key length %d\n",
+                         (int)session_key_blob.length));
+               data_blob_free(&reply);
+               goto done;
+       }
+       memcpy(session_key, session_key_blob.data, 16);
+       data_blob_free(&session_key_blob);
+       *auth_msg = reply;
+       *new_spnego = gensec_have_feature(auth_generic_state->gensec_security,
+                                         GENSEC_FEATURE_NEW_SPNEGO);
        status = NT_STATUS_OK;
 
 done:
-       TALLOC_FREE(ntlmssp_state);
+       TALLOC_FREE(auth_generic_state);
        return status;
 }
 
@@ -144,17 +159,18 @@ static bool check_client_uid(struct winbindd_cli_state *state, uid_t uid)
 {
        int ret;
        uid_t ret_uid;
+       gid_t ret_gid;
 
        ret_uid = (uid_t)-1;
 
-       ret = sys_getpeereid(state->sock, &ret_uid);
+       ret = getpeereid(state->sock, &ret_uid, &ret_gid);
        if (ret != 0) {
                DEBUG(1, ("check_client_uid: Could not get socket peer uid: %s; "
                        "denying access\n", strerror(errno)));
                return False;
        }
 
-       if (uid != ret_uid) {
+       if (uid != ret_uid && ret_uid != sec_initial_uid()) {
                DEBUG(1, ("check_client_uid: Client lied about its uid: said %u, "
                        "actually was %u; denying access\n",
                        (unsigned int)uid, (unsigned int)ret_uid));
@@ -164,14 +180,15 @@ static bool check_client_uid(struct winbindd_cli_state *state, uid_t uid)
        return True;
 }
 
-void winbindd_ccache_ntlm_auth(struct winbindd_cli_state *state)
+bool winbindd_ccache_ntlm_auth(struct winbindd_cli_state *state)
 {
        struct winbindd_domain *domain;
-       fstring name_domain, name_user;
+       fstring name_namespace, name_domain, name_user;
        NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
        struct WINBINDD_MEMORY_CREDS *entry;
        DATA_BLOB initial, challenge, auth;
-       uint32 initial_blob_len, challenge_blob_len, extra_len;
+       uint32_t initial_blob_len, challenge_blob_len, extra_len;
+       bool ok;
 
        /* Ensure null termination */
        state->request->data.ccache_ntlm_auth.user[
@@ -182,12 +199,14 @@ void winbindd_ccache_ntlm_auth(struct winbindd_cli_state *state)
 
        /* Parse domain and username */
 
-       if (!canonicalize_username(state->request->data.ccache_ntlm_auth.user,
-                               name_domain, name_user)) {
+       ok = canonicalize_username(state->request->data.ccache_ntlm_auth.user,
+                                  name_namespace,
+                                  name_domain,
+                                  name_user);
+       if (!ok) {
                DEBUG(5,("winbindd_ccache_ntlm_auth: cannot parse domain and user from name [%s]\n",
                        state->request->data.ccache_ntlm_auth.user));
-               request_error(state);
-               return;
+               return false;
        }
 
        domain = find_auth_domain(state->request->flags, name_domain);
@@ -195,13 +214,11 @@ void winbindd_ccache_ntlm_auth(struct winbindd_cli_state *state)
        if (domain == NULL) {
                DEBUG(5,("winbindd_ccache_ntlm_auth: can't get domain [%s]\n",
                        name_domain));
-               request_error(state);
-               return;
+               return false;
        }
 
        if (!check_client_uid(state, state->request->data.ccache_ntlm_auth.uid)) {
-               request_error(state);
-               return;
+               return false;
        }
 
        /* validate blob lengths */
@@ -223,7 +240,11 @@ void winbindd_ccache_ntlm_auth(struct winbindd_cli_state *state)
        }
 
        /* Parse domain and username */
-       if (!parse_domain_user(state->request->data.ccache_ntlm_auth.user, name_domain, name_user)) {
+       ok = parse_domain_user(state->request->data.ccache_ntlm_auth.user,
+                              name_namespace,
+                              name_domain,
+                              name_user);
+       if (!ok) {
                DEBUG(10,("winbindd_dual_ccache_ntlm_auth: cannot parse "
                        "domain and user from name [%s]\n",
                        state->request->data.ccache_ntlm_auth.user));
@@ -257,10 +278,17 @@ void winbindd_ccache_ntlm_auth(struct winbindd_cli_state *state)
                state->request->extra_data.data + initial_blob_len,
                state->request->data.ccache_ntlm_auth.challenge_blob_len);
 
-       result = do_ntlm_auth_with_hashes(
-               name_user, name_domain, entry->lm_hash, entry->nt_hash,
-               initial, challenge, &auth,
-               state->response->data.ccache_ntlm_auth.session_key);
+       result = do_ntlm_auth_with_stored_pw(
+                       name_namespace,
+                       name_domain,
+                       name_user,
+                       entry->pass,
+                       initial,
+                       challenge,
+                       talloc_tos(),
+                       &auth,
+                       state->response->data.ccache_ntlm_auth.session_key,
+                       &state->response->data.ccache_ntlm_auth.new_spnego);
 
        if (!NT_STATUS_IS_OK(result)) {
                goto process_result;
@@ -278,18 +306,15 @@ void winbindd_ccache_ntlm_auth(struct winbindd_cli_state *state)
        data_blob_free(&auth);
 
   process_result:
-       if (!NT_STATUS_IS_OK(result)) {
-               request_error(state);
-               return;
-       }
-       request_ok(state);
+       return NT_STATUS_IS_OK(result);
 }
 
-void winbindd_ccache_save(struct winbindd_cli_state *state)
+bool winbindd_ccache_save(struct winbindd_cli_state *state)
 {
        struct winbindd_domain *domain;
-       fstring name_domain, name_user;
+       fstring name_namespace, name_domain, name_user;
        NTSTATUS status;
+       bool ok;
 
        /* Ensure null termination */
        state->request->data.ccache_save.user[
@@ -303,13 +328,15 @@ void winbindd_ccache_save(struct winbindd_cli_state *state)
 
        /* Parse domain and username */
 
-       if (!canonicalize_username(state->request->data.ccache_save.user,
-                                  name_domain, name_user)) {
+       ok = canonicalize_username(state->request->data.ccache_save.user,
+                                  name_namespace,
+                                  name_domain,
+                                  name_user);
+       if (!ok) {
                DEBUG(5,("winbindd_ccache_save: cannot parse domain and user "
                         "from name [%s]\n",
                         state->request->data.ccache_save.user));
-               request_error(state);
-               return;
+               return false;
        }
 
        /*
@@ -325,13 +352,11 @@ void winbindd_ccache_save(struct winbindd_cli_state *state)
        if (domain == NULL) {
                DEBUG(5, ("winbindd_ccache_save: can't get domain [%s]\n",
                          name_domain));
-               request_error(state);
-               return;
+               return false;
        }
 
        if (!check_client_uid(state, state->request->data.ccache_save.uid)) {
-               request_error(state);
-               return;
+               return false;
        }
 
        status = winbindd_add_memory_creds(
@@ -342,8 +367,7 @@ void winbindd_ccache_save(struct winbindd_cli_state *state)
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1, ("winbindd_add_memory_creds failed %s\n",
                          nt_errstr(status)));
-               request_error(state);
-               return;
+               return false;
        }
-       request_ok(state);
+       return true;
 }