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 */
26 #include "libwbclient.h"
30 struct wbc_ping_state {
31 struct winbindd_request req;
34 static void wbcPing_done(struct tevent_req *subreq);
36 /** @brief Ping winbind to see if the service is up and running
38 * @param mem_ctx talloc context to allocate the request from
39 * @param ev event context to use for async operation
40 * @param wb_ctx winbind context to use
42 * @return Async request on successful dispatch of the request, NULL on error
45 struct tevent_req *wbcPing_send(TALLOC_CTX *mem_ctx,
46 struct tevent_context *ev,
47 struct wb_context *wb_ctx)
49 struct tevent_req *req, *subreq;
50 struct wbc_ping_state *state;
52 req = tevent_req_create(mem_ctx, &state, struct wbc_ping_state);
57 ZERO_STRUCT(state->req);
59 state->req.cmd = WINBINDD_PING;
60 subreq = wb_trans_send(state, ev, wb_ctx, false, &state->req);
61 if (tevent_req_nomem(subreq, req)) {
62 return tevent_req_post(req, ev);
65 tevent_req_set_callback(subreq, wbcPing_done, req);
69 static void wbcPing_done(struct tevent_req *subreq)
71 struct tevent_req *req = tevent_req_callback_data(
72 subreq, struct tevent_req);
73 struct wbc_ping_state *state = tevent_req_data(
74 req, struct wbc_ping_state);
75 struct winbindd_response *resp;
78 wbc_status = wb_trans_recv(subreq, state, &resp);
80 if (!WBC_ERROR_IS_OK(wbc_status)) {
81 tevent_req_error(req, wbc_status);
89 /** @brief Receive ping response from winbind
91 * @param req async request sent in #wbcPing_send
93 * @return NT_STATUS_OK on success, an error status on error.
96 wbcErr wbcPing_recv(struct tevent_req *req)
100 if (tevent_req_is_wbcerr(req, &wbc_status)) {
101 tevent_req_received(req);
105 tevent_req_received(req);
106 return WBC_ERR_SUCCESS;
109 /** @brief Ping winbindd to see if the daemon is running
115 struct winbindd_request request;
116 struct winbindd_response response;
118 /* Initialize request */
120 ZERO_STRUCT(request);
121 ZERO_STRUCT(response);
123 return wbcRequestResponse(WINBINDD_PING, &request, &response);
126 wbcErr wbcInterfaceDetails(struct wbcInterfaceDetails **_details)
128 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
129 struct wbcInterfaceDetails *info;
130 struct wbcDomainInfo *domain = NULL;
131 struct winbindd_request request;
132 struct winbindd_response response;
134 /* Initialize request */
136 ZERO_STRUCT(request);
137 ZERO_STRUCT(response);
139 info = talloc(NULL, struct wbcInterfaceDetails);
140 BAIL_ON_PTR_ERROR(info, wbc_status);
142 /* first the interface version */
143 wbc_status = wbcRequestResponse(WINBINDD_INTERFACE_VERSION, NULL, &response);
144 BAIL_ON_WBC_ERROR(wbc_status);
145 info->interface_version = response.data.interface_version;
147 /* then the samba version and the winbind separator */
148 wbc_status = wbcRequestResponse(WINBINDD_INFO, NULL, &response);
149 BAIL_ON_WBC_ERROR(wbc_status);
151 info->winbind_version = talloc_strdup(info,
152 response.data.info.samba_version);
153 BAIL_ON_PTR_ERROR(info->winbind_version, wbc_status);
154 info->winbind_separator = response.data.info.winbind_separator;
156 /* then the local netbios name */
157 wbc_status = wbcRequestResponse(WINBINDD_NETBIOS_NAME, NULL, &response);
158 BAIL_ON_WBC_ERROR(wbc_status);
160 info->netbios_name = talloc_strdup(info,
161 response.data.netbios_name);
162 BAIL_ON_PTR_ERROR(info->netbios_name, wbc_status);
164 /* then the local workgroup name */
165 wbc_status = wbcRequestResponse(WINBINDD_DOMAIN_NAME, NULL, &response);
166 BAIL_ON_WBC_ERROR(wbc_status);
168 info->netbios_domain = talloc_strdup(info,
169 response.data.domain_name);
170 BAIL_ON_PTR_ERROR(info->netbios_domain, wbc_status);
172 wbc_status = wbcDomainInfo(info->netbios_domain, &domain);
173 if (wbc_status == WBC_ERR_DOMAIN_NOT_FOUND) {
174 /* maybe it's a standalone server */
176 wbc_status = WBC_ERR_SUCCESS;
178 BAIL_ON_WBC_ERROR(wbc_status);
182 info->dns_domain = talloc_strdup(info,
184 wbcFreeMemory(domain);
185 BAIL_ON_PTR_ERROR(info->dns_domain, wbc_status);
187 info->dns_domain = NULL;
193 wbc_status = WBC_ERR_SUCCESS;
201 /* Lookup the current status of a trusted domain */
202 wbcErr wbcDomainInfo(const char *domain, struct wbcDomainInfo **dinfo)
204 struct winbindd_request request;
205 struct winbindd_response response;
206 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
207 struct wbcDomainInfo *info = NULL;
209 if (!domain || !dinfo) {
210 wbc_status = WBC_ERR_INVALID_PARAM;
211 BAIL_ON_WBC_ERROR(wbc_status);
214 /* Initialize request */
216 ZERO_STRUCT(request);
217 ZERO_STRUCT(response);
219 strncpy(request.domain_name, domain,
220 sizeof(request.domain_name)-1);
222 wbc_status = wbcRequestResponse(WINBINDD_DOMAIN_INFO,
225 BAIL_ON_WBC_ERROR(wbc_status);
227 info = talloc(NULL, struct wbcDomainInfo);
228 BAIL_ON_PTR_ERROR(info, wbc_status);
230 info->short_name = talloc_strdup(info,
231 response.data.domain_info.name);
232 BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
234 info->dns_name = talloc_strdup(info,
235 response.data.domain_info.alt_name);
236 BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
238 wbc_status = wbcStringToSid(response.data.domain_info.sid,
240 BAIL_ON_WBC_ERROR(wbc_status);
242 if (response.data.domain_info.native_mode)
243 info->domain_flags |= WBC_DOMINFO_DOMAIN_NATIVE;
244 if (response.data.domain_info.active_directory)
245 info->domain_flags |= WBC_DOMINFO_DOMAIN_AD;
246 if (response.data.domain_info.primary)
247 info->domain_flags |= WBC_DOMINFO_DOMAIN_PRIMARY;
251 wbc_status = WBC_ERR_SUCCESS;
254 if (!WBC_ERROR_IS_OK(wbc_status)) {
262 /* Resolve a NetbiosName via WINS */
263 wbcErr wbcResolveWinsByName(const char *name, char **ip)
265 struct winbindd_request request;
266 struct winbindd_response response;
267 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
270 ZERO_STRUCT(request);
271 ZERO_STRUCT(response);
275 strncpy(request.data.winsreq, name,
276 sizeof(request.data.winsreq)-1);
278 wbc_status = wbcRequestResponse(WINBINDD_WINS_BYNAME,
281 BAIL_ON_WBC_ERROR(wbc_status);
283 /* Display response */
285 ipaddr = talloc_strdup(NULL, response.data.winsresp);
286 BAIL_ON_PTR_ERROR(ipaddr, wbc_status);
289 wbc_status = WBC_ERR_SUCCESS;
295 /* Resolve an IP address via WINS into a NetbiosName */
296 wbcErr wbcResolveWinsByIP(const char *ip, char **name)
298 struct winbindd_request request;
299 struct winbindd_response response;
300 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
303 ZERO_STRUCT(request);
304 ZERO_STRUCT(response);
308 strncpy(request.data.winsreq, ip,
309 sizeof(request.data.winsreq)-1);
311 wbc_status = wbcRequestResponse(WINBINDD_WINS_BYIP,
314 BAIL_ON_WBC_ERROR(wbc_status);
316 /* Display response */
318 name_str = talloc_strdup(NULL, response.data.winsresp);
319 BAIL_ON_PTR_ERROR(name_str, wbc_status);
322 wbc_status = WBC_ERR_SUCCESS;
331 static wbcErr process_domain_info_string(TALLOC_CTX *ctx,
332 struct wbcDomainInfo *info,
335 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
339 if (!info || !info_string) {
340 wbc_status = WBC_ERR_INVALID_PARAM;
341 BAIL_ON_WBC_ERROR(wbc_status);
349 if ((s = strchr(r, '\\')) == NULL) {
350 wbc_status = WBC_ERR_INVALID_RESPONSE;
351 BAIL_ON_WBC_ERROR(wbc_status);
356 info->short_name = talloc_strdup(ctx, r);
357 BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
362 if ((s = strchr(r, '\\')) == NULL) {
363 wbc_status = WBC_ERR_INVALID_RESPONSE;
364 BAIL_ON_WBC_ERROR(wbc_status);
369 info->dns_name = talloc_strdup(ctx, r);
370 BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
374 if ((s = strchr(r, '\\')) == NULL) {
375 wbc_status = WBC_ERR_INVALID_RESPONSE;
376 BAIL_ON_WBC_ERROR(wbc_status);
381 wbc_status = wbcStringToSid(r, &info->sid);
382 BAIL_ON_WBC_ERROR(wbc_status);
386 if ((s = strchr(r, '\\')) == NULL) {
387 wbc_status = WBC_ERR_INVALID_RESPONSE;
388 BAIL_ON_WBC_ERROR(wbc_status);
393 if (strcmp(r, "None") == 0) {
394 info->trust_type = WBC_DOMINFO_TRUSTTYPE_NONE;
395 } else if (strcmp(r, "External") == 0) {
396 info->trust_type = WBC_DOMINFO_TRUSTTYPE_EXTERNAL;
397 } else if (strcmp(r, "Forest") == 0) {
398 info->trust_type = WBC_DOMINFO_TRUSTTYPE_FOREST;
399 } else if (strcmp(r, "In Forest") == 0) {
400 info->trust_type = WBC_DOMINFO_TRUSTTYPE_IN_FOREST;
402 wbc_status = WBC_ERR_INVALID_RESPONSE;
403 BAIL_ON_WBC_ERROR(wbc_status);
408 if ((s = strchr(r, '\\')) == NULL) {
409 wbc_status = WBC_ERR_INVALID_RESPONSE;
410 BAIL_ON_WBC_ERROR(wbc_status);
415 if (strcmp(r, "Yes") == 0) {
416 info->trust_flags |= WBC_DOMINFO_TRUST_TRANSITIVE;
421 if ((s = strchr(r, '\\')) == NULL) {
422 wbc_status = WBC_ERR_INVALID_RESPONSE;
423 BAIL_ON_WBC_ERROR(wbc_status);
428 if (strcmp(r, "Yes") == 0) {
429 info->trust_flags |= WBC_DOMINFO_TRUST_INCOMING;
434 if ((s = strchr(r, '\\')) == NULL) {
435 wbc_status = WBC_ERR_INVALID_RESPONSE;
436 BAIL_ON_WBC_ERROR(wbc_status);
441 if (strcmp(r, "Yes") == 0) {
442 info->trust_flags |= WBC_DOMINFO_TRUST_OUTGOING;
445 /* Online/Offline status */
449 wbc_status = WBC_ERR_INVALID_RESPONSE;
450 BAIL_ON_WBC_ERROR(wbc_status);
452 if ( strcmp(r, "Offline") == 0) {
453 info->domain_flags |= WBC_DOMINFO_DOMAIN_OFFLINE;
456 wbc_status = WBC_ERR_SUCCESS;
462 /* Enumerate the domain trusts known by Winbind */
463 wbcErr wbcListTrusts(struct wbcDomainInfo **domains, size_t *num_domains)
465 struct winbindd_response response;
466 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
469 char *extra_data = NULL;
471 struct wbcDomainInfo *d_list = NULL;
477 ZERO_STRUCT(response);
481 wbc_status = wbcRequestResponse(WINBINDD_LIST_TRUSTDOM,
484 BAIL_ON_WBC_ERROR(wbc_status);
486 /* Decode the response */
488 p = (char *)response.extra_data.data;
490 if ((p == NULL) || (strlen(p) == 0)) {
491 /* We should always at least get back our
494 wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
495 BAIL_ON_WBC_ERROR(wbc_status);
498 /* Count number of domains */
504 if ((q = strchr(p, '\n')) != NULL)
509 d_list = talloc_array(NULL, struct wbcDomainInfo, count);
510 BAIL_ON_PTR_ERROR(d_list, wbc_status);
512 extra_data = strdup((char*)response.extra_data.data);
513 BAIL_ON_PTR_ERROR(extra_data, wbc_status);
517 /* Outer loop processes the list of domain information */
519 for (i=0; i<count && p; i++) {
520 char *next = strchr(p, '\n');
527 wbc_status = process_domain_info_string(d_list, &d_list[i], p);
528 BAIL_ON_WBC_ERROR(wbc_status);
537 if (!WBC_ERROR_IS_OK(wbc_status)) {
547 /* Enumerate the domain trusts known by Winbind */
548 wbcErr wbcLookupDomainController(const char *domain,
550 struct wbcDomainControllerInfo **dc_info)
552 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
553 struct winbindd_request request;
554 struct winbindd_response response;
555 struct wbcDomainControllerInfo *dc = NULL;
557 /* validate input params */
559 if (!domain || !dc_info) {
560 wbc_status = WBC_ERR_INVALID_PARAM;
561 BAIL_ON_WBC_ERROR(wbc_status);
564 ZERO_STRUCT(request);
565 ZERO_STRUCT(response);
567 strncpy(request.data.dsgetdcname.domain_name, domain,
568 sizeof(request.data.dsgetdcname.domain_name)-1);
570 request.flags = flags;
572 dc = talloc(NULL, struct wbcDomainControllerInfo);
573 BAIL_ON_PTR_ERROR(dc, wbc_status);
577 wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
580 BAIL_ON_WBC_ERROR(wbc_status);
582 dc->dc_name = talloc_strdup(dc, response.data.dsgetdcname.dc_unc);
583 BAIL_ON_PTR_ERROR(dc->dc_name, wbc_status);
588 if (!WBC_ERROR_IS_OK(wbc_status)) {
595 static wbcErr wbc_create_domain_controller_info_ex(TALLOC_CTX *mem_ctx,
596 const struct winbindd_response *resp,
597 struct wbcDomainControllerInfoEx **_i)
599 wbcErr wbc_status = WBC_ERR_SUCCESS;
600 struct wbcDomainControllerInfoEx *i;
603 i = talloc(mem_ctx, struct wbcDomainControllerInfoEx);
604 BAIL_ON_PTR_ERROR(i, wbc_status);
606 i->dc_unc = talloc_strdup(i, resp->data.dsgetdcname.dc_unc);
607 BAIL_ON_PTR_ERROR(i->dc_unc, wbc_status);
609 i->dc_address = talloc_strdup(i, resp->data.dsgetdcname.dc_address);
610 BAIL_ON_PTR_ERROR(i->dc_address, wbc_status);
612 i->dc_address_type = resp->data.dsgetdcname.dc_address_type;
614 wbc_status = wbcStringToGuid(resp->data.dsgetdcname.domain_guid, &guid);
615 if (WBC_ERROR_IS_OK(wbc_status)) {
616 i->domain_guid = talloc(i, struct wbcGuid);
617 BAIL_ON_PTR_ERROR(i->domain_guid, wbc_status);
619 *i->domain_guid = guid;
621 i->domain_guid = NULL;
624 i->domain_name = talloc_strdup(i, resp->data.dsgetdcname.domain_name);
625 BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
627 if (resp->data.dsgetdcname.forest_name[0] != '\0') {
628 i->forest_name = talloc_strdup(i,
629 resp->data.dsgetdcname.forest_name);
630 BAIL_ON_PTR_ERROR(i->forest_name, wbc_status);
632 i->forest_name = NULL;
635 i->dc_flags = resp->data.dsgetdcname.dc_flags;
637 if (resp->data.dsgetdcname.dc_site_name[0] != '\0') {
638 i->dc_site_name = talloc_strdup(i,
639 resp->data.dsgetdcname.dc_site_name);
640 BAIL_ON_PTR_ERROR(i->dc_site_name, wbc_status);
642 i->dc_site_name = NULL;
645 if (resp->data.dsgetdcname.client_site_name[0] != '\0') {
646 i->client_site_name = talloc_strdup(i,
647 resp->data.dsgetdcname.client_site_name);
648 BAIL_ON_PTR_ERROR(i->client_site_name, wbc_status);
650 i->client_site_name = NULL;
661 /* Get extended domain controller information */
662 wbcErr wbcLookupDomainControllerEx(const char *domain,
663 struct wbcGuid *guid,
666 struct wbcDomainControllerInfoEx **dc_info)
668 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
669 struct winbindd_request request;
670 struct winbindd_response response;
672 /* validate input params */
674 if (!domain || !dc_info) {
675 wbc_status = WBC_ERR_INVALID_PARAM;
676 BAIL_ON_WBC_ERROR(wbc_status);
679 ZERO_STRUCT(request);
680 ZERO_STRUCT(response);
682 request.data.dsgetdcname.flags = flags;
684 strncpy(request.data.dsgetdcname.domain_name, domain,
685 sizeof(request.data.dsgetdcname.domain_name)-1);
688 strncpy(request.data.dsgetdcname.site_name, site,
689 sizeof(request.data.dsgetdcname.site_name)-1);
695 wbc_status = wbcGuidToString(guid, &str);
696 BAIL_ON_WBC_ERROR(wbc_status);
698 strncpy(request.data.dsgetdcname.domain_guid, str,
699 sizeof(request.data.dsgetdcname.domain_guid)-1);
706 wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
709 BAIL_ON_WBC_ERROR(wbc_status);
712 wbc_status = wbc_create_domain_controller_info_ex(NULL,
715 BAIL_ON_WBC_ERROR(wbc_status);
718 wbc_status = WBC_ERR_SUCCESS;
723 /* Initialize a named blob and add to list of blobs */
724 wbcErr wbcAddNamedBlob(size_t *num_blobs,
725 struct wbcNamedBlob **blobs,
731 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
732 struct wbcNamedBlob blob;
734 *blobs = talloc_realloc(NULL, *blobs, struct wbcNamedBlob,
736 BAIL_ON_PTR_ERROR(*blobs, wbc_status);
738 blob.name = talloc_strdup(*blobs, name);
739 BAIL_ON_PTR_ERROR(blob.name, wbc_status);
741 blob.blob.length = length;
742 blob.blob.data = (uint8_t *)talloc_memdup(*blobs, data, length);
743 BAIL_ON_PTR_ERROR(blob.blob.data, wbc_status);
745 (*(blobs))[*num_blobs] = blob;
748 wbc_status = WBC_ERR_SUCCESS;
750 if (!WBC_ERROR_IS_OK(wbc_status)) {
751 wbcFreeMemory(*blobs);