Add wbcListTrusts() API call to libwbclient.so
[ira/wip.git] / source3 / 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 /** @brief Lookup the current status of a trusted domain
123  *
124  * @param domain      Domain to query
125  * @param *dinfo       Pointer to returned domain_info struct
126  *
127  * @return #wbcErr
128  *
129  **/
130
131
132 wbcErr wbcDomainInfo(const char *domain, struct wbcDomainInfo **dinfo)
133 {
134         struct winbindd_request request;
135         struct winbindd_response response;
136         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
137         struct wbcDomainInfo *info = NULL;
138
139         if (!domain || !dinfo) {
140                 wbc_status = WBC_ERR_INVALID_PARAM;
141                 BAIL_ON_WBC_ERROR(wbc_status);
142         }
143
144         /* Initialize request */
145
146         ZERO_STRUCT(request);
147         ZERO_STRUCT(response);
148
149         strncpy(request.domain_name, domain,
150                 sizeof(request.domain_name)-1);
151
152         wbc_status = wbcRequestResponse(WINBINDD_DOMAIN_INFO,
153                                         &request,
154                                         &response);
155         BAIL_ON_WBC_ERROR(wbc_status);
156
157         info = talloc(NULL, struct wbcDomainInfo);
158         BAIL_ON_PTR_ERROR(info, wbc_status);
159
160         info->short_name = talloc_strdup(info,
161                                          response.data.domain_info.name);
162         BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
163
164         info->dns_name = talloc_strdup(info,
165                                        response.data.domain_info.alt_name);
166         BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
167
168         wbc_status = wbcStringToSid(response.data.domain_info.sid,
169                                     &info->sid);
170         BAIL_ON_WBC_ERROR(wbc_status);
171
172         if (response.data.domain_info.native_mode)
173                 info->domain_flags |= WBC_DOMINFO_NATIVE;
174         if (response.data.domain_info.active_directory)
175                 info->domain_flags |= WBC_DOMINFO_AD;
176         if (response.data.domain_info.primary)
177                 info->domain_flags |= WBC_DOMINFO_PRIMARY;
178
179         *dinfo = info;
180
181         wbc_status = WBC_ERR_SUCCESS;
182
183  done:
184         if (!WBC_ERROR_IS_OK(wbc_status)) {
185                 talloc_free(info);
186         }
187
188         return wbc_status;
189 }
190
191
192 /** @brief Resolve a NetbiosName via WINS
193  *
194  * @param name         Name to resolve
195  * @param *ip          Pointer to the ip address string
196  *
197  * @return #wbcErr
198  *
199  **/
200 wbcErr wbcResolveWinsByName(const char *name, const char **ip)
201 {
202         struct winbindd_request request;
203         struct winbindd_response response;
204         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
205         const char *ipaddr;
206
207         ZERO_STRUCT(request);
208         ZERO_STRUCT(response);
209
210         /* Send request */
211
212         strncpy(request.data.winsreq, name,
213                 sizeof(request.data.winsreq)-1);
214
215         wbc_status = wbcRequestResponse(WINBINDD_WINS_BYNAME,
216                                         &request,
217                                         &response);
218         BAIL_ON_WBC_ERROR(wbc_status);
219
220         /* Display response */
221
222         ipaddr = talloc_strdup(NULL, response.data.winsresp);
223         BAIL_ON_PTR_ERROR(ipaddr, wbc_status);
224
225         *ip = ipaddr;
226         wbc_status = WBC_ERR_SUCCESS;
227
228  done:
229         return wbc_status;
230 }
231
232 /** @brief Resolve an IP address via WINS into a NetbiosName
233  *
234  * @param ip          The ip address string
235  * @param *name       Pointer to the name
236  *
237  * @return #wbcErr
238  *
239  **/
240 wbcErr wbcResolveWinsByIP(const char *ip, const char **name)
241 {
242         struct winbindd_request request;
243         struct winbindd_response response;
244         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
245         const char *name_str;
246
247         ZERO_STRUCT(request);
248         ZERO_STRUCT(response);
249
250         /* Send request */
251
252         strncpy(request.data.winsreq, ip,
253                 sizeof(request.data.winsreq)-1);
254
255         wbc_status = wbcRequestResponse(WINBINDD_WINS_BYIP,
256                                         &request,
257                                         &response);
258         BAIL_ON_WBC_ERROR(wbc_status);
259
260         /* Display response */
261
262         name_str = talloc_strdup(NULL, response.data.winsresp);
263         BAIL_ON_PTR_ERROR(name_str, wbc_status);
264
265         *name = name_str;
266         wbc_status = WBC_ERR_SUCCESS;
267
268  done:
269         return wbc_status;
270 }
271
272 /**
273  */
274
275 static wbcErr process_domain_info_string(TALLOC_CTX *ctx, 
276                                          struct wbcDomainInfo *info,
277                                          char *info_string)
278 {
279         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
280         char *r = NULL;
281         char *s = NULL;
282
283         if (!info || !info_string) {
284                 wbc_status = WBC_ERR_INVALID_PARAM;
285                 BAIL_ON_WBC_ERROR(wbc_status);
286         }
287
288         r = info_string;
289
290         /* Short Name */
291         if ((s = strchr(r, '\\')) == NULL) {
292                 wbc_status = WBC_ERR_INVALID_RESPONSE;
293                 BAIL_ON_WBC_ERROR(wbc_status);
294         }
295         *s = '\0';
296         s++;
297
298         info->short_name = talloc_strdup(ctx, r);
299         BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
300
301
302         /* DNS Name */
303         r = s;
304         if ((s = strchr(r, '\\')) == NULL) {
305                 wbc_status = WBC_ERR_INVALID_RESPONSE;
306                 BAIL_ON_WBC_ERROR(wbc_status);
307         }
308         *s = '\0';
309         s++;
310
311         info->dns_name = talloc_strdup(ctx, r);
312         BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
313
314         /* SID */
315         r = s;
316         if ((s = strchr(r, '\\')) == NULL) {
317                 wbc_status = WBC_ERR_INVALID_RESPONSE;
318                 BAIL_ON_WBC_ERROR(wbc_status);
319         }
320         *s = '\0';
321         s++;
322
323         wbc_status = wbcStringToSid(r, &info->sid);
324         BAIL_ON_WBC_ERROR(wbc_status);
325         
326         /* Trust type */
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, "None") == 0) {
336                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_NONE;
337         } else if (strcmp(r, "External") == 0) {
338                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_EXTERNAL;
339         } else if (strcmp(r, "Forest") == 0) {
340                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_FOREST;
341         } else if (strcmp(r, "In Forest") == 0) {
342                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_IN_FOREST;
343         } else {
344                 wbc_status = WBC_ERR_INVALID_RESPONSE;
345                 BAIL_ON_WBC_ERROR(wbc_status);
346         }
347
348         /* Transitive */
349         r = s;
350         if ((s = strchr(r, '\\')) == NULL) {
351                 wbc_status = WBC_ERR_INVALID_RESPONSE;
352                 BAIL_ON_WBC_ERROR(wbc_status);
353         }
354         *s = '\0';
355         s++;
356
357         if (strcmp(r, "Yes") == 0) {
358                 info->trust_flags |= WBC_DOMINFO_TRUST_TRANSITIVE;              
359         }
360         
361         /* Incoming */
362         r = s;
363         if ((s = strchr(r, '\\')) == NULL) {
364                 wbc_status = WBC_ERR_INVALID_RESPONSE;
365                 BAIL_ON_WBC_ERROR(wbc_status);
366         }
367         *s = '\0';
368         s++;
369
370         if (strcmp(r, "Yes") == 0) {
371                 info->trust_flags |= WBC_DOMINFO_TRUST_INCOMING;                
372         }
373
374         /* Outgoing */
375         r = s;
376         if (r == NULL) {
377                 wbc_status = WBC_ERR_INVALID_RESPONSE;
378                 BAIL_ON_WBC_ERROR(wbc_status);
379         }
380
381         if (strcmp(r, "Yes") == 0) {
382                 info->trust_flags |= WBC_DOMINFO_TRUST_OUTGOING;                
383         }
384
385         wbc_status = WBC_ERR_SUCCESS;
386
387  done:
388         return wbc_status;
389 }
390
391 /** @brief Enumerate the domain trusts known by Winbind
392  *
393  * @param **domains     Pointer to the allocated domain list array
394  * @param *num_domains  Pointer to number of domains returned
395  *
396  * @return #wbcErr
397  *
398  **/
399 wbcErr wbcListTrusts(struct wbcDomainInfo **domains, size_t *num_domains)
400 {
401         struct winbindd_response response;
402         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
403         char *p = NULL;
404         char *q = NULL;
405         char *extra_data = NULL;        
406         int count = 0;  
407         struct wbcDomainInfo *d_list = NULL;
408         int i = 0;
409         
410         *domains = NULL;
411         *num_domains = 0;
412         
413         ZERO_STRUCT(response);
414
415         /* Send request */
416
417         wbc_status = wbcRequestResponse(WINBINDD_LIST_TRUSTDOM,
418                                         NULL,
419                                         &response);
420         BAIL_ON_WBC_ERROR(wbc_status);
421
422         /* Decode the response */
423
424         p = (char *)response.extra_data.data;
425
426         if (strlen(p) == 0) {
427                 /* We should always at least get back our 
428                    own SAM domain */
429                 
430                 wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
431                 BAIL_ON_WBC_ERROR(wbc_status);
432         }
433
434         /* Count number of domains */
435
436         count = 0;      
437         while (p) {
438                 count++;
439
440                 if ((q = strchr(p, '\n')) != NULL)
441                         q++;
442                 p = q;          
443         }
444
445         d_list = talloc_array(NULL, struct wbcDomainInfo, count);
446         BAIL_ON_PTR_ERROR(d_list, wbc_status);
447
448         extra_data = strdup((char*)response.extra_data.data);
449         BAIL_ON_PTR_ERROR(extra_data, wbc_status);
450
451         p = extra_data; 
452
453         /* Outer loop processes the list of domain information */
454
455         for (i=0; i<count && p; i++) {
456                 char *next = strchr(p, '\n');
457                 
458                 if (next) {
459                         *next = '\0';
460                         next++;
461                 }
462
463                 wbc_status = process_domain_info_string(d_list, &d_list[i], p);
464                 BAIL_ON_WBC_ERROR(wbc_status);
465
466                 p = next;
467         }
468
469         *domains = d_list;      
470         *num_domains = i;       
471         
472  done:
473         if (!WBC_ERROR_IS_OK(wbc_status)) {
474                 if (d_list)
475                         talloc_free(d_list);
476                 if (extra_data)
477                         free(extra_data);
478         }
479
480         return wbc_status;
481 }