00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
00088
00089
00090
00091
00092
00093
00094
00095
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
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
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
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
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
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
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
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 }