winbindd: winbindd_ccache_ntlm_auth() -> bool_dispatch_table
[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  * @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 (strncmp(r, "Routed", strlen("Routed")) == 0) {
459                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_NONE;
460                 info->trust_routing = strdup(r);
461                 BAIL_ON_PTR_ERROR(info->trust_routing, wbc_status);
462         } else if (strcmp(r, "Local") == 0) {
463                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_LOCAL;
464         } else if (strcmp(r, "Workstation") == 0) {
465                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_WKSTA;
466         } else if (strcmp(r, "RWDC") == 0) {
467                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_RWDC;
468         } else if (strcmp(r, "RODC") == 0) {
469                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_RODC;
470         } else if (strcmp(r, "PDC") == 0) {
471                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_PDC;
472         } else if (strcmp(r, "External") == 0) {
473                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_EXTERNAL;
474         } else if (strcmp(r, "Forest") == 0) {
475                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_FOREST;
476         } else if (strcmp(r, "In Forest") == 0) {
477                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_IN_FOREST;
478         } else {
479                 wbc_status = WBC_ERR_INVALID_RESPONSE;
480                 BAIL_ON_WBC_ERROR(wbc_status);
481         }
482
483         /* Transitive */
484         r = s;
485         if ((s = strchr(r, '\\')) == NULL) {
486                 wbc_status = WBC_ERR_INVALID_RESPONSE;
487                 BAIL_ON_WBC_ERROR(wbc_status);
488         }
489         *s = '\0';
490         s++;
491
492         if (strcmp(r, "Yes") == 0) {
493                 info->trust_flags |= WBC_DOMINFO_TRUST_TRANSITIVE;
494         }
495
496         /* Incoming */
497         r = s;
498         if ((s = strchr(r, '\\')) == NULL) {
499                 wbc_status = WBC_ERR_INVALID_RESPONSE;
500                 BAIL_ON_WBC_ERROR(wbc_status);
501         }
502         *s = '\0';
503         s++;
504
505         if (strcmp(r, "Yes") == 0) {
506                 info->trust_flags |= WBC_DOMINFO_TRUST_INCOMING;
507         }
508
509         /* Outgoing */
510         r = s;
511         if ((s = strchr(r, '\\')) == NULL) {
512                 wbc_status = WBC_ERR_INVALID_RESPONSE;
513                 BAIL_ON_WBC_ERROR(wbc_status);
514         }
515         *s = '\0';
516         s++;
517
518         if (strcmp(r, "Yes") == 0) {
519                 info->trust_flags |= WBC_DOMINFO_TRUST_OUTGOING;
520         }
521
522         /* Online/Offline status */
523         r = s;
524         if ( strcmp(r, "Offline") == 0) {
525                 info->domain_flags |= WBC_DOMINFO_DOMAIN_OFFLINE;
526         }
527
528         wbc_status = WBC_ERR_SUCCESS;
529
530  done:
531         return wbc_status;
532 }
533
534 static void wbcDomainInfoListDestructor(void *ptr)
535 {
536         struct wbcDomainInfo *i = (struct wbcDomainInfo *)ptr;
537
538         while (i->short_name != NULL) {
539                 free(i->short_name);
540                 free(i->dns_name);
541                 i += 1;
542         }
543 }
544
545 /* Enumerate the domain trusts known by Winbind */
546 wbcErr wbcCtxListTrusts(struct wbcContext *ctx,
547                         struct wbcDomainInfo **domains, size_t *num_domains)
548 {
549         struct winbindd_response response;
550         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
551         char *p = NULL;
552         char *extra_data = NULL;
553         struct wbcDomainInfo *d_list = NULL;
554         int i = 0;
555
556         *domains = NULL;
557         *num_domains = 0;
558
559         ZERO_STRUCT(response);
560
561         /* Send request */
562
563         wbc_status = wbcRequestResponse(ctx, WINBINDD_LIST_TRUSTDOM,
564                                         NULL,
565                                         &response);
566         BAIL_ON_WBC_ERROR(wbc_status);
567
568         /* Decode the response */
569
570         p = (char *)response.extra_data.data;
571
572         if ((p == NULL) || (strlen(p) == 0)) {
573                 /* We should always at least get back our
574                    own SAM domain */
575
576                 wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
577                 BAIL_ON_WBC_ERROR(wbc_status);
578         }
579
580         d_list = (struct wbcDomainInfo *)wbcAllocateMemory(
581                 response.data.num_entries + 1,sizeof(struct wbcDomainInfo),
582                 wbcDomainInfoListDestructor);
583         BAIL_ON_PTR_ERROR(d_list, wbc_status);
584
585         extra_data = strdup((char*)response.extra_data.data);
586         BAIL_ON_PTR_ERROR(extra_data, wbc_status);
587
588         p = extra_data;
589
590         /* Outer loop processes the list of domain information */
591
592         for (i=0; i<response.data.num_entries && p; i++) {
593                 char *next = strchr(p, '\n');
594
595                 if (next) {
596                         *next = '\0';
597                         next++;
598                 }
599
600                 wbc_status = process_domain_info_string(&d_list[i], p);
601                 BAIL_ON_WBC_ERROR(wbc_status);
602
603                 p = next;
604         }
605
606         *domains = d_list;
607         d_list = NULL;
608         *num_domains = i;
609
610  done:
611         winbindd_free_response(&response);
612         wbcFreeMemory(d_list);
613         free(extra_data);
614         return wbc_status;
615 }
616
617 wbcErr wbcListTrusts(struct wbcDomainInfo **domains, size_t *num_domains)
618 {
619         return wbcCtxListTrusts(NULL, domains, num_domains);
620 }
621
622 static void wbcDomainControllerInfoDestructor(void *ptr)
623 {
624         struct wbcDomainControllerInfo *i =
625                 (struct wbcDomainControllerInfo *)ptr;
626         free(i->dc_name);
627 }
628
629 /* Enumerate the domain trusts known by Winbind */
630 wbcErr wbcCtxLookupDomainController(struct wbcContext *ctx,
631                                     const char *domain, uint32_t flags,
632                                     struct wbcDomainControllerInfo **dc_info)
633 {
634         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
635         struct winbindd_request request;
636         struct winbindd_response response;
637         struct wbcDomainControllerInfo *dc = NULL;
638
639         /* validate input params */
640
641         if (!domain || !dc_info) {
642                 wbc_status = WBC_ERR_INVALID_PARAM;
643                 BAIL_ON_WBC_ERROR(wbc_status);
644         }
645
646         ZERO_STRUCT(request);
647         ZERO_STRUCT(response);
648
649         strncpy(request.data.dsgetdcname.domain_name, domain,
650                 sizeof(request.data.dsgetdcname.domain_name)-1);
651
652         request.flags = flags;
653
654         dc = (struct wbcDomainControllerInfo *)wbcAllocateMemory(
655                  1, sizeof(struct wbcDomainControllerInfo),
656                 wbcDomainControllerInfoDestructor);
657         BAIL_ON_PTR_ERROR(dc, wbc_status);
658
659         /* Send request */
660
661         wbc_status = wbcRequestResponse(ctx, WINBINDD_DSGETDCNAME,
662                                         &request,
663                                         &response);
664         BAIL_ON_WBC_ERROR(wbc_status);
665
666         dc->dc_name = strdup(response.data.dsgetdcname.dc_unc);
667         BAIL_ON_PTR_ERROR(dc->dc_name, wbc_status);
668
669         *dc_info = dc;
670         dc = NULL;
671
672 done:
673         wbcFreeMemory(dc);
674         return wbc_status;
675 }
676
677 wbcErr wbcLookupDomainController(const char *domain, uint32_t flags,
678                                  struct wbcDomainControllerInfo **dc_info)
679 {
680         return wbcCtxLookupDomainController(NULL, domain, flags, dc_info);
681 }
682
683 static void wbcDomainControllerInfoExDestructor(void *ptr)
684 {
685         struct wbcDomainControllerInfoEx *i =
686                 (struct wbcDomainControllerInfoEx *)ptr;
687         free(discard_const_p(char, i->dc_unc));
688         free(discard_const_p(char, i->dc_address));
689         free(discard_const_p(char, i->domain_guid));
690         free(discard_const_p(char, i->domain_name));
691         free(discard_const_p(char, i->forest_name));
692         free(discard_const_p(char, i->dc_site_name));
693         free(discard_const_p(char, i->client_site_name));
694 }
695
696 static wbcErr wbc_create_domain_controller_info_ex(const struct winbindd_response *resp,
697                                                    struct wbcDomainControllerInfoEx **_i)
698 {
699         wbcErr wbc_status = WBC_ERR_SUCCESS;
700         struct wbcDomainControllerInfoEx *i;
701         struct wbcGuid guid;
702
703         i = (struct wbcDomainControllerInfoEx *)wbcAllocateMemory(
704                 1, sizeof(struct wbcDomainControllerInfoEx),
705                 wbcDomainControllerInfoExDestructor);
706         BAIL_ON_PTR_ERROR(i, wbc_status);
707
708         i->dc_unc = strdup(resp->data.dsgetdcname.dc_unc);
709         BAIL_ON_PTR_ERROR(i->dc_unc, wbc_status);
710
711         i->dc_address = strdup(resp->data.dsgetdcname.dc_address);
712         BAIL_ON_PTR_ERROR(i->dc_address, wbc_status);
713
714         i->dc_address_type = resp->data.dsgetdcname.dc_address_type;
715
716         wbc_status = wbcStringToGuid(resp->data.dsgetdcname.domain_guid, &guid);
717         if (WBC_ERROR_IS_OK(wbc_status)) {
718                 i->domain_guid = (struct wbcGuid *)malloc(
719                         sizeof(struct wbcGuid));
720                 BAIL_ON_PTR_ERROR(i->domain_guid, wbc_status);
721
722                 *i->domain_guid = guid;
723         }
724
725         i->domain_name = strdup(resp->data.dsgetdcname.domain_name);
726         BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
727
728         if (resp->data.dsgetdcname.forest_name[0] != '\0') {
729                 i->forest_name = strdup(resp->data.dsgetdcname.forest_name);
730                 BAIL_ON_PTR_ERROR(i->forest_name, wbc_status);
731         }
732
733         i->dc_flags = resp->data.dsgetdcname.dc_flags;
734
735         if (resp->data.dsgetdcname.dc_site_name[0] != '\0') {
736                 i->dc_site_name = strdup(resp->data.dsgetdcname.dc_site_name);
737                 BAIL_ON_PTR_ERROR(i->dc_site_name, wbc_status);
738         }
739
740         if (resp->data.dsgetdcname.client_site_name[0] != '\0') {
741                 i->client_site_name = strdup(
742                         resp->data.dsgetdcname.client_site_name);
743                 BAIL_ON_PTR_ERROR(i->client_site_name, wbc_status);
744         }
745
746         *_i = i;
747         i = NULL;
748
749 done:
750         if (i != NULL) {
751                 wbcFreeMemory(i);
752         }
753         return wbc_status;
754 }
755
756 /* Get extended domain controller information */
757 wbcErr wbcCtxLookupDomainControllerEx(struct wbcContext *ctx,
758                                       const char *domain,
759                                       struct wbcGuid *guid,
760                                       const char *site,
761                                       uint32_t flags,
762                                       struct wbcDomainControllerInfoEx **dc_info)
763 {
764         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
765         struct winbindd_request request;
766         struct winbindd_response response;
767
768         /* validate input params */
769
770         if (!domain || !dc_info) {
771                 wbc_status = WBC_ERR_INVALID_PARAM;
772                 BAIL_ON_WBC_ERROR(wbc_status);
773         }
774
775         ZERO_STRUCT(request);
776         ZERO_STRUCT(response);
777
778         request.data.dsgetdcname.flags = flags;
779
780         strncpy(request.data.dsgetdcname.domain_name, domain,
781                 sizeof(request.data.dsgetdcname.domain_name)-1);
782
783         if (site) {
784                 strncpy(request.data.dsgetdcname.site_name, site,
785                         sizeof(request.data.dsgetdcname.site_name)-1);
786         }
787
788         if (guid) {
789                 char *str = NULL;
790
791                 wbc_status = wbcGuidToString(guid, &str);
792                 BAIL_ON_WBC_ERROR(wbc_status);
793
794                 strncpy(request.data.dsgetdcname.domain_guid, str,
795                         sizeof(request.data.dsgetdcname.domain_guid)-1);
796
797                 wbcFreeMemory(str);
798         }
799
800         /* Send request */
801
802         wbc_status = wbcRequestResponse(ctx, WINBINDD_DSGETDCNAME,
803                                         &request,
804                                         &response);
805         BAIL_ON_WBC_ERROR(wbc_status);
806
807         if (dc_info) {
808                 wbc_status = wbc_create_domain_controller_info_ex(&response,
809                                                                   dc_info);
810                 BAIL_ON_WBC_ERROR(wbc_status);
811         }
812
813         wbc_status = WBC_ERR_SUCCESS;
814 done:
815         return wbc_status;
816 }
817
818 wbcErr wbcLookupDomainControllerEx(const char *domain,
819                                    struct wbcGuid *guid,
820                                    const char *site,
821                                    uint32_t flags,
822                                    struct wbcDomainControllerInfoEx **dc_info)
823 {
824         return wbcCtxLookupDomainControllerEx(NULL, domain, guid, site,
825                                               flags, dc_info);
826 }
827
828 static void wbcNamedBlobDestructor(void *ptr)
829 {
830         struct wbcNamedBlob *b = (struct wbcNamedBlob *)ptr;
831
832         while (b->name != NULL) {
833                 free(discard_const_p(char, b->name));
834                 free(b->blob.data);
835                 b += 1;
836         }
837 }
838
839 /* Initialize a named blob and add to list of blobs */
840 wbcErr wbcAddNamedBlob(size_t *num_blobs,
841                        struct wbcNamedBlob **pblobs,
842                        const char *name,
843                        uint32_t flags,
844                        uint8_t *data,
845                        size_t length)
846 {
847         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
848         struct wbcNamedBlob *blobs, *blob;
849
850         if (name == NULL) {
851                 return WBC_ERR_INVALID_PARAM;
852         }
853
854         /*
855          * Overallocate the b->name==NULL terminator for
856          * wbcNamedBlobDestructor
857          */
858         blobs = (struct wbcNamedBlob *)wbcAllocateMemory(
859                 *num_blobs + 2, sizeof(struct wbcNamedBlob),
860                 wbcNamedBlobDestructor);
861
862         if (blobs == NULL) {
863                 return WBC_ERR_NO_MEMORY;
864         }
865
866         if (*pblobs != NULL) {
867                 struct wbcNamedBlob *old = *pblobs;
868                 memcpy(blobs, old, sizeof(struct wbcNamedBlob) * (*num_blobs));
869                 if (*num_blobs != 0) {
870                         /* end indicator for wbcNamedBlobDestructor */
871                         old[0].name = NULL;
872                 }
873                 wbcFreeMemory(old);
874         }
875         *pblobs = blobs;
876
877         blob = &blobs[*num_blobs];
878
879         blob->name = strdup(name);
880         BAIL_ON_PTR_ERROR(blob->name, wbc_status);
881         blob->flags = flags;
882
883         blob->blob.length = length;
884         blob->blob.data = (uint8_t *)malloc(length);
885         BAIL_ON_PTR_ERROR(blob->blob.data, wbc_status);
886         memcpy(blob->blob.data, data, length);
887
888         *num_blobs += 1;
889         *pblobs = blobs;
890         blobs = NULL;
891
892         wbc_status = WBC_ERR_SUCCESS;
893 done:
894         wbcFreeMemory(blobs);
895         return wbc_status;
896 }