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