s3: Add wbinfo --dc-info
[kai/samba.git] / nsswitch / libwbclient / wbc_util.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Winbind client asynchronous API, utility functions
5
6    Copyright (C) Gerald (Jerry) Carter 2007-2008
7
8
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.
13
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.
18
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/>.
21 */
22
23 /* Required Headers */
24
25 #include "replace.h"
26 #include "libwbclient.h"
27 #include "../winbind_client.h"
28
29 /** @brief Ping winbindd to see if the daemon is running
30  *
31  * @return #wbcErr
32  **/
33 wbcErr wbcPing(void)
34 {
35         struct winbindd_request request;
36         struct winbindd_response response;
37
38         /* Initialize request */
39
40         ZERO_STRUCT(request);
41         ZERO_STRUCT(response);
42
43         return wbcRequestResponse(WINBINDD_PING, &request, &response);
44 }
45
46 static void wbcInterfaceDetailsDestructor(void *ptr)
47 {
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);
53 }
54
55 /**
56  * @brief Query useful information about the winbind service
57  *
58  * @param *_details     pointer to hold the struct wbcInterfaceDetails
59  *
60  * @return #wbcErr
61  */
62
63 wbcErr wbcInterfaceDetails(struct wbcInterfaceDetails **_details)
64 {
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;
70
71         /* Initialize request */
72
73         ZERO_STRUCT(request);
74         ZERO_STRUCT(response);
75
76         info = (struct wbcInterfaceDetails *)wbcAllocateMemory(
77                 1, sizeof(struct wbcInterfaceDetails),
78                 wbcInterfaceDetailsDestructor);
79         BAIL_ON_PTR_ERROR(info, wbc_status);
80
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;
85
86         /* then the samba version and the winbind separator */
87         wbc_status = wbcRequestResponse(WINBINDD_INFO, NULL, &response);
88         BAIL_ON_WBC_ERROR(wbc_status);
89
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;
93
94         /* then the local netbios name */
95         wbc_status = wbcRequestResponse(WINBINDD_NETBIOS_NAME, NULL, &response);
96         BAIL_ON_WBC_ERROR(wbc_status);
97
98         info->netbios_name = strdup(response.data.netbios_name);
99         BAIL_ON_PTR_ERROR(info->netbios_name, wbc_status);
100
101         /* then the local workgroup name */
102         wbc_status = wbcRequestResponse(WINBINDD_DOMAIN_NAME, NULL, &response);
103         BAIL_ON_WBC_ERROR(wbc_status);
104
105         info->netbios_domain = strdup(response.data.domain_name);
106         BAIL_ON_PTR_ERROR(info->netbios_domain, wbc_status);
107
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);
115         }
116
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;
123         }
124
125         *_details = info;
126         info = NULL;
127
128         wbc_status = WBC_ERR_SUCCESS;
129
130 done:
131         wbcFreeMemory(info);
132         return wbc_status;
133 }
134
135 static void wbcDomainInfoDestructor(void *ptr)
136 {
137         struct wbcDomainInfo *i = (struct wbcDomainInfo *)ptr;
138         free(i->short_name);
139         free(i->dns_name);
140 }
141
142 /** @brief Lookup the current status of a trusted domain, sync wrapper
143  *
144  * @param domain      Domain to query
145  * @param *dinfo       Pointer to returned struct wbcDomainInfo
146  *
147  * @return #wbcErr
148  */
149
150 wbcErr wbcDomainInfo(const char *domain, struct wbcDomainInfo **dinfo)
151 {
152         struct winbindd_request request;
153         struct winbindd_response response;
154         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
155         struct wbcDomainInfo *info = NULL;
156
157         if (!domain || !dinfo) {
158                 wbc_status = WBC_ERR_INVALID_PARAM;
159                 BAIL_ON_WBC_ERROR(wbc_status);
160         }
161
162         /* Initialize request */
163
164         ZERO_STRUCT(request);
165         ZERO_STRUCT(response);
166
167         strncpy(request.domain_name, domain,
168                 sizeof(request.domain_name)-1);
169
170         wbc_status = wbcRequestResponse(WINBINDD_DOMAIN_INFO,
171                                         &request,
172                                         &response);
173         BAIL_ON_WBC_ERROR(wbc_status);
174
175         info = (struct wbcDomainInfo *)wbcAllocateMemory(
176                 1, sizeof(struct wbcDomainInfo), wbcDomainInfoDestructor);
177         BAIL_ON_PTR_ERROR(info, wbc_status);
178
179         info->short_name = strdup(response.data.domain_info.name);
180         BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
181
182         info->dns_name = strdup(response.data.domain_info.alt_name);
183         BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
184
185         wbc_status = wbcStringToSid(response.data.domain_info.sid,
186                                     &info->sid);
187         BAIL_ON_WBC_ERROR(wbc_status);
188
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;
195
196         *dinfo = info;
197         info = NULL;
198
199         wbc_status = WBC_ERR_SUCCESS;
200
201  done:
202         wbcFreeMemory(info);
203         return wbc_status;
204 }
205
206 /* Get the list of current DCs */
207 wbcErr wbcDcInfo(const char *domain, size_t *num_dcs,
208                  const char ***dc_names, const char ***dc_ips)
209 {
210         struct winbindd_request request;
211         struct winbindd_response response;
212         const char **names = NULL;
213         const char **ips = NULL;
214         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
215         size_t extra_len;
216         int i;
217         char *p;
218
219         /* Initialise request */
220
221         ZERO_STRUCT(request);
222         ZERO_STRUCT(response);
223
224         if (domain != NULL) {
225                 strncpy(request.domain_name, domain,
226                         sizeof(request.domain_name) - 1);
227         }
228
229         wbc_status = wbcRequestResponse(WINBINDD_DC_INFO,
230                                         &request, &response);
231         BAIL_ON_WBC_ERROR(wbc_status);
232
233         names = wbcAllocateStringArray(response.data.num_entries);
234         BAIL_ON_PTR_ERROR(names, wbc_status);
235
236         ips = wbcAllocateStringArray(response.data.num_entries);
237         BAIL_ON_PTR_ERROR(names, wbc_status);
238
239         wbc_status = WBC_ERR_INVALID_RESPONSE;
240
241         p = (char *)response.extra_data.data;
242
243         if (response.length < (sizeof(struct winbindd_response)+1)) {
244                 goto done;
245         }
246
247         extra_len = response.length - sizeof(struct winbindd_response);
248
249         if (p[extra_len-1] != '\0') {
250                 goto done;
251         }
252
253         for (i=0; i<response.data.num_entries; i++) {
254                 char *q;
255
256                 q = strchr(p, '\n');
257                 if (q == NULL) {
258                         goto done;
259                 }
260                 names[i] = strndup(p, q-p);
261                 BAIL_ON_PTR_ERROR(names[i], wbc_status);
262                 p = q+1;
263
264                 q = strchr(p, '\n');
265                 if (q == NULL) {
266                         goto done;
267                 }
268                 ips[i] = strndup(p, q-p);
269                 BAIL_ON_PTR_ERROR(ips[i], wbc_status);
270                 p = q+1;
271         }
272         if (p[0] != '\0') {
273                 goto done;
274         }
275
276         wbc_status = WBC_ERR_SUCCESS;
277 done:
278         if (response.extra_data.data)
279                 free(response.extra_data.data);
280
281         if (WBC_ERROR_IS_OK(wbc_status)) {
282                 *num_dcs = response.data.num_entries;
283                 *dc_names = names;
284                 names = NULL;
285                 *dc_ips = ips;
286                 ips = NULL;
287         }
288         wbcFreeMemory(names);
289         wbcFreeMemory(ips);
290         return wbc_status;
291 }
292
293 /* Resolve a NetbiosName via WINS */
294 wbcErr wbcResolveWinsByName(const char *name, char **ip)
295 {
296         struct winbindd_request request;
297         struct winbindd_response response;
298         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
299         char *ipaddr;
300
301         ZERO_STRUCT(request);
302         ZERO_STRUCT(response);
303
304         /* Send request */
305
306         strncpy(request.data.winsreq, name,
307                 sizeof(request.data.winsreq)-1);
308
309         wbc_status = wbcRequestResponse(WINBINDD_WINS_BYNAME,
310                                         &request,
311                                         &response);
312         BAIL_ON_WBC_ERROR(wbc_status);
313
314         /* Display response */
315
316         ipaddr = wbcStrDup(response.data.winsresp);
317         BAIL_ON_PTR_ERROR(ipaddr, wbc_status);
318
319         *ip = ipaddr;
320         wbc_status = WBC_ERR_SUCCESS;
321
322  done:
323         return wbc_status;
324 }
325
326 /* Resolve an IP address via WINS into a NetbiosName */
327 wbcErr wbcResolveWinsByIP(const char *ip, char **name)
328 {
329         struct winbindd_request request;
330         struct winbindd_response response;
331         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
332         char *name_str;
333
334         ZERO_STRUCT(request);
335         ZERO_STRUCT(response);
336
337         /* Send request */
338
339         strncpy(request.data.winsreq, ip,
340                 sizeof(request.data.winsreq)-1);
341
342         wbc_status = wbcRequestResponse(WINBINDD_WINS_BYIP,
343                                         &request,
344                                         &response);
345         BAIL_ON_WBC_ERROR(wbc_status);
346
347         /* Display response */
348
349         name_str = wbcStrDup(response.data.winsresp);
350         BAIL_ON_PTR_ERROR(name_str, wbc_status);
351
352         *name = name_str;
353         wbc_status = WBC_ERR_SUCCESS;
354
355  done:
356         return wbc_status;
357 }
358
359 /**
360  */
361
362 static wbcErr process_domain_info_string(struct wbcDomainInfo *info,
363                                          char *info_string)
364 {
365         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
366         char *r = NULL;
367         char *s = NULL;
368
369         r = info_string;
370
371         /* Short Name */
372         if ((s = strchr(r, '\\')) == NULL) {
373                 wbc_status = WBC_ERR_INVALID_RESPONSE;
374                 BAIL_ON_WBC_ERROR(wbc_status);
375         }
376         *s = '\0';
377         s++;
378
379         info->short_name = strdup(r);
380         BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
381
382
383         /* DNS Name */
384         r = s;
385         if ((s = strchr(r, '\\')) == NULL) {
386                 wbc_status = WBC_ERR_INVALID_RESPONSE;
387                 BAIL_ON_WBC_ERROR(wbc_status);
388         }
389         *s = '\0';
390         s++;
391
392         info->dns_name = strdup(r);
393         BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
394
395         /* SID */
396         r = s;
397         if ((s = strchr(r, '\\')) == NULL) {
398                 wbc_status = WBC_ERR_INVALID_RESPONSE;
399                 BAIL_ON_WBC_ERROR(wbc_status);
400         }
401         *s = '\0';
402         s++;
403
404         wbc_status = wbcStringToSid(r, &info->sid);
405         BAIL_ON_WBC_ERROR(wbc_status);
406
407         /* Trust type */
408         r = s;
409         if ((s = strchr(r, '\\')) == NULL) {
410                 wbc_status = WBC_ERR_INVALID_RESPONSE;
411                 BAIL_ON_WBC_ERROR(wbc_status);
412         }
413         *s = '\0';
414         s++;
415
416         if (strcmp(r, "None") == 0) {
417                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_NONE;
418         } else if (strcmp(r, "External") == 0) {
419                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_EXTERNAL;
420         } else if (strcmp(r, "Forest") == 0) {
421                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_FOREST;
422         } else if (strcmp(r, "In Forest") == 0) {
423                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_IN_FOREST;
424         } else {
425                 wbc_status = WBC_ERR_INVALID_RESPONSE;
426                 BAIL_ON_WBC_ERROR(wbc_status);
427         }
428
429         /* Transitive */
430         r = s;
431         if ((s = strchr(r, '\\')) == NULL) {
432                 wbc_status = WBC_ERR_INVALID_RESPONSE;
433                 BAIL_ON_WBC_ERROR(wbc_status);
434         }
435         *s = '\0';
436         s++;
437
438         if (strcmp(r, "Yes") == 0) {
439                 info->trust_flags |= WBC_DOMINFO_TRUST_TRANSITIVE;
440         }
441
442         /* Incoming */
443         r = s;
444         if ((s = strchr(r, '\\')) == NULL) {
445                 wbc_status = WBC_ERR_INVALID_RESPONSE;
446                 BAIL_ON_WBC_ERROR(wbc_status);
447         }
448         *s = '\0';
449         s++;
450
451         if (strcmp(r, "Yes") == 0) {
452                 info->trust_flags |= WBC_DOMINFO_TRUST_INCOMING;
453         }
454
455         /* Outgoing */
456         r = s;
457         if ((s = strchr(r, '\\')) == NULL) {
458                 wbc_status = WBC_ERR_INVALID_RESPONSE;
459                 BAIL_ON_WBC_ERROR(wbc_status);
460         }
461         *s = '\0';
462         s++;
463
464         if (strcmp(r, "Yes") == 0) {
465                 info->trust_flags |= WBC_DOMINFO_TRUST_OUTGOING;
466         }
467
468         /* Online/Offline status */
469
470         r = s;
471         if (r == NULL) {
472                 wbc_status = WBC_ERR_INVALID_RESPONSE;
473                 BAIL_ON_WBC_ERROR(wbc_status);
474         }
475         if ( strcmp(r, "Offline") == 0) {
476                 info->domain_flags |= WBC_DOMINFO_DOMAIN_OFFLINE;
477         }
478
479         wbc_status = WBC_ERR_SUCCESS;
480
481  done:
482         return wbc_status;
483 }
484
485 static void wbcDomainInfoListDestructor(void *ptr)
486 {
487         struct wbcDomainInfo *i = (struct wbcDomainInfo *)ptr;
488
489         while (i->short_name != NULL) {
490                 free(i->short_name);
491                 free(i->dns_name);
492                 i += 1;
493         }
494 }
495
496 /* Enumerate the domain trusts known by Winbind */
497 wbcErr wbcListTrusts(struct wbcDomainInfo **domains, size_t *num_domains)
498 {
499         struct winbindd_response response;
500         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
501         char *p = NULL;
502         char *extra_data = NULL;
503         struct wbcDomainInfo *d_list = NULL;
504         int i = 0;
505
506         *domains = NULL;
507         *num_domains = 0;
508
509         ZERO_STRUCT(response);
510
511         /* Send request */
512
513         wbc_status = wbcRequestResponse(WINBINDD_LIST_TRUSTDOM,
514                                         NULL,
515                                         &response);
516         BAIL_ON_WBC_ERROR(wbc_status);
517
518         /* Decode the response */
519
520         p = (char *)response.extra_data.data;
521
522         if ((p == NULL) || (strlen(p) == 0)) {
523                 /* We should always at least get back our
524                    own SAM domain */
525
526                 wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
527                 BAIL_ON_WBC_ERROR(wbc_status);
528         }
529
530         d_list = (struct wbcDomainInfo *)wbcAllocateMemory(
531                 response.data.num_entries + 1,sizeof(struct wbcDomainInfo),
532                 wbcDomainInfoListDestructor);
533         BAIL_ON_PTR_ERROR(d_list, wbc_status);
534
535         extra_data = strdup((char*)response.extra_data.data);
536         BAIL_ON_PTR_ERROR(extra_data, wbc_status);
537
538         p = extra_data;
539
540         /* Outer loop processes the list of domain information */
541
542         for (i=0; i<response.data.num_entries && p; i++) {
543                 char *next = strchr(p, '\n');
544
545                 if (next) {
546                         *next = '\0';
547                         next++;
548                 }
549
550                 wbc_status = process_domain_info_string(&d_list[i], p);
551                 BAIL_ON_WBC_ERROR(wbc_status);
552
553                 p = next;
554         }
555
556         *domains = d_list;
557         d_list = NULL;
558         *num_domains = i;
559
560  done:
561         winbindd_free_response(&response);
562         wbcFreeMemory(d_list);
563         free(extra_data);
564         return wbc_status;
565 }
566
567 static void wbcDomainControllerInfoDestructor(void *ptr)
568 {
569         struct wbcDomainControllerInfo *i =
570                 (struct wbcDomainControllerInfo *)ptr;
571         free(i->dc_name);
572 }
573
574 /* Enumerate the domain trusts known by Winbind */
575 wbcErr wbcLookupDomainController(const char *domain,
576                                  uint32_t flags,
577                                 struct wbcDomainControllerInfo **dc_info)
578 {
579         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
580         struct winbindd_request request;
581         struct winbindd_response response;
582         struct wbcDomainControllerInfo *dc = NULL;
583
584         /* validate input params */
585
586         if (!domain || !dc_info) {
587                 wbc_status = WBC_ERR_INVALID_PARAM;
588                 BAIL_ON_WBC_ERROR(wbc_status);
589         }
590
591         ZERO_STRUCT(request);
592         ZERO_STRUCT(response);
593
594         strncpy(request.data.dsgetdcname.domain_name, domain,
595                 sizeof(request.data.dsgetdcname.domain_name)-1);
596
597         request.flags = flags;
598
599         dc = (struct wbcDomainControllerInfo *)wbcAllocateMemory(
600                  1, sizeof(struct wbcDomainControllerInfo),
601                 wbcDomainControllerInfoDestructor);
602         BAIL_ON_PTR_ERROR(dc, wbc_status);
603
604         /* Send request */
605
606         wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
607                                         &request,
608                                         &response);
609         BAIL_ON_WBC_ERROR(wbc_status);
610
611         dc->dc_name = strdup(response.data.dsgetdcname.dc_unc);
612         BAIL_ON_PTR_ERROR(dc->dc_name, wbc_status);
613
614         *dc_info = dc;
615         dc = NULL;
616
617 done:
618         wbcFreeMemory(dc);
619         return wbc_status;
620 }
621
622 static void wbcDomainControllerInfoExDestructor(void *ptr)
623 {
624         struct wbcDomainControllerInfoEx *i =
625                 (struct wbcDomainControllerInfoEx *)ptr;
626         free((char *)(i->dc_unc));
627         free((char *)(i->dc_address));
628         free((char *)(i->domain_guid));
629         free((char *)(i->domain_name));
630         free((char *)(i->forest_name));
631         free((char *)(i->dc_site_name));
632         free((char *)(i->client_site_name));
633 }
634
635 static wbcErr wbc_create_domain_controller_info_ex(const struct winbindd_response *resp,
636                                                    struct wbcDomainControllerInfoEx **_i)
637 {
638         wbcErr wbc_status = WBC_ERR_SUCCESS;
639         struct wbcDomainControllerInfoEx *i;
640         struct wbcGuid guid;
641
642         i = (struct wbcDomainControllerInfoEx *)wbcAllocateMemory(
643                 1, sizeof(struct wbcDomainControllerInfoEx),
644                 wbcDomainControllerInfoExDestructor);
645         BAIL_ON_PTR_ERROR(i, wbc_status);
646
647         i->dc_unc = strdup(resp->data.dsgetdcname.dc_unc);
648         BAIL_ON_PTR_ERROR(i->dc_unc, wbc_status);
649
650         i->dc_address = strdup(resp->data.dsgetdcname.dc_address);
651         BAIL_ON_PTR_ERROR(i->dc_address, wbc_status);
652
653         i->dc_address_type = resp->data.dsgetdcname.dc_address_type;
654
655         wbc_status = wbcStringToGuid(resp->data.dsgetdcname.domain_guid, &guid);
656         if (WBC_ERROR_IS_OK(wbc_status)) {
657                 i->domain_guid = (struct wbcGuid *)malloc(
658                         sizeof(struct wbcGuid));
659                 BAIL_ON_PTR_ERROR(i->domain_guid, wbc_status);
660
661                 *i->domain_guid = guid;
662         }
663
664         i->domain_name = strdup(resp->data.dsgetdcname.domain_name);
665         BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
666
667         if (resp->data.dsgetdcname.forest_name[0] != '\0') {
668                 i->forest_name = strdup(resp->data.dsgetdcname.forest_name);
669                 BAIL_ON_PTR_ERROR(i->forest_name, wbc_status);
670         }
671
672         i->dc_flags = resp->data.dsgetdcname.dc_flags;
673
674         if (resp->data.dsgetdcname.dc_site_name[0] != '\0') {
675                 i->dc_site_name = strdup(resp->data.dsgetdcname.dc_site_name);
676                 BAIL_ON_PTR_ERROR(i->dc_site_name, wbc_status);
677         }
678
679         if (resp->data.dsgetdcname.client_site_name[0] != '\0') {
680                 i->client_site_name = strdup(
681                         resp->data.dsgetdcname.client_site_name);
682                 BAIL_ON_PTR_ERROR(i->client_site_name, wbc_status);
683         }
684
685         *_i = i;
686         i = NULL;
687
688 done:
689         if (i != NULL) {
690                 wbcFreeMemory(i);
691         }
692         return wbc_status;
693 }
694
695 /* Get extended domain controller information */
696 wbcErr wbcLookupDomainControllerEx(const char *domain,
697                                    struct wbcGuid *guid,
698                                    const char *site,
699                                    uint32_t flags,
700                                    struct wbcDomainControllerInfoEx **dc_info)
701 {
702         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
703         struct winbindd_request request;
704         struct winbindd_response response;
705
706         /* validate input params */
707
708         if (!domain || !dc_info) {
709                 wbc_status = WBC_ERR_INVALID_PARAM;
710                 BAIL_ON_WBC_ERROR(wbc_status);
711         }
712
713         ZERO_STRUCT(request);
714         ZERO_STRUCT(response);
715
716         request.data.dsgetdcname.flags = flags;
717
718         strncpy(request.data.dsgetdcname.domain_name, domain,
719                 sizeof(request.data.dsgetdcname.domain_name)-1);
720
721         if (site) {
722                 strncpy(request.data.dsgetdcname.site_name, site,
723                         sizeof(request.data.dsgetdcname.site_name)-1);
724         }
725
726         if (guid) {
727                 char *str = NULL;
728
729                 wbc_status = wbcGuidToString(guid, &str);
730                 BAIL_ON_WBC_ERROR(wbc_status);
731
732                 strncpy(request.data.dsgetdcname.domain_guid, str,
733                         sizeof(request.data.dsgetdcname.domain_guid)-1);
734
735                 wbcFreeMemory(str);
736         }
737
738         /* Send request */
739
740         wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
741                                         &request,
742                                         &response);
743         BAIL_ON_WBC_ERROR(wbc_status);
744
745         if (dc_info) {
746                 wbc_status = wbc_create_domain_controller_info_ex(&response,
747                                                                   dc_info);
748                 BAIL_ON_WBC_ERROR(wbc_status);
749         }
750
751         wbc_status = WBC_ERR_SUCCESS;
752 done:
753         return wbc_status;
754 }
755
756 static void wbcNamedBlobDestructor(void *ptr)
757 {
758         struct wbcNamedBlob *b = (struct wbcNamedBlob *)ptr;
759
760         while (b->name != NULL) {
761                 free((char *)(b->name));
762                 free(b->blob.data);
763                 b += 1;
764         }
765 }
766
767 /* Initialize a named blob and add to list of blobs */
768 wbcErr wbcAddNamedBlob(size_t *num_blobs,
769                        struct wbcNamedBlob **pblobs,
770                        const char *name,
771                        uint32_t flags,
772                        uint8_t *data,
773                        size_t length)
774 {
775         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
776         struct wbcNamedBlob *blobs, *blob;
777
778         if (name == NULL) {
779                 return WBC_ERR_INVALID_PARAM;
780         }
781
782         /*
783          * Overallocate the b->name==NULL terminator for
784          * wbcNamedBlobDestructor
785          */
786         blobs = (struct wbcNamedBlob *)wbcAllocateMemory(
787                 *num_blobs + 2, sizeof(struct wbcNamedBlob),
788                 wbcNamedBlobDestructor);
789
790         if (*pblobs != NULL) {
791                 struct wbcNamedBlob *old = *pblobs;
792                 memcpy(blobs, old, sizeof(struct wbcNamedBlob) * (*num_blobs));
793                 if (*num_blobs != 0) {
794                         /* end indicator for wbcNamedBlobDestructor */
795                         old[0].name = NULL;
796                 }
797                 wbcFreeMemory(old);
798         }
799         *pblobs = blobs;
800
801         blob = &blobs[*num_blobs];
802
803         blob->name = strdup(name);
804         BAIL_ON_PTR_ERROR(blob->name, wbc_status);
805         blob->flags = flags;
806
807         blob->blob.length = length;
808         blob->blob.data = (uint8_t *)malloc(length);
809         BAIL_ON_PTR_ERROR(blob->blob.data, wbc_status);
810         memcpy(blob->blob.data, data, length);
811
812         *num_blobs += 1;
813         *pblobs = blobs;
814         blobs = NULL;
815
816         wbc_status = WBC_ERR_SUCCESS;
817 done:
818         wbcFreeMemory(blobs);
819         return wbc_status;
820 }