Merge branch 'master' of ctdb into 'master' of samba
[nivanova/samba-autobuild/.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(ips, 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         r = s;
470         if ( strcmp(r, "Offline") == 0) {
471                 info->domain_flags |= WBC_DOMINFO_DOMAIN_OFFLINE;
472         }
473
474         wbc_status = WBC_ERR_SUCCESS;
475
476  done:
477         return wbc_status;
478 }
479
480 static void wbcDomainInfoListDestructor(void *ptr)
481 {
482         struct wbcDomainInfo *i = (struct wbcDomainInfo *)ptr;
483
484         while (i->short_name != NULL) {
485                 free(i->short_name);
486                 free(i->dns_name);
487                 i += 1;
488         }
489 }
490
491 /* Enumerate the domain trusts known by Winbind */
492 wbcErr wbcListTrusts(struct wbcDomainInfo **domains, size_t *num_domains)
493 {
494         struct winbindd_response response;
495         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
496         char *p = NULL;
497         char *extra_data = NULL;
498         struct wbcDomainInfo *d_list = NULL;
499         int i = 0;
500
501         *domains = NULL;
502         *num_domains = 0;
503
504         ZERO_STRUCT(response);
505
506         /* Send request */
507
508         wbc_status = wbcRequestResponse(WINBINDD_LIST_TRUSTDOM,
509                                         NULL,
510                                         &response);
511         BAIL_ON_WBC_ERROR(wbc_status);
512
513         /* Decode the response */
514
515         p = (char *)response.extra_data.data;
516
517         if ((p == NULL) || (strlen(p) == 0)) {
518                 /* We should always at least get back our
519                    own SAM domain */
520
521                 wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
522                 BAIL_ON_WBC_ERROR(wbc_status);
523         }
524
525         d_list = (struct wbcDomainInfo *)wbcAllocateMemory(
526                 response.data.num_entries + 1,sizeof(struct wbcDomainInfo),
527                 wbcDomainInfoListDestructor);
528         BAIL_ON_PTR_ERROR(d_list, wbc_status);
529
530         extra_data = strdup((char*)response.extra_data.data);
531         BAIL_ON_PTR_ERROR(extra_data, wbc_status);
532
533         p = extra_data;
534
535         /* Outer loop processes the list of domain information */
536
537         for (i=0; i<response.data.num_entries && p; i++) {
538                 char *next = strchr(p, '\n');
539
540                 if (next) {
541                         *next = '\0';
542                         next++;
543                 }
544
545                 wbc_status = process_domain_info_string(&d_list[i], p);
546                 BAIL_ON_WBC_ERROR(wbc_status);
547
548                 p = next;
549         }
550
551         *domains = d_list;
552         d_list = NULL;
553         *num_domains = i;
554
555  done:
556         winbindd_free_response(&response);
557         wbcFreeMemory(d_list);
558         free(extra_data);
559         return wbc_status;
560 }
561
562 static void wbcDomainControllerInfoDestructor(void *ptr)
563 {
564         struct wbcDomainControllerInfo *i =
565                 (struct wbcDomainControllerInfo *)ptr;
566         free(i->dc_name);
567 }
568
569 /* Enumerate the domain trusts known by Winbind */
570 wbcErr wbcLookupDomainController(const char *domain,
571                                  uint32_t flags,
572                                 struct wbcDomainControllerInfo **dc_info)
573 {
574         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
575         struct winbindd_request request;
576         struct winbindd_response response;
577         struct wbcDomainControllerInfo *dc = NULL;
578
579         /* validate input params */
580
581         if (!domain || !dc_info) {
582                 wbc_status = WBC_ERR_INVALID_PARAM;
583                 BAIL_ON_WBC_ERROR(wbc_status);
584         }
585
586         ZERO_STRUCT(request);
587         ZERO_STRUCT(response);
588
589         strncpy(request.data.dsgetdcname.domain_name, domain,
590                 sizeof(request.data.dsgetdcname.domain_name)-1);
591
592         request.flags = flags;
593
594         dc = (struct wbcDomainControllerInfo *)wbcAllocateMemory(
595                  1, sizeof(struct wbcDomainControllerInfo),
596                 wbcDomainControllerInfoDestructor);
597         BAIL_ON_PTR_ERROR(dc, wbc_status);
598
599         /* Send request */
600
601         wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
602                                         &request,
603                                         &response);
604         BAIL_ON_WBC_ERROR(wbc_status);
605
606         dc->dc_name = strdup(response.data.dsgetdcname.dc_unc);
607         BAIL_ON_PTR_ERROR(dc->dc_name, wbc_status);
608
609         *dc_info = dc;
610         dc = NULL;
611
612 done:
613         wbcFreeMemory(dc);
614         return wbc_status;
615 }
616
617 static void wbcDomainControllerInfoExDestructor(void *ptr)
618 {
619         struct wbcDomainControllerInfoEx *i =
620                 (struct wbcDomainControllerInfoEx *)ptr;
621         free(discard_const_p(char, i->dc_unc));
622         free(discard_const_p(char, i->dc_address));
623         free(discard_const_p(char, i->domain_guid));
624         free(discard_const_p(char, i->domain_name));
625         free(discard_const_p(char, i->forest_name));
626         free(discard_const_p(char, i->dc_site_name));
627         free(discard_const_p(char, i->client_site_name));
628 }
629
630 static wbcErr wbc_create_domain_controller_info_ex(const struct winbindd_response *resp,
631                                                    struct wbcDomainControllerInfoEx **_i)
632 {
633         wbcErr wbc_status = WBC_ERR_SUCCESS;
634         struct wbcDomainControllerInfoEx *i;
635         struct wbcGuid guid;
636
637         i = (struct wbcDomainControllerInfoEx *)wbcAllocateMemory(
638                 1, sizeof(struct wbcDomainControllerInfoEx),
639                 wbcDomainControllerInfoExDestructor);
640         BAIL_ON_PTR_ERROR(i, wbc_status);
641
642         i->dc_unc = strdup(resp->data.dsgetdcname.dc_unc);
643         BAIL_ON_PTR_ERROR(i->dc_unc, wbc_status);
644
645         i->dc_address = strdup(resp->data.dsgetdcname.dc_address);
646         BAIL_ON_PTR_ERROR(i->dc_address, wbc_status);
647
648         i->dc_address_type = resp->data.dsgetdcname.dc_address_type;
649
650         wbc_status = wbcStringToGuid(resp->data.dsgetdcname.domain_guid, &guid);
651         if (WBC_ERROR_IS_OK(wbc_status)) {
652                 i->domain_guid = (struct wbcGuid *)malloc(
653                         sizeof(struct wbcGuid));
654                 BAIL_ON_PTR_ERROR(i->domain_guid, wbc_status);
655
656                 *i->domain_guid = guid;
657         }
658
659         i->domain_name = strdup(resp->data.dsgetdcname.domain_name);
660         BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
661
662         if (resp->data.dsgetdcname.forest_name[0] != '\0') {
663                 i->forest_name = strdup(resp->data.dsgetdcname.forest_name);
664                 BAIL_ON_PTR_ERROR(i->forest_name, wbc_status);
665         }
666
667         i->dc_flags = resp->data.dsgetdcname.dc_flags;
668
669         if (resp->data.dsgetdcname.dc_site_name[0] != '\0') {
670                 i->dc_site_name = strdup(resp->data.dsgetdcname.dc_site_name);
671                 BAIL_ON_PTR_ERROR(i->dc_site_name, wbc_status);
672         }
673
674         if (resp->data.dsgetdcname.client_site_name[0] != '\0') {
675                 i->client_site_name = strdup(
676                         resp->data.dsgetdcname.client_site_name);
677                 BAIL_ON_PTR_ERROR(i->client_site_name, wbc_status);
678         }
679
680         *_i = i;
681         i = NULL;
682
683 done:
684         if (i != NULL) {
685                 wbcFreeMemory(i);
686         }
687         return wbc_status;
688 }
689
690 /* Get extended domain controller information */
691 wbcErr wbcLookupDomainControllerEx(const char *domain,
692                                    struct wbcGuid *guid,
693                                    const char *site,
694                                    uint32_t flags,
695                                    struct wbcDomainControllerInfoEx **dc_info)
696 {
697         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
698         struct winbindd_request request;
699         struct winbindd_response response;
700
701         /* validate input params */
702
703         if (!domain || !dc_info) {
704                 wbc_status = WBC_ERR_INVALID_PARAM;
705                 BAIL_ON_WBC_ERROR(wbc_status);
706         }
707
708         ZERO_STRUCT(request);
709         ZERO_STRUCT(response);
710
711         request.data.dsgetdcname.flags = flags;
712
713         strncpy(request.data.dsgetdcname.domain_name, domain,
714                 sizeof(request.data.dsgetdcname.domain_name)-1);
715
716         if (site) {
717                 strncpy(request.data.dsgetdcname.site_name, site,
718                         sizeof(request.data.dsgetdcname.site_name)-1);
719         }
720
721         if (guid) {
722                 char *str = NULL;
723
724                 wbc_status = wbcGuidToString(guid, &str);
725                 BAIL_ON_WBC_ERROR(wbc_status);
726
727                 strncpy(request.data.dsgetdcname.domain_guid, str,
728                         sizeof(request.data.dsgetdcname.domain_guid)-1);
729
730                 wbcFreeMemory(str);
731         }
732
733         /* Send request */
734
735         wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
736                                         &request,
737                                         &response);
738         BAIL_ON_WBC_ERROR(wbc_status);
739
740         if (dc_info) {
741                 wbc_status = wbc_create_domain_controller_info_ex(&response,
742                                                                   dc_info);
743                 BAIL_ON_WBC_ERROR(wbc_status);
744         }
745
746         wbc_status = WBC_ERR_SUCCESS;
747 done:
748         return wbc_status;
749 }
750
751 static void wbcNamedBlobDestructor(void *ptr)
752 {
753         struct wbcNamedBlob *b = (struct wbcNamedBlob *)ptr;
754
755         while (b->name != NULL) {
756                 free(discard_const_p(char, b->name));
757                 free(b->blob.data);
758                 b += 1;
759         }
760 }
761
762 /* Initialize a named blob and add to list of blobs */
763 wbcErr wbcAddNamedBlob(size_t *num_blobs,
764                        struct wbcNamedBlob **pblobs,
765                        const char *name,
766                        uint32_t flags,
767                        uint8_t *data,
768                        size_t length)
769 {
770         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
771         struct wbcNamedBlob *blobs, *blob;
772
773         if (name == NULL) {
774                 return WBC_ERR_INVALID_PARAM;
775         }
776
777         /*
778          * Overallocate the b->name==NULL terminator for
779          * wbcNamedBlobDestructor
780          */
781         blobs = (struct wbcNamedBlob *)wbcAllocateMemory(
782                 *num_blobs + 2, sizeof(struct wbcNamedBlob),
783                 wbcNamedBlobDestructor);
784
785         if (blobs == NULL) {
786                 return WBC_ERR_NO_MEMORY;
787         }
788
789         if (*pblobs != NULL) {
790                 struct wbcNamedBlob *old = *pblobs;
791                 memcpy(blobs, old, sizeof(struct wbcNamedBlob) * (*num_blobs));
792                 if (*num_blobs != 0) {
793                         /* end indicator for wbcNamedBlobDestructor */
794                         old[0].name = NULL;
795                 }
796                 wbcFreeMemory(old);
797         }
798         *pblobs = blobs;
799
800         blob = &blobs[*num_blobs];
801
802         blob->name = strdup(name);
803         BAIL_ON_PTR_ERROR(blob->name, wbc_status);
804         blob->flags = flags;
805
806         blob->blob.length = length;
807         blob->blob.data = (uint8_t *)malloc(length);
808         BAIL_ON_PTR_ERROR(blob->blob.data, wbc_status);
809         memcpy(blob->blob.data, data, length);
810
811         *num_blobs += 1;
812         *pblobs = blobs;
813         blobs = NULL;
814
815         wbc_status = WBC_ERR_SUCCESS;
816 done:
817         wbcFreeMemory(blobs);
818         return wbc_status;
819 }