fcec32af8a8fc83e775bbe7baa02852449b5152d
[ira/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 struct wbc_ping_state {
31         struct winbindd_request req;
32 };
33
34 static void wbcPing_done(struct tevent_req *subreq);
35
36 /** @brief Ping winbind to see if the service is up and running
37  *
38  * @param mem_ctx       talloc context to allocate the request from
39  * @param ev            event context to use for async operation
40  * @param wb_ctx        winbind context to use
41  *
42  * @return Async request on successful dispatch of the request, NULL on error
43  */
44
45 struct tevent_req *wbcPing_send(TALLOC_CTX *mem_ctx,
46                                 struct tevent_context *ev,
47                                 struct wb_context *wb_ctx)
48 {
49         struct tevent_req *req, *subreq;
50         struct wbc_ping_state *state;
51
52         req = tevent_req_create(mem_ctx, &state, struct wbc_ping_state);
53         if (req == NULL) {
54                 return NULL;
55         }
56
57         ZERO_STRUCT(state->req);
58
59         state->req.cmd = WINBINDD_PING;
60         subreq = wb_trans_send(state, ev, wb_ctx, false, &state->req);
61         if (tevent_req_nomem(subreq, req)) {
62                 return tevent_req_post(req, ev);
63         }
64
65         tevent_req_set_callback(subreq, wbcPing_done, req);
66         return req;
67 }
68
69 static void wbcPing_done(struct tevent_req *subreq)
70 {
71         struct tevent_req *req = tevent_req_callback_data(
72                         subreq, struct tevent_req);
73         struct wbc_ping_state *state = tevent_req_data(
74                         req, struct wbc_ping_state);
75         struct winbindd_response *resp;
76         wbcErr wbc_status;
77
78         wbc_status = wb_trans_recv(subreq, state, &resp);
79         TALLOC_FREE(subreq);
80         if (!WBC_ERROR_IS_OK(wbc_status)) {
81                 tevent_req_error(req, wbc_status);
82                 return;
83         }
84         TALLOC_FREE(resp);
85
86         tevent_req_done(req);
87 }
88
89 /** @brief Receive ping response from winbind
90  *
91  * @param req           async request sent in #wbcPing_send
92  *
93  * @return NT_STATUS_OK on success, an error status on error.
94  */
95
96 wbcErr wbcPing_recv(struct tevent_req *req)
97 {
98         wbcErr wbc_status;
99
100         if (tevent_req_is_wbcerr(req, &wbc_status)) {
101                 tevent_req_received(req);
102                 return wbc_status;
103         }
104
105         tevent_req_received(req);
106         return WBC_ERR_SUCCESS;
107 }
108
109 /** @brief Ping winbindd to see if the daemon is running
110  *
111  * @return #wbcErr
112  **/
113 wbcErr wbcPing(void)
114 {
115         struct winbindd_request request;
116         struct winbindd_response response;
117
118         /* Initialize request */
119
120         ZERO_STRUCT(request);
121         ZERO_STRUCT(response);
122
123         return wbcRequestResponse(WINBINDD_PING, &request, &response);
124 }
125
126 struct wbc_interface_version_state {
127         struct winbindd_request req;
128         uint32_t version;
129 };
130
131 static void wbcInterfaceVersion_done(struct tevent_req *subreq);
132
133 /**
134  * @brief Request the interface version from winbind
135  *
136  * @param mem_ctx       talloc context to allocate memory from
137  * @param ev            tevent context to use for async requests
138  * @param wb_ctx        winbind context
139  *
140  * @return tevevt_req on success, NULL on failure
141  */
142
143 struct tevent_req *wbcInterfaceVersion_send(TALLOC_CTX *mem_ctx,
144                                             struct tevent_context *ev,
145                                             struct wb_context *wb_ctx)
146 {
147         struct tevent_req *req, *subreq;
148         struct wbc_interface_version_state *state;
149
150         req = tevent_req_create(mem_ctx, &state, struct wbc_interface_version_state);
151         if (req == NULL) {
152                 return NULL;
153         }
154
155         ZERO_STRUCT(state->req);
156         state->req.cmd = WINBINDD_INTERFACE_VERSION;
157
158         subreq = wb_trans_send(state, ev, wb_ctx, false, &state->req);
159         if (tevent_req_nomem(subreq, req)) {
160                 return tevent_req_post(req, ev);
161         }
162
163         tevent_req_set_callback(subreq, wbcInterfaceVersion_done, req);
164
165         return req;
166 }
167
168 static void wbcInterfaceVersion_done(struct tevent_req *subreq)
169 {
170         struct tevent_req *req = tevent_req_callback_data(
171                         subreq, struct tevent_req);
172         struct wbc_interface_version_state *state = tevent_req_data(
173                         req, struct wbc_interface_version_state);
174         struct winbindd_response *resp;
175         wbcErr wbc_status;
176
177         wbc_status = wb_trans_recv(subreq, state, &resp);
178         TALLOC_FREE(subreq);
179         if (!WBC_ERROR_IS_OK(wbc_status)) {
180                 tevent_req_error(req, wbc_status);
181                 return;
182         }
183         state->version = resp->data.interface_version;
184         TALLOC_FREE(resp);
185
186         tevent_req_done(req);
187 }
188
189 /**
190  * @brief Receive the winbind interface version
191  *
192  * @param req                   tevent_req containing the request
193  * @param interface_version     pointer to uint32_t to hold the interface
194  *                              version
195  *
196  * @return #wbcErr
197  */
198
199 wbcErr wbcInterfaceVersion_recv(struct tevent_req *req,
200                                 uint32_t *interface_version)
201 {
202         struct wbc_interface_version_state *state = tevent_req_data(
203                         req, struct wbc_interface_version_state);
204         wbcErr wbc_status;
205
206         if (tevent_req_is_wbcerr(req, &wbc_status)) {
207                 tevent_req_received(req);
208                 return wbc_status;
209         }
210
211         *interface_version = state->version;
212
213         tevent_req_received(req);
214         return WBC_ERR_SUCCESS;
215 }
216
217 struct wbc_info_state {
218         struct winbindd_request req;
219         char separator;
220         char *version_string;
221 };
222
223 static void wbcInfo_done(struct tevent_req *subreq);
224
225 /**
226  * @brief Request information about the winbind service
227  *
228  * @param mem_ctx       talloc context to allocate memory from
229  * @param ev            tevent context to use for async requests
230  * @param wb_ctx        winbind context
231  *
232  * @return tevent_req on success, NULL on failure
233  */
234
235 struct tevent_req *wbcInfo_send(TALLOC_CTX *mem_ctx,
236                                 struct tevent_context *ev,
237                                 struct wb_context *wb_ctx)
238 {
239         struct tevent_req *req, *subreq;
240         struct wbc_info_state *state;
241
242         req = tevent_req_create(mem_ctx, &state, struct wbc_info_state);
243         if (req == NULL) {
244                 return NULL;
245         }
246
247         ZERO_STRUCT(state->req);
248         state->req.cmd = WINBINDD_INFO;
249
250         subreq = wb_trans_send(state, ev, wb_ctx, false, &state->req);
251         if (tevent_req_nomem(subreq, req)) {
252                 return tevent_req_post(req, ev);
253         }
254
255         tevent_req_set_callback(subreq, wbcInfo_done, req);
256         return req;
257 }
258
259 static void wbcInfo_done(struct tevent_req *subreq)
260 {
261         struct tevent_req *req = tevent_req_callback_data(
262                         subreq, struct tevent_req);
263         struct wbc_info_state *state = tevent_req_data(
264                         req, struct wbc_info_state);
265         struct winbindd_response *resp;
266         wbcErr wbc_status;
267
268         wbc_status = wb_trans_recv(subreq, state, &resp);
269         TALLOC_FREE(subreq);
270         if (!WBC_ERROR_IS_OK(wbc_status)) {
271                 tevent_req_error(req, wbc_status);
272                 return;
273         }
274         state->version_string = talloc_strdup(state,
275                                         resp->data.info.samba_version);
276         if (tevent_req_nomem(state->version_string, subreq)) {
277                 return;
278         }
279         state->separator = resp->data.info.winbind_separator;
280         TALLOC_FREE(resp);
281
282         tevent_req_done(req);
283 }
284
285 /**
286  * @brief Receive information about the running winbind service
287  *
288  * @param req                   tevent_req containing the request
289  * @param mem_ctx               talloc context to allocate memory from
290  * @param winbind_separator     pointer to a char to hold the separator
291  * @param version_string        pointer to a string to hold the version string
292  *
293  * @return #wbcErr
294  */
295
296 wbcErr wbcInfo_recv(struct tevent_req *req,
297                     TALLOC_CTX *mem_ctx,
298                     char *winbind_separator,
299                     char **version_string)
300 {
301         struct wbc_info_state *state = tevent_req_data(
302                         req, struct wbc_info_state);
303         wbcErr wbc_status;
304
305         if (tevent_req_is_wbcerr(req, &wbc_status)) {
306                 tevent_req_received(req);
307                 return wbc_status;
308         }
309
310         *winbind_separator = state->separator;
311         *version_string = talloc_steal(mem_ctx, state->version_string);
312
313         tevent_req_received(req);
314         return WBC_ERR_SUCCESS;
315 }
316
317 struct wbc_netbios_name_state {
318         struct winbindd_request req;
319         char *netbios_name;
320 };
321
322 static void wbcNetbiosName_done(struct tevent_req *subreq);
323
324 /**
325  * @brief Request the machine's netbios name
326  *
327  * @param mem_ctx       talloc context to allocate memory from
328  * @param ev            tevent context to use for async requests
329  * @param wb_ctx        winbind context
330  *
331  * @return tevent_req on success, NULL on failure
332  */
333
334 struct tevent_req *wbcNetbiosName_send(TALLOC_CTX *mem_ctx,
335                                        struct tevent_context *ev,
336                                        struct wb_context *wb_ctx)
337 {
338         struct tevent_req *req, *subreq;
339         struct wbc_netbios_name_state *state;
340
341         req = tevent_req_create(mem_ctx, &state, struct wbc_netbios_name_state);
342         if (req == NULL) {
343                 return NULL;
344         }
345
346         ZERO_STRUCT(state->req);
347         state->req.cmd = WINBINDD_NETBIOS_NAME;
348
349         subreq = wb_trans_send(state, ev, wb_ctx, false, &state->req);
350         if (tevent_req_nomem(subreq, req)) {
351                 return tevent_req_post(req, ev);
352         }
353
354         tevent_req_set_callback(subreq, wbcNetbiosName_done, req);
355         return req;
356 }
357
358 static void wbcNetbiosName_done(struct tevent_req *subreq)
359 {
360         struct tevent_req *req = tevent_req_callback_data(
361                         subreq, struct tevent_req);
362         struct wbc_netbios_name_state *state = tevent_req_data(
363                         req, struct wbc_netbios_name_state);
364         struct winbindd_response *resp;
365         wbcErr wbc_status;
366
367         wbc_status = wb_trans_recv(subreq, state, &resp);
368         TALLOC_FREE(subreq);
369         if (!WBC_ERROR_IS_OK(wbc_status)) {
370                 tevent_req_error(req, wbc_status);
371                 return;
372         }
373         state->netbios_name = talloc_strdup(state,
374                                         resp->data.info.samba_version);
375         if (tevent_req_nomem(state->netbios_name, subreq)) {
376                 return;
377         }
378         TALLOC_FREE(resp);
379
380         tevent_req_done(req);
381 }
382
383 /**
384  * @brief Receive the machine's netbios name
385  *
386  * @param req           tevent_req containing the request
387  * @param mem_ctx       talloc context to allocate memory from
388  * @param netbios_name  pointer to a string to hold the netbios name
389  *
390  * @return #wbcErr
391  */
392
393 wbcErr wbcNetbiosName_recv(struct tevent_req *req,
394                            TALLOC_CTX *mem_ctx,
395                            char **netbios_name)
396 {
397         struct wbc_netbios_name_state *state = tevent_req_data(
398                         req, struct wbc_netbios_name_state);
399         wbcErr wbc_status;
400
401         if (tevent_req_is_wbcerr(req, &wbc_status)) {
402                 tevent_req_received(req);
403                 return wbc_status;
404         }
405
406         *netbios_name = talloc_steal(mem_ctx, state->netbios_name);
407
408         tevent_req_received(req);
409         return WBC_ERR_SUCCESS;
410 }
411
412 struct wbc_domain_name_state {
413         struct winbindd_request req;
414         char *domain_name;
415 };
416
417 static void wbcDomainName_done(struct tevent_req *subreq);
418
419 /**
420  * @brief Request the machine's domain name
421  *
422  * @param mem_ctx       talloc context to allocate memory from
423  * @param ev            tevent context to use for async requests
424  * @param wb_ctx        winbind context
425  *
426  * @return tevent_req on success, NULL on failure
427  */
428
429 struct tevent_req *wbcDomainName_send(TALLOC_CTX *mem_ctx,
430                                       struct tevent_context *ev,
431                                       struct wb_context *wb_ctx)
432 {
433         struct tevent_req *req, *subreq;
434         struct wbc_domain_name_state *state;
435
436         req = tevent_req_create(mem_ctx, &state, struct wbc_domain_name_state);
437         if (req == NULL) {
438                 return NULL;
439         }
440
441         ZERO_STRUCT(state->req);
442         state->req.cmd = WINBINDD_DOMAIN_NAME;
443
444         subreq = wb_trans_send(state, ev, wb_ctx, false, &state->req);
445         if (tevent_req_nomem(subreq, req)) {
446                 return tevent_req_post(req, ev);
447         }
448
449         tevent_req_set_callback(subreq, wbcDomainName_done, req);
450         return req;
451 }
452
453 static void wbcDomainName_done(struct tevent_req *subreq)
454 {
455         struct tevent_req *req = tevent_req_callback_data(
456                         subreq, struct tevent_req);
457         struct wbc_domain_name_state *state = tevent_req_data(
458                         req, struct wbc_domain_name_state);
459         struct winbindd_response *resp;
460         wbcErr wbc_status;
461
462         wbc_status = wb_trans_recv(subreq, state, &resp);
463         TALLOC_FREE(subreq);
464         if (!WBC_ERROR_IS_OK(wbc_status)) {
465                 tevent_req_error(req, wbc_status);
466                 return;
467         }
468         state->domain_name = talloc_strdup(state, resp->data.domain_name);
469         if (tevent_req_nomem(state->domain_name, subreq)) {
470                 return;
471         }
472         TALLOC_FREE(resp);
473
474         tevent_req_done(req);
475 }
476
477 /**
478  * @brief Receive the machine's domain name
479  *
480  * @param req           tevent_req containing the request
481  * @param mem_ctx       talloc context to allocate memory from
482  * @param domain_name   pointer to a string to hold the domain name
483  *
484  * @return #wbcErr
485  */
486
487 wbcErr wbcDomainName_recv(struct tevent_req *req,
488                           TALLOC_CTX *mem_ctx,
489                           char **domain_name)
490 {
491         struct wbc_domain_name_state *state = tevent_req_data(
492                         req, struct wbc_domain_name_state);
493         wbcErr wbc_status;
494
495         if (tevent_req_is_wbcerr(req, &wbc_status)) {
496                 tevent_req_received(req);
497                 return wbc_status;
498         }
499
500         *domain_name = talloc_steal(mem_ctx, state->domain_name);
501
502         tevent_req_received(req);
503         return WBC_ERR_SUCCESS;
504 }
505
506 wbcErr wbcInterfaceDetails(struct wbcInterfaceDetails **_details)
507 {
508         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
509         struct wbcInterfaceDetails *info;
510         struct wbcDomainInfo *domain = NULL;
511         struct winbindd_request request;
512         struct winbindd_response response;
513
514         /* Initialize request */
515
516         ZERO_STRUCT(request);
517         ZERO_STRUCT(response);
518
519         info = talloc(NULL, struct wbcInterfaceDetails);
520         BAIL_ON_PTR_ERROR(info, wbc_status);
521
522         /* first the interface version */
523         wbc_status = wbcRequestResponse(WINBINDD_INTERFACE_VERSION, NULL, &response);
524         BAIL_ON_WBC_ERROR(wbc_status);
525         info->interface_version = response.data.interface_version;
526
527         /* then the samba version and the winbind separator */
528         wbc_status = wbcRequestResponse(WINBINDD_INFO, NULL, &response);
529         BAIL_ON_WBC_ERROR(wbc_status);
530
531         info->winbind_version = talloc_strdup(info,
532                                               response.data.info.samba_version);
533         BAIL_ON_PTR_ERROR(info->winbind_version, wbc_status);
534         info->winbind_separator = response.data.info.winbind_separator;
535
536         /* then the local netbios name */
537         wbc_status = wbcRequestResponse(WINBINDD_NETBIOS_NAME, NULL, &response);
538         BAIL_ON_WBC_ERROR(wbc_status);
539
540         info->netbios_name = talloc_strdup(info,
541                                            response.data.netbios_name);
542         BAIL_ON_PTR_ERROR(info->netbios_name, wbc_status);
543
544         /* then the local workgroup name */
545         wbc_status = wbcRequestResponse(WINBINDD_DOMAIN_NAME, NULL, &response);
546         BAIL_ON_WBC_ERROR(wbc_status);
547
548         info->netbios_domain = talloc_strdup(info,
549                                         response.data.domain_name);
550         BAIL_ON_PTR_ERROR(info->netbios_domain, wbc_status);
551
552         wbc_status = wbcDomainInfo(info->netbios_domain, &domain);
553         if (wbc_status == WBC_ERR_DOMAIN_NOT_FOUND) {
554                 /* maybe it's a standalone server */
555                 domain = NULL;
556                 wbc_status = WBC_ERR_SUCCESS;
557         } else {
558                 BAIL_ON_WBC_ERROR(wbc_status);
559         }
560
561         if (domain) {
562                 info->dns_domain = talloc_strdup(info,
563                                                  domain->dns_name);
564                 wbcFreeMemory(domain);
565                 BAIL_ON_PTR_ERROR(info->dns_domain, wbc_status);
566         } else {
567                 info->dns_domain = NULL;
568         }
569
570         *_details = info;
571         info = NULL;
572
573         wbc_status = WBC_ERR_SUCCESS;
574
575 done:
576         talloc_free(info);
577         return wbc_status;
578 }
579
580
581 /* Lookup the current status of a trusted domain */
582 wbcErr wbcDomainInfo(const char *domain, struct wbcDomainInfo **dinfo)
583 {
584         struct winbindd_request request;
585         struct winbindd_response response;
586         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
587         struct wbcDomainInfo *info = NULL;
588
589         if (!domain || !dinfo) {
590                 wbc_status = WBC_ERR_INVALID_PARAM;
591                 BAIL_ON_WBC_ERROR(wbc_status);
592         }
593
594         /* Initialize request */
595
596         ZERO_STRUCT(request);
597         ZERO_STRUCT(response);
598
599         strncpy(request.domain_name, domain,
600                 sizeof(request.domain_name)-1);
601
602         wbc_status = wbcRequestResponse(WINBINDD_DOMAIN_INFO,
603                                         &request,
604                                         &response);
605         BAIL_ON_WBC_ERROR(wbc_status);
606
607         info = talloc(NULL, struct wbcDomainInfo);
608         BAIL_ON_PTR_ERROR(info, wbc_status);
609
610         info->short_name = talloc_strdup(info,
611                                          response.data.domain_info.name);
612         BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
613
614         info->dns_name = talloc_strdup(info,
615                                        response.data.domain_info.alt_name);
616         BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
617
618         wbc_status = wbcStringToSid(response.data.domain_info.sid,
619                                     &info->sid);
620         BAIL_ON_WBC_ERROR(wbc_status);
621
622         if (response.data.domain_info.native_mode)
623                 info->domain_flags |= WBC_DOMINFO_DOMAIN_NATIVE;
624         if (response.data.domain_info.active_directory)
625                 info->domain_flags |= WBC_DOMINFO_DOMAIN_AD;
626         if (response.data.domain_info.primary)
627                 info->domain_flags |= WBC_DOMINFO_DOMAIN_PRIMARY;
628
629         *dinfo = info;
630
631         wbc_status = WBC_ERR_SUCCESS;
632
633  done:
634         if (!WBC_ERROR_IS_OK(wbc_status)) {
635                 talloc_free(info);
636         }
637
638         return wbc_status;
639 }
640
641
642 /* Resolve a NetbiosName via WINS */
643 wbcErr wbcResolveWinsByName(const char *name, char **ip)
644 {
645         struct winbindd_request request;
646         struct winbindd_response response;
647         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
648         char *ipaddr;
649
650         ZERO_STRUCT(request);
651         ZERO_STRUCT(response);
652
653         /* Send request */
654
655         strncpy(request.data.winsreq, name,
656                 sizeof(request.data.winsreq)-1);
657
658         wbc_status = wbcRequestResponse(WINBINDD_WINS_BYNAME,
659                                         &request,
660                                         &response);
661         BAIL_ON_WBC_ERROR(wbc_status);
662
663         /* Display response */
664
665         ipaddr = talloc_strdup(NULL, response.data.winsresp);
666         BAIL_ON_PTR_ERROR(ipaddr, wbc_status);
667
668         *ip = ipaddr;
669         wbc_status = WBC_ERR_SUCCESS;
670
671  done:
672         return wbc_status;
673 }
674
675 /* Resolve an IP address via WINS into a NetbiosName */
676 wbcErr wbcResolveWinsByIP(const char *ip, char **name)
677 {
678         struct winbindd_request request;
679         struct winbindd_response response;
680         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
681         char *name_str;
682
683         ZERO_STRUCT(request);
684         ZERO_STRUCT(response);
685
686         /* Send request */
687
688         strncpy(request.data.winsreq, ip,
689                 sizeof(request.data.winsreq)-1);
690
691         wbc_status = wbcRequestResponse(WINBINDD_WINS_BYIP,
692                                         &request,
693                                         &response);
694         BAIL_ON_WBC_ERROR(wbc_status);
695
696         /* Display response */
697
698         name_str = talloc_strdup(NULL, response.data.winsresp);
699         BAIL_ON_PTR_ERROR(name_str, wbc_status);
700
701         *name = name_str;
702         wbc_status = WBC_ERR_SUCCESS;
703
704  done:
705         return wbc_status;
706 }
707
708 /**
709  */
710
711 static wbcErr process_domain_info_string(TALLOC_CTX *ctx,
712                                          struct wbcDomainInfo *info,
713                                          char *info_string)
714 {
715         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
716         char *r = NULL;
717         char *s = NULL;
718
719         if (!info || !info_string) {
720                 wbc_status = WBC_ERR_INVALID_PARAM;
721                 BAIL_ON_WBC_ERROR(wbc_status);
722         }
723
724         ZERO_STRUCTP(info);
725
726         r = info_string;
727
728         /* Short Name */
729         if ((s = strchr(r, '\\')) == NULL) {
730                 wbc_status = WBC_ERR_INVALID_RESPONSE;
731                 BAIL_ON_WBC_ERROR(wbc_status);
732         }
733         *s = '\0';
734         s++;
735
736         info->short_name = talloc_strdup(ctx, r);
737         BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
738
739
740         /* DNS Name */
741         r = s;
742         if ((s = strchr(r, '\\')) == NULL) {
743                 wbc_status = WBC_ERR_INVALID_RESPONSE;
744                 BAIL_ON_WBC_ERROR(wbc_status);
745         }
746         *s = '\0';
747         s++;
748
749         info->dns_name = talloc_strdup(ctx, r);
750         BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
751
752         /* SID */
753         r = s;
754         if ((s = strchr(r, '\\')) == NULL) {
755                 wbc_status = WBC_ERR_INVALID_RESPONSE;
756                 BAIL_ON_WBC_ERROR(wbc_status);
757         }
758         *s = '\0';
759         s++;
760
761         wbc_status = wbcStringToSid(r, &info->sid);
762         BAIL_ON_WBC_ERROR(wbc_status);
763
764         /* Trust type */
765         r = s;
766         if ((s = strchr(r, '\\')) == NULL) {
767                 wbc_status = WBC_ERR_INVALID_RESPONSE;
768                 BAIL_ON_WBC_ERROR(wbc_status);
769         }
770         *s = '\0';
771         s++;
772
773         if (strcmp(r, "None") == 0) {
774                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_NONE;
775         } else if (strcmp(r, "External") == 0) {
776                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_EXTERNAL;
777         } else if (strcmp(r, "Forest") == 0) {
778                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_FOREST;
779         } else if (strcmp(r, "In Forest") == 0) {
780                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_IN_FOREST;
781         } else {
782                 wbc_status = WBC_ERR_INVALID_RESPONSE;
783                 BAIL_ON_WBC_ERROR(wbc_status);
784         }
785
786         /* Transitive */
787         r = s;
788         if ((s = strchr(r, '\\')) == NULL) {
789                 wbc_status = WBC_ERR_INVALID_RESPONSE;
790                 BAIL_ON_WBC_ERROR(wbc_status);
791         }
792         *s = '\0';
793         s++;
794
795         if (strcmp(r, "Yes") == 0) {
796                 info->trust_flags |= WBC_DOMINFO_TRUST_TRANSITIVE;
797         }
798
799         /* Incoming */
800         r = s;
801         if ((s = strchr(r, '\\')) == NULL) {
802                 wbc_status = WBC_ERR_INVALID_RESPONSE;
803                 BAIL_ON_WBC_ERROR(wbc_status);
804         }
805         *s = '\0';
806         s++;
807
808         if (strcmp(r, "Yes") == 0) {
809                 info->trust_flags |= WBC_DOMINFO_TRUST_INCOMING;
810         }
811
812         /* Outgoing */
813         r = s;
814         if ((s = strchr(r, '\\')) == NULL) {
815                 wbc_status = WBC_ERR_INVALID_RESPONSE;
816                 BAIL_ON_WBC_ERROR(wbc_status);
817         }
818         *s = '\0';
819         s++;
820
821         if (strcmp(r, "Yes") == 0) {
822                 info->trust_flags |= WBC_DOMINFO_TRUST_OUTGOING;
823         }
824
825         /* Online/Offline status */
826
827         r = s;
828         if (r == NULL) {
829                 wbc_status = WBC_ERR_INVALID_RESPONSE;
830                 BAIL_ON_WBC_ERROR(wbc_status);
831         }
832         if ( strcmp(r, "Offline") == 0) {
833                 info->domain_flags |= WBC_DOMINFO_DOMAIN_OFFLINE;
834         }
835
836         wbc_status = WBC_ERR_SUCCESS;
837
838  done:
839         return wbc_status;
840 }
841
842 /* Enumerate the domain trusts known by Winbind */
843 wbcErr wbcListTrusts(struct wbcDomainInfo **domains, size_t *num_domains)
844 {
845         struct winbindd_response response;
846         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
847         char *p = NULL;
848         char *q = NULL;
849         char *extra_data = NULL;
850         int count = 0;
851         struct wbcDomainInfo *d_list = NULL;
852         int i = 0;
853
854         *domains = NULL;
855         *num_domains = 0;
856
857         ZERO_STRUCT(response);
858
859         /* Send request */
860
861         wbc_status = wbcRequestResponse(WINBINDD_LIST_TRUSTDOM,
862                                         NULL,
863                                         &response);
864         BAIL_ON_WBC_ERROR(wbc_status);
865
866         /* Decode the response */
867
868         p = (char *)response.extra_data.data;
869
870         if ((p == NULL) || (strlen(p) == 0)) {
871                 /* We should always at least get back our
872                    own SAM domain */
873
874                 wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
875                 BAIL_ON_WBC_ERROR(wbc_status);
876         }
877
878         /* Count number of domains */
879
880         count = 0;
881         while (p) {
882                 count++;
883
884                 if ((q = strchr(p, '\n')) != NULL)
885                         q++;
886                 p = q;
887         }
888
889         d_list = talloc_array(NULL, struct wbcDomainInfo, count);
890         BAIL_ON_PTR_ERROR(d_list, wbc_status);
891
892         extra_data = strdup((char*)response.extra_data.data);
893         BAIL_ON_PTR_ERROR(extra_data, wbc_status);
894
895         p = extra_data;
896
897         /* Outer loop processes the list of domain information */
898
899         for (i=0; i<count && p; i++) {
900                 char *next = strchr(p, '\n');
901
902                 if (next) {
903                         *next = '\0';
904                         next++;
905                 }
906
907                 wbc_status = process_domain_info_string(d_list, &d_list[i], p);
908                 BAIL_ON_WBC_ERROR(wbc_status);
909
910                 p = next;
911         }
912
913         *domains = d_list;
914         *num_domains = i;
915
916  done:
917         if (!WBC_ERROR_IS_OK(wbc_status)) {
918                 if (d_list)
919                         talloc_free(d_list);
920                 if (extra_data)
921                         free(extra_data);
922         }
923
924         return wbc_status;
925 }
926
927 /* Enumerate the domain trusts known by Winbind */
928 wbcErr wbcLookupDomainController(const char *domain,
929                                  uint32_t flags,
930                                 struct wbcDomainControllerInfo **dc_info)
931 {
932         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
933         struct winbindd_request request;
934         struct winbindd_response response;
935         struct wbcDomainControllerInfo *dc = NULL;
936
937         /* validate input params */
938
939         if (!domain || !dc_info) {
940                 wbc_status = WBC_ERR_INVALID_PARAM;
941                 BAIL_ON_WBC_ERROR(wbc_status);
942         }
943
944         ZERO_STRUCT(request);
945         ZERO_STRUCT(response);
946
947         strncpy(request.data.dsgetdcname.domain_name, domain,
948                 sizeof(request.data.dsgetdcname.domain_name)-1);
949
950         request.flags = flags;
951
952         dc = talloc(NULL, struct wbcDomainControllerInfo);
953         BAIL_ON_PTR_ERROR(dc, wbc_status);
954
955         /* Send request */
956
957         wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
958                                         &request,
959                                         &response);
960         BAIL_ON_WBC_ERROR(wbc_status);
961
962         dc->dc_name = talloc_strdup(dc, response.data.dsgetdcname.dc_unc);
963         BAIL_ON_PTR_ERROR(dc->dc_name, wbc_status);
964
965         *dc_info = dc;
966
967 done:
968         if (!WBC_ERROR_IS_OK(wbc_status)) {
969                 talloc_free(dc);
970         }
971
972         return wbc_status;
973 }
974
975 static wbcErr wbc_create_domain_controller_info_ex(TALLOC_CTX *mem_ctx,
976                                                    const struct winbindd_response *resp,
977                                                    struct wbcDomainControllerInfoEx **_i)
978 {
979         wbcErr wbc_status = WBC_ERR_SUCCESS;
980         struct wbcDomainControllerInfoEx *i;
981         struct wbcGuid guid;
982
983         i = talloc(mem_ctx, struct wbcDomainControllerInfoEx);
984         BAIL_ON_PTR_ERROR(i, wbc_status);
985
986         i->dc_unc = talloc_strdup(i, resp->data.dsgetdcname.dc_unc);
987         BAIL_ON_PTR_ERROR(i->dc_unc, wbc_status);
988
989         i->dc_address = talloc_strdup(i, resp->data.dsgetdcname.dc_address);
990         BAIL_ON_PTR_ERROR(i->dc_address, wbc_status);
991
992         i->dc_address_type = resp->data.dsgetdcname.dc_address_type;
993
994         wbc_status = wbcStringToGuid(resp->data.dsgetdcname.domain_guid, &guid);
995         if (WBC_ERROR_IS_OK(wbc_status)) {
996                 i->domain_guid = talloc(i, struct wbcGuid);
997                 BAIL_ON_PTR_ERROR(i->domain_guid, wbc_status);
998
999                 *i->domain_guid = guid;
1000         } else {
1001                 i->domain_guid = NULL;
1002         }
1003
1004         i->domain_name = talloc_strdup(i, resp->data.dsgetdcname.domain_name);
1005         BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
1006
1007         if (resp->data.dsgetdcname.forest_name[0] != '\0') {
1008                 i->forest_name = talloc_strdup(i,
1009                         resp->data.dsgetdcname.forest_name);
1010                 BAIL_ON_PTR_ERROR(i->forest_name, wbc_status);
1011         } else {
1012                 i->forest_name = NULL;
1013         }
1014
1015         i->dc_flags = resp->data.dsgetdcname.dc_flags;
1016
1017         if (resp->data.dsgetdcname.dc_site_name[0] != '\0') {
1018                 i->dc_site_name = talloc_strdup(i,
1019                         resp->data.dsgetdcname.dc_site_name);
1020                 BAIL_ON_PTR_ERROR(i->dc_site_name, wbc_status);
1021         } else {
1022                 i->dc_site_name = NULL;
1023         }
1024
1025         if (resp->data.dsgetdcname.client_site_name[0] != '\0') {
1026                 i->client_site_name = talloc_strdup(i,
1027                         resp->data.dsgetdcname.client_site_name);
1028                 BAIL_ON_PTR_ERROR(i->client_site_name, wbc_status);
1029         } else {
1030                 i->client_site_name = NULL;
1031         }
1032
1033         *_i = i;
1034         i = NULL;
1035
1036 done:
1037         talloc_free(i);
1038         return wbc_status;
1039 }
1040
1041 /* Get extended domain controller information */
1042 wbcErr wbcLookupDomainControllerEx(const char *domain,
1043                                    struct wbcGuid *guid,
1044                                    const char *site,
1045                                    uint32_t flags,
1046                                    struct wbcDomainControllerInfoEx **dc_info)
1047 {
1048         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
1049         struct winbindd_request request;
1050         struct winbindd_response response;
1051
1052         /* validate input params */
1053
1054         if (!domain || !dc_info) {
1055                 wbc_status = WBC_ERR_INVALID_PARAM;
1056                 BAIL_ON_WBC_ERROR(wbc_status);
1057         }
1058
1059         ZERO_STRUCT(request);
1060         ZERO_STRUCT(response);
1061
1062         request.data.dsgetdcname.flags = flags;
1063
1064         strncpy(request.data.dsgetdcname.domain_name, domain,
1065                 sizeof(request.data.dsgetdcname.domain_name)-1);
1066
1067         if (site) {
1068                 strncpy(request.data.dsgetdcname.site_name, site,
1069                         sizeof(request.data.dsgetdcname.site_name)-1);
1070         }
1071
1072         if (guid) {
1073                 char *str = NULL;
1074
1075                 wbc_status = wbcGuidToString(guid, &str);
1076                 BAIL_ON_WBC_ERROR(wbc_status);
1077
1078                 strncpy(request.data.dsgetdcname.domain_guid, str,
1079                         sizeof(request.data.dsgetdcname.domain_guid)-1);
1080
1081                 wbcFreeMemory(str);
1082         }
1083
1084         /* Send request */
1085
1086         wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
1087                                         &request,
1088                                         &response);
1089         BAIL_ON_WBC_ERROR(wbc_status);
1090
1091         if (dc_info) {
1092                 wbc_status = wbc_create_domain_controller_info_ex(NULL,
1093                                                                   &response,
1094                                                                   dc_info);
1095                 BAIL_ON_WBC_ERROR(wbc_status);
1096         }
1097
1098         wbc_status = WBC_ERR_SUCCESS;
1099 done:
1100         return wbc_status;
1101 }
1102
1103 /* Initialize a named blob and add to list of blobs */
1104 wbcErr wbcAddNamedBlob(size_t *num_blobs,
1105                        struct wbcNamedBlob **blobs,
1106                        const char *name,
1107                        uint32_t flags,
1108                        uint8_t *data,
1109                        size_t length)
1110 {
1111         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
1112         struct wbcNamedBlob blob;
1113
1114         *blobs = talloc_realloc(NULL, *blobs, struct wbcNamedBlob,
1115                                 *(num_blobs)+1);
1116         BAIL_ON_PTR_ERROR(*blobs, wbc_status);
1117
1118         blob.name               = talloc_strdup(*blobs, name);
1119         BAIL_ON_PTR_ERROR(blob.name, wbc_status);
1120         blob.flags              = flags;
1121         blob.blob.length        = length;
1122         blob.blob.data          = (uint8_t *)talloc_memdup(*blobs, data, length);
1123         BAIL_ON_PTR_ERROR(blob.blob.data, wbc_status);
1124
1125         (*(blobs))[*num_blobs] = blob;
1126         *(num_blobs) += 1;
1127
1128         wbc_status = WBC_ERR_SUCCESS;
1129 done:
1130         if (!WBC_ERROR_IS_OK(wbc_status)) {
1131                 wbcFreeMemory(*blobs);
1132         }
1133         return wbc_status;
1134 }