s3-winbindd: Fix typo in comment.
[Samba.git] / nsswitch / libwbclient / wbc_util.c
blob5637b2ec445cfc60c37413a4705f608676ebb550
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);
47 /**
48 * @brief Query useful information about the winbind service
50 * @param *_details pointer to hold the struct wbcInterfaceDetails
52 * @return #wbcErr
55 wbcErr wbcInterfaceDetails(struct wbcInterfaceDetails **_details)
57 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
58 struct wbcInterfaceDetails *info;
59 struct wbcDomainInfo *domain = NULL;
60 struct winbindd_request request;
61 struct winbindd_response response;
63 /* Initialize request */
65 ZERO_STRUCT(request);
66 ZERO_STRUCT(response);
68 info = talloc(NULL, struct wbcInterfaceDetails);
69 BAIL_ON_PTR_ERROR(info, wbc_status);
71 /* first the interface version */
72 wbc_status = wbcRequestResponse(WINBINDD_INTERFACE_VERSION, NULL, &response);
73 BAIL_ON_WBC_ERROR(wbc_status);
74 info->interface_version = response.data.interface_version;
76 /* then the samba version and the winbind separator */
77 wbc_status = wbcRequestResponse(WINBINDD_INFO, NULL, &response);
78 BAIL_ON_WBC_ERROR(wbc_status);
80 info->winbind_version = talloc_strdup(info,
81 response.data.info.samba_version);
82 BAIL_ON_PTR_ERROR(info->winbind_version, wbc_status);
83 info->winbind_separator = response.data.info.winbind_separator;
85 /* then the local netbios name */
86 wbc_status = wbcRequestResponse(WINBINDD_NETBIOS_NAME, NULL, &response);
87 BAIL_ON_WBC_ERROR(wbc_status);
89 info->netbios_name = talloc_strdup(info,
90 response.data.netbios_name);
91 BAIL_ON_PTR_ERROR(info->netbios_name, wbc_status);
93 /* then the local workgroup name */
94 wbc_status = wbcRequestResponse(WINBINDD_DOMAIN_NAME, NULL, &response);
95 BAIL_ON_WBC_ERROR(wbc_status);
97 info->netbios_domain = talloc_strdup(info,
98 response.data.domain_name);
99 BAIL_ON_PTR_ERROR(info->netbios_domain, wbc_status);
101 wbc_status = wbcDomainInfo(info->netbios_domain, &domain);
102 if (wbc_status == WBC_ERR_DOMAIN_NOT_FOUND) {
103 /* maybe it's a standalone server */
104 domain = NULL;
105 wbc_status = WBC_ERR_SUCCESS;
106 } else {
107 BAIL_ON_WBC_ERROR(wbc_status);
110 if (domain) {
111 info->dns_domain = talloc_strdup(info,
112 domain->dns_name);
113 wbcFreeMemory(domain);
114 BAIL_ON_PTR_ERROR(info->dns_domain, wbc_status);
115 } else {
116 info->dns_domain = NULL;
119 *_details = info;
120 info = NULL;
122 wbc_status = WBC_ERR_SUCCESS;
124 done:
125 talloc_free(info);
126 return wbc_status;
130 /** @brief Lookup the current status of a trusted domain, sync wrapper
132 * @param domain Domain to query
133 * @param *dinfo Pointer to returned struct wbcDomainInfo
135 * @return #wbcErr
138 wbcErr wbcDomainInfo(const char *domain, struct wbcDomainInfo **dinfo)
140 struct winbindd_request request;
141 struct winbindd_response response;
142 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
143 struct wbcDomainInfo *info = NULL;
145 if (!domain || !dinfo) {
146 wbc_status = WBC_ERR_INVALID_PARAM;
147 BAIL_ON_WBC_ERROR(wbc_status);
150 /* Initialize request */
152 ZERO_STRUCT(request);
153 ZERO_STRUCT(response);
155 strncpy(request.domain_name, domain,
156 sizeof(request.domain_name)-1);
158 wbc_status = wbcRequestResponse(WINBINDD_DOMAIN_INFO,
159 &request,
160 &response);
161 BAIL_ON_WBC_ERROR(wbc_status);
163 info = talloc(NULL, struct wbcDomainInfo);
164 BAIL_ON_PTR_ERROR(info, wbc_status);
166 info->short_name = talloc_strdup(info,
167 response.data.domain_info.name);
168 BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
170 info->dns_name = talloc_strdup(info,
171 response.data.domain_info.alt_name);
172 BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
174 wbc_status = wbcStringToSid(response.data.domain_info.sid,
175 &info->sid);
176 BAIL_ON_WBC_ERROR(wbc_status);
178 if (response.data.domain_info.native_mode)
179 info->domain_flags |= WBC_DOMINFO_DOMAIN_NATIVE;
180 if (response.data.domain_info.active_directory)
181 info->domain_flags |= WBC_DOMINFO_DOMAIN_AD;
182 if (response.data.domain_info.primary)
183 info->domain_flags |= WBC_DOMINFO_DOMAIN_PRIMARY;
185 *dinfo = info;
187 wbc_status = WBC_ERR_SUCCESS;
189 done:
190 if (!WBC_ERROR_IS_OK(wbc_status)) {
191 talloc_free(info);
194 return wbc_status;
198 /* Resolve a NetbiosName via WINS */
199 wbcErr wbcResolveWinsByName(const char *name, char **ip)
201 struct winbindd_request request;
202 struct winbindd_response response;
203 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
204 char *ipaddr;
206 ZERO_STRUCT(request);
207 ZERO_STRUCT(response);
209 /* Send request */
211 strncpy(request.data.winsreq, name,
212 sizeof(request.data.winsreq)-1);
214 wbc_status = wbcRequestResponse(WINBINDD_WINS_BYNAME,
215 &request,
216 &response);
217 BAIL_ON_WBC_ERROR(wbc_status);
219 /* Display response */
221 ipaddr = talloc_strdup(NULL, response.data.winsresp);
222 BAIL_ON_PTR_ERROR(ipaddr, wbc_status);
224 *ip = ipaddr;
225 wbc_status = WBC_ERR_SUCCESS;
227 done:
228 return wbc_status;
231 /* Resolve an IP address via WINS into a NetbiosName */
232 wbcErr wbcResolveWinsByIP(const char *ip, char **name)
234 struct winbindd_request request;
235 struct winbindd_response response;
236 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
237 char *name_str;
239 ZERO_STRUCT(request);
240 ZERO_STRUCT(response);
242 /* Send request */
244 strncpy(request.data.winsreq, ip,
245 sizeof(request.data.winsreq)-1);
247 wbc_status = wbcRequestResponse(WINBINDD_WINS_BYIP,
248 &request,
249 &response);
250 BAIL_ON_WBC_ERROR(wbc_status);
252 /* Display response */
254 name_str = talloc_strdup(NULL, response.data.winsresp);
255 BAIL_ON_PTR_ERROR(name_str, wbc_status);
257 *name = name_str;
258 wbc_status = WBC_ERR_SUCCESS;
260 done:
261 return wbc_status;
267 static wbcErr process_domain_info_string(TALLOC_CTX *ctx,
268 struct wbcDomainInfo *info,
269 char *info_string)
271 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
272 char *r = NULL;
273 char *s = NULL;
275 if (!info || !info_string) {
276 wbc_status = WBC_ERR_INVALID_PARAM;
277 BAIL_ON_WBC_ERROR(wbc_status);
280 ZERO_STRUCTP(info);
282 r = info_string;
284 /* Short Name */
285 if ((s = strchr(r, '\\')) == NULL) {
286 wbc_status = WBC_ERR_INVALID_RESPONSE;
287 BAIL_ON_WBC_ERROR(wbc_status);
289 *s = '\0';
290 s++;
292 info->short_name = talloc_strdup(ctx, r);
293 BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
296 /* DNS Name */
297 r = s;
298 if ((s = strchr(r, '\\')) == NULL) {
299 wbc_status = WBC_ERR_INVALID_RESPONSE;
300 BAIL_ON_WBC_ERROR(wbc_status);
302 *s = '\0';
303 s++;
305 info->dns_name = talloc_strdup(ctx, r);
306 BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
308 /* SID */
309 r = s;
310 if ((s = strchr(r, '\\')) == NULL) {
311 wbc_status = WBC_ERR_INVALID_RESPONSE;
312 BAIL_ON_WBC_ERROR(wbc_status);
314 *s = '\0';
315 s++;
317 wbc_status = wbcStringToSid(r, &info->sid);
318 BAIL_ON_WBC_ERROR(wbc_status);
320 /* Trust type */
321 r = s;
322 if ((s = strchr(r, '\\')) == NULL) {
323 wbc_status = WBC_ERR_INVALID_RESPONSE;
324 BAIL_ON_WBC_ERROR(wbc_status);
326 *s = '\0';
327 s++;
329 if (strcmp(r, "None") == 0) {
330 info->trust_type = WBC_DOMINFO_TRUSTTYPE_NONE;
331 } else if (strcmp(r, "External") == 0) {
332 info->trust_type = WBC_DOMINFO_TRUSTTYPE_EXTERNAL;
333 } else if (strcmp(r, "Forest") == 0) {
334 info->trust_type = WBC_DOMINFO_TRUSTTYPE_FOREST;
335 } else if (strcmp(r, "In Forest") == 0) {
336 info->trust_type = WBC_DOMINFO_TRUSTTYPE_IN_FOREST;
337 } else {
338 wbc_status = WBC_ERR_INVALID_RESPONSE;
339 BAIL_ON_WBC_ERROR(wbc_status);
342 /* Transitive */
343 r = s;
344 if ((s = strchr(r, '\\')) == NULL) {
345 wbc_status = WBC_ERR_INVALID_RESPONSE;
346 BAIL_ON_WBC_ERROR(wbc_status);
348 *s = '\0';
349 s++;
351 if (strcmp(r, "Yes") == 0) {
352 info->trust_flags |= WBC_DOMINFO_TRUST_TRANSITIVE;
355 /* Incoming */
356 r = s;
357 if ((s = strchr(r, '\\')) == NULL) {
358 wbc_status = WBC_ERR_INVALID_RESPONSE;
359 BAIL_ON_WBC_ERROR(wbc_status);
361 *s = '\0';
362 s++;
364 if (strcmp(r, "Yes") == 0) {
365 info->trust_flags |= WBC_DOMINFO_TRUST_INCOMING;
368 /* Outgoing */
369 r = s;
370 if ((s = strchr(r, '\\')) == NULL) {
371 wbc_status = WBC_ERR_INVALID_RESPONSE;
372 BAIL_ON_WBC_ERROR(wbc_status);
374 *s = '\0';
375 s++;
377 if (strcmp(r, "Yes") == 0) {
378 info->trust_flags |= WBC_DOMINFO_TRUST_OUTGOING;
381 /* Online/Offline status */
383 r = s;
384 if (r == NULL) {
385 wbc_status = WBC_ERR_INVALID_RESPONSE;
386 BAIL_ON_WBC_ERROR(wbc_status);
388 if ( strcmp(r, "Offline") == 0) {
389 info->domain_flags |= WBC_DOMINFO_DOMAIN_OFFLINE;
392 wbc_status = WBC_ERR_SUCCESS;
394 done:
395 return wbc_status;
398 /* Enumerate the domain trusts known by Winbind */
399 wbcErr wbcListTrusts(struct wbcDomainInfo **domains, size_t *num_domains)
401 struct winbindd_response response;
402 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
403 char *p = NULL;
404 char *q = NULL;
405 char *extra_data = NULL;
406 int count = 0;
407 struct wbcDomainInfo *d_list = NULL;
408 int i = 0;
410 *domains = NULL;
411 *num_domains = 0;
413 ZERO_STRUCT(response);
415 /* Send request */
417 wbc_status = wbcRequestResponse(WINBINDD_LIST_TRUSTDOM,
418 NULL,
419 &response);
420 BAIL_ON_WBC_ERROR(wbc_status);
422 /* Decode the response */
424 p = (char *)response.extra_data.data;
426 if ((p == NULL) || (strlen(p) == 0)) {
427 /* We should always at least get back our
428 own SAM domain */
430 wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
431 BAIL_ON_WBC_ERROR(wbc_status);
434 /* Count number of domains */
436 count = 0;
437 while (p) {
438 count++;
440 if ((q = strchr(p, '\n')) != NULL)
441 q++;
442 p = q;
445 d_list = talloc_array(NULL, struct wbcDomainInfo, count);
446 BAIL_ON_PTR_ERROR(d_list, wbc_status);
448 extra_data = strdup((char*)response.extra_data.data);
449 BAIL_ON_PTR_ERROR(extra_data, wbc_status);
451 p = extra_data;
453 /* Outer loop processes the list of domain information */
455 for (i=0; i<count && p; i++) {
456 char *next = strchr(p, '\n');
458 if (next) {
459 *next = '\0';
460 next++;
463 wbc_status = process_domain_info_string(d_list, &d_list[i], p);
464 BAIL_ON_WBC_ERROR(wbc_status);
466 p = next;
469 *domains = d_list;
470 d_list = NULL;
471 *num_domains = i;
473 done:
474 winbindd_free_response(&response);
475 talloc_free(d_list);
476 free(extra_data);
477 return wbc_status;
480 /* Enumerate the domain trusts known by Winbind */
481 wbcErr wbcLookupDomainController(const char *domain,
482 uint32_t flags,
483 struct wbcDomainControllerInfo **dc_info)
485 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
486 struct winbindd_request request;
487 struct winbindd_response response;
488 struct wbcDomainControllerInfo *dc = NULL;
490 /* validate input params */
492 if (!domain || !dc_info) {
493 wbc_status = WBC_ERR_INVALID_PARAM;
494 BAIL_ON_WBC_ERROR(wbc_status);
497 ZERO_STRUCT(request);
498 ZERO_STRUCT(response);
500 strncpy(request.data.dsgetdcname.domain_name, domain,
501 sizeof(request.data.dsgetdcname.domain_name)-1);
503 request.flags = flags;
505 dc = talloc(NULL, struct wbcDomainControllerInfo);
506 BAIL_ON_PTR_ERROR(dc, wbc_status);
508 /* Send request */
510 wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
511 &request,
512 &response);
513 BAIL_ON_WBC_ERROR(wbc_status);
515 dc->dc_name = talloc_strdup(dc, response.data.dsgetdcname.dc_unc);
516 BAIL_ON_PTR_ERROR(dc->dc_name, wbc_status);
518 *dc_info = dc;
520 done:
521 if (!WBC_ERROR_IS_OK(wbc_status)) {
522 talloc_free(dc);
525 return wbc_status;
528 static wbcErr wbc_create_domain_controller_info_ex(TALLOC_CTX *mem_ctx,
529 const struct winbindd_response *resp,
530 struct wbcDomainControllerInfoEx **_i)
532 wbcErr wbc_status = WBC_ERR_SUCCESS;
533 struct wbcDomainControllerInfoEx *i;
534 struct wbcGuid guid;
536 i = talloc(mem_ctx, struct wbcDomainControllerInfoEx);
537 BAIL_ON_PTR_ERROR(i, wbc_status);
539 i->dc_unc = talloc_strdup(i, resp->data.dsgetdcname.dc_unc);
540 BAIL_ON_PTR_ERROR(i->dc_unc, wbc_status);
542 i->dc_address = talloc_strdup(i, resp->data.dsgetdcname.dc_address);
543 BAIL_ON_PTR_ERROR(i->dc_address, wbc_status);
545 i->dc_address_type = resp->data.dsgetdcname.dc_address_type;
547 wbc_status = wbcStringToGuid(resp->data.dsgetdcname.domain_guid, &guid);
548 if (WBC_ERROR_IS_OK(wbc_status)) {
549 i->domain_guid = talloc(i, struct wbcGuid);
550 BAIL_ON_PTR_ERROR(i->domain_guid, wbc_status);
552 *i->domain_guid = guid;
553 } else {
554 i->domain_guid = NULL;
557 i->domain_name = talloc_strdup(i, resp->data.dsgetdcname.domain_name);
558 BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
560 if (resp->data.dsgetdcname.forest_name[0] != '\0') {
561 i->forest_name = talloc_strdup(i,
562 resp->data.dsgetdcname.forest_name);
563 BAIL_ON_PTR_ERROR(i->forest_name, wbc_status);
564 } else {
565 i->forest_name = NULL;
568 i->dc_flags = resp->data.dsgetdcname.dc_flags;
570 if (resp->data.dsgetdcname.dc_site_name[0] != '\0') {
571 i->dc_site_name = talloc_strdup(i,
572 resp->data.dsgetdcname.dc_site_name);
573 BAIL_ON_PTR_ERROR(i->dc_site_name, wbc_status);
574 } else {
575 i->dc_site_name = NULL;
578 if (resp->data.dsgetdcname.client_site_name[0] != '\0') {
579 i->client_site_name = talloc_strdup(i,
580 resp->data.dsgetdcname.client_site_name);
581 BAIL_ON_PTR_ERROR(i->client_site_name, wbc_status);
582 } else {
583 i->client_site_name = NULL;
586 *_i = i;
587 i = NULL;
589 done:
590 talloc_free(i);
591 return wbc_status;
594 /* Get extended domain controller information */
595 wbcErr wbcLookupDomainControllerEx(const char *domain,
596 struct wbcGuid *guid,
597 const char *site,
598 uint32_t flags,
599 struct wbcDomainControllerInfoEx **dc_info)
601 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
602 struct winbindd_request request;
603 struct winbindd_response response;
605 /* validate input params */
607 if (!domain || !dc_info) {
608 wbc_status = WBC_ERR_INVALID_PARAM;
609 BAIL_ON_WBC_ERROR(wbc_status);
612 ZERO_STRUCT(request);
613 ZERO_STRUCT(response);
615 request.data.dsgetdcname.flags = flags;
617 strncpy(request.data.dsgetdcname.domain_name, domain,
618 sizeof(request.data.dsgetdcname.domain_name)-1);
620 if (site) {
621 strncpy(request.data.dsgetdcname.site_name, site,
622 sizeof(request.data.dsgetdcname.site_name)-1);
625 if (guid) {
626 char *str = NULL;
628 wbc_status = wbcGuidToString(guid, &str);
629 BAIL_ON_WBC_ERROR(wbc_status);
631 strncpy(request.data.dsgetdcname.domain_guid, str,
632 sizeof(request.data.dsgetdcname.domain_guid)-1);
634 wbcFreeMemory(str);
637 /* Send request */
639 wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
640 &request,
641 &response);
642 BAIL_ON_WBC_ERROR(wbc_status);
644 if (dc_info) {
645 wbc_status = wbc_create_domain_controller_info_ex(NULL,
646 &response,
647 dc_info);
648 BAIL_ON_WBC_ERROR(wbc_status);
651 wbc_status = WBC_ERR_SUCCESS;
652 done:
653 return wbc_status;
656 /* Initialize a named blob and add to list of blobs */
657 wbcErr wbcAddNamedBlob(size_t *num_blobs,
658 struct wbcNamedBlob **blobs,
659 const char *name,
660 uint32_t flags,
661 uint8_t *data,
662 size_t length)
664 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
665 struct wbcNamedBlob blob;
667 *blobs = talloc_realloc(NULL, *blobs, struct wbcNamedBlob,
668 *(num_blobs)+1);
669 BAIL_ON_PTR_ERROR(*blobs, wbc_status);
671 blob.name = talloc_strdup(*blobs, name);
672 BAIL_ON_PTR_ERROR(blob.name, wbc_status);
673 blob.flags = flags;
674 blob.blob.length = length;
675 blob.blob.data = (uint8_t *)talloc_memdup(*blobs, data, length);
676 BAIL_ON_PTR_ERROR(blob.blob.data, wbc_status);
678 (*(blobs))[*num_blobs] = blob;
679 *(num_blobs) += 1;
681 wbc_status = WBC_ERR_SUCCESS;
682 done:
683 if (!WBC_ERROR_IS_OK(wbc_status)) {
684 wbcFreeMemory(*blobs);
686 return wbc_status;