libwbclient: Make wbc_create_logon_info not use talloc
[Samba/ekacnet.git] / nsswitch / libwbclient / wbc_pam.c
blob892ccb7aa2e7bcc89ab5ac90a957fa34a71caff8
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 bool sid_attr_compose(struct wbcSidWithAttr *s,
51 const struct wbcDomainSid *d,
52 uint32_t rid, uint32_t attr)
54 if (d->num_auths >= WBC_MAXSUBAUTHS) {
55 return false;
57 s->sid = *d;
58 s->sid.sub_auths[s->sid.num_auths++] = rid;
59 s->attributes = attr;
60 return true;
63 static void wbcAuthUserInfoDestructor(void *ptr)
65 struct wbcAuthUserInfo *i = (struct wbcAuthUserInfo *)ptr;
66 free(i->account_name);
67 free(i->user_principal);
68 free(i->full_name);
69 free(i->domain_name);
70 free(i->dns_domain_name);
71 free(i->logon_server);
72 free(i->logon_script);
73 free(i->profile_path);
74 free(i->home_directory);
75 free(i->home_drive);
76 free(i->sids);
79 static wbcErr wbc_create_auth_info(const struct winbindd_response *resp,
80 struct wbcAuthUserInfo **_i)
82 wbcErr wbc_status = WBC_ERR_SUCCESS;
83 struct wbcAuthUserInfo *i;
84 struct wbcDomainSid domain_sid;
85 char *p;
86 uint32_t sn = 0;
87 uint32_t j;
89 i = (struct wbcAuthUserInfo *)wbcAllocateMemory(
90 sizeof(struct wbcAuthUserInfo), 1,
91 wbcAuthUserInfoDestructor);
92 BAIL_ON_PTR_ERROR(i, wbc_status);
94 i->user_flags = resp->data.auth.info3.user_flgs;
96 i->account_name = strdup(resp->data.auth.info3.user_name);
97 BAIL_ON_PTR_ERROR(i->account_name, wbc_status);
98 i->user_principal= NULL;
99 i->full_name = strdup(resp->data.auth.info3.full_name);
100 BAIL_ON_PTR_ERROR(i->full_name, wbc_status);
101 i->domain_name = strdup(resp->data.auth.info3.logon_dom);
102 BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
103 i->dns_domain_name= NULL;
105 i->acct_flags = resp->data.auth.info3.acct_flags;
106 memcpy(i->user_session_key,
107 resp->data.auth.user_session_key,
108 sizeof(i->user_session_key));
109 memcpy(i->lm_session_key,
110 resp->data.auth.first_8_lm_hash,
111 sizeof(i->lm_session_key));
113 i->logon_count = resp->data.auth.info3.logon_count;
114 i->bad_password_count = resp->data.auth.info3.bad_pw_count;
116 i->logon_time = resp->data.auth.info3.logon_time;
117 i->logoff_time = resp->data.auth.info3.logoff_time;
118 i->kickoff_time = resp->data.auth.info3.kickoff_time;
119 i->pass_last_set_time = resp->data.auth.info3.pass_last_set_time;
120 i->pass_can_change_time = resp->data.auth.info3.pass_can_change_time;
121 i->pass_must_change_time= resp->data.auth.info3.pass_must_change_time;
123 i->logon_server = strdup(resp->data.auth.info3.logon_srv);
124 BAIL_ON_PTR_ERROR(i->logon_server, wbc_status);
125 i->logon_script = strdup(resp->data.auth.info3.logon_script);
126 BAIL_ON_PTR_ERROR(i->logon_script, wbc_status);
127 i->profile_path = strdup(resp->data.auth.info3.profile_path);
128 BAIL_ON_PTR_ERROR(i->profile_path, wbc_status);
129 i->home_directory= strdup(resp->data.auth.info3.home_dir);
130 BAIL_ON_PTR_ERROR(i->home_directory, wbc_status);
131 i->home_drive = strdup(resp->data.auth.info3.dir_drive);
132 BAIL_ON_PTR_ERROR(i->home_drive, wbc_status);
134 i->num_sids = 2;
135 i->num_sids += resp->data.auth.info3.num_groups;
136 i->num_sids += resp->data.auth.info3.num_other_sids;
138 i->sids = (struct wbcSidWithAttr *)calloc(
139 sizeof(struct wbcSidWithAttr), i->num_sids);
140 BAIL_ON_PTR_ERROR(i->sids, wbc_status);
142 wbc_status = wbcStringToSid(resp->data.auth.info3.dom_sid,
143 &domain_sid);
144 BAIL_ON_WBC_ERROR(wbc_status);
146 sn = 0;
147 if (!sid_attr_compose(&i->sids[sn], &domain_sid,
148 resp->data.auth.info3.user_rid, 0)) {
149 wbc_status = WBC_ERR_INVALID_SID;
150 goto done;
152 sn++;
153 if (!sid_attr_compose(&i->sids[sn], &domain_sid,
154 resp->data.auth.info3.group_rid, 0)) {
155 wbc_status = WBC_ERR_INVALID_SID;
156 goto done;
158 sn++;
160 p = (char *)resp->extra_data.data;
161 if (!p) {
162 wbc_status = WBC_ERR_INVALID_RESPONSE;
163 BAIL_ON_WBC_ERROR(wbc_status);
166 for (j=0; j < resp->data.auth.info3.num_groups; j++) {
167 uint32_t rid;
168 uint32_t attrs;
169 int ret;
170 char *s = p;
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 ret = sscanf(s, "0x%08X:0x%08X", &rid, &attrs);
180 if (ret != 2) {
181 wbc_status = WBC_ERR_INVALID_RESPONSE;
182 BAIL_ON_WBC_ERROR(wbc_status);
185 if (!sid_attr_compose(&i->sids[sn], &domain_sid,
186 rid, attrs)) {
187 wbc_status = WBC_ERR_INVALID_SID;
188 goto done;
190 sn++;
193 for (j=0; j < resp->data.auth.info3.num_other_sids; j++) {
194 uint32_t attrs;
195 int ret;
196 char *s = p;
197 char *a;
198 char *e = strchr(p, '\n');
199 if (!e) {
200 wbc_status = WBC_ERR_INVALID_RESPONSE;
201 BAIL_ON_WBC_ERROR(wbc_status);
203 e[0] = '\0';
204 p = &e[1];
206 e = strchr(s, ':');
207 if (!e) {
208 wbc_status = WBC_ERR_INVALID_RESPONSE;
209 BAIL_ON_WBC_ERROR(wbc_status);
211 e[0] = '\0';
212 a = &e[1];
214 ret = sscanf(a, "0x%08X",
215 &attrs);
216 if (ret != 1) {
217 wbc_status = WBC_ERR_INVALID_RESPONSE;
218 BAIL_ON_WBC_ERROR(wbc_status);
221 wbc_status = wbcStringToSid(s, &i->sids[sn].sid);
222 BAIL_ON_WBC_ERROR(wbc_status);
224 i->sids[sn].attributes = attrs;
225 sn++;
228 i->num_sids = sn;
230 *_i = i;
231 i = NULL;
232 done:
233 wbcFreeMemory(i);
234 return wbc_status;
237 static wbcErr wbc_create_error_info(const struct winbindd_response *resp,
238 struct wbcAuthErrorInfo **_e)
240 wbcErr wbc_status = WBC_ERR_SUCCESS;
241 struct wbcAuthErrorInfo *e;
243 e = talloc(NULL, struct wbcAuthErrorInfo);
244 BAIL_ON_PTR_ERROR(e, wbc_status);
246 e->nt_status = resp->data.auth.nt_status;
247 e->pam_error = resp->data.auth.pam_error;
248 e->nt_string = talloc_strdup(e, resp->data.auth.nt_status_string);
249 BAIL_ON_PTR_ERROR(e->nt_string, wbc_status);
251 e->display_string = talloc_strdup(e, resp->data.auth.error_string);
252 BAIL_ON_PTR_ERROR(e->display_string, wbc_status);
254 *_e = e;
255 e = NULL;
257 done:
258 talloc_free(e);
259 return wbc_status;
262 static wbcErr wbc_create_password_policy_info(const struct winbindd_response *resp,
263 struct wbcUserPasswordPolicyInfo **_i)
265 wbcErr wbc_status = WBC_ERR_SUCCESS;
266 struct wbcUserPasswordPolicyInfo *i;
268 i = (struct wbcUserPasswordPolicyInfo *)wbcAllocateMemory(
269 sizeof(struct wbcUserPasswordPolicyInfo), 1, NULL);
270 BAIL_ON_PTR_ERROR(i, wbc_status);
272 i->min_passwordage = resp->data.auth.policy.min_passwordage;
273 i->min_length_password = resp->data.auth.policy.min_length_password;
274 i->password_history = resp->data.auth.policy.password_history;
275 i->password_properties = resp->data.auth.policy.password_properties;
276 i->expire = resp->data.auth.policy.expire;
278 *_i = i;
279 i = NULL;
281 done:
282 wbcFreeMemory(i);
283 return wbc_status;
286 static void wbcLogonUserInfoDestructor(void *ptr)
288 struct wbcLogonUserInfo *i = (struct wbcLogonUserInfo *)ptr;
289 wbcFreeMemory(i->info);
290 wbcFreeMemory(i->blobs);
293 static wbcErr wbc_create_logon_info(struct winbindd_response *resp,
294 struct wbcLogonUserInfo **_i)
296 wbcErr wbc_status = WBC_ERR_SUCCESS;
297 struct wbcLogonUserInfo *i;
299 i = (struct wbcLogonUserInfo *)wbcAllocateMemory(
300 sizeof(struct wbcLogonUserInfo), 1,
301 wbcLogonUserInfoDestructor);
302 BAIL_ON_PTR_ERROR(i, wbc_status);
304 wbc_status = wbc_create_auth_info(resp, &i->info);
305 BAIL_ON_WBC_ERROR(wbc_status);
307 if (resp->data.auth.krb5ccname &&
308 strlen(resp->data.auth.krb5ccname)) {
309 wbc_status = wbcAddNamedBlob(&i->num_blobs,
310 &i->blobs,
311 "krb5ccname",
313 (uint8_t *)resp->data.auth.krb5ccname,
314 strlen(resp->data.auth.krb5ccname)+1);
315 BAIL_ON_WBC_ERROR(wbc_status);
318 if (resp->data.auth.unix_username &&
319 strlen(resp->data.auth.unix_username)) {
320 wbc_status = wbcAddNamedBlob(&i->num_blobs,
321 &i->blobs,
322 "unix_username",
324 (uint8_t *)resp->data.auth.unix_username,
325 strlen(resp->data.auth.unix_username)+1);
326 BAIL_ON_WBC_ERROR(wbc_status);
329 *_i = i;
330 i = NULL;
331 done:
332 wbcFreeMemory(i);
333 return wbc_status;
337 /* Authenticate with more detailed information */
338 wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params,
339 struct wbcAuthUserInfo **info,
340 struct wbcAuthErrorInfo **error)
342 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
343 int cmd = 0;
344 struct winbindd_request request;
345 struct winbindd_response response;
347 ZERO_STRUCT(request);
348 ZERO_STRUCT(response);
350 if (error) {
351 *error = NULL;
354 if (!params) {
355 wbc_status = WBC_ERR_INVALID_PARAM;
356 BAIL_ON_WBC_ERROR(wbc_status);
359 if (!params->account_name) {
360 wbc_status = WBC_ERR_INVALID_PARAM;
361 BAIL_ON_WBC_ERROR(wbc_status);
364 /* Initialize request */
366 switch (params->level) {
367 case WBC_AUTH_USER_LEVEL_PLAIN:
368 cmd = WINBINDD_PAM_AUTH;
369 request.flags = WBFLAG_PAM_INFO3_TEXT |
370 WBFLAG_PAM_USER_SESSION_KEY |
371 WBFLAG_PAM_LMKEY;
373 if (!params->password.plaintext) {
374 wbc_status = WBC_ERR_INVALID_PARAM;
375 BAIL_ON_WBC_ERROR(wbc_status);
378 if (params->domain_name && params->domain_name[0]) {
379 /* We need to get the winbind separator :-( */
380 struct winbindd_response sep_response;
382 ZERO_STRUCT(sep_response);
384 wbc_status = wbcRequestResponse(WINBINDD_INFO,
385 NULL, &sep_response);
386 BAIL_ON_WBC_ERROR(wbc_status);
388 snprintf(request.data.auth.user,
389 sizeof(request.data.auth.user)-1,
390 "%s%c%s",
391 params->domain_name,
392 sep_response.data.info.winbind_separator,
393 params->account_name);
394 } else {
395 strncpy(request.data.auth.user,
396 params->account_name,
397 sizeof(request.data.auth.user)-1);
400 strncpy(request.data.auth.pass,
401 params->password.plaintext,
402 sizeof(request.data.auth.pass)-1);
403 break;
405 case WBC_AUTH_USER_LEVEL_HASH:
406 wbc_status = WBC_ERR_NOT_IMPLEMENTED;
407 BAIL_ON_WBC_ERROR(wbc_status);
408 break;
410 case WBC_AUTH_USER_LEVEL_RESPONSE:
411 cmd = WINBINDD_PAM_AUTH_CRAP;
412 request.flags = WBFLAG_PAM_INFO3_TEXT |
413 WBFLAG_PAM_USER_SESSION_KEY |
414 WBFLAG_PAM_LMKEY;
416 if (params->password.response.lm_length &&
417 !params->password.response.lm_data) {
418 wbc_status = WBC_ERR_INVALID_PARAM;
419 BAIL_ON_WBC_ERROR(wbc_status);
421 if (params->password.response.lm_length == 0 &&
422 params->password.response.lm_data) {
423 wbc_status = WBC_ERR_INVALID_PARAM;
424 BAIL_ON_WBC_ERROR(wbc_status);
427 if (params->password.response.nt_length &&
428 !params->password.response.nt_data) {
429 wbc_status = WBC_ERR_INVALID_PARAM;
430 BAIL_ON_WBC_ERROR(wbc_status);
432 if (params->password.response.nt_length == 0&&
433 params->password.response.nt_data) {
434 wbc_status = WBC_ERR_INVALID_PARAM;
435 BAIL_ON_WBC_ERROR(wbc_status);
438 strncpy(request.data.auth_crap.user,
439 params->account_name,
440 sizeof(request.data.auth_crap.user)-1);
441 if (params->domain_name) {
442 strncpy(request.data.auth_crap.domain,
443 params->domain_name,
444 sizeof(request.data.auth_crap.domain)-1);
446 if (params->workstation_name) {
447 strncpy(request.data.auth_crap.workstation,
448 params->workstation_name,
449 sizeof(request.data.auth_crap.workstation)-1);
452 request.data.auth_crap.logon_parameters =
453 params->parameter_control;
455 memcpy(request.data.auth_crap.chal,
456 params->password.response.challenge,
457 sizeof(request.data.auth_crap.chal));
459 request.data.auth_crap.lm_resp_len =
460 MIN(params->password.response.lm_length,
461 sizeof(request.data.auth_crap.lm_resp));
462 if (params->password.response.lm_data) {
463 memcpy(request.data.auth_crap.lm_resp,
464 params->password.response.lm_data,
465 request.data.auth_crap.lm_resp_len);
467 request.data.auth_crap.nt_resp_len = params->password.response.nt_length;
468 if (params->password.response.nt_length > sizeof(request.data.auth_crap.nt_resp)) {
469 request.flags |= WBFLAG_BIG_NTLMV2_BLOB;
470 request.extra_len = params->password.response.nt_length;
471 request.extra_data.data = talloc_zero_array(NULL, char, request.extra_len);
472 if (request.extra_data.data == NULL) {
473 wbc_status = WBC_ERR_NO_MEMORY;
474 BAIL_ON_WBC_ERROR(wbc_status);
476 memcpy(request.extra_data.data,
477 params->password.response.nt_data,
478 request.data.auth_crap.nt_resp_len);
479 } else if (params->password.response.nt_data) {
480 memcpy(request.data.auth_crap.nt_resp,
481 params->password.response.nt_data,
482 request.data.auth_crap.nt_resp_len);
484 break;
485 default:
486 break;
489 if (cmd == 0) {
490 wbc_status = WBC_ERR_INVALID_PARAM;
491 BAIL_ON_WBC_ERROR(wbc_status);
494 if (params->flags) {
495 request.flags |= params->flags;
498 if (cmd == WINBINDD_PAM_AUTH_CRAP) {
499 wbc_status = wbcRequestResponsePriv(cmd, &request, &response);
500 } else {
501 wbc_status = wbcRequestResponse(cmd, &request, &response);
503 if (response.data.auth.nt_status != 0) {
504 if (error) {
505 wbc_status = wbc_create_error_info(&response,
506 error);
507 BAIL_ON_WBC_ERROR(wbc_status);
510 wbc_status = WBC_ERR_AUTH_ERROR;
511 BAIL_ON_WBC_ERROR(wbc_status);
513 BAIL_ON_WBC_ERROR(wbc_status);
515 if (info) {
516 wbc_status = wbc_create_auth_info(&response, info);
517 BAIL_ON_WBC_ERROR(wbc_status);
520 done:
521 winbindd_free_response(&response);
523 talloc_free(request.extra_data.data);
525 return wbc_status;
528 /* Trigger a verification of the trust credentials of a specific domain */
529 wbcErr wbcCheckTrustCredentials(const char *domain,
530 struct wbcAuthErrorInfo **error)
532 struct winbindd_request request;
533 struct winbindd_response response;
534 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
536 ZERO_STRUCT(request);
537 ZERO_STRUCT(response);
539 if (domain) {
540 strncpy(request.domain_name, domain,
541 sizeof(request.domain_name)-1);
544 /* Send request */
546 wbc_status = wbcRequestResponsePriv(WINBINDD_CHECK_MACHACC,
547 &request, &response);
548 if (response.data.auth.nt_status != 0) {
549 if (error) {
550 wbc_status = wbc_create_error_info(&response,
551 error);
552 BAIL_ON_WBC_ERROR(wbc_status);
555 wbc_status = WBC_ERR_AUTH_ERROR;
556 BAIL_ON_WBC_ERROR(wbc_status);
558 BAIL_ON_WBC_ERROR(wbc_status);
560 done:
561 return wbc_status;
564 /* Trigger a change of the trust credentials for a specific domain */
565 wbcErr wbcChangeTrustCredentials(const char *domain,
566 struct wbcAuthErrorInfo **error)
568 struct winbindd_request request;
569 struct winbindd_response response;
570 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
572 ZERO_STRUCT(request);
573 ZERO_STRUCT(response);
575 if (domain) {
576 strncpy(request.domain_name, domain,
577 sizeof(request.domain_name)-1);
580 /* Send request */
582 wbc_status = wbcRequestResponsePriv(WINBINDD_CHANGE_MACHACC,
583 &request, &response);
584 if (response.data.auth.nt_status != 0) {
585 if (error) {
586 wbc_status = wbc_create_error_info(&response,
587 error);
588 BAIL_ON_WBC_ERROR(wbc_status);
591 wbc_status = WBC_ERR_AUTH_ERROR;
592 BAIL_ON_WBC_ERROR(wbc_status);
594 BAIL_ON_WBC_ERROR(wbc_status);
596 done:
597 return wbc_status;
601 * Trigger a no-op NETLOGON call. Lightweight version of
602 * wbcCheckTrustCredentials
604 wbcErr wbcPingDc(const char *domain, struct wbcAuthErrorInfo **error)
606 struct winbindd_request request;
607 struct winbindd_response response;
608 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
610 if (domain) {
612 * the current protocol doesn't support
613 * specifying a domain
615 wbc_status = WBC_ERR_NOT_IMPLEMENTED;
616 BAIL_ON_WBC_ERROR(wbc_status);
619 ZERO_STRUCT(request);
620 ZERO_STRUCT(response);
622 /* Send request */
624 wbc_status = wbcRequestResponse(WINBINDD_PING_DC,
625 &request,
626 &response);
627 if (response.data.auth.nt_status != 0) {
628 if (error) {
629 wbc_status = wbc_create_error_info(&response,
630 error);
631 BAIL_ON_WBC_ERROR(wbc_status);
634 wbc_status = WBC_ERR_AUTH_ERROR;
635 BAIL_ON_WBC_ERROR(wbc_status);
637 BAIL_ON_WBC_ERROR(wbc_status);
639 done:
640 return wbc_status;
643 /* Trigger an extended logoff notification to Winbind for a specific user */
644 wbcErr wbcLogoffUserEx(const struct wbcLogoffUserParams *params,
645 struct wbcAuthErrorInfo **error)
647 struct winbindd_request request;
648 struct winbindd_response response;
649 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
650 int i;
652 /* validate input */
654 if (!params || !params->username) {
655 wbc_status = WBC_ERR_INVALID_PARAM;
656 BAIL_ON_WBC_ERROR(wbc_status);
659 if ((params->num_blobs > 0) && (params->blobs == NULL)) {
660 wbc_status = WBC_ERR_INVALID_PARAM;
661 BAIL_ON_WBC_ERROR(wbc_status);
663 if ((params->num_blobs == 0) && (params->blobs != NULL)) {
664 wbc_status = WBC_ERR_INVALID_PARAM;
665 BAIL_ON_WBC_ERROR(wbc_status);
668 ZERO_STRUCT(request);
669 ZERO_STRUCT(response);
671 strncpy(request.data.logoff.user, params->username,
672 sizeof(request.data.logoff.user)-1);
674 for (i=0; i<params->num_blobs; i++) {
676 if (strcasecmp(params->blobs[i].name, "ccfilename") == 0) {
677 if (params->blobs[i].blob.data) {
678 strncpy(request.data.logoff.krb5ccname,
679 (const char *)params->blobs[i].blob.data,
680 sizeof(request.data.logoff.krb5ccname) - 1);
682 continue;
685 if (strcasecmp(params->blobs[i].name, "user_uid") == 0) {
686 if (params->blobs[i].blob.data) {
687 memcpy(&request.data.logoff.uid,
688 params->blobs[i].blob.data,
689 MIN(params->blobs[i].blob.length,
690 sizeof(request.data.logoff.uid)));
692 continue;
695 if (strcasecmp(params->blobs[i].name, "flags") == 0) {
696 if (params->blobs[i].blob.data) {
697 memcpy(&request.flags,
698 params->blobs[i].blob.data,
699 MIN(params->blobs[i].blob.length,
700 sizeof(request.flags)));
702 continue;
706 /* Send request */
708 wbc_status = wbcRequestResponse(WINBINDD_PAM_LOGOFF,
709 &request,
710 &response);
712 /* Take the response above and return it to the caller */
713 if (response.data.auth.nt_status != 0) {
714 if (error) {
715 wbc_status = wbc_create_error_info(&response,
716 error);
717 BAIL_ON_WBC_ERROR(wbc_status);
720 wbc_status = WBC_ERR_AUTH_ERROR;
721 BAIL_ON_WBC_ERROR(wbc_status);
723 BAIL_ON_WBC_ERROR(wbc_status);
725 done:
726 return wbc_status;
729 /* Trigger a logoff notification to Winbind for a specific user */
730 wbcErr wbcLogoffUser(const char *username,
731 uid_t uid,
732 const char *ccfilename)
734 struct winbindd_request request;
735 struct winbindd_response response;
736 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
738 /* validate input */
740 if (!username) {
741 wbc_status = WBC_ERR_INVALID_PARAM;
742 BAIL_ON_WBC_ERROR(wbc_status);
745 ZERO_STRUCT(request);
746 ZERO_STRUCT(response);
748 strncpy(request.data.logoff.user, username,
749 sizeof(request.data.logoff.user)-1);
750 request.data.logoff.uid = uid;
752 if (ccfilename) {
753 strncpy(request.data.logoff.krb5ccname, ccfilename,
754 sizeof(request.data.logoff.krb5ccname)-1);
757 /* Send request */
759 wbc_status = wbcRequestResponse(WINBINDD_PAM_LOGOFF,
760 &request,
761 &response);
763 /* Take the response above and return it to the caller */
765 done:
766 return wbc_status;
769 /* Change a password for a user with more detailed information upon failure */
770 wbcErr wbcChangeUserPasswordEx(const struct wbcChangePasswordParams *params,
771 struct wbcAuthErrorInfo **error,
772 enum wbcPasswordChangeRejectReason *reject_reason,
773 struct wbcUserPasswordPolicyInfo **policy)
775 struct winbindd_request request;
776 struct winbindd_response response;
777 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
778 int cmd = 0;
780 /* validate input */
782 if (!params->account_name) {
783 wbc_status = WBC_ERR_INVALID_PARAM;
784 BAIL_ON_WBC_ERROR(wbc_status);
787 if (error) {
788 *error = NULL;
791 if (policy) {
792 *policy = NULL;
795 if (reject_reason) {
796 *reject_reason = -1;
799 ZERO_STRUCT(request);
800 ZERO_STRUCT(response);
802 switch (params->level) {
803 case WBC_CHANGE_PASSWORD_LEVEL_PLAIN:
804 cmd = WINBINDD_PAM_CHAUTHTOK;
806 if (!params->account_name) {
807 wbc_status = WBC_ERR_INVALID_PARAM;
808 BAIL_ON_WBC_ERROR(wbc_status);
811 strncpy(request.data.chauthtok.user, params->account_name,
812 sizeof(request.data.chauthtok.user) - 1);
814 if (params->old_password.plaintext) {
815 strncpy(request.data.chauthtok.oldpass,
816 params->old_password.plaintext,
817 sizeof(request.data.chauthtok.oldpass) - 1);
820 if (params->new_password.plaintext) {
821 strncpy(request.data.chauthtok.newpass,
822 params->new_password.plaintext,
823 sizeof(request.data.chauthtok.newpass) - 1);
825 break;
827 case WBC_CHANGE_PASSWORD_LEVEL_RESPONSE:
828 cmd = WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP;
830 if (!params->account_name || !params->domain_name) {
831 wbc_status = WBC_ERR_INVALID_PARAM;
832 BAIL_ON_WBC_ERROR(wbc_status);
835 if (params->old_password.response.old_lm_hash_enc_length &&
836 !params->old_password.response.old_lm_hash_enc_data) {
837 wbc_status = WBC_ERR_INVALID_PARAM;
838 BAIL_ON_WBC_ERROR(wbc_status);
841 if (params->old_password.response.old_lm_hash_enc_length == 0 &&
842 params->old_password.response.old_lm_hash_enc_data) {
843 wbc_status = WBC_ERR_INVALID_PARAM;
844 BAIL_ON_WBC_ERROR(wbc_status);
847 if (params->old_password.response.old_nt_hash_enc_length &&
848 !params->old_password.response.old_nt_hash_enc_data) {
849 wbc_status = WBC_ERR_INVALID_PARAM;
850 BAIL_ON_WBC_ERROR(wbc_status);
853 if (params->old_password.response.old_nt_hash_enc_length == 0 &&
854 params->old_password.response.old_nt_hash_enc_data) {
855 wbc_status = WBC_ERR_INVALID_PARAM;
856 BAIL_ON_WBC_ERROR(wbc_status);
859 if (params->new_password.response.lm_length &&
860 !params->new_password.response.lm_data) {
861 wbc_status = WBC_ERR_INVALID_PARAM;
862 BAIL_ON_WBC_ERROR(wbc_status);
865 if (params->new_password.response.lm_length == 0 &&
866 params->new_password.response.lm_data) {
867 wbc_status = WBC_ERR_INVALID_PARAM;
868 BAIL_ON_WBC_ERROR(wbc_status);
871 if (params->new_password.response.nt_length &&
872 !params->new_password.response.nt_data) {
873 wbc_status = WBC_ERR_INVALID_PARAM;
874 BAIL_ON_WBC_ERROR(wbc_status);
877 if (params->new_password.response.nt_length == 0 &&
878 params->new_password.response.nt_data) {
879 wbc_status = WBC_ERR_INVALID_PARAM;
880 BAIL_ON_WBC_ERROR(wbc_status);
883 strncpy(request.data.chng_pswd_auth_crap.user,
884 params->account_name,
885 sizeof(request.data.chng_pswd_auth_crap.user) - 1);
887 strncpy(request.data.chng_pswd_auth_crap.domain,
888 params->domain_name,
889 sizeof(request.data.chng_pswd_auth_crap.domain) - 1);
891 if (params->new_password.response.nt_data) {
892 memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd,
893 params->new_password.response.nt_data,
894 request.data.chng_pswd_auth_crap.new_nt_pswd_len);
895 request.data.chng_pswd_auth_crap.new_nt_pswd_len =
896 params->new_password.response.nt_length;
899 if (params->new_password.response.lm_data) {
900 memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd,
901 params->new_password.response.lm_data,
902 request.data.chng_pswd_auth_crap.new_lm_pswd_len);
903 request.data.chng_pswd_auth_crap.new_lm_pswd_len =
904 params->new_password.response.lm_length;
907 if (params->old_password.response.old_nt_hash_enc_data) {
908 memcpy(request.data.chng_pswd_auth_crap.old_nt_hash_enc,
909 params->old_password.response.old_nt_hash_enc_data,
910 request.data.chng_pswd_auth_crap.old_nt_hash_enc_len);
911 request.data.chng_pswd_auth_crap.old_nt_hash_enc_len =
912 params->old_password.response.old_nt_hash_enc_length;
915 if (params->old_password.response.old_lm_hash_enc_data) {
916 memcpy(request.data.chng_pswd_auth_crap.old_lm_hash_enc,
917 params->old_password.response.old_lm_hash_enc_data,
918 request.data.chng_pswd_auth_crap.old_lm_hash_enc_len);
919 request.data.chng_pswd_auth_crap.old_lm_hash_enc_len =
920 params->old_password.response.old_lm_hash_enc_length;
923 break;
924 default:
925 wbc_status = WBC_ERR_INVALID_PARAM;
926 BAIL_ON_WBC_ERROR(wbc_status);
927 break;
930 /* Send request */
932 wbc_status = wbcRequestResponse(cmd,
933 &request,
934 &response);
935 if (WBC_ERROR_IS_OK(wbc_status)) {
936 goto done;
939 /* Take the response above and return it to the caller */
941 if (response.data.auth.nt_status != 0) {
942 if (error) {
943 wbc_status = wbc_create_error_info(&response,
944 error);
945 BAIL_ON_WBC_ERROR(wbc_status);
950 if (policy) {
951 wbc_status = wbc_create_password_policy_info(&response,
952 policy);
953 BAIL_ON_WBC_ERROR(wbc_status);
956 if (reject_reason) {
957 *reject_reason = response.data.auth.reject_reason;
960 wbc_status = WBC_ERR_PWD_CHANGE_FAILED;
961 BAIL_ON_WBC_ERROR(wbc_status);
963 done:
964 return wbc_status;
967 /* Change a password for a user */
968 wbcErr wbcChangeUserPassword(const char *username,
969 const char *old_password,
970 const char *new_password)
972 wbcErr wbc_status = WBC_ERR_SUCCESS;
973 struct wbcChangePasswordParams params;
975 ZERO_STRUCT(params);
977 params.account_name = username;
978 params.level = WBC_CHANGE_PASSWORD_LEVEL_PLAIN;
979 params.old_password.plaintext = old_password;
980 params.new_password.plaintext = new_password;
982 wbc_status = wbcChangeUserPasswordEx(&params,
983 NULL,
984 NULL,
985 NULL);
986 BAIL_ON_WBC_ERROR(wbc_status);
988 done:
989 return wbc_status;
992 /* Logon a User */
993 wbcErr wbcLogonUser(const struct wbcLogonUserParams *params,
994 struct wbcLogonUserInfo **info,
995 struct wbcAuthErrorInfo **error,
996 struct wbcUserPasswordPolicyInfo **policy)
998 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
999 struct winbindd_request request;
1000 struct winbindd_response response;
1001 uint32_t i;
1003 ZERO_STRUCT(request);
1004 ZERO_STRUCT(response);
1006 if (info) {
1007 *info = NULL;
1009 if (error) {
1010 *error = NULL;
1012 if (policy) {
1013 *policy = NULL;
1016 if (!params) {
1017 wbc_status = WBC_ERR_INVALID_PARAM;
1018 BAIL_ON_WBC_ERROR(wbc_status);
1021 if (!params->username) {
1022 wbc_status = WBC_ERR_INVALID_PARAM;
1023 BAIL_ON_WBC_ERROR(wbc_status);
1026 if ((params->num_blobs > 0) && (params->blobs == NULL)) {
1027 wbc_status = WBC_ERR_INVALID_PARAM;
1028 BAIL_ON_WBC_ERROR(wbc_status);
1030 if ((params->num_blobs == 0) && (params->blobs != NULL)) {
1031 wbc_status = WBC_ERR_INVALID_PARAM;
1032 BAIL_ON_WBC_ERROR(wbc_status);
1035 /* Initialize request */
1037 request.flags = WBFLAG_PAM_INFO3_TEXT |
1038 WBFLAG_PAM_USER_SESSION_KEY |
1039 WBFLAG_PAM_LMKEY;
1041 if (!params->password) {
1042 wbc_status = WBC_ERR_INVALID_PARAM;
1043 BAIL_ON_WBC_ERROR(wbc_status);
1046 strncpy(request.data.auth.user,
1047 params->username,
1048 sizeof(request.data.auth.user)-1);
1050 strncpy(request.data.auth.pass,
1051 params->password,
1052 sizeof(request.data.auth.pass)-1);
1054 for (i=0; i<params->num_blobs; i++) {
1056 if (strcasecmp(params->blobs[i].name, "krb5_cc_type") == 0) {
1057 if (params->blobs[i].blob.data) {
1058 strncpy(request.data.auth.krb5_cc_type,
1059 (const char *)params->blobs[i].blob.data,
1060 sizeof(request.data.auth.krb5_cc_type) - 1);
1062 continue;
1065 if (strcasecmp(params->blobs[i].name, "user_uid") == 0) {
1066 if (params->blobs[i].blob.data) {
1067 memcpy(&request.data.auth.uid,
1068 params->blobs[i].blob.data,
1069 MIN(sizeof(request.data.auth.uid),
1070 params->blobs[i].blob.length));
1072 continue;
1075 if (strcasecmp(params->blobs[i].name, "flags") == 0) {
1076 if (params->blobs[i].blob.data) {
1077 uint32_t flags;
1078 memcpy(&flags,
1079 params->blobs[i].blob.data,
1080 MIN(sizeof(flags),
1081 params->blobs[i].blob.length));
1082 request.flags |= flags;
1084 continue;
1087 if (strcasecmp(params->blobs[i].name, "membership_of") == 0) {
1088 if (params->blobs[i].blob.data &&
1089 params->blobs[i].blob.data[0] > 0) {
1090 strncpy(request.data.auth.require_membership_of_sid,
1091 (const char *)params->blobs[i].blob.data,
1092 sizeof(request.data.auth.require_membership_of_sid) - 1);
1094 continue;
1098 wbc_status = wbcRequestResponse(WINBINDD_PAM_AUTH,
1099 &request,
1100 &response);
1102 if (response.data.auth.nt_status != 0) {
1103 if (error) {
1104 wbc_status = wbc_create_error_info(&response,
1105 error);
1106 BAIL_ON_WBC_ERROR(wbc_status);
1109 wbc_status = WBC_ERR_AUTH_ERROR;
1110 BAIL_ON_WBC_ERROR(wbc_status);
1112 BAIL_ON_WBC_ERROR(wbc_status);
1114 if (info) {
1115 wbc_status = wbc_create_logon_info(&response,
1116 info);
1117 BAIL_ON_WBC_ERROR(wbc_status);
1120 if (policy) {
1121 wbc_status = wbc_create_password_policy_info(&response,
1122 policy);
1123 BAIL_ON_WBC_ERROR(wbc_status);
1126 done:
1127 winbindd_free_response(&response);
1129 return wbc_status;
1132 /* Authenticate a user with cached credentials */
1133 wbcErr wbcCredentialCache(struct wbcCredentialCacheParams *params,
1134 struct wbcCredentialCacheInfo **info,
1135 struct wbcAuthErrorInfo **error)
1137 wbcErr status = WBC_ERR_UNKNOWN_FAILURE;
1138 struct wbcCredentialCacheInfo *result = NULL;
1139 struct winbindd_request request;
1140 struct winbindd_response response;
1141 struct wbcNamedBlob *initial_blob = NULL;
1142 struct wbcNamedBlob *challenge_blob = NULL;
1143 int i;
1145 ZERO_STRUCT(request);
1146 ZERO_STRUCT(response);
1148 if (info != NULL) {
1149 *info = NULL;
1151 if (error != NULL) {
1152 *error = NULL;
1154 if ((params == NULL)
1155 || (params->account_name == NULL)
1156 || (params->level != WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP)) {
1157 status = WBC_ERR_INVALID_PARAM;
1158 goto fail;
1161 if (params->domain_name != NULL) {
1162 status = wbcRequestResponse(WINBINDD_INFO, NULL, &response);
1163 if (!WBC_ERROR_IS_OK(status)) {
1164 goto fail;
1166 snprintf(request.data.ccache_ntlm_auth.user,
1167 sizeof(request.data.ccache_ntlm_auth.user)-1,
1168 "%s%c%s", params->domain_name,
1169 response.data.info.winbind_separator,
1170 params->account_name);
1171 } else {
1172 strncpy(request.data.ccache_ntlm_auth.user,
1173 params->account_name,
1174 sizeof(request.data.ccache_ntlm_auth.user)-1);
1176 request.data.ccache_ntlm_auth.uid = getuid();
1178 for (i=0; i<params->num_blobs; i++) {
1179 if (strcasecmp(params->blobs[i].name, "initial_blob") == 0) {
1180 initial_blob = &params->blobs[i];
1181 break;
1183 if (strcasecmp(params->blobs[i].name, "challenge_blob") == 0) {
1184 challenge_blob = &params->blobs[i];
1185 break;
1189 request.data.ccache_ntlm_auth.initial_blob_len = 0;
1190 request.data.ccache_ntlm_auth.challenge_blob_len = 0;
1191 request.extra_len = 0;
1193 if (initial_blob != NULL) {
1194 request.data.ccache_ntlm_auth.initial_blob_len =
1195 initial_blob->blob.length;
1196 request.extra_len += initial_blob->blob.length;
1198 if (challenge_blob != NULL) {
1199 request.data.ccache_ntlm_auth.challenge_blob_len =
1200 challenge_blob->blob.length;
1201 request.extra_len += challenge_blob->blob.length;
1204 if (request.extra_len != 0) {
1205 request.extra_data.data = talloc_array(
1206 NULL, char, request.extra_len);
1207 if (request.extra_data.data == NULL) {
1208 status = WBC_ERR_NO_MEMORY;
1209 goto fail;
1212 if (initial_blob != NULL) {
1213 memcpy(request.extra_data.data,
1214 initial_blob->blob.data, initial_blob->blob.length);
1216 if (challenge_blob != NULL) {
1217 memcpy(request.extra_data.data
1218 + request.data.ccache_ntlm_auth.initial_blob_len,
1219 challenge_blob->blob.data,
1220 challenge_blob->blob.length);
1223 status = wbcRequestResponse(WINBINDD_CCACHE_NTLMAUTH, &request,
1224 &response);
1225 if (!WBC_ERROR_IS_OK(status)) {
1226 goto fail;
1229 result = talloc(NULL, struct wbcCredentialCacheInfo);
1230 if (result == NULL) {
1231 status = WBC_ERR_NO_MEMORY;
1232 goto fail;
1234 result->num_blobs = 0;
1235 result->blobs = talloc(result, struct wbcNamedBlob);
1236 if (result->blobs == NULL) {
1237 status = WBC_ERR_NO_MEMORY;
1238 goto fail;
1240 status = wbcAddNamedBlob(&result->num_blobs, &result->blobs,
1241 "auth_blob", 0,
1242 (uint8_t *)response.extra_data.data,
1243 response.data.ccache_ntlm_auth.auth_blob_len);
1244 if (!WBC_ERROR_IS_OK(status)) {
1245 goto fail;
1247 status = wbcAddNamedBlob(
1248 &result->num_blobs, &result->blobs, "session_key", 0,
1249 response.data.ccache_ntlm_auth.session_key,
1250 sizeof(response.data.ccache_ntlm_auth.session_key));
1251 if (!WBC_ERROR_IS_OK(status)) {
1252 goto fail;
1255 *info = result;
1256 result = NULL;
1257 status = WBC_ERR_SUCCESS;
1258 fail:
1259 TALLOC_FREE(request.extra_data.data);
1260 winbindd_free_response(&response);
1261 talloc_free(result);
1262 return status;
1265 /* Authenticate a user with cached credentials */
1266 wbcErr wbcCredentialSave(const char *user, const char *password)
1268 struct winbindd_request request;
1269 struct winbindd_response response;
1271 ZERO_STRUCT(request);
1272 ZERO_STRUCT(response);
1274 strncpy(request.data.ccache_save.user, user,
1275 sizeof(request.data.ccache_save.user)-1);
1276 strncpy(request.data.ccache_save.pass, password,
1277 sizeof(request.data.ccache_save.pass)-1);
1278 request.data.ccache_save.uid = getuid();
1280 return wbcRequestResponse(WINBINDD_CCACHE_SAVE, &request, &response);