libwbclient: Add async wbcPing_send/_recv
[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 "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 wbcErr wbcInterfaceDetails(struct wbcInterfaceDetails **_details)
127 {
128         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
129         struct wbcInterfaceDetails *info;
130         struct wbcDomainInfo *domain = NULL;
131         struct winbindd_request request;
132         struct winbindd_response response;
133
134         /* Initialize request */
135
136         ZERO_STRUCT(request);
137         ZERO_STRUCT(response);
138
139         info = talloc(NULL, struct wbcInterfaceDetails);
140         BAIL_ON_PTR_ERROR(info, wbc_status);
141
142         /* first the interface version */
143         wbc_status = wbcRequestResponse(WINBINDD_INTERFACE_VERSION, NULL, &response);
144         BAIL_ON_WBC_ERROR(wbc_status);
145         info->interface_version = response.data.interface_version;
146
147         /* then the samba version and the winbind separator */
148         wbc_status = wbcRequestResponse(WINBINDD_INFO, NULL, &response);
149         BAIL_ON_WBC_ERROR(wbc_status);
150
151         info->winbind_version = talloc_strdup(info,
152                                               response.data.info.samba_version);
153         BAIL_ON_PTR_ERROR(info->winbind_version, wbc_status);
154         info->winbind_separator = response.data.info.winbind_separator;
155
156         /* then the local netbios name */
157         wbc_status = wbcRequestResponse(WINBINDD_NETBIOS_NAME, NULL, &response);
158         BAIL_ON_WBC_ERROR(wbc_status);
159
160         info->netbios_name = talloc_strdup(info,
161                                            response.data.netbios_name);
162         BAIL_ON_PTR_ERROR(info->netbios_name, wbc_status);
163
164         /* then the local workgroup name */
165         wbc_status = wbcRequestResponse(WINBINDD_DOMAIN_NAME, NULL, &response);
166         BAIL_ON_WBC_ERROR(wbc_status);
167
168         info->netbios_domain = talloc_strdup(info,
169                                         response.data.domain_name);
170         BAIL_ON_PTR_ERROR(info->netbios_domain, wbc_status);
171
172         wbc_status = wbcDomainInfo(info->netbios_domain, &domain);
173         if (wbc_status == WBC_ERR_DOMAIN_NOT_FOUND) {
174                 /* maybe it's a standalone server */
175                 domain = NULL;
176                 wbc_status = WBC_ERR_SUCCESS;
177         } else {
178                 BAIL_ON_WBC_ERROR(wbc_status);
179         }
180
181         if (domain) {
182                 info->dns_domain = talloc_strdup(info,
183                                                  domain->dns_name);
184                 wbcFreeMemory(domain);
185                 BAIL_ON_PTR_ERROR(info->dns_domain, wbc_status);
186         } else {
187                 info->dns_domain = NULL;
188         }
189
190         *_details = info;
191         info = NULL;
192
193         wbc_status = WBC_ERR_SUCCESS;
194
195 done:
196         talloc_free(info);
197         return wbc_status;
198 }
199
200
201 /* Lookup the current status of a trusted domain */
202 wbcErr wbcDomainInfo(const char *domain, struct wbcDomainInfo **dinfo)
203 {
204         struct winbindd_request request;
205         struct winbindd_response response;
206         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
207         struct wbcDomainInfo *info = NULL;
208
209         if (!domain || !dinfo) {
210                 wbc_status = WBC_ERR_INVALID_PARAM;
211                 BAIL_ON_WBC_ERROR(wbc_status);
212         }
213
214         /* Initialize request */
215
216         ZERO_STRUCT(request);
217         ZERO_STRUCT(response);
218
219         strncpy(request.domain_name, domain,
220                 sizeof(request.domain_name)-1);
221
222         wbc_status = wbcRequestResponse(WINBINDD_DOMAIN_INFO,
223                                         &request,
224                                         &response);
225         BAIL_ON_WBC_ERROR(wbc_status);
226
227         info = talloc(NULL, struct wbcDomainInfo);
228         BAIL_ON_PTR_ERROR(info, wbc_status);
229
230         info->short_name = talloc_strdup(info,
231                                          response.data.domain_info.name);
232         BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
233
234         info->dns_name = talloc_strdup(info,
235                                        response.data.domain_info.alt_name);
236         BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
237
238         wbc_status = wbcStringToSid(response.data.domain_info.sid,
239                                     &info->sid);
240         BAIL_ON_WBC_ERROR(wbc_status);
241
242         if (response.data.domain_info.native_mode)
243                 info->domain_flags |= WBC_DOMINFO_DOMAIN_NATIVE;
244         if (response.data.domain_info.active_directory)
245                 info->domain_flags |= WBC_DOMINFO_DOMAIN_AD;
246         if (response.data.domain_info.primary)
247                 info->domain_flags |= WBC_DOMINFO_DOMAIN_PRIMARY;
248
249         *dinfo = info;
250
251         wbc_status = WBC_ERR_SUCCESS;
252
253  done:
254         if (!WBC_ERROR_IS_OK(wbc_status)) {
255                 talloc_free(info);
256         }
257
258         return wbc_status;
259 }
260
261
262 /* Resolve a NetbiosName via WINS */
263 wbcErr wbcResolveWinsByName(const char *name, char **ip)
264 {
265         struct winbindd_request request;
266         struct winbindd_response response;
267         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
268         char *ipaddr;
269
270         ZERO_STRUCT(request);
271         ZERO_STRUCT(response);
272
273         /* Send request */
274
275         strncpy(request.data.winsreq, name,
276                 sizeof(request.data.winsreq)-1);
277
278         wbc_status = wbcRequestResponse(WINBINDD_WINS_BYNAME,
279                                         &request,
280                                         &response);
281         BAIL_ON_WBC_ERROR(wbc_status);
282
283         /* Display response */
284
285         ipaddr = talloc_strdup(NULL, response.data.winsresp);
286         BAIL_ON_PTR_ERROR(ipaddr, wbc_status);
287
288         *ip = ipaddr;
289         wbc_status = WBC_ERR_SUCCESS;
290
291  done:
292         return wbc_status;
293 }
294
295 /* Resolve an IP address via WINS into a NetbiosName */
296 wbcErr wbcResolveWinsByIP(const char *ip, char **name)
297 {
298         struct winbindd_request request;
299         struct winbindd_response response;
300         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
301         char *name_str;
302
303         ZERO_STRUCT(request);
304         ZERO_STRUCT(response);
305
306         /* Send request */
307
308         strncpy(request.data.winsreq, ip,
309                 sizeof(request.data.winsreq)-1);
310
311         wbc_status = wbcRequestResponse(WINBINDD_WINS_BYIP,
312                                         &request,
313                                         &response);
314         BAIL_ON_WBC_ERROR(wbc_status);
315
316         /* Display response */
317
318         name_str = talloc_strdup(NULL, response.data.winsresp);
319         BAIL_ON_PTR_ERROR(name_str, wbc_status);
320
321         *name = name_str;
322         wbc_status = WBC_ERR_SUCCESS;
323
324  done:
325         return wbc_status;
326 }
327
328 /**
329  */
330
331 static wbcErr process_domain_info_string(TALLOC_CTX *ctx,
332                                          struct wbcDomainInfo *info,
333                                          char *info_string)
334 {
335         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
336         char *r = NULL;
337         char *s = NULL;
338
339         if (!info || !info_string) {
340                 wbc_status = WBC_ERR_INVALID_PARAM;
341                 BAIL_ON_WBC_ERROR(wbc_status);
342         }
343
344         ZERO_STRUCTP(info);
345
346         r = info_string;
347
348         /* Short Name */
349         if ((s = strchr(r, '\\')) == NULL) {
350                 wbc_status = WBC_ERR_INVALID_RESPONSE;
351                 BAIL_ON_WBC_ERROR(wbc_status);
352         }
353         *s = '\0';
354         s++;
355
356         info->short_name = talloc_strdup(ctx, r);
357         BAIL_ON_PTR_ERROR(info->short_name, wbc_status);
358
359
360         /* DNS Name */
361         r = s;
362         if ((s = strchr(r, '\\')) == NULL) {
363                 wbc_status = WBC_ERR_INVALID_RESPONSE;
364                 BAIL_ON_WBC_ERROR(wbc_status);
365         }
366         *s = '\0';
367         s++;
368
369         info->dns_name = talloc_strdup(ctx, r);
370         BAIL_ON_PTR_ERROR(info->dns_name, wbc_status);
371
372         /* SID */
373         r = s;
374         if ((s = strchr(r, '\\')) == NULL) {
375                 wbc_status = WBC_ERR_INVALID_RESPONSE;
376                 BAIL_ON_WBC_ERROR(wbc_status);
377         }
378         *s = '\0';
379         s++;
380
381         wbc_status = wbcStringToSid(r, &info->sid);
382         BAIL_ON_WBC_ERROR(wbc_status);
383
384         /* Trust type */
385         r = s;
386         if ((s = strchr(r, '\\')) == NULL) {
387                 wbc_status = WBC_ERR_INVALID_RESPONSE;
388                 BAIL_ON_WBC_ERROR(wbc_status);
389         }
390         *s = '\0';
391         s++;
392
393         if (strcmp(r, "None") == 0) {
394                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_NONE;
395         } else if (strcmp(r, "External") == 0) {
396                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_EXTERNAL;
397         } else if (strcmp(r, "Forest") == 0) {
398                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_FOREST;
399         } else if (strcmp(r, "In Forest") == 0) {
400                 info->trust_type = WBC_DOMINFO_TRUSTTYPE_IN_FOREST;
401         } else {
402                 wbc_status = WBC_ERR_INVALID_RESPONSE;
403                 BAIL_ON_WBC_ERROR(wbc_status);
404         }
405
406         /* Transitive */
407         r = s;
408         if ((s = strchr(r, '\\')) == NULL) {
409                 wbc_status = WBC_ERR_INVALID_RESPONSE;
410                 BAIL_ON_WBC_ERROR(wbc_status);
411         }
412         *s = '\0';
413         s++;
414
415         if (strcmp(r, "Yes") == 0) {
416                 info->trust_flags |= WBC_DOMINFO_TRUST_TRANSITIVE;
417         }
418
419         /* Incoming */
420         r = s;
421         if ((s = strchr(r, '\\')) == NULL) {
422                 wbc_status = WBC_ERR_INVALID_RESPONSE;
423                 BAIL_ON_WBC_ERROR(wbc_status);
424         }
425         *s = '\0';
426         s++;
427
428         if (strcmp(r, "Yes") == 0) {
429                 info->trust_flags |= WBC_DOMINFO_TRUST_INCOMING;
430         }
431
432         /* Outgoing */
433         r = s;
434         if ((s = strchr(r, '\\')) == NULL) {
435                 wbc_status = WBC_ERR_INVALID_RESPONSE;
436                 BAIL_ON_WBC_ERROR(wbc_status);
437         }
438         *s = '\0';
439         s++;
440
441         if (strcmp(r, "Yes") == 0) {
442                 info->trust_flags |= WBC_DOMINFO_TRUST_OUTGOING;
443         }
444
445         /* Online/Offline status */
446
447         r = s;
448         if (r == NULL) {
449                 wbc_status = WBC_ERR_INVALID_RESPONSE;
450                 BAIL_ON_WBC_ERROR(wbc_status);
451         }
452         if ( strcmp(r, "Offline") == 0) {
453                 info->domain_flags |= WBC_DOMINFO_DOMAIN_OFFLINE;
454         }
455
456         wbc_status = WBC_ERR_SUCCESS;
457
458  done:
459         return wbc_status;
460 }
461
462 /* Enumerate the domain trusts known by Winbind */
463 wbcErr wbcListTrusts(struct wbcDomainInfo **domains, size_t *num_domains)
464 {
465         struct winbindd_response response;
466         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
467         char *p = NULL;
468         char *q = NULL;
469         char *extra_data = NULL;
470         int count = 0;
471         struct wbcDomainInfo *d_list = NULL;
472         int i = 0;
473
474         *domains = NULL;
475         *num_domains = 0;
476
477         ZERO_STRUCT(response);
478
479         /* Send request */
480
481         wbc_status = wbcRequestResponse(WINBINDD_LIST_TRUSTDOM,
482                                         NULL,
483                                         &response);
484         BAIL_ON_WBC_ERROR(wbc_status);
485
486         /* Decode the response */
487
488         p = (char *)response.extra_data.data;
489
490         if ((p == NULL) || (strlen(p) == 0)) {
491                 /* We should always at least get back our
492                    own SAM domain */
493
494                 wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
495                 BAIL_ON_WBC_ERROR(wbc_status);
496         }
497
498         /* Count number of domains */
499
500         count = 0;
501         while (p) {
502                 count++;
503
504                 if ((q = strchr(p, '\n')) != NULL)
505                         q++;
506                 p = q;
507         }
508
509         d_list = talloc_array(NULL, struct wbcDomainInfo, count);
510         BAIL_ON_PTR_ERROR(d_list, wbc_status);
511
512         extra_data = strdup((char*)response.extra_data.data);
513         BAIL_ON_PTR_ERROR(extra_data, wbc_status);
514
515         p = extra_data;
516
517         /* Outer loop processes the list of domain information */
518
519         for (i=0; i<count && p; i++) {
520                 char *next = strchr(p, '\n');
521
522                 if (next) {
523                         *next = '\0';
524                         next++;
525                 }
526
527                 wbc_status = process_domain_info_string(d_list, &d_list[i], p);
528                 BAIL_ON_WBC_ERROR(wbc_status);
529
530                 p = next;
531         }
532
533         *domains = d_list;
534         *num_domains = i;
535
536  done:
537         if (!WBC_ERROR_IS_OK(wbc_status)) {
538                 if (d_list)
539                         talloc_free(d_list);
540                 if (extra_data)
541                         free(extra_data);
542         }
543
544         return wbc_status;
545 }
546
547 /* Enumerate the domain trusts known by Winbind */
548 wbcErr wbcLookupDomainController(const char *domain,
549                                  uint32_t flags,
550                                 struct wbcDomainControllerInfo **dc_info)
551 {
552         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
553         struct winbindd_request request;
554         struct winbindd_response response;
555         struct wbcDomainControllerInfo *dc = NULL;
556
557         /* validate input params */
558
559         if (!domain || !dc_info) {
560                 wbc_status = WBC_ERR_INVALID_PARAM;
561                 BAIL_ON_WBC_ERROR(wbc_status);
562         }
563
564         ZERO_STRUCT(request);
565         ZERO_STRUCT(response);
566
567         strncpy(request.data.dsgetdcname.domain_name, domain,
568                 sizeof(request.data.dsgetdcname.domain_name)-1);
569
570         request.flags = flags;
571
572         dc = talloc(NULL, struct wbcDomainControllerInfo);
573         BAIL_ON_PTR_ERROR(dc, wbc_status);
574
575         /* Send request */
576
577         wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
578                                         &request,
579                                         &response);
580         BAIL_ON_WBC_ERROR(wbc_status);
581
582         dc->dc_name = talloc_strdup(dc, response.data.dsgetdcname.dc_unc);
583         BAIL_ON_PTR_ERROR(dc->dc_name, wbc_status);
584
585         *dc_info = dc;
586
587 done:
588         if (!WBC_ERROR_IS_OK(wbc_status)) {
589                 talloc_free(dc);
590         }
591
592         return wbc_status;
593 }
594
595 static wbcErr wbc_create_domain_controller_info_ex(TALLOC_CTX *mem_ctx,
596                                                    const struct winbindd_response *resp,
597                                                    struct wbcDomainControllerInfoEx **_i)
598 {
599         wbcErr wbc_status = WBC_ERR_SUCCESS;
600         struct wbcDomainControllerInfoEx *i;
601         struct wbcGuid guid;
602
603         i = talloc(mem_ctx, struct wbcDomainControllerInfoEx);
604         BAIL_ON_PTR_ERROR(i, wbc_status);
605
606         i->dc_unc = talloc_strdup(i, resp->data.dsgetdcname.dc_unc);
607         BAIL_ON_PTR_ERROR(i->dc_unc, wbc_status);
608
609         i->dc_address = talloc_strdup(i, resp->data.dsgetdcname.dc_address);
610         BAIL_ON_PTR_ERROR(i->dc_address, wbc_status);
611
612         i->dc_address_type = resp->data.dsgetdcname.dc_address_type;
613
614         wbc_status = wbcStringToGuid(resp->data.dsgetdcname.domain_guid, &guid);
615         if (WBC_ERROR_IS_OK(wbc_status)) {
616                 i->domain_guid = talloc(i, struct wbcGuid);
617                 BAIL_ON_PTR_ERROR(i->domain_guid, wbc_status);
618
619                 *i->domain_guid = guid;
620         } else {
621                 i->domain_guid = NULL;
622         }
623
624         i->domain_name = talloc_strdup(i, resp->data.dsgetdcname.domain_name);
625         BAIL_ON_PTR_ERROR(i->domain_name, wbc_status);
626
627         if (resp->data.dsgetdcname.forest_name[0] != '\0') {
628                 i->forest_name = talloc_strdup(i,
629                         resp->data.dsgetdcname.forest_name);
630                 BAIL_ON_PTR_ERROR(i->forest_name, wbc_status);
631         } else {
632                 i->forest_name = NULL;
633         }
634
635         i->dc_flags = resp->data.dsgetdcname.dc_flags;
636
637         if (resp->data.dsgetdcname.dc_site_name[0] != '\0') {
638                 i->dc_site_name = talloc_strdup(i,
639                         resp->data.dsgetdcname.dc_site_name);
640                 BAIL_ON_PTR_ERROR(i->dc_site_name, wbc_status);
641         } else {
642                 i->dc_site_name = NULL;
643         }
644
645         if (resp->data.dsgetdcname.client_site_name[0] != '\0') {
646                 i->client_site_name = talloc_strdup(i,
647                         resp->data.dsgetdcname.client_site_name);
648                 BAIL_ON_PTR_ERROR(i->client_site_name, wbc_status);
649         } else {
650                 i->client_site_name = NULL;
651         }
652
653         *_i = i;
654         i = NULL;
655
656 done:
657         talloc_free(i);
658         return wbc_status;
659 }
660
661 /* Get extended domain controller information */
662 wbcErr wbcLookupDomainControllerEx(const char *domain,
663                                    struct wbcGuid *guid,
664                                    const char *site,
665                                    uint32_t flags,
666                                    struct wbcDomainControllerInfoEx **dc_info)
667 {
668         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
669         struct winbindd_request request;
670         struct winbindd_response response;
671
672         /* validate input params */
673
674         if (!domain || !dc_info) {
675                 wbc_status = WBC_ERR_INVALID_PARAM;
676                 BAIL_ON_WBC_ERROR(wbc_status);
677         }
678
679         ZERO_STRUCT(request);
680         ZERO_STRUCT(response);
681
682         request.data.dsgetdcname.flags = flags;
683
684         strncpy(request.data.dsgetdcname.domain_name, domain,
685                 sizeof(request.data.dsgetdcname.domain_name)-1);
686
687         if (site) {
688                 strncpy(request.data.dsgetdcname.site_name, site,
689                         sizeof(request.data.dsgetdcname.site_name)-1);
690         }
691
692         if (guid) {
693                 char *str = NULL;
694
695                 wbc_status = wbcGuidToString(guid, &str);
696                 BAIL_ON_WBC_ERROR(wbc_status);
697
698                 strncpy(request.data.dsgetdcname.domain_guid, str,
699                         sizeof(request.data.dsgetdcname.domain_guid)-1);
700
701                 wbcFreeMemory(str);
702         }
703
704         /* Send request */
705
706         wbc_status = wbcRequestResponse(WINBINDD_DSGETDCNAME,
707                                         &request,
708                                         &response);
709         BAIL_ON_WBC_ERROR(wbc_status);
710
711         if (dc_info) {
712                 wbc_status = wbc_create_domain_controller_info_ex(NULL,
713                                                                   &response,
714                                                                   dc_info);
715                 BAIL_ON_WBC_ERROR(wbc_status);
716         }
717
718         wbc_status = WBC_ERR_SUCCESS;
719 done:
720         return wbc_status;
721 }
722
723 /* Initialize a named blob and add to list of blobs */
724 wbcErr wbcAddNamedBlob(size_t *num_blobs,
725                        struct wbcNamedBlob **blobs,
726                        const char *name,
727                        uint32_t flags,
728                        uint8_t *data,
729                        size_t length)
730 {
731         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
732         struct wbcNamedBlob blob;
733
734         *blobs = talloc_realloc(NULL, *blobs, struct wbcNamedBlob,
735                                 *(num_blobs)+1);
736         BAIL_ON_PTR_ERROR(*blobs, wbc_status);
737
738         blob.name               = talloc_strdup(*blobs, name);
739         BAIL_ON_PTR_ERROR(blob.name, wbc_status);
740         blob.flags              = flags;
741         blob.blob.length        = length;
742         blob.blob.data          = (uint8_t *)talloc_memdup(*blobs, data, length);
743         BAIL_ON_PTR_ERROR(blob.blob.data, wbc_status);
744
745         (*(blobs))[*num_blobs] = blob;
746         *(num_blobs) += 1;
747
748         wbc_status = WBC_ERR_SUCCESS;
749 done:
750         if (!WBC_ERROR_IS_OK(wbc_status)) {
751                 wbcFreeMemory(*blobs);
752         }
753         return wbc_status;
754 }