libwbclient: Implement wbcAuthenticateUserEx_send/recv
[Samba/gebeck_regimport.git] / nsswitch / libwbclient / wbc_pam.c
blobef85f2b7fd7a38a19a8fcb6ee8e2711b2c0b960c
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind client API
6 Copyright (C) Gerald (Jerry) Carter 2007
7 Copyright (C) Guenther Deschner 2008
8 Copyright (C) Volker Lendecke 2009
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 3 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Library General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 /* Required Headers */
26 #include "replace.h"
27 #include "libwbclient.h"
28 #include "../winbind_client.h"
30 /* Authenticate a username/password pair */
31 wbcErr wbcAuthenticateUser(const char *username,
32 const char *password)
34 wbcErr wbc_status = WBC_ERR_SUCCESS;
35 struct wbcAuthUserParams params;
37 ZERO_STRUCT(params);
39 params.account_name = username;
40 params.level = WBC_AUTH_USER_LEVEL_PLAIN;
41 params.password.plaintext = password;
43 wbc_status = wbcAuthenticateUserEx(&params, NULL, NULL);
44 BAIL_ON_WBC_ERROR(wbc_status);
46 done:
47 return wbc_status;
50 static wbcErr wbc_create_auth_info(TALLOC_CTX *mem_ctx,
51 const struct winbindd_response *resp,
52 struct wbcAuthUserInfo **_i)
54 wbcErr wbc_status = WBC_ERR_SUCCESS;
55 struct wbcAuthUserInfo *i;
56 struct wbcDomainSid domain_sid;
57 char *p;
58 uint32_t sn = 0;
59 uint32_t j;
61 i = talloc(mem_ctx, struct wbcAuthUserInfo);
62 BAIL_ON_PTR_ERROR(i, wbc_status);
64 i->user_flags = resp->data.auth.info3.user_flgs;
66 i->account_name = talloc_strdup(i, resp->data.auth.info3.user_name);
67 BAIL_ON_PTR_ERROR(i->account_name, wbc_status);
68 i->user_principal= NULL;
69 i->full_name = talloc_strdup(i, resp->data.auth.info3.full_name);
70 BAIL_ON_PTR_ERROR(i->full_name, wbc_status);
71 i->domain_name = talloc_strdup(i, resp->data.auth.info3.logon_dom);
72 BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
73 i->dns_domain_name= NULL;
75 i->acct_flags = resp->data.auth.info3.acct_flags;
76 memcpy(i->user_session_key,
77 resp->data.auth.user_session_key,
78 sizeof(i->user_session_key));
79 memcpy(i->lm_session_key,
80 resp->data.auth.first_8_lm_hash,
81 sizeof(i->lm_session_key));
83 i->logon_count = resp->data.auth.info3.logon_count;
84 i->bad_password_count = resp->data.auth.info3.bad_pw_count;
86 i->logon_time = resp->data.auth.info3.logon_time;
87 i->logoff_time = resp->data.auth.info3.logoff_time;
88 i->kickoff_time = resp->data.auth.info3.kickoff_time;
89 i->pass_last_set_time = resp->data.auth.info3.pass_last_set_time;
90 i->pass_can_change_time = resp->data.auth.info3.pass_can_change_time;
91 i->pass_must_change_time= resp->data.auth.info3.pass_must_change_time;
93 i->logon_server = talloc_strdup(i, resp->data.auth.info3.logon_srv);
94 BAIL_ON_PTR_ERROR(i->logon_server, wbc_status);
95 i->logon_script = talloc_strdup(i, resp->data.auth.info3.logon_script);
96 BAIL_ON_PTR_ERROR(i->logon_script, wbc_status);
97 i->profile_path = talloc_strdup(i, resp->data.auth.info3.profile_path);
98 BAIL_ON_PTR_ERROR(i->profile_path, wbc_status);
99 i->home_directory= talloc_strdup(i, resp->data.auth.info3.home_dir);
100 BAIL_ON_PTR_ERROR(i->home_directory, wbc_status);
101 i->home_drive = talloc_strdup(i, resp->data.auth.info3.dir_drive);
102 BAIL_ON_PTR_ERROR(i->home_drive, wbc_status);
104 i->num_sids = 2;
105 i->num_sids += resp->data.auth.info3.num_groups;
106 i->num_sids += resp->data.auth.info3.num_other_sids;
108 i->sids = talloc_array(i, struct wbcSidWithAttr, i->num_sids);
109 BAIL_ON_PTR_ERROR(i->sids, wbc_status);
111 wbc_status = wbcStringToSid(resp->data.auth.info3.dom_sid,
112 &domain_sid);
113 BAIL_ON_WBC_ERROR(wbc_status);
115 #define _SID_COMPOSE(s, d, r, a) { \
116 (s).sid = d; \
117 if ((s).sid.num_auths < WBC_MAXSUBAUTHS) { \
118 (s).sid.sub_auths[(s).sid.num_auths++] = r; \
119 } else { \
120 wbc_status = WBC_ERR_INVALID_SID; \
121 BAIL_ON_WBC_ERROR(wbc_status); \
123 (s).attributes = a; \
124 } while (0)
126 sn = 0;
127 _SID_COMPOSE(i->sids[sn], domain_sid,
128 resp->data.auth.info3.user_rid,
130 sn++;
131 _SID_COMPOSE(i->sids[sn], domain_sid,
132 resp->data.auth.info3.group_rid,
134 sn++;
136 p = (char *)resp->extra_data.data;
137 if (!p) {
138 wbc_status = WBC_ERR_INVALID_RESPONSE;
139 BAIL_ON_WBC_ERROR(wbc_status);
142 for (j=0; j < resp->data.auth.info3.num_groups; j++) {
143 uint32_t rid;
144 uint32_t attrs;
145 int ret;
146 char *s = p;
147 char *e = strchr(p, '\n');
148 if (!e) {
149 wbc_status = WBC_ERR_INVALID_RESPONSE;
150 BAIL_ON_WBC_ERROR(wbc_status);
152 e[0] = '\0';
153 p = &e[1];
155 ret = sscanf(s, "0x%08X:0x%08X", &rid, &attrs);
156 if (ret != 2) {
157 wbc_status = WBC_ERR_INVALID_RESPONSE;
158 BAIL_ON_WBC_ERROR(wbc_status);
161 _SID_COMPOSE(i->sids[sn], domain_sid,
162 rid, attrs);
163 sn++;
166 for (j=0; j < resp->data.auth.info3.num_other_sids; j++) {
167 uint32_t attrs;
168 int ret;
169 char *s = p;
170 char *a;
171 char *e = strchr(p, '\n');
172 if (!e) {
173 wbc_status = WBC_ERR_INVALID_RESPONSE;
174 BAIL_ON_WBC_ERROR(wbc_status);
176 e[0] = '\0';
177 p = &e[1];
179 e = strchr(s, ':');
180 if (!e) {
181 wbc_status = WBC_ERR_INVALID_RESPONSE;
182 BAIL_ON_WBC_ERROR(wbc_status);
184 e[0] = '\0';
185 a = &e[1];
187 ret = sscanf(a, "0x%08X",
188 &attrs);
189 if (ret != 1) {
190 wbc_status = WBC_ERR_INVALID_RESPONSE;
191 BAIL_ON_WBC_ERROR(wbc_status);
194 wbc_status = wbcStringToSid(s, &i->sids[sn].sid);
195 BAIL_ON_WBC_ERROR(wbc_status);
197 i->sids[sn].attributes = attrs;
198 sn++;
201 i->num_sids = sn;
203 *_i = i;
204 i = NULL;
205 done:
206 talloc_free(i);
207 return wbc_status;
210 static wbcErr wbc_create_error_info(const struct winbindd_response *resp,
211 struct wbcAuthErrorInfo **_e)
213 wbcErr wbc_status = WBC_ERR_SUCCESS;
214 struct wbcAuthErrorInfo *e;
216 e = talloc(NULL, struct wbcAuthErrorInfo);
217 BAIL_ON_PTR_ERROR(e, wbc_status);
219 e->nt_status = resp->data.auth.nt_status;
220 e->pam_error = resp->data.auth.pam_error;
221 e->nt_string = talloc_strdup(e, resp->data.auth.nt_status_string);
222 BAIL_ON_PTR_ERROR(e->nt_string, wbc_status);
224 e->display_string = talloc_strdup(e, resp->data.auth.error_string);
225 BAIL_ON_PTR_ERROR(e->display_string, wbc_status);
227 *_e = e;
228 e = NULL;
230 done:
231 talloc_free(e);
232 return wbc_status;
235 static wbcErr wbc_create_password_policy_info(const struct winbindd_response *resp,
236 struct wbcUserPasswordPolicyInfo **_i)
238 wbcErr wbc_status = WBC_ERR_SUCCESS;
239 struct wbcUserPasswordPolicyInfo *i;
241 i = talloc(NULL, struct wbcUserPasswordPolicyInfo);
242 BAIL_ON_PTR_ERROR(i, wbc_status);
244 i->min_passwordage = resp->data.auth.policy.min_passwordage;
245 i->min_length_password = resp->data.auth.policy.min_length_password;
246 i->password_history = resp->data.auth.policy.password_history;
247 i->password_properties = resp->data.auth.policy.password_properties;
248 i->expire = resp->data.auth.policy.expire;
250 *_i = i;
251 i = NULL;
253 done:
254 talloc_free(i);
255 return wbc_status;
258 static wbcErr wbc_create_logon_info(struct winbindd_response *resp,
259 struct wbcLogonUserInfo **_i)
261 wbcErr wbc_status = WBC_ERR_SUCCESS;
262 struct wbcLogonUserInfo *i;
264 i = talloc_zero(NULL, struct wbcLogonUserInfo);
265 BAIL_ON_PTR_ERROR(i, wbc_status);
267 wbc_status = wbc_create_auth_info(i, resp, &i->info);
268 BAIL_ON_WBC_ERROR(wbc_status);
270 if (resp->data.auth.krb5ccname &&
271 strlen(resp->data.auth.krb5ccname)) {
272 wbc_status = wbcAddNamedBlob(&i->num_blobs,
273 &i->blobs,
274 "krb5ccname",
276 (uint8_t *)resp->data.auth.krb5ccname,
277 strlen(resp->data.auth.krb5ccname)+1);
278 BAIL_ON_WBC_ERROR(wbc_status);
281 if (resp->data.auth.unix_username &&
282 strlen(resp->data.auth.unix_username)) {
283 wbc_status = wbcAddNamedBlob(&i->num_blobs,
284 &i->blobs,
285 "unix_username",
287 (uint8_t *)resp->data.auth.unix_username,
288 strlen(resp->data.auth.unix_username)+1);
289 BAIL_ON_WBC_ERROR(wbc_status);
292 *_i = i;
293 i = NULL;
294 done:
295 if (!WBC_ERROR_IS_OK(wbc_status) && i) {
296 wbcFreeMemory(i->blobs);
299 talloc_free(i);
300 return wbc_status;
303 struct wbc_authenticate_user_ex_state {
304 struct winbindd_request req;
305 struct tevent_context *ev;
306 struct wb_context *wb_ctx;
307 const struct wbcAuthUserParams *params;
308 struct wbcAuthUserInfo *info;
309 struct wbcAuthErrorInfo *error;
312 static void wbcAuthenticateUserEx_got_info(struct tevent_req *subreq);
313 static void wbcAuthenticateUserEx_done(struct tevent_req *subreq);
315 struct tevent_req *wbcAuthenticateUserEx_send(TALLOC_CTX *mem_ctx,
316 struct tevent_context *ev,
317 struct wb_context *wb_ctx,
318 const struct wbcAuthUserParams *params)
320 struct tevent_req *req, *subreq;
321 struct wbc_authenticate_user_ex_state *state;
323 req = tevent_req_create(mem_ctx, &state,
324 struct wbc_authenticate_user_ex_state);
325 if (req == NULL) {
326 return NULL;
329 state->ev = ev;
330 state->wb_ctx = wb_ctx;
331 state->params = params;
333 if (!params) {
334 tevent_req_error(req, WBC_ERR_INVALID_PARAM);
335 return tevent_req_post(req, ev);
338 if (!params->account_name) {
339 tevent_req_error(req, WBC_ERR_INVALID_PARAM);
340 return tevent_req_post(req, ev);
343 ZERO_STRUCT(state->req);
345 if (params->flags) {
346 state->req.flags = params->flags;
349 switch (params->level) {
350 case WBC_AUTH_USER_LEVEL_PLAIN:
351 state->req.cmd = WINBINDD_PAM_AUTH;
352 state->req.flags |= WBFLAG_PAM_INFO3_TEXT |
353 WBFLAG_PAM_USER_SESSION_KEY |
354 WBFLAG_PAM_LMKEY;
356 if (!params->password.plaintext) {
357 tevent_req_error(req, WBC_ERR_INVALID_PARAM);
358 return tevent_req_post(req, ev);
361 strncpy(state->req.data.auth.pass,
362 params->password.plaintext,
363 sizeof(state->req.data.auth.pass)-1);
365 if (params->domain_name && params->domain_name[0]) {
366 /* We need to get the winbind separator :-( */
367 subreq = wbcInfo_send(state, ev, wb_ctx);
368 if (tevent_req_nomem(subreq, req)) {
369 return tevent_req_post(req, ev);
372 tevent_req_set_callback(subreq,
373 wbcAuthenticateUserEx_got_info,
374 req);
375 return req;
376 } else {
377 strncpy(state->req.data.auth.user,
378 params->account_name,
379 sizeof(state->req.data.auth.user)-1);
382 break;
384 case WBC_AUTH_USER_LEVEL_HASH:
385 tevent_req_error(req, WBC_ERR_NOT_IMPLEMENTED);
386 return tevent_req_post(req, ev);
387 /* Make some static code checkers happy */
388 break;
390 case WBC_AUTH_USER_LEVEL_RESPONSE:
391 state->req.cmd = WINBINDD_PAM_AUTH_CRAP;
392 state->req.flags |= WBFLAG_PAM_INFO3_TEXT |
393 WBFLAG_PAM_USER_SESSION_KEY |
394 WBFLAG_PAM_LMKEY;
396 if (params->password.response.lm_length &&
397 !params->password.response.lm_data) {
398 tevent_req_error(req, WBC_ERR_INVALID_PARAM);
399 return tevent_req_post(req, ev);
401 if (params->password.response.lm_length == 0 &&
402 params->password.response.lm_data) {
403 tevent_req_error(req, WBC_ERR_INVALID_PARAM);
404 return tevent_req_post(req, ev);
407 if (params->password.response.nt_length &&
408 !params->password.response.nt_data) {
409 tevent_req_error(req, WBC_ERR_INVALID_PARAM);
410 return tevent_req_post(req, ev);
412 if (params->password.response.nt_length == 0&&
413 params->password.response.nt_data) {
414 tevent_req_error(req, WBC_ERR_INVALID_PARAM);
415 return tevent_req_post(req, ev);
418 strncpy(state->req.data.auth_crap.user,
419 params->account_name,
420 sizeof(state->req.data.auth_crap.user)-1);
421 if (params->domain_name) {
422 strncpy(state->req.data.auth_crap.domain,
423 params->domain_name,
424 sizeof(state->req.data.auth_crap.domain)-1);
426 if (params->workstation_name) {
427 strncpy(state->req.data.auth_crap.workstation,
428 params->workstation_name,
429 sizeof(state->req.data.auth_crap.workstation)-1);
432 state->req.data.auth_crap.logon_parameters =
433 params->parameter_control;
435 memcpy(state->req.data.auth_crap.chal,
436 params->password.response.challenge,
437 sizeof(state->req.data.auth_crap.chal));
439 state->req.data.auth_crap.lm_resp_len =
440 MIN(params->password.response.lm_length,
441 sizeof(state->req.data.auth_crap.lm_resp));
442 state->req.data.auth_crap.nt_resp_len =
443 MIN(params->password.response.nt_length,
444 sizeof(state->req.data.auth_crap.nt_resp));
445 if (params->password.response.lm_data) {
446 memcpy(state->req.data.auth_crap.lm_resp,
447 params->password.response.lm_data,
448 state->req.data.auth_crap.lm_resp_len);
450 if (params->password.response.nt_data) {
451 memcpy(state->req.data.auth_crap.nt_resp,
452 params->password.response.nt_data,
453 state->req.data.auth_crap.nt_resp_len);
455 break;
456 default:
457 tevent_req_error(req, WBC_ERR_INVALID_PARAM);
458 return tevent_req_post(req, ev);
459 break;
462 subreq = wb_trans_send(state, ev, wb_ctx, false, &state->req);
463 if (tevent_req_nomem(subreq, req)) {
464 return tevent_req_post(req, ev);
467 tevent_req_set_callback(subreq, wbcAuthenticateUserEx_done, req);
468 return req;
471 static void wbcAuthenticateUserEx_got_info(struct tevent_req *subreq)
473 struct tevent_req *req = tevent_req_callback_data(
474 subreq, struct tevent_req);
475 struct wbc_authenticate_user_ex_state *state = tevent_req_data(
476 req, struct wbc_authenticate_user_ex_state);
477 char *version_string;
478 char separator;
479 wbcErr wbc_status;
481 wbc_status = wbcInfo_recv(subreq, state, &separator, &version_string);
482 TALLOC_FREE(subreq);
483 if (!WBC_ERROR_IS_OK(wbc_status)) {
484 tevent_req_error(req, wbc_status);
485 return;
488 snprintf(state->req.data.auth.user,
489 sizeof(state->req.data.auth.user)-1,
490 "%s%c%s",
491 state->params->domain_name,
492 separator,
493 state->params->account_name);
495 subreq = wb_trans_send(state, state->ev, state->wb_ctx, false,
496 &state->req);
497 if (tevent_req_nomem(subreq, req)) {
498 return;
501 tevent_req_set_callback(subreq, wbcAuthenticateUserEx_done, req);
502 return;
505 static void wbcAuthenticateUserEx_done(struct tevent_req *subreq)
507 struct tevent_req *req = tevent_req_callback_data(
508 subreq, struct tevent_req);
509 struct wbc_authenticate_user_ex_state *state = tevent_req_data(
510 req, struct wbc_authenticate_user_ex_state);
511 struct winbindd_response *resp;
512 wbcErr wbc_status;
514 ZERO_STRUCT(resp);
516 wbc_status = wb_trans_recv(subreq, state, &resp);
517 TALLOC_FREE(subreq);
518 if (!WBC_ERROR_IS_OK(wbc_status)) {
519 tevent_req_error(req, wbc_status);
520 goto done;
523 if (resp->data.auth.nt_status != 0) {
524 wbc_status = wbc_create_error_info(resp, &state->error);
525 if (!WBC_ERROR_IS_OK(wbc_status)) {
526 tevent_req_error(req, wbc_status);
527 goto done;
530 tevent_req_error(req, WBC_ERR_AUTH_ERROR);
531 goto done;
534 wbc_status = wbc_create_auth_info(state, resp, &state->info);
535 if (!WBC_ERROR_IS_OK(wbc_status)) {
536 tevent_req_error(req, wbc_status);
537 goto done;
540 done:
541 TALLOC_FREE(resp);
544 wbcErr wbcAuthenticateUserEx_recv(struct tevent_req *req,
545 TALLOC_CTX *mem_ctx,
546 struct wbcAuthUserInfo **info,
547 struct wbcAuthErrorInfo **error)
549 struct wbc_authenticate_user_ex_state *state = tevent_req_data(
550 req, struct wbc_authenticate_user_ex_state);
551 wbcErr wbc_status;
553 if (error) {
554 *error = NULL;
557 if (tevent_req_is_wbcerr(req, &wbc_status)) {
558 tevent_req_received(req);
559 if (error) {
560 *error = talloc_steal(mem_ctx, state->error);
562 return wbc_status;
565 if (info) {
566 *info = talloc_steal(mem_ctx, state->info);
569 tevent_req_received(req);
570 return wbc_status;
573 /* Authenticate with more detailed information */
574 wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params,
575 struct wbcAuthUserInfo **info,
576 struct wbcAuthErrorInfo **error)
578 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
579 int cmd = 0;
580 struct winbindd_request request;
581 struct winbindd_response response;
583 ZERO_STRUCT(request);
584 ZERO_STRUCT(response);
586 if (error) {
587 *error = NULL;
590 if (!params) {
591 wbc_status = WBC_ERR_INVALID_PARAM;
592 BAIL_ON_WBC_ERROR(wbc_status);
595 if (!params->account_name) {
596 wbc_status = WBC_ERR_INVALID_PARAM;
597 BAIL_ON_WBC_ERROR(wbc_status);
600 /* Initialize request */
602 switch (params->level) {
603 case WBC_AUTH_USER_LEVEL_PLAIN:
604 cmd = WINBINDD_PAM_AUTH;
605 request.flags = WBFLAG_PAM_INFO3_TEXT |
606 WBFLAG_PAM_USER_SESSION_KEY |
607 WBFLAG_PAM_LMKEY;
609 if (!params->password.plaintext) {
610 wbc_status = WBC_ERR_INVALID_PARAM;
611 BAIL_ON_WBC_ERROR(wbc_status);
614 if (params->domain_name && params->domain_name[0]) {
615 /* We need to get the winbind separator :-( */
616 struct winbindd_response sep_response;
618 ZERO_STRUCT(sep_response);
620 wbc_status = wbcRequestResponse(WINBINDD_INFO,
621 NULL, &sep_response);
622 BAIL_ON_WBC_ERROR(wbc_status);
624 snprintf(request.data.auth.user,
625 sizeof(request.data.auth.user)-1,
626 "%s%c%s",
627 params->domain_name,
628 sep_response.data.info.winbind_separator,
629 params->account_name);
630 } else {
631 strncpy(request.data.auth.user,
632 params->account_name,
633 sizeof(request.data.auth.user)-1);
636 strncpy(request.data.auth.pass,
637 params->password.plaintext,
638 sizeof(request.data.auth.pass)-1);
639 break;
641 case WBC_AUTH_USER_LEVEL_HASH:
642 wbc_status = WBC_ERR_NOT_IMPLEMENTED;
643 BAIL_ON_WBC_ERROR(wbc_status);
644 break;
646 case WBC_AUTH_USER_LEVEL_RESPONSE:
647 cmd = WINBINDD_PAM_AUTH_CRAP;
648 request.flags = WBFLAG_PAM_INFO3_TEXT |
649 WBFLAG_PAM_USER_SESSION_KEY |
650 WBFLAG_PAM_LMKEY;
652 if (params->password.response.lm_length &&
653 !params->password.response.lm_data) {
654 wbc_status = WBC_ERR_INVALID_PARAM;
655 BAIL_ON_WBC_ERROR(wbc_status);
657 if (params->password.response.lm_length == 0 &&
658 params->password.response.lm_data) {
659 wbc_status = WBC_ERR_INVALID_PARAM;
660 BAIL_ON_WBC_ERROR(wbc_status);
663 if (params->password.response.nt_length &&
664 !params->password.response.nt_data) {
665 wbc_status = WBC_ERR_INVALID_PARAM;
666 BAIL_ON_WBC_ERROR(wbc_status);
668 if (params->password.response.nt_length == 0&&
669 params->password.response.nt_data) {
670 wbc_status = WBC_ERR_INVALID_PARAM;
671 BAIL_ON_WBC_ERROR(wbc_status);
674 strncpy(request.data.auth_crap.user,
675 params->account_name,
676 sizeof(request.data.auth_crap.user)-1);
677 if (params->domain_name) {
678 strncpy(request.data.auth_crap.domain,
679 params->domain_name,
680 sizeof(request.data.auth_crap.domain)-1);
682 if (params->workstation_name) {
683 strncpy(request.data.auth_crap.workstation,
684 params->workstation_name,
685 sizeof(request.data.auth_crap.workstation)-1);
688 request.data.auth_crap.logon_parameters =
689 params->parameter_control;
691 memcpy(request.data.auth_crap.chal,
692 params->password.response.challenge,
693 sizeof(request.data.auth_crap.chal));
695 request.data.auth_crap.lm_resp_len =
696 MIN(params->password.response.lm_length,
697 sizeof(request.data.auth_crap.lm_resp));
698 if (params->password.response.lm_data) {
699 memcpy(request.data.auth_crap.lm_resp,
700 params->password.response.lm_data,
701 request.data.auth_crap.lm_resp_len);
703 request.data.auth_crap.nt_resp_len = params->password.response.nt_length;
704 if (params->password.response.nt_length > sizeof(request.data.auth_crap.nt_resp)) {
705 request.flags |= WBFLAG_BIG_NTLMV2_BLOB;
706 request.extra_len = params->password.response.nt_length;
707 request.extra_data.data = talloc_zero_array(NULL, char, request.extra_len);
708 if (request.extra_data.data == NULL) {
709 wbc_status = WBC_ERR_NO_MEMORY;
710 BAIL_ON_WBC_ERROR(wbc_status);
712 memcpy(request.extra_data.data,
713 params->password.response.nt_data,
714 request.data.auth_crap.nt_resp_len);
715 } else if (params->password.response.nt_data) {
716 memcpy(request.data.auth_crap.nt_resp,
717 params->password.response.nt_data,
718 request.data.auth_crap.nt_resp_len);
720 break;
721 default:
722 break;
725 if (cmd == 0) {
726 wbc_status = WBC_ERR_INVALID_PARAM;
727 BAIL_ON_WBC_ERROR(wbc_status);
730 if (params->flags) {
731 request.flags |= params->flags;
734 wbc_status = wbcRequestResponse(cmd,
735 &request,
736 &response);
737 if (response.data.auth.nt_status != 0) {
738 if (error) {
739 wbc_status = wbc_create_error_info(&response,
740 error);
741 BAIL_ON_WBC_ERROR(wbc_status);
744 wbc_status = WBC_ERR_AUTH_ERROR;
745 BAIL_ON_WBC_ERROR(wbc_status);
747 BAIL_ON_WBC_ERROR(wbc_status);
749 if (info) {
750 wbc_status = wbc_create_auth_info(NULL,
751 &response,
752 info);
753 BAIL_ON_WBC_ERROR(wbc_status);
756 done:
757 winbindd_free_response(&response);
759 talloc_free(request.extra_data.data);
761 return wbc_status;
764 /* Trigger a verification of the trust credentials of a specific domain */
765 wbcErr wbcCheckTrustCredentials(const char *domain,
766 struct wbcAuthErrorInfo **error)
768 struct winbindd_request request;
769 struct winbindd_response response;
770 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
772 ZERO_STRUCT(request);
773 ZERO_STRUCT(response);
775 if (domain) {
776 strncpy(request.domain_name, domain,
777 sizeof(request.domain_name)-1);
780 /* Send request */
782 wbc_status = wbcRequestResponse(WINBINDD_CHECK_MACHACC,
783 &request,
784 &response);
785 if (response.data.auth.nt_status != 0) {
786 if (error) {
787 wbc_status = wbc_create_error_info(&response,
788 error);
789 BAIL_ON_WBC_ERROR(wbc_status);
792 wbc_status = WBC_ERR_AUTH_ERROR;
793 BAIL_ON_WBC_ERROR(wbc_status);
795 BAIL_ON_WBC_ERROR(wbc_status);
797 done:
798 return wbc_status;
801 /* Trigger a change of the trust credentials for a specific domain */
802 wbcErr wbcChangeTrustCredentials(const char *domain,
803 struct wbcAuthErrorInfo **error)
805 struct winbindd_request request;
806 struct winbindd_response response;
807 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
809 ZERO_STRUCT(request);
810 ZERO_STRUCT(response);
812 if (domain) {
813 strncpy(request.domain_name, domain,
814 sizeof(request.domain_name)-1);
817 /* Send request */
819 wbc_status = wbcRequestResponse(WINBINDD_CHANGE_MACHACC,
820 &request,
821 &response);
822 if (response.data.auth.nt_status != 0) {
823 if (error) {
824 wbc_status = wbc_create_error_info(&response,
825 error);
826 BAIL_ON_WBC_ERROR(wbc_status);
829 wbc_status = WBC_ERR_AUTH_ERROR;
830 BAIL_ON_WBC_ERROR(wbc_status);
832 BAIL_ON_WBC_ERROR(wbc_status);
834 done:
835 return wbc_status;
839 * Trigger a no-op NETLOGON call. Lightweight version of
840 * wbcCheckTrustCredentials
842 wbcErr wbcPingDc(const char *domain, struct wbcAuthErrorInfo **error)
844 struct winbindd_request request;
845 struct winbindd_response response;
846 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
848 if (domain) {
850 * the current protocol doesn't support
851 * specifying a domain
853 wbc_status = WBC_ERR_NOT_IMPLEMENTED;
854 BAIL_ON_WBC_ERROR(wbc_status);
857 ZERO_STRUCT(request);
858 ZERO_STRUCT(response);
860 /* Send request */
862 wbc_status = wbcRequestResponse(WINBINDD_PING_DC,
863 &request,
864 &response);
865 if (response.data.auth.nt_status != 0) {
866 if (error) {
867 wbc_status = wbc_create_error_info(&response,
868 error);
869 BAIL_ON_WBC_ERROR(wbc_status);
872 wbc_status = WBC_ERR_AUTH_ERROR;
873 BAIL_ON_WBC_ERROR(wbc_status);
875 BAIL_ON_WBC_ERROR(wbc_status);
877 done:
878 return wbc_status;
881 /* Trigger an extended logoff notification to Winbind for a specific user */
882 wbcErr wbcLogoffUserEx(const struct wbcLogoffUserParams *params,
883 struct wbcAuthErrorInfo **error)
885 struct winbindd_request request;
886 struct winbindd_response response;
887 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
888 int i;
890 /* validate input */
892 if (!params || !params->username) {
893 wbc_status = WBC_ERR_INVALID_PARAM;
894 BAIL_ON_WBC_ERROR(wbc_status);
897 if ((params->num_blobs > 0) && (params->blobs == NULL)) {
898 wbc_status = WBC_ERR_INVALID_PARAM;
899 BAIL_ON_WBC_ERROR(wbc_status);
901 if ((params->num_blobs == 0) && (params->blobs != NULL)) {
902 wbc_status = WBC_ERR_INVALID_PARAM;
903 BAIL_ON_WBC_ERROR(wbc_status);
906 ZERO_STRUCT(request);
907 ZERO_STRUCT(response);
909 strncpy(request.data.logoff.user, params->username,
910 sizeof(request.data.logoff.user)-1);
912 for (i=0; i<params->num_blobs; i++) {
914 if (strcasecmp(params->blobs[i].name, "ccfilename") == 0) {
915 if (params->blobs[i].blob.data) {
916 strncpy(request.data.logoff.krb5ccname,
917 (const char *)params->blobs[i].blob.data,
918 sizeof(request.data.logoff.krb5ccname) - 1);
920 continue;
923 if (strcasecmp(params->blobs[i].name, "user_uid") == 0) {
924 if (params->blobs[i].blob.data) {
925 memcpy(&request.data.logoff.uid,
926 params->blobs[i].blob.data,
927 MIN(params->blobs[i].blob.length,
928 sizeof(request.data.logoff.uid)));
930 continue;
933 if (strcasecmp(params->blobs[i].name, "flags") == 0) {
934 if (params->blobs[i].blob.data) {
935 memcpy(&request.flags,
936 params->blobs[i].blob.data,
937 MIN(params->blobs[i].blob.length,
938 sizeof(request.flags)));
940 continue;
944 /* Send request */
946 wbc_status = wbcRequestResponse(WINBINDD_PAM_LOGOFF,
947 &request,
948 &response);
950 /* Take the response above and return it to the caller */
951 if (response.data.auth.nt_status != 0) {
952 if (error) {
953 wbc_status = wbc_create_error_info(&response,
954 error);
955 BAIL_ON_WBC_ERROR(wbc_status);
958 wbc_status = WBC_ERR_AUTH_ERROR;
959 BAIL_ON_WBC_ERROR(wbc_status);
961 BAIL_ON_WBC_ERROR(wbc_status);
963 done:
964 return wbc_status;
967 /* Trigger a logoff notification to Winbind for a specific user */
968 wbcErr wbcLogoffUser(const char *username,
969 uid_t uid,
970 const char *ccfilename)
972 struct winbindd_request request;
973 struct winbindd_response response;
974 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
976 /* validate input */
978 if (!username) {
979 wbc_status = WBC_ERR_INVALID_PARAM;
980 BAIL_ON_WBC_ERROR(wbc_status);
983 ZERO_STRUCT(request);
984 ZERO_STRUCT(response);
986 strncpy(request.data.logoff.user, username,
987 sizeof(request.data.logoff.user)-1);
988 request.data.logoff.uid = uid;
990 if (ccfilename) {
991 strncpy(request.data.logoff.krb5ccname, ccfilename,
992 sizeof(request.data.logoff.krb5ccname)-1);
995 /* Send request */
997 wbc_status = wbcRequestResponse(WINBINDD_PAM_LOGOFF,
998 &request,
999 &response);
1001 /* Take the response above and return it to the caller */
1003 done:
1004 return wbc_status;
1007 /* Change a password for a user with more detailed information upon failure */
1008 wbcErr wbcChangeUserPasswordEx(const struct wbcChangePasswordParams *params,
1009 struct wbcAuthErrorInfo **error,
1010 enum wbcPasswordChangeRejectReason *reject_reason,
1011 struct wbcUserPasswordPolicyInfo **policy)
1013 struct winbindd_request request;
1014 struct winbindd_response response;
1015 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
1016 int cmd = 0;
1018 /* validate input */
1020 if (!params->account_name) {
1021 wbc_status = WBC_ERR_INVALID_PARAM;
1022 BAIL_ON_WBC_ERROR(wbc_status);
1025 if (error) {
1026 *error = NULL;
1029 if (policy) {
1030 *policy = NULL;
1033 if (reject_reason) {
1034 *reject_reason = -1;
1037 ZERO_STRUCT(request);
1038 ZERO_STRUCT(response);
1040 switch (params->level) {
1041 case WBC_CHANGE_PASSWORD_LEVEL_PLAIN:
1042 cmd = WINBINDD_PAM_CHAUTHTOK;
1044 if (!params->account_name) {
1045 wbc_status = WBC_ERR_INVALID_PARAM;
1046 BAIL_ON_WBC_ERROR(wbc_status);
1049 strncpy(request.data.chauthtok.user, params->account_name,
1050 sizeof(request.data.chauthtok.user) - 1);
1052 if (params->old_password.plaintext) {
1053 strncpy(request.data.chauthtok.oldpass,
1054 params->old_password.plaintext,
1055 sizeof(request.data.chauthtok.oldpass) - 1);
1058 if (params->new_password.plaintext) {
1059 strncpy(request.data.chauthtok.newpass,
1060 params->new_password.plaintext,
1061 sizeof(request.data.chauthtok.newpass) - 1);
1063 break;
1065 case WBC_CHANGE_PASSWORD_LEVEL_RESPONSE:
1066 cmd = WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP;
1068 if (!params->account_name || !params->domain_name) {
1069 wbc_status = WBC_ERR_INVALID_PARAM;
1070 BAIL_ON_WBC_ERROR(wbc_status);
1073 if (params->old_password.response.old_lm_hash_enc_length &&
1074 !params->old_password.response.old_lm_hash_enc_data) {
1075 wbc_status = WBC_ERR_INVALID_PARAM;
1076 BAIL_ON_WBC_ERROR(wbc_status);
1079 if (params->old_password.response.old_lm_hash_enc_length == 0 &&
1080 params->old_password.response.old_lm_hash_enc_data) {
1081 wbc_status = WBC_ERR_INVALID_PARAM;
1082 BAIL_ON_WBC_ERROR(wbc_status);
1085 if (params->old_password.response.old_nt_hash_enc_length &&
1086 !params->old_password.response.old_nt_hash_enc_data) {
1087 wbc_status = WBC_ERR_INVALID_PARAM;
1088 BAIL_ON_WBC_ERROR(wbc_status);
1091 if (params->old_password.response.old_nt_hash_enc_length == 0 &&
1092 params->old_password.response.old_nt_hash_enc_data) {
1093 wbc_status = WBC_ERR_INVALID_PARAM;
1094 BAIL_ON_WBC_ERROR(wbc_status);
1097 if (params->new_password.response.lm_length &&
1098 !params->new_password.response.lm_data) {
1099 wbc_status = WBC_ERR_INVALID_PARAM;
1100 BAIL_ON_WBC_ERROR(wbc_status);
1103 if (params->new_password.response.lm_length == 0 &&
1104 params->new_password.response.lm_data) {
1105 wbc_status = WBC_ERR_INVALID_PARAM;
1106 BAIL_ON_WBC_ERROR(wbc_status);
1109 if (params->new_password.response.nt_length &&
1110 !params->new_password.response.nt_data) {
1111 wbc_status = WBC_ERR_INVALID_PARAM;
1112 BAIL_ON_WBC_ERROR(wbc_status);
1115 if (params->new_password.response.nt_length == 0 &&
1116 params->new_password.response.nt_data) {
1117 wbc_status = WBC_ERR_INVALID_PARAM;
1118 BAIL_ON_WBC_ERROR(wbc_status);
1121 strncpy(request.data.chng_pswd_auth_crap.user,
1122 params->account_name,
1123 sizeof(request.data.chng_pswd_auth_crap.user) - 1);
1125 strncpy(request.data.chng_pswd_auth_crap.domain,
1126 params->domain_name,
1127 sizeof(request.data.chng_pswd_auth_crap.domain) - 1);
1129 if (params->new_password.response.nt_data) {
1130 memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd,
1131 params->new_password.response.nt_data,
1132 request.data.chng_pswd_auth_crap.new_nt_pswd_len);
1133 request.data.chng_pswd_auth_crap.new_nt_pswd_len =
1134 params->new_password.response.nt_length;
1137 if (params->new_password.response.lm_data) {
1138 memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd,
1139 params->new_password.response.lm_data,
1140 request.data.chng_pswd_auth_crap.new_lm_pswd_len);
1141 request.data.chng_pswd_auth_crap.new_lm_pswd_len =
1142 params->new_password.response.lm_length;
1145 if (params->old_password.response.old_nt_hash_enc_data) {
1146 memcpy(request.data.chng_pswd_auth_crap.old_nt_hash_enc,
1147 params->old_password.response.old_nt_hash_enc_data,
1148 request.data.chng_pswd_auth_crap.old_nt_hash_enc_len);
1149 request.data.chng_pswd_auth_crap.old_nt_hash_enc_len =
1150 params->old_password.response.old_nt_hash_enc_length;
1153 if (params->old_password.response.old_lm_hash_enc_data) {
1154 memcpy(request.data.chng_pswd_auth_crap.old_lm_hash_enc,
1155 params->old_password.response.old_lm_hash_enc_data,
1156 request.data.chng_pswd_auth_crap.old_lm_hash_enc_len);
1157 request.data.chng_pswd_auth_crap.old_lm_hash_enc_len =
1158 params->old_password.response.old_lm_hash_enc_length;
1161 break;
1162 default:
1163 wbc_status = WBC_ERR_INVALID_PARAM;
1164 BAIL_ON_WBC_ERROR(wbc_status);
1165 break;
1168 /* Send request */
1170 wbc_status = wbcRequestResponse(cmd,
1171 &request,
1172 &response);
1173 if (WBC_ERROR_IS_OK(wbc_status)) {
1174 goto done;
1177 /* Take the response above and return it to the caller */
1179 if (response.data.auth.nt_status != 0) {
1180 if (error) {
1181 wbc_status = wbc_create_error_info(&response,
1182 error);
1183 BAIL_ON_WBC_ERROR(wbc_status);
1188 if (policy) {
1189 wbc_status = wbc_create_password_policy_info(&response,
1190 policy);
1191 BAIL_ON_WBC_ERROR(wbc_status);
1194 if (reject_reason) {
1195 *reject_reason = response.data.auth.reject_reason;
1198 wbc_status = WBC_ERR_PWD_CHANGE_FAILED;
1199 BAIL_ON_WBC_ERROR(wbc_status);
1201 done:
1202 return wbc_status;
1205 /* Change a password for a user */
1206 wbcErr wbcChangeUserPassword(const char *username,
1207 const char *old_password,
1208 const char *new_password)
1210 wbcErr wbc_status = WBC_ERR_SUCCESS;
1211 struct wbcChangePasswordParams params;
1213 ZERO_STRUCT(params);
1215 params.account_name = username;
1216 params.level = WBC_CHANGE_PASSWORD_LEVEL_PLAIN;
1217 params.old_password.plaintext = old_password;
1218 params.new_password.plaintext = new_password;
1220 wbc_status = wbcChangeUserPasswordEx(&params,
1221 NULL,
1222 NULL,
1223 NULL);
1224 BAIL_ON_WBC_ERROR(wbc_status);
1226 done:
1227 return wbc_status;
1230 /* Logon a User */
1231 wbcErr wbcLogonUser(const struct wbcLogonUserParams *params,
1232 struct wbcLogonUserInfo **info,
1233 struct wbcAuthErrorInfo **error,
1234 struct wbcUserPasswordPolicyInfo **policy)
1236 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
1237 int cmd = 0;
1238 struct winbindd_request request;
1239 struct winbindd_response response;
1240 uint32_t i;
1242 ZERO_STRUCT(request);
1243 ZERO_STRUCT(response);
1245 if (info) {
1246 *info = NULL;
1248 if (error) {
1249 *error = NULL;
1251 if (policy) {
1252 *policy = NULL;
1255 if (!params) {
1256 wbc_status = WBC_ERR_INVALID_PARAM;
1257 BAIL_ON_WBC_ERROR(wbc_status);
1260 if (!params->username) {
1261 wbc_status = WBC_ERR_INVALID_PARAM;
1262 BAIL_ON_WBC_ERROR(wbc_status);
1265 if ((params->num_blobs > 0) && (params->blobs == NULL)) {
1266 wbc_status = WBC_ERR_INVALID_PARAM;
1267 BAIL_ON_WBC_ERROR(wbc_status);
1269 if ((params->num_blobs == 0) && (params->blobs != NULL)) {
1270 wbc_status = WBC_ERR_INVALID_PARAM;
1271 BAIL_ON_WBC_ERROR(wbc_status);
1274 /* Initialize request */
1276 cmd = WINBINDD_PAM_AUTH;
1277 request.flags = WBFLAG_PAM_INFO3_TEXT |
1278 WBFLAG_PAM_USER_SESSION_KEY |
1279 WBFLAG_PAM_LMKEY;
1281 if (!params->password) {
1282 wbc_status = WBC_ERR_INVALID_PARAM;
1283 BAIL_ON_WBC_ERROR(wbc_status);
1286 strncpy(request.data.auth.user,
1287 params->username,
1288 sizeof(request.data.auth.user)-1);
1290 strncpy(request.data.auth.pass,
1291 params->password,
1292 sizeof(request.data.auth.pass)-1);
1294 for (i=0; i<params->num_blobs; i++) {
1296 if (strcasecmp(params->blobs[i].name, "krb5_cc_type") == 0) {
1297 if (params->blobs[i].blob.data) {
1298 strncpy(request.data.auth.krb5_cc_type,
1299 (const char *)params->blobs[i].blob.data,
1300 sizeof(request.data.auth.krb5_cc_type) - 1);
1302 continue;
1305 if (strcasecmp(params->blobs[i].name, "user_uid") == 0) {
1306 if (params->blobs[i].blob.data) {
1307 memcpy(&request.data.auth.uid,
1308 params->blobs[i].blob.data,
1309 MIN(sizeof(request.data.auth.uid),
1310 params->blobs[i].blob.length));
1312 continue;
1315 if (strcasecmp(params->blobs[i].name, "flags") == 0) {
1316 if (params->blobs[i].blob.data) {
1317 uint32_t flags;
1318 memcpy(&flags,
1319 params->blobs[i].blob.data,
1320 MIN(sizeof(flags),
1321 params->blobs[i].blob.length));
1322 request.flags |= flags;
1324 continue;
1327 if (strcasecmp(params->blobs[i].name, "membership_of") == 0) {
1328 if (params->blobs[i].blob.data &&
1329 params->blobs[i].blob.data[0] > 0) {
1330 strncpy(request.data.auth.require_membership_of_sid,
1331 (const char *)params->blobs[i].blob.data,
1332 sizeof(request.data.auth.require_membership_of_sid) - 1);
1334 continue;
1338 wbc_status = wbcRequestResponse(cmd,
1339 &request,
1340 &response);
1342 if (response.data.auth.nt_status != 0) {
1343 if (error) {
1344 wbc_status = wbc_create_error_info(&response,
1345 error);
1346 BAIL_ON_WBC_ERROR(wbc_status);
1349 wbc_status = WBC_ERR_AUTH_ERROR;
1350 BAIL_ON_WBC_ERROR(wbc_status);
1352 BAIL_ON_WBC_ERROR(wbc_status);
1354 if (info) {
1355 wbc_status = wbc_create_logon_info(&response,
1356 info);
1357 BAIL_ON_WBC_ERROR(wbc_status);
1360 if (policy) {
1361 wbc_status = wbc_create_password_policy_info(&response,
1362 policy);
1363 BAIL_ON_WBC_ERROR(wbc_status);
1366 done:
1367 winbindd_free_response(&response);
1369 return wbc_status;
1372 /* Authenticate a user with cached credentials */
1373 wbcErr wbcCredentialCache(struct wbcCredentialCacheParams *params,
1374 struct wbcCredentialCacheInfo **info,
1375 struct wbcAuthErrorInfo **error)
1377 wbcErr status = WBC_ERR_UNKNOWN_FAILURE;
1378 struct wbcCredentialCacheInfo *result = NULL;
1379 struct winbindd_request request;
1380 struct winbindd_response response;
1381 struct wbcNamedBlob *initial_blob = NULL;
1382 struct wbcNamedBlob *challenge_blob = NULL;
1383 int i;
1385 ZERO_STRUCT(request);
1386 ZERO_STRUCT(response);
1388 if (info != NULL) {
1389 *info = NULL;
1391 if (error != NULL) {
1392 *error = NULL;
1394 if ((params == NULL)
1395 || (params->account_name == NULL)
1396 || (params->level != WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP)) {
1397 status = WBC_ERR_INVALID_PARAM;
1398 goto fail;
1401 if (params->domain_name != NULL) {
1402 status = wbcRequestResponse(WINBINDD_INFO, NULL, &response);
1403 if (!WBC_ERROR_IS_OK(status)) {
1404 goto fail;
1406 snprintf(request.data.ccache_ntlm_auth.user,
1407 sizeof(request.data.ccache_ntlm_auth.user)-1,
1408 "%s%c%s", params->domain_name,
1409 response.data.info.winbind_separator,
1410 params->account_name);
1411 } else {
1412 strncpy(request.data.ccache_ntlm_auth.user,
1413 params->account_name,
1414 sizeof(request.data.ccache_ntlm_auth.user)-1);
1416 request.data.ccache_ntlm_auth.uid = getuid();
1418 for (i=0; i<params->num_blobs; i++) {
1419 if (strcasecmp(params->blobs[i].name, "initial_blob") == 0) {
1420 initial_blob = &params->blobs[i];
1421 break;
1423 if (strcasecmp(params->blobs[i].name, "challenge_blob") == 0) {
1424 challenge_blob = &params->blobs[i];
1425 break;
1429 request.data.ccache_ntlm_auth.initial_blob_len = 0;
1430 request.data.ccache_ntlm_auth.challenge_blob_len = 0;
1431 request.extra_len = 0;
1433 if (initial_blob != NULL) {
1434 request.data.ccache_ntlm_auth.initial_blob_len =
1435 initial_blob->blob.length;
1436 request.extra_len += initial_blob->blob.length;
1438 if (challenge_blob != NULL) {
1439 request.data.ccache_ntlm_auth.challenge_blob_len =
1440 challenge_blob->blob.length;
1441 request.extra_len += challenge_blob->blob.length;
1444 if (request.extra_len != 0) {
1445 request.extra_data.data = talloc_array(
1446 NULL, char, request.extra_len);
1447 if (request.extra_data.data == NULL) {
1448 status = WBC_ERR_NO_MEMORY;
1449 goto fail;
1452 if (initial_blob != NULL) {
1453 memcpy(request.extra_data.data,
1454 initial_blob->blob.data, initial_blob->blob.length);
1456 if (challenge_blob != NULL) {
1457 memcpy(request.extra_data.data
1458 + request.data.ccache_ntlm_auth.initial_blob_len,
1459 challenge_blob->blob.data,
1460 challenge_blob->blob.length);
1463 status = wbcRequestResponse(WINBINDD_CCACHE_NTLMAUTH, &request,
1464 &response);
1465 if (!WBC_ERROR_IS_OK(status)) {
1466 goto fail;
1469 result = talloc(NULL, struct wbcCredentialCacheInfo);
1470 if (result == NULL) {
1471 status = WBC_ERR_NO_MEMORY;
1472 goto fail;
1474 result->num_blobs = 0;
1475 result->blobs = talloc(result, struct wbcNamedBlob);
1476 if (result->blobs == NULL) {
1477 status = WBC_ERR_NO_MEMORY;
1478 goto fail;
1480 status = wbcAddNamedBlob(&result->num_blobs, &result->blobs,
1481 "auth_blob", 0,
1482 (uint8_t *)response.extra_data.data,
1483 response.data.ccache_ntlm_auth.auth_blob_len);
1484 if (!WBC_ERROR_IS_OK(status)) {
1485 goto fail;
1487 status = wbcAddNamedBlob(
1488 &result->num_blobs, &result->blobs, "session_key", 0,
1489 response.data.ccache_ntlm_auth.session_key,
1490 sizeof(response.data.ccache_ntlm_auth.session_key));
1491 if (!WBC_ERROR_IS_OK(status)) {
1492 goto fail;
1495 winbindd_free_response(&response);
1496 *info = result;
1497 return WBC_ERR_SUCCESS;
1499 fail:
1500 TALLOC_FREE(request.extra_data.data);
1501 winbindd_free_response(&response);
1502 talloc_free(result);
1503 return status;
1506 /* Authenticate a user with cached credentials */
1507 wbcErr wbcCredentialSave(const char *user, const char *password)
1509 struct winbindd_request request;
1510 struct winbindd_response response;
1512 ZERO_STRUCT(request);
1513 ZERO_STRUCT(response);
1515 strncpy(request.data.ccache_save.user, user,
1516 sizeof(request.data.ccache_save.user)-1);
1517 strncpy(request.data.ccache_save.pass, password,
1518 sizeof(request.data.ccache_save.pass)-1);
1519 request.data.ccache_save.uid = getuid();
1521 return wbcRequestResponse(WINBINDD_CCACHE_SAVE, &request, &response);