libcli/security Provide a common, top level libcli/security/security.h
[Samba/gebeck_regimport.git] / nsswitch / libwbclient / wbc_pam_async.c
blob21d187f124b051601025b05c3adb1f709d98e997
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind client API
6 Copyright (C) 2009 Kai Blin <kai@samba.org>
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 3 of the License, or (at your option) any later version.
13 This library 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 GNU
16 Library General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 /* Required Headers */
24 #include "replace.h"
25 #include "libwbclient.h"
26 #include "../winbind_client.h"
27 #include "wbc_async.h"
29 /* FIXME: Currently this is still a copy of the same function from wbc_pam.c */
30 static wbcErr wbc_create_auth_info(TALLOC_CTX *mem_ctx,
31 const struct winbindd_response *resp,
32 struct wbcAuthUserInfo **_i)
34 wbcErr wbc_status = WBC_ERR_SUCCESS;
35 struct wbcAuthUserInfo *i;
36 struct wbcDomainSid domain_sid;
37 char *p;
38 uint32_t sn = 0;
39 uint32_t j;
41 i = talloc(mem_ctx, struct wbcAuthUserInfo);
42 BAIL_ON_PTR_ERROR(i, wbc_status);
44 i->user_flags = resp->data.auth.info3.user_flgs;
46 i->account_name = talloc_strdup(i, resp->data.auth.info3.user_name);
47 BAIL_ON_PTR_ERROR(i->account_name, wbc_status);
48 i->user_principal= NULL;
49 i->full_name = talloc_strdup(i, resp->data.auth.info3.full_name);
50 BAIL_ON_PTR_ERROR(i->full_name, wbc_status);
51 i->domain_name = talloc_strdup(i, resp->data.auth.info3.logon_dom);
52 BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
53 i->dns_domain_name= NULL;
55 i->acct_flags = resp->data.auth.info3.acct_flags;
56 memcpy(i->user_session_key,
57 resp->data.auth.user_session_key,
58 sizeof(i->user_session_key));
59 memcpy(i->lm_session_key,
60 resp->data.auth.first_8_lm_hash,
61 sizeof(i->lm_session_key));
63 i->logon_count = resp->data.auth.info3.logon_count;
64 i->bad_password_count = resp->data.auth.info3.bad_pw_count;
66 i->logon_time = resp->data.auth.info3.logon_time;
67 i->logoff_time = resp->data.auth.info3.logoff_time;
68 i->kickoff_time = resp->data.auth.info3.kickoff_time;
69 i->pass_last_set_time = resp->data.auth.info3.pass_last_set_time;
70 i->pass_can_change_time = resp->data.auth.info3.pass_can_change_time;
71 i->pass_must_change_time= resp->data.auth.info3.pass_must_change_time;
73 i->logon_server = talloc_strdup(i, resp->data.auth.info3.logon_srv);
74 BAIL_ON_PTR_ERROR(i->logon_server, wbc_status);
75 i->logon_script = talloc_strdup(i, resp->data.auth.info3.logon_script);
76 BAIL_ON_PTR_ERROR(i->logon_script, wbc_status);
77 i->profile_path = talloc_strdup(i, resp->data.auth.info3.profile_path);
78 BAIL_ON_PTR_ERROR(i->profile_path, wbc_status);
79 i->home_directory= talloc_strdup(i, resp->data.auth.info3.home_dir);
80 BAIL_ON_PTR_ERROR(i->home_directory, wbc_status);
81 i->home_drive = talloc_strdup(i, resp->data.auth.info3.dir_drive);
82 BAIL_ON_PTR_ERROR(i->home_drive, wbc_status);
84 i->num_sids = 2;
85 i->num_sids += resp->data.auth.info3.num_groups;
86 i->num_sids += resp->data.auth.info3.num_other_sids;
88 i->sids = talloc_array(i, struct wbcSidWithAttr, i->num_sids);
89 BAIL_ON_PTR_ERROR(i->sids, wbc_status);
91 wbc_status = wbcStringToSid(resp->data.auth.info3.dom_sid,
92 &domain_sid);
93 BAIL_ON_WBC_ERROR(wbc_status);
95 #define _SID_COMPOSE(s, d, r, a) { \
96 (s).sid = d; \
97 if ((s).sid.num_auths < WBC_MAXSUBAUTHS) { \
98 (s).sid.sub_auths[(s).sid.num_auths++] = r; \
99 } else { \
100 wbc_status = WBC_ERR_INVALID_SID; \
101 BAIL_ON_WBC_ERROR(wbc_status); \
103 (s).attributes = a; \
104 } while (0)
106 sn = 0;
107 _SID_COMPOSE(i->sids[sn], domain_sid,
108 resp->data.auth.info3.user_rid,
110 sn++;
111 _SID_COMPOSE(i->sids[sn], domain_sid,
112 resp->data.auth.info3.group_rid,
114 sn++;
116 p = (char *)resp->extra_data.data;
117 if (!p) {
118 wbc_status = WBC_ERR_INVALID_RESPONSE;
119 BAIL_ON_WBC_ERROR(wbc_status);
122 for (j=0; j < resp->data.auth.info3.num_groups; j++) {
123 uint32_t rid;
124 uint32_t attrs;
125 int ret;
126 char *s = p;
127 char *e = strchr(p, '\n');
128 if (!e) {
129 wbc_status = WBC_ERR_INVALID_RESPONSE;
130 BAIL_ON_WBC_ERROR(wbc_status);
132 e[0] = '\0';
133 p = &e[1];
135 ret = sscanf(s, "0x%08X:0x%08X", &rid, &attrs);
136 if (ret != 2) {
137 wbc_status = WBC_ERR_INVALID_RESPONSE;
138 BAIL_ON_WBC_ERROR(wbc_status);
141 _SID_COMPOSE(i->sids[sn], domain_sid,
142 rid, attrs);
143 sn++;
146 for (j=0; j < resp->data.auth.info3.num_other_sids; j++) {
147 uint32_t attrs;
148 int ret;
149 char *s = p;
150 char *a;
151 char *e = strchr(p, '\n');
152 if (!e) {
153 wbc_status = WBC_ERR_INVALID_RESPONSE;
154 BAIL_ON_WBC_ERROR(wbc_status);
156 e[0] = '\0';
157 p = &e[1];
159 e = strchr(s, ':');
160 if (!e) {
161 wbc_status = WBC_ERR_INVALID_RESPONSE;
162 BAIL_ON_WBC_ERROR(wbc_status);
164 e[0] = '\0';
165 a = &e[1];
167 ret = sscanf(a, "0x%08X",
168 &attrs);
169 if (ret != 1) {
170 wbc_status = WBC_ERR_INVALID_RESPONSE;
171 BAIL_ON_WBC_ERROR(wbc_status);
174 wbc_status = wbcStringToSid(s, &i->sids[sn].sid);
175 BAIL_ON_WBC_ERROR(wbc_status);
177 i->sids[sn].attributes = attrs;
178 sn++;
181 i->num_sids = sn;
183 *_i = i;
184 i = NULL;
185 done:
186 talloc_free(i);
187 return wbc_status;
190 /* FIXME: Currently this is still a copy of the same function from wbc_pam.c */
191 static wbcErr wbc_create_error_info(const struct winbindd_response *resp,
192 struct wbcAuthErrorInfo **_e)
194 wbcErr wbc_status = WBC_ERR_SUCCESS;
195 struct wbcAuthErrorInfo *e;
197 e = talloc(NULL, struct wbcAuthErrorInfo);
198 BAIL_ON_PTR_ERROR(e, wbc_status);
200 e->nt_status = resp->data.auth.nt_status;
201 e->pam_error = resp->data.auth.pam_error;
202 e->nt_string = talloc_strdup(e, resp->data.auth.nt_status_string);
203 BAIL_ON_PTR_ERROR(e->nt_string, wbc_status);
205 e->display_string = talloc_strdup(e, resp->data.auth.error_string);
206 BAIL_ON_PTR_ERROR(e->display_string, wbc_status);
208 *_e = e;
209 e = NULL;
211 done:
212 talloc_free(e);
213 return wbc_status;
216 struct wbc_authenticate_user_ex_state {
217 struct winbindd_request req;
218 struct tevent_context *ev;
219 struct wb_context *wb_ctx;
220 const struct wbcAuthUserParams *params;
221 struct wbcAuthUserInfo *info;
222 struct wbcAuthErrorInfo *error;
225 static void wbcAuthenticateUserEx_got_info(struct tevent_req *subreq);
226 static void wbcAuthenticateUserEx_done(struct tevent_req *subreq);
228 struct tevent_req *wbcAuthenticateUserEx_send(TALLOC_CTX *mem_ctx,
229 struct tevent_context *ev,
230 struct wb_context *wb_ctx,
231 const struct wbcAuthUserParams *params)
233 struct tevent_req *req, *subreq;
234 struct wbc_authenticate_user_ex_state *state;
236 req = tevent_req_create(mem_ctx, &state,
237 struct wbc_authenticate_user_ex_state);
238 if (req == NULL) {
239 return NULL;
242 state->ev = ev;
243 state->wb_ctx = wb_ctx;
244 state->params = params;
246 if (!params) {
247 tevent_req_error(req, WBC_ERR_INVALID_PARAM);
248 return tevent_req_post(req, ev);
251 if (!params->account_name) {
252 tevent_req_error(req, WBC_ERR_INVALID_PARAM);
253 return tevent_req_post(req, ev);
256 ZERO_STRUCT(state->req);
258 if (params->flags) {
259 state->req.flags = params->flags;
262 switch (params->level) {
263 case WBC_AUTH_USER_LEVEL_PLAIN:
264 state->req.cmd = WINBINDD_PAM_AUTH;
265 state->req.flags |= WBFLAG_PAM_INFO3_TEXT |
266 WBFLAG_PAM_USER_SESSION_KEY |
267 WBFLAG_PAM_LMKEY;
269 if (!params->password.plaintext) {
270 tevent_req_error(req, WBC_ERR_INVALID_PARAM);
271 return tevent_req_post(req, ev);
274 strncpy(state->req.data.auth.pass,
275 params->password.plaintext,
276 sizeof(state->req.data.auth.pass)-1);
278 if (params->domain_name && params->domain_name[0]) {
279 /* We need to get the winbind separator :-( */
280 subreq = wbcInfo_send(state, ev, wb_ctx);
281 if (tevent_req_nomem(subreq, req)) {
282 return tevent_req_post(req, ev);
285 tevent_req_set_callback(subreq,
286 wbcAuthenticateUserEx_got_info,
287 req);
288 return req;
289 } else {
290 strncpy(state->req.data.auth.user,
291 params->account_name,
292 sizeof(state->req.data.auth.user)-1);
295 break;
297 case WBC_AUTH_USER_LEVEL_HASH:
298 tevent_req_error(req, WBC_ERR_NOT_IMPLEMENTED);
299 return tevent_req_post(req, ev);
300 /* Make some static code checkers happy */
301 break;
303 case WBC_AUTH_USER_LEVEL_RESPONSE:
304 state->req.cmd = WINBINDD_PAM_AUTH_CRAP;
305 state->req.flags |= WBFLAG_PAM_INFO3_TEXT |
306 WBFLAG_PAM_USER_SESSION_KEY |
307 WBFLAG_PAM_LMKEY;
309 if (params->password.response.lm_length &&
310 !params->password.response.lm_data) {
311 tevent_req_error(req, WBC_ERR_INVALID_PARAM);
312 return tevent_req_post(req, ev);
314 if (params->password.response.lm_length == 0 &&
315 params->password.response.lm_data) {
316 tevent_req_error(req, WBC_ERR_INVALID_PARAM);
317 return tevent_req_post(req, ev);
320 if (params->password.response.nt_length &&
321 !params->password.response.nt_data) {
322 tevent_req_error(req, WBC_ERR_INVALID_PARAM);
323 return tevent_req_post(req, ev);
325 if (params->password.response.nt_length == 0&&
326 params->password.response.nt_data) {
327 tevent_req_error(req, WBC_ERR_INVALID_PARAM);
328 return tevent_req_post(req, ev);
331 strncpy(state->req.data.auth_crap.user,
332 params->account_name,
333 sizeof(state->req.data.auth_crap.user)-1);
334 if (params->domain_name) {
335 strncpy(state->req.data.auth_crap.domain,
336 params->domain_name,
337 sizeof(state->req.data.auth_crap.domain)-1);
339 if (params->workstation_name) {
340 strncpy(state->req.data.auth_crap.workstation,
341 params->workstation_name,
342 sizeof(state->req.data.auth_crap.workstation)-1);
345 state->req.data.auth_crap.logon_parameters =
346 params->parameter_control;
348 memcpy(state->req.data.auth_crap.chal,
349 params->password.response.challenge,
350 sizeof(state->req.data.auth_crap.chal));
352 state->req.data.auth_crap.lm_resp_len =
353 MIN(params->password.response.lm_length,
354 sizeof(state->req.data.auth_crap.lm_resp));
355 state->req.data.auth_crap.nt_resp_len =
356 MIN(params->password.response.nt_length,
357 sizeof(state->req.data.auth_crap.nt_resp));
358 if (params->password.response.lm_data) {
359 memcpy(state->req.data.auth_crap.lm_resp,
360 params->password.response.lm_data,
361 state->req.data.auth_crap.lm_resp_len);
363 if (params->password.response.nt_data) {
364 memcpy(state->req.data.auth_crap.nt_resp,
365 params->password.response.nt_data,
366 state->req.data.auth_crap.nt_resp_len);
368 break;
369 default:
370 tevent_req_error(req, WBC_ERR_INVALID_PARAM);
371 return tevent_req_post(req, ev);
372 break;
375 subreq = wb_trans_send(state, ev, wb_ctx, false, &state->req);
376 if (tevent_req_nomem(subreq, req)) {
377 return tevent_req_post(req, ev);
380 tevent_req_set_callback(subreq, wbcAuthenticateUserEx_done, req);
381 return req;
384 static void wbcAuthenticateUserEx_got_info(struct tevent_req *subreq)
386 struct tevent_req *req = tevent_req_callback_data(
387 subreq, struct tevent_req);
388 struct wbc_authenticate_user_ex_state *state = tevent_req_data(
389 req, struct wbc_authenticate_user_ex_state);
390 char *version_string;
391 char separator;
392 wbcErr wbc_status;
394 wbc_status = wbcInfo_recv(subreq, state, &separator, &version_string);
395 TALLOC_FREE(subreq);
396 if (!WBC_ERROR_IS_OK(wbc_status)) {
397 tevent_req_error(req, wbc_status);
398 return;
401 snprintf(state->req.data.auth.user,
402 sizeof(state->req.data.auth.user)-1,
403 "%s%c%s",
404 state->params->domain_name,
405 separator,
406 state->params->account_name);
408 subreq = wb_trans_send(state, state->ev, state->wb_ctx, false,
409 &state->req);
410 if (tevent_req_nomem(subreq, req)) {
411 return;
414 tevent_req_set_callback(subreq, wbcAuthenticateUserEx_done, req);
415 return;
418 static void wbcAuthenticateUserEx_done(struct tevent_req *subreq)
420 struct tevent_req *req = tevent_req_callback_data(
421 subreq, struct tevent_req);
422 struct wbc_authenticate_user_ex_state *state = tevent_req_data(
423 req, struct wbc_authenticate_user_ex_state);
424 struct winbindd_response *resp;
425 wbcErr wbc_status;
427 ZERO_STRUCT(resp);
429 wbc_status = wb_trans_recv(subreq, state, &resp);
430 TALLOC_FREE(subreq);
431 if (!WBC_ERROR_IS_OK(wbc_status)) {
432 tevent_req_error(req, wbc_status);
433 goto done;
436 if (resp->data.auth.nt_status != 0) {
437 wbc_status = wbc_create_error_info(resp, &state->error);
438 if (!WBC_ERROR_IS_OK(wbc_status)) {
439 tevent_req_error(req, wbc_status);
440 goto done;
443 tevent_req_error(req, WBC_ERR_AUTH_ERROR);
444 goto done;
447 wbc_status = wbc_create_auth_info(state, resp, &state->info);
448 if (!WBC_ERROR_IS_OK(wbc_status)) {
449 tevent_req_error(req, wbc_status);
450 goto done;
453 done:
454 TALLOC_FREE(resp);
457 wbcErr wbcAuthenticateUserEx_recv(struct tevent_req *req,
458 TALLOC_CTX *mem_ctx,
459 struct wbcAuthUserInfo **info,
460 struct wbcAuthErrorInfo **error)
462 struct wbc_authenticate_user_ex_state *state = tevent_req_data(
463 req, struct wbc_authenticate_user_ex_state);
464 wbcErr wbc_status;
466 if (error) {
467 *error = NULL;
470 if (tevent_req_is_wbcerr(req, &wbc_status)) {
471 tevent_req_received(req);
472 if (error) {
473 *error = talloc_steal(mem_ctx, state->error);
475 return wbc_status;
478 if (info) {
479 *info = talloc_steal(mem_ctx, state->info);
482 tevent_req_received(req);
483 return wbc_status;