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