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