2 Unix SMB/CIFS implementation.
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 */
25 #include "libwbclient.h"
29 /** @brief Ping winbindd to see if the daemon is running
36 struct winbindd_request request;
37 struct winbindd_response response;
39 /* Initialize request */
42 ZERO_STRUCT(response);
44 return wbcRequestResponse(WINBINDD_PING, &request, &response);
47 wbcErr wbcInterfaceDetails(struct wbcInterfaceDetails **_details)
49 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
50 struct wbcInterfaceDetails *info;
51 struct wbcDomainInfo *domain = NULL;
52 struct winbindd_request request;
53 struct winbindd_response response;
55 /* Initialize request */
58 ZERO_STRUCT(response);
60 info = talloc(NULL, struct wbcInterfaceDetails);
61 BAIL_ON_PTR_ERROR(info, wbc_status);
63 /* first the interface version */
64 wbc_status = wbcRequestResponse(WINBINDD_INTERFACE_VERSION, NULL, &response);
65 BAIL_ON_WBC_ERROR(wbc_status);
66 info->interface_version = response.data.interface_version;
68 /* then the samba version and the winbind separator */
69 wbc_status = wbcRequestResponse(WINBINDD_INFO, NULL, &response);
70 BAIL_ON_WBC_ERROR(wbc_status);
72 info->winbind_version = talloc_strdup(info,
73 response.data.info.samba_version);
74 BAIL_ON_PTR_ERROR(info->winbind_version, wbc_status);
75 info->winbind_separator = response.data.info.winbind_separator;
77 /* then the local netbios name */
78 wbc_status = wbcRequestResponse(WINBINDD_NETBIOS_NAME, NULL, &response);
79 BAIL_ON_WBC_ERROR(wbc_status);
81 info->netbios_name = talloc_strdup(info,
82 response.data.netbios_name);
83 BAIL_ON_PTR_ERROR(info->netbios_name, wbc_status);
85 /* then the local workgroup name */
86 wbc_status = wbcRequestResponse(WINBINDD_DOMAIN_NAME, NULL, &response);
87 BAIL_ON_WBC_ERROR(wbc_status);
89 info->netbios_domain = talloc_strdup(info,
90 response.data.domain_name);
91 BAIL_ON_PTR_ERROR(info->netbios_domain, wbc_status);
93 wbc_status = wbcDomainInfo(info->netbios_domain, &domain);
94 if (wbc_status == WBC_ERR_DOMAIN_NOT_FOUND) {
95 /* maybe it's a standalone server */
97 wbc_status = WBC_ERR_SUCCESS;
99 BAIL_ON_WBC_ERROR(wbc_status);
103 info->dns_domain = talloc_strdup(info,
105 wbcFreeMemory(domain);
106 BAIL_ON_PTR_ERROR(info->dns_domain, wbc_status);
108 info->dns_domain = NULL;
114 wbc_status = WBC_ERR_SUCCESS;
122 /* Lookup the current status of a trusted domain */
123 wbcErr wbcDomainInfo(const char *domain, struct wbcDomainInfo **dinfo)
125 struct winbindd_request request;
126 struct winbindd_response response;
127 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
128 struct wbcDomainInfo *info = NULL;
130 if (!domain || !dinfo) {
131 wbc_status = WBC_ERR_INVALID_PARAM;
132 BAIL_ON_WBC_ERROR(wbc_status);
135 /* Initialize request */
137 ZERO_STRUCT(request);
138 ZERO_STRUCT(response);
140 strncpy(request.domain_name, domain,
141 sizeof(request.domain_name)-1);
143 wbc_status = wbcRequestResponse(WINBINDD_DOMAIN_INFO,
146 BAIL_ON_WBC_ERROR(wbc_status);
148 info = talloc(NULL, struct wbcDomainInfo);
149 BAIL_ON_PTR_ERROR(info, wbc_status);
151 info->short_name = talloc_strdup(info,
152 response.data.domain_info.name);
153 BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
155 info->dns_name = talloc_strdup(info,
156 response.data.domain_info.alt_name);
157 BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
159 wbc_status = wbcStringToSid(response.data.domain_info.sid,
161 BAIL_ON_WBC_ERROR(wbc_status);
163 if (response.data.domain_info.native_mode)
164 info->domain_flags |= WBC_DOMINFO_DOMAIN_NATIVE;
165 if (response.data.domain_info.active_directory)
166 info->domain_flags |= WBC_DOMINFO_DOMAIN_AD;
167 if (response.data.domain_info.primary)
168 info->domain_flags |= WBC_DOMINFO_DOMAIN_PRIMARY;
172 wbc_status = WBC_ERR_SUCCESS;
175 if (!WBC_ERROR_IS_OK(wbc_status)) {
182 /* Get the list of current DCs */
183 wbcErr wbcDcInfo(const char *domain, size_t *num_dcs,
184 const char ***dc_names, const char ***dc_ips)
186 struct winbindd_request request;
187 struct winbindd_response response;
188 const char **names = NULL;
189 const char **ips = NULL;
190 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
195 /* Initialise request */
197 ZERO_STRUCT(request);
198 ZERO_STRUCT(response);
200 if (domain != NULL) {
201 strncpy(request.domain_name, domain,
202 sizeof(request.domain_name) - 1);
205 wbc_status = wbcRequestResponse(WINBINDD_DC_INFO,
206 &request, &response);
207 BAIL_ON_WBC_ERROR(wbc_status);
209 names = talloc_zero_array(NULL, const char *,
210 response.data.num_entries);
211 BAIL_ON_PTR_ERROR(names, wbc_status);
213 ips = talloc_zero_array(NULL, const char *,
214 response.data.num_entries);
215 BAIL_ON_PTR_ERROR(names, wbc_status);
217 wbc_status = WBC_ERR_INVALID_RESPONSE;
219 p = (char *)response.extra_data.data;
221 if (response.length < (sizeof(struct winbindd_response)+1)) {
225 extra_len = response.length - sizeof(struct winbindd_response);
227 if (p[extra_len-1] != '\0') {
231 for (i=0; i<response.data.num_entries; i++) {
238 names[i] = talloc_strndup(names, p, q-p);
239 BAIL_ON_PTR_ERROR(names[i], wbc_status);
246 ips[i] = talloc_strndup(ips, p, q-p);
247 BAIL_ON_PTR_ERROR(ips[i], wbc_status);
254 wbc_status = WBC_ERR_SUCCESS;
256 if (response.extra_data.data)
257 free(response.extra_data.data);
259 if (WBC_ERROR_IS_OK(wbc_status)) {
260 *num_dcs = response.data.num_entries;
266 wbcFreeMemory(names);
271 /* Resolve a NetbiosName via WINS */
272 wbcErr wbcResolveWinsByName(const char *name, char **ip)
274 struct winbindd_request request;
275 struct winbindd_response response;
276 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
279 ZERO_STRUCT(request);
280 ZERO_STRUCT(response);
284 strncpy(request.data.winsreq, name,
285 sizeof(request.data.winsreq)-1);
287 wbc_status = wbcRequestResponse(WINBINDD_WINS_BYNAME,
290 BAIL_ON_WBC_ERROR(wbc_status);
292 /* Display response */
294 ipaddr = talloc_strdup(NULL, response.data.winsresp);
295 BAIL_ON_PTR_ERROR(ipaddr, wbc_status);
298 wbc_status = WBC_ERR_SUCCESS;
304 /* Resolve an IP address via WINS into a NetbiosName */
305 wbcErr wbcResolveWinsByIP(const char *ip, char **name)
307 struct winbindd_request request;
308 struct winbindd_response response;
309 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
312 ZERO_STRUCT(request);
313 ZERO_STRUCT(response);
317 strncpy(request.data.winsreq, ip,
318 sizeof(request.data.winsreq)-1);
320 wbc_status = wbcRequestResponse(WINBINDD_WINS_BYIP,
323 BAIL_ON_WBC_ERROR(wbc_status);
325 /* Display response */
327 name_str = talloc_strdup(NULL, response.data.winsresp);
328 BAIL_ON_PTR_ERROR(name_str, wbc_status);
331 wbc_status = WBC_ERR_SUCCESS;
340 static wbcErr process_domain_info_string(TALLOC_CTX *ctx,
341 struct wbcDomainInfo *info,
344 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
348 if (!info || !info_string) {
349 wbc_status = WBC_ERR_INVALID_PARAM;
350 BAIL_ON_WBC_ERROR(wbc_status);
358 if ((s = strchr(r, '\\')) == NULL) {
359 wbc_status = WBC_ERR_INVALID_RESPONSE;
360 BAIL_ON_WBC_ERROR(wbc_status);
365 info->short_name = talloc_strdup(ctx, r);
366 BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
371 if ((s = strchr(r, '\\')) == NULL) {
372 wbc_status = WBC_ERR_INVALID_RESPONSE;
373 BAIL_ON_WBC_ERROR(wbc_status);
378 info->dns_name = talloc_strdup(ctx, r);
379 BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
383 if ((s = strchr(r, '\\')) == NULL) {
384 wbc_status = WBC_ERR_INVALID_RESPONSE;
385 BAIL_ON_WBC_ERROR(wbc_status);
390 wbc_status = wbcStringToSid(r, &info->sid);
391 BAIL_ON_WBC_ERROR(wbc_status);
395 if ((s = strchr(r, '\\')) == NULL) {
396 wbc_status = WBC_ERR_INVALID_RESPONSE;
397 BAIL_ON_WBC_ERROR(wbc_status);
402 if (strcmp(r, "None") == 0) {
403 info->trust_type = WBC_DOMINFO_TRUSTTYPE_NONE;
404 } else if (strcmp(r, "External") == 0) {
405 info->trust_type = WBC_DOMINFO_TRUSTTYPE_EXTERNAL;
406 } else if (strcmp(r, "Forest") == 0) {
407 info->trust_type = WBC_DOMINFO_TRUSTTYPE_FOREST;
408 } else if (strcmp(r, "In Forest") == 0) {
409 info->trust_type = WBC_DOMINFO_TRUSTTYPE_IN_FOREST;
411 wbc_status = WBC_ERR_INVALID_RESPONSE;
412 BAIL_ON_WBC_ERROR(wbc_status);
417 if ((s = strchr(r, '\\')) == NULL) {
418 wbc_status = WBC_ERR_INVALID_RESPONSE;
419 BAIL_ON_WBC_ERROR(wbc_status);
424 if (strcmp(r, "Yes") == 0) {
425 info->trust_flags |= WBC_DOMINFO_TRUST_TRANSITIVE;
430 if ((s = strchr(r, '\\')) == NULL) {
431 wbc_status = WBC_ERR_INVALID_RESPONSE;
432 BAIL_ON_WBC_ERROR(wbc_status);
437 if (strcmp(r, "Yes") == 0) {
438 info->trust_flags |= WBC_DOMINFO_TRUST_INCOMING;
443 if ((s = strchr(r, '\\')) == NULL) {
444 wbc_status = WBC_ERR_INVALID_RESPONSE;
445 BAIL_ON_WBC_ERROR(wbc_status);
450 if (strcmp(r, "Yes") == 0) {
451 info->trust_flags |= WBC_DOMINFO_TRUST_OUTGOING;
454 /* Online/Offline status */
458 wbc_status = WBC_ERR_INVALID_RESPONSE;
459 BAIL_ON_WBC_ERROR(wbc_status);
461 if ( strcmp(r, "Offline") == 0) {
462 info->domain_flags |= WBC_DOMINFO_DOMAIN_OFFLINE;
465 wbc_status = WBC_ERR_SUCCESS;
471 /* Enumerate the domain trusts known by Winbind */
472 wbcErr wbcListTrusts(struct wbcDomainInfo **domains, size_t *num_domains)
474 struct winbindd_response response;
475 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
478 char *extra_data = NULL;
480 struct wbcDomainInfo *d_list = NULL;
486 ZERO_STRUCT(response);
490 wbc_status = wbcRequestResponse(WINBINDD_LIST_TRUSTDOM,
493 BAIL_ON_WBC_ERROR(wbc_status);
495 /* Decode the response */
497 p = (char *)response.extra_data.data;
499 if (strlen(p) == 0) {
500 /* We should always at least get back our
503 wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
504 BAIL_ON_WBC_ERROR(wbc_status);
507 /* Count number of domains */
513 if ((q = strchr(p, '\n')) != NULL)
518 d_list = talloc_array(NULL, struct wbcDomainInfo, count);
519 BAIL_ON_PTR_ERROR(d_list, wbc_status);
521 extra_data = strdup((char*)response.extra_data.data);
522 BAIL_ON_PTR_ERROR(extra_data, wbc_status);
526 /* Outer loop processes the list of domain information */
528 for (i=0; i<count && p; i++) {
529 char *next = strchr(p, '\n');
536 wbc_status = process_domain_info_string(d_list, &d_list[i], p);
537 BAIL_ON_WBC_ERROR(wbc_status);
546 if (!WBC_ERROR_IS_OK(wbc_status)) {
556 /* Enumerate the domain trusts known by Winbind */
557 wbcErr wbcLookupDomainController(const char *domain,
559 struct wbcDomainControllerInfo **dc_info)
561 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
562 struct winbindd_request request;
563 struct winbindd_response response;
564 struct wbcDomainControllerInfo *dc = NULL;
566 /* validate input params */
568 if (!domain || !dc_info) {
569 wbc_status = WBC_ERR_INVALID_PARAM;
570 BAIL_ON_WBC_ERROR(wbc_status);
573 ZERO_STRUCT(request);
574 ZERO_STRUCT(response);
576 strncpy(request.domain_name, domain, sizeof(request.domain_name)-1);
578 request.flags = flags;
580 dc = talloc(NULL, struct wbcDomainControllerInfo);
581 BAIL_ON_PTR_ERROR(dc, wbc_status);
585 wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
588 BAIL_ON_WBC_ERROR(wbc_status);
590 dc->dc_name = talloc_strdup(dc, response.data.dc_name);
591 BAIL_ON_PTR_ERROR(dc->dc_name, wbc_status);
596 if (!WBC_ERROR_IS_OK(wbc_status)) {
603 static wbcErr wbc_create_domain_controller_info_ex(TALLOC_CTX *mem_ctx,
604 const struct winbindd_response *resp,
605 struct wbcDomainControllerInfoEx **_i)
607 wbcErr wbc_status = WBC_ERR_SUCCESS;
608 struct wbcDomainControllerInfoEx *i;
611 i = talloc(mem_ctx, struct wbcDomainControllerInfoEx);
612 BAIL_ON_PTR_ERROR(i, wbc_status);
614 i->dc_unc = talloc_strdup(i, resp->data.dsgetdcname.dc_unc);
615 BAIL_ON_PTR_ERROR(i->dc_unc, wbc_status);
617 i->dc_address = talloc_strdup(i, resp->data.dsgetdcname.dc_address);
618 BAIL_ON_PTR_ERROR(i->dc_address, wbc_status);
620 i->dc_address_type = resp->data.dsgetdcname.dc_address_type;
622 wbc_status = wbcStringToGuid(resp->data.dsgetdcname.domain_guid, &guid);
623 if (WBC_ERROR_IS_OK(wbc_status)) {
624 i->domain_guid = talloc(i, struct wbcGuid);
625 BAIL_ON_PTR_ERROR(i->domain_guid, wbc_status);
627 *i->domain_guid = guid;
629 i->domain_guid = NULL;
632 i->domain_name = talloc_strdup(i, resp->data.dsgetdcname.domain_name);
633 BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
635 if (resp->data.dsgetdcname.forest_name[0] != '\0') {
636 i->forest_name = talloc_strdup(i,
637 resp->data.dsgetdcname.forest_name);
638 BAIL_ON_PTR_ERROR(i->forest_name, wbc_status);
640 i->forest_name = NULL;
643 i->dc_flags = resp->data.dsgetdcname.dc_flags;
645 if (resp->data.dsgetdcname.dc_site_name[0] != '\0') {
646 i->dc_site_name = talloc_strdup(i,
647 resp->data.dsgetdcname.dc_site_name);
648 BAIL_ON_PTR_ERROR(i->dc_site_name, wbc_status);
650 i->dc_site_name = NULL;
653 if (resp->data.dsgetdcname.client_site_name[0] != '\0') {
654 i->client_site_name = talloc_strdup(i,
655 resp->data.dsgetdcname.client_site_name);
656 BAIL_ON_PTR_ERROR(i->client_site_name, wbc_status);
658 i->client_site_name = NULL;
669 /* Get extended domain controller information */
670 wbcErr wbcLookupDomainControllerEx(const char *domain,
671 struct wbcGuid *guid,
674 struct wbcDomainControllerInfoEx **dc_info)
676 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
677 struct winbindd_request request;
678 struct winbindd_response response;
680 /* validate input params */
682 if (!domain || !dc_info) {
683 wbc_status = WBC_ERR_INVALID_PARAM;
684 BAIL_ON_WBC_ERROR(wbc_status);
687 ZERO_STRUCT(request);
688 ZERO_STRUCT(response);
690 request.data.dsgetdcname.flags = flags;
692 strncpy(request.data.dsgetdcname.domain_name, domain,
693 sizeof(request.data.dsgetdcname.domain_name)-1);
696 strncpy(request.data.dsgetdcname.site_name, site,
697 sizeof(request.data.dsgetdcname.site_name)-1);
703 wbc_status = wbcGuidToString(guid, &str);
704 BAIL_ON_WBC_ERROR(wbc_status);
706 strncpy(request.data.dsgetdcname.domain_guid, str,
707 sizeof(request.data.dsgetdcname.domain_guid)-1);
714 wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
717 BAIL_ON_WBC_ERROR(wbc_status);
720 wbc_status = wbc_create_domain_controller_info_ex(NULL,
723 BAIL_ON_WBC_ERROR(wbc_status);
726 wbc_status = WBC_ERR_SUCCESS;
731 /* Initialize a named blob and add to list of blobs */
732 wbcErr wbcAddNamedBlob(size_t *num_blobs,
733 struct wbcNamedBlob **blobs,
739 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
740 struct wbcNamedBlob blob;
742 *blobs = talloc_realloc(NULL, *blobs, struct wbcNamedBlob,
744 BAIL_ON_PTR_ERROR(*blobs, wbc_status);
746 blob.name = talloc_strdup(*blobs, name);
747 BAIL_ON_PTR_ERROR(blob.name, wbc_status);
749 blob.blob.length = length;
750 blob.blob.data = (uint8_t *)talloc_memdup(*blobs, data, length);
751 BAIL_ON_PTR_ERROR(blob.blob.data, wbc_status);
753 (*(blobs))[*num_blobs] = blob;
756 wbc_status = WBC_ERR_SUCCESS;
758 if (!WBC_ERROR_IS_OK(wbc_status) && blobs) {
759 wbcFreeMemory(*blobs);