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
->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
);
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
;
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
,
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
,
336 (uint8_t *)resp
->data
.auth
.unix_username
,
337 strlen(resp
->data
.auth
.unix_username
)+1);
338 BAIL_ON_WBC_ERROR(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
;
357 struct winbindd_request request
;
358 struct winbindd_response response
;
360 ZERO_STRUCT(request
);
361 ZERO_STRUCT(response
);
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
|
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,
405 sep_response
.data
.info
.winbind_separator
,
406 params
->account_name
);
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);
418 case WBC_AUTH_USER_LEVEL_HASH
:
419 wbc_status
= WBC_ERR_NOT_IMPLEMENTED
;
420 BAIL_ON_WBC_ERROR(wbc_status
);
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
|
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
,
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(
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
);
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
;
518 wbc_status
= WBC_ERR_INVALID_PARAM
;
519 BAIL_ON_WBC_ERROR(wbc_status
);
523 request
.flags
|= params
->flags
;
526 if (cmd
== WINBINDD_PAM_AUTH_CRAP
) {
527 wbc_status
= wbcRequestResponsePriv(ctx
, cmd
,
528 &request
, &response
);
530 wbc_status
= wbcRequestResponse(ctx
, cmd
,
531 &request
, &response
);
533 if (response
.data
.auth
.nt_status
!= 0) {
535 wbc_status
= wbc_create_error_info(&response
,
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
);
546 wbc_status
= wbc_create_auth_info(&response
, info
);
547 BAIL_ON_WBC_ERROR(wbc_status
);
551 winbindd_free_response(&response
);
553 free(request
.extra_data
.data
);
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
);
577 strncpy(request
.domain_name
, domain
,
578 sizeof(request
.domain_name
)-1);
583 wbc_status
= wbcRequestResponsePriv(ctx
, WINBINDD_CHECK_MACHACC
,
584 &request
, &response
);
585 if (response
.data
.auth
.nt_status
!= 0) {
587 wbc_status
= wbc_create_error_info(&response
,
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
);
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
);
619 strncpy(request
.domain_name
, domain
,
620 sizeof(request
.domain_name
)-1);
625 wbc_status
= wbcRequestResponsePriv(ctx
, WINBINDD_CHANGE_MACHACC
,
626 &request
, &response
);
627 if (response
.data
.auth
.nt_status
!= 0) {
629 wbc_status
= wbc_create_error_info(&response
,
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
);
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
);
679 strncpy(request
.domain_name
, domain
,
680 sizeof(request
.domain_name
)-1);
685 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_PING_DC
,
689 if (dcname
&& response
.extra_data
.data
) {
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) {
701 wbc_status
= wbc_create_error_info(&response
,
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
);
715 wbcErr
wbcPingDc2(const char *domain
, struct wbcAuthErrorInfo
**error
,
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
;
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);
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
)));
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
)));
787 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_PAM_LOGOFF
,
791 /* Take the response above and return it to the caller */
792 if (response
.data
.auth
.nt_status
!= 0) {
794 wbc_status
= wbc_create_error_info(&response
,
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
);
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
;
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
;
838 strncpy(request
.data
.logoff
.krb5ccname
, ccfilename
,
839 sizeof(request
.data
.logoff
.krb5ccname
)-1);
844 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_PAM_LOGOFF
,
848 /* Take the response above and return it to the caller */
854 wbcErr
wbcLogoffUser(const char *username
,
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
;
875 if (!params
->account_name
) {
876 wbc_status
= WBC_ERR_INVALID_PARAM
;
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
;
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);
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
;
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
;
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
;
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
;
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
;
952 if (params
->new_password
.response
.lm_length
&&
953 !params
->new_password
.response
.lm_data
) {
954 wbc_status
= WBC_ERR_INVALID_PARAM
;
958 if (params
->new_password
.response
.lm_length
== 0 &&
959 params
->new_password
.response
.lm_data
) {
960 wbc_status
= WBC_ERR_INVALID_PARAM
;
964 if (params
->new_password
.response
.nt_length
&&
965 !params
->new_password
.response
.nt_data
) {
966 wbc_status
= WBC_ERR_INVALID_PARAM
;
970 if (params
->new_password
.response
.nt_length
== 0 &&
971 params
->new_password
.response
.nt_data
) {
972 wbc_status
= WBC_ERR_INVALID_PARAM
;
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
,
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
);
1018 wbc_status
= WBC_ERR_INVALID_PARAM
;
1025 wbc_status
= wbcRequestResponse(ctx
, cmd
,
1028 if (WBC_ERROR_IS_OK(wbc_status
)) {
1032 /* Take the response above and return it to the caller */
1034 if (response
.data
.auth
.nt_status
!= 0) {
1036 wbc_status
= wbc_create_error_info(&response
,
1038 BAIL_ON_WBC_ERROR(wbc_status
);
1044 wbc_status
= wbc_create_password_policy_info(&response
,
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
);
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
, ¶ms
,
1089 BAIL_ON_WBC_ERROR(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
);
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
;
1115 ZERO_STRUCT(request
);
1116 ZERO_STRUCT(response
);
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
|
1153 if (!params
->password
) {
1154 wbc_status
= WBC_ERR_INVALID_PARAM
;
1155 BAIL_ON_WBC_ERROR(wbc_status
);
1158 strncpy(request
.data
.auth
.user
,
1160 sizeof(request
.data
.auth
.user
)-1);
1162 strncpy(request
.data
.auth
.pass
,
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);
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
));
1187 if (strcasecmp(params
->blobs
[i
].name
, "flags") == 0) {
1188 if (params
->blobs
[i
].blob
.data
) {
1191 params
->blobs
[i
].blob
.data
,
1193 params
->blobs
[i
].blob
.length
));
1194 request
.flags
|= flags
;
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);
1210 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_PAM_AUTH
,
1214 if (response
.data
.auth
.nt_status
!= 0) {
1216 wbc_status
= wbc_create_error_info(&response
,
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
);
1227 wbc_status
= wbc_create_logon_info(&response
,
1229 BAIL_ON_WBC_ERROR(wbc_status
);
1233 wbc_status
= wbc_create_password_policy_info(&response
,
1235 BAIL_ON_WBC_ERROR(wbc_status
);
1239 winbindd_free_response(&response
);
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
;
1273 ZERO_STRUCT(request
);
1274 ZERO_STRUCT(response
);
1278 if (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
;
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
;
1294 initial_blob
= ¶ms
->blobs
[i
];
1297 if (strcasecmp(params
->blobs
[i
].name
, "challenge_blob") == 0) {
1298 if (challenge_blob
!= NULL
) {
1299 status
= WBC_ERR_INVALID_PARAM
;
1302 challenge_blob
= ¶ms
->blobs
[i
];
1307 if (params
->domain_name
!= NULL
) {
1308 status
= wbcRequestResponse(ctx
, WINBINDD_INFO
,
1310 if (!WBC_ERROR_IS_OK(status
)) {
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
);
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
;
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
)) {
1364 result
= (struct wbcCredentialCacheInfo
*)wbcAllocateMemory(
1365 1, sizeof(struct wbcCredentialCacheInfo
),
1366 wbcCredentialCacheInfoDestructor
);
1367 if (result
== NULL
) {
1368 status
= WBC_ERR_NO_MEMORY
;
1371 result
->num_blobs
= 0;
1372 result
->blobs
= NULL
;
1373 status
= wbcAddNamedBlob(&result
->num_blobs
, &result
->blobs
,
1375 (uint8_t *)response
.extra_data
.data
,
1376 response
.data
.ccache_ntlm_auth
.auth_blob_len
);
1377 if (!WBC_ERROR_IS_OK(status
)) {
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
)) {
1390 status
= WBC_ERR_SUCCESS
;
1392 free(request
.extra_data
.data
);
1393 winbindd_free_response(&response
);
1394 wbcFreeMemory(result
);
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
);