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