s4:rpc_server/samr: use the same logic in *info_DomInfo7() as in info_DomGeneralInfor...
[Samba.git] / nsswitch / libwbclient / wbc_pam.c
blob672cf3733420bea827fff8965cba49d09d08075f
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 wbcCtxAuthenticateUser(struct wbcContext *ctx,
32 const char *username, 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 = wbcCtxAuthenticateUserEx(ctx, &params, NULL, NULL);
44 BAIL_ON_WBC_ERROR(wbc_status);
46 done:
47 return wbc_status;
50 wbcErr wbcAuthenticateUser(const char *username, const char *password)
52 return wbcCtxAuthenticateUser(NULL, username, password);
55 static bool sid_attr_compose(struct wbcSidWithAttr *s,
56 const struct wbcDomainSid *d,
57 uint32_t rid, uint32_t attr)
59 if (d->num_auths >= WBC_MAXSUBAUTHS) {
60 return false;
62 s->sid = *d;
63 s->sid.sub_auths[s->sid.num_auths++] = rid;
64 s->attributes = attr;
65 return true;
68 static void wbcAuthUserInfoDestructor(void *ptr)
70 struct wbcAuthUserInfo *i = (struct wbcAuthUserInfo *)ptr;
71 free(i->account_name);
72 free(i->user_principal);
73 free(i->full_name);
74 free(i->domain_name);
75 free(i->dns_domain_name);
76 free(i->logon_server);
77 free(i->logon_script);
78 free(i->profile_path);
79 free(i->home_directory);
80 free(i->home_drive);
81 free(i->sids);
84 static wbcErr wbc_create_auth_info(const struct winbindd_response *resp,
85 struct wbcAuthUserInfo **_i)
87 wbcErr wbc_status = WBC_ERR_SUCCESS;
88 struct wbcAuthUserInfo *i;
89 struct wbcDomainSid domain_sid;
90 char *p;
91 uint32_t sn = 0;
92 uint32_t j;
94 i = (struct wbcAuthUserInfo *)wbcAllocateMemory(
95 1, sizeof(struct wbcAuthUserInfo),
96 wbcAuthUserInfoDestructor);
97 BAIL_ON_PTR_ERROR(i, wbc_status);
99 i->user_flags = resp->data.auth.info3.user_flgs;
101 i->account_name = strdup(resp->data.auth.info3.user_name);
102 BAIL_ON_PTR_ERROR(i->account_name, wbc_status);
103 i->user_principal= NULL;
104 i->full_name = strdup(resp->data.auth.info3.full_name);
105 BAIL_ON_PTR_ERROR(i->full_name, wbc_status);
106 i->domain_name = strdup(resp->data.auth.info3.logon_dom);
107 BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
108 i->dns_domain_name= NULL;
110 i->acct_flags = resp->data.auth.info3.acct_flags;
111 memcpy(i->user_session_key,
112 resp->data.auth.user_session_key,
113 sizeof(i->user_session_key));
114 memcpy(i->lm_session_key,
115 resp->data.auth.first_8_lm_hash,
116 sizeof(i->lm_session_key));
118 i->logon_count = resp->data.auth.info3.logon_count;
119 i->bad_password_count = resp->data.auth.info3.bad_pw_count;
121 i->logon_time = resp->data.auth.info3.logon_time;
122 i->logoff_time = resp->data.auth.info3.logoff_time;
123 i->kickoff_time = resp->data.auth.info3.kickoff_time;
124 i->pass_last_set_time = resp->data.auth.info3.pass_last_set_time;
125 i->pass_can_change_time = resp->data.auth.info3.pass_can_change_time;
126 i->pass_must_change_time= resp->data.auth.info3.pass_must_change_time;
128 i->logon_server = strdup(resp->data.auth.info3.logon_srv);
129 BAIL_ON_PTR_ERROR(i->logon_server, wbc_status);
130 i->logon_script = strdup(resp->data.auth.info3.logon_script);
131 BAIL_ON_PTR_ERROR(i->logon_script, wbc_status);
132 i->profile_path = strdup(resp->data.auth.info3.profile_path);
133 BAIL_ON_PTR_ERROR(i->profile_path, wbc_status);
134 i->home_directory= strdup(resp->data.auth.info3.home_dir);
135 BAIL_ON_PTR_ERROR(i->home_directory, wbc_status);
136 i->home_drive = strdup(resp->data.auth.info3.dir_drive);
137 BAIL_ON_PTR_ERROR(i->home_drive, wbc_status);
139 i->num_sids = 2;
140 i->num_sids += resp->data.auth.info3.num_groups;
141 i->num_sids += resp->data.auth.info3.num_other_sids;
143 i->sids = (struct wbcSidWithAttr *)calloc(
144 sizeof(struct wbcSidWithAttr), i->num_sids);
145 BAIL_ON_PTR_ERROR(i->sids, wbc_status);
147 wbc_status = wbcStringToSid(resp->data.auth.info3.dom_sid,
148 &domain_sid);
149 BAIL_ON_WBC_ERROR(wbc_status);
151 sn = 0;
152 if (!sid_attr_compose(&i->sids[sn], &domain_sid,
153 resp->data.auth.info3.user_rid, 0)) {
154 wbc_status = WBC_ERR_INVALID_SID;
155 goto done;
157 sn++;
158 if (!sid_attr_compose(&i->sids[sn], &domain_sid,
159 resp->data.auth.info3.group_rid, 0)) {
160 wbc_status = WBC_ERR_INVALID_SID;
161 goto done;
163 sn++;
165 p = (char *)resp->extra_data.data;
166 if (!p) {
167 wbc_status = WBC_ERR_INVALID_RESPONSE;
168 BAIL_ON_WBC_ERROR(wbc_status);
171 for (j=0; j < resp->data.auth.info3.num_groups; j++) {
172 uint32_t rid;
173 uint32_t attrs;
174 int ret;
175 char *s = p;
176 char *e = strchr(p, '\n');
177 if (!e) {
178 wbc_status = WBC_ERR_INVALID_RESPONSE;
179 BAIL_ON_WBC_ERROR(wbc_status);
181 e[0] = '\0';
182 p = &e[1];
184 ret = sscanf(s, "0x%08X:0x%08X", &rid, &attrs);
185 if (ret != 2) {
186 wbc_status = WBC_ERR_INVALID_RESPONSE;
187 BAIL_ON_WBC_ERROR(wbc_status);
190 if (!sid_attr_compose(&i->sids[sn], &domain_sid,
191 rid, attrs)) {
192 wbc_status = WBC_ERR_INVALID_SID;
193 goto done;
195 sn++;
198 for (j=0; j < resp->data.auth.info3.num_other_sids; j++) {
199 uint32_t attrs;
200 int ret;
201 char *s = p;
202 char *a;
203 char *e = strchr(p, '\n');
204 if (!e) {
205 wbc_status = WBC_ERR_INVALID_RESPONSE;
206 BAIL_ON_WBC_ERROR(wbc_status);
208 e[0] = '\0';
209 p = &e[1];
211 e = strchr(s, ':');
212 if (!e) {
213 wbc_status = WBC_ERR_INVALID_RESPONSE;
214 BAIL_ON_WBC_ERROR(wbc_status);
216 e[0] = '\0';
217 a = &e[1];
219 ret = sscanf(a, "0x%08X",
220 &attrs);
221 if (ret != 1) {
222 wbc_status = WBC_ERR_INVALID_RESPONSE;
223 BAIL_ON_WBC_ERROR(wbc_status);
226 wbc_status = wbcStringToSid(s, &i->sids[sn].sid);
227 BAIL_ON_WBC_ERROR(wbc_status);
229 i->sids[sn].attributes = attrs;
230 sn++;
233 i->num_sids = sn;
235 *_i = i;
236 i = NULL;
237 done:
238 wbcFreeMemory(i);
239 return wbc_status;
242 static void wbcAuthErrorInfoDestructor(void *ptr)
244 struct wbcAuthErrorInfo *e = (struct wbcAuthErrorInfo *)ptr;
245 free(e->nt_string);
246 free(e->display_string);
249 static wbcErr wbc_create_error_info(const struct winbindd_response *resp,
250 struct wbcAuthErrorInfo **_e)
252 wbcErr wbc_status = WBC_ERR_SUCCESS;
253 struct wbcAuthErrorInfo *e;
255 e = (struct wbcAuthErrorInfo *)wbcAllocateMemory(
256 1, sizeof(struct wbcAuthErrorInfo),
257 wbcAuthErrorInfoDestructor);
258 BAIL_ON_PTR_ERROR(e, wbc_status);
260 e->nt_status = resp->data.auth.nt_status;
261 e->pam_error = resp->data.auth.pam_error;
262 e->nt_string = strdup(resp->data.auth.nt_status_string);
263 BAIL_ON_PTR_ERROR(e->nt_string, wbc_status);
265 e->display_string = strdup(resp->data.auth.error_string);
266 BAIL_ON_PTR_ERROR(e->display_string, wbc_status);
268 *_e = e;
269 e = NULL;
271 done:
272 wbcFreeMemory(e);
273 return wbc_status;
276 static wbcErr wbc_create_password_policy_info(const struct winbindd_response *resp,
277 struct wbcUserPasswordPolicyInfo **_i)
279 wbcErr wbc_status = WBC_ERR_SUCCESS;
280 struct wbcUserPasswordPolicyInfo *i;
282 i = (struct wbcUserPasswordPolicyInfo *)wbcAllocateMemory(
283 1, sizeof(struct wbcUserPasswordPolicyInfo), NULL);
284 BAIL_ON_PTR_ERROR(i, wbc_status);
286 i->min_passwordage = resp->data.auth.policy.min_passwordage;
287 i->min_length_password = resp->data.auth.policy.min_length_password;
288 i->password_history = resp->data.auth.policy.password_history;
289 i->password_properties = resp->data.auth.policy.password_properties;
290 i->expire = resp->data.auth.policy.expire;
292 *_i = i;
293 i = NULL;
295 done:
296 wbcFreeMemory(i);
297 return wbc_status;
300 static void wbcLogonUserInfoDestructor(void *ptr)
302 struct wbcLogonUserInfo *i = (struct wbcLogonUserInfo *)ptr;
303 wbcFreeMemory(i->info);
304 wbcFreeMemory(i->blobs);
307 static wbcErr wbc_create_logon_info(struct winbindd_response *resp,
308 struct wbcLogonUserInfo **_i)
310 wbcErr wbc_status = WBC_ERR_SUCCESS;
311 struct wbcLogonUserInfo *i;
313 i = (struct wbcLogonUserInfo *)wbcAllocateMemory(
314 1, sizeof(struct wbcLogonUserInfo),
315 wbcLogonUserInfoDestructor);
316 BAIL_ON_PTR_ERROR(i, wbc_status);
318 wbc_status = wbc_create_auth_info(resp, &i->info);
319 BAIL_ON_WBC_ERROR(wbc_status);
321 if (resp->data.auth.krb5ccname[0] != '\0') {
322 wbc_status = wbcAddNamedBlob(&i->num_blobs,
323 &i->blobs,
324 "krb5ccname",
326 (uint8_t *)resp->data.auth.krb5ccname,
327 strlen(resp->data.auth.krb5ccname)+1);
328 BAIL_ON_WBC_ERROR(wbc_status);
331 if (resp->data.auth.unix_username[0] != '\0') {
332 wbc_status = wbcAddNamedBlob(&i->num_blobs,
333 &i->blobs,
334 "unix_username",
336 (uint8_t *)resp->data.auth.unix_username,
337 strlen(resp->data.auth.unix_username)+1);
338 BAIL_ON_WBC_ERROR(wbc_status);
341 *_i = i;
342 i = NULL;
343 done:
344 wbcFreeMemory(i);
345 return wbc_status;
349 /* Authenticate with more detailed information */
350 wbcErr wbcCtxAuthenticateUserEx(struct wbcContext *ctx,
351 const struct wbcAuthUserParams *params,
352 struct wbcAuthUserInfo **info,
353 struct wbcAuthErrorInfo **error)
355 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
356 int cmd = 0;
357 struct winbindd_request request;
358 struct winbindd_response response;
360 ZERO_STRUCT(request);
361 ZERO_STRUCT(response);
363 if (error) {
364 *error = NULL;
367 if (!params) {
368 wbc_status = WBC_ERR_INVALID_PARAM;
369 BAIL_ON_WBC_ERROR(wbc_status);
372 if (params->level != WBC_AUTH_USER_LEVEL_PAC && !params->account_name) {
373 wbc_status = WBC_ERR_INVALID_PARAM;
374 BAIL_ON_WBC_ERROR(wbc_status);
377 /* Initialize request */
379 switch (params->level) {
380 case WBC_AUTH_USER_LEVEL_PLAIN:
381 cmd = WINBINDD_PAM_AUTH;
382 request.flags = WBFLAG_PAM_INFO3_TEXT |
383 WBFLAG_PAM_USER_SESSION_KEY |
384 WBFLAG_PAM_LMKEY;
386 if (!params->password.plaintext) {
387 wbc_status = WBC_ERR_INVALID_PARAM;
388 BAIL_ON_WBC_ERROR(wbc_status);
391 if (params->domain_name && params->domain_name[0]) {
392 /* We need to get the winbind separator :-( */
393 struct winbindd_response sep_response;
395 ZERO_STRUCT(sep_response);
397 wbc_status = wbcRequestResponse(ctx, WINBINDD_INFO,
398 NULL, &sep_response);
399 BAIL_ON_WBC_ERROR(wbc_status);
401 snprintf(request.data.auth.user,
402 sizeof(request.data.auth.user)-1,
403 "%s%c%s",
404 params->domain_name,
405 sep_response.data.info.winbind_separator,
406 params->account_name);
407 } else {
408 strncpy(request.data.auth.user,
409 params->account_name,
410 sizeof(request.data.auth.user)-1);
413 strncpy(request.data.auth.pass,
414 params->password.plaintext,
415 sizeof(request.data.auth.pass)-1);
416 break;
418 case WBC_AUTH_USER_LEVEL_HASH:
419 wbc_status = WBC_ERR_NOT_IMPLEMENTED;
420 BAIL_ON_WBC_ERROR(wbc_status);
421 break;
423 case WBC_AUTH_USER_LEVEL_RESPONSE:
424 cmd = WINBINDD_PAM_AUTH_CRAP;
425 request.flags = WBFLAG_PAM_INFO3_TEXT |
426 WBFLAG_PAM_USER_SESSION_KEY |
427 WBFLAG_PAM_LMKEY;
429 if (params->password.response.lm_length &&
430 !params->password.response.lm_data) {
431 wbc_status = WBC_ERR_INVALID_PARAM;
432 BAIL_ON_WBC_ERROR(wbc_status);
434 if (params->password.response.lm_length == 0 &&
435 params->password.response.lm_data) {
436 wbc_status = WBC_ERR_INVALID_PARAM;
437 BAIL_ON_WBC_ERROR(wbc_status);
440 if (params->password.response.nt_length &&
441 !params->password.response.nt_data) {
442 wbc_status = WBC_ERR_INVALID_PARAM;
443 BAIL_ON_WBC_ERROR(wbc_status);
445 if (params->password.response.nt_length == 0&&
446 params->password.response.nt_data) {
447 wbc_status = WBC_ERR_INVALID_PARAM;
448 BAIL_ON_WBC_ERROR(wbc_status);
451 strncpy(request.data.auth_crap.user,
452 params->account_name,
453 sizeof(request.data.auth_crap.user)-1);
454 if (params->domain_name) {
455 strncpy(request.data.auth_crap.domain,
456 params->domain_name,
457 sizeof(request.data.auth_crap.domain)-1);
459 if (params->workstation_name) {
460 strncpy(request.data.auth_crap.workstation,
461 params->workstation_name,
462 sizeof(request.data.auth_crap.workstation)-1);
465 request.data.auth_crap.logon_parameters =
466 params->parameter_control;
468 memcpy(request.data.auth_crap.chal,
469 params->password.response.challenge,
470 sizeof(request.data.auth_crap.chal));
472 request.data.auth_crap.lm_resp_len =
473 MIN(params->password.response.lm_length,
474 sizeof(request.data.auth_crap.lm_resp));
475 if (params->password.response.lm_data) {
476 memcpy(request.data.auth_crap.lm_resp,
477 params->password.response.lm_data,
478 request.data.auth_crap.lm_resp_len);
480 request.data.auth_crap.nt_resp_len = params->password.response.nt_length;
481 if (params->password.response.nt_length > sizeof(request.data.auth_crap.nt_resp)) {
482 request.flags |= WBFLAG_BIG_NTLMV2_BLOB;
483 request.extra_len = params->password.response.nt_length;
484 request.extra_data.data = (char *)malloc(
485 request.extra_len);
486 if (request.extra_data.data == NULL) {
487 wbc_status = WBC_ERR_NO_MEMORY;
488 BAIL_ON_WBC_ERROR(wbc_status);
490 memcpy(request.extra_data.data,
491 params->password.response.nt_data,
492 request.data.auth_crap.nt_resp_len);
493 } else if (params->password.response.nt_data) {
494 memcpy(request.data.auth_crap.nt_resp,
495 params->password.response.nt_data,
496 request.data.auth_crap.nt_resp_len);
498 break;
500 case WBC_AUTH_USER_LEVEL_PAC:
501 cmd = WINBINDD_PAM_AUTH_CRAP;
502 request.flags = WBFLAG_PAM_AUTH_PAC | WBFLAG_PAM_INFO3_TEXT;
503 request.extra_data.data = malloc(params->password.pac.length);
504 if (request.extra_data.data == NULL) {
505 wbc_status = WBC_ERR_NO_MEMORY;
506 BAIL_ON_WBC_ERROR(wbc_status);
508 memcpy(request.extra_data.data, params->password.pac.data,
509 params->password.pac.length);
510 request.extra_len = params->password.pac.length;
511 break;
513 default:
514 break;
517 if (cmd == 0) {
518 wbc_status = WBC_ERR_INVALID_PARAM;
519 BAIL_ON_WBC_ERROR(wbc_status);
522 if (params->flags) {
523 request.flags |= params->flags;
526 if (cmd == WINBINDD_PAM_AUTH_CRAP) {
527 wbc_status = wbcRequestResponsePriv(ctx, cmd,
528 &request, &response);
529 } else {
530 wbc_status = wbcRequestResponse(ctx, cmd,
531 &request, &response);
533 if (response.data.auth.nt_status != 0) {
534 if (error) {
535 wbc_status = wbc_create_error_info(&response,
536 error);
537 BAIL_ON_WBC_ERROR(wbc_status);
540 wbc_status = WBC_ERR_AUTH_ERROR;
541 BAIL_ON_WBC_ERROR(wbc_status);
543 BAIL_ON_WBC_ERROR(wbc_status);
545 if (info) {
546 wbc_status = wbc_create_auth_info(&response, info);
547 BAIL_ON_WBC_ERROR(wbc_status);
550 done:
551 winbindd_free_response(&response);
553 free(request.extra_data.data);
555 return wbc_status;
558 wbcErr wbcAuthenticateUserEx(const struct wbcAuthUserParams *params,
559 struct wbcAuthUserInfo **info,
560 struct wbcAuthErrorInfo **error)
562 return wbcCtxAuthenticateUserEx(NULL, params, info, error);
565 /* Trigger a verification of the trust credentials of a specific domain */
566 wbcErr wbcCtxCheckTrustCredentials(struct wbcContext *ctx, const char *domain,
567 struct wbcAuthErrorInfo **error)
569 struct winbindd_request request;
570 struct winbindd_response response;
571 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
573 ZERO_STRUCT(request);
574 ZERO_STRUCT(response);
576 if (domain) {
577 strncpy(request.domain_name, domain,
578 sizeof(request.domain_name)-1);
581 /* Send request */
583 wbc_status = wbcRequestResponsePriv(ctx, WINBINDD_CHECK_MACHACC,
584 &request, &response);
585 if (response.data.auth.nt_status != 0) {
586 if (error) {
587 wbc_status = wbc_create_error_info(&response,
588 error);
589 BAIL_ON_WBC_ERROR(wbc_status);
592 wbc_status = WBC_ERR_AUTH_ERROR;
593 BAIL_ON_WBC_ERROR(wbc_status);
595 BAIL_ON_WBC_ERROR(wbc_status);
597 done:
598 return wbc_status;
601 wbcErr wbcCheckTrustCredentials(const char *domain,
602 struct wbcAuthErrorInfo **error)
604 return wbcCtxCheckTrustCredentials(NULL, domain, error);
607 /* Trigger a change of the trust credentials for a specific domain */
608 wbcErr wbcCtxChangeTrustCredentials(struct wbcContext *ctx, const char *domain,
609 struct wbcAuthErrorInfo **error)
611 struct winbindd_request request;
612 struct winbindd_response response;
613 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
615 ZERO_STRUCT(request);
616 ZERO_STRUCT(response);
618 if (domain) {
619 strncpy(request.domain_name, domain,
620 sizeof(request.domain_name)-1);
623 /* Send request */
625 wbc_status = wbcRequestResponsePriv(ctx, WINBINDD_CHANGE_MACHACC,
626 &request, &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 wbcErr wbcChangeTrustCredentials(const char *domain,
644 struct wbcAuthErrorInfo **error)
646 return wbcCtxChangeTrustCredentials(NULL, domain, error);
650 * Trigger a no-op NETLOGON call. Lightweight version of
651 * wbcCheckTrustCredentials
653 wbcErr wbcCtxPingDc(struct wbcContext *ctx, const char *domain,
654 struct wbcAuthErrorInfo **error)
656 return wbcCtxPingDc2(ctx, domain, error, NULL);
659 wbcErr wbcPingDc(const char *domain, struct wbcAuthErrorInfo **error)
661 return wbcPingDc2(domain, error, NULL);
665 * Trigger a no-op NETLOGON call. Lightweight version of
666 * wbcCheckTrustCredentials, optionally return attempted DC
668 wbcErr wbcCtxPingDc2(struct wbcContext *ctx, const char *domain,
669 struct wbcAuthErrorInfo **error, char **dcname)
671 struct winbindd_request request;
672 struct winbindd_response response;
673 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
675 ZERO_STRUCT(request);
676 ZERO_STRUCT(response);
678 if (domain) {
679 strncpy(request.domain_name, domain,
680 sizeof(request.domain_name)-1);
683 /* Send request */
685 wbc_status = wbcRequestResponse(ctx, WINBINDD_PING_DC,
686 &request,
687 &response);
689 if (dcname && response.extra_data.data) {
690 size_t len;
692 len = response.length - sizeof(struct winbindd_response);
693 *dcname = wbcAllocateMemory(1, len, NULL);
694 BAIL_ON_PTR_ERROR(*dcname, wbc_status);
696 strlcpy(*dcname, response.extra_data.data, len);
699 if (response.data.auth.nt_status != 0) {
700 if (error) {
701 wbc_status = wbc_create_error_info(&response,
702 error);
703 BAIL_ON_WBC_ERROR(wbc_status);
706 wbc_status = WBC_ERR_AUTH_ERROR;
707 BAIL_ON_WBC_ERROR(wbc_status);
709 BAIL_ON_WBC_ERROR(wbc_status);
711 done:
712 return wbc_status;
715 wbcErr wbcPingDc2(const char *domain, struct wbcAuthErrorInfo **error,
716 char **dcname)
718 return wbcCtxPingDc2(NULL, domain, error, dcname);
721 /* Trigger an extended logoff notification to Winbind for a specific user */
722 wbcErr wbcCtxLogoffUserEx(struct wbcContext *ctx,
723 const struct wbcLogoffUserParams *params,
724 struct wbcAuthErrorInfo **error)
726 struct winbindd_request request;
727 struct winbindd_response response;
728 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
729 int i;
731 /* validate input */
733 if (!params || !params->username) {
734 wbc_status = WBC_ERR_INVALID_PARAM;
735 BAIL_ON_WBC_ERROR(wbc_status);
738 if ((params->num_blobs > 0) && (params->blobs == NULL)) {
739 wbc_status = WBC_ERR_INVALID_PARAM;
740 BAIL_ON_WBC_ERROR(wbc_status);
742 if ((params->num_blobs == 0) && (params->blobs != NULL)) {
743 wbc_status = WBC_ERR_INVALID_PARAM;
744 BAIL_ON_WBC_ERROR(wbc_status);
747 ZERO_STRUCT(request);
748 ZERO_STRUCT(response);
750 strncpy(request.data.logoff.user, params->username,
751 sizeof(request.data.logoff.user)-1);
753 for (i=0; i<params->num_blobs; i++) {
755 if (strcasecmp(params->blobs[i].name, "ccfilename") == 0) {
756 if (params->blobs[i].blob.data) {
757 strncpy(request.data.logoff.krb5ccname,
758 (const char *)params->blobs[i].blob.data,
759 sizeof(request.data.logoff.krb5ccname) - 1);
761 continue;
764 if (strcasecmp(params->blobs[i].name, "user_uid") == 0) {
765 if (params->blobs[i].blob.data) {
766 memcpy(&request.data.logoff.uid,
767 params->blobs[i].blob.data,
768 MIN(params->blobs[i].blob.length,
769 sizeof(request.data.logoff.uid)));
771 continue;
774 if (strcasecmp(params->blobs[i].name, "flags") == 0) {
775 if (params->blobs[i].blob.data) {
776 memcpy(&request.flags,
777 params->blobs[i].blob.data,
778 MIN(params->blobs[i].blob.length,
779 sizeof(request.flags)));
781 continue;
785 /* Send request */
787 wbc_status = wbcRequestResponse(ctx, WINBINDD_PAM_LOGOFF,
788 &request,
789 &response);
791 /* Take the response above and return it to the caller */
792 if (response.data.auth.nt_status != 0) {
793 if (error) {
794 wbc_status = wbc_create_error_info(&response,
795 error);
796 BAIL_ON_WBC_ERROR(wbc_status);
799 wbc_status = WBC_ERR_AUTH_ERROR;
800 BAIL_ON_WBC_ERROR(wbc_status);
802 BAIL_ON_WBC_ERROR(wbc_status);
804 done:
805 return wbc_status;
808 wbcErr wbcLogoffUserEx(const struct wbcLogoffUserParams *params,
809 struct wbcAuthErrorInfo **error)
811 return wbcCtxLogoffUserEx(NULL, params, error);
814 /* Trigger a logoff notification to Winbind for a specific user */
815 wbcErr wbcCtxLogoffUser(struct wbcContext *ctx,
816 const char *username, uid_t uid,
817 const char *ccfilename)
819 struct winbindd_request request;
820 struct winbindd_response response;
821 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
823 /* validate input */
825 if (!username) {
826 wbc_status = WBC_ERR_INVALID_PARAM;
827 BAIL_ON_WBC_ERROR(wbc_status);
830 ZERO_STRUCT(request);
831 ZERO_STRUCT(response);
833 strncpy(request.data.logoff.user, username,
834 sizeof(request.data.logoff.user)-1);
835 request.data.logoff.uid = uid;
837 if (ccfilename) {
838 strncpy(request.data.logoff.krb5ccname, ccfilename,
839 sizeof(request.data.logoff.krb5ccname)-1);
842 /* Send request */
844 wbc_status = wbcRequestResponse(ctx, WINBINDD_PAM_LOGOFF,
845 &request,
846 &response);
848 /* Take the response above and return it to the caller */
850 done:
851 return wbc_status;
854 wbcErr wbcLogoffUser(const char *username,
855 uid_t uid,
856 const char *ccfilename)
858 return wbcCtxLogoffUser(NULL, username, uid, ccfilename);
861 /* Change a password for a user with more detailed information upon failure */
862 wbcErr wbcCtxChangeUserPasswordEx(struct wbcContext *ctx,
863 const struct wbcChangePasswordParams *params,
864 struct wbcAuthErrorInfo **error,
865 enum wbcPasswordChangeRejectReason *reject_reason,
866 struct wbcUserPasswordPolicyInfo **policy)
868 struct winbindd_request request;
869 struct winbindd_response response;
870 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
871 int cmd = 0;
873 /* validate input */
875 if (!params->account_name) {
876 wbc_status = WBC_ERR_INVALID_PARAM;
877 goto done;
880 if (error) {
881 *error = NULL;
884 if (policy) {
885 *policy = NULL;
888 if (reject_reason) {
889 *reject_reason = -1;
892 ZERO_STRUCT(request);
893 ZERO_STRUCT(response);
895 switch (params->level) {
896 case WBC_CHANGE_PASSWORD_LEVEL_PLAIN:
897 cmd = WINBINDD_PAM_CHAUTHTOK;
899 if (!params->account_name) {
900 wbc_status = WBC_ERR_INVALID_PARAM;
901 goto done;
904 strncpy(request.data.chauthtok.user, params->account_name,
905 sizeof(request.data.chauthtok.user) - 1);
907 if (params->old_password.plaintext) {
908 strncpy(request.data.chauthtok.oldpass,
909 params->old_password.plaintext,
910 sizeof(request.data.chauthtok.oldpass) - 1);
913 if (params->new_password.plaintext) {
914 strncpy(request.data.chauthtok.newpass,
915 params->new_password.plaintext,
916 sizeof(request.data.chauthtok.newpass) - 1);
918 break;
920 case WBC_CHANGE_PASSWORD_LEVEL_RESPONSE:
921 cmd = WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP;
923 if (!params->account_name || !params->domain_name) {
924 wbc_status = WBC_ERR_INVALID_PARAM;
925 goto done;
928 if (params->old_password.response.old_lm_hash_enc_length &&
929 !params->old_password.response.old_lm_hash_enc_data) {
930 wbc_status = WBC_ERR_INVALID_PARAM;
931 goto done;
934 if (params->old_password.response.old_lm_hash_enc_length == 0 &&
935 params->old_password.response.old_lm_hash_enc_data) {
936 wbc_status = WBC_ERR_INVALID_PARAM;
937 goto done;
940 if (params->old_password.response.old_nt_hash_enc_length &&
941 !params->old_password.response.old_nt_hash_enc_data) {
942 wbc_status = WBC_ERR_INVALID_PARAM;
943 goto done;
946 if (params->old_password.response.old_nt_hash_enc_length == 0 &&
947 params->old_password.response.old_nt_hash_enc_data) {
948 wbc_status = WBC_ERR_INVALID_PARAM;
949 goto done;
952 if (params->new_password.response.lm_length &&
953 !params->new_password.response.lm_data) {
954 wbc_status = WBC_ERR_INVALID_PARAM;
955 goto done;
958 if (params->new_password.response.lm_length == 0 &&
959 params->new_password.response.lm_data) {
960 wbc_status = WBC_ERR_INVALID_PARAM;
961 goto done;
964 if (params->new_password.response.nt_length &&
965 !params->new_password.response.nt_data) {
966 wbc_status = WBC_ERR_INVALID_PARAM;
967 goto done;
970 if (params->new_password.response.nt_length == 0 &&
971 params->new_password.response.nt_data) {
972 wbc_status = WBC_ERR_INVALID_PARAM;
973 goto done;
976 strncpy(request.data.chng_pswd_auth_crap.user,
977 params->account_name,
978 sizeof(request.data.chng_pswd_auth_crap.user) - 1);
980 strncpy(request.data.chng_pswd_auth_crap.domain,
981 params->domain_name,
982 sizeof(request.data.chng_pswd_auth_crap.domain) - 1);
984 if (params->new_password.response.nt_data) {
985 request.data.chng_pswd_auth_crap.new_nt_pswd_len =
986 params->new_password.response.nt_length;
987 memcpy(request.data.chng_pswd_auth_crap.new_nt_pswd,
988 params->new_password.response.nt_data,
989 request.data.chng_pswd_auth_crap.new_nt_pswd_len);
992 if (params->new_password.response.lm_data) {
993 request.data.chng_pswd_auth_crap.new_lm_pswd_len =
994 params->new_password.response.lm_length;
995 memcpy(request.data.chng_pswd_auth_crap.new_lm_pswd,
996 params->new_password.response.lm_data,
997 request.data.chng_pswd_auth_crap.new_lm_pswd_len);
1000 if (params->old_password.response.old_nt_hash_enc_data) {
1001 request.data.chng_pswd_auth_crap.old_nt_hash_enc_len =
1002 params->old_password.response.old_nt_hash_enc_length;
1003 memcpy(request.data.chng_pswd_auth_crap.old_nt_hash_enc,
1004 params->old_password.response.old_nt_hash_enc_data,
1005 request.data.chng_pswd_auth_crap.old_nt_hash_enc_len);
1008 if (params->old_password.response.old_lm_hash_enc_data) {
1009 request.data.chng_pswd_auth_crap.old_lm_hash_enc_len =
1010 params->old_password.response.old_lm_hash_enc_length;
1011 memcpy(request.data.chng_pswd_auth_crap.old_lm_hash_enc,
1012 params->old_password.response.old_lm_hash_enc_data,
1013 request.data.chng_pswd_auth_crap.old_lm_hash_enc_len);
1016 break;
1017 default:
1018 wbc_status = WBC_ERR_INVALID_PARAM;
1019 goto done;
1020 break;
1023 /* Send request */
1025 wbc_status = wbcRequestResponse(ctx, cmd,
1026 &request,
1027 &response);
1028 if (WBC_ERROR_IS_OK(wbc_status)) {
1029 goto done;
1032 /* Take the response above and return it to the caller */
1034 if (response.data.auth.nt_status != 0) {
1035 if (error) {
1036 wbc_status = wbc_create_error_info(&response,
1037 error);
1038 BAIL_ON_WBC_ERROR(wbc_status);
1043 if (policy) {
1044 wbc_status = wbc_create_password_policy_info(&response,
1045 policy);
1046 BAIL_ON_WBC_ERROR(wbc_status);
1049 if (reject_reason) {
1050 *reject_reason = response.data.auth.reject_reason;
1053 wbc_status = WBC_ERR_PWD_CHANGE_FAILED;
1054 BAIL_ON_WBC_ERROR(wbc_status);
1056 done:
1057 return wbc_status;
1060 wbcErr wbcChangeUserPasswordEx(const struct wbcChangePasswordParams *params,
1061 struct wbcAuthErrorInfo **error,
1062 enum wbcPasswordChangeRejectReason *reject_reason,
1063 struct wbcUserPasswordPolicyInfo **policy)
1065 return wbcCtxChangeUserPasswordEx(NULL, params, error,
1066 reject_reason, policy);
1069 /* Change a password for a user */
1070 wbcErr wbcCtxChangeUserPassword(struct wbcContext *ctx,
1071 const char *username,
1072 const char *old_password,
1073 const char *new_password)
1075 wbcErr wbc_status = WBC_ERR_SUCCESS;
1076 struct wbcChangePasswordParams params;
1078 ZERO_STRUCT(params);
1080 params.account_name = username;
1081 params.level = WBC_CHANGE_PASSWORD_LEVEL_PLAIN;
1082 params.old_password.plaintext = old_password;
1083 params.new_password.plaintext = new_password;
1085 wbc_status = wbcCtxChangeUserPasswordEx(ctx, &params,
1086 NULL,
1087 NULL,
1088 NULL);
1089 BAIL_ON_WBC_ERROR(wbc_status);
1091 done:
1092 return wbc_status;
1095 wbcErr wbcChangeUserPassword(const char *username,
1096 const char *old_password,
1097 const char *new_password)
1099 return wbcCtxChangeUserPassword(NULL, username,
1100 old_password, new_password);
1103 /* Logon a User */
1104 wbcErr wbcCtxLogonUser(struct wbcContext *ctx,
1105 const struct wbcLogonUserParams *params,
1106 struct wbcLogonUserInfo **info,
1107 struct wbcAuthErrorInfo **error,
1108 struct wbcUserPasswordPolicyInfo **policy)
1110 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
1111 struct winbindd_request request;
1112 struct winbindd_response response;
1113 uint32_t i;
1115 ZERO_STRUCT(request);
1116 ZERO_STRUCT(response);
1118 if (info) {
1119 *info = NULL;
1121 if (error) {
1122 *error = NULL;
1124 if (policy) {
1125 *policy = NULL;
1128 if (!params) {
1129 wbc_status = WBC_ERR_INVALID_PARAM;
1130 BAIL_ON_WBC_ERROR(wbc_status);
1133 if (!params->username) {
1134 wbc_status = WBC_ERR_INVALID_PARAM;
1135 BAIL_ON_WBC_ERROR(wbc_status);
1138 if ((params->num_blobs > 0) && (params->blobs == NULL)) {
1139 wbc_status = WBC_ERR_INVALID_PARAM;
1140 BAIL_ON_WBC_ERROR(wbc_status);
1142 if ((params->num_blobs == 0) && (params->blobs != NULL)) {
1143 wbc_status = WBC_ERR_INVALID_PARAM;
1144 BAIL_ON_WBC_ERROR(wbc_status);
1147 /* Initialize request */
1149 request.flags = WBFLAG_PAM_INFO3_TEXT |
1150 WBFLAG_PAM_USER_SESSION_KEY |
1151 WBFLAG_PAM_LMKEY;
1153 if (!params->password) {
1154 wbc_status = WBC_ERR_INVALID_PARAM;
1155 BAIL_ON_WBC_ERROR(wbc_status);
1158 strncpy(request.data.auth.user,
1159 params->username,
1160 sizeof(request.data.auth.user)-1);
1162 strncpy(request.data.auth.pass,
1163 params->password,
1164 sizeof(request.data.auth.pass)-1);
1166 for (i=0; i<params->num_blobs; i++) {
1168 if (strcasecmp(params->blobs[i].name, "krb5_cc_type") == 0) {
1169 if (params->blobs[i].blob.data) {
1170 strncpy(request.data.auth.krb5_cc_type,
1171 (const char *)params->blobs[i].blob.data,
1172 sizeof(request.data.auth.krb5_cc_type) - 1);
1174 continue;
1177 if (strcasecmp(params->blobs[i].name, "user_uid") == 0) {
1178 if (params->blobs[i].blob.data) {
1179 memcpy(&request.data.auth.uid,
1180 params->blobs[i].blob.data,
1181 MIN(sizeof(request.data.auth.uid),
1182 params->blobs[i].blob.length));
1184 continue;
1187 if (strcasecmp(params->blobs[i].name, "flags") == 0) {
1188 if (params->blobs[i].blob.data) {
1189 uint32_t flags;
1190 memcpy(&flags,
1191 params->blobs[i].blob.data,
1192 MIN(sizeof(flags),
1193 params->blobs[i].blob.length));
1194 request.flags |= flags;
1196 continue;
1199 if (strcasecmp(params->blobs[i].name, "membership_of") == 0) {
1200 if (params->blobs[i].blob.data &&
1201 params->blobs[i].blob.data[0] > 0) {
1202 strncpy(request.data.auth.require_membership_of_sid,
1203 (const char *)params->blobs[i].blob.data,
1204 sizeof(request.data.auth.require_membership_of_sid) - 1);
1206 continue;
1210 wbc_status = wbcRequestResponse(ctx, WINBINDD_PAM_AUTH,
1211 &request,
1212 &response);
1214 if (response.data.auth.nt_status != 0) {
1215 if (error) {
1216 wbc_status = wbc_create_error_info(&response,
1217 error);
1218 BAIL_ON_WBC_ERROR(wbc_status);
1221 wbc_status = WBC_ERR_AUTH_ERROR;
1222 BAIL_ON_WBC_ERROR(wbc_status);
1224 BAIL_ON_WBC_ERROR(wbc_status);
1226 if (info) {
1227 wbc_status = wbc_create_logon_info(&response,
1228 info);
1229 BAIL_ON_WBC_ERROR(wbc_status);
1232 if (policy) {
1233 wbc_status = wbc_create_password_policy_info(&response,
1234 policy);
1235 BAIL_ON_WBC_ERROR(wbc_status);
1238 done:
1239 winbindd_free_response(&response);
1241 return wbc_status;
1244 wbcErr wbcLogonUser(const struct wbcLogonUserParams *params,
1245 struct wbcLogonUserInfo **info,
1246 struct wbcAuthErrorInfo **error,
1247 struct wbcUserPasswordPolicyInfo **policy)
1249 return wbcCtxLogonUser(NULL, params, info, error, policy);
1252 static void wbcCredentialCacheInfoDestructor(void *ptr)
1254 struct wbcCredentialCacheInfo *i =
1255 (struct wbcCredentialCacheInfo *)ptr;
1256 wbcFreeMemory(i->blobs);
1259 /* Authenticate a user with cached credentials */
1260 wbcErr wbcCtxCredentialCache(struct wbcContext *ctx,
1261 struct wbcCredentialCacheParams *params,
1262 struct wbcCredentialCacheInfo **info,
1263 struct wbcAuthErrorInfo **error)
1265 wbcErr status = WBC_ERR_UNKNOWN_FAILURE;
1266 struct wbcCredentialCacheInfo *result = NULL;
1267 struct winbindd_request request;
1268 struct winbindd_response response;
1269 struct wbcNamedBlob *initial_blob = NULL;
1270 struct wbcNamedBlob *challenge_blob = NULL;
1271 int i;
1273 ZERO_STRUCT(request);
1274 ZERO_STRUCT(response);
1276 *info = NULL;
1278 if (error != NULL) {
1279 *error = NULL;
1281 if ((params == NULL)
1282 || (params->account_name == NULL)
1283 || (params->level != WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP)) {
1284 status = WBC_ERR_INVALID_PARAM;
1285 goto fail;
1288 for (i=0; i<params->num_blobs; i++) {
1289 if (strcasecmp(params->blobs[i].name, "initial_blob") == 0) {
1290 if (initial_blob != NULL) {
1291 status = WBC_ERR_INVALID_PARAM;
1292 goto fail;
1294 initial_blob = &params->blobs[i];
1295 continue;
1297 if (strcasecmp(params->blobs[i].name, "challenge_blob") == 0) {
1298 if (challenge_blob != NULL) {
1299 status = WBC_ERR_INVALID_PARAM;
1300 goto fail;
1302 challenge_blob = &params->blobs[i];
1303 continue;
1307 if (params->domain_name != NULL) {
1308 status = wbcRequestResponse(ctx, WINBINDD_INFO,
1309 NULL, &response);
1310 if (!WBC_ERROR_IS_OK(status)) {
1311 goto fail;
1313 snprintf(request.data.ccache_ntlm_auth.user,
1314 sizeof(request.data.ccache_ntlm_auth.user)-1,
1315 "%s%c%s", params->domain_name,
1316 response.data.info.winbind_separator,
1317 params->account_name);
1318 } else {
1319 strncpy(request.data.ccache_ntlm_auth.user,
1320 params->account_name,
1321 sizeof(request.data.ccache_ntlm_auth.user)-1);
1323 request.data.ccache_ntlm_auth.uid = getuid();
1325 request.data.ccache_ntlm_auth.initial_blob_len = 0;
1326 request.data.ccache_ntlm_auth.challenge_blob_len = 0;
1327 request.extra_len = 0;
1329 if (initial_blob != NULL) {
1330 request.data.ccache_ntlm_auth.initial_blob_len =
1331 initial_blob->blob.length;
1332 request.extra_len += initial_blob->blob.length;
1334 if (challenge_blob != NULL) {
1335 request.data.ccache_ntlm_auth.challenge_blob_len =
1336 challenge_blob->blob.length;
1337 request.extra_len += challenge_blob->blob.length;
1340 if (request.extra_len != 0) {
1341 request.extra_data.data = (char *)malloc(request.extra_len);
1342 if (request.extra_data.data == NULL) {
1343 status = WBC_ERR_NO_MEMORY;
1344 goto fail;
1347 if (initial_blob != NULL) {
1348 memcpy(request.extra_data.data,
1349 initial_blob->blob.data, initial_blob->blob.length);
1351 if (challenge_blob != NULL) {
1352 memcpy(request.extra_data.data
1353 + request.data.ccache_ntlm_auth.initial_blob_len,
1354 challenge_blob->blob.data,
1355 challenge_blob->blob.length);
1358 status = wbcRequestResponse(ctx, WINBINDD_CCACHE_NTLMAUTH,
1359 &request, &response);
1360 if (!WBC_ERROR_IS_OK(status)) {
1361 goto fail;
1364 result = (struct wbcCredentialCacheInfo *)wbcAllocateMemory(
1365 1, sizeof(struct wbcCredentialCacheInfo),
1366 wbcCredentialCacheInfoDestructor);
1367 if (result == NULL) {
1368 status = WBC_ERR_NO_MEMORY;
1369 goto fail;
1371 result->num_blobs = 0;
1372 result->blobs = NULL;
1373 status = wbcAddNamedBlob(&result->num_blobs, &result->blobs,
1374 "auth_blob", 0,
1375 (uint8_t *)response.extra_data.data,
1376 response.data.ccache_ntlm_auth.auth_blob_len);
1377 if (!WBC_ERROR_IS_OK(status)) {
1378 goto fail;
1380 status = wbcAddNamedBlob(
1381 &result->num_blobs, &result->blobs, "session_key", 0,
1382 response.data.ccache_ntlm_auth.session_key,
1383 sizeof(response.data.ccache_ntlm_auth.session_key));
1384 if (!WBC_ERROR_IS_OK(status)) {
1385 goto fail;
1388 *info = result;
1389 result = NULL;
1390 status = WBC_ERR_SUCCESS;
1391 fail:
1392 free(request.extra_data.data);
1393 winbindd_free_response(&response);
1394 wbcFreeMemory(result);
1395 return status;
1398 wbcErr wbcCredentialCache(struct wbcCredentialCacheParams *params,
1399 struct wbcCredentialCacheInfo **info,
1400 struct wbcAuthErrorInfo **error)
1402 return wbcCtxCredentialCache(NULL, params, info, error);
1405 /* Authenticate a user with cached credentials */
1406 wbcErr wbcCtxCredentialSave(struct wbcContext *ctx,
1407 const char *user, const char *password)
1409 struct winbindd_request request;
1410 struct winbindd_response response;
1412 ZERO_STRUCT(request);
1413 ZERO_STRUCT(response);
1415 strncpy(request.data.ccache_save.user, user,
1416 sizeof(request.data.ccache_save.user)-1);
1417 strncpy(request.data.ccache_save.pass, password,
1418 sizeof(request.data.ccache_save.pass)-1);
1419 request.data.ccache_save.uid = getuid();
1421 return wbcRequestResponse(ctx, WINBINDD_CCACHE_SAVE, &request, &response);
1424 wbcErr wbcCredentialSave(const char *user, const char *password)
1426 return wbcCtxCredentialSave(NULL, user, password);