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