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