r11068: Fix pam_auth_crap, remove the sync code. I don't know what it was when I
[samba.git] / source4 / winbind / wb_pam_auth.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Authenticate a user
5
6    Copyright (C) Volker Lendecke 2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "libcli/composite/composite.h"
25 #include "winbind/wb_async_helpers.h"
26 #include "winbind/wb_server.h"
27 #include "smbd/service_stream.h"
28 #include "libcli/auth/credentials.h"
29
30 struct pam_auth_crap_state {
31         struct composite_context *ctx;
32         struct wbsrv_domain *domain;
33         const char *domain_name;
34         const char *user_name;
35         const char *workstation;
36         DATA_BLOB chal, nt_resp, lm_resp;
37
38         struct creds_CredentialState *creds_state;
39         struct netr_Authenticator auth, auth2;
40         struct netr_NetworkInfo ninfo;
41         struct netr_LogonSamLogon r;
42
43         struct netr_UserSessionKey user_session_key;
44         struct netr_LMSessionKey lm_key;
45         DATA_BLOB info3;
46 };
47
48 static struct rpc_request *send_samlogon(struct pam_auth_crap_state *state);
49 static void pam_auth_crap_recv_init(struct composite_context *ctx);
50 static void pam_auth_crap_recv_samlogon(struct rpc_request *req);
51
52 struct composite_context *wb_cmd_pam_auth_crap_send(struct wbsrv_call *call,
53                                                     const char *domain,
54                                                     const char *user,
55                                                     const char *workstation,
56                                                     DATA_BLOB chal,
57                                                     DATA_BLOB nt_resp,
58                                                     DATA_BLOB lm_resp)
59 {
60         struct composite_context *result, *ctx;
61         struct pam_auth_crap_state *state;
62         struct wbsrv_service *service = call->wbconn->listen_socket->service;
63
64         result = talloc(NULL, struct composite_context);
65         if (result == NULL) goto failed;
66         result->state = COMPOSITE_STATE_IN_PROGRESS;
67         result->event_ctx = call->event_ctx;
68         result->async.fn = NULL;
69
70         state = talloc(result, struct pam_auth_crap_state);
71         if (state == NULL) goto failed;
72         state->ctx = result;
73         result->private_data = state;
74
75         state->domain = service->domains;
76
77         state->domain_name = talloc_strdup(state, domain);
78         if (state->domain_name == NULL) goto failed;
79
80         state->user_name = talloc_strdup(state, user);
81         if (state->user_name == NULL) goto failed;
82
83         state->workstation = talloc_strdup(state, workstation);
84         if (state->workstation == NULL) goto failed;
85
86         state->chal = data_blob_talloc(state, chal.data, chal.length);
87         if ((chal.data != NULL) && (state->chal.data == NULL)) goto failed;
88
89         state->nt_resp = data_blob_talloc(state, nt_resp.data, nt_resp.length);
90         if ((nt_resp.data != NULL) &&
91             (state->nt_resp.data == NULL)) goto failed;
92
93         state->lm_resp = data_blob_talloc(state, lm_resp.data, lm_resp.length);
94         if ((lm_resp.data != NULL) &&
95             (state->lm_resp.data == NULL)) goto failed;
96
97         if (state->domain->initialized) {
98                 struct rpc_request *req = send_samlogon(state);
99                 if (req == NULL) goto failed;
100                 req->async.callback = pam_auth_crap_recv_samlogon;
101                 req->async.private = state;
102                 return result;
103         }
104
105         ctx = wb_init_domain_send(state->domain, result->event_ctx,
106                                   call->wbconn->conn->msg_ctx);
107         if (ctx == NULL) goto failed;
108         ctx->async.fn = pam_auth_crap_recv_init;
109         ctx->async.private_data = state;
110         return result;
111
112  failed:
113         talloc_free(result);
114         return NULL;
115 }
116
117 static void pam_auth_crap_recv_init(struct composite_context *ctx)
118 {
119         struct pam_auth_crap_state *state =
120                 talloc_get_type(ctx->async.private_data,
121                                 struct pam_auth_crap_state);
122         struct rpc_request *req;
123
124         state->ctx->status = wb_init_domain_recv(ctx);
125         if (!composite_is_ok(state->ctx)) return;
126
127         req = send_samlogon(state);
128         composite_continue_rpc(state->ctx, req,
129                                pam_auth_crap_recv_samlogon, state);
130 }
131
132 static struct rpc_request *send_samlogon(struct pam_auth_crap_state *state)
133 {
134         state->creds_state = cli_credentials_get_netlogon_creds(
135                 state->domain->schannel_creds);
136         creds_client_authenticator(state->creds_state, &state->auth);
137
138         state->ninfo.identity_info.account_name.string = state->user_name;
139         state->ninfo.identity_info.domain_name.string =  state->domain_name;
140         state->ninfo.identity_info.parameter_control = 0;
141         state->ninfo.identity_info.logon_id_low = 0;
142         state->ninfo.identity_info.logon_id_high = 0;
143         state->ninfo.identity_info.workstation.string = state->workstation;
144
145         SMB_ASSERT(state->chal.length == sizeof(state->ninfo.challenge));
146         memcpy(state->ninfo.challenge, state->chal.data,
147                sizeof(state->ninfo.challenge));
148
149         state->ninfo.nt.length = state->nt_resp.length;
150         state->ninfo.nt.data = state->nt_resp.data;
151         state->ninfo.lm.length = state->lm_resp.length;
152         state->ninfo.lm.data = state->lm_resp.data;
153
154         state->r.in.server_name = talloc_asprintf(
155                 state, "\\\\%s",
156                 dcerpc_server_name(state->domain->netlogon_pipe));
157         if (state->r.in.server_name == NULL) return NULL;
158
159         state->r.in.workstation = cli_credentials_get_workstation(
160                 state->domain->schannel_creds);
161         state->r.in.credential = &state->auth;
162         state->r.in.return_authenticator = &state->auth2;
163         state->r.in.logon_level = 2;
164         state->r.in.validation_level = 3;
165         state->r.in.logon.network = &state->ninfo;
166         state->r.out.return_authenticator = NULL;
167
168         return dcerpc_netr_LogonSamLogon_send(state->domain->netlogon_pipe,
169                                               state, &state->r);
170 }
171
172 static void pam_auth_crap_recv_samlogon(struct rpc_request *req)
173 {
174         struct pam_auth_crap_state *state =
175                 talloc_get_type(req->async.private,
176                                 struct pam_auth_crap_state);
177         struct netr_SamBaseInfo *base;
178         DATA_BLOB tmp_blob;
179
180         state->ctx->status = dcerpc_ndr_request_recv(req);
181         if (!composite_is_ok(state->ctx)) return;
182         state->ctx->status = state->r.out.result;
183         if (!composite_is_ok(state->ctx)) return;
184
185         if ((state->r.out.return_authenticator == NULL) ||
186             (!creds_client_check(state->creds_state,
187                                  &state->r.out.return_authenticator->cred))) {
188                 DEBUG(0, ("Credentials check failed!\n"));
189                 composite_error(state->ctx, NT_STATUS_ACCESS_DENIED);
190                 return;
191         }
192
193         creds_decrypt_samlogon(state->creds_state,
194                                state->r.in.validation_level,
195                                &state->r.out.validation);
196
197         state->ctx->status = ndr_push_struct_blob(
198                 &tmp_blob, state, state->r.out.validation.sam3,
199                 (ndr_push_flags_fn_t)ndr_push_netr_SamInfo3);
200         if (!composite_is_ok(state->ctx)) return;
201
202         state->info3 = data_blob_talloc(state, NULL, tmp_blob.length+4);
203         if (composite_nomem(state->info3.data, state->ctx)) return;
204
205         SIVAL(state->info3.data, 0, 1);
206         memcpy(state->info3.data+4, tmp_blob.data, tmp_blob.length);
207
208         base = NULL;
209         switch(state->r.in.validation_level) {
210         case 2:
211                 base = &state->r.out.validation.sam2->base;
212                 break;
213         case 3:
214                 base = &state->r.out.validation.sam3->base;
215                 break;
216         case 6:
217                 base = &state->r.out.validation.sam6->base;
218                 break;
219         }
220         if (base == NULL) {
221                 composite_error(state->ctx, NT_STATUS_INTERNAL_ERROR);
222                 return;
223         }
224
225         state->user_session_key = base->key;
226         state->lm_key = base->LMSessKey;
227
228         composite_done(state->ctx);
229 }
230
231 NTSTATUS wb_cmd_pam_auth_crap_recv(struct composite_context *c,
232                                    TALLOC_CTX *mem_ctx,
233                                    DATA_BLOB *info3,
234                                    struct netr_UserSessionKey *user_session_key,
235                                    struct netr_LMSessionKey *lm_key)
236 {
237         NTSTATUS status = composite_wait(c);
238         if (NT_STATUS_IS_OK(status)) {
239                 struct pam_auth_crap_state *state =
240                         talloc_get_type(c->private_data,
241                                         struct pam_auth_crap_state);
242                 info3->length = state->info3.length;
243                 info3->data = talloc_steal(mem_ctx, state->info3.data);
244                 *user_session_key = state->user_session_key;
245                 *lm_key = state->lm_key;
246         }
247         talloc_free(c);
248         return status;
249 }
250
251 NTSTATUS wb_cmd_pam_auth_crap(struct wbsrv_call *call,
252                               const char *domain, const char *user,
253                               const char *workstation,
254                               DATA_BLOB chal, DATA_BLOB nt_resp,
255                               DATA_BLOB lm_resp, TALLOC_CTX *mem_ctx,
256                               DATA_BLOB *info3,
257                               struct netr_UserSessionKey *user_session_key,
258                               struct netr_LMSessionKey *lm_key)
259 {
260         struct composite_context *c =
261                 wb_cmd_pam_auth_crap_send(call, domain, user, workstation,
262                                           chal, nt_resp, lm_resp);
263         return wb_cmd_pam_auth_crap_recv(c, mem_ctx, info3, user_session_key,
264                                          lm_key);
265 }