2 Unix SMB/CIFS implementation.
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 */
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
;
39 params
.account_name
= username
;
40 params
.level
= WBC_AUTH_USER_LEVEL_PLAIN
;
41 params
.password
.plaintext
= password
;
43 wbc_status
= wbcCtxAuthenticateUserEx(ctx
, ¶ms
, NULL
, NULL
);
44 BAIL_ON_WBC_ERROR(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
) {
63 s
->sid
.sub_auths
[s
->sid
.num_auths
++] = rid
;
68 static void wbcAuthUserInfoDestructor(void *ptr
)
70 struct wbcAuthUserInfo
*i
= (struct wbcAuthUserInfo
*)ptr
;
71 free(i
->account_name
);
72 free(i
->user_principal
);
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
);
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
;
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
);
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
,
149 BAIL_ON_WBC_ERROR(wbc_status
);
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
;
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
;
165 p
= (char *)resp
->extra_data
.data
;
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
++) {
176 char *e
= strchr(p
, '\n');
178 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
179 BAIL_ON_WBC_ERROR(wbc_status
);
184 ret
= sscanf(s
, "0x%08X:0x%08X", &rid
, &attrs
);
186 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
187 BAIL_ON_WBC_ERROR(wbc_status
);
190 if (!sid_attr_compose(&i
->sids
[sn
], &domain_sid
,
192 wbc_status
= WBC_ERR_INVALID_SID
;
198 for (j
=0; j
< resp
->data
.auth
.info3
.num_other_sids
; j
++) {
203 char *e
= strchr(p
, '\n');
205 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
206 BAIL_ON_WBC_ERROR(wbc_status
);
213 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
214 BAIL_ON_WBC_ERROR(wbc_status
);
219 ret
= sscanf(a
, "0x%08X",
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
;
242 static void wbcAuthErrorInfoDestructor(void *ptr
)
244 struct wbcAuthErrorInfo
*e
= (struct wbcAuthErrorInfo
*)ptr
;
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
->authoritative
= resp
->data
.auth
.authoritative
;
263 e
->nt_string
= strdup(resp
->data
.auth
.nt_status_string
);
264 BAIL_ON_PTR_ERROR(e
->nt_string
, wbc_status
);
266 e
->display_string
= strdup(resp
->data
.auth
.error_string
);
267 BAIL_ON_PTR_ERROR(e
->display_string
, wbc_status
);
277 static wbcErr
wbc_create_password_policy_info(const struct winbindd_response
*resp
,
278 struct wbcUserPasswordPolicyInfo
**_i
)
280 wbcErr wbc_status
= WBC_ERR_SUCCESS
;
281 struct wbcUserPasswordPolicyInfo
*i
;
283 i
= (struct wbcUserPasswordPolicyInfo
*)wbcAllocateMemory(
284 1, sizeof(struct wbcUserPasswordPolicyInfo
), NULL
);
285 BAIL_ON_PTR_ERROR(i
, wbc_status
);
287 i
->min_passwordage
= resp
->data
.auth
.policy
.min_passwordage
;
288 i
->min_length_password
= resp
->data
.auth
.policy
.min_length_password
;
289 i
->password_history
= resp
->data
.auth
.policy
.password_history
;
290 i
->password_properties
= resp
->data
.auth
.policy
.password_properties
;
291 i
->expire
= resp
->data
.auth
.policy
.expire
;
301 static void wbcLogonUserInfoDestructor(void *ptr
)
303 struct wbcLogonUserInfo
*i
= (struct wbcLogonUserInfo
*)ptr
;
304 wbcFreeMemory(i
->info
);
305 wbcFreeMemory(i
->blobs
);
308 static wbcErr
wbc_create_logon_info(struct winbindd_response
*resp
,
309 struct wbcLogonUserInfo
**_i
)
311 wbcErr wbc_status
= WBC_ERR_SUCCESS
;
312 struct wbcLogonUserInfo
*i
;
314 i
= (struct wbcLogonUserInfo
*)wbcAllocateMemory(
315 1, sizeof(struct wbcLogonUserInfo
),
316 wbcLogonUserInfoDestructor
);
317 BAIL_ON_PTR_ERROR(i
, wbc_status
);
319 wbc_status
= wbc_create_auth_info(resp
, &i
->info
);
320 BAIL_ON_WBC_ERROR(wbc_status
);
322 if (resp
->data
.auth
.krb5ccname
[0] != '\0') {
323 wbc_status
= wbcAddNamedBlob(&i
->num_blobs
,
327 (uint8_t *)resp
->data
.auth
.krb5ccname
,
328 strlen(resp
->data
.auth
.krb5ccname
)+1);
329 BAIL_ON_WBC_ERROR(wbc_status
);
332 if (resp
->data
.auth
.unix_username
[0] != '\0') {
333 wbc_status
= wbcAddNamedBlob(&i
->num_blobs
,
337 (uint8_t *)resp
->data
.auth
.unix_username
,
338 strlen(resp
->data
.auth
.unix_username
)+1);
339 BAIL_ON_WBC_ERROR(wbc_status
);
350 /* Authenticate with more detailed information */
351 wbcErr
wbcCtxAuthenticateUserEx(struct wbcContext
*ctx
,
352 const struct wbcAuthUserParams
*params
,
353 struct wbcAuthUserInfo
**info
,
354 struct wbcAuthErrorInfo
**error
)
356 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
358 struct winbindd_request request
;
359 struct winbindd_response response
;
361 ZERO_STRUCT(request
);
362 ZERO_STRUCT(response
);
369 wbc_status
= WBC_ERR_INVALID_PARAM
;
370 BAIL_ON_WBC_ERROR(wbc_status
);
373 if (params
->level
!= WBC_AUTH_USER_LEVEL_PAC
&& !params
->account_name
) {
374 wbc_status
= WBC_ERR_INVALID_PARAM
;
375 BAIL_ON_WBC_ERROR(wbc_status
);
378 /* Initialize request */
380 switch (params
->level
) {
381 case WBC_AUTH_USER_LEVEL_PLAIN
:
382 cmd
= WINBINDD_PAM_AUTH
;
383 request
.flags
= WBFLAG_PAM_INFO3_TEXT
|
384 WBFLAG_PAM_USER_SESSION_KEY
|
387 if (!params
->password
.plaintext
) {
388 wbc_status
= WBC_ERR_INVALID_PARAM
;
389 BAIL_ON_WBC_ERROR(wbc_status
);
392 if (params
->domain_name
&& params
->domain_name
[0]) {
393 /* We need to get the winbind separator :-( */
394 struct winbindd_response sep_response
;
396 ZERO_STRUCT(sep_response
);
398 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_INFO
,
399 NULL
, &sep_response
);
400 BAIL_ON_WBC_ERROR(wbc_status
);
402 snprintf(request
.data
.auth
.user
,
403 sizeof(request
.data
.auth
.user
)-1,
406 sep_response
.data
.info
.winbind_separator
,
407 params
->account_name
);
409 strncpy(request
.data
.auth
.user
,
410 params
->account_name
,
411 sizeof(request
.data
.auth
.user
)-1);
414 strncpy(request
.data
.auth
.pass
,
415 params
->password
.plaintext
,
416 sizeof(request
.data
.auth
.pass
)-1);
419 case WBC_AUTH_USER_LEVEL_HASH
:
420 wbc_status
= WBC_ERR_NOT_IMPLEMENTED
;
421 BAIL_ON_WBC_ERROR(wbc_status
);
424 case WBC_AUTH_USER_LEVEL_RESPONSE
:
425 cmd
= WINBINDD_PAM_AUTH_CRAP
;
426 request
.flags
= WBFLAG_PAM_INFO3_TEXT
|
427 WBFLAG_PAM_USER_SESSION_KEY
|
430 if (params
->password
.response
.lm_length
&&
431 !params
->password
.response
.lm_data
) {
432 wbc_status
= WBC_ERR_INVALID_PARAM
;
433 BAIL_ON_WBC_ERROR(wbc_status
);
435 if (params
->password
.response
.lm_length
== 0 &&
436 params
->password
.response
.lm_data
) {
437 wbc_status
= WBC_ERR_INVALID_PARAM
;
438 BAIL_ON_WBC_ERROR(wbc_status
);
441 if (params
->password
.response
.nt_length
&&
442 !params
->password
.response
.nt_data
) {
443 wbc_status
= WBC_ERR_INVALID_PARAM
;
444 BAIL_ON_WBC_ERROR(wbc_status
);
446 if (params
->password
.response
.nt_length
== 0&&
447 params
->password
.response
.nt_data
) {
448 wbc_status
= WBC_ERR_INVALID_PARAM
;
449 BAIL_ON_WBC_ERROR(wbc_status
);
452 strncpy(request
.data
.auth_crap
.user
,
453 params
->account_name
,
454 sizeof(request
.data
.auth_crap
.user
)-1);
455 if (params
->domain_name
) {
456 strncpy(request
.data
.auth_crap
.domain
,
458 sizeof(request
.data
.auth_crap
.domain
)-1);
460 if (params
->workstation_name
) {
461 strncpy(request
.data
.auth_crap
.workstation
,
462 params
->workstation_name
,
463 sizeof(request
.data
.auth_crap
.workstation
)-1);
466 request
.data
.auth_crap
.logon_parameters
=
467 params
->parameter_control
;
469 memcpy(request
.data
.auth_crap
.chal
,
470 params
->password
.response
.challenge
,
471 sizeof(request
.data
.auth_crap
.chal
));
473 request
.data
.auth_crap
.lm_resp_len
=
474 MIN(params
->password
.response
.lm_length
,
475 sizeof(request
.data
.auth_crap
.lm_resp
));
476 if (params
->password
.response
.lm_data
) {
477 memcpy(request
.data
.auth_crap
.lm_resp
,
478 params
->password
.response
.lm_data
,
479 request
.data
.auth_crap
.lm_resp_len
);
481 request
.data
.auth_crap
.nt_resp_len
= params
->password
.response
.nt_length
;
482 if (params
->password
.response
.nt_length
> sizeof(request
.data
.auth_crap
.nt_resp
)) {
483 request
.flags
|= WBFLAG_BIG_NTLMV2_BLOB
;
484 request
.extra_len
= params
->password
.response
.nt_length
;
485 request
.extra_data
.data
= (char *)malloc(
487 if (request
.extra_data
.data
== NULL
) {
488 wbc_status
= WBC_ERR_NO_MEMORY
;
489 BAIL_ON_WBC_ERROR(wbc_status
);
491 memcpy(request
.extra_data
.data
,
492 params
->password
.response
.nt_data
,
493 request
.data
.auth_crap
.nt_resp_len
);
494 } else if (params
->password
.response
.nt_data
) {
495 memcpy(request
.data
.auth_crap
.nt_resp
,
496 params
->password
.response
.nt_data
,
497 request
.data
.auth_crap
.nt_resp_len
);
501 case WBC_AUTH_USER_LEVEL_PAC
:
502 cmd
= WINBINDD_PAM_AUTH_CRAP
;
503 request
.flags
= WBFLAG_PAM_AUTH_PAC
| WBFLAG_PAM_INFO3_TEXT
;
504 request
.extra_data
.data
= malloc(params
->password
.pac
.length
);
505 if (request
.extra_data
.data
== NULL
) {
506 wbc_status
= WBC_ERR_NO_MEMORY
;
507 BAIL_ON_WBC_ERROR(wbc_status
);
509 memcpy(request
.extra_data
.data
, params
->password
.pac
.data
,
510 params
->password
.pac
.length
);
511 request
.extra_len
= params
->password
.pac
.length
;
519 wbc_status
= WBC_ERR_INVALID_PARAM
;
520 BAIL_ON_WBC_ERROR(wbc_status
);
524 request
.flags
|= params
->flags
;
527 if (cmd
== WINBINDD_PAM_AUTH_CRAP
) {
528 wbc_status
= wbcRequestResponsePriv(ctx
, cmd
,
529 &request
, &response
);
531 wbc_status
= wbcRequestResponse(ctx
, cmd
,
532 &request
, &response
);
534 if (response
.data
.auth
.nt_status
!= 0) {
536 wbc_status
= wbc_create_error_info(&response
,
538 BAIL_ON_WBC_ERROR(wbc_status
);
541 wbc_status
= WBC_ERR_AUTH_ERROR
;
542 BAIL_ON_WBC_ERROR(wbc_status
);
544 BAIL_ON_WBC_ERROR(wbc_status
);
547 wbc_status
= wbc_create_auth_info(&response
, info
);
548 BAIL_ON_WBC_ERROR(wbc_status
);
552 winbindd_free_response(&response
);
554 free(request
.extra_data
.data
);
559 wbcErr
wbcAuthenticateUserEx(const struct wbcAuthUserParams
*params
,
560 struct wbcAuthUserInfo
**info
,
561 struct wbcAuthErrorInfo
**error
)
563 return wbcCtxAuthenticateUserEx(NULL
, params
, info
, error
);
566 /* Trigger a verification of the trust credentials of a specific domain */
567 wbcErr
wbcCtxCheckTrustCredentials(struct wbcContext
*ctx
, const char *domain
,
568 struct wbcAuthErrorInfo
**error
)
570 struct winbindd_request request
;
571 struct winbindd_response response
;
572 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
574 ZERO_STRUCT(request
);
575 ZERO_STRUCT(response
);
578 strncpy(request
.domain_name
, domain
,
579 sizeof(request
.domain_name
)-1);
584 wbc_status
= wbcRequestResponsePriv(ctx
, WINBINDD_CHECK_MACHACC
,
585 &request
, &response
);
586 if (response
.data
.auth
.nt_status
!= 0) {
588 wbc_status
= wbc_create_error_info(&response
,
590 BAIL_ON_WBC_ERROR(wbc_status
);
593 wbc_status
= WBC_ERR_AUTH_ERROR
;
594 BAIL_ON_WBC_ERROR(wbc_status
);
596 BAIL_ON_WBC_ERROR(wbc_status
);
602 wbcErr
wbcCheckTrustCredentials(const char *domain
,
603 struct wbcAuthErrorInfo
**error
)
605 return wbcCtxCheckTrustCredentials(NULL
, domain
, error
);
608 /* Trigger a change of the trust credentials for a specific domain */
609 wbcErr
wbcCtxChangeTrustCredentials(struct wbcContext
*ctx
, const char *domain
,
610 struct wbcAuthErrorInfo
**error
)
612 struct winbindd_request request
;
613 struct winbindd_response response
;
614 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
616 ZERO_STRUCT(request
);
617 ZERO_STRUCT(response
);
620 strncpy(request
.domain_name
, domain
,
621 sizeof(request
.domain_name
)-1);
626 wbc_status
= wbcRequestResponsePriv(ctx
, WINBINDD_CHANGE_MACHACC
,
627 &request
, &response
);
628 if (response
.data
.auth
.nt_status
!= 0) {
630 wbc_status
= wbc_create_error_info(&response
,
632 BAIL_ON_WBC_ERROR(wbc_status
);
635 wbc_status
= WBC_ERR_AUTH_ERROR
;
636 BAIL_ON_WBC_ERROR(wbc_status
);
638 BAIL_ON_WBC_ERROR(wbc_status
);
644 wbcErr
wbcChangeTrustCredentials(const char *domain
,
645 struct wbcAuthErrorInfo
**error
)
647 return wbcCtxChangeTrustCredentials(NULL
, domain
, error
);
651 * Trigger a no-op NETLOGON call. Lightweight version of
652 * wbcCheckTrustCredentials
654 wbcErr
wbcCtxPingDc(struct wbcContext
*ctx
, const char *domain
,
655 struct wbcAuthErrorInfo
**error
)
657 return wbcCtxPingDc2(ctx
, domain
, error
, NULL
);
660 wbcErr
wbcPingDc(const char *domain
, struct wbcAuthErrorInfo
**error
)
662 return wbcPingDc2(domain
, error
, NULL
);
666 * Trigger a no-op NETLOGON call. Lightweight version of
667 * wbcCheckTrustCredentials, optionally return attempted DC
669 wbcErr
wbcCtxPingDc2(struct wbcContext
*ctx
, const char *domain
,
670 struct wbcAuthErrorInfo
**error
, char **dcname
)
672 struct winbindd_request request
;
673 struct winbindd_response response
;
674 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
676 ZERO_STRUCT(request
);
677 ZERO_STRUCT(response
);
680 strncpy(request
.domain_name
, domain
,
681 sizeof(request
.domain_name
)-1);
686 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_PING_DC
,
690 if (dcname
&& response
.extra_data
.data
) {
693 len
= response
.length
- sizeof(struct winbindd_response
);
694 *dcname
= wbcAllocateMemory(1, len
, NULL
);
695 BAIL_ON_PTR_ERROR(*dcname
, wbc_status
);
697 strlcpy(*dcname
, response
.extra_data
.data
, len
);
700 if (response
.data
.auth
.nt_status
!= 0) {
702 wbc_status
= wbc_create_error_info(&response
,
704 BAIL_ON_WBC_ERROR(wbc_status
);
707 wbc_status
= WBC_ERR_AUTH_ERROR
;
708 BAIL_ON_WBC_ERROR(wbc_status
);
710 BAIL_ON_WBC_ERROR(wbc_status
);
716 wbcErr
wbcPingDc2(const char *domain
, struct wbcAuthErrorInfo
**error
,
719 return wbcCtxPingDc2(NULL
, domain
, error
, dcname
);
722 /* Trigger an extended logoff notification to Winbind for a specific user */
723 wbcErr
wbcCtxLogoffUserEx(struct wbcContext
*ctx
,
724 const struct wbcLogoffUserParams
*params
,
725 struct wbcAuthErrorInfo
**error
)
727 struct winbindd_request request
;
728 struct winbindd_response response
;
729 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
734 if (!params
|| !params
->username
) {
735 wbc_status
= WBC_ERR_INVALID_PARAM
;
736 BAIL_ON_WBC_ERROR(wbc_status
);
739 if ((params
->num_blobs
> 0) && (params
->blobs
== NULL
)) {
740 wbc_status
= WBC_ERR_INVALID_PARAM
;
741 BAIL_ON_WBC_ERROR(wbc_status
);
743 if ((params
->num_blobs
== 0) && (params
->blobs
!= NULL
)) {
744 wbc_status
= WBC_ERR_INVALID_PARAM
;
745 BAIL_ON_WBC_ERROR(wbc_status
);
748 ZERO_STRUCT(request
);
749 ZERO_STRUCT(response
);
751 strncpy(request
.data
.logoff
.user
, params
->username
,
752 sizeof(request
.data
.logoff
.user
)-1);
754 for (i
=0; i
<params
->num_blobs
; i
++) {
756 if (strcasecmp(params
->blobs
[i
].name
, "ccfilename") == 0) {
757 if (params
->blobs
[i
].blob
.data
) {
758 strncpy(request
.data
.logoff
.krb5ccname
,
759 (const char *)params
->blobs
[i
].blob
.data
,
760 sizeof(request
.data
.logoff
.krb5ccname
) - 1);
765 if (strcasecmp(params
->blobs
[i
].name
, "user_uid") == 0) {
766 if (params
->blobs
[i
].blob
.data
) {
767 memcpy(&request
.data
.logoff
.uid
,
768 params
->blobs
[i
].blob
.data
,
769 MIN(params
->blobs
[i
].blob
.length
,
770 sizeof(request
.data
.logoff
.uid
)));
775 if (strcasecmp(params
->blobs
[i
].name
, "flags") == 0) {
776 if (params
->blobs
[i
].blob
.data
) {
777 memcpy(&request
.flags
,
778 params
->blobs
[i
].blob
.data
,
779 MIN(params
->blobs
[i
].blob
.length
,
780 sizeof(request
.flags
)));
788 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_PAM_LOGOFF
,
792 /* Take the response above and return it to the caller */
793 if (response
.data
.auth
.nt_status
!= 0) {
795 wbc_status
= wbc_create_error_info(&response
,
797 BAIL_ON_WBC_ERROR(wbc_status
);
800 wbc_status
= WBC_ERR_AUTH_ERROR
;
801 BAIL_ON_WBC_ERROR(wbc_status
);
803 BAIL_ON_WBC_ERROR(wbc_status
);
809 wbcErr
wbcLogoffUserEx(const struct wbcLogoffUserParams
*params
,
810 struct wbcAuthErrorInfo
**error
)
812 return wbcCtxLogoffUserEx(NULL
, params
, error
);
815 /* Trigger a logoff notification to Winbind for a specific user */
816 wbcErr
wbcCtxLogoffUser(struct wbcContext
*ctx
,
817 const char *username
, uid_t uid
,
818 const char *ccfilename
)
820 struct winbindd_request request
;
821 struct winbindd_response response
;
822 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
827 wbc_status
= WBC_ERR_INVALID_PARAM
;
828 BAIL_ON_WBC_ERROR(wbc_status
);
831 ZERO_STRUCT(request
);
832 ZERO_STRUCT(response
);
834 strncpy(request
.data
.logoff
.user
, username
,
835 sizeof(request
.data
.logoff
.user
)-1);
836 request
.data
.logoff
.uid
= uid
;
839 strncpy(request
.data
.logoff
.krb5ccname
, ccfilename
,
840 sizeof(request
.data
.logoff
.krb5ccname
)-1);
845 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_PAM_LOGOFF
,
849 /* Take the response above and return it to the caller */
855 wbcErr
wbcLogoffUser(const char *username
,
857 const char *ccfilename
)
859 return wbcCtxLogoffUser(NULL
, username
, uid
, ccfilename
);
862 /* Change a password for a user with more detailed information upon failure */
863 wbcErr
wbcCtxChangeUserPasswordEx(struct wbcContext
*ctx
,
864 const struct wbcChangePasswordParams
*params
,
865 struct wbcAuthErrorInfo
**error
,
866 enum wbcPasswordChangeRejectReason
*reject_reason
,
867 struct wbcUserPasswordPolicyInfo
**policy
)
869 struct winbindd_request request
;
870 struct winbindd_response response
;
871 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
876 if (!params
->account_name
) {
877 wbc_status
= WBC_ERR_INVALID_PARAM
;
893 ZERO_STRUCT(request
);
894 ZERO_STRUCT(response
);
896 switch (params
->level
) {
897 case WBC_CHANGE_PASSWORD_LEVEL_PLAIN
:
898 cmd
= WINBINDD_PAM_CHAUTHTOK
;
900 if (!params
->account_name
) {
901 wbc_status
= WBC_ERR_INVALID_PARAM
;
905 strncpy(request
.data
.chauthtok
.user
, params
->account_name
,
906 sizeof(request
.data
.chauthtok
.user
) - 1);
908 if (params
->old_password
.plaintext
) {
909 strncpy(request
.data
.chauthtok
.oldpass
,
910 params
->old_password
.plaintext
,
911 sizeof(request
.data
.chauthtok
.oldpass
) - 1);
914 if (params
->new_password
.plaintext
) {
915 strncpy(request
.data
.chauthtok
.newpass
,
916 params
->new_password
.plaintext
,
917 sizeof(request
.data
.chauthtok
.newpass
) - 1);
921 case WBC_CHANGE_PASSWORD_LEVEL_RESPONSE
:
922 cmd
= WINBINDD_PAM_CHNG_PSWD_AUTH_CRAP
;
924 if (!params
->account_name
|| !params
->domain_name
) {
925 wbc_status
= WBC_ERR_INVALID_PARAM
;
929 if (params
->old_password
.response
.old_lm_hash_enc_length
&&
930 !params
->old_password
.response
.old_lm_hash_enc_data
) {
931 wbc_status
= WBC_ERR_INVALID_PARAM
;
935 if (params
->old_password
.response
.old_lm_hash_enc_length
== 0 &&
936 params
->old_password
.response
.old_lm_hash_enc_data
) {
937 wbc_status
= WBC_ERR_INVALID_PARAM
;
941 if (params
->old_password
.response
.old_nt_hash_enc_length
&&
942 !params
->old_password
.response
.old_nt_hash_enc_data
) {
943 wbc_status
= WBC_ERR_INVALID_PARAM
;
947 if (params
->old_password
.response
.old_nt_hash_enc_length
== 0 &&
948 params
->old_password
.response
.old_nt_hash_enc_data
) {
949 wbc_status
= WBC_ERR_INVALID_PARAM
;
953 if (params
->new_password
.response
.lm_length
&&
954 !params
->new_password
.response
.lm_data
) {
955 wbc_status
= WBC_ERR_INVALID_PARAM
;
959 if (params
->new_password
.response
.lm_length
== 0 &&
960 params
->new_password
.response
.lm_data
) {
961 wbc_status
= WBC_ERR_INVALID_PARAM
;
965 if (params
->new_password
.response
.nt_length
&&
966 !params
->new_password
.response
.nt_data
) {
967 wbc_status
= WBC_ERR_INVALID_PARAM
;
971 if (params
->new_password
.response
.nt_length
== 0 &&
972 params
->new_password
.response
.nt_data
) {
973 wbc_status
= WBC_ERR_INVALID_PARAM
;
977 strncpy(request
.data
.chng_pswd_auth_crap
.user
,
978 params
->account_name
,
979 sizeof(request
.data
.chng_pswd_auth_crap
.user
) - 1);
981 strncpy(request
.data
.chng_pswd_auth_crap
.domain
,
983 sizeof(request
.data
.chng_pswd_auth_crap
.domain
) - 1);
985 if (params
->new_password
.response
.nt_data
) {
986 request
.data
.chng_pswd_auth_crap
.new_nt_pswd_len
=
987 params
->new_password
.response
.nt_length
;
988 memcpy(request
.data
.chng_pswd_auth_crap
.new_nt_pswd
,
989 params
->new_password
.response
.nt_data
,
990 request
.data
.chng_pswd_auth_crap
.new_nt_pswd_len
);
993 if (params
->new_password
.response
.lm_data
) {
994 request
.data
.chng_pswd_auth_crap
.new_lm_pswd_len
=
995 params
->new_password
.response
.lm_length
;
996 memcpy(request
.data
.chng_pswd_auth_crap
.new_lm_pswd
,
997 params
->new_password
.response
.lm_data
,
998 request
.data
.chng_pswd_auth_crap
.new_lm_pswd_len
);
1001 if (params
->old_password
.response
.old_nt_hash_enc_data
) {
1002 request
.data
.chng_pswd_auth_crap
.old_nt_hash_enc_len
=
1003 params
->old_password
.response
.old_nt_hash_enc_length
;
1004 memcpy(request
.data
.chng_pswd_auth_crap
.old_nt_hash_enc
,
1005 params
->old_password
.response
.old_nt_hash_enc_data
,
1006 request
.data
.chng_pswd_auth_crap
.old_nt_hash_enc_len
);
1009 if (params
->old_password
.response
.old_lm_hash_enc_data
) {
1010 request
.data
.chng_pswd_auth_crap
.old_lm_hash_enc_len
=
1011 params
->old_password
.response
.old_lm_hash_enc_length
;
1012 memcpy(request
.data
.chng_pswd_auth_crap
.old_lm_hash_enc
,
1013 params
->old_password
.response
.old_lm_hash_enc_data
,
1014 request
.data
.chng_pswd_auth_crap
.old_lm_hash_enc_len
);
1019 wbc_status
= WBC_ERR_INVALID_PARAM
;
1026 wbc_status
= wbcRequestResponse(ctx
, cmd
,
1029 if (WBC_ERROR_IS_OK(wbc_status
)) {
1033 /* Take the response above and return it to the caller */
1035 if (response
.data
.auth
.nt_status
!= 0) {
1037 wbc_status
= wbc_create_error_info(&response
,
1039 BAIL_ON_WBC_ERROR(wbc_status
);
1045 wbc_status
= wbc_create_password_policy_info(&response
,
1047 BAIL_ON_WBC_ERROR(wbc_status
);
1050 if (reject_reason
) {
1051 *reject_reason
= response
.data
.auth
.reject_reason
;
1054 wbc_status
= WBC_ERR_PWD_CHANGE_FAILED
;
1055 BAIL_ON_WBC_ERROR(wbc_status
);
1061 wbcErr
wbcChangeUserPasswordEx(const struct wbcChangePasswordParams
*params
,
1062 struct wbcAuthErrorInfo
**error
,
1063 enum wbcPasswordChangeRejectReason
*reject_reason
,
1064 struct wbcUserPasswordPolicyInfo
**policy
)
1066 return wbcCtxChangeUserPasswordEx(NULL
, params
, error
,
1067 reject_reason
, policy
);
1070 /* Change a password for a user */
1071 wbcErr
wbcCtxChangeUserPassword(struct wbcContext
*ctx
,
1072 const char *username
,
1073 const char *old_password
,
1074 const char *new_password
)
1076 wbcErr wbc_status
= WBC_ERR_SUCCESS
;
1077 struct wbcChangePasswordParams params
;
1079 ZERO_STRUCT(params
);
1081 params
.account_name
= username
;
1082 params
.level
= WBC_CHANGE_PASSWORD_LEVEL_PLAIN
;
1083 params
.old_password
.plaintext
= old_password
;
1084 params
.new_password
.plaintext
= new_password
;
1086 wbc_status
= wbcCtxChangeUserPasswordEx(ctx
, ¶ms
,
1090 BAIL_ON_WBC_ERROR(wbc_status
);
1096 wbcErr
wbcChangeUserPassword(const char *username
,
1097 const char *old_password
,
1098 const char *new_password
)
1100 return wbcCtxChangeUserPassword(NULL
, username
,
1101 old_password
, new_password
);
1105 wbcErr
wbcCtxLogonUser(struct wbcContext
*ctx
,
1106 const struct wbcLogonUserParams
*params
,
1107 struct wbcLogonUserInfo
**info
,
1108 struct wbcAuthErrorInfo
**error
,
1109 struct wbcUserPasswordPolicyInfo
**policy
)
1111 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
1112 struct winbindd_request request
;
1113 struct winbindd_response response
;
1116 ZERO_STRUCT(request
);
1117 ZERO_STRUCT(response
);
1130 wbc_status
= WBC_ERR_INVALID_PARAM
;
1131 BAIL_ON_WBC_ERROR(wbc_status
);
1134 if (!params
->username
) {
1135 wbc_status
= WBC_ERR_INVALID_PARAM
;
1136 BAIL_ON_WBC_ERROR(wbc_status
);
1139 if ((params
->num_blobs
> 0) && (params
->blobs
== NULL
)) {
1140 wbc_status
= WBC_ERR_INVALID_PARAM
;
1141 BAIL_ON_WBC_ERROR(wbc_status
);
1143 if ((params
->num_blobs
== 0) && (params
->blobs
!= NULL
)) {
1144 wbc_status
= WBC_ERR_INVALID_PARAM
;
1145 BAIL_ON_WBC_ERROR(wbc_status
);
1148 /* Initialize request */
1150 request
.flags
= WBFLAG_PAM_INFO3_TEXT
|
1151 WBFLAG_PAM_USER_SESSION_KEY
|
1154 if (!params
->password
) {
1155 wbc_status
= WBC_ERR_INVALID_PARAM
;
1156 BAIL_ON_WBC_ERROR(wbc_status
);
1159 strncpy(request
.data
.auth
.user
,
1161 sizeof(request
.data
.auth
.user
)-1);
1163 strncpy(request
.data
.auth
.pass
,
1165 sizeof(request
.data
.auth
.pass
)-1);
1167 for (i
=0; i
<params
->num_blobs
; i
++) {
1169 if (strcasecmp(params
->blobs
[i
].name
, "krb5_cc_type") == 0) {
1170 if (params
->blobs
[i
].blob
.data
) {
1171 strncpy(request
.data
.auth
.krb5_cc_type
,
1172 (const char *)params
->blobs
[i
].blob
.data
,
1173 sizeof(request
.data
.auth
.krb5_cc_type
) - 1);
1178 if (strcasecmp(params
->blobs
[i
].name
, "user_uid") == 0) {
1179 if (params
->blobs
[i
].blob
.data
) {
1180 memcpy(&request
.data
.auth
.uid
,
1181 params
->blobs
[i
].blob
.data
,
1182 MIN(sizeof(request
.data
.auth
.uid
),
1183 params
->blobs
[i
].blob
.length
));
1188 if (strcasecmp(params
->blobs
[i
].name
, "flags") == 0) {
1189 if (params
->blobs
[i
].blob
.data
) {
1192 params
->blobs
[i
].blob
.data
,
1194 params
->blobs
[i
].blob
.length
));
1195 request
.flags
|= flags
;
1200 if (strcasecmp(params
->blobs
[i
].name
, "membership_of") == 0) {
1201 if (params
->blobs
[i
].blob
.data
&&
1202 params
->blobs
[i
].blob
.data
[0] > 0) {
1203 strncpy(request
.data
.auth
.require_membership_of_sid
,
1204 (const char *)params
->blobs
[i
].blob
.data
,
1205 sizeof(request
.data
.auth
.require_membership_of_sid
) - 1);
1211 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_PAM_AUTH
,
1215 if (response
.data
.auth
.nt_status
!= 0) {
1217 wbc_status
= wbc_create_error_info(&response
,
1219 BAIL_ON_WBC_ERROR(wbc_status
);
1222 wbc_status
= WBC_ERR_AUTH_ERROR
;
1223 BAIL_ON_WBC_ERROR(wbc_status
);
1225 BAIL_ON_WBC_ERROR(wbc_status
);
1228 wbc_status
= wbc_create_logon_info(&response
,
1230 BAIL_ON_WBC_ERROR(wbc_status
);
1234 wbc_status
= wbc_create_password_policy_info(&response
,
1236 BAIL_ON_WBC_ERROR(wbc_status
);
1240 winbindd_free_response(&response
);
1245 wbcErr
wbcLogonUser(const struct wbcLogonUserParams
*params
,
1246 struct wbcLogonUserInfo
**info
,
1247 struct wbcAuthErrorInfo
**error
,
1248 struct wbcUserPasswordPolicyInfo
**policy
)
1250 return wbcCtxLogonUser(NULL
, params
, info
, error
, policy
);
1253 static void wbcCredentialCacheInfoDestructor(void *ptr
)
1255 struct wbcCredentialCacheInfo
*i
=
1256 (struct wbcCredentialCacheInfo
*)ptr
;
1257 wbcFreeMemory(i
->blobs
);
1260 /* Authenticate a user with cached credentials */
1261 wbcErr
wbcCtxCredentialCache(struct wbcContext
*ctx
,
1262 struct wbcCredentialCacheParams
*params
,
1263 struct wbcCredentialCacheInfo
**info
,
1264 struct wbcAuthErrorInfo
**error
)
1266 wbcErr status
= WBC_ERR_UNKNOWN_FAILURE
;
1267 struct wbcCredentialCacheInfo
*result
= NULL
;
1268 struct winbindd_request request
;
1269 struct winbindd_response response
;
1270 struct wbcNamedBlob
*initial_blob
= NULL
;
1271 struct wbcNamedBlob
*challenge_blob
= NULL
;
1274 ZERO_STRUCT(request
);
1275 ZERO_STRUCT(response
);
1279 if (error
!= NULL
) {
1282 if ((params
== NULL
)
1283 || (params
->account_name
== NULL
)
1284 || (params
->level
!= WBC_CREDENTIAL_CACHE_LEVEL_NTLMSSP
)) {
1285 status
= WBC_ERR_INVALID_PARAM
;
1289 for (i
=0; i
<params
->num_blobs
; i
++) {
1291 * Older callers may used to provide the NEGOTIATE request
1292 * as "initial_blob", but it was completely ignored by winbindd.
1294 * So we keep ignoring it.
1296 * A new callers that is capable to support "new_spnego",
1297 * will provide the NEGOTIATE request as "negotiate_blob"
1300 if (strcasecmp(params
->blobs
[i
].name
, "negotiate_blob") == 0) {
1301 if (initial_blob
!= NULL
) {
1302 status
= WBC_ERR_INVALID_PARAM
;
1305 initial_blob
= ¶ms
->blobs
[i
];
1308 if (strcasecmp(params
->blobs
[i
].name
, "challenge_blob") == 0) {
1309 if (challenge_blob
!= NULL
) {
1310 status
= WBC_ERR_INVALID_PARAM
;
1313 challenge_blob
= ¶ms
->blobs
[i
];
1318 if (params
->domain_name
!= NULL
) {
1319 status
= wbcRequestResponse(ctx
, WINBINDD_INFO
,
1321 if (!WBC_ERROR_IS_OK(status
)) {
1324 snprintf(request
.data
.ccache_ntlm_auth
.user
,
1325 sizeof(request
.data
.ccache_ntlm_auth
.user
)-1,
1326 "%s%c%s", params
->domain_name
,
1327 response
.data
.info
.winbind_separator
,
1328 params
->account_name
);
1330 strncpy(request
.data
.ccache_ntlm_auth
.user
,
1331 params
->account_name
,
1332 sizeof(request
.data
.ccache_ntlm_auth
.user
)-1);
1334 request
.data
.ccache_ntlm_auth
.uid
= getuid();
1336 request
.data
.ccache_ntlm_auth
.initial_blob_len
= 0;
1337 request
.data
.ccache_ntlm_auth
.challenge_blob_len
= 0;
1338 request
.extra_len
= 0;
1340 if (initial_blob
!= NULL
) {
1341 request
.data
.ccache_ntlm_auth
.initial_blob_len
=
1342 initial_blob
->blob
.length
;
1343 request
.extra_len
+= initial_blob
->blob
.length
;
1345 if (challenge_blob
!= NULL
) {
1346 request
.data
.ccache_ntlm_auth
.challenge_blob_len
=
1347 challenge_blob
->blob
.length
;
1348 request
.extra_len
+= challenge_blob
->blob
.length
;
1351 if (request
.extra_len
!= 0) {
1352 request
.extra_data
.data
= (char *)malloc(request
.extra_len
);
1353 if (request
.extra_data
.data
== NULL
) {
1354 status
= WBC_ERR_NO_MEMORY
;
1358 if (initial_blob
!= NULL
) {
1359 memcpy(request
.extra_data
.data
,
1360 initial_blob
->blob
.data
, initial_blob
->blob
.length
);
1362 if (challenge_blob
!= NULL
) {
1363 memcpy(request
.extra_data
.data
1364 + request
.data
.ccache_ntlm_auth
.initial_blob_len
,
1365 challenge_blob
->blob
.data
,
1366 challenge_blob
->blob
.length
);
1369 status
= wbcRequestResponse(ctx
, WINBINDD_CCACHE_NTLMAUTH
,
1370 &request
, &response
);
1371 if (!WBC_ERROR_IS_OK(status
)) {
1375 result
= (struct wbcCredentialCacheInfo
*)wbcAllocateMemory(
1376 1, sizeof(struct wbcCredentialCacheInfo
),
1377 wbcCredentialCacheInfoDestructor
);
1378 if (result
== NULL
) {
1379 status
= WBC_ERR_NO_MEMORY
;
1382 result
->num_blobs
= 0;
1383 result
->blobs
= NULL
;
1384 status
= wbcAddNamedBlob(&result
->num_blobs
, &result
->blobs
,
1386 (uint8_t *)response
.extra_data
.data
,
1387 response
.data
.ccache_ntlm_auth
.auth_blob_len
);
1388 if (!WBC_ERROR_IS_OK(status
)) {
1391 status
= wbcAddNamedBlob(
1392 &result
->num_blobs
, &result
->blobs
, "session_key", 0,
1393 response
.data
.ccache_ntlm_auth
.session_key
,
1394 sizeof(response
.data
.ccache_ntlm_auth
.session_key
));
1395 if (!WBC_ERROR_IS_OK(status
)) {
1398 if (response
.data
.ccache_ntlm_auth
.new_spnego
) {
1399 status
= wbcAddNamedBlob(
1400 &result
->num_blobs
, &result
->blobs
, "new_spnego", 0,
1401 &response
.data
.ccache_ntlm_auth
.new_spnego
,
1402 sizeof(response
.data
.ccache_ntlm_auth
.new_spnego
));
1403 if (!WBC_ERROR_IS_OK(status
)) {
1410 status
= WBC_ERR_SUCCESS
;
1412 free(request
.extra_data
.data
);
1413 winbindd_free_response(&response
);
1414 wbcFreeMemory(result
);
1418 wbcErr
wbcCredentialCache(struct wbcCredentialCacheParams
*params
,
1419 struct wbcCredentialCacheInfo
**info
,
1420 struct wbcAuthErrorInfo
**error
)
1422 return wbcCtxCredentialCache(NULL
, params
, info
, error
);
1425 /* Authenticate a user with cached credentials */
1426 wbcErr
wbcCtxCredentialSave(struct wbcContext
*ctx
,
1427 const char *user
, const char *password
)
1429 struct winbindd_request request
;
1430 struct winbindd_response response
;
1432 ZERO_STRUCT(request
);
1433 ZERO_STRUCT(response
);
1435 strncpy(request
.data
.ccache_save
.user
, user
,
1436 sizeof(request
.data
.ccache_save
.user
)-1);
1437 strncpy(request
.data
.ccache_save
.pass
, password
,
1438 sizeof(request
.data
.ccache_save
.pass
)-1);
1439 request
.data
.ccache_save
.uid
= getuid();
1441 return wbcRequestResponse(ctx
, WINBINDD_CCACHE_SAVE
, &request
, &response
);
1444 wbcErr
wbcCredentialSave(const char *user
, const char *password
)
1446 return wbcCtxCredentialSave(NULL
, user
, password
);