winbindd: winbindd_ccache_ntlm_auth() -> bool_dispatch_table
[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         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 wbcCtxLookupName(struct wbcContext *ctx,
184                         const char *domain,
185                         const char *name,
186                         struct wbcDomainSid *sid,
187                         enum wbcSidType *name_type)
188 {
189         struct winbindd_request request;
190         struct winbindd_response response;
191         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
192
193         if (!sid || !name_type) {
194                 wbc_status = WBC_ERR_INVALID_PARAM;
195                 BAIL_ON_WBC_ERROR(wbc_status);
196         }
197
198         /* Initialize request */
199
200         ZERO_STRUCT(request);
201         ZERO_STRUCT(response);
202
203         /* dst is already null terminated from the memset above */
204
205         strncpy(request.data.name.dom_name, domain,
206                 sizeof(request.data.name.dom_name)-1);
207         strncpy(request.data.name.name, name,
208                 sizeof(request.data.name.name)-1);
209
210         wbc_status = wbcRequestResponse(ctx, WINBINDD_LOOKUPNAME,
211                                         &request,
212                                         &response);
213         BAIL_ON_WBC_ERROR(wbc_status);
214
215         wbc_status = wbcStringToSid(response.data.sid.sid, sid);
216         BAIL_ON_WBC_ERROR(wbc_status);
217
218         *name_type = (enum wbcSidType)response.data.sid.type;
219
220         wbc_status = WBC_ERR_SUCCESS;
221
222  done:
223         return wbc_status;
224 }
225
226 wbcErr wbcLookupName(const char *domain,
227                      const char *name,
228                      struct wbcDomainSid *sid,
229                      enum wbcSidType *name_type)
230 {
231         return wbcCtxLookupName(NULL, domain, name, sid, name_type);
232 }
233
234
235 /* Convert a SID to a domain and name */
236 wbcErr wbcCtxLookupSid(struct wbcContext *ctx,
237                        const struct wbcDomainSid *sid,
238                        char **pdomain,
239                        char **pname,
240                        enum wbcSidType *pname_type)
241 {
242         struct winbindd_request request;
243         struct winbindd_response response;
244         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
245         char *domain, *name;
246
247         if (!sid) {
248                 return WBC_ERR_INVALID_PARAM;
249         }
250
251         /* Initialize request */
252
253         ZERO_STRUCT(request);
254         ZERO_STRUCT(response);
255
256         wbcSidToStringBuf(sid, request.data.sid, sizeof(request.data.sid));
257
258         /* Make request */
259
260         wbc_status = wbcRequestResponse(ctx, WINBINDD_LOOKUPSID,
261                                         &request,
262                                         &response);
263         if (!WBC_ERROR_IS_OK(wbc_status)) {
264                 return wbc_status;
265         }
266
267         /* Copy out result */
268
269         wbc_status = WBC_ERR_NO_MEMORY;
270         domain = NULL;
271         name = NULL;
272
273         domain = wbcStrDup(response.data.name.dom_name);
274         if (domain == NULL) {
275                 goto done;
276         }
277         name = wbcStrDup(response.data.name.name);
278         if (name == NULL) {
279                 goto done;
280         }
281         if (pdomain != NULL) {
282                 *pdomain = domain;
283                 domain = NULL;
284         }
285         if (pname != NULL) {
286                 *pname = name;
287                 name = NULL;
288         }
289         if (pname_type != NULL) {
290                 *pname_type = (enum wbcSidType)response.data.name.type;
291         }
292         wbc_status = WBC_ERR_SUCCESS;
293 done:
294         wbcFreeMemory(name);
295         wbcFreeMemory(domain);
296         return wbc_status;
297 }
298
299 wbcErr wbcLookupSid(const struct wbcDomainSid *sid,
300                     char **pdomain,
301                     char **pname,
302                     enum wbcSidType *pname_type)
303 {
304         return wbcCtxLookupSid(NULL, sid, pdomain, pname, pname_type);
305 }
306
307 static void wbcDomainInfosDestructor(void *ptr)
308 {
309         struct wbcDomainInfo *i = (struct wbcDomainInfo *)ptr;
310
311         while (i->short_name != NULL) {
312                 wbcFreeMemory(i->short_name);
313                 wbcFreeMemory(i->dns_name);
314                 i += 1;
315         }
316 }
317
318 static void wbcTranslatedNamesDestructor(void *ptr)
319 {
320         struct wbcTranslatedName *n = (struct wbcTranslatedName *)ptr;
321
322         while (n->name != NULL) {
323                 wbcFreeMemory(n->name);
324                 n += 1;
325         }
326 }
327
328 wbcErr wbcCtxLookupSids(struct wbcContext *ctx,
329                         const struct wbcDomainSid *sids, int num_sids,
330                         struct wbcDomainInfo **pdomains, int *pnum_domains,
331                         struct wbcTranslatedName **pnames)
332 {
333         struct winbindd_request request;
334         struct winbindd_response response;
335         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
336         int buflen, i, extra_len, num_domains, num_names;
337         char *sidlist, *p, *q, *extra_data;
338         struct wbcDomainInfo *domains = NULL;
339         struct wbcTranslatedName *names = NULL;
340
341         buflen = num_sids * (WBC_SID_STRING_BUFLEN + 1) + 1;
342
343         sidlist = (char *)malloc(buflen);
344         if (sidlist == NULL) {
345                 return WBC_ERR_NO_MEMORY;
346         }
347
348         p = sidlist;
349
350         for (i=0; i<num_sids; i++) {
351                 int remaining;
352                 int len;
353
354                 remaining = buflen - (p - sidlist);
355
356                 len = wbcSidToStringBuf(&sids[i], p, remaining);
357                 if (len > remaining) {
358                         free(sidlist);
359                         return WBC_ERR_UNKNOWN_FAILURE;
360                 }
361
362                 p += len;
363                 *p++ = '\n';
364         }
365         *p++ = '\0';
366
367         ZERO_STRUCT(request);
368         ZERO_STRUCT(response);
369
370         request.extra_data.data = sidlist;
371         request.extra_len = p - sidlist;
372
373         wbc_status = wbcRequestResponse(ctx, WINBINDD_LOOKUPSIDS,
374                                         &request, &response);
375         free(sidlist);
376         if (!WBC_ERROR_IS_OK(wbc_status)) {
377                 return wbc_status;
378         }
379
380         extra_len = response.length - sizeof(struct winbindd_response);
381         extra_data = (char *)response.extra_data.data;
382
383         if ((extra_len <= 0) || (extra_data[extra_len-1] != '\0')) {
384                 goto wbc_err_invalid;
385         }
386
387         p = extra_data;
388
389         num_domains = strtoul(p, &q, 10);
390         if (*q != '\n') {
391                 goto wbc_err_invalid;
392         }
393         p = q+1;
394
395         domains = (struct wbcDomainInfo *)wbcAllocateMemory(
396                 num_domains+1, sizeof(struct wbcDomainInfo),
397                 wbcDomainInfosDestructor);
398         if (domains == NULL) {
399                 wbc_status = WBC_ERR_NO_MEMORY;
400                 goto fail;
401         }
402
403         for (i=0; i<num_domains; i++) {
404
405                 q = strchr(p, ' ');
406                 if (q == NULL) {
407                         goto wbc_err_invalid;
408                 }
409                 *q = '\0';
410                 wbc_status = wbcStringToSid(p, &domains[i].sid);
411                 if (!WBC_ERROR_IS_OK(wbc_status)) {
412                         goto fail;
413                 }
414                 p = q+1;
415
416                 q = strchr(p, '\n');
417                 if (q == NULL) {
418                         goto wbc_err_invalid;
419                 }
420                 *q = '\0';
421                 domains[i].short_name = wbcStrDup(p);
422                 if (domains[i].short_name == NULL) {
423                         wbc_status = WBC_ERR_NO_MEMORY;
424                         goto fail;
425                 }
426                 p = q+1;
427         }
428
429         num_names = strtoul(p, &q, 10);
430         if (*q != '\n') {
431                 goto wbc_err_invalid;
432         }
433         p = q+1;
434
435         if (num_names != num_sids) {
436                 goto wbc_err_invalid;
437         }
438
439         names = (struct wbcTranslatedName *)wbcAllocateMemory(
440                 num_names+1, sizeof(struct wbcTranslatedName),
441                 wbcTranslatedNamesDestructor);
442         if (names == NULL) {
443                 wbc_status = WBC_ERR_NO_MEMORY;
444                 goto fail;
445         }
446
447         for (i=0; i<num_names; i++) {
448
449                 names[i].domain_index = strtoul(p, &q, 10);
450                 if (names[i].domain_index < 0) {
451                         goto wbc_err_invalid;
452                 }
453                 if (names[i].domain_index >= num_domains) {
454                         goto wbc_err_invalid;
455                 }
456
457                 if (*q != ' ') {
458                         goto wbc_err_invalid;
459                 }
460                 p = q+1;
461
462                 names[i].type = strtoul(p, &q, 10);
463                 if (*q != ' ') {
464                         goto wbc_err_invalid;
465                 }
466                 p = q+1;
467
468                 q = strchr(p, '\n');
469                 if (q == NULL) {
470                         goto wbc_err_invalid;
471                 }
472                 *q = '\0';
473                 names[i].name = wbcStrDup(p);
474                 if (names[i].name == NULL) {
475                         wbc_status = WBC_ERR_NO_MEMORY;
476                         goto fail;
477                 }
478                 p = q+1;
479         }
480         if (*p != '\0') {
481                 goto wbc_err_invalid;
482         }
483
484         *pdomains = domains;
485         *pnames = names;
486         winbindd_free_response(&response);
487         return WBC_ERR_SUCCESS;
488
489 wbc_err_invalid:
490         wbc_status = WBC_ERR_INVALID_RESPONSE;
491 fail:
492         winbindd_free_response(&response);
493         wbcFreeMemory(domains);
494         wbcFreeMemory(names);
495         return wbc_status;
496 }
497
498 wbcErr wbcLookupSids(const struct wbcDomainSid *sids, int num_sids,
499                      struct wbcDomainInfo **pdomains, int *pnum_domains,
500                      struct wbcTranslatedName **pnames)
501 {
502         return wbcCtxLookupSids(NULL, sids, num_sids, pdomains,
503                                 pnum_domains, pnames);
504 }
505
506 /* Translate a collection of RIDs within a domain to names */
507
508 wbcErr wbcCtxLookupRids(struct wbcContext *ctx, struct wbcDomainSid *dom_sid,
509                      int num_rids,
510                      uint32_t *rids,
511                      const char **pp_domain_name,
512                      const char ***pnames,
513                      enum wbcSidType **ptypes)
514 {
515         size_t i, len, ridbuf_size;
516         char *ridlist;
517         char *p;
518         struct winbindd_request request;
519         struct winbindd_response response;
520         char *domain_name = NULL;
521         const char **names = NULL;
522         enum wbcSidType *types = NULL;
523         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
524
525         /* Initialise request */
526
527         ZERO_STRUCT(request);
528         ZERO_STRUCT(response);
529
530         if (!dom_sid || (num_rids == 0)) {
531                 wbc_status = WBC_ERR_INVALID_PARAM;
532                 BAIL_ON_WBC_ERROR(wbc_status);
533         }
534
535         wbcSidToStringBuf(dom_sid, request.data.sid, sizeof(request.data.sid));
536
537         /* Even if all the Rids were of maximum 32bit values,
538            we would only have 11 bytes per rid in the final array
539            ("4294967296" + \n).  Add one more byte for the
540            terminating '\0' */
541
542         ridbuf_size = (sizeof(char)*11) * num_rids + 1;
543
544         ridlist = (char *)malloc(ridbuf_size);
545         BAIL_ON_PTR_ERROR(ridlist, wbc_status);
546
547         len = 0;
548         for (i=0; i<num_rids; i++) {
549                 len += snprintf(ridlist + len, ridbuf_size - len, "%u\n",
550                                 rids[i]);
551         }
552         ridlist[len] = '\0';
553         len += 1;
554
555         request.extra_data.data = ridlist;
556         request.extra_len = len;
557
558         wbc_status = wbcRequestResponse(ctx, WINBINDD_LOOKUPRIDS,
559                                         &request,
560                                         &response);
561         free(ridlist);
562         BAIL_ON_WBC_ERROR(wbc_status);
563
564         domain_name = wbcStrDup(response.data.domain_name);
565         BAIL_ON_PTR_ERROR(domain_name, wbc_status);
566
567         names = wbcAllocateStringArray(num_rids);
568         BAIL_ON_PTR_ERROR(names, wbc_status);
569
570         types = (enum wbcSidType *)wbcAllocateMemory(
571                 num_rids, sizeof(enum wbcSidType), NULL);
572         BAIL_ON_PTR_ERROR(types, wbc_status);
573
574         p = (char *)response.extra_data.data;
575
576         for (i=0; i<num_rids; i++) {
577                 char *q;
578
579                 if (*p == '\0') {
580                         wbc_status = WBC_ERR_INVALID_RESPONSE;
581                         goto done;
582                 }
583
584                 types[i] = (enum wbcSidType)strtoul(p, &q, 10);
585
586                 if (*q != ' ') {
587                         wbc_status = WBC_ERR_INVALID_RESPONSE;
588                         goto done;
589                 }
590
591                 p = q+1;
592
593                 if ((q = strchr(p, '\n')) == NULL) {
594                         wbc_status = WBC_ERR_INVALID_RESPONSE;
595                         goto done;
596                 }
597
598                 *q = '\0';
599
600                 names[i] = strdup(p);
601                 BAIL_ON_PTR_ERROR(names[i], wbc_status);
602
603                 p = q+1;
604         }
605
606         if (*p != '\0') {
607                 wbc_status = WBC_ERR_INVALID_RESPONSE;
608                 goto done;
609         }
610
611         wbc_status = WBC_ERR_SUCCESS;
612
613  done:
614         winbindd_free_response(&response);
615
616         if (WBC_ERROR_IS_OK(wbc_status)) {
617                 *pp_domain_name = domain_name;
618                 *pnames = names;
619                 *ptypes = types;
620         }
621         else {
622                 wbcFreeMemory(domain_name);
623                 wbcFreeMemory(names);
624                 wbcFreeMemory(types);
625         }
626
627         return wbc_status;
628 }
629
630 wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid,
631                      int num_rids,
632                      uint32_t *rids,
633                      const char **pp_domain_name,
634                      const char ***pnames,
635                      enum wbcSidType **ptypes)
636 {
637         return wbcCtxLookupRids(NULL, dom_sid, num_rids, rids,
638                                 pp_domain_name, pnames, ptypes);
639 }
640
641 /* Get the groups a user belongs to */
642 wbcErr wbcCtxLookupUserSids(struct wbcContext *ctx,
643                             const struct wbcDomainSid *user_sid,
644                             bool domain_groups_only,
645                             uint32_t *num_sids,
646                             struct wbcDomainSid **_sids)
647 {
648         uint32_t i;
649         const char *s;
650         struct winbindd_request request;
651         struct winbindd_response response;
652         struct wbcDomainSid *sids = NULL;
653         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
654         int cmd;
655
656         /* Initialise request */
657
658         ZERO_STRUCT(request);
659         ZERO_STRUCT(response);
660
661         if (!user_sid) {
662                 wbc_status = WBC_ERR_INVALID_PARAM;
663                 BAIL_ON_WBC_ERROR(wbc_status);
664         }
665
666         wbcSidToStringBuf(user_sid, request.data.sid, sizeof(request.data.sid));
667
668         if (domain_groups_only) {
669                 cmd = WINBINDD_GETUSERDOMGROUPS;
670         } else {
671                 cmd = WINBINDD_GETUSERSIDS;
672         }
673
674         wbc_status = wbcRequestResponse(ctx, cmd,
675                                         &request,
676                                         &response);
677         BAIL_ON_WBC_ERROR(wbc_status);
678
679         if (response.data.num_entries &&
680             !response.extra_data.data) {
681                 wbc_status = WBC_ERR_INVALID_RESPONSE;
682                 BAIL_ON_WBC_ERROR(wbc_status);
683         }
684
685         sids = (struct wbcDomainSid *)wbcAllocateMemory(
686                 response.data.num_entries, sizeof(struct wbcDomainSid),
687                 NULL);
688         BAIL_ON_PTR_ERROR(sids, wbc_status);
689
690         s = (const char *)response.extra_data.data;
691         for (i = 0; i < response.data.num_entries; i++) {
692                 char *n = strchr(s, '\n');
693                 if (n) {
694                         *n = '\0';
695                 }
696                 wbc_status = wbcStringToSid(s, &sids[i]);
697                 BAIL_ON_WBC_ERROR(wbc_status);
698                 s += strlen(s) + 1;
699         }
700
701         *num_sids = response.data.num_entries;
702         *_sids = sids;
703         sids = NULL;
704         wbc_status = WBC_ERR_SUCCESS;
705
706  done:
707         winbindd_free_response(&response);
708         if (sids) {
709                 wbcFreeMemory(sids);
710         }
711
712         return wbc_status;
713 }
714
715 wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid,
716                          bool domain_groups_only,
717                          uint32_t *num_sids,
718                          struct wbcDomainSid **_sids)
719 {
720         return wbcCtxLookupUserSids(NULL, user_sid, domain_groups_only,
721                                     num_sids, _sids);
722 }
723
724 static inline
725 wbcErr _sid_to_rid(struct wbcDomainSid *sid, uint32_t *rid)
726 {
727         if (sid->num_auths < 1) {
728                 return WBC_ERR_INVALID_RESPONSE;
729         }
730         *rid = sid->sub_auths[sid->num_auths - 1];
731
732         return WBC_ERR_SUCCESS;
733 }
734
735 /* Get alias membership for sids */
736 wbcErr wbcCtxGetSidAliases(struct wbcContext *ctx,
737                            const struct wbcDomainSid *dom_sid,
738                            struct wbcDomainSid *sids,
739                            uint32_t num_sids,
740                            uint32_t **alias_rids,
741                            uint32_t *num_alias_rids)
742 {
743         uint32_t i;
744         const char *s;
745         struct winbindd_request request;
746         struct winbindd_response response;
747         ssize_t extra_data_len = 0;
748         char * extra_data = NULL;
749         ssize_t buflen = 0;
750         struct wbcDomainSid sid;
751         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
752         uint32_t * rids = NULL;
753
754         /* Initialise request */
755
756         ZERO_STRUCT(request);
757         ZERO_STRUCT(response);
758
759         if (!dom_sid) {
760                 wbc_status = WBC_ERR_INVALID_PARAM;
761                 goto done;
762         }
763
764         wbcSidToStringBuf(dom_sid, request.data.sid, sizeof(request.data.sid));
765
766         /* Lets assume each sid is around 57 characters
767          * S-1-5-21-AAAAAAAAAAA-BBBBBBBBBBB-CCCCCCCCCCC-DDDDDDDDDDD\n */
768         buflen = 57 * num_sids;
769         extra_data = (char *)malloc(buflen);
770         if (!extra_data) {
771                 wbc_status = WBC_ERR_NO_MEMORY;
772                 goto done;
773         }
774
775         /* Build the sid list */
776         for (i=0; i<num_sids; i++) {
777                 char sid_str[WBC_SID_STRING_BUFLEN];
778                 size_t sid_len;
779
780                 sid_len = wbcSidToStringBuf(&sids[i], sid_str, sizeof(sid_str));
781
782                 if (buflen < extra_data_len + sid_len + 2) {
783                         buflen *= 2;
784                         extra_data = (char *)realloc(extra_data, buflen);
785                         if (!extra_data) {
786                                 wbc_status = WBC_ERR_NO_MEMORY;
787                                 BAIL_ON_WBC_ERROR(wbc_status);
788                         }
789                 }
790
791                 strncpy(&extra_data[extra_data_len], sid_str,
792                         buflen - extra_data_len);
793                 extra_data_len += sid_len;
794                 extra_data[extra_data_len++] = '\n';
795                 extra_data[extra_data_len] = '\0';
796         }
797         extra_data_len += 1;
798
799         request.extra_data.data = extra_data;
800         request.extra_len = extra_data_len;
801
802         wbc_status = wbcRequestResponse(ctx, WINBINDD_GETSIDALIASES,
803                                         &request,
804                                         &response);
805         BAIL_ON_WBC_ERROR(wbc_status);
806
807         if (response.data.num_entries &&
808             !response.extra_data.data) {
809                 wbc_status = WBC_ERR_INVALID_RESPONSE;
810                 goto done;
811         }
812
813         rids = (uint32_t *)wbcAllocateMemory(response.data.num_entries,
814                                              sizeof(uint32_t), NULL);
815         BAIL_ON_PTR_ERROR(rids, wbc_status);
816
817         s = (const char *)response.extra_data.data;
818         for (i = 0; i < response.data.num_entries; i++) {
819                 char *n = strchr(s, '\n');
820                 if (n) {
821                         *n = '\0';
822                 }
823                 wbc_status = wbcStringToSid(s, &sid);
824                 BAIL_ON_WBC_ERROR(wbc_status);
825                 wbc_status = _sid_to_rid(&sid, &rids[i]);
826                 BAIL_ON_WBC_ERROR(wbc_status);
827                 s += strlen(s) + 1;
828         }
829
830         *num_alias_rids = response.data.num_entries;
831         *alias_rids = rids;
832         rids = NULL;
833         wbc_status = WBC_ERR_SUCCESS;
834
835  done:
836         free(extra_data);
837         winbindd_free_response(&response);
838         wbcFreeMemory(rids);
839         return wbc_status;
840 }
841
842 wbcErr wbcGetSidAliases(const struct wbcDomainSid *dom_sid,
843                         struct wbcDomainSid *sids,
844                         uint32_t num_sids,
845                         uint32_t **alias_rids,
846                         uint32_t *num_alias_rids)
847 {
848         return wbcCtxGetSidAliases(NULL, dom_sid, sids, num_sids,
849                                    alias_rids, num_alias_rids);
850 }
851
852
853 /* Lists Users */
854 wbcErr wbcCtxListUsers(struct wbcContext *ctx,
855                        const char *domain_name,
856                        uint32_t *_num_users,
857                        const char ***_users)
858 {
859         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
860         struct winbindd_request request;
861         struct winbindd_response response;
862         uint32_t num_users = 0;
863         const char **users = NULL;
864         const char *next;
865
866         /* Initialise request */
867
868         ZERO_STRUCT(request);
869         ZERO_STRUCT(response);
870
871         if (domain_name) {
872                 strncpy(request.domain_name, domain_name,
873                         sizeof(request.domain_name)-1);
874         }
875
876         wbc_status = wbcRequestResponse(ctx, WINBINDD_LIST_USERS,
877                                         &request,
878                                         &response);
879         BAIL_ON_WBC_ERROR(wbc_status);
880
881         users = wbcAllocateStringArray(response.data.num_entries);
882         if (users == NULL) {
883                 return WBC_ERR_NO_MEMORY;
884         }
885
886         /* Look through extra data */
887
888         next = (const char *)response.extra_data.data;
889         while (next) {
890                 const char *current;
891                 char *k;
892
893                 if (num_users >= response.data.num_entries) {
894                         wbc_status = WBC_ERR_INVALID_RESPONSE;
895                         goto done;
896                 }
897
898                 current = next;
899                 k = strchr(next, ',');
900
901                 if (k) {
902                         k[0] = '\0';
903                         next = k+1;
904                 } else {
905                         next = NULL;
906                 }
907
908                 users[num_users] = strdup(current);
909                 BAIL_ON_PTR_ERROR(users[num_users], wbc_status);
910                 num_users += 1;
911         }
912         if (num_users != response.data.num_entries) {
913                 wbc_status = WBC_ERR_INVALID_RESPONSE;
914                 goto done;
915         }
916
917         *_num_users = response.data.num_entries;
918         *_users = users;
919         users = NULL;
920         wbc_status = WBC_ERR_SUCCESS;
921
922  done:
923         winbindd_free_response(&response);
924         wbcFreeMemory(users);
925         return wbc_status;
926 }
927
928 wbcErr wbcListUsers(const char *domain_name,
929                     uint32_t *_num_users,
930                     const char ***_users)
931 {
932         return wbcCtxListUsers(NULL, domain_name, _num_users, _users);
933 }
934
935 /* Lists Groups */
936 wbcErr wbcCtxListGroups(struct wbcContext *ctx,
937                         const char *domain_name,
938                         uint32_t *_num_groups,
939                         const char ***_groups)
940 {
941         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
942         struct winbindd_request request;
943         struct winbindd_response response;
944         uint32_t num_groups = 0;
945         const char **groups = NULL;
946         const char *next;
947
948         /* Initialise request */
949
950         ZERO_STRUCT(request);
951         ZERO_STRUCT(response);
952
953         if (domain_name) {
954                 strncpy(request.domain_name, domain_name,
955                         sizeof(request.domain_name)-1);
956         }
957
958         wbc_status = wbcRequestResponse(ctx, WINBINDD_LIST_GROUPS,
959                                         &request,
960                                         &response);
961         BAIL_ON_WBC_ERROR(wbc_status);
962
963         groups = wbcAllocateStringArray(response.data.num_entries);
964         if (groups == NULL) {
965                 return WBC_ERR_NO_MEMORY;
966         }
967
968         /* Look through extra data */
969
970         next = (const char *)response.extra_data.data;
971         while (next) {
972                 const char *current;
973                 char *k;
974
975                 if (num_groups >= response.data.num_entries) {
976                         wbc_status = WBC_ERR_INVALID_RESPONSE;
977                         goto done;
978                 }
979
980                 current = next;
981                 k = strchr(next, ',');
982
983                 if (k) {
984                         k[0] = '\0';
985                         next = k+1;
986                 } else {
987                         next = NULL;
988                 }
989
990                 groups[num_groups] = strdup(current);
991                 BAIL_ON_PTR_ERROR(groups[num_groups], wbc_status);
992                 num_groups += 1;
993         }
994         if (num_groups != response.data.num_entries) {
995                 wbc_status = WBC_ERR_INVALID_RESPONSE;
996                 goto done;
997         }
998
999         *_num_groups = response.data.num_entries;
1000         *_groups = groups;
1001         groups = NULL;
1002         wbc_status = WBC_ERR_SUCCESS;
1003
1004  done:
1005         winbindd_free_response(&response);
1006         wbcFreeMemory(groups);
1007         return wbc_status;
1008 }
1009
1010 wbcErr wbcListGroups(const char *domain_name,
1011                      uint32_t *_num_groups,
1012                      const char ***_groups)
1013 {
1014         return wbcCtxListGroups(NULL, domain_name, _num_groups, _groups);
1015 }
1016
1017 wbcErr wbcCtxGetDisplayName(struct wbcContext *ctx,
1018                             const struct wbcDomainSid *sid,
1019                             char **pdomain,
1020                             char **pfullname,
1021                             enum wbcSidType *pname_type)
1022 {
1023         wbcErr wbc_status;
1024         char *domain = NULL;
1025         char *name = NULL;
1026         enum wbcSidType name_type;
1027
1028         wbc_status = wbcCtxLookupSid(ctx, sid, &domain, &name, &name_type);
1029         BAIL_ON_WBC_ERROR(wbc_status);
1030
1031         if (name_type == WBC_SID_NAME_USER) {
1032                 uid_t uid;
1033                 struct passwd *pwd;
1034
1035                 wbc_status = wbcCtxSidToUid(ctx, sid, &uid);
1036                 BAIL_ON_WBC_ERROR(wbc_status);
1037
1038                 wbc_status = wbcCtxGetpwuid(ctx, uid, &pwd);
1039                 BAIL_ON_WBC_ERROR(wbc_status);
1040
1041                 wbcFreeMemory(name);
1042
1043                 name = wbcStrDup(pwd->pw_gecos);
1044                 wbcFreeMemory(pwd);
1045                 BAIL_ON_PTR_ERROR(name, wbc_status);
1046         }
1047
1048         wbc_status = WBC_ERR_SUCCESS;
1049
1050  done:
1051         if (WBC_ERROR_IS_OK(wbc_status)) {
1052                 *pdomain = domain;
1053                 *pfullname = name;
1054                 *pname_type = name_type;
1055         } else {
1056                 wbcFreeMemory(domain);
1057                 wbcFreeMemory(name);
1058         }
1059
1060         return wbc_status;
1061 }
1062
1063 wbcErr wbcGetDisplayName(const struct wbcDomainSid *sid,
1064                          char **pdomain,
1065                          char **pfullname,
1066                          enum wbcSidType *pname_type)
1067 {
1068         return wbcCtxGetDisplayName(NULL, sid, pdomain, pfullname, pname_type);
1069 }
1070
1071 const char* wbcSidTypeString(enum wbcSidType type)
1072 {
1073         switch (type) {
1074         case WBC_SID_NAME_USE_NONE: return "SID_NONE";
1075         case WBC_SID_NAME_USER:     return "SID_USER";
1076         case WBC_SID_NAME_DOM_GRP:  return "SID_DOM_GROUP";
1077         case WBC_SID_NAME_DOMAIN:   return "SID_DOMAIN";
1078         case WBC_SID_NAME_ALIAS:    return "SID_ALIAS";
1079         case WBC_SID_NAME_WKN_GRP:  return "SID_WKN_GROUP";
1080         case WBC_SID_NAME_DELETED:  return "SID_DELETED";
1081         case WBC_SID_NAME_INVALID:  return "SID_INVALID";
1082         case WBC_SID_NAME_UNKNOWN:  return "SID_UNKNOWN";
1083         case WBC_SID_NAME_COMPUTER: return "SID_COMPUTER";
1084         case WBC_SID_NAME_LABEL:    return "SID_LABEL";
1085         default:                    return "Unknown type";
1086         }
1087 }