s3:libwbclient: Fix bug 6349, initialize domain info struct
[samba.git] / nsswitch / libwbclient / wbc_util.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Winbind client API
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
28
29
30 /** @brief Ping winbindd to see if the daemon is running
31  *
32  * @return #wbcErr
33  **/
34
35 wbcErr wbcPing(void)
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(WINBINDD_PING, &request, &response);
46 }
47
48 wbcErr wbcInterfaceDetails(struct wbcInterfaceDetails **_details)
49 {
50         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
51         struct wbcInterfaceDetails *info;
52         struct wbcDomainInfo *domain = NULL;
53         struct winbindd_request request;
54         struct winbindd_response response;
55
56         /* Initialize request */
57
58         ZERO_STRUCT(request);
59         ZERO_STRUCT(response);
60
61         info = talloc(NULL, struct wbcInterfaceDetails);
62         BAIL_ON_PTR_ERROR(info, wbc_status);
63
64         /* first the interface version */
65         wbc_status = wbcRequestResponse(WINBINDD_INTERFACE_VERSION, NULL, &response);
66         BAIL_ON_WBC_ERROR(wbc_status);
67         info->interface_version = response.data.interface_version;
68
69         /* then the samba version and the winbind separator */
70         wbc_status = wbcRequestResponse(WINBINDD_INFO, NULL, &response);
71         BAIL_ON_WBC_ERROR(wbc_status);
72
73         info->winbind_version = talloc_strdup(info,
74                                               response.data.info.samba_version);
75         BAIL_ON_PTR_ERROR(info->winbind_version, wbc_status);
76         info->winbind_separator = response.data.info.winbind_separator;
77
78         /* then the local netbios name */
79         wbc_status = wbcRequestResponse(WINBINDD_NETBIOS_NAME, NULL, &response);
80         BAIL_ON_WBC_ERROR(wbc_status);
81
82         info->netbios_name = talloc_strdup(info,
83                                            response.data.netbios_name);
84         BAIL_ON_PTR_ERROR(info->netbios_name, wbc_status);
85
86         /* then the local workgroup name */
87         wbc_status = wbcRequestResponse(WINBINDD_DOMAIN_NAME, NULL, &response);
88         BAIL_ON_WBC_ERROR(wbc_status);
89
90         info->netbios_domain = talloc_strdup(info,
91                                         response.data.domain_name);
92         BAIL_ON_PTR_ERROR(info->netbios_domain, wbc_status);
93
94         wbc_status = wbcDomainInfo(info->netbios_domain, &domain);
95         if (wbc_status == WBC_ERR_DOMAIN_NOT_FOUND) {
96                 /* maybe it's a standalone server */
97                 domain = NULL;
98                 wbc_status = WBC_ERR_SUCCESS;
99         } else {
100                 BAIL_ON_WBC_ERROR(wbc_status);
101         }
102
103         if (domain) {
104                 info->dns_domain = talloc_strdup(info,
105                                                  domain->dns_name);
106                 wbcFreeMemory(domain);
107                 BAIL_ON_PTR_ERROR(info->dns_domain, wbc_status);
108         } else {
109                 info->dns_domain = NULL;
110         }
111
112         *_details = info;
113         info = NULL;
114
115         wbc_status = WBC_ERR_SUCCESS;
116
117 done:
118         talloc_free(info);
119         return wbc_status;
120 }
121
122
123 /* Lookup the current status of a trusted domain */
124 wbcErr wbcDomainInfo(const char *domain, struct wbcDomainInfo **dinfo)
125 {
126         struct winbindd_request request;
127         struct winbindd_response response;
128         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
129         struct wbcDomainInfo *info = NULL;
130
131         if (!domain || !dinfo) {
132                 wbc_status = WBC_ERR_INVALID_PARAM;
133                 BAIL_ON_WBC_ERROR(wbc_status);
134         }
135
136         /* Initialize request */
137
138         ZERO_STRUCT(request);
139         ZERO_STRUCT(response);
140
141         strncpy(request.domain_name, domain,
142                 sizeof(request.domain_name)-1);
143
144         wbc_status = wbcRequestResponse(WINBINDD_DOMAIN_INFO,
145                                         &request,
146                                         &response);
147         BAIL_ON_WBC_ERROR(wbc_status);
148
149         info = talloc(NULL, struct wbcDomainInfo);
150         BAIL_ON_PTR_ERROR(info, wbc_status);
151
152         info->short_name = talloc_strdup(info,
153                                          response.data.domain_info.name);
154         BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
155
156         info->dns_name = talloc_strdup(info,
157                                        response.data.domain_info.alt_name);
158         BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
159
160         wbc_status = wbcStringToSid(response.data.domain_info.sid,
161                                     &info->sid);
162         BAIL_ON_WBC_ERROR(wbc_status);
163
164         if (response.data.domain_info.native_mode)
165                 info->domain_flags |= WBC_DOMINFO_DOMAIN_NATIVE;
166         if (response.data.domain_info.active_directory)
167                 info->domain_flags |= WBC_DOMINFO_DOMAIN_AD;
168         if (response.data.domain_info.primary)
169                 info->domain_flags |= WBC_DOMINFO_DOMAIN_PRIMARY;
170
171         *dinfo = info;
172
173         wbc_status = WBC_ERR_SUCCESS;
174
175  done:
176         if (!WBC_ERROR_IS_OK(wbc_status)) {
177                 talloc_free(info);
178         }
179
180         return wbc_status;
181 }
182
183
184 /* Resolve a NetbiosName via WINS */
185 wbcErr wbcResolveWinsByName(const char *name, char **ip)
186 {
187         struct winbindd_request request;
188         struct winbindd_response response;
189         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
190         char *ipaddr;
191
192         ZERO_STRUCT(request);
193         ZERO_STRUCT(response);
194
195         /* Send request */
196
197         strncpy(request.data.winsreq, name,
198                 sizeof(request.data.winsreq)-1);
199
200         wbc_status = wbcRequestResponse(WINBINDD_WINS_BYNAME,
201                                         &request,
202                                         &response);
203         BAIL_ON_WBC_ERROR(wbc_status);
204
205         /* Display response */
206
207         ipaddr = talloc_strdup(NULL, response.data.winsresp);
208         BAIL_ON_PTR_ERROR(ipaddr, wbc_status);
209
210         *ip = ipaddr;
211         wbc_status = WBC_ERR_SUCCESS;
212
213  done:
214         return wbc_status;
215 }
216
217 /* Resolve an IP address via WINS into a NetbiosName */
218 wbcErr wbcResolveWinsByIP(const char *ip, char **name)
219 {
220         struct winbindd_request request;
221         struct winbindd_response response;
222         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
223         char *name_str;
224
225         ZERO_STRUCT(request);
226         ZERO_STRUCT(response);
227
228         /* Send request */
229
230         strncpy(request.data.winsreq, ip,
231                 sizeof(request.data.winsreq)-1);
232
233         wbc_status = wbcRequestResponse(WINBINDD_WINS_BYIP,
234                                         &request,
235                                         &response);
236         BAIL_ON_WBC_ERROR(wbc_status);
237
238         /* Display response */
239
240         name_str = talloc_strdup(NULL, response.data.winsresp);
241         BAIL_ON_PTR_ERROR(name_str, wbc_status);
242
243         *name = name_str;
244         wbc_status = WBC_ERR_SUCCESS;
245
246  done:
247         return wbc_status;
248 }
249
250 /**
251  */
252
253 static wbcErr process_domain_info_string(TALLOC_CTX *ctx,
254                                          struct wbcDomainInfo *info,
255                                          char *info_string)
256 {
257         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
258         char *r = NULL;
259         char *s = NULL;
260
261         if (!info || !info_string) {
262                 wbc_status = WBC_ERR_INVALID_PARAM;
263                 BAIL_ON_WBC_ERROR(wbc_status);
264         }
265
266         ZERO_STRUCTP(info);
267
268         r = info_string;
269
270         /* Short Name */
271         if ((s = strchr(r, '\\')) == NULL) {
272                 wbc_status = WBC_ERR_INVALID_RESPONSE;
273                 BAIL_ON_WBC_ERROR(wbc_status);
274         }
275         *s = '\0';
276         s++;
277
278         info->short_name = talloc_strdup(ctx, r);
279         BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
280
281
282         /* DNS Name */
283         r = s;
284         if ((s = strchr(r, '\\')) == NULL) {
285                 wbc_status = WBC_ERR_INVALID_RESPONSE;
286                 BAIL_ON_WBC_ERROR(wbc_status);
287         }
288         *s = '\0';
289         s++;
290
291         info->dns_name = talloc_strdup(ctx, r);
292         BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
293
294         /* SID */
295         r = s;
296         if ((s = strchr(r, '\\')) == NULL) {
297                 wbc_status = WBC_ERR_INVALID_RESPONSE;
298                 BAIL_ON_WBC_ERROR(wbc_status);
299         }
300         *s = '\0';
301         s++;
302
303         wbc_status = wbcStringToSid(r, &info->sid);
304         BAIL_ON_WBC_ERROR(wbc_status);
305
306         /* Trust type */
307         r = s;
308         if ((s = strchr(r, '\\')) == NULL) {
309                 wbc_status = WBC_ERR_INVALID_RESPONSE;
310                 BAIL_ON_WBC_ERROR(wbc_status);
311         }
312         *s = '\0';
313         s++;
314
315         if (strcmp(r, "None") == 0) {
316                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_NONE;
317         } else if (strcmp(r, "External") == 0) {
318                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_EXTERNAL;
319         } else if (strcmp(r, "Forest") == 0) {
320                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_FOREST;
321         } else if (strcmp(r, "In Forest") == 0) {
322                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_IN_FOREST;
323         } else {
324                 wbc_status = WBC_ERR_INVALID_RESPONSE;
325                 BAIL_ON_WBC_ERROR(wbc_status);
326         }
327
328         /* Transitive */
329         r = s;
330         if ((s = strchr(r, '\\')) == NULL) {
331                 wbc_status = WBC_ERR_INVALID_RESPONSE;
332                 BAIL_ON_WBC_ERROR(wbc_status);
333         }
334         *s = '\0';
335         s++;
336
337         if (strcmp(r, "Yes") == 0) {
338                 info->trust_flags |= WBC_DOMINFO_TRUST_TRANSITIVE;
339         }
340
341         /* Incoming */
342         r = s;
343         if ((s = strchr(r, '\\')) == NULL) {
344                 wbc_status = WBC_ERR_INVALID_RESPONSE;
345                 BAIL_ON_WBC_ERROR(wbc_status);
346         }
347         *s = '\0';
348         s++;
349
350         if (strcmp(r, "Yes") == 0) {
351                 info->trust_flags |= WBC_DOMINFO_TRUST_INCOMING;
352         }
353
354         /* Outgoing */
355         r = s;
356         if ((s = strchr(r, '\\')) == NULL) {
357                 wbc_status = WBC_ERR_INVALID_RESPONSE;
358                 BAIL_ON_WBC_ERROR(wbc_status);
359         }
360         *s = '\0';
361         s++;
362
363         if (strcmp(r, "Yes") == 0) {
364                 info->trust_flags |= WBC_DOMINFO_TRUST_OUTGOING;
365         }
366
367         /* Online/Offline status */
368
369         r = s;
370         if (r == NULL) {
371                 wbc_status = WBC_ERR_INVALID_RESPONSE;
372                 BAIL_ON_WBC_ERROR(wbc_status);
373         }
374         if ( strcmp(r, "Offline") == 0) {
375                 info->domain_flags |= WBC_DOMINFO_DOMAIN_OFFLINE;
376         }
377
378         wbc_status = WBC_ERR_SUCCESS;
379
380  done:
381         return wbc_status;
382 }
383
384 /* Enumerate the domain trusts known by Winbind */
385 wbcErr wbcListTrusts(struct wbcDomainInfo **domains, size_t *num_domains)
386 {
387         struct winbindd_response response;
388         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
389         char *p = NULL;
390         char *q = NULL;
391         char *extra_data = NULL;
392         int count = 0;
393         struct wbcDomainInfo *d_list = NULL;
394         int i = 0;
395
396         *domains = NULL;
397         *num_domains = 0;
398
399         ZERO_STRUCT(response);
400
401         /* Send request */
402
403         wbc_status = wbcRequestResponse(WINBINDD_LIST_TRUSTDOM,
404                                         NULL,
405                                         &response);
406         BAIL_ON_WBC_ERROR(wbc_status);
407
408         /* Decode the response */
409
410         p = (char *)response.extra_data.data;
411
412         if ((p == NULL) || (strlen(p) == 0)) {
413                 /* We should always at least get back our
414                    own SAM domain */
415
416                 wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
417                 BAIL_ON_WBC_ERROR(wbc_status);
418         }
419
420         /* Count number of domains */
421
422         count = 0;
423         while (p) {
424                 count++;
425
426                 if ((q = strchr(p, '\n')) != NULL)
427                         q++;
428                 p = q;
429         }
430
431         d_list = talloc_array(NULL, struct wbcDomainInfo, count);
432         BAIL_ON_PTR_ERROR(d_list, wbc_status);
433
434         extra_data = strdup((char*)response.extra_data.data);
435         BAIL_ON_PTR_ERROR(extra_data, wbc_status);
436
437         p = extra_data;
438
439         /* Outer loop processes the list of domain information */
440
441         for (i=0; i<count && p; i++) {
442                 char *next = strchr(p, '\n');
443
444                 if (next) {
445                         *next = '\0';
446                         next++;
447                 }
448
449                 wbc_status = process_domain_info_string(d_list, &d_list[i], p);
450                 BAIL_ON_WBC_ERROR(wbc_status);
451
452                 p = next;
453         }
454
455         *domains = d_list;
456         *num_domains = i;
457
458  done:
459         if (!WBC_ERROR_IS_OK(wbc_status)) {
460                 if (d_list)
461                         talloc_free(d_list);
462                 if (extra_data)
463                         free(extra_data);
464         }
465
466         return wbc_status;
467 }
468
469 /* Enumerate the domain trusts known by Winbind */
470 wbcErr wbcLookupDomainController(const char *domain,
471                                  uint32_t flags,
472                                 struct wbcDomainControllerInfo **dc_info)
473 {
474         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
475         struct winbindd_request request;
476         struct winbindd_response response;
477         struct wbcDomainControllerInfo *dc = NULL;
478
479         /* validate input params */
480
481         if (!domain || !dc_info) {
482                 wbc_status = WBC_ERR_INVALID_PARAM;
483                 BAIL_ON_WBC_ERROR(wbc_status);
484         }
485
486         ZERO_STRUCT(request);
487         ZERO_STRUCT(response);
488
489         strncpy(request.domain_name, domain, sizeof(request.domain_name)-1);
490
491         request.flags = flags;
492
493         dc = talloc(NULL, struct wbcDomainControllerInfo);
494         BAIL_ON_PTR_ERROR(dc, wbc_status);
495
496         /* Send request */
497
498         wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
499                                         &request,
500                                         &response);
501         BAIL_ON_WBC_ERROR(wbc_status);
502
503         dc->dc_name = talloc_strdup(dc, response.data.dc_name);
504         BAIL_ON_PTR_ERROR(dc->dc_name, wbc_status);
505
506         *dc_info = dc;
507
508 done:
509         if (!WBC_ERROR_IS_OK(wbc_status)) {
510                 talloc_free(dc);
511         }
512
513         return wbc_status;
514 }
515
516 static wbcErr wbc_create_domain_controller_info_ex(TALLOC_CTX *mem_ctx,
517                                                    const struct winbindd_response *resp,
518                                                    struct wbcDomainControllerInfoEx **_i)
519 {
520         wbcErr wbc_status = WBC_ERR_SUCCESS;
521         struct wbcDomainControllerInfoEx *i;
522         struct wbcGuid guid;
523
524         i = talloc(mem_ctx, struct wbcDomainControllerInfoEx);
525         BAIL_ON_PTR_ERROR(i, wbc_status);
526
527         i->dc_unc = talloc_strdup(i, resp->data.dsgetdcname.dc_unc);
528         BAIL_ON_PTR_ERROR(i->dc_unc, wbc_status);
529
530         i->dc_address = talloc_strdup(i, resp->data.dsgetdcname.dc_address);
531         BAIL_ON_PTR_ERROR(i->dc_address, wbc_status);
532
533         i->dc_address_type = resp->data.dsgetdcname.dc_address_type;
534
535         wbc_status = wbcStringToGuid(resp->data.dsgetdcname.domain_guid, &guid);
536         if (WBC_ERROR_IS_OK(wbc_status)) {
537                 i->domain_guid = talloc(i, struct wbcGuid);
538                 BAIL_ON_PTR_ERROR(i->domain_guid, wbc_status);
539
540                 *i->domain_guid = guid;
541         } else {
542                 i->domain_guid = NULL;
543         }
544
545         i->domain_name = talloc_strdup(i, resp->data.dsgetdcname.domain_name);
546         BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
547
548         if (resp->data.dsgetdcname.forest_name[0] != '\0') {
549                 i->forest_name = talloc_strdup(i,
550                         resp->data.dsgetdcname.forest_name);
551                 BAIL_ON_PTR_ERROR(i->forest_name, wbc_status);
552         } else {
553                 i->forest_name = NULL;
554         }
555
556         i->dc_flags = resp->data.dsgetdcname.dc_flags;
557
558         if (resp->data.dsgetdcname.dc_site_name[0] != '\0') {
559                 i->dc_site_name = talloc_strdup(i,
560                         resp->data.dsgetdcname.dc_site_name);
561                 BAIL_ON_PTR_ERROR(i->dc_site_name, wbc_status);
562         } else {
563                 i->dc_site_name = NULL;
564         }
565
566         if (resp->data.dsgetdcname.client_site_name[0] != '\0') {
567                 i->client_site_name = talloc_strdup(i,
568                         resp->data.dsgetdcname.client_site_name);
569                 BAIL_ON_PTR_ERROR(i->client_site_name, wbc_status);
570         } else {
571                 i->client_site_name = NULL;
572         }
573
574         *_i = i;
575         i = NULL;
576
577 done:
578         talloc_free(i);
579         return wbc_status;
580 }
581
582 /* Get extended domain controller information */
583 wbcErr wbcLookupDomainControllerEx(const char *domain,
584                                    struct wbcGuid *guid,
585                                    const char *site,
586                                    uint32_t flags,
587                                    struct wbcDomainControllerInfoEx **dc_info)
588 {
589         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
590         struct winbindd_request request;
591         struct winbindd_response response;
592
593         /* validate input params */
594
595         if (!domain || !dc_info) {
596                 wbc_status = WBC_ERR_INVALID_PARAM;
597                 BAIL_ON_WBC_ERROR(wbc_status);
598         }
599
600         ZERO_STRUCT(request);
601         ZERO_STRUCT(response);
602
603         request.data.dsgetdcname.flags = flags;
604
605         strncpy(request.data.dsgetdcname.domain_name, domain,
606                 sizeof(request.data.dsgetdcname.domain_name)-1);
607
608         if (site) {
609                 strncpy(request.data.dsgetdcname.site_name, site,
610                         sizeof(request.data.dsgetdcname.site_name)-1);
611         }
612
613         if (guid) {
614                 char *str = NULL;
615
616                 wbc_status = wbcGuidToString(guid, &str);
617                 BAIL_ON_WBC_ERROR(wbc_status);
618
619                 strncpy(request.data.dsgetdcname.domain_guid, str,
620                         sizeof(request.data.dsgetdcname.domain_guid)-1);
621
622                 wbcFreeMemory(str);
623         }
624
625         /* Send request */
626
627         wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
628                                         &request,
629                                         &response);
630         BAIL_ON_WBC_ERROR(wbc_status);
631
632         if (dc_info) {
633                 wbc_status = wbc_create_domain_controller_info_ex(NULL,
634                                                                   &response,
635                                                                   dc_info);
636                 BAIL_ON_WBC_ERROR(wbc_status);
637         }
638
639         wbc_status = WBC_ERR_SUCCESS;
640 done:
641         return wbc_status;
642 }
643
644 /* Initialize a named blob and add to list of blobs */
645 wbcErr wbcAddNamedBlob(size_t *num_blobs,
646                        struct wbcNamedBlob **blobs,
647                        const char *name,
648                        uint32_t flags,
649                        uint8_t *data,
650                        size_t length)
651 {
652         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
653         struct wbcNamedBlob blob;
654
655         *blobs = talloc_realloc(NULL, *blobs, struct wbcNamedBlob,
656                                 *(num_blobs)+1);
657         BAIL_ON_PTR_ERROR(*blobs, wbc_status);
658
659         blob.name               = talloc_strdup(*blobs, name);
660         BAIL_ON_PTR_ERROR(blob.name, wbc_status);
661         blob.flags              = flags;
662         blob.blob.length        = length;
663         blob.blob.data          = (uint8_t *)talloc_memdup(*blobs, data, length);
664         BAIL_ON_PTR_ERROR(blob.blob.data, wbc_status);
665
666         (*(blobs))[*num_blobs] = blob;
667         *(num_blobs) += 1;
668
669         wbc_status = WBC_ERR_SUCCESS;
670 done:
671         if (!WBC_ERROR_IS_OK(wbc_status) && blobs) {
672                 wbcFreeMemory(*blobs);
673         }
674         return wbc_status;
675 }