nsswitch/winbindd_ccache_access.c

説明を見る。
00001 /*
00002    Unix SMB/CIFS implementation.
00003 
00004    Winbind daemon - cached credentials funcions
00005 
00006    Copyright (C) Robert O'Callahan 2006
00007    Copyright (C) Jeremy Allison 2006 (minor fixes to fit into Samba and
00008                                       protect against integer wrap).
00009    
00010    This program is free software; you can redistribute it and/or modify
00011    it under the terms of the GNU General Public License as published by
00012    the Free Software Foundation; either version 2 of the License, or
00013    (at your option) any later version.
00014    
00015    This program is distributed in the hope that it will be useful,
00016    but WITHOUT ANY WARRANTY; without even the implied warranty of
00017    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018    GNU General Public License for more details.
00019    
00020    You should have received a copy of the GNU General Public License
00021    along with this program; if not, write to the Free Software
00022    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00023 */
00024 
00025 #include "includes.h"
00026 #include "winbindd.h"
00027 
00028 #undef DBGC_CLASS
00029 #define DBGC_CLASS DBGC_WINBIND
00030 
00031 static BOOL client_can_access_ccache_entry(uid_t client_uid,
00032                                         struct WINBINDD_MEMORY_CREDS *entry)
00033 {
00034         if (client_uid == entry->uid || client_uid == 0) {
00035                 DEBUG(10, ("Access granted to uid %d\n", client_uid));
00036                 return True;
00037         }
00038 
00039         DEBUG(1, ("Access denied to uid %d (expected %d)\n", client_uid, entry->uid));
00040         return False;
00041 }
00042 
00043 static NTSTATUS do_ntlm_auth_with_hashes(const char *username,
00044                                         const char *domain,
00045                                         const unsigned char lm_hash[LM_HASH_LEN],
00046                                         const unsigned char nt_hash[NT_HASH_LEN],
00047                                         const DATA_BLOB initial_msg,
00048                                         const DATA_BLOB challenge_msg,
00049                                         DATA_BLOB *auth_msg)
00050 {
00051         NTSTATUS status;
00052         NTLMSSP_STATE *ntlmssp_state = NULL;
00053         DATA_BLOB dummy_msg, reply;
00054 
00055         status = ntlmssp_client_start(&ntlmssp_state);
00056 
00057         if (!NT_STATUS_IS_OK(status)) {
00058                 DEBUG(1, ("Could not start NTLMSSP client: %s\n",
00059                         nt_errstr(status)));
00060                 goto done;
00061         }
00062 
00063         status = ntlmssp_set_username(ntlmssp_state, username);
00064 
00065         if (!NT_STATUS_IS_OK(status)) {
00066                 DEBUG(1, ("Could not set username: %s\n",
00067                         nt_errstr(status)));
00068                 goto done;
00069         }
00070 
00071         status = ntlmssp_set_domain(ntlmssp_state, domain);
00072 
00073         if (!NT_STATUS_IS_OK(status)) {
00074                 DEBUG(1, ("Could not set domain: %s\n",
00075                         nt_errstr(status)));
00076                 goto done;
00077         }
00078 
00079         status = ntlmssp_set_hashes(ntlmssp_state, lm_hash, nt_hash);
00080         
00081         if (!NT_STATUS_IS_OK(status)) {
00082                 DEBUG(1, ("Could not set hashes: %s\n",
00083                         nt_errstr(status)));
00084                 goto done;
00085         }
00086 
00087         /* We need to get our protocol handler into the right state. So first
00088            we ask it to generate the initial message. Actually the client has already
00089            sent its own initial message, so we're going to drop this one on the floor.
00090            The client might have sent a different message, for example with different
00091            negotiation options, but as far as I can tell this won't hurt us. (Unless
00092            the client sent a different username or domain, in which case that's their
00093            problem for telling us the wrong username or domain.)
00094            Since we have a copy of the initial message that the client sent, we could
00095            resolve any discrepancies if we had to.
00096         */
00097         dummy_msg = data_blob(NULL, 0);
00098         reply = data_blob(NULL, 0);
00099         status = ntlmssp_update(ntlmssp_state, dummy_msg, &reply);
00100         data_blob_free(&dummy_msg);
00101         data_blob_free(&reply);
00102 
00103         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
00104                 DEBUG(1, ("Failed to create initial message! [%s]\n",
00105                         nt_errstr(status)));
00106                 goto done;
00107         }
00108 
00109         /* Now we are ready to handle the server's actual response. */
00110         status = ntlmssp_update(ntlmssp_state, challenge_msg, &reply);
00111 
00112         if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
00113                 DEBUG(1, ("We didn't get a response to the challenge! [%s]\n",
00114                         nt_errstr(status)));
00115                 data_blob_free(&reply);
00116                 goto done;
00117         }
00118         *auth_msg = reply;
00119         status = NT_STATUS_OK;
00120 
00121 done:
00122         ntlmssp_end(&ntlmssp_state);
00123         return status;
00124 }
00125 
00126 static BOOL check_client_uid(struct winbindd_cli_state *state, uid_t uid)
00127 {
00128         int ret;
00129         uid_t ret_uid;
00130 
00131         ret_uid = (uid_t)-1;
00132 
00133         ret = sys_getpeereid(state->sock, &ret_uid);
00134         if (ret != 0) {
00135                 DEBUG(1, ("check_client_uid: Could not get socket peer uid: %s; "
00136                         "denying access\n", strerror(errno)));
00137                 return False;
00138         }
00139 
00140         if (uid != ret_uid) {
00141                 DEBUG(1, ("check_client_uid: Client lied about its uid: said %d, "
00142                         "actually was %d; denying access\n",
00143                         uid, ret_uid));
00144                 return False;
00145         }
00146 
00147         return True;
00148 }
00149 
00150 void winbindd_ccache_ntlm_auth(struct winbindd_cli_state *state)
00151 {
00152         struct winbindd_domain *domain;
00153         fstring name_domain, name_user;
00154 
00155         /* Ensure null termination */
00156         state->request.data.ccache_ntlm_auth.user[
00157                         sizeof(state->request.data.ccache_ntlm_auth.user)-1]='\0';
00158 
00159         DEBUG(3, ("[%5lu]: perform NTLM auth on behalf of user %s\n", (unsigned long)state->pid,
00160                 state->request.data.ccache_ntlm_auth.user));
00161 
00162         /* Parse domain and username */
00163 
00164         if (!canonicalize_username(state->request.data.ccache_ntlm_auth.user,
00165                                 name_domain, name_user)) {
00166                 DEBUG(5,("winbindd_ccache_ntlm_auth: cannot parse domain and user from name [%s]\n",
00167                         state->request.data.ccache_ntlm_auth.user));
00168                 request_error(state);
00169                 return;
00170         }
00171 
00172         domain = find_auth_domain(state, name_domain);
00173 
00174         if (domain == NULL) {
00175                 DEBUG(5,("winbindd_ccache_ntlm_auth: can't get domain [%s]\n",
00176                         name_domain));
00177                 request_error(state);
00178                 return;
00179         }
00180 
00181         if (!check_client_uid(state, state->request.data.ccache_ntlm_auth.uid)) {
00182                 request_error(state);
00183                 return;
00184         }
00185 
00186         sendto_domain(state, domain);
00187 }
00188 
00189 enum winbindd_result winbindd_dual_ccache_ntlm_auth(struct winbindd_domain *domain,
00190                                                 struct winbindd_cli_state *state)
00191 {
00192         NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
00193         struct WINBINDD_MEMORY_CREDS *entry;
00194         DATA_BLOB initial, challenge, auth;
00195         fstring name_domain, name_user;
00196         uint32 initial_blob_len, challenge_blob_len, extra_len;
00197 
00198         /* Ensure null termination */
00199         state->request.data.ccache_ntlm_auth.user[
00200                 sizeof(state->request.data.ccache_ntlm_auth.user)-1]='\0';
00201 
00202         DEBUG(3, ("winbindd_dual_ccache_ntlm_auth: [%5lu]: perform NTLM auth on "
00203                 "behalf of user %s (dual)\n", (unsigned long)state->pid,
00204                 state->request.data.ccache_ntlm_auth.user));
00205 
00206         /* validate blob lengths */
00207         initial_blob_len = state->request.data.ccache_ntlm_auth.initial_blob_len;
00208         challenge_blob_len = state->request.data.ccache_ntlm_auth.challenge_blob_len;
00209         extra_len = state->request.extra_len;
00210 
00211         if (initial_blob_len > extra_len || challenge_blob_len > extra_len ||
00212                 initial_blob_len + challenge_blob_len > extra_len ||
00213                 initial_blob_len + challenge_blob_len < initial_blob_len ||
00214                 initial_blob_len + challenge_blob_len < challenge_blob_len) {
00215 
00216                 DEBUG(10,("winbindd_dual_ccache_ntlm_auth: blob lengths overrun "
00217                         "or wrap. Buffer [%d+%d > %d]\n",
00218                         initial_blob_len,
00219                         challenge_blob_len,
00220                         extra_len));
00221                 goto process_result;
00222         }
00223 
00224         /* Parse domain and username */
00225         if (!parse_domain_user(state->request.data.ccache_ntlm_auth.user, name_domain, name_user)) {
00226                 DEBUG(10,("winbindd_dual_ccache_ntlm_auth: cannot parse "
00227                         "domain and user from name [%s]\n",
00228                         state->request.data.ccache_ntlm_auth.user));
00229                 goto process_result;
00230         }
00231 
00232         entry = find_memory_creds_by_name(state->request.data.ccache_ntlm_auth.user);
00233         if (entry == NULL || entry->nt_hash == NULL || entry->lm_hash == NULL) {
00234                 DEBUG(10,("winbindd_dual_ccache_ntlm_auth: could not find "
00235                         "credentials for user %s\n", 
00236                         state->request.data.ccache_ntlm_auth.user));
00237                 goto process_result;
00238         }
00239 
00240         DEBUG(10,("winbindd_dual_ccache_ntlm_auth: found ccache [%s]\n", entry->username));
00241 
00242         if (!client_can_access_ccache_entry(state->request.data.ccache_ntlm_auth.uid, entry)) {
00243                 goto process_result;
00244         }
00245 
00246         if (initial_blob_len == 0 && challenge_blob_len == 0) {
00247                 /* this is just a probe to see if credentials are available. */
00248                 result = NT_STATUS_OK;
00249                 state->response.data.ccache_ntlm_auth.auth_blob_len = 0;
00250                 goto process_result;
00251         }
00252 
00253         initial = data_blob(state->request.extra_data.data, initial_blob_len);
00254         challenge = data_blob(state->request.extra_data.data + initial_blob_len, 
00255                                 state->request.data.ccache_ntlm_auth.challenge_blob_len);
00256 
00257         if (!initial.data || !challenge.data) {
00258                 result = NT_STATUS_NO_MEMORY;
00259         } else {
00260                 result = do_ntlm_auth_with_hashes(name_user, name_domain,
00261                                                 entry->lm_hash, entry->nt_hash,
00262                                                 initial, challenge, &auth);
00263         }
00264 
00265         data_blob_free(&initial);
00266         data_blob_free(&challenge);
00267 
00268         if (!NT_STATUS_IS_OK(result)) {
00269                 goto process_result;
00270         }
00271 
00272         state->response.extra_data.data = smb_xmemdup(auth.data, auth.length);
00273         if (!state->response.extra_data.data) {
00274                 result = NT_STATUS_NO_MEMORY;
00275                 goto process_result;
00276         }
00277         state->response.length += auth.length;
00278         state->response.data.ccache_ntlm_auth.auth_blob_len = auth.length;
00279 
00280         data_blob_free(&auth);
00281 
00282   process_result:
00283         return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
00284 }

Sambaに対してSat Aug 29 21:23:10 2009に生成されました。  doxygen 1.4.7