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