s3:winbind: Fix a potential segfault in libwbclient
[Samba/aatanasov.git] / nsswitch / libwbclient / wbc_util.c
blob7f3b61bb25d4f22c25689501510c78d13b3e48f4
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 "replace.h"
26 #include "libwbclient.h"
30 /** @brief Ping winbindd to see if the daemon is running
32 * @return #wbcErr
33 **/
35 wbcErr wbcPing(void)
37 struct winbindd_request request;
38 struct winbindd_response response;
40 /* Initialize request */
42 ZERO_STRUCT(request);
43 ZERO_STRUCT(response);
45 return wbcRequestResponse(WINBINDD_PING, &request, &response);
48 wbcErr wbcInterfaceDetails(struct wbcInterfaceDetails **_details)
50 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
51 struct wbcInterfaceDetails *info;
52 struct wbcDomainInfo *domain = NULL;
53 struct winbindd_request request;
54 struct winbindd_response response;
56 /* Initialize request */
58 ZERO_STRUCT(request);
59 ZERO_STRUCT(response);
61 info = talloc(NULL, struct wbcInterfaceDetails);
62 BAIL_ON_PTR_ERROR(info, wbc_status);
64 /* first the interface version */
65 wbc_status = wbcRequestResponse(WINBINDD_INTERFACE_VERSION, NULL, &response);
66 BAIL_ON_WBC_ERROR(wbc_status);
67 info->interface_version = response.data.interface_version;
69 /* then the samba version and the winbind separator */
70 wbc_status = wbcRequestResponse(WINBINDD_INFO, NULL, &response);
71 BAIL_ON_WBC_ERROR(wbc_status);
73 info->winbind_version = talloc_strdup(info,
74 response.data.info.samba_version);
75 BAIL_ON_PTR_ERROR(info->winbind_version, wbc_status);
76 info->winbind_separator = response.data.info.winbind_separator;
78 /* then the local netbios name */
79 wbc_status = wbcRequestResponse(WINBINDD_NETBIOS_NAME, NULL, &response);
80 BAIL_ON_WBC_ERROR(wbc_status);
82 info->netbios_name = talloc_strdup(info,
83 response.data.netbios_name);
84 BAIL_ON_PTR_ERROR(info->netbios_name, wbc_status);
86 /* then the local workgroup name */
87 wbc_status = wbcRequestResponse(WINBINDD_DOMAIN_NAME, NULL, &response);
88 BAIL_ON_WBC_ERROR(wbc_status);
90 info->netbios_domain = talloc_strdup(info,
91 response.data.domain_name);
92 BAIL_ON_PTR_ERROR(info->netbios_domain, wbc_status);
94 wbc_status = wbcDomainInfo(info->netbios_domain, &domain);
95 if (wbc_status == WBC_ERR_DOMAIN_NOT_FOUND) {
96 /* maybe it's a standalone server */
97 domain = NULL;
98 wbc_status = WBC_ERR_SUCCESS;
99 } else {
100 BAIL_ON_WBC_ERROR(wbc_status);
103 if (domain) {
104 info->dns_domain = talloc_strdup(info,
105 domain->dns_name);
106 wbcFreeMemory(domain);
107 BAIL_ON_PTR_ERROR(info->dns_domain, wbc_status);
108 } else {
109 info->dns_domain = NULL;
112 *_details = info;
113 info = NULL;
115 wbc_status = WBC_ERR_SUCCESS;
117 done:
118 talloc_free(info);
119 return wbc_status;
123 /* Lookup the current status of a trusted domain */
124 wbcErr wbcDomainInfo(const char *domain, struct wbcDomainInfo **dinfo)
126 struct winbindd_request request;
127 struct winbindd_response response;
128 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
129 struct wbcDomainInfo *info = NULL;
131 if (!domain || !dinfo) {
132 wbc_status = WBC_ERR_INVALID_PARAM;
133 BAIL_ON_WBC_ERROR(wbc_status);
136 /* Initialize request */
138 ZERO_STRUCT(request);
139 ZERO_STRUCT(response);
141 strncpy(request.domain_name, domain,
142 sizeof(request.domain_name)-1);
144 wbc_status = wbcRequestResponse(WINBINDD_DOMAIN_INFO,
145 &request,
146 &response);
147 BAIL_ON_WBC_ERROR(wbc_status);
149 info = talloc(NULL, struct wbcDomainInfo);
150 BAIL_ON_PTR_ERROR(info, wbc_status);
152 info->short_name = talloc_strdup(info,
153 response.data.domain_info.name);
154 BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
156 info->dns_name = talloc_strdup(info,
157 response.data.domain_info.alt_name);
158 BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
160 wbc_status = wbcStringToSid(response.data.domain_info.sid,
161 &info->sid);
162 BAIL_ON_WBC_ERROR(wbc_status);
164 if (response.data.domain_info.native_mode)
165 info->domain_flags |= WBC_DOMINFO_DOMAIN_NATIVE;
166 if (response.data.domain_info.active_directory)
167 info->domain_flags |= WBC_DOMINFO_DOMAIN_AD;
168 if (response.data.domain_info.primary)
169 info->domain_flags |= WBC_DOMINFO_DOMAIN_PRIMARY;
171 *dinfo = info;
173 wbc_status = WBC_ERR_SUCCESS;
175 done:
176 if (!WBC_ERROR_IS_OK(wbc_status)) {
177 talloc_free(info);
180 return wbc_status;
184 /* Resolve a NetbiosName via WINS */
185 wbcErr wbcResolveWinsByName(const char *name, char **ip)
187 struct winbindd_request request;
188 struct winbindd_response response;
189 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
190 char *ipaddr;
192 ZERO_STRUCT(request);
193 ZERO_STRUCT(response);
195 /* Send request */
197 strncpy(request.data.winsreq, name,
198 sizeof(request.data.winsreq)-1);
200 wbc_status = wbcRequestResponse(WINBINDD_WINS_BYNAME,
201 &request,
202 &response);
203 BAIL_ON_WBC_ERROR(wbc_status);
205 /* Display response */
207 ipaddr = talloc_strdup(NULL, response.data.winsresp);
208 BAIL_ON_PTR_ERROR(ipaddr, wbc_status);
210 *ip = ipaddr;
211 wbc_status = WBC_ERR_SUCCESS;
213 done:
214 return wbc_status;
217 /* Resolve an IP address via WINS into a NetbiosName */
218 wbcErr wbcResolveWinsByIP(const char *ip, char **name)
220 struct winbindd_request request;
221 struct winbindd_response response;
222 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
223 char *name_str;
225 ZERO_STRUCT(request);
226 ZERO_STRUCT(response);
228 /* Send request */
230 strncpy(request.data.winsreq, ip,
231 sizeof(request.data.winsreq)-1);
233 wbc_status = wbcRequestResponse(WINBINDD_WINS_BYIP,
234 &request,
235 &response);
236 BAIL_ON_WBC_ERROR(wbc_status);
238 /* Display response */
240 name_str = talloc_strdup(NULL, response.data.winsresp);
241 BAIL_ON_PTR_ERROR(name_str, wbc_status);
243 *name = name_str;
244 wbc_status = WBC_ERR_SUCCESS;
246 done:
247 return wbc_status;
253 static wbcErr process_domain_info_string(TALLOC_CTX *ctx,
254 struct wbcDomainInfo *info,
255 char *info_string)
257 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
258 char *r = NULL;
259 char *s = NULL;
261 if (!info || !info_string) {
262 wbc_status = WBC_ERR_INVALID_PARAM;
263 BAIL_ON_WBC_ERROR(wbc_status);
266 r = info_string;
268 /* Short Name */
269 if ((s = strchr(r, '\\')) == NULL) {
270 wbc_status = WBC_ERR_INVALID_RESPONSE;
271 BAIL_ON_WBC_ERROR(wbc_status);
273 *s = '\0';
274 s++;
276 info->short_name = talloc_strdup(ctx, r);
277 BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
280 /* DNS Name */
281 r = s;
282 if ((s = strchr(r, '\\')) == NULL) {
283 wbc_status = WBC_ERR_INVALID_RESPONSE;
284 BAIL_ON_WBC_ERROR(wbc_status);
286 *s = '\0';
287 s++;
289 info->dns_name = talloc_strdup(ctx, r);
290 BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
292 /* SID */
293 r = s;
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 wbc_status = wbcStringToSid(r, &info->sid);
302 BAIL_ON_WBC_ERROR(wbc_status);
304 /* Trust type */
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 if (strcmp(r, "None") == 0) {
314 info->trust_type = WBC_DOMINFO_TRUSTTYPE_NONE;
315 } else if (strcmp(r, "External") == 0) {
316 info->trust_type = WBC_DOMINFO_TRUSTTYPE_EXTERNAL;
317 } else if (strcmp(r, "Forest") == 0) {
318 info->trust_type = WBC_DOMINFO_TRUSTTYPE_FOREST;
319 } else if (strcmp(r, "In Forest") == 0) {
320 info->trust_type = WBC_DOMINFO_TRUSTTYPE_IN_FOREST;
321 } else {
322 wbc_status = WBC_ERR_INVALID_RESPONSE;
323 BAIL_ON_WBC_ERROR(wbc_status);
326 /* Transitive */
327 r = s;
328 if ((s = strchr(r, '\\')) == NULL) {
329 wbc_status = WBC_ERR_INVALID_RESPONSE;
330 BAIL_ON_WBC_ERROR(wbc_status);
332 *s = '\0';
333 s++;
335 if (strcmp(r, "Yes") == 0) {
336 info->trust_flags |= WBC_DOMINFO_TRUST_TRANSITIVE;
339 /* Incoming */
340 r = s;
341 if ((s = strchr(r, '\\')) == NULL) {
342 wbc_status = WBC_ERR_INVALID_RESPONSE;
343 BAIL_ON_WBC_ERROR(wbc_status);
345 *s = '\0';
346 s++;
348 if (strcmp(r, "Yes") == 0) {
349 info->trust_flags |= WBC_DOMINFO_TRUST_INCOMING;
352 /* Outgoing */
353 r = s;
354 if ((s = strchr(r, '\\')) == NULL) {
355 wbc_status = WBC_ERR_INVALID_RESPONSE;
356 BAIL_ON_WBC_ERROR(wbc_status);
358 *s = '\0';
359 s++;
361 if (strcmp(r, "Yes") == 0) {
362 info->trust_flags |= WBC_DOMINFO_TRUST_OUTGOING;
365 /* Online/Offline status */
367 r = s;
368 if (r == NULL) {
369 wbc_status = WBC_ERR_INVALID_RESPONSE;
370 BAIL_ON_WBC_ERROR(wbc_status);
372 if ( strcmp(r, "Offline") == 0) {
373 info->domain_flags |= WBC_DOMINFO_DOMAIN_OFFLINE;
376 wbc_status = WBC_ERR_SUCCESS;
378 done:
379 return wbc_status;
382 /* Enumerate the domain trusts known by Winbind */
383 wbcErr wbcListTrusts(struct wbcDomainInfo **domains, size_t *num_domains)
385 struct winbindd_response response;
386 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
387 char *p = NULL;
388 char *q = NULL;
389 char *extra_data = NULL;
390 int count = 0;
391 struct wbcDomainInfo *d_list = NULL;
392 int i = 0;
394 *domains = NULL;
395 *num_domains = 0;
397 ZERO_STRUCT(response);
399 /* Send request */
401 wbc_status = wbcRequestResponse(WINBINDD_LIST_TRUSTDOM,
402 NULL,
403 &response);
404 BAIL_ON_WBC_ERROR(wbc_status);
406 /* Decode the response */
408 p = (char *)response.extra_data.data;
410 if ((p == NULL) || (strlen(p) == 0)) {
411 /* We should always at least get back our
412 own SAM domain */
414 wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
415 BAIL_ON_WBC_ERROR(wbc_status);
418 /* Count number of domains */
420 count = 0;
421 while (p) {
422 count++;
424 if ((q = strchr(p, '\n')) != NULL)
425 q++;
426 p = q;
429 d_list = talloc_array(NULL, struct wbcDomainInfo, count);
430 BAIL_ON_PTR_ERROR(d_list, wbc_status);
432 extra_data = strdup((char*)response.extra_data.data);
433 BAIL_ON_PTR_ERROR(extra_data, wbc_status);
435 p = extra_data;
437 /* Outer loop processes the list of domain information */
439 for (i=0; i<count && p; i++) {
440 char *next = strchr(p, '\n');
442 if (next) {
443 *next = '\0';
444 next++;
447 wbc_status = process_domain_info_string(d_list, &d_list[i], p);
448 BAIL_ON_WBC_ERROR(wbc_status);
450 p = next;
453 *domains = d_list;
454 *num_domains = i;
456 done:
457 if (!WBC_ERROR_IS_OK(wbc_status)) {
458 if (d_list)
459 talloc_free(d_list);
460 if (extra_data)
461 free(extra_data);
464 return wbc_status;
467 /* Enumerate the domain trusts known by Winbind */
468 wbcErr wbcLookupDomainController(const char *domain,
469 uint32_t flags,
470 struct wbcDomainControllerInfo **dc_info)
472 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
473 struct winbindd_request request;
474 struct winbindd_response response;
475 struct wbcDomainControllerInfo *dc = NULL;
477 /* validate input params */
479 if (!domain || !dc_info) {
480 wbc_status = WBC_ERR_INVALID_PARAM;
481 BAIL_ON_WBC_ERROR(wbc_status);
484 ZERO_STRUCT(request);
485 ZERO_STRUCT(response);
487 strncpy(request.domain_name, domain, sizeof(request.domain_name)-1);
489 request.flags = flags;
491 dc = talloc(NULL, struct wbcDomainControllerInfo);
492 BAIL_ON_PTR_ERROR(dc, wbc_status);
494 /* Send request */
496 wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
497 &request,
498 &response);
499 BAIL_ON_WBC_ERROR(wbc_status);
501 dc->dc_name = talloc_strdup(dc, response.data.dc_name);
502 BAIL_ON_PTR_ERROR(dc->dc_name, wbc_status);
504 *dc_info = dc;
506 done:
507 if (!WBC_ERROR_IS_OK(wbc_status)) {
508 talloc_free(dc);
511 return wbc_status;
514 static wbcErr wbc_create_domain_controller_info_ex(TALLOC_CTX *mem_ctx,
515 const struct winbindd_response *resp,
516 struct wbcDomainControllerInfoEx **_i)
518 wbcErr wbc_status = WBC_ERR_SUCCESS;
519 struct wbcDomainControllerInfoEx *i;
520 struct wbcGuid guid;
522 i = talloc(mem_ctx, struct wbcDomainControllerInfoEx);
523 BAIL_ON_PTR_ERROR(i, wbc_status);
525 i->dc_unc = talloc_strdup(i, resp->data.dsgetdcname.dc_unc);
526 BAIL_ON_PTR_ERROR(i->dc_unc, wbc_status);
528 i->dc_address = talloc_strdup(i, resp->data.dsgetdcname.dc_address);
529 BAIL_ON_PTR_ERROR(i->dc_address, wbc_status);
531 i->dc_address_type = resp->data.dsgetdcname.dc_address_type;
533 wbc_status = wbcStringToGuid(resp->data.dsgetdcname.domain_guid, &guid);
534 if (WBC_ERROR_IS_OK(wbc_status)) {
535 i->domain_guid = talloc(i, struct wbcGuid);
536 BAIL_ON_PTR_ERROR(i->domain_guid, wbc_status);
538 *i->domain_guid = guid;
539 } else {
540 i->domain_guid = NULL;
543 i->domain_name = talloc_strdup(i, resp->data.dsgetdcname.domain_name);
544 BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
546 if (resp->data.dsgetdcname.forest_name[0] != '\0') {
547 i->forest_name = talloc_strdup(i,
548 resp->data.dsgetdcname.forest_name);
549 BAIL_ON_PTR_ERROR(i->forest_name, wbc_status);
550 } else {
551 i->forest_name = NULL;
554 i->dc_flags = resp->data.dsgetdcname.dc_flags;
556 if (resp->data.dsgetdcname.dc_site_name[0] != '\0') {
557 i->dc_site_name = talloc_strdup(i,
558 resp->data.dsgetdcname.dc_site_name);
559 BAIL_ON_PTR_ERROR(i->dc_site_name, wbc_status);
560 } else {
561 i->dc_site_name = NULL;
564 if (resp->data.dsgetdcname.client_site_name[0] != '\0') {
565 i->client_site_name = talloc_strdup(i,
566 resp->data.dsgetdcname.client_site_name);
567 BAIL_ON_PTR_ERROR(i->client_site_name, wbc_status);
568 } else {
569 i->client_site_name = NULL;
572 *_i = i;
573 i = NULL;
575 done:
576 talloc_free(i);
577 return wbc_status;
580 /* Get extended domain controller information */
581 wbcErr wbcLookupDomainControllerEx(const char *domain,
582 struct wbcGuid *guid,
583 const char *site,
584 uint32_t flags,
585 struct wbcDomainControllerInfoEx **dc_info)
587 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
588 struct winbindd_request request;
589 struct winbindd_response response;
591 /* validate input params */
593 if (!domain || !dc_info) {
594 wbc_status = WBC_ERR_INVALID_PARAM;
595 BAIL_ON_WBC_ERROR(wbc_status);
598 ZERO_STRUCT(request);
599 ZERO_STRUCT(response);
601 request.data.dsgetdcname.flags = flags;
603 strncpy(request.data.dsgetdcname.domain_name, domain,
604 sizeof(request.data.dsgetdcname.domain_name)-1);
606 if (site) {
607 strncpy(request.data.dsgetdcname.site_name, site,
608 sizeof(request.data.dsgetdcname.site_name)-1);
611 if (guid) {
612 char *str = NULL;
614 wbc_status = wbcGuidToString(guid, &str);
615 BAIL_ON_WBC_ERROR(wbc_status);
617 strncpy(request.data.dsgetdcname.domain_guid, str,
618 sizeof(request.data.dsgetdcname.domain_guid)-1);
620 wbcFreeMemory(str);
623 /* Send request */
625 wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
626 &request,
627 &response);
628 BAIL_ON_WBC_ERROR(wbc_status);
630 if (dc_info) {
631 wbc_status = wbc_create_domain_controller_info_ex(NULL,
632 &response,
633 dc_info);
634 BAIL_ON_WBC_ERROR(wbc_status);
637 wbc_status = WBC_ERR_SUCCESS;
638 done:
639 return wbc_status;
642 /* Initialize a named blob and add to list of blobs */
643 wbcErr wbcAddNamedBlob(size_t *num_blobs,
644 struct wbcNamedBlob **blobs,
645 const char *name,
646 uint32_t flags,
647 uint8_t *data,
648 size_t length)
650 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
651 struct wbcNamedBlob blob;
653 *blobs = talloc_realloc(NULL, *blobs, struct wbcNamedBlob,
654 *(num_blobs)+1);
655 BAIL_ON_PTR_ERROR(*blobs, wbc_status);
657 blob.name = talloc_strdup(*blobs, name);
658 BAIL_ON_PTR_ERROR(blob.name, wbc_status);
659 blob.flags = flags;
660 blob.blob.length = length;
661 blob.blob.data = (uint8_t *)talloc_memdup(*blobs, data, length);
662 BAIL_ON_PTR_ERROR(blob.blob.data, wbc_status);
664 (*(blobs))[*num_blobs] = blob;
665 *(num_blobs) += 1;
667 wbc_status = WBC_ERR_SUCCESS;
668 done:
669 if (!WBC_ERROR_IS_OK(wbc_status) && blobs) {
670 wbcFreeMemory(*blobs);
672 return wbc_status;