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