libwbclient: Make wbcDomainInfo not use talloc
[Samba/gebeck_regimport.git] / nsswitch / libwbclient / wbc_util.c
blob4e2c4557d741986b1f3bc576bb1d6ace0a90e851
1 /*
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 */
25 #include "replace.h"
26 #include "libwbclient.h"
27 #include "../winbind_client.h"
29 /** @brief Ping winbindd to see if the daemon is running
31 * @return #wbcErr
32 **/
33 wbcErr wbcPing(void)
35 struct winbindd_request request;
36 struct winbindd_response response;
38 /* Initialize request */
40 ZERO_STRUCT(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);
52 free(i->dns_domain);
55 /**
56 * @brief Query useful information about the winbind service
58 * @param *_details pointer to hold the struct wbcInterfaceDetails
60 * @return #wbcErr
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 */
73 ZERO_STRUCT(request);
74 ZERO_STRUCT(response);
76 info = (struct wbcInterfaceDetails *)wbcAllocateMemory(
77 sizeof(struct wbcInterfaceDetails), 1,
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 */
111 domain = NULL;
112 wbc_status = WBC_ERR_SUCCESS;
113 } else {
114 BAIL_ON_WBC_ERROR(wbc_status);
117 if (domain) {
118 info->dns_domain = strdup(domain->dns_name);
119 wbcFreeMemory(domain);
120 BAIL_ON_PTR_ERROR(info->dns_domain, wbc_status);
121 } else {
122 info->dns_domain = NULL;
125 *_details = info;
126 info = NULL;
128 wbc_status = WBC_ERR_SUCCESS;
130 done:
131 wbcFreeMemory(info);
132 return wbc_status;
135 static void wbcDomainInfoDestructor(void *ptr)
137 struct wbcDomainInfo *i = (struct wbcDomainInfo *)ptr;
138 free(i->short_name);
139 free(i->dns_name);
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
147 * @return #wbcErr
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,
171 &request,
172 &response);
173 BAIL_ON_WBC_ERROR(wbc_status);
175 info = (struct wbcDomainInfo *)wbcAllocateMemory(
176 sizeof(struct wbcDomainInfo), 1, 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,
186 &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;
196 *dinfo = info;
197 info = NULL;
199 wbc_status = WBC_ERR_SUCCESS;
201 done:
202 wbcFreeMemory(info);
203 return wbc_status;
207 /* Resolve a NetbiosName via WINS */
208 wbcErr wbcResolveWinsByName(const char *name, char **ip)
210 struct winbindd_request request;
211 struct winbindd_response response;
212 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
213 char *ipaddr;
215 ZERO_STRUCT(request);
216 ZERO_STRUCT(response);
218 /* Send request */
220 strncpy(request.data.winsreq, name,
221 sizeof(request.data.winsreq)-1);
223 wbc_status = wbcRequestResponse(WINBINDD_WINS_BYNAME,
224 &request,
225 &response);
226 BAIL_ON_WBC_ERROR(wbc_status);
228 /* Display response */
230 ipaddr = talloc_strdup(NULL, response.data.winsresp);
231 BAIL_ON_PTR_ERROR(ipaddr, wbc_status);
233 *ip = ipaddr;
234 wbc_status = WBC_ERR_SUCCESS;
236 done:
237 return wbc_status;
240 /* Resolve an IP address via WINS into a NetbiosName */
241 wbcErr wbcResolveWinsByIP(const char *ip, char **name)
243 struct winbindd_request request;
244 struct winbindd_response response;
245 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
246 char *name_str;
248 ZERO_STRUCT(request);
249 ZERO_STRUCT(response);
251 /* Send request */
253 strncpy(request.data.winsreq, ip,
254 sizeof(request.data.winsreq)-1);
256 wbc_status = wbcRequestResponse(WINBINDD_WINS_BYIP,
257 &request,
258 &response);
259 BAIL_ON_WBC_ERROR(wbc_status);
261 /* Display response */
263 name_str = talloc_strdup(NULL, response.data.winsresp);
264 BAIL_ON_PTR_ERROR(name_str, wbc_status);
266 *name = name_str;
267 wbc_status = WBC_ERR_SUCCESS;
269 done:
270 return wbc_status;
276 static wbcErr process_domain_info_string(TALLOC_CTX *ctx,
277 struct wbcDomainInfo *info,
278 char *info_string)
280 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
281 char *r = NULL;
282 char *s = NULL;
284 if (!info || !info_string) {
285 wbc_status = WBC_ERR_INVALID_PARAM;
286 BAIL_ON_WBC_ERROR(wbc_status);
289 ZERO_STRUCTP(info);
291 r = info_string;
293 /* Short Name */
294 if ((s = strchr(r, '\\')) == NULL) {
295 wbc_status = WBC_ERR_INVALID_RESPONSE;
296 BAIL_ON_WBC_ERROR(wbc_status);
298 *s = '\0';
299 s++;
301 info->short_name = talloc_strdup(ctx, r);
302 BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
305 /* DNS Name */
306 r = s;
307 if ((s = strchr(r, '\\')) == NULL) {
308 wbc_status = WBC_ERR_INVALID_RESPONSE;
309 BAIL_ON_WBC_ERROR(wbc_status);
311 *s = '\0';
312 s++;
314 info->dns_name = talloc_strdup(ctx, r);
315 BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
317 /* SID */
318 r = s;
319 if ((s = strchr(r, '\\')) == NULL) {
320 wbc_status = WBC_ERR_INVALID_RESPONSE;
321 BAIL_ON_WBC_ERROR(wbc_status);
323 *s = '\0';
324 s++;
326 wbc_status = wbcStringToSid(r, &info->sid);
327 BAIL_ON_WBC_ERROR(wbc_status);
329 /* Trust type */
330 r = s;
331 if ((s = strchr(r, '\\')) == NULL) {
332 wbc_status = WBC_ERR_INVALID_RESPONSE;
333 BAIL_ON_WBC_ERROR(wbc_status);
335 *s = '\0';
336 s++;
338 if (strcmp(r, "None") == 0) {
339 info->trust_type = WBC_DOMINFO_TRUSTTYPE_NONE;
340 } else if (strcmp(r, "External") == 0) {
341 info->trust_type = WBC_DOMINFO_TRUSTTYPE_EXTERNAL;
342 } else if (strcmp(r, "Forest") == 0) {
343 info->trust_type = WBC_DOMINFO_TRUSTTYPE_FOREST;
344 } else if (strcmp(r, "In Forest") == 0) {
345 info->trust_type = WBC_DOMINFO_TRUSTTYPE_IN_FOREST;
346 } else {
347 wbc_status = WBC_ERR_INVALID_RESPONSE;
348 BAIL_ON_WBC_ERROR(wbc_status);
351 /* Transitive */
352 r = s;
353 if ((s = strchr(r, '\\')) == NULL) {
354 wbc_status = WBC_ERR_INVALID_RESPONSE;
355 BAIL_ON_WBC_ERROR(wbc_status);
357 *s = '\0';
358 s++;
360 if (strcmp(r, "Yes") == 0) {
361 info->trust_flags |= WBC_DOMINFO_TRUST_TRANSITIVE;
364 /* Incoming */
365 r = s;
366 if ((s = strchr(r, '\\')) == NULL) {
367 wbc_status = WBC_ERR_INVALID_RESPONSE;
368 BAIL_ON_WBC_ERROR(wbc_status);
370 *s = '\0';
371 s++;
373 if (strcmp(r, "Yes") == 0) {
374 info->trust_flags |= WBC_DOMINFO_TRUST_INCOMING;
377 /* Outgoing */
378 r = s;
379 if ((s = strchr(r, '\\')) == NULL) {
380 wbc_status = WBC_ERR_INVALID_RESPONSE;
381 BAIL_ON_WBC_ERROR(wbc_status);
383 *s = '\0';
384 s++;
386 if (strcmp(r, "Yes") == 0) {
387 info->trust_flags |= WBC_DOMINFO_TRUST_OUTGOING;
390 /* Online/Offline status */
392 r = s;
393 if (r == NULL) {
394 wbc_status = WBC_ERR_INVALID_RESPONSE;
395 BAIL_ON_WBC_ERROR(wbc_status);
397 if ( strcmp(r, "Offline") == 0) {
398 info->domain_flags |= WBC_DOMINFO_DOMAIN_OFFLINE;
401 wbc_status = WBC_ERR_SUCCESS;
403 done:
404 return wbc_status;
407 /* Enumerate the domain trusts known by Winbind */
408 wbcErr wbcListTrusts(struct wbcDomainInfo **domains, size_t *num_domains)
410 struct winbindd_response response;
411 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
412 char *p = NULL;
413 char *q = NULL;
414 char *extra_data = NULL;
415 int count = 0;
416 struct wbcDomainInfo *d_list = NULL;
417 int i = 0;
419 *domains = NULL;
420 *num_domains = 0;
422 ZERO_STRUCT(response);
424 /* Send request */
426 wbc_status = wbcRequestResponse(WINBINDD_LIST_TRUSTDOM,
427 NULL,
428 &response);
429 BAIL_ON_WBC_ERROR(wbc_status);
431 /* Decode the response */
433 p = (char *)response.extra_data.data;
435 if ((p == NULL) || (strlen(p) == 0)) {
436 /* We should always at least get back our
437 own SAM domain */
439 wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
440 BAIL_ON_WBC_ERROR(wbc_status);
443 /* Count number of domains */
445 count = 0;
446 while (p) {
447 count++;
449 if ((q = strchr(p, '\n')) != NULL)
450 q++;
451 p = q;
454 d_list = talloc_array(NULL, struct wbcDomainInfo, count);
455 BAIL_ON_PTR_ERROR(d_list, wbc_status);
457 extra_data = strdup((char*)response.extra_data.data);
458 BAIL_ON_PTR_ERROR(extra_data, wbc_status);
460 p = extra_data;
462 /* Outer loop processes the list of domain information */
464 for (i=0; i<count && p; i++) {
465 char *next = strchr(p, '\n');
467 if (next) {
468 *next = '\0';
469 next++;
472 wbc_status = process_domain_info_string(d_list, &d_list[i], p);
473 BAIL_ON_WBC_ERROR(wbc_status);
475 p = next;
478 *domains = d_list;
479 d_list = NULL;
480 *num_domains = i;
482 done:
483 winbindd_free_response(&response);
484 talloc_free(d_list);
485 free(extra_data);
486 return wbc_status;
489 /* Enumerate the domain trusts known by Winbind */
490 wbcErr wbcLookupDomainController(const char *domain,
491 uint32_t flags,
492 struct wbcDomainControllerInfo **dc_info)
494 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
495 struct winbindd_request request;
496 struct winbindd_response response;
497 struct wbcDomainControllerInfo *dc = NULL;
499 /* validate input params */
501 if (!domain || !dc_info) {
502 wbc_status = WBC_ERR_INVALID_PARAM;
503 BAIL_ON_WBC_ERROR(wbc_status);
506 ZERO_STRUCT(request);
507 ZERO_STRUCT(response);
509 strncpy(request.data.dsgetdcname.domain_name, domain,
510 sizeof(request.data.dsgetdcname.domain_name)-1);
512 request.flags = flags;
514 dc = talloc(NULL, struct wbcDomainControllerInfo);
515 BAIL_ON_PTR_ERROR(dc, wbc_status);
517 /* Send request */
519 wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
520 &request,
521 &response);
522 BAIL_ON_WBC_ERROR(wbc_status);
524 dc->dc_name = talloc_strdup(dc, response.data.dsgetdcname.dc_unc);
525 BAIL_ON_PTR_ERROR(dc->dc_name, wbc_status);
527 *dc_info = dc;
529 done:
530 if (!WBC_ERROR_IS_OK(wbc_status)) {
531 talloc_free(dc);
534 return wbc_status;
537 static wbcErr wbc_create_domain_controller_info_ex(TALLOC_CTX *mem_ctx,
538 const struct winbindd_response *resp,
539 struct wbcDomainControllerInfoEx **_i)
541 wbcErr wbc_status = WBC_ERR_SUCCESS;
542 struct wbcDomainControllerInfoEx *i;
543 struct wbcGuid guid;
545 i = talloc(mem_ctx, struct wbcDomainControllerInfoEx);
546 BAIL_ON_PTR_ERROR(i, wbc_status);
548 i->dc_unc = talloc_strdup(i, resp->data.dsgetdcname.dc_unc);
549 BAIL_ON_PTR_ERROR(i->dc_unc, wbc_status);
551 i->dc_address = talloc_strdup(i, resp->data.dsgetdcname.dc_address);
552 BAIL_ON_PTR_ERROR(i->dc_address, wbc_status);
554 i->dc_address_type = resp->data.dsgetdcname.dc_address_type;
556 wbc_status = wbcStringToGuid(resp->data.dsgetdcname.domain_guid, &guid);
557 if (WBC_ERROR_IS_OK(wbc_status)) {
558 i->domain_guid = talloc(i, struct wbcGuid);
559 BAIL_ON_PTR_ERROR(i->domain_guid, wbc_status);
561 *i->domain_guid = guid;
562 } else {
563 i->domain_guid = NULL;
566 i->domain_name = talloc_strdup(i, resp->data.dsgetdcname.domain_name);
567 BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
569 if (resp->data.dsgetdcname.forest_name[0] != '\0') {
570 i->forest_name = talloc_strdup(i,
571 resp->data.dsgetdcname.forest_name);
572 BAIL_ON_PTR_ERROR(i->forest_name, wbc_status);
573 } else {
574 i->forest_name = NULL;
577 i->dc_flags = resp->data.dsgetdcname.dc_flags;
579 if (resp->data.dsgetdcname.dc_site_name[0] != '\0') {
580 i->dc_site_name = talloc_strdup(i,
581 resp->data.dsgetdcname.dc_site_name);
582 BAIL_ON_PTR_ERROR(i->dc_site_name, wbc_status);
583 } else {
584 i->dc_site_name = NULL;
587 if (resp->data.dsgetdcname.client_site_name[0] != '\0') {
588 i->client_site_name = talloc_strdup(i,
589 resp->data.dsgetdcname.client_site_name);
590 BAIL_ON_PTR_ERROR(i->client_site_name, wbc_status);
591 } else {
592 i->client_site_name = NULL;
595 *_i = i;
596 i = NULL;
598 done:
599 talloc_free(i);
600 return wbc_status;
603 /* Get extended domain controller information */
604 wbcErr wbcLookupDomainControllerEx(const char *domain,
605 struct wbcGuid *guid,
606 const char *site,
607 uint32_t flags,
608 struct wbcDomainControllerInfoEx **dc_info)
610 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
611 struct winbindd_request request;
612 struct winbindd_response response;
614 /* validate input params */
616 if (!domain || !dc_info) {
617 wbc_status = WBC_ERR_INVALID_PARAM;
618 BAIL_ON_WBC_ERROR(wbc_status);
621 ZERO_STRUCT(request);
622 ZERO_STRUCT(response);
624 request.data.dsgetdcname.flags = flags;
626 strncpy(request.data.dsgetdcname.domain_name, domain,
627 sizeof(request.data.dsgetdcname.domain_name)-1);
629 if (site) {
630 strncpy(request.data.dsgetdcname.site_name, site,
631 sizeof(request.data.dsgetdcname.site_name)-1);
634 if (guid) {
635 char *str = NULL;
637 wbc_status = wbcGuidToString(guid, &str);
638 BAIL_ON_WBC_ERROR(wbc_status);
640 strncpy(request.data.dsgetdcname.domain_guid, str,
641 sizeof(request.data.dsgetdcname.domain_guid)-1);
643 wbcFreeMemory(str);
646 /* Send request */
648 wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
649 &request,
650 &response);
651 BAIL_ON_WBC_ERROR(wbc_status);
653 if (dc_info) {
654 wbc_status = wbc_create_domain_controller_info_ex(NULL,
655 &response,
656 dc_info);
657 BAIL_ON_WBC_ERROR(wbc_status);
660 wbc_status = WBC_ERR_SUCCESS;
661 done:
662 return wbc_status;
665 /* Initialize a named blob and add to list of blobs */
666 wbcErr wbcAddNamedBlob(size_t *num_blobs,
667 struct wbcNamedBlob **blobs,
668 const char *name,
669 uint32_t flags,
670 uint8_t *data,
671 size_t length)
673 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
674 struct wbcNamedBlob blob;
676 *blobs = talloc_realloc(NULL, *blobs, struct wbcNamedBlob,
677 *(num_blobs)+1);
678 BAIL_ON_PTR_ERROR(*blobs, wbc_status);
680 blob.name = talloc_strdup(*blobs, name);
681 BAIL_ON_PTR_ERROR(blob.name, wbc_status);
682 blob.flags = flags;
683 blob.blob.length = length;
684 blob.blob.data = (uint8_t *)talloc_memdup(*blobs, data, length);
685 BAIL_ON_PTR_ERROR(blob.blob.data, wbc_status);
687 (*(blobs))[*num_blobs] = blob;
688 *(num_blobs) += 1;
690 wbc_status = WBC_ERR_SUCCESS;
691 done:
692 if (!WBC_ERROR_IS_OK(wbc_status)) {
693 wbcFreeMemory(*blobs);
695 return wbc_status;