2 Unix SMB/CIFS implementation.
6 Copyright (C) Volker Lendecke 2005
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "libcli/composite/composite.h"
26 #include "winbind/wb_async_helpers.h"
27 #include "winbind/wb_server.h"
28 #include "smbd/service_stream.h"
29 #include "libcli/auth/credentials.h"
31 /* Oh, there is so much to keep an eye on when authenticating a user. Oh my! */
32 struct pam_auth_crap_state {
33 struct composite_context *ctx;
34 struct event_context *event_ctx;
35 uint32_t logon_parameters;
36 const char *domain_name;
37 const char *user_name;
38 const char *workstation;
39 DATA_BLOB chal, nt_resp, lm_resp;
41 struct creds_CredentialState *creds_state;
42 struct netr_Authenticator auth, auth2;
43 struct netr_NetworkInfo ninfo;
44 struct netr_LogonSamLogon r;
46 struct netr_UserSessionKey user_session_key;
47 struct netr_LMSessionKey lm_key;
51 static struct composite_context *crap_samlogon_send_req(struct wbsrv_domain *domain,
53 static NTSTATUS crap_samlogon_recv_req(struct composite_context *ctx, void *p);
55 /* NTLM authentication.
57 Fill parameters into a control block to pass to the next function.
58 No application logic, this is done by the helper function paramters
59 to wb_domain_request_send()
63 struct composite_context *wb_cmd_pam_auth_crap_send(struct wbsrv_call *call,
64 uint32_t logon_parameters,
67 const char *workstation,
72 struct pam_auth_crap_state *state;
73 struct wbsrv_service *service = call->wbconn->listen_socket->service;
75 state = talloc(NULL, struct pam_auth_crap_state);
76 if (state == NULL) goto failed;
78 state->event_ctx = call->event_ctx;
80 state->logon_parameters = logon_parameters;
82 state->domain_name = talloc_strdup(state, domain);
83 if (state->domain_name == NULL) goto failed;
85 state->user_name = talloc_strdup(state, user);
86 if (state->user_name == NULL) goto failed;
88 state->workstation = talloc_strdup(state, workstation);
89 if (state->workstation == NULL) goto failed;
91 state->chal = data_blob_talloc(state, chal.data, chal.length);
92 if ((chal.data != NULL) && (state->chal.data == NULL)) goto failed;
94 state->nt_resp = data_blob_talloc(state, nt_resp.data, nt_resp.length);
95 if ((nt_resp.data != NULL) &&
96 (state->nt_resp.data == NULL)) goto failed;
98 state->lm_resp = data_blob_talloc(state, lm_resp.data, lm_resp.length);
99 if ((lm_resp.data != NULL) &&
100 (state->lm_resp.data == NULL)) goto failed;
102 state->ctx = wb_domain_request_send(state, service,
103 service->primary_sid,
104 crap_samlogon_send_req,
105 crap_samlogon_recv_req,
107 if (state->ctx == NULL) goto failed;
108 state->ctx->private_data = state;
119 Send of a SamLogon request to authenticate a user.
121 static struct composite_context *crap_samlogon_send_req(struct wbsrv_domain *domain,
124 struct pam_auth_crap_state *state =
125 talloc_get_type(p, struct pam_auth_crap_state);
127 cli_credentials_get_netlogon_creds(domain->schannel_creds);
129 creds_client_authenticator(state->creds_state, &state->auth);
131 state->ninfo.identity_info.account_name.string = state->user_name;
132 state->ninfo.identity_info.domain_name.string = state->domain_name;
133 state->ninfo.identity_info.parameter_control = state->logon_parameters;
134 state->ninfo.identity_info.logon_id_low = 0;
135 state->ninfo.identity_info.logon_id_high = 0;
136 state->ninfo.identity_info.workstation.string = state->workstation;
138 SMB_ASSERT(state->chal.length == sizeof(state->ninfo.challenge));
139 memcpy(state->ninfo.challenge, state->chal.data,
140 sizeof(state->ninfo.challenge));
142 state->ninfo.nt.length = state->nt_resp.length;
143 state->ninfo.nt.data = state->nt_resp.data;
144 state->ninfo.lm.length = state->lm_resp.length;
145 state->ninfo.lm.data = state->lm_resp.data;
147 state->r.in.server_name = talloc_asprintf(
148 state, "\\\\%s", dcerpc_server_name(domain->netlogon_pipe));
149 if (state->r.in.server_name == NULL) return NULL;
151 ZERO_STRUCT(state->auth2);
153 state->r.in.workstation =
154 cli_credentials_get_workstation(domain->schannel_creds);
155 state->r.in.credential = &state->auth;
156 state->r.in.return_authenticator = &state->auth2;
157 state->r.in.logon_level = 2;
158 state->r.in.validation_level = 3;
159 state->r.in.logon.network = &state->ninfo;
160 state->r.out.return_authenticator = NULL;
162 return composite_netr_LogonSamLogon_send(domain->netlogon_pipe,
169 Check the SamLogon reply, decrypt and parse out the session keys and the info3 structure
171 static NTSTATUS crap_samlogon_recv_req(struct composite_context *ctx,
174 struct pam_auth_crap_state *state =
175 talloc_get_type(p, struct pam_auth_crap_state);
176 struct netr_SamBaseInfo *base;
180 status = composite_netr_LogonSamLogon_recv(ctx);
181 if (!NT_STATUS_IS_OK(status)) return status;
183 if ((state->r.out.return_authenticator == NULL) ||
184 (!creds_client_check(state->creds_state,
185 &state->r.out.return_authenticator->cred))) {
186 DEBUG(0, ("Credentials check failed!\n"));
187 return NT_STATUS_ACCESS_DENIED;
190 status = state->r.out.result;
191 if (!NT_STATUS_IS_OK(status)) return status;
193 /* Decrypt the session keys before we reform the info3, so the
194 * person on the other end of winbindd pipe doesn't have to.
195 * They won't have the encryption key anyway */
196 creds_decrypt_samlogon(state->creds_state,
197 state->r.in.validation_level,
198 &state->r.out.validation);
200 status = ndr_push_struct_blob(
202 state->r.out.validation.sam3,
203 (ndr_push_flags_fn_t)ndr_push_netr_SamInfo3);
204 NT_STATUS_NOT_OK_RETURN(status);
206 /* The Samba3 protocol is a bit broken (due to non-IDL
207 * heritage, so for compatability we must add a non-zero 4
208 * bytes to the info3 */
209 state->info3 = data_blob_talloc(state, NULL, tmp_blob.length+4);
210 NT_STATUS_HAVE_NO_MEMORY(state->info3.data);
212 SIVAL(state->info3.data, 0, 1);
213 memcpy(state->info3.data+4, tmp_blob.data, tmp_blob.length);
215 /* We actually only ask for level 3, and assume it above, but anyway... */
217 switch(state->r.in.validation_level) {
219 base = &state->r.out.validation.sam2->base;
222 base = &state->r.out.validation.sam3->base;
225 base = &state->r.out.validation.sam6->base;
229 return NT_STATUS_INTERNAL_ERROR;
232 state->user_session_key = base->key;
233 state->lm_key = base->LMSessKey;
235 /* Give the caller the most accurate username possible.
236 * Assists where case sensitive comparisons may be done by our
237 * ntlm_auth callers */
238 if (base->account_name.string) {
239 state->user_name = base->account_name.string;
240 talloc_steal(state, base->account_name.string);
242 if (base->domain.string) {
243 state->domain_name = base->domain.string;
244 talloc_steal(state, base->domain.string);
250 NTSTATUS wb_cmd_pam_auth_crap_recv(struct composite_context *c,
253 struct netr_UserSessionKey *user_session_key,
254 struct netr_LMSessionKey *lm_key,
255 char **unix_username)
257 struct pam_auth_crap_state *state =
258 talloc_get_type(c->private_data, struct pam_auth_crap_state);
259 NTSTATUS status = composite_wait(c);
260 if (NT_STATUS_IS_OK(status)) {
261 info3->length = state->info3.length;
262 info3->data = talloc_steal(mem_ctx, state->info3.data);
263 *user_session_key = state->user_session_key;
264 *lm_key = state->lm_key;
265 *unix_username = talloc_asprintf(mem_ctx, "%s%s%s",
266 state->domain_name, lp_winbind_separator(),
268 if (!*unix_username) {
269 status = NT_STATUS_NO_MEMORY;
276 NTSTATUS wb_cmd_pam_auth_crap(struct wbsrv_call *call,
277 uint32_t logon_parameters,
278 const char *domain, const char *user,
279 const char *workstation,
280 DATA_BLOB chal, DATA_BLOB nt_resp,
281 DATA_BLOB lm_resp, TALLOC_CTX *mem_ctx,
283 struct netr_UserSessionKey *user_session_key,
284 struct netr_LMSessionKey *lm_key,
285 char **unix_username)
287 struct composite_context *c =
288 wb_cmd_pam_auth_crap_send(call, logon_parameters,
289 domain, user, workstation,
290 chal, nt_resp, lm_resp);
291 return wb_cmd_pam_auth_crap_recv(c, mem_ctx, info3, user_session_key,
292 lm_key, unix_username);
295 struct composite_context *wb_cmd_pam_auth_send(struct wbsrv_call *call,
298 const char *password)
300 struct composite_context *c;
301 struct cli_credentials *credentials;
302 const char *workstation;
305 DATA_BLOB chal, nt_resp, lm_resp, names_blob;
306 int flags = CLI_CRED_NTLM_AUTH;
307 if (lp_client_lanman_auth()) {
308 flags |= CLI_CRED_LANMAN_AUTH;
311 if (lp_client_ntlmv2_auth()) {
312 flags |= CLI_CRED_NTLMv2_AUTH;
315 DEBUG(5, ("wbsrv_samba3_pam_auth_crap called\n"));
317 credentials = cli_credentials_init(call);
321 cli_credentials_set_conf(credentials);
322 cli_credentials_set_domain(credentials, domain, CRED_SPECIFIED);
323 cli_credentials_set_username(credentials, user, CRED_SPECIFIED);
325 cli_credentials_set_password(credentials, password, CRED_SPECIFIED);
327 chal = data_blob_talloc(call, NULL, 8);
331 generate_random_buffer(chal.data, chal.length);
332 cli_credentials_get_ntlm_username_domain(credentials, call,
334 /* for best compatability with multiple vitual netbios names
335 * on the host, this should be generated from the
336 * cli_credentials associated with the machine account */
337 workstation = cli_credentials_get_workstation(credentials);
339 names_blob = NTLMv2_generate_names_blob(call, cli_credentials_get_workstation(credentials),
340 cli_credentials_get_domain(credentials));
342 status = cli_credentials_get_ntlm_response(credentials, call,
348 if (!NT_STATUS_IS_OK(status)) {
351 c = wb_cmd_pam_auth_crap_send(call, 0 /* logon parameters */,
352 domain, user, workstation,
353 chal, nt_resp, lm_resp);
357 NTSTATUS wb_cmd_pam_auth_recv(struct composite_context *c)
359 struct pam_auth_crap_state *state =
360 talloc_get_type(c->private_data, struct pam_auth_crap_state);
361 NTSTATUS status = composite_wait(c);
366 NTSTATUS wb_cmd_pam_auth(struct wbsrv_call *call,
367 const char *domain, const char *user,
368 const char *password)
370 struct composite_context *c =
371 wb_cmd_pam_auth_send(call, domain, user,
373 return wb_cmd_pam_auth_recv(c);