fcb7671d8388c7c45d8a205ef98621241071d6b8
[metze/samba/wip.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         r = info_string;
267
268         /* Short Name */
269         if ((s = strchr(r, '\\')) == NULL) {
270                 wbc_status = WBC_ERR_INVALID_RESPONSE;
271                 BAIL_ON_WBC_ERROR(wbc_status);
272         }
273         *s = '\0';
274         s++;
275
276         info->short_name = talloc_strdup(ctx, r);
277         BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
278
279
280         /* DNS Name */
281         r = s;
282         if ((s = strchr(r, '\\')) == NULL) {
283                 wbc_status = WBC_ERR_INVALID_RESPONSE;
284                 BAIL_ON_WBC_ERROR(wbc_status);
285         }
286         *s = '\0';
287         s++;
288
289         info->dns_name = talloc_strdup(ctx, r);
290         BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
291
292         /* SID */
293         r = s;
294         if ((s = strchr(r, '\\')) == NULL) {
295                 wbc_status = WBC_ERR_INVALID_RESPONSE;
296                 BAIL_ON_WBC_ERROR(wbc_status);
297         }
298         *s = '\0';
299         s++;
300
301         wbc_status = wbcStringToSid(r, &info->sid);
302         BAIL_ON_WBC_ERROR(wbc_status);
303
304         /* Trust type */
305         r = s;
306         if ((s = strchr(r, '\\')) == NULL) {
307                 wbc_status = WBC_ERR_INVALID_RESPONSE;
308                 BAIL_ON_WBC_ERROR(wbc_status);
309         }
310         *s = '\0';
311         s++;
312
313         if (strcmp(r, "None") == 0) {
314                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_NONE;
315         } else if (strcmp(r, "External") == 0) {
316                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_EXTERNAL;
317         } else if (strcmp(r, "Forest") == 0) {
318                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_FOREST;
319         } else if (strcmp(r, "In Forest") == 0) {
320                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_IN_FOREST;
321         } else {
322                 wbc_status = WBC_ERR_INVALID_RESPONSE;
323                 BAIL_ON_WBC_ERROR(wbc_status);
324         }
325
326         /* Transitive */
327         r = s;
328         if ((s = strchr(r, '\\')) == NULL) {
329                 wbc_status = WBC_ERR_INVALID_RESPONSE;
330                 BAIL_ON_WBC_ERROR(wbc_status);
331         }
332         *s = '\0';
333         s++;
334
335         if (strcmp(r, "Yes") == 0) {
336                 info->trust_flags |= WBC_DOMINFO_TRUST_TRANSITIVE;
337         }
338
339         /* Incoming */
340         r = s;
341         if ((s = strchr(r, '\\')) == NULL) {
342                 wbc_status = WBC_ERR_INVALID_RESPONSE;
343                 BAIL_ON_WBC_ERROR(wbc_status);
344         }
345         *s = '\0';
346         s++;
347
348         if (strcmp(r, "Yes") == 0) {
349                 info->trust_flags |= WBC_DOMINFO_TRUST_INCOMING;
350         }
351
352         /* Outgoing */
353         r = s;
354         if ((s = strchr(r, '\\')) == NULL) {
355                 wbc_status = WBC_ERR_INVALID_RESPONSE;
356                 BAIL_ON_WBC_ERROR(wbc_status);
357         }
358         *s = '\0';
359         s++;
360
361         if (strcmp(r, "Yes") == 0) {
362                 info->trust_flags |= WBC_DOMINFO_TRUST_OUTGOING;
363         }
364
365         /* Online/Offline status */
366
367         r = s;
368         if (r == NULL) {
369                 wbc_status = WBC_ERR_INVALID_RESPONSE;
370                 BAIL_ON_WBC_ERROR(wbc_status);
371         }
372         if ( strcmp(r, "Offline") == 0) {
373                 info->domain_flags |= WBC_DOMINFO_DOMAIN_OFFLINE;
374         }
375
376         wbc_status = WBC_ERR_SUCCESS;
377
378  done:
379         return wbc_status;
380 }
381
382 /* Enumerate the domain trusts known by Winbind */
383 wbcErr wbcListTrusts(struct wbcDomainInfo **domains, size_t *num_domains)
384 {
385         struct winbindd_response response;
386         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
387         char *p = NULL;
388         char *q = NULL;
389         char *extra_data = NULL;
390         int count = 0;
391         struct wbcDomainInfo *d_list = NULL;
392         int i = 0;
393
394         *domains = NULL;
395         *num_domains = 0;
396
397         ZERO_STRUCT(response);
398
399         /* Send request */
400
401         wbc_status = wbcRequestResponse(WINBINDD_LIST_TRUSTDOM,
402                                         NULL,
403                                         &response);
404         BAIL_ON_WBC_ERROR(wbc_status);
405
406         /* Decode the response */
407
408         p = (char *)response.extra_data.data;
409
410         if (strlen(p) == 0) {
411                 /* We should always at least get back our
412                    own SAM domain */
413
414                 wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
415                 BAIL_ON_WBC_ERROR(wbc_status);
416         }
417
418         /* Count number of domains */
419
420         count = 0;
421         while (p) {
422                 count++;
423
424                 if ((q = strchr(p, '\n')) != NULL)
425                         q++;
426                 p = q;
427         }
428
429         d_list = talloc_array(NULL, struct wbcDomainInfo, count);
430         BAIL_ON_PTR_ERROR(d_list, wbc_status);
431
432         extra_data = strdup((char*)response.extra_data.data);
433         BAIL_ON_PTR_ERROR(extra_data, wbc_status);
434
435         p = extra_data;
436
437         /* Outer loop processes the list of domain information */
438
439         for (i=0; i<count && p; i++) {
440                 char *next = strchr(p, '\n');
441
442                 if (next) {
443                         *next = '\0';
444                         next++;
445                 }
446
447                 wbc_status = process_domain_info_string(d_list, &d_list[i], p);
448                 BAIL_ON_WBC_ERROR(wbc_status);
449
450                 p = next;
451         }
452
453         *domains = d_list;
454         *num_domains = i;
455
456  done:
457         if (!WBC_ERROR_IS_OK(wbc_status)) {
458                 if (d_list)
459                         talloc_free(d_list);
460                 if (extra_data)
461                         free(extra_data);
462         }
463
464         return wbc_status;
465 }
466
467 /* Enumerate the domain trusts known by Winbind */
468 wbcErr wbcLookupDomainController(const char *domain,
469                                  uint32_t flags,
470                                 struct wbcDomainControllerInfo **dc_info)
471 {
472         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
473         struct winbindd_request request;
474         struct winbindd_response response;
475         struct wbcDomainControllerInfo *dc = NULL;
476
477         /* validate input params */
478
479         if (!domain || !dc_info) {
480                 wbc_status = WBC_ERR_INVALID_PARAM;
481                 BAIL_ON_WBC_ERROR(wbc_status);
482         }
483
484         ZERO_STRUCT(request);
485         ZERO_STRUCT(response);
486
487         strncpy(request.domain_name, domain, sizeof(request.domain_name)-1);
488
489         request.flags = flags;
490
491         dc = talloc(NULL, struct wbcDomainControllerInfo);
492         BAIL_ON_PTR_ERROR(dc, wbc_status);
493
494         /* Send request */
495
496         wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
497                                         &request,
498                                         &response);
499         BAIL_ON_WBC_ERROR(wbc_status);
500
501         dc->dc_name = talloc_strdup(dc, response.data.dc_name);
502         BAIL_ON_PTR_ERROR(dc->dc_name, wbc_status);
503
504         *dc_info = dc;
505
506 done:
507         if (!WBC_ERROR_IS_OK(wbc_status)) {
508                 talloc_free(dc);
509         }
510
511         return wbc_status;
512 }
513
514 static wbcErr wbc_create_domain_controller_info_ex(TALLOC_CTX *mem_ctx,
515                                                    const struct winbindd_response *resp,
516                                                    struct wbcDomainControllerInfoEx **_i)
517 {
518         wbcErr wbc_status = WBC_ERR_SUCCESS;
519         struct wbcDomainControllerInfoEx *i;
520         struct wbcGuid guid;
521
522         i = talloc(mem_ctx, struct wbcDomainControllerInfoEx);
523         BAIL_ON_PTR_ERROR(i, wbc_status);
524
525         i->dc_unc = talloc_strdup(i, resp->data.dsgetdcname.dc_unc);
526         BAIL_ON_PTR_ERROR(i->dc_unc, wbc_status);
527
528         i->dc_address = talloc_strdup(i, resp->data.dsgetdcname.dc_address);
529         BAIL_ON_PTR_ERROR(i->dc_address, wbc_status);
530
531         i->dc_address_type = resp->data.dsgetdcname.dc_address_type;
532
533         wbc_status = wbcStringToGuid(resp->data.dsgetdcname.domain_guid, &guid);
534         if (WBC_ERROR_IS_OK(wbc_status)) {
535                 i->domain_guid = talloc(i, struct wbcGuid);
536                 BAIL_ON_PTR_ERROR(i->domain_guid, wbc_status);
537
538                 *i->domain_guid = guid;
539         } else {
540                 i->domain_guid = NULL;
541         }
542
543         i->domain_name = talloc_strdup(i, resp->data.dsgetdcname.domain_name);
544         BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
545
546         if (resp->data.dsgetdcname.forest_name[0] != '\0') {
547                 i->forest_name = talloc_strdup(i,
548                         resp->data.dsgetdcname.forest_name);
549                 BAIL_ON_PTR_ERROR(i->forest_name, wbc_status);
550         } else {
551                 i->forest_name = NULL;
552         }
553
554         i->dc_flags = resp->data.dsgetdcname.dc_flags;
555
556         if (resp->data.dsgetdcname.dc_site_name[0] != '\0') {
557                 i->dc_site_name = talloc_strdup(i,
558                         resp->data.dsgetdcname.dc_site_name);
559                 BAIL_ON_PTR_ERROR(i->dc_site_name, wbc_status);
560         } else {
561                 i->dc_site_name = NULL;
562         }
563
564         if (resp->data.dsgetdcname.client_site_name[0] != '\0') {
565                 i->client_site_name = talloc_strdup(i,
566                         resp->data.dsgetdcname.client_site_name);
567                 BAIL_ON_PTR_ERROR(i->client_site_name, wbc_status);
568         } else {
569                 i->client_site_name = NULL;
570         }
571
572         *_i = i;
573         i = NULL;
574
575 done:
576         talloc_free(i);
577         return wbc_status;
578 }
579
580 /* Get extended domain controller information */
581 wbcErr wbcLookupDomainControllerEx(const char *domain,
582                                    struct wbcGuid *guid,
583                                    const char *site,
584                                    uint32_t flags,
585                                    struct wbcDomainControllerInfoEx **dc_info)
586 {
587         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
588         struct winbindd_request request;
589         struct winbindd_response response;
590
591         /* validate input params */
592
593         if (!domain || !dc_info) {
594                 wbc_status = WBC_ERR_INVALID_PARAM;
595                 BAIL_ON_WBC_ERROR(wbc_status);
596         }
597
598         ZERO_STRUCT(request);
599         ZERO_STRUCT(response);
600
601         request.data.dsgetdcname.flags = flags;
602
603         strncpy(request.data.dsgetdcname.domain_name, domain,
604                 sizeof(request.data.dsgetdcname.domain_name)-1);
605
606         if (site) {
607                 strncpy(request.data.dsgetdcname.site_name, site,
608                         sizeof(request.data.dsgetdcname.site_name)-1);
609         }
610
611         if (guid) {
612                 char *str = NULL;
613
614                 wbc_status = wbcGuidToString(guid, &str);
615                 BAIL_ON_WBC_ERROR(wbc_status);
616
617                 strncpy(request.data.dsgetdcname.domain_guid, str,
618                         sizeof(request.data.dsgetdcname.domain_guid)-1);
619
620                 wbcFreeMemory(str);
621         }
622
623         /* Send request */
624
625         wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
626                                         &request,
627                                         &response);
628         BAIL_ON_WBC_ERROR(wbc_status);
629
630         if (dc_info) {
631                 wbc_status = wbc_create_domain_controller_info_ex(NULL,
632                                                                   &response,
633                                                                   dc_info);
634                 BAIL_ON_WBC_ERROR(wbc_status);
635         }
636
637         wbc_status = WBC_ERR_SUCCESS;
638 done:
639         return wbc_status;
640 }
641
642 /* Initialize a named blob and add to list of blobs */
643 wbcErr wbcAddNamedBlob(size_t *num_blobs,
644                        struct wbcNamedBlob **blobs,
645                        const char *name,
646                        uint32_t flags,
647                        uint8_t *data,
648                        size_t length)
649 {
650         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
651         struct wbcNamedBlob blob;
652
653         *blobs = talloc_realloc(NULL, *blobs, struct wbcNamedBlob,
654                                 *(num_blobs)+1);
655         BAIL_ON_PTR_ERROR(*blobs, wbc_status);
656
657         blob.name               = talloc_strdup(*blobs, name);
658         BAIL_ON_PTR_ERROR(blob.name, wbc_status);
659         blob.flags              = flags;
660         blob.blob.length        = length;
661         blob.blob.data          = (uint8_t *)talloc_memdup(*blobs, data, length);
662         BAIL_ON_PTR_ERROR(blob.blob.data, wbc_status);
663
664         (*(blobs))[*num_blobs] = blob;
665         *(num_blobs) += 1;
666
667         wbc_status = WBC_ERR_SUCCESS;
668 done:
669         if (!WBC_ERROR_IS_OK(wbc_status) && blobs) {
670                 wbcFreeMemory(*blobs);
671         }
672         return wbc_status;
673 }