tsocket: fill in sa.sa_len if the system supports it
[Samba/gebeck_regimport.git] / nsswitch / libwbclient / wbc_util.c
blob75b0093a208ebf1cd3e0ad37b0d48bc9c8a8e59c
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 = wbcStrDup(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 = wbcStrDup(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(struct wbcDomainInfo *info,
277 char *info_string)
279 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
280 char *r = NULL;
281 char *s = NULL;
283 r = info_string;
285 /* Short Name */
286 if ((s = strchr(r, '\\')) == NULL) {
287 wbc_status = WBC_ERR_INVALID_RESPONSE;
288 BAIL_ON_WBC_ERROR(wbc_status);
290 *s = '\0';
291 s++;
293 info->short_name = strdup(r);
294 BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
297 /* DNS Name */
298 r = s;
299 if ((s = strchr(r, '\\')) == NULL) {
300 wbc_status = WBC_ERR_INVALID_RESPONSE;
301 BAIL_ON_WBC_ERROR(wbc_status);
303 *s = '\0';
304 s++;
306 info->dns_name = strdup(r);
307 BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
309 /* SID */
310 r = s;
311 if ((s = strchr(r, '\\')) == NULL) {
312 wbc_status = WBC_ERR_INVALID_RESPONSE;
313 BAIL_ON_WBC_ERROR(wbc_status);
315 *s = '\0';
316 s++;
318 wbc_status = wbcStringToSid(r, &info->sid);
319 BAIL_ON_WBC_ERROR(wbc_status);
321 /* Trust type */
322 r = s;
323 if ((s = strchr(r, '\\')) == NULL) {
324 wbc_status = WBC_ERR_INVALID_RESPONSE;
325 BAIL_ON_WBC_ERROR(wbc_status);
327 *s = '\0';
328 s++;
330 if (strcmp(r, "None") == 0) {
331 info->trust_type = WBC_DOMINFO_TRUSTTYPE_NONE;
332 } else if (strcmp(r, "External") == 0) {
333 info->trust_type = WBC_DOMINFO_TRUSTTYPE_EXTERNAL;
334 } else if (strcmp(r, "Forest") == 0) {
335 info->trust_type = WBC_DOMINFO_TRUSTTYPE_FOREST;
336 } else if (strcmp(r, "In Forest") == 0) {
337 info->trust_type = WBC_DOMINFO_TRUSTTYPE_IN_FOREST;
338 } else {
339 wbc_status = WBC_ERR_INVALID_RESPONSE;
340 BAIL_ON_WBC_ERROR(wbc_status);
343 /* Transitive */
344 r = s;
345 if ((s = strchr(r, '\\')) == NULL) {
346 wbc_status = WBC_ERR_INVALID_RESPONSE;
347 BAIL_ON_WBC_ERROR(wbc_status);
349 *s = '\0';
350 s++;
352 if (strcmp(r, "Yes") == 0) {
353 info->trust_flags |= WBC_DOMINFO_TRUST_TRANSITIVE;
356 /* Incoming */
357 r = s;
358 if ((s = strchr(r, '\\')) == NULL) {
359 wbc_status = WBC_ERR_INVALID_RESPONSE;
360 BAIL_ON_WBC_ERROR(wbc_status);
362 *s = '\0';
363 s++;
365 if (strcmp(r, "Yes") == 0) {
366 info->trust_flags |= WBC_DOMINFO_TRUST_INCOMING;
369 /* Outgoing */
370 r = s;
371 if ((s = strchr(r, '\\')) == NULL) {
372 wbc_status = WBC_ERR_INVALID_RESPONSE;
373 BAIL_ON_WBC_ERROR(wbc_status);
375 *s = '\0';
376 s++;
378 if (strcmp(r, "Yes") == 0) {
379 info->trust_flags |= WBC_DOMINFO_TRUST_OUTGOING;
382 /* Online/Offline status */
384 r = s;
385 if (r == NULL) {
386 wbc_status = WBC_ERR_INVALID_RESPONSE;
387 BAIL_ON_WBC_ERROR(wbc_status);
389 if ( strcmp(r, "Offline") == 0) {
390 info->domain_flags |= WBC_DOMINFO_DOMAIN_OFFLINE;
393 wbc_status = WBC_ERR_SUCCESS;
395 done:
396 return wbc_status;
399 static void wbcDomainInfoListDestructor(void *ptr)
401 struct wbcDomainInfo *i = (struct wbcDomainInfo *)ptr;
403 while (i->short_name != NULL) {
404 free(i->short_name);
405 free(i->dns_name);
406 i += 1;
410 /* Enumerate the domain trusts known by Winbind */
411 wbcErr wbcListTrusts(struct wbcDomainInfo **domains, size_t *num_domains)
413 struct winbindd_response response;
414 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
415 char *p = NULL;
416 char *extra_data = NULL;
417 struct wbcDomainInfo *d_list = NULL;
418 int i = 0;
420 *domains = NULL;
421 *num_domains = 0;
423 ZERO_STRUCT(response);
425 /* Send request */
427 wbc_status = wbcRequestResponse(WINBINDD_LIST_TRUSTDOM,
428 NULL,
429 &response);
430 BAIL_ON_WBC_ERROR(wbc_status);
432 /* Decode the response */
434 p = (char *)response.extra_data.data;
436 if ((p == NULL) || (strlen(p) == 0)) {
437 /* We should always at least get back our
438 own SAM domain */
440 wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
441 BAIL_ON_WBC_ERROR(wbc_status);
444 d_list = (struct wbcDomainInfo *)wbcAllocateMemory(
445 sizeof(struct wbcDomainInfo), response.data.num_entries + 1,
446 wbcDomainInfoListDestructor);
447 BAIL_ON_PTR_ERROR(d_list, wbc_status);
449 extra_data = strdup((char*)response.extra_data.data);
450 BAIL_ON_PTR_ERROR(extra_data, wbc_status);
452 p = extra_data;
454 /* Outer loop processes the list of domain information */
456 for (i=0; i<response.data.num_entries && p; i++) {
457 char *next = strchr(p, '\n');
459 if (next) {
460 *next = '\0';
461 next++;
464 wbc_status = process_domain_info_string(&d_list[i], p);
465 BAIL_ON_WBC_ERROR(wbc_status);
467 p = next;
470 *domains = d_list;
471 d_list = NULL;
472 *num_domains = i;
474 done:
475 winbindd_free_response(&response);
476 wbcFreeMemory(d_list);
477 free(extra_data);
478 return wbc_status;
481 static void wbcDomainControllerInfoDestructor(void *ptr)
483 struct wbcDomainControllerInfo *i =
484 (struct wbcDomainControllerInfo *)ptr;
485 free(i->dc_name);
488 /* Enumerate the domain trusts known by Winbind */
489 wbcErr wbcLookupDomainController(const char *domain,
490 uint32_t flags,
491 struct wbcDomainControllerInfo **dc_info)
493 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
494 struct winbindd_request request;
495 struct winbindd_response response;
496 struct wbcDomainControllerInfo *dc = NULL;
498 /* validate input params */
500 if (!domain || !dc_info) {
501 wbc_status = WBC_ERR_INVALID_PARAM;
502 BAIL_ON_WBC_ERROR(wbc_status);
505 ZERO_STRUCT(request);
506 ZERO_STRUCT(response);
508 strncpy(request.data.dsgetdcname.domain_name, domain,
509 sizeof(request.data.dsgetdcname.domain_name)-1);
511 request.flags = flags;
513 dc = (struct wbcDomainControllerInfo *)wbcAllocateMemory(
514 sizeof(struct wbcDomainControllerInfo), 1,
515 wbcDomainControllerInfoDestructor);
516 BAIL_ON_PTR_ERROR(dc, wbc_status);
518 /* Send request */
520 wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
521 &request,
522 &response);
523 BAIL_ON_WBC_ERROR(wbc_status);
525 dc->dc_name = strdup(response.data.dsgetdcname.dc_unc);
526 BAIL_ON_PTR_ERROR(dc->dc_name, wbc_status);
528 *dc_info = dc;
529 dc = NULL;
531 done:
532 wbcFreeMemory(dc);
533 return wbc_status;
536 static void wbcDomainControllerInfoExDestructor(void *ptr)
538 struct wbcDomainControllerInfoEx *i =
539 (struct wbcDomainControllerInfoEx *)ptr;
540 free((char *)(i->dc_unc));
541 free((char *)(i->dc_address));
542 free((char *)(i->domain_guid));
543 free((char *)(i->domain_name));
544 free((char *)(i->forest_name));
545 free((char *)(i->dc_site_name));
546 free((char *)(i->client_site_name));
549 static wbcErr wbc_create_domain_controller_info_ex(const struct winbindd_response *resp,
550 struct wbcDomainControllerInfoEx **_i)
552 wbcErr wbc_status = WBC_ERR_SUCCESS;
553 struct wbcDomainControllerInfoEx *i;
554 struct wbcGuid guid;
556 i = (struct wbcDomainControllerInfoEx *)wbcAllocateMemory(
557 sizeof(struct wbcDomainControllerInfoEx), 1,
558 wbcDomainControllerInfoExDestructor);
559 BAIL_ON_PTR_ERROR(i, wbc_status);
561 i->dc_unc = strdup(resp->data.dsgetdcname.dc_unc);
562 BAIL_ON_PTR_ERROR(i->dc_unc, wbc_status);
564 i->dc_address = strdup(resp->data.dsgetdcname.dc_address);
565 BAIL_ON_PTR_ERROR(i->dc_address, wbc_status);
567 i->dc_address_type = resp->data.dsgetdcname.dc_address_type;
569 wbc_status = wbcStringToGuid(resp->data.dsgetdcname.domain_guid, &guid);
570 if (WBC_ERROR_IS_OK(wbc_status)) {
571 i->domain_guid = (struct wbcGuid *)malloc(
572 sizeof(struct wbcGuid));
573 BAIL_ON_PTR_ERROR(i->domain_guid, wbc_status);
575 *i->domain_guid = guid;
578 i->domain_name = strdup(resp->data.dsgetdcname.domain_name);
579 BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
581 if (resp->data.dsgetdcname.forest_name[0] != '\0') {
582 i->forest_name = strdup(resp->data.dsgetdcname.forest_name);
583 BAIL_ON_PTR_ERROR(i->forest_name, wbc_status);
586 i->dc_flags = resp->data.dsgetdcname.dc_flags;
588 if (resp->data.dsgetdcname.dc_site_name[0] != '\0') {
589 i->dc_site_name = strdup(resp->data.dsgetdcname.dc_site_name);
590 BAIL_ON_PTR_ERROR(i->dc_site_name, wbc_status);
593 if (resp->data.dsgetdcname.client_site_name[0] != '\0') {
594 i->client_site_name = strdup(
595 resp->data.dsgetdcname.client_site_name);
596 BAIL_ON_PTR_ERROR(i->client_site_name, wbc_status);
599 *_i = i;
600 i = NULL;
602 done:
603 if (i != NULL) {
604 wbcFreeMemory(i);
606 return wbc_status;
609 /* Get extended domain controller information */
610 wbcErr wbcLookupDomainControllerEx(const char *domain,
611 struct wbcGuid *guid,
612 const char *site,
613 uint32_t flags,
614 struct wbcDomainControllerInfoEx **dc_info)
616 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
617 struct winbindd_request request;
618 struct winbindd_response response;
620 /* validate input params */
622 if (!domain || !dc_info) {
623 wbc_status = WBC_ERR_INVALID_PARAM;
624 BAIL_ON_WBC_ERROR(wbc_status);
627 ZERO_STRUCT(request);
628 ZERO_STRUCT(response);
630 request.data.dsgetdcname.flags = flags;
632 strncpy(request.data.dsgetdcname.domain_name, domain,
633 sizeof(request.data.dsgetdcname.domain_name)-1);
635 if (site) {
636 strncpy(request.data.dsgetdcname.site_name, site,
637 sizeof(request.data.dsgetdcname.site_name)-1);
640 if (guid) {
641 char *str = NULL;
643 wbc_status = wbcGuidToString(guid, &str);
644 BAIL_ON_WBC_ERROR(wbc_status);
646 strncpy(request.data.dsgetdcname.domain_guid, str,
647 sizeof(request.data.dsgetdcname.domain_guid)-1);
649 wbcFreeMemory(str);
652 /* Send request */
654 wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
655 &request,
656 &response);
657 BAIL_ON_WBC_ERROR(wbc_status);
659 if (dc_info) {
660 wbc_status = wbc_create_domain_controller_info_ex(&response,
661 dc_info);
662 BAIL_ON_WBC_ERROR(wbc_status);
665 wbc_status = WBC_ERR_SUCCESS;
666 done:
667 return wbc_status;
670 static void wbcNamedBlobDestructor(void *ptr)
672 struct wbcNamedBlob *b = (struct wbcNamedBlob *)ptr;
674 while (b->name != NULL) {
675 free((char *)(b->name));
676 free(b->blob.data);
677 b += 1;
681 /* Initialize a named blob and add to list of blobs */
682 wbcErr wbcAddNamedBlob(size_t *num_blobs,
683 struct wbcNamedBlob **pblobs,
684 const char *name,
685 uint32_t flags,
686 uint8_t *data,
687 size_t length)
689 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
690 struct wbcNamedBlob *blobs, *blob;
692 if (name == NULL) {
693 return WBC_ERR_INVALID_PARAM;
697 * Overallocate the b->name==NULL terminator for
698 * wbcNamedBlobDestructor
700 blobs = (struct wbcNamedBlob *)wbcAllocateMemory(
701 sizeof(struct wbcNamedBlob), *num_blobs + 2,
702 wbcNamedBlobDestructor);
704 if (*pblobs != NULL) {
705 struct wbcNamedBlob *old = *pblobs;
706 memcpy(blobs, old, sizeof(struct wbcNamedBlob) * (*num_blobs));
707 if (*num_blobs != 0) {
708 /* end indicator for wbcNamedBlobDestructor */
709 old[0].name = NULL;
711 wbcFreeMemory(old);
713 *pblobs = blobs;
715 blob = &blobs[*num_blobs];
717 blob->name = strdup(name);
718 BAIL_ON_PTR_ERROR(blob->name, wbc_status);
719 blob->flags = flags;
721 blob->blob.length = length;
722 blob->blob.data = (uint8_t *)malloc(length);
723 BAIL_ON_PTR_ERROR(blob->blob.data, wbc_status);
724 memcpy(blob->blob.data, data, length);
726 *num_blobs += 1;
727 *pblobs = blobs;
728 blobs = NULL;
730 wbc_status = WBC_ERR_SUCCESS;
731 done:
732 wbcFreeMemory(blobs);
733 return wbc_status;