s3: Implement wbcGetSidAliases
[tprouty/samba.git] / nsswitch / libwbclient / wbc_sid.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Winbind client API
5
6    Copyright (C) Gerald (Jerry) Carter 2007
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 /* Convert a binary SID to a character string */
29 wbcErr wbcSidToString(const struct wbcDomainSid *sid,
30                       char **sid_string)
31 {
32         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
33         uint32_t id_auth;
34         int i;
35         char *tmp = NULL;
36
37         if (!sid) {
38                 wbc_status = WBC_ERR_INVALID_SID;
39                 BAIL_ON_WBC_ERROR(wbc_status);
40         }
41
42         id_auth = sid->id_auth[5] +
43                 (sid->id_auth[4] << 8) +
44                 (sid->id_auth[3] << 16) +
45                 (sid->id_auth[2] << 24);
46
47         tmp = talloc_asprintf(NULL, "S-%d-%d", sid->sid_rev_num, id_auth);
48         BAIL_ON_PTR_ERROR(tmp, wbc_status);
49
50         for (i=0; i<sid->num_auths; i++) {
51                 char *tmp2;
52                 tmp2 = talloc_asprintf_append(tmp, "-%u", sid->sub_auths[i]);
53                 BAIL_ON_PTR_ERROR(tmp2, wbc_status);
54
55                 tmp = tmp2;
56         }
57
58         *sid_string = tmp;
59         tmp = NULL;
60
61         wbc_status = WBC_ERR_SUCCESS;
62
63 done:
64         talloc_free(tmp);
65
66         return wbc_status;
67 }
68
69 /* Convert a character string to a binary SID */
70 wbcErr wbcStringToSid(const char *str,
71                       struct wbcDomainSid *sid)
72 {
73         const char *p;
74         char *q;
75         uint32_t x;
76         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
77
78         if (!sid) {
79                 wbc_status = WBC_ERR_INVALID_PARAM;
80                 BAIL_ON_WBC_ERROR(wbc_status);
81         }
82
83         /* Sanity check for either "S-" or "s-" */
84
85         if (!str
86             || (str[0]!='S' && str[0]!='s')
87             || (str[1]!='-'))
88         {
89                 wbc_status = WBC_ERR_INVALID_PARAM;
90                 BAIL_ON_WBC_ERROR(wbc_status);
91         }
92
93         /* Get the SID revision number */
94
95         p = str+2;
96         x = (uint32_t)strtol(p, &q, 10);
97         if (x==0 || !q || *q!='-') {
98                 wbc_status = WBC_ERR_INVALID_SID;
99                 BAIL_ON_WBC_ERROR(wbc_status);
100         }
101         sid->sid_rev_num = (uint8_t)x;
102
103         /* Next the Identifier Authority.  This is stored in big-endian
104            in a 6 byte array. */
105
106         p = q+1;
107         x = (uint32_t)strtol(p, &q, 10);
108         if (!q || *q!='-') {
109                 wbc_status = WBC_ERR_INVALID_SID;
110                 BAIL_ON_WBC_ERROR(wbc_status);
111         }
112         sid->id_auth[5] = (x & 0x000000ff);
113         sid->id_auth[4] = (x & 0x0000ff00) >> 8;
114         sid->id_auth[3] = (x & 0x00ff0000) >> 16;
115         sid->id_auth[2] = (x & 0xff000000) >> 24;
116         sid->id_auth[1] = 0;
117         sid->id_auth[0] = 0;
118
119         /* now read the the subauthorities */
120
121         p = q +1;
122         sid->num_auths = 0;
123         while (sid->num_auths < WBC_MAXSUBAUTHS) {
124                 x=(uint32_t)strtoul(p, &q, 10);
125                 if (p == q)
126                         break;
127                 if (q == NULL) {
128                         wbc_status = WBC_ERR_INVALID_SID;
129                         BAIL_ON_WBC_ERROR(wbc_status);
130                 }
131                 sid->sub_auths[sid->num_auths++] = x;
132
133                 if ((*q!='-') || (*q=='\0'))
134                         break;
135                 p = q + 1;
136         }
137
138         /* IF we ended early, then the SID could not be converted */
139
140         if (q && *q!='\0') {
141                 wbc_status = WBC_ERR_INVALID_SID;
142                 BAIL_ON_WBC_ERROR(wbc_status);
143         }
144
145         wbc_status = WBC_ERR_SUCCESS;
146
147 done:
148         return wbc_status;
149
150 }
151
152 /* Convert a domain and name to SID */
153 wbcErr wbcLookupName(const char *domain,
154                      const char *name,
155                      struct wbcDomainSid *sid,
156                      enum wbcSidType *name_type)
157 {
158         struct winbindd_request request;
159         struct winbindd_response response;
160         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
161
162         if (!sid || !name_type) {
163                 wbc_status = WBC_ERR_INVALID_PARAM;
164                 BAIL_ON_WBC_ERROR(wbc_status);
165         }
166
167         /* Initialize request */
168
169         ZERO_STRUCT(request);
170         ZERO_STRUCT(response);
171
172         /* dst is already null terminated from the memset above */
173
174         strncpy(request.data.name.dom_name, domain,
175                 sizeof(request.data.name.dom_name)-1);
176         strncpy(request.data.name.name, name,
177                 sizeof(request.data.name.name)-1);
178
179         wbc_status = wbcRequestResponse(WINBINDD_LOOKUPNAME,
180                                         &request,
181                                         &response);
182         BAIL_ON_WBC_ERROR(wbc_status);
183
184         wbc_status = wbcStringToSid(response.data.sid.sid, sid);
185         BAIL_ON_WBC_ERROR(wbc_status);
186
187         *name_type = (enum wbcSidType)response.data.sid.type;
188
189         wbc_status = WBC_ERR_SUCCESS;
190
191  done:
192         return wbc_status;
193 }
194
195 /* Convert a SID to a domain and name */
196 wbcErr wbcLookupSid(const struct wbcDomainSid *sid,
197                     char **pdomain,
198                     char **pname,
199                     enum wbcSidType *pname_type)
200 {
201         struct winbindd_request request;
202         struct winbindd_response response;
203         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
204         char *sid_string = NULL;
205         char *domain = NULL;
206         char *name = NULL;
207         enum wbcSidType name_type = WBC_SID_NAME_USE_NONE;
208
209         if (!sid) {
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         /* dst is already null terminated from the memset above */
220
221         wbc_status = wbcSidToString(sid, &sid_string);
222         BAIL_ON_WBC_ERROR(wbc_status);
223
224         strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
225         wbcFreeMemory(sid_string);
226
227         /* Make request */
228
229         wbc_status = wbcRequestResponse(WINBINDD_LOOKUPSID,
230                                            &request,
231                                            &response);
232         BAIL_ON_WBC_ERROR(wbc_status);
233
234         /* Copy out result */
235
236         domain = talloc_strdup(NULL, response.data.name.dom_name);
237         BAIL_ON_PTR_ERROR(domain, wbc_status);
238
239         name = talloc_strdup(NULL, response.data.name.name);
240         BAIL_ON_PTR_ERROR(name, wbc_status);
241
242         name_type = (enum wbcSidType)response.data.name.type;
243
244         wbc_status = WBC_ERR_SUCCESS;
245
246  done:
247         if (WBC_ERROR_IS_OK(wbc_status)) {
248                 if (pdomain != NULL) {
249                         *pdomain = domain;
250                 }
251                 if (pname != NULL) {
252                         *pname = name;
253                 }
254                 if (pname_type != NULL) {
255                         *pname_type = name_type;
256                 }
257         }
258         else {
259 #if 0
260                 /*
261                  * Found by Coverity: In this particular routine we can't end
262                  * up here with a non-NULL name. Further up there are just two
263                  * exit paths that lead here, neither of which leave an
264                  * allocated name. If you add more paths up there, re-activate
265                  * this.
266                  */
267                 if (name != NULL) {
268                         talloc_free(name);
269                 }
270 #endif
271                 if (domain != NULL) {
272                         talloc_free(domain);
273                 }
274         }
275
276         return wbc_status;
277 }
278
279 /* Translate a collection of RIDs within a domain to names */
280
281 wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid,
282                      int num_rids,
283                      uint32_t *rids,
284                      const char **pp_domain_name,
285                      const char ***pnames,
286                      enum wbcSidType **ptypes)
287 {
288         size_t i, len, ridbuf_size;
289         char *ridlist;
290         char *p;
291         struct winbindd_request request;
292         struct winbindd_response response;
293         char *sid_string = NULL;
294         char *domain_name = NULL;
295         const char **names = NULL;
296         enum wbcSidType *types = NULL;
297         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
298
299         /* Initialise request */
300
301         ZERO_STRUCT(request);
302         ZERO_STRUCT(response);
303
304         if (!dom_sid || (num_rids == 0)) {
305                 wbc_status = WBC_ERR_INVALID_PARAM;
306                 BAIL_ON_WBC_ERROR(wbc_status);
307         }
308
309         wbc_status = wbcSidToString(dom_sid, &sid_string);
310         BAIL_ON_WBC_ERROR(wbc_status);
311
312         strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
313         wbcFreeMemory(sid_string);
314
315         /* Even if all the Rids were of maximum 32bit values,
316            we would only have 11 bytes per rid in the final array
317            ("4294967296" + \n).  Add one more byte for the
318            terminating '\0' */
319
320         ridbuf_size = (sizeof(char)*11) * num_rids + 1;
321
322         ridlist = talloc_zero_array(NULL, char, ridbuf_size);
323         BAIL_ON_PTR_ERROR(ridlist, wbc_status);
324
325         len = 0;
326         for (i=0; i<num_rids && (len-1)>0; i++) {
327                 char ridstr[12];
328
329                 len = strlen(ridlist);
330                 p = ridlist + len;
331
332                 snprintf( ridstr, sizeof(ridstr)-1, "%u\n", rids[i]);
333                 strncat(p, ridstr, ridbuf_size-len-1);
334         }
335
336         request.extra_data.data = ridlist;
337         request.extra_len = strlen(ridlist)+1;
338
339         wbc_status = wbcRequestResponse(WINBINDD_LOOKUPRIDS,
340                                         &request,
341                                         &response);
342         talloc_free(ridlist);
343         BAIL_ON_WBC_ERROR(wbc_status);
344
345         domain_name = talloc_strdup(NULL, response.data.domain_name);
346         BAIL_ON_PTR_ERROR(domain_name, wbc_status);
347
348         names = talloc_array(NULL, const char*, num_rids);
349         BAIL_ON_PTR_ERROR(names, wbc_status);
350
351         types = talloc_array(NULL, enum wbcSidType, num_rids);
352         BAIL_ON_PTR_ERROR(types, wbc_status);
353
354         p = (char *)response.extra_data.data;
355
356         for (i=0; i<num_rids; i++) {
357                 char *q;
358
359                 if (*p == '\0') {
360                         wbc_status = WBC_ERR_INVALID_RESPONSE;
361                         BAIL_ON_WBC_ERROR(wbc_status);
362                 }
363
364                 types[i] = (enum wbcSidType)strtoul(p, &q, 10);
365
366                 if (*q != ' ') {
367                         wbc_status = WBC_ERR_INVALID_RESPONSE;
368                         BAIL_ON_WBC_ERROR(wbc_status);
369                 }
370
371                 p = q+1;
372
373                 if ((q = strchr(p, '\n')) == NULL) {
374                         wbc_status = WBC_ERR_INVALID_RESPONSE;
375                         BAIL_ON_WBC_ERROR(wbc_status);
376                 }
377
378                 *q = '\0';
379
380                 names[i] = talloc_strdup(names, p);
381                 BAIL_ON_PTR_ERROR(names[i], wbc_status);
382
383                 p = q+1;
384         }
385
386         if (*p != '\0') {
387                 wbc_status = WBC_ERR_INVALID_RESPONSE;
388                 BAIL_ON_WBC_ERROR(wbc_status);
389         }
390
391         wbc_status = WBC_ERR_SUCCESS;
392
393  done:
394         if (response.extra_data.data) {
395                 free(response.extra_data.data);
396         }
397
398         if (WBC_ERROR_IS_OK(wbc_status)) {
399                 *pp_domain_name = domain_name;
400                 *pnames = names;
401                 *ptypes = types;
402         }
403         else {
404                 if (domain_name)
405                         talloc_free(domain_name);
406                 if (names)
407                         talloc_free(names);
408                 if (types)
409                         talloc_free(types);
410         }
411
412         return wbc_status;
413 }
414
415 /* Get the groups a user belongs to */
416 wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid,
417                          bool domain_groups_only,
418                          uint32_t *num_sids,
419                          struct wbcDomainSid **_sids)
420 {
421         uint32_t i;
422         const char *s;
423         struct winbindd_request request;
424         struct winbindd_response response;
425         char *sid_string = NULL;
426         struct wbcDomainSid *sids = NULL;
427         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
428         int cmd;
429
430         /* Initialise request */
431
432         ZERO_STRUCT(request);
433         ZERO_STRUCT(response);
434
435         if (!user_sid) {
436                 wbc_status = WBC_ERR_INVALID_PARAM;
437                 BAIL_ON_WBC_ERROR(wbc_status);
438         }
439
440         wbc_status = wbcSidToString(user_sid, &sid_string);
441         BAIL_ON_WBC_ERROR(wbc_status);
442
443         strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
444         wbcFreeMemory(sid_string);
445
446         if (domain_groups_only) {
447                 cmd = WINBINDD_GETUSERDOMGROUPS;
448         } else {
449                 cmd = WINBINDD_GETUSERSIDS;
450         }
451
452         wbc_status = wbcRequestResponse(cmd,
453                                         &request,
454                                         &response);
455         BAIL_ON_WBC_ERROR(wbc_status);
456
457         if (response.data.num_entries &&
458             !response.extra_data.data) {
459                 wbc_status = WBC_ERR_INVALID_RESPONSE;
460                 BAIL_ON_WBC_ERROR(wbc_status);
461         }
462
463         sids = talloc_array(NULL, struct wbcDomainSid,
464                             response.data.num_entries);
465         BAIL_ON_PTR_ERROR(sids, wbc_status);
466
467         s = (const char *)response.extra_data.data;
468         for (i = 0; i < response.data.num_entries; i++) {
469                 char *n = strchr(s, '\n');
470                 if (n) {
471                         *n = '\0';
472                 }
473                 wbc_status = wbcStringToSid(s, &sids[i]);
474                 BAIL_ON_WBC_ERROR(wbc_status);
475                 s += strlen(s) + 1;
476         }
477
478         *num_sids = response.data.num_entries;
479         *_sids = sids;
480         sids = NULL;
481         wbc_status = WBC_ERR_SUCCESS;
482
483  done:
484         if (response.extra_data.data) {
485                 free(response.extra_data.data);
486         }
487         if (sids) {
488                 talloc_free(sids);
489         }
490
491         return wbc_status;
492 }
493
494 static inline
495 wbcErr _sid_to_rid(struct wbcDomainSid *sid, uint32_t *rid)
496 {
497         if (sid->num_auths < 1) {
498                 return WBC_ERR_INVALID_RESPONSE;
499         }
500         *rid = sid->sub_auths[sid->num_auths - 1];
501
502         return WBC_ERR_SUCCESS;
503 }
504
505 /* Get alias membership for sids */
506 wbcErr wbcGetSidAliases(const struct wbcDomainSid *dom_sid,
507                         struct wbcDomainSid *sids,
508                         uint32_t num_sids,
509                         uint32_t **alias_rids,
510                         uint32_t *num_alias_rids)
511 {
512         uint32_t i;
513         const char *s;
514         struct winbindd_request request;
515         struct winbindd_response response;
516         char *sid_string = NULL;
517         ssize_t sid_len;
518         ssize_t extra_data_len = 0;
519         char * extra_data = NULL;
520         ssize_t buflen = 0;
521         struct wbcDomainSid sid;
522         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
523         uint32_t * rids = NULL;
524
525         /* Initialise request */
526
527         ZERO_STRUCT(request);
528         ZERO_STRUCT(response);
529
530         if (!dom_sid) {
531                 wbc_status = WBC_ERR_INVALID_PARAM;
532                 BAIL_ON_WBC_ERROR(wbc_status);
533         }
534
535         wbc_status = wbcSidToString(dom_sid, &sid_string);
536         BAIL_ON_WBC_ERROR(wbc_status);
537
538         strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
539         wbcFreeMemory(sid_string);
540         sid_string = NULL;
541
542         /* Lets assume each sid is around 54 characters
543          * S-1-5-AAAAAAAAAAA-BBBBBBBBBBB-CCCCCCCCCCC-DDDDDDDDDDD\n */
544         buflen = 54 * num_sids;
545         extra_data = talloc_array(NULL, char, buflen);
546         if (!extra_data) {
547                 wbc_status = WBC_ERR_NO_MEMORY;
548                 BAIL_ON_WBC_ERROR(wbc_status);
549         }
550
551         /* Build the sid list */
552         for (i=0; i<num_sids; i++) {
553                 if (sid_string) {
554                         wbcFreeMemory(sid_string);
555                         sid_string = NULL;
556                 }
557                 wbc_status = wbcSidToString(&sids[i], &sid_string);
558                 BAIL_ON_WBC_ERROR(wbc_status);
559
560                 sid_len = strlen(sid_string);
561
562                 if (buflen < extra_data_len + sid_len + 2) {
563                         buflen *= 2;
564                         extra_data = talloc_realloc(NULL, extra_data,
565                             char, buflen);
566                         if (!extra_data) {
567                                 wbc_status = WBC_ERR_NO_MEMORY;
568                                 BAIL_ON_WBC_ERROR(wbc_status);
569                         }
570                 }
571
572                 strncpy(&extra_data[extra_data_len], sid_string,
573                         buflen - extra_data_len);
574                 extra_data_len += sid_len;
575                 extra_data[extra_data_len++] = '\n';
576                 extra_data[extra_data_len] = '\0';
577         }
578
579         request.extra_data.data = extra_data;
580         request.extra_len = extra_data_len;
581
582         wbc_status = wbcRequestResponse(WINBINDD_GETSIDALIASES,
583                                         &request,
584                                         &response);
585         BAIL_ON_WBC_ERROR(wbc_status);
586
587         if (response.data.num_entries &&
588             !response.extra_data.data) {
589                 wbc_status = WBC_ERR_INVALID_RESPONSE;
590                 BAIL_ON_WBC_ERROR(wbc_status);
591         }
592
593         rids = talloc_array(NULL, uint32_t,
594                             response.data.num_entries);
595         BAIL_ON_PTR_ERROR(sids, wbc_status);
596
597         s = (const char *)response.extra_data.data;
598         for (i = 0; i < response.data.num_entries; i++) {
599                 char *n = strchr(s, '\n');
600                 if (n) {
601                         *n = '\0';
602                 }
603                 wbc_status = wbcStringToSid(s, &sid);
604                 BAIL_ON_WBC_ERROR(wbc_status);
605                 wbc_status = _sid_to_rid(&sid, &rids[i]);
606                 BAIL_ON_WBC_ERROR(wbc_status);
607                 s += strlen(s) + 1;
608         }
609
610         *num_alias_rids = response.data.num_entries;
611         *alias_rids = rids;
612         rids = NULL;
613         wbc_status = WBC_ERR_SUCCESS;
614
615  done:
616         if (sid_string) {
617                 wbcFreeMemory(sid_string);
618         }
619         if (extra_data) {
620                 talloc_free(extra_data);
621         }
622         if (response.extra_data.data) {
623                 free(response.extra_data.data);
624         }
625         if (rids) {
626                 talloc_free(rids);
627         }
628
629         return wbc_status;
630 }
631
632
633 /* Lists Users */
634 wbcErr wbcListUsers(const char *domain_name,
635                     uint32_t *_num_users,
636                     const char ***_users)
637 {
638         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
639         struct winbindd_request request;
640         struct winbindd_response response;
641         uint32_t num_users = 0;
642         const char **users = NULL;
643         const char *next;
644
645         /* Initialise request */
646
647         ZERO_STRUCT(request);
648         ZERO_STRUCT(response);
649
650         if (domain_name) {
651                 strncpy(request.domain_name, domain_name,
652                         sizeof(request.domain_name)-1);
653         }
654
655         wbc_status = wbcRequestResponse(WINBINDD_LIST_USERS,
656                                         &request,
657                                         &response);
658         BAIL_ON_WBC_ERROR(wbc_status);
659
660         /* Look through extra data */
661
662         next = (const char *)response.extra_data.data;
663         while (next) {
664                 const char **tmp;
665                 const char *current = next;
666                 char *k = strchr(next, ',');
667                 if (k) {
668                         k[0] = '\0';
669                         next = k+1;
670                 } else {
671                         next = NULL;
672                 }
673
674                 tmp = talloc_realloc(NULL, users,
675                                      const char *,
676                                      num_users+1);
677                 BAIL_ON_PTR_ERROR(tmp, wbc_status);
678                 users = tmp;
679
680                 users[num_users] = talloc_strdup(users, current);
681                 BAIL_ON_PTR_ERROR(users[num_users], wbc_status);
682
683                 num_users++;
684         }
685
686         *_num_users = num_users;
687         *_users = users;
688         users = NULL;
689         wbc_status = WBC_ERR_SUCCESS;
690
691  done:
692         if (response.extra_data.data) {
693                 free(response.extra_data.data);
694         }
695         if (users) {
696                 talloc_free(users);
697         }
698         return wbc_status;
699 }
700
701 /* Lists Groups */
702 wbcErr wbcListGroups(const char *domain_name,
703                      uint32_t *_num_groups,
704                      const char ***_groups)
705 {
706         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
707         struct winbindd_request request;
708         struct winbindd_response response;
709         uint32_t num_groups = 0;
710         const char **groups = NULL;
711         const char *next;
712
713         /* Initialise request */
714
715         ZERO_STRUCT(request);
716         ZERO_STRUCT(response);
717
718         if (domain_name) {
719                 strncpy(request.domain_name, domain_name,
720                         sizeof(request.domain_name)-1);
721         }
722
723         wbc_status = wbcRequestResponse(WINBINDD_LIST_GROUPS,
724                                         &request,
725                                         &response);
726         BAIL_ON_WBC_ERROR(wbc_status);
727
728         /* Look through extra data */
729
730         next = (const char *)response.extra_data.data;
731         while (next) {
732                 const char **tmp;
733                 const char *current = next;
734                 char *k = strchr(next, ',');
735                 if (k) {
736                         k[0] = '\0';
737                         next = k+1;
738                 } else {
739                         next = NULL;
740                 }
741
742                 tmp = talloc_realloc(NULL, groups,
743                                      const char *,
744                                      num_groups+1);
745                 BAIL_ON_PTR_ERROR(tmp, wbc_status);
746                 groups = tmp;
747
748                 groups[num_groups] = talloc_strdup(groups, current);
749                 BAIL_ON_PTR_ERROR(groups[num_groups], wbc_status);
750
751                 num_groups++;
752         }
753
754         *_num_groups = num_groups;
755         *_groups = groups;
756         groups = NULL;
757         wbc_status = WBC_ERR_SUCCESS;
758
759  done:
760         if (response.extra_data.data) {
761                 free(response.extra_data.data);
762         }
763         if (groups) {
764                 talloc_free(groups);
765         }
766         return wbc_status;
767 }
768
769 wbcErr wbcGetDisplayName(const struct wbcDomainSid *sid,
770                          char **pdomain,
771                          char **pfullname,
772                          enum wbcSidType *pname_type)
773 {
774         wbcErr wbc_status;
775         char *domain = NULL;
776         char *name = NULL;
777         enum wbcSidType name_type;
778
779         wbc_status = wbcLookupSid(sid, &domain, &name, &name_type);
780         BAIL_ON_WBC_ERROR(wbc_status);
781
782         if (name_type == WBC_SID_NAME_USER) {
783                 uid_t uid;
784                 struct passwd *pwd;
785
786                 wbc_status = wbcSidToUid(sid, &uid);
787                 BAIL_ON_WBC_ERROR(wbc_status);
788
789                 wbc_status = wbcGetpwuid(uid, &pwd);
790                 BAIL_ON_WBC_ERROR(wbc_status);
791
792                 wbcFreeMemory(name);
793
794                 name = talloc_strdup(NULL, pwd->pw_gecos);
795                 BAIL_ON_PTR_ERROR(name, wbc_status);
796         }
797
798         wbc_status = WBC_ERR_SUCCESS;
799
800  done:
801         if (WBC_ERROR_IS_OK(wbc_status)) {
802                 *pdomain = domain;
803                 *pfullname = name;
804                 *pname_type = name_type;
805         } else {
806                 wbcFreeMemory(domain);
807                 wbcFreeMemory(name);
808         }
809
810         return wbc_status;
811 }