2 Unix SMB/CIFS implementation.
4 Winbind client asynchronous API, utility functions
6 Copyright (C) Gerald (Jerry) Carter 2007-2008
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Lesser General Public
11 License as published by the Free Software Foundation; either
12 version 3 of the License, or (at your option) any later version.
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Library General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 /* Required Headers */
26 #include "libwbclient.h"
27 #include "../winbind_client.h"
29 /** @brief Ping winbindd to see if the daemon is running
35 struct winbindd_request request
;
36 struct winbindd_response response
;
38 /* Initialize request */
41 ZERO_STRUCT(response
);
43 return wbcRequestResponse(WINBINDD_PING
, &request
, &response
);
46 static void wbcInterfaceDetailsDestructor(void *ptr
)
48 struct wbcInterfaceDetails
*i
= (struct wbcInterfaceDetails
*)ptr
;
49 free(i
->winbind_version
);
50 free(i
->netbios_name
);
51 free(i
->netbios_domain
);
56 * @brief Query useful information about the winbind service
58 * @param *_details pointer to hold the struct wbcInterfaceDetails
63 wbcErr
wbcInterfaceDetails(struct wbcInterfaceDetails
**_details
)
65 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
66 struct wbcInterfaceDetails
*info
;
67 struct wbcDomainInfo
*domain
= NULL
;
68 struct winbindd_request request
;
69 struct winbindd_response response
;
71 /* Initialize request */
74 ZERO_STRUCT(response
);
76 info
= (struct wbcInterfaceDetails
*)wbcAllocateMemory(
77 1, sizeof(struct wbcInterfaceDetails
),
78 wbcInterfaceDetailsDestructor
);
79 BAIL_ON_PTR_ERROR(info
, wbc_status
);
81 /* first the interface version */
82 wbc_status
= wbcRequestResponse(WINBINDD_INTERFACE_VERSION
, NULL
, &response
);
83 BAIL_ON_WBC_ERROR(wbc_status
);
84 info
->interface_version
= response
.data
.interface_version
;
86 /* then the samba version and the winbind separator */
87 wbc_status
= wbcRequestResponse(WINBINDD_INFO
, NULL
, &response
);
88 BAIL_ON_WBC_ERROR(wbc_status
);
90 info
->winbind_version
= strdup(response
.data
.info
.samba_version
);
91 BAIL_ON_PTR_ERROR(info
->winbind_version
, wbc_status
);
92 info
->winbind_separator
= response
.data
.info
.winbind_separator
;
94 /* then the local netbios name */
95 wbc_status
= wbcRequestResponse(WINBINDD_NETBIOS_NAME
, NULL
, &response
);
96 BAIL_ON_WBC_ERROR(wbc_status
);
98 info
->netbios_name
= strdup(response
.data
.netbios_name
);
99 BAIL_ON_PTR_ERROR(info
->netbios_name
, wbc_status
);
101 /* then the local workgroup name */
102 wbc_status
= wbcRequestResponse(WINBINDD_DOMAIN_NAME
, NULL
, &response
);
103 BAIL_ON_WBC_ERROR(wbc_status
);
105 info
->netbios_domain
= strdup(response
.data
.domain_name
);
106 BAIL_ON_PTR_ERROR(info
->netbios_domain
, wbc_status
);
108 wbc_status
= wbcDomainInfo(info
->netbios_domain
, &domain
);
109 if (wbc_status
== WBC_ERR_DOMAIN_NOT_FOUND
) {
110 /* maybe it's a standalone server */
112 wbc_status
= WBC_ERR_SUCCESS
;
114 BAIL_ON_WBC_ERROR(wbc_status
);
118 info
->dns_domain
= strdup(domain
->dns_name
);
119 wbcFreeMemory(domain
);
120 BAIL_ON_PTR_ERROR(info
->dns_domain
, wbc_status
);
122 info
->dns_domain
= NULL
;
128 wbc_status
= WBC_ERR_SUCCESS
;
135 static void wbcDomainInfoDestructor(void *ptr
)
137 struct wbcDomainInfo
*i
= (struct wbcDomainInfo
*)ptr
;
142 /** @brief Lookup the current status of a trusted domain, sync wrapper
144 * @param domain Domain to query
145 * @param *dinfo Pointer to returned struct wbcDomainInfo
150 wbcErr
wbcDomainInfo(const char *domain
, struct wbcDomainInfo
**dinfo
)
152 struct winbindd_request request
;
153 struct winbindd_response response
;
154 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
155 struct wbcDomainInfo
*info
= NULL
;
157 if (!domain
|| !dinfo
) {
158 wbc_status
= WBC_ERR_INVALID_PARAM
;
159 BAIL_ON_WBC_ERROR(wbc_status
);
162 /* Initialize request */
164 ZERO_STRUCT(request
);
165 ZERO_STRUCT(response
);
167 strncpy(request
.domain_name
, domain
,
168 sizeof(request
.domain_name
)-1);
170 wbc_status
= wbcRequestResponse(WINBINDD_DOMAIN_INFO
,
173 BAIL_ON_WBC_ERROR(wbc_status
);
175 info
= (struct wbcDomainInfo
*)wbcAllocateMemory(
176 1, sizeof(struct wbcDomainInfo
), wbcDomainInfoDestructor
);
177 BAIL_ON_PTR_ERROR(info
, wbc_status
);
179 info
->short_name
= strdup(response
.data
.domain_info
.name
);
180 BAIL_ON_PTR_ERROR(info
->short_name
, wbc_status
);
182 info
->dns_name
= strdup(response
.data
.domain_info
.alt_name
);
183 BAIL_ON_PTR_ERROR(info
->dns_name
, wbc_status
);
185 wbc_status
= wbcStringToSid(response
.data
.domain_info
.sid
,
187 BAIL_ON_WBC_ERROR(wbc_status
);
189 if (response
.data
.domain_info
.native_mode
)
190 info
->domain_flags
|= WBC_DOMINFO_DOMAIN_NATIVE
;
191 if (response
.data
.domain_info
.active_directory
)
192 info
->domain_flags
|= WBC_DOMINFO_DOMAIN_AD
;
193 if (response
.data
.domain_info
.primary
)
194 info
->domain_flags
|= WBC_DOMINFO_DOMAIN_PRIMARY
;
199 wbc_status
= WBC_ERR_SUCCESS
;
206 /* Get the list of current DCs */
207 wbcErr
wbcDcInfo(const char *domain
, size_t *num_dcs
,
208 const char ***dc_names
, const char ***dc_ips
)
210 struct winbindd_request request
;
211 struct winbindd_response response
;
212 const char **names
= NULL
;
213 const char **ips
= NULL
;
214 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
219 /* Initialise request */
221 ZERO_STRUCT(request
);
222 ZERO_STRUCT(response
);
224 if (domain
!= NULL
) {
225 strncpy(request
.domain_name
, domain
,
226 sizeof(request
.domain_name
) - 1);
229 wbc_status
= wbcRequestResponse(WINBINDD_DC_INFO
,
230 &request
, &response
);
231 BAIL_ON_WBC_ERROR(wbc_status
);
233 names
= wbcAllocateStringArray(response
.data
.num_entries
);
234 BAIL_ON_PTR_ERROR(names
, wbc_status
);
236 ips
= wbcAllocateStringArray(response
.data
.num_entries
);
237 BAIL_ON_PTR_ERROR(ips
, wbc_status
);
239 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
241 p
= (char *)response
.extra_data
.data
;
243 if (response
.length
< (sizeof(struct winbindd_response
)+1)) {
247 extra_len
= response
.length
- sizeof(struct winbindd_response
);
249 if (p
[extra_len
-1] != '\0') {
253 for (i
=0; i
<response
.data
.num_entries
; i
++) {
260 names
[i
] = strndup(p
, q
-p
);
261 BAIL_ON_PTR_ERROR(names
[i
], wbc_status
);
268 ips
[i
] = strndup(p
, q
-p
);
269 BAIL_ON_PTR_ERROR(ips
[i
], wbc_status
);
276 wbc_status
= WBC_ERR_SUCCESS
;
278 if (response
.extra_data
.data
)
279 free(response
.extra_data
.data
);
281 if (WBC_ERROR_IS_OK(wbc_status
)) {
282 *num_dcs
= response
.data
.num_entries
;
288 wbcFreeMemory(names
);
293 /* Resolve a NetbiosName via WINS */
294 wbcErr
wbcResolveWinsByName(const char *name
, char **ip
)
296 struct winbindd_request request
;
297 struct winbindd_response response
;
298 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
301 ZERO_STRUCT(request
);
302 ZERO_STRUCT(response
);
306 strncpy(request
.data
.winsreq
, name
,
307 sizeof(request
.data
.winsreq
)-1);
309 wbc_status
= wbcRequestResponse(WINBINDD_WINS_BYNAME
,
312 BAIL_ON_WBC_ERROR(wbc_status
);
314 /* Display response */
316 ipaddr
= wbcStrDup(response
.data
.winsresp
);
317 BAIL_ON_PTR_ERROR(ipaddr
, wbc_status
);
320 wbc_status
= WBC_ERR_SUCCESS
;
326 /* Resolve an IP address via WINS into a NetbiosName */
327 wbcErr
wbcResolveWinsByIP(const char *ip
, char **name
)
329 struct winbindd_request request
;
330 struct winbindd_response response
;
331 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
334 ZERO_STRUCT(request
);
335 ZERO_STRUCT(response
);
339 strncpy(request
.data
.winsreq
, ip
,
340 sizeof(request
.data
.winsreq
)-1);
342 wbc_status
= wbcRequestResponse(WINBINDD_WINS_BYIP
,
345 BAIL_ON_WBC_ERROR(wbc_status
);
347 /* Display response */
349 name_str
= wbcStrDup(response
.data
.winsresp
);
350 BAIL_ON_PTR_ERROR(name_str
, wbc_status
);
353 wbc_status
= WBC_ERR_SUCCESS
;
362 static wbcErr
process_domain_info_string(struct wbcDomainInfo
*info
,
365 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
372 if ((s
= strchr(r
, '\\')) == NULL
) {
373 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
374 BAIL_ON_WBC_ERROR(wbc_status
);
379 info
->short_name
= strdup(r
);
380 BAIL_ON_PTR_ERROR(info
->short_name
, wbc_status
);
385 if ((s
= strchr(r
, '\\')) == NULL
) {
386 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
387 BAIL_ON_WBC_ERROR(wbc_status
);
392 info
->dns_name
= strdup(r
);
393 BAIL_ON_PTR_ERROR(info
->dns_name
, wbc_status
);
397 if ((s
= strchr(r
, '\\')) == NULL
) {
398 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
399 BAIL_ON_WBC_ERROR(wbc_status
);
404 wbc_status
= wbcStringToSid(r
, &info
->sid
);
405 BAIL_ON_WBC_ERROR(wbc_status
);
409 if ((s
= strchr(r
, '\\')) == NULL
) {
410 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
411 BAIL_ON_WBC_ERROR(wbc_status
);
416 if (strcmp(r
, "None") == 0) {
417 info
->trust_type
= WBC_DOMINFO_TRUSTTYPE_NONE
;
418 } else if (strcmp(r
, "External") == 0) {
419 info
->trust_type
= WBC_DOMINFO_TRUSTTYPE_EXTERNAL
;
420 } else if (strcmp(r
, "Forest") == 0) {
421 info
->trust_type
= WBC_DOMINFO_TRUSTTYPE_FOREST
;
422 } else if (strcmp(r
, "In Forest") == 0) {
423 info
->trust_type
= WBC_DOMINFO_TRUSTTYPE_IN_FOREST
;
425 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
426 BAIL_ON_WBC_ERROR(wbc_status
);
431 if ((s
= strchr(r
, '\\')) == NULL
) {
432 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
433 BAIL_ON_WBC_ERROR(wbc_status
);
438 if (strcmp(r
, "Yes") == 0) {
439 info
->trust_flags
|= WBC_DOMINFO_TRUST_TRANSITIVE
;
444 if ((s
= strchr(r
, '\\')) == NULL
) {
445 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
446 BAIL_ON_WBC_ERROR(wbc_status
);
451 if (strcmp(r
, "Yes") == 0) {
452 info
->trust_flags
|= WBC_DOMINFO_TRUST_INCOMING
;
457 if ((s
= strchr(r
, '\\')) == NULL
) {
458 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
459 BAIL_ON_WBC_ERROR(wbc_status
);
464 if (strcmp(r
, "Yes") == 0) {
465 info
->trust_flags
|= WBC_DOMINFO_TRUST_OUTGOING
;
468 /* Online/Offline status */
472 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
473 BAIL_ON_WBC_ERROR(wbc_status
);
475 if ( strcmp(r
, "Offline") == 0) {
476 info
->domain_flags
|= WBC_DOMINFO_DOMAIN_OFFLINE
;
479 wbc_status
= WBC_ERR_SUCCESS
;
485 static void wbcDomainInfoListDestructor(void *ptr
)
487 struct wbcDomainInfo
*i
= (struct wbcDomainInfo
*)ptr
;
489 while (i
->short_name
!= NULL
) {
496 /* Enumerate the domain trusts known by Winbind */
497 wbcErr
wbcListTrusts(struct wbcDomainInfo
**domains
, size_t *num_domains
)
499 struct winbindd_response response
;
500 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
502 char *extra_data
= NULL
;
503 struct wbcDomainInfo
*d_list
= NULL
;
509 ZERO_STRUCT(response
);
513 wbc_status
= wbcRequestResponse(WINBINDD_LIST_TRUSTDOM
,
516 BAIL_ON_WBC_ERROR(wbc_status
);
518 /* Decode the response */
520 p
= (char *)response
.extra_data
.data
;
522 if ((p
== NULL
) || (strlen(p
) == 0)) {
523 /* We should always at least get back our
526 wbc_status
= WBC_ERR_DOMAIN_NOT_FOUND
;
527 BAIL_ON_WBC_ERROR(wbc_status
);
530 d_list
= (struct wbcDomainInfo
*)wbcAllocateMemory(
531 response
.data
.num_entries
+ 1,sizeof(struct wbcDomainInfo
),
532 wbcDomainInfoListDestructor
);
533 BAIL_ON_PTR_ERROR(d_list
, wbc_status
);
535 extra_data
= strdup((char*)response
.extra_data
.data
);
536 BAIL_ON_PTR_ERROR(extra_data
, wbc_status
);
540 /* Outer loop processes the list of domain information */
542 for (i
=0; i
<response
.data
.num_entries
&& p
; i
++) {
543 char *next
= strchr(p
, '\n');
550 wbc_status
= process_domain_info_string(&d_list
[i
], p
);
551 BAIL_ON_WBC_ERROR(wbc_status
);
561 winbindd_free_response(&response
);
562 wbcFreeMemory(d_list
);
567 static void wbcDomainControllerInfoDestructor(void *ptr
)
569 struct wbcDomainControllerInfo
*i
=
570 (struct wbcDomainControllerInfo
*)ptr
;
574 /* Enumerate the domain trusts known by Winbind */
575 wbcErr
wbcLookupDomainController(const char *domain
,
577 struct wbcDomainControllerInfo
**dc_info
)
579 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
580 struct winbindd_request request
;
581 struct winbindd_response response
;
582 struct wbcDomainControllerInfo
*dc
= NULL
;
584 /* validate input params */
586 if (!domain
|| !dc_info
) {
587 wbc_status
= WBC_ERR_INVALID_PARAM
;
588 BAIL_ON_WBC_ERROR(wbc_status
);
591 ZERO_STRUCT(request
);
592 ZERO_STRUCT(response
);
594 strncpy(request
.data
.dsgetdcname
.domain_name
, domain
,
595 sizeof(request
.data
.dsgetdcname
.domain_name
)-1);
597 request
.flags
= flags
;
599 dc
= (struct wbcDomainControllerInfo
*)wbcAllocateMemory(
600 1, sizeof(struct wbcDomainControllerInfo
),
601 wbcDomainControllerInfoDestructor
);
602 BAIL_ON_PTR_ERROR(dc
, wbc_status
);
606 wbc_status
= wbcRequestResponse(WINBINDD_DSGETDCNAME
,
609 BAIL_ON_WBC_ERROR(wbc_status
);
611 dc
->dc_name
= strdup(response
.data
.dsgetdcname
.dc_unc
);
612 BAIL_ON_PTR_ERROR(dc
->dc_name
, wbc_status
);
622 static void wbcDomainControllerInfoExDestructor(void *ptr
)
624 struct wbcDomainControllerInfoEx
*i
=
625 (struct wbcDomainControllerInfoEx
*)ptr
;
626 free(discard_const_p(char, i
->dc_unc
));
627 free(discard_const_p(char, i
->dc_address
));
628 free(discard_const_p(char, i
->domain_guid
));
629 free(discard_const_p(char, i
->domain_name
));
630 free(discard_const_p(char, i
->forest_name
));
631 free(discard_const_p(char, i
->dc_site_name
));
632 free(discard_const_p(char, i
->client_site_name
));
635 static wbcErr
wbc_create_domain_controller_info_ex(const struct winbindd_response
*resp
,
636 struct wbcDomainControllerInfoEx
**_i
)
638 wbcErr wbc_status
= WBC_ERR_SUCCESS
;
639 struct wbcDomainControllerInfoEx
*i
;
642 i
= (struct wbcDomainControllerInfoEx
*)wbcAllocateMemory(
643 1, sizeof(struct wbcDomainControllerInfoEx
),
644 wbcDomainControllerInfoExDestructor
);
645 BAIL_ON_PTR_ERROR(i
, wbc_status
);
647 i
->dc_unc
= strdup(resp
->data
.dsgetdcname
.dc_unc
);
648 BAIL_ON_PTR_ERROR(i
->dc_unc
, wbc_status
);
650 i
->dc_address
= strdup(resp
->data
.dsgetdcname
.dc_address
);
651 BAIL_ON_PTR_ERROR(i
->dc_address
, wbc_status
);
653 i
->dc_address_type
= resp
->data
.dsgetdcname
.dc_address_type
;
655 wbc_status
= wbcStringToGuid(resp
->data
.dsgetdcname
.domain_guid
, &guid
);
656 if (WBC_ERROR_IS_OK(wbc_status
)) {
657 i
->domain_guid
= (struct wbcGuid
*)malloc(
658 sizeof(struct wbcGuid
));
659 BAIL_ON_PTR_ERROR(i
->domain_guid
, wbc_status
);
661 *i
->domain_guid
= guid
;
664 i
->domain_name
= strdup(resp
->data
.dsgetdcname
.domain_name
);
665 BAIL_ON_PTR_ERROR(i
->domain_name
, wbc_status
);
667 if (resp
->data
.dsgetdcname
.forest_name
[0] != '\0') {
668 i
->forest_name
= strdup(resp
->data
.dsgetdcname
.forest_name
);
669 BAIL_ON_PTR_ERROR(i
->forest_name
, wbc_status
);
672 i
->dc_flags
= resp
->data
.dsgetdcname
.dc_flags
;
674 if (resp
->data
.dsgetdcname
.dc_site_name
[0] != '\0') {
675 i
->dc_site_name
= strdup(resp
->data
.dsgetdcname
.dc_site_name
);
676 BAIL_ON_PTR_ERROR(i
->dc_site_name
, wbc_status
);
679 if (resp
->data
.dsgetdcname
.client_site_name
[0] != '\0') {
680 i
->client_site_name
= strdup(
681 resp
->data
.dsgetdcname
.client_site_name
);
682 BAIL_ON_PTR_ERROR(i
->client_site_name
, wbc_status
);
695 /* Get extended domain controller information */
696 wbcErr
wbcLookupDomainControllerEx(const char *domain
,
697 struct wbcGuid
*guid
,
700 struct wbcDomainControllerInfoEx
**dc_info
)
702 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
703 struct winbindd_request request
;
704 struct winbindd_response response
;
706 /* validate input params */
708 if (!domain
|| !dc_info
) {
709 wbc_status
= WBC_ERR_INVALID_PARAM
;
710 BAIL_ON_WBC_ERROR(wbc_status
);
713 ZERO_STRUCT(request
);
714 ZERO_STRUCT(response
);
716 request
.data
.dsgetdcname
.flags
= flags
;
718 strncpy(request
.data
.dsgetdcname
.domain_name
, domain
,
719 sizeof(request
.data
.dsgetdcname
.domain_name
)-1);
722 strncpy(request
.data
.dsgetdcname
.site_name
, site
,
723 sizeof(request
.data
.dsgetdcname
.site_name
)-1);
729 wbc_status
= wbcGuidToString(guid
, &str
);
730 BAIL_ON_WBC_ERROR(wbc_status
);
732 strncpy(request
.data
.dsgetdcname
.domain_guid
, str
,
733 sizeof(request
.data
.dsgetdcname
.domain_guid
)-1);
740 wbc_status
= wbcRequestResponse(WINBINDD_DSGETDCNAME
,
743 BAIL_ON_WBC_ERROR(wbc_status
);
746 wbc_status
= wbc_create_domain_controller_info_ex(&response
,
748 BAIL_ON_WBC_ERROR(wbc_status
);
751 wbc_status
= WBC_ERR_SUCCESS
;
756 static void wbcNamedBlobDestructor(void *ptr
)
758 struct wbcNamedBlob
*b
= (struct wbcNamedBlob
*)ptr
;
760 while (b
->name
!= NULL
) {
761 free(discard_const_p(char, b
->name
));
767 /* Initialize a named blob and add to list of blobs */
768 wbcErr
wbcAddNamedBlob(size_t *num_blobs
,
769 struct wbcNamedBlob
**pblobs
,
775 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
776 struct wbcNamedBlob
*blobs
, *blob
;
779 return WBC_ERR_INVALID_PARAM
;
783 * Overallocate the b->name==NULL terminator for
784 * wbcNamedBlobDestructor
786 blobs
= (struct wbcNamedBlob
*)wbcAllocateMemory(
787 *num_blobs
+ 2, sizeof(struct wbcNamedBlob
),
788 wbcNamedBlobDestructor
);
791 return WBC_ERR_NO_MEMORY
;
794 if (*pblobs
!= NULL
) {
795 struct wbcNamedBlob
*old
= *pblobs
;
796 memcpy(blobs
, old
, sizeof(struct wbcNamedBlob
) * (*num_blobs
));
797 if (*num_blobs
!= 0) {
798 /* end indicator for wbcNamedBlobDestructor */
805 blob
= &blobs
[*num_blobs
];
807 blob
->name
= strdup(name
);
808 BAIL_ON_PTR_ERROR(blob
->name
, wbc_status
);
811 blob
->blob
.length
= length
;
812 blob
->blob
.data
= (uint8_t *)malloc(length
);
813 BAIL_ON_PTR_ERROR(blob
->blob
.data
, wbc_status
);
814 memcpy(blob
->blob
.data
, data
, length
);
820 wbc_status
= WBC_ERR_SUCCESS
;
822 wbcFreeMemory(blobs
);