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