s3:libwbclient: Fix bug 6349, initialize domain info struct
[Samba.git] / source / nsswitch / libwbclient / wbc_util.c
blob77613e0aa008d3308857543b555def7082ee39af
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind client API
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
31 * @return #wbcErr
32 **/
34 wbcErr wbcPing(void)
36 struct winbindd_request request;
37 struct winbindd_response response;
39 /* Initialize request */
41 ZERO_STRUCT(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 */
57 ZERO_STRUCT(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 */
96 domain = NULL;
97 wbc_status = WBC_ERR_SUCCESS;
98 } else {
99 BAIL_ON_WBC_ERROR(wbc_status);
102 if (domain) {
103 info->dns_domain = talloc_strdup(info,
104 domain->dns_name);
105 wbcFreeMemory(domain);
106 BAIL_ON_PTR_ERROR(info->dns_domain, wbc_status);
107 } else {
108 info->dns_domain = NULL;
111 *_details = info;
112 info = NULL;
114 wbc_status = WBC_ERR_SUCCESS;
116 done:
117 talloc_free(info);
118 return wbc_status;
122 /** @brief Lookup the current status of a trusted domain
124 * @param domain Domain to query
125 * @param *dinfo Pointer to returned domain_info struct
127 * @return #wbcErr
132 wbcErr wbcDomainInfo(const char *domain, struct wbcDomainInfo **dinfo)
134 struct winbindd_request request;
135 struct winbindd_response response;
136 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
137 struct wbcDomainInfo *info = NULL;
139 if (!domain || !dinfo) {
140 wbc_status = WBC_ERR_INVALID_PARAM;
141 BAIL_ON_WBC_ERROR(wbc_status);
144 /* Initialize request */
146 ZERO_STRUCT(request);
147 ZERO_STRUCT(response);
149 strncpy(request.domain_name, domain,
150 sizeof(request.domain_name)-1);
152 wbc_status = wbcRequestResponse(WINBINDD_DOMAIN_INFO,
153 &request,
154 &response);
155 BAIL_ON_WBC_ERROR(wbc_status);
157 info = talloc(NULL, struct wbcDomainInfo);
158 BAIL_ON_PTR_ERROR(info, wbc_status);
160 info->short_name = talloc_strdup(info,
161 response.data.domain_info.name);
162 BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
164 info->dns_name = talloc_strdup(info,
165 response.data.domain_info.alt_name);
166 BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
168 wbc_status = wbcStringToSid(response.data.domain_info.sid,
169 &info->sid);
170 BAIL_ON_WBC_ERROR(wbc_status);
172 if (response.data.domain_info.native_mode)
173 info->domain_flags |= WBC_DOMINFO_DOMAIN_NATIVE;
174 if (response.data.domain_info.active_directory)
175 info->domain_flags |= WBC_DOMINFO_DOMAIN_AD;
176 if (response.data.domain_info.primary)
177 info->domain_flags |= WBC_DOMINFO_DOMAIN_PRIMARY;
179 *dinfo = info;
181 wbc_status = WBC_ERR_SUCCESS;
183 done:
184 if (!WBC_ERROR_IS_OK(wbc_status)) {
185 talloc_free(info);
188 return wbc_status;
192 /** @brief Resolve a NetbiosName via WINS
194 * @param name Name to resolve
195 * @param *ip Pointer to the ip address string
197 * @return #wbcErr
200 wbcErr wbcResolveWinsByName(const char *name, char **ip)
202 struct winbindd_request request;
203 struct winbindd_response response;
204 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
205 char *ipaddr;
207 ZERO_STRUCT(request);
208 ZERO_STRUCT(response);
210 /* Send request */
212 strncpy(request.data.winsreq, name,
213 sizeof(request.data.winsreq)-1);
215 wbc_status = wbcRequestResponse(WINBINDD_WINS_BYNAME,
216 &request,
217 &response);
218 BAIL_ON_WBC_ERROR(wbc_status);
220 /* Display response */
222 ipaddr = talloc_strdup(NULL, response.data.winsresp);
223 BAIL_ON_PTR_ERROR(ipaddr, wbc_status);
225 *ip = ipaddr;
226 wbc_status = WBC_ERR_SUCCESS;
228 done:
229 return wbc_status;
232 /** @brief Resolve an IP address via WINS into a NetbiosName
234 * @param ip The ip address string
235 * @param *name Pointer to the name
237 * @return #wbcErr
240 wbcErr wbcResolveWinsByIP(const char *ip, char **name)
242 struct winbindd_request request;
243 struct winbindd_response response;
244 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
245 char *name_str;
247 ZERO_STRUCT(request);
248 ZERO_STRUCT(response);
250 /* Send request */
252 strncpy(request.data.winsreq, ip,
253 sizeof(request.data.winsreq)-1);
255 wbc_status = wbcRequestResponse(WINBINDD_WINS_BYIP,
256 &request,
257 &response);
258 BAIL_ON_WBC_ERROR(wbc_status);
260 /* Display response */
262 name_str = talloc_strdup(NULL, response.data.winsresp);
263 BAIL_ON_PTR_ERROR(name_str, wbc_status);
265 *name = name_str;
266 wbc_status = WBC_ERR_SUCCESS;
268 done:
269 return wbc_status;
275 static wbcErr process_domain_info_string(TALLOC_CTX *ctx,
276 struct wbcDomainInfo *info,
277 char *info_string)
279 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
280 char *r = NULL;
281 char *s = NULL;
283 if (!info || !info_string) {
284 wbc_status = WBC_ERR_INVALID_PARAM;
285 BAIL_ON_WBC_ERROR(wbc_status);
288 ZERO_STRUCTP(info);
290 r = info_string;
292 /* Short Name */
293 if ((s = strchr(r, '\\')) == NULL) {
294 wbc_status = WBC_ERR_INVALID_RESPONSE;
295 BAIL_ON_WBC_ERROR(wbc_status);
297 *s = '\0';
298 s++;
300 info->short_name = talloc_strdup(ctx, r);
301 BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
304 /* DNS Name */
305 r = s;
306 if ((s = strchr(r, '\\')) == NULL) {
307 wbc_status = WBC_ERR_INVALID_RESPONSE;
308 BAIL_ON_WBC_ERROR(wbc_status);
310 *s = '\0';
311 s++;
313 info->dns_name = talloc_strdup(ctx, r);
314 BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
316 /* SID */
317 r = s;
318 if ((s = strchr(r, '\\')) == NULL) {
319 wbc_status = WBC_ERR_INVALID_RESPONSE;
320 BAIL_ON_WBC_ERROR(wbc_status);
322 *s = '\0';
323 s++;
325 wbc_status = wbcStringToSid(r, &info->sid);
326 BAIL_ON_WBC_ERROR(wbc_status);
328 /* Trust type */
329 r = s;
330 if ((s = strchr(r, '\\')) == NULL) {
331 wbc_status = WBC_ERR_INVALID_RESPONSE;
332 BAIL_ON_WBC_ERROR(wbc_status);
334 *s = '\0';
335 s++;
337 if (strcmp(r, "None") == 0) {
338 info->trust_type = WBC_DOMINFO_TRUSTTYPE_NONE;
339 } else if (strcmp(r, "External") == 0) {
340 info->trust_type = WBC_DOMINFO_TRUSTTYPE_EXTERNAL;
341 } else if (strcmp(r, "Forest") == 0) {
342 info->trust_type = WBC_DOMINFO_TRUSTTYPE_FOREST;
343 } else if (strcmp(r, "In Forest") == 0) {
344 info->trust_type = WBC_DOMINFO_TRUSTTYPE_IN_FOREST;
345 } else {
346 wbc_status = WBC_ERR_INVALID_RESPONSE;
347 BAIL_ON_WBC_ERROR(wbc_status);
350 /* Transitive */
351 r = s;
352 if ((s = strchr(r, '\\')) == NULL) {
353 wbc_status = WBC_ERR_INVALID_RESPONSE;
354 BAIL_ON_WBC_ERROR(wbc_status);
356 *s = '\0';
357 s++;
359 if (strcmp(r, "Yes") == 0) {
360 info->trust_flags |= WBC_DOMINFO_TRUST_TRANSITIVE;
363 /* Incoming */
364 r = s;
365 if ((s = strchr(r, '\\')) == NULL) {
366 wbc_status = WBC_ERR_INVALID_RESPONSE;
367 BAIL_ON_WBC_ERROR(wbc_status);
369 *s = '\0';
370 s++;
372 if (strcmp(r, "Yes") == 0) {
373 info->trust_flags |= WBC_DOMINFO_TRUST_INCOMING;
376 /* Outgoing */
377 r = s;
378 if ((s = strchr(r, '\\')) == NULL) {
379 wbc_status = WBC_ERR_INVALID_RESPONSE;
380 BAIL_ON_WBC_ERROR(wbc_status);
382 *s = '\0';
383 s++;
385 if (strcmp(r, "Yes") == 0) {
386 info->trust_flags |= WBC_DOMINFO_TRUST_OUTGOING;
389 /* Online/Offline status */
391 r = s;
392 if (r == NULL) {
393 wbc_status = WBC_ERR_INVALID_RESPONSE;
394 BAIL_ON_WBC_ERROR(wbc_status);
396 if ( strcmp(r, "Offline") == 0) {
397 info->domain_flags |= WBC_DOMINFO_DOMAIN_OFFLINE;
400 wbc_status = WBC_ERR_SUCCESS;
402 done:
403 return wbc_status;
406 /** @brief Enumerate the domain trusts known by Winbind
408 * @param **domains Pointer to the allocated domain list array
409 * @param *num_domains Pointer to number of domains returned
411 * @return #wbcErr
414 wbcErr wbcListTrusts(struct wbcDomainInfo **domains, size_t *num_domains)
416 struct winbindd_response response;
417 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
418 char *p = NULL;
419 char *q = NULL;
420 char *extra_data = NULL;
421 int count = 0;
422 struct wbcDomainInfo *d_list = NULL;
423 int i = 0;
425 *domains = NULL;
426 *num_domains = 0;
428 ZERO_STRUCT(response);
430 /* Send request */
432 wbc_status = wbcRequestResponse(WINBINDD_LIST_TRUSTDOM,
433 NULL,
434 &response);
435 BAIL_ON_WBC_ERROR(wbc_status);
437 /* Decode the response */
439 p = (char *)response.extra_data.data;
441 if (strlen(p) == 0) {
442 /* We should always at least get back our
443 own SAM domain */
445 wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
446 BAIL_ON_WBC_ERROR(wbc_status);
449 /* Count number of domains */
451 count = 0;
452 while (p) {
453 count++;
455 if ((q = strchr(p, '\n')) != NULL)
456 q++;
457 p = q;
460 d_list = talloc_array(NULL, struct wbcDomainInfo, count);
461 BAIL_ON_PTR_ERROR(d_list, wbc_status);
463 extra_data = strdup((char*)response.extra_data.data);
464 BAIL_ON_PTR_ERROR(extra_data, wbc_status);
466 p = extra_data;
468 /* Outer loop processes the list of domain information */
470 for (i=0; i<count && p; i++) {
471 char *next = strchr(p, '\n');
473 if (next) {
474 *next = '\0';
475 next++;
478 wbc_status = process_domain_info_string(d_list, &d_list[i], p);
479 BAIL_ON_WBC_ERROR(wbc_status);
481 p = next;
484 *domains = d_list;
485 *num_domains = i;
487 done:
488 if (!WBC_ERROR_IS_OK(wbc_status)) {
489 if (d_list)
490 talloc_free(d_list);
491 if (extra_data)
492 free(extra_data);
495 return wbc_status;
498 /** @brief Enumerate the domain trusts known by Winbind
500 * @param domain Name of the domain to query for a DC
501 * @param flags Bit flags used to control the domain location query
502 * @param *dc_info Pointer to the returned domain controller information
504 * @return #wbcErr
510 wbcErr wbcLookupDomainController(const char *domain,
511 uint32_t flags,
512 struct wbcDomainControllerInfo **dc_info)
514 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
515 struct winbindd_request request;
516 struct winbindd_response response;
517 struct wbcDomainControllerInfo *dc = NULL;
519 /* validate input params */
521 if (!domain || !dc_info) {
522 wbc_status = WBC_ERR_INVALID_PARAM;
523 BAIL_ON_WBC_ERROR(wbc_status);
526 ZERO_STRUCT(request);
527 ZERO_STRUCT(response);
529 strncpy(request.domain_name, domain, sizeof(request.domain_name)-1);
531 request.flags = flags;
533 dc = talloc(NULL, struct wbcDomainControllerInfo);
534 BAIL_ON_PTR_ERROR(dc, wbc_status);
536 /* Send request */
538 wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
539 &request,
540 &response);
541 BAIL_ON_WBC_ERROR(wbc_status);
543 dc->dc_name = talloc_strdup(dc, response.data.dc_name);
544 BAIL_ON_PTR_ERROR(dc->dc_name, wbc_status);
546 *dc_info = dc;
548 done:
549 if (!WBC_ERROR_IS_OK(wbc_status)) {
550 talloc_free(dc);
553 return wbc_status;
556 static wbcErr wbc_create_domain_controller_info_ex(TALLOC_CTX *mem_ctx,
557 const struct winbindd_response *resp,
558 struct wbcDomainControllerInfoEx **_i)
560 wbcErr wbc_status = WBC_ERR_SUCCESS;
561 struct wbcDomainControllerInfoEx *i;
562 struct wbcGuid guid;
564 i = talloc(mem_ctx, struct wbcDomainControllerInfoEx);
565 BAIL_ON_PTR_ERROR(i, wbc_status);
567 i->dc_unc = talloc_strdup(i, resp->data.dsgetdcname.dc_unc);
568 BAIL_ON_PTR_ERROR(i->dc_unc, wbc_status);
570 i->dc_address = talloc_strdup(i, resp->data.dsgetdcname.dc_address);
571 BAIL_ON_PTR_ERROR(i->dc_address, wbc_status);
573 i->dc_address_type = resp->data.dsgetdcname.dc_address_type;
575 wbc_status = wbcStringToGuid(resp->data.dsgetdcname.domain_guid, &guid);
576 if (WBC_ERROR_IS_OK(wbc_status)) {
577 i->domain_guid = talloc(i, struct wbcGuid);
578 BAIL_ON_PTR_ERROR(i->domain_guid, wbc_status);
580 *i->domain_guid = guid;
581 } else {
582 i->domain_guid = NULL;
585 i->domain_name = talloc_strdup(i, resp->data.dsgetdcname.domain_name);
586 BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
588 if (resp->data.dsgetdcname.forest_name[0] != '\0') {
589 i->forest_name = talloc_strdup(i,
590 resp->data.dsgetdcname.forest_name);
591 BAIL_ON_PTR_ERROR(i->forest_name, wbc_status);
592 } else {
593 i->forest_name = NULL;
596 i->dc_flags = resp->data.dsgetdcname.dc_flags;
598 if (resp->data.dsgetdcname.dc_site_name[0] != '\0') {
599 i->dc_site_name = talloc_strdup(i,
600 resp->data.dsgetdcname.dc_site_name);
601 BAIL_ON_PTR_ERROR(i->dc_site_name, wbc_status);
602 } else {
603 i->dc_site_name = NULL;
606 if (resp->data.dsgetdcname.client_site_name[0] != '\0') {
607 i->client_site_name = talloc_strdup(i,
608 resp->data.dsgetdcname.client_site_name);
609 BAIL_ON_PTR_ERROR(i->client_site_name, wbc_status);
610 } else {
611 i->client_site_name = NULL;
614 *_i = i;
615 i = NULL;
617 done:
618 talloc_free(i);
619 return wbc_status;
622 /** @brief Get extended domain controller information
624 * @param domain Name of the domain to query for a DC
625 * @param guid Guid of the domain to query for a DC
626 * @param site Site of the domain to query for a DC
627 * @param flags Bit flags used to control the domain location query
628 * @param *dc_info Pointer to the returned extended domain controller information
630 * @return #wbcErr
634 wbcErr wbcLookupDomainControllerEx(const char *domain,
635 struct wbcGuid *guid,
636 const char *site,
637 uint32_t flags,
638 struct wbcDomainControllerInfoEx **dc_info)
640 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
641 struct winbindd_request request;
642 struct winbindd_response response;
644 /* validate input params */
646 if (!domain || !dc_info) {
647 wbc_status = WBC_ERR_INVALID_PARAM;
648 BAIL_ON_WBC_ERROR(wbc_status);
651 ZERO_STRUCT(request);
652 ZERO_STRUCT(response);
654 request.data.dsgetdcname.flags = flags;
656 strncpy(request.data.dsgetdcname.domain_name, domain,
657 sizeof(request.data.dsgetdcname.domain_name)-1);
659 if (site) {
660 strncpy(request.data.dsgetdcname.site_name, site,
661 sizeof(request.data.dsgetdcname.site_name)-1);
664 if (guid) {
665 char *str = NULL;
667 wbc_status = wbcGuidToString(guid, &str);
668 BAIL_ON_WBC_ERROR(wbc_status);
670 strncpy(request.data.dsgetdcname.domain_guid, str,
671 sizeof(request.data.dsgetdcname.domain_guid)-1);
673 wbcFreeMemory(str);
676 /* Send request */
678 wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
679 &request,
680 &response);
681 BAIL_ON_WBC_ERROR(wbc_status);
683 if (dc_info) {
684 wbc_status = wbc_create_domain_controller_info_ex(NULL,
685 &response,
686 dc_info);
687 BAIL_ON_WBC_ERROR(wbc_status);
690 wbc_status = WBC_ERR_SUCCESS;
691 done:
692 return wbc_status;
695 /** @brief Initialize a named blob and add to list of blobs
697 * @param[in,out] num_blobs Pointer to the number of blobs
698 * @param[in,out] blobs Pointer to an array of blobs
699 * @param[in] name Name of the new named blob
700 * @param[in] flags Flags of the new named blob
701 * @param[in] data Blob data of new blob
702 * @param[in] length Blob data length of new blob
704 * @return #wbcErr
708 wbcErr wbcAddNamedBlob(size_t *num_blobs,
709 struct wbcNamedBlob **blobs,
710 const char *name,
711 uint32_t flags,
712 uint8_t *data,
713 size_t length)
715 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
716 struct wbcNamedBlob blob;
718 *blobs = talloc_realloc(NULL, *blobs, struct wbcNamedBlob,
719 *(num_blobs)+1);
720 BAIL_ON_PTR_ERROR(*blobs, wbc_status);
722 blob.name = talloc_strdup(*blobs, name);
723 BAIL_ON_PTR_ERROR(blob.name, wbc_status);
724 blob.flags = flags;
725 blob.blob.length = length;
726 blob.blob.data = (uint8_t *)talloc_memdup(*blobs, data, length);
727 BAIL_ON_PTR_ERROR(blob.blob.data, wbc_status);
729 (*(blobs))[*num_blobs] = blob;
730 *(num_blobs) += 1;
732 wbc_status = WBC_ERR_SUCCESS;
733 done:
734 if (!WBC_ERROR_IS_OK(wbc_status) && blobs) {
735 wbcFreeMemory(*blobs);
737 return wbc_status;