wbclient: fix conversion logic in wbcSidToStringBuf
[kai/samba-autobuild/.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         uint64_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         id_auth = (uint64_t)sid->id_auth[5] +
44                 ((uint64_t)sid->id_auth[4] << 8) +
45                 ((uint64_t)sid->id_auth[3] << 16) +
46                 ((uint64_t)sid->id_auth[2] << 24) +
47                 ((uint64_t)sid->id_auth[1] << 32) +
48                 ((uint64_t)sid->id_auth[0] << 40);
49
50         ofs = snprintf(buf, buflen, "S-%hhu-", (unsigned char)sid->sid_rev_num);
51         if (id_auth >= UINT32_MAX) {
52                 ofs += snprintf(buf + ofs, MAX(buflen - ofs, 0), "0x%llx",
53                                 (unsigned long long)id_auth);
54         } else {
55                 ofs += snprintf(buf + ofs, MAX(buflen - ofs, 0), "%llu",
56                                 (unsigned long long)id_auth);
57         }
58
59         for (i = 0; i < sid->num_auths; i++) {
60                 ofs += snprintf(buf + ofs, MAX(buflen - ofs, 0), "-%u",
61                                 (unsigned int)sid->sub_auths[i]);
62         }
63         return ofs;
64 }
65
66 /* Convert a binary SID to a character string */
67 wbcErr wbcSidToString(const struct wbcDomainSid *sid,
68                       char **sid_string)
69 {
70         char buf[WBC_SID_STRING_BUFLEN];
71         char *result;
72         int len;
73
74         if (!sid) {
75                 return WBC_ERR_INVALID_SID;
76         }
77
78         len = wbcSidToStringBuf(sid, buf, sizeof(buf));
79
80         if (len+1 > sizeof(buf)) {
81                 return WBC_ERR_INVALID_SID;
82         }
83
84         result = (char *)wbcAllocateMemory(len+1, 1, NULL);
85         if (result == NULL) {
86                 return WBC_ERR_NO_MEMORY;
87         }
88         memcpy(result, buf, len+1);
89
90         *sid_string = result;
91         return WBC_ERR_SUCCESS;
92 }
93
94 #define AUTHORITY_MASK  (~(0xffffffffffffULL))
95
96 /* Convert a character string to a binary SID */
97 wbcErr wbcStringToSid(const char *str,
98                       struct wbcDomainSid *sid)
99 {
100         const char *p;
101         char *q;
102         uint64_t x;
103         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
104
105         if (!sid) {
106                 wbc_status = WBC_ERR_INVALID_PARAM;
107                 BAIL_ON_WBC_ERROR(wbc_status);
108         }
109
110         /* Sanity check for either "S-" or "s-" */
111
112         if (!str
113             || (str[0]!='S' && str[0]!='s')
114             || (str[1]!='-'))
115         {
116                 wbc_status = WBC_ERR_INVALID_PARAM;
117                 BAIL_ON_WBC_ERROR(wbc_status);
118         }
119
120         /* Get the SID revision number */
121
122         p = str+2;
123         x = (uint64_t)strtoul(p, &q, 10);
124         if (x==0 || x > UINT8_MAX || !q || *q!='-') {
125                 wbc_status = WBC_ERR_INVALID_SID;
126                 BAIL_ON_WBC_ERROR(wbc_status);
127         }
128         sid->sid_rev_num = (uint8_t)x;
129
130         /*
131          * Next the Identifier Authority.  This is stored big-endian in a
132          * 6 byte array. If the authority value is >= UINT_MAX, then it should
133          * be expressed as a hex value, according to MS-DTYP.
134          */
135         p = q+1;
136         x = strtoull(p, &q, 0);
137         if (!q || *q!='-' || (x & AUTHORITY_MASK)) {
138                 wbc_status = WBC_ERR_INVALID_SID;
139                 BAIL_ON_WBC_ERROR(wbc_status);
140         }
141         sid->id_auth[5] = (x & 0x0000000000ffULL);
142         sid->id_auth[4] = (x & 0x00000000ff00ULL) >> 8;
143         sid->id_auth[3] = (x & 0x000000ff0000ULL) >> 16;
144         sid->id_auth[2] = (x & 0x0000ff000000ULL) >> 24;
145         sid->id_auth[1] = (x & 0x00ff00000000ULL) >> 32;
146         sid->id_auth[0] = (x & 0xff0000000000ULL) >> 40;
147
148         /* now read the the subauthorities */
149         p = q +1;
150         sid->num_auths = 0;
151         while (sid->num_auths < WBC_MAXSUBAUTHS) {
152                 x = strtoull(p, &q, 10);
153                 if (p == q)
154                         break;
155                 if (x > UINT32_MAX) {
156                         wbc_status = WBC_ERR_INVALID_SID;
157                         BAIL_ON_WBC_ERROR(wbc_status);
158                 }
159                 sid->sub_auths[sid->num_auths++] = x;
160
161                 if (*q != '-') {
162                         break;
163                 }
164                 p = q + 1;
165         }
166
167         /* IF we ended early, then the SID could not be converted */
168
169         if (q && *q!='\0') {
170                 wbc_status = WBC_ERR_INVALID_SID;
171                 BAIL_ON_WBC_ERROR(wbc_status);
172         }
173
174         wbc_status = WBC_ERR_SUCCESS;
175
176 done:
177         return wbc_status;
178
179 }
180
181
182 /* Convert a domain and name to SID */
183 wbcErr wbcLookupName(const char *domain,
184                      const char *name,
185                      struct wbcDomainSid *sid,
186                      enum wbcSidType *name_type)
187 {
188         struct winbindd_request request;
189         struct winbindd_response response;
190         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
191
192         if (!sid || !name_type) {
193                 wbc_status = WBC_ERR_INVALID_PARAM;
194                 BAIL_ON_WBC_ERROR(wbc_status);
195         }
196
197         /* Initialize request */
198
199         ZERO_STRUCT(request);
200         ZERO_STRUCT(response);
201
202         /* dst is already null terminated from the memset above */
203
204         strncpy(request.data.name.dom_name, domain,
205                 sizeof(request.data.name.dom_name)-1);
206         strncpy(request.data.name.name, name,
207                 sizeof(request.data.name.name)-1);
208
209         wbc_status = wbcRequestResponse(WINBINDD_LOOKUPNAME,
210                                         &request,
211                                         &response);
212         BAIL_ON_WBC_ERROR(wbc_status);
213
214         wbc_status = wbcStringToSid(response.data.sid.sid, sid);
215         BAIL_ON_WBC_ERROR(wbc_status);
216
217         *name_type = (enum wbcSidType)response.data.sid.type;
218
219         wbc_status = WBC_ERR_SUCCESS;
220
221  done:
222         return wbc_status;
223 }
224
225
226 /* Convert a SID to a domain and name */
227 wbcErr wbcLookupSid(const struct wbcDomainSid *sid,
228                     char **pdomain,
229                     char **pname,
230                     enum wbcSidType *pname_type)
231 {
232         struct winbindd_request request;
233         struct winbindd_response response;
234         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
235         char *domain, *name;
236
237         if (!sid) {
238                 return WBC_ERR_INVALID_PARAM;
239         }
240
241         /* Initialize request */
242
243         ZERO_STRUCT(request);
244         ZERO_STRUCT(response);
245
246         wbcSidToStringBuf(sid, request.data.sid, sizeof(request.data.sid));
247
248         /* Make request */
249
250         wbc_status = wbcRequestResponse(WINBINDD_LOOKUPSID, &request,
251                                         &response);
252         if (!WBC_ERROR_IS_OK(wbc_status)) {
253                 return wbc_status;
254         }
255
256         /* Copy out result */
257
258         wbc_status = WBC_ERR_NO_MEMORY;
259         domain = NULL;
260         name = NULL;
261
262         domain = wbcStrDup(response.data.name.dom_name);
263         if (domain == NULL) {
264                 goto done;
265         }
266         name = wbcStrDup(response.data.name.name);
267         if (name == NULL) {
268                 goto done;
269         }
270         if (pdomain != NULL) {
271                 *pdomain = domain;
272                 domain = NULL;
273         }
274         if (pname != NULL) {
275                 *pname = name;
276                 name = NULL;
277         }
278         if (pname_type != NULL) {
279                 *pname_type = (enum wbcSidType)response.data.name.type;
280         }
281         wbc_status = WBC_ERR_SUCCESS;
282 done:
283         wbcFreeMemory(name);
284         wbcFreeMemory(domain);
285         return wbc_status;
286 }
287
288 static void wbcDomainInfosDestructor(void *ptr)
289 {
290         struct wbcDomainInfo *i = (struct wbcDomainInfo *)ptr;
291
292         while (i->short_name != NULL) {
293                 wbcFreeMemory(i->short_name);
294                 wbcFreeMemory(i->dns_name);
295                 i += 1;
296         }
297 }
298
299 static void wbcTranslatedNamesDestructor(void *ptr)
300 {
301         struct wbcTranslatedName *n = (struct wbcTranslatedName *)ptr;
302
303         while (n->name != NULL) {
304                 wbcFreeMemory(n->name);
305                 n += 1;
306         }
307 }
308
309 wbcErr wbcLookupSids(const struct wbcDomainSid *sids, int num_sids,
310                      struct wbcDomainInfo **pdomains, int *pnum_domains,
311                      struct wbcTranslatedName **pnames)
312 {
313         struct winbindd_request request;
314         struct winbindd_response response;
315         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
316         int buflen, i, extra_len, num_domains, num_names;
317         char *sidlist, *p, *q, *extra_data;
318         struct wbcDomainInfo *domains = NULL;
319         struct wbcTranslatedName *names = NULL;
320
321         buflen = num_sids * (WBC_SID_STRING_BUFLEN + 1) + 1;
322
323         sidlist = (char *)malloc(buflen);
324         if (sidlist == NULL) {
325                 return WBC_ERR_NO_MEMORY;
326         }
327
328         p = sidlist;
329
330         for (i=0; i<num_sids; i++) {
331                 int remaining;
332                 int len;
333
334                 remaining = buflen - (p - sidlist);
335
336                 len = wbcSidToStringBuf(&sids[i], p, remaining);
337                 if (len > remaining) {
338                         free(sidlist);
339                         return WBC_ERR_UNKNOWN_FAILURE;
340                 }
341
342                 p += len;
343                 *p++ = '\n';
344         }
345         *p++ = '\0';
346
347         ZERO_STRUCT(request);
348         ZERO_STRUCT(response);
349
350         request.extra_data.data = sidlist;
351         request.extra_len = p - sidlist;
352
353         wbc_status = wbcRequestResponse(WINBINDD_LOOKUPSIDS,
354                                         &request, &response);
355         free(sidlist);
356         if (!WBC_ERROR_IS_OK(wbc_status)) {
357                 return wbc_status;
358         }
359
360         extra_len = response.length - sizeof(struct winbindd_response);
361         extra_data = (char *)response.extra_data.data;
362
363         if ((extra_len <= 0) || (extra_data[extra_len-1] != '\0')) {
364                 goto wbc_err_invalid;
365         }
366
367         p = extra_data;
368
369         num_domains = strtoul(p, &q, 10);
370         if (*q != '\n') {
371                 goto wbc_err_invalid;
372         }
373         p = q+1;
374
375         domains = (struct wbcDomainInfo *)wbcAllocateMemory(
376                 num_domains+1, sizeof(struct wbcDomainInfo),
377                 wbcDomainInfosDestructor);
378         if (domains == NULL) {
379                 wbc_status = WBC_ERR_NO_MEMORY;
380                 goto fail;
381         }
382
383         for (i=0; i<num_domains; i++) {
384
385                 q = strchr(p, ' ');
386                 if (q == NULL) {
387                         goto wbc_err_invalid;
388                 }
389                 *q = '\0';
390                 wbc_status = wbcStringToSid(p, &domains[i].sid);
391                 if (!WBC_ERROR_IS_OK(wbc_status)) {
392                         goto fail;
393                 }
394                 p = q+1;
395
396                 q = strchr(p, '\n');
397                 if (q == NULL) {
398                         goto wbc_err_invalid;
399                 }
400                 *q = '\0';
401                 domains[i].short_name = wbcStrDup(p);
402                 if (domains[i].short_name == NULL) {
403                         wbc_status = WBC_ERR_NO_MEMORY;
404                         goto fail;
405                 }
406                 p = q+1;
407         }
408
409         num_names = strtoul(p, &q, 10);
410         if (*q != '\n') {
411                 goto wbc_err_invalid;
412         }
413         p = q+1;
414
415         if (num_names != num_sids) {
416                 goto wbc_err_invalid;
417         }
418
419         names = (struct wbcTranslatedName *)wbcAllocateMemory(
420                 num_names+1, sizeof(struct wbcTranslatedName),
421                 wbcTranslatedNamesDestructor);
422         if (names == NULL) {
423                 wbc_status = WBC_ERR_NO_MEMORY;
424                 goto fail;
425         }
426
427         for (i=0; i<num_names; i++) {
428
429                 names[i].domain_index = strtoul(p, &q, 10);
430                 if (*q != ' ') {
431                         goto wbc_err_invalid;
432                 }
433                 p = q+1;
434
435                 names[i].type = strtoul(p, &q, 10);
436                 if (*q != ' ') {
437                         goto wbc_err_invalid;
438                 }
439                 p = q+1;
440
441                 q = strchr(p, '\n');
442                 if (q == NULL) {
443                         goto wbc_err_invalid;
444                 }
445                 *q = '\0';
446                 names[i].name = wbcStrDup(p);
447                 if (names[i].name == NULL) {
448                         wbc_status = WBC_ERR_NO_MEMORY;
449                         goto fail;
450                 }
451                 p = q+1;
452         }
453         if (*p != '\0') {
454                 goto wbc_err_invalid;
455         }
456
457         *pdomains = domains;
458         *pnames = names;
459         winbindd_free_response(&response);
460         return WBC_ERR_SUCCESS;
461
462 wbc_err_invalid:
463         wbc_status = WBC_ERR_INVALID_RESPONSE;
464 fail:
465         winbindd_free_response(&response);
466         wbcFreeMemory(domains);
467         wbcFreeMemory(names);
468         return wbc_status;
469 }
470
471 /* Translate a collection of RIDs within a domain to names */
472
473 wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid,
474                      int num_rids,
475                      uint32_t *rids,
476                      const char **pp_domain_name,
477                      const char ***pnames,
478                      enum wbcSidType **ptypes)
479 {
480         size_t i, len, ridbuf_size;
481         char *ridlist;
482         char *p;
483         struct winbindd_request request;
484         struct winbindd_response response;
485         char *domain_name = NULL;
486         const char **names = NULL;
487         enum wbcSidType *types = NULL;
488         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
489
490         /* Initialise request */
491
492         ZERO_STRUCT(request);
493         ZERO_STRUCT(response);
494
495         if (!dom_sid || (num_rids == 0)) {
496                 wbc_status = WBC_ERR_INVALID_PARAM;
497                 BAIL_ON_WBC_ERROR(wbc_status);
498         }
499
500         wbcSidToStringBuf(dom_sid, request.data.sid, sizeof(request.data.sid));
501
502         /* Even if all the Rids were of maximum 32bit values,
503            we would only have 11 bytes per rid in the final array
504            ("4294967296" + \n).  Add one more byte for the
505            terminating '\0' */
506
507         ridbuf_size = (sizeof(char)*11) * num_rids + 1;
508
509         ridlist = (char *)malloc(ridbuf_size);
510         BAIL_ON_PTR_ERROR(ridlist, wbc_status);
511
512         len = 0;
513         for (i=0; i<num_rids; i++) {
514                 len += snprintf(ridlist + len, ridbuf_size - len, "%u\n",
515                                 rids[i]);
516         }
517         ridlist[len] = '\0';
518         len += 1;
519
520         request.extra_data.data = ridlist;
521         request.extra_len = len;
522
523         wbc_status = wbcRequestResponse(WINBINDD_LOOKUPRIDS,
524                                         &request,
525                                         &response);
526         free(ridlist);
527         BAIL_ON_WBC_ERROR(wbc_status);
528
529         domain_name = wbcStrDup(response.data.domain_name);
530         BAIL_ON_PTR_ERROR(domain_name, wbc_status);
531
532         names = wbcAllocateStringArray(num_rids);
533         BAIL_ON_PTR_ERROR(names, wbc_status);
534
535         types = (enum wbcSidType *)wbcAllocateMemory(
536                 num_rids, sizeof(enum wbcSidType), NULL);
537         BAIL_ON_PTR_ERROR(types, wbc_status);
538
539         p = (char *)response.extra_data.data;
540
541         for (i=0; i<num_rids; i++) {
542                 char *q;
543
544                 if (*p == '\0') {
545                         wbc_status = WBC_ERR_INVALID_RESPONSE;
546                         goto done;
547                 }
548
549                 types[i] = (enum wbcSidType)strtoul(p, &q, 10);
550
551                 if (*q != ' ') {
552                         wbc_status = WBC_ERR_INVALID_RESPONSE;
553                         goto done;
554                 }
555
556                 p = q+1;
557
558                 if ((q = strchr(p, '\n')) == NULL) {
559                         wbc_status = WBC_ERR_INVALID_RESPONSE;
560                         goto done;
561                 }
562
563                 *q = '\0';
564
565                 names[i] = strdup(p);
566                 BAIL_ON_PTR_ERROR(names[i], wbc_status);
567
568                 p = q+1;
569         }
570
571         if (*p != '\0') {
572                 wbc_status = WBC_ERR_INVALID_RESPONSE;
573                 goto done;
574         }
575
576         wbc_status = WBC_ERR_SUCCESS;
577
578  done:
579         winbindd_free_response(&response);
580
581         if (WBC_ERROR_IS_OK(wbc_status)) {
582                 *pp_domain_name = domain_name;
583                 *pnames = names;
584                 *ptypes = types;
585         }
586         else {
587                 wbcFreeMemory(domain_name);
588                 wbcFreeMemory(names);
589                 wbcFreeMemory(types);
590         }
591
592         return wbc_status;
593 }
594
595 /* Get the groups a user belongs to */
596 wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid,
597                          bool domain_groups_only,
598                          uint32_t *num_sids,
599                          struct wbcDomainSid **_sids)
600 {
601         uint32_t i;
602         const char *s;
603         struct winbindd_request request;
604         struct winbindd_response response;
605         struct wbcDomainSid *sids = NULL;
606         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
607         int cmd;
608
609         /* Initialise request */
610
611         ZERO_STRUCT(request);
612         ZERO_STRUCT(response);
613
614         if (!user_sid) {
615                 wbc_status = WBC_ERR_INVALID_PARAM;
616                 BAIL_ON_WBC_ERROR(wbc_status);
617         }
618
619         wbcSidToStringBuf(user_sid, request.data.sid, sizeof(request.data.sid));
620
621         if (domain_groups_only) {
622                 cmd = WINBINDD_GETUSERDOMGROUPS;
623         } else {
624                 cmd = WINBINDD_GETUSERSIDS;
625         }
626
627         wbc_status = wbcRequestResponse(cmd,
628                                         &request,
629                                         &response);
630         BAIL_ON_WBC_ERROR(wbc_status);
631
632         if (response.data.num_entries &&
633             !response.extra_data.data) {
634                 wbc_status = WBC_ERR_INVALID_RESPONSE;
635                 BAIL_ON_WBC_ERROR(wbc_status);
636         }
637
638         sids = (struct wbcDomainSid *)wbcAllocateMemory(
639                 response.data.num_entries, sizeof(struct wbcDomainSid),
640                 NULL);
641         BAIL_ON_PTR_ERROR(sids, wbc_status);
642
643         s = (const char *)response.extra_data.data;
644         for (i = 0; i < response.data.num_entries; i++) {
645                 char *n = strchr(s, '\n');
646                 if (n) {
647                         *n = '\0';
648                 }
649                 wbc_status = wbcStringToSid(s, &sids[i]);
650                 BAIL_ON_WBC_ERROR(wbc_status);
651                 s += strlen(s) + 1;
652         }
653
654         *num_sids = response.data.num_entries;
655         *_sids = sids;
656         sids = NULL;
657         wbc_status = WBC_ERR_SUCCESS;
658
659  done:
660         winbindd_free_response(&response);
661         if (sids) {
662                 wbcFreeMemory(sids);
663         }
664
665         return wbc_status;
666 }
667
668 static inline
669 wbcErr _sid_to_rid(struct wbcDomainSid *sid, uint32_t *rid)
670 {
671         if (sid->num_auths < 1) {
672                 return WBC_ERR_INVALID_RESPONSE;
673         }
674         *rid = sid->sub_auths[sid->num_auths - 1];
675
676         return WBC_ERR_SUCCESS;
677 }
678
679 /* Get alias membership for sids */
680 wbcErr wbcGetSidAliases(const struct wbcDomainSid *dom_sid,
681                         struct wbcDomainSid *sids,
682                         uint32_t num_sids,
683                         uint32_t **alias_rids,
684                         uint32_t *num_alias_rids)
685 {
686         uint32_t i;
687         const char *s;
688         struct winbindd_request request;
689         struct winbindd_response response;
690         ssize_t extra_data_len = 0;
691         char * extra_data = NULL;
692         ssize_t buflen = 0;
693         struct wbcDomainSid sid;
694         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
695         uint32_t * rids = NULL;
696
697         /* Initialise request */
698
699         ZERO_STRUCT(request);
700         ZERO_STRUCT(response);
701
702         if (!dom_sid) {
703                 wbc_status = WBC_ERR_INVALID_PARAM;
704                 goto done;
705         }
706
707         wbcSidToStringBuf(dom_sid, request.data.sid, sizeof(request.data.sid));
708
709         /* Lets assume each sid is around 57 characters
710          * S-1-5-21-AAAAAAAAAAA-BBBBBBBBBBB-CCCCCCCCCCC-DDDDDDDDDDD\n */
711         buflen = 57 * num_sids;
712         extra_data = (char *)malloc(buflen);
713         if (!extra_data) {
714                 wbc_status = WBC_ERR_NO_MEMORY;
715                 goto done;
716         }
717
718         /* Build the sid list */
719         for (i=0; i<num_sids; i++) {
720                 char sid_str[WBC_SID_STRING_BUFLEN];
721                 size_t sid_len;
722
723                 sid_len = wbcSidToStringBuf(&sids[i], sid_str, sizeof(sid_str));
724
725                 if (buflen < extra_data_len + sid_len + 2) {
726                         buflen *= 2;
727                         extra_data = (char *)realloc(extra_data, buflen);
728                         if (!extra_data) {
729                                 wbc_status = WBC_ERR_NO_MEMORY;
730                                 BAIL_ON_WBC_ERROR(wbc_status);
731                         }
732                 }
733
734                 strncpy(&extra_data[extra_data_len], sid_str,
735                         buflen - extra_data_len);
736                 extra_data_len += sid_len;
737                 extra_data[extra_data_len++] = '\n';
738                 extra_data[extra_data_len] = '\0';
739         }
740         extra_data_len += 1;
741
742         request.extra_data.data = extra_data;
743         request.extra_len = extra_data_len;
744
745         wbc_status = wbcRequestResponse(WINBINDD_GETSIDALIASES,
746                                         &request,
747                                         &response);
748         BAIL_ON_WBC_ERROR(wbc_status);
749
750         if (response.data.num_entries &&
751             !response.extra_data.data) {
752                 wbc_status = WBC_ERR_INVALID_RESPONSE;
753                 goto done;
754         }
755
756         rids = (uint32_t *)wbcAllocateMemory(response.data.num_entries,
757                                              sizeof(uint32_t), NULL);
758         BAIL_ON_PTR_ERROR(sids, wbc_status);
759
760         s = (const char *)response.extra_data.data;
761         for (i = 0; i < response.data.num_entries; i++) {
762                 char *n = strchr(s, '\n');
763                 if (n) {
764                         *n = '\0';
765                 }
766                 wbc_status = wbcStringToSid(s, &sid);
767                 BAIL_ON_WBC_ERROR(wbc_status);
768                 wbc_status = _sid_to_rid(&sid, &rids[i]);
769                 BAIL_ON_WBC_ERROR(wbc_status);
770                 s += strlen(s) + 1;
771         }
772
773         *num_alias_rids = response.data.num_entries;
774         *alias_rids = rids;
775         rids = NULL;
776         wbc_status = WBC_ERR_SUCCESS;
777
778  done:
779         free(extra_data);
780         winbindd_free_response(&response);
781         wbcFreeMemory(rids);
782         return wbc_status;
783 }
784
785
786 /* Lists Users */
787 wbcErr wbcListUsers(const char *domain_name,
788                     uint32_t *_num_users,
789                     const char ***_users)
790 {
791         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
792         struct winbindd_request request;
793         struct winbindd_response response;
794         uint32_t num_users = 0;
795         const char **users = NULL;
796         const char *next;
797
798         /* Initialise request */
799
800         ZERO_STRUCT(request);
801         ZERO_STRUCT(response);
802
803         if (domain_name) {
804                 strncpy(request.domain_name, domain_name,
805                         sizeof(request.domain_name)-1);
806         }
807
808         wbc_status = wbcRequestResponse(WINBINDD_LIST_USERS,
809                                         &request,
810                                         &response);
811         BAIL_ON_WBC_ERROR(wbc_status);
812
813         users = wbcAllocateStringArray(response.data.num_entries);
814         if (users == NULL) {
815                 return WBC_ERR_NO_MEMORY;
816         }
817
818         /* Look through extra data */
819
820         next = (const char *)response.extra_data.data;
821         while (next) {
822                 const char *current;
823                 char *k;
824
825                 if (num_users >= response.data.num_entries) {
826                         wbc_status = WBC_ERR_INVALID_RESPONSE;
827                         goto done;
828                 }
829
830                 current = next;
831                 k = strchr(next, ',');
832
833                 if (k) {
834                         k[0] = '\0';
835                         next = k+1;
836                 } else {
837                         next = NULL;
838                 }
839
840                 users[num_users] = strdup(current);
841                 BAIL_ON_PTR_ERROR(users[num_users], wbc_status);
842                 num_users += 1;
843         }
844         if (num_users != response.data.num_entries) {
845                 wbc_status = WBC_ERR_INVALID_RESPONSE;
846                 goto done;
847         }
848
849         *_num_users = response.data.num_entries;
850         *_users = users;
851         users = NULL;
852         wbc_status = WBC_ERR_SUCCESS;
853
854  done:
855         winbindd_free_response(&response);
856         wbcFreeMemory(users);
857         return wbc_status;
858 }
859
860 /* Lists Groups */
861 wbcErr wbcListGroups(const char *domain_name,
862                      uint32_t *_num_groups,
863                      const char ***_groups)
864 {
865         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
866         struct winbindd_request request;
867         struct winbindd_response response;
868         uint32_t num_groups = 0;
869         const char **groups = NULL;
870         const char *next;
871
872         /* Initialise request */
873
874         ZERO_STRUCT(request);
875         ZERO_STRUCT(response);
876
877         if (domain_name) {
878                 strncpy(request.domain_name, domain_name,
879                         sizeof(request.domain_name)-1);
880         }
881
882         wbc_status = wbcRequestResponse(WINBINDD_LIST_GROUPS,
883                                         &request,
884                                         &response);
885         BAIL_ON_WBC_ERROR(wbc_status);
886
887         groups = wbcAllocateStringArray(response.data.num_entries);
888         if (groups == NULL) {
889                 return WBC_ERR_NO_MEMORY;
890         }
891
892         /* Look through extra data */
893
894         next = (const char *)response.extra_data.data;
895         while (next) {
896                 const char *current;
897                 char *k;
898
899                 if (num_groups >= response.data.num_entries) {
900                         wbc_status = WBC_ERR_INVALID_RESPONSE;
901                         goto done;
902                 }
903
904                 current = next;
905                 k = strchr(next, ',');
906
907                 if (k) {
908                         k[0] = '\0';
909                         next = k+1;
910                 } else {
911                         next = NULL;
912                 }
913
914                 groups[num_groups] = strdup(current);
915                 BAIL_ON_PTR_ERROR(groups[num_groups], wbc_status);
916                 num_groups += 1;
917         }
918         if (num_groups != response.data.num_entries) {
919                 wbc_status = WBC_ERR_INVALID_RESPONSE;
920                 goto done;
921         }
922
923         *_num_groups = response.data.num_entries;
924         *_groups = groups;
925         groups = NULL;
926         wbc_status = WBC_ERR_SUCCESS;
927
928  done:
929         winbindd_free_response(&response);
930         wbcFreeMemory(groups);
931         return wbc_status;
932 }
933
934 wbcErr wbcGetDisplayName(const struct wbcDomainSid *sid,
935                          char **pdomain,
936                          char **pfullname,
937                          enum wbcSidType *pname_type)
938 {
939         wbcErr wbc_status;
940         char *domain = NULL;
941         char *name = NULL;
942         enum wbcSidType name_type;
943
944         wbc_status = wbcLookupSid(sid, &domain, &name, &name_type);
945         BAIL_ON_WBC_ERROR(wbc_status);
946
947         if (name_type == WBC_SID_NAME_USER) {
948                 uid_t uid;
949                 struct passwd *pwd;
950
951                 wbc_status = wbcSidToUid(sid, &uid);
952                 BAIL_ON_WBC_ERROR(wbc_status);
953
954                 wbc_status = wbcGetpwuid(uid, &pwd);
955                 BAIL_ON_WBC_ERROR(wbc_status);
956
957                 wbcFreeMemory(name);
958
959                 name = wbcStrDup(pwd->pw_gecos);
960                 wbcFreeMemory(pwd);
961                 BAIL_ON_PTR_ERROR(name, wbc_status);
962         }
963
964         wbc_status = WBC_ERR_SUCCESS;
965
966  done:
967         if (WBC_ERROR_IS_OK(wbc_status)) {
968                 *pdomain = domain;
969                 *pfullname = name;
970                 *pname_type = name_type;
971         } else {
972                 wbcFreeMemory(domain);
973                 wbcFreeMemory(name);
974         }
975
976         return wbc_status;
977 }
978
979 const char* wbcSidTypeString(enum wbcSidType type)
980 {
981         switch (type) {
982         case WBC_SID_NAME_USE_NONE: return "SID_NONE";
983         case WBC_SID_NAME_USER:     return "SID_USER";
984         case WBC_SID_NAME_DOM_GRP:  return "SID_DOM_GROUP";
985         case WBC_SID_NAME_DOMAIN:   return "SID_DOMAIN";
986         case WBC_SID_NAME_ALIAS:    return "SID_ALIAS";
987         case WBC_SID_NAME_WKN_GRP:  return "SID_WKN_GROUP";
988         case WBC_SID_NAME_DELETED:  return "SID_DELETED";
989         case WBC_SID_NAME_INVALID:  return "SID_INVALID";
990         case WBC_SID_NAME_UNKNOWN:  return "SID_UNKNOWN";
991         case WBC_SID_NAME_COMPUTER: return "SID_COMPUTER";
992         default:                    return "Unknown type";
993         }
994 }