Follow error code name convention in libwbclient.
[ira/wip.git] / source3 / 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
8
9    This library is free software; you can redistribute it and/or
10    modify it under the terms of the GNU Lesser General Public
11    License as published by the Free Software Foundation; either
12    version 3 of the License, or (at your option) any later version.
13
14    This library is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    Library General Public License for more details.
18
19    You should have received a copy of the GNU Lesser General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 /* Required Headers */
24
25 #include "libwbclient.h"
26
27
28 /** @brief Convert a binary SID to a character string
29  *
30  * @param sid           Binary Security Identifier
31  * @param **sid_string  Resulting character string
32  *
33  * @return #wbcErr
34  **/
35
36 wbcErr wbcSidToString(const struct wbcDomainSid *sid,
37                       char **sid_string)
38 {
39         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
40         uint32_t id_auth;
41         int i;
42         char *tmp = NULL;
43         TALLOC_CTX *ctx = NULL;
44
45         if (!sid) {
46                 wbc_status = WBC_ERR_INVALID_SID;
47                 BAIL_ON_WBC_ERROR(wbc_status);
48         }
49
50         ctx = talloc_init("wbcSidToString");
51         BAIL_ON_PTR_ERROR(ctx, wbc_status);
52
53         id_auth = sid->id_auth[5] +
54                 (sid->id_auth[4] << 8) +
55                 (sid->id_auth[3] << 16) +
56                 (sid->id_auth[2] << 24);
57
58         tmp = talloc_asprintf(ctx, "S-%d-%d", sid->sid_rev_num, id_auth);
59         BAIL_ON_PTR_ERROR(tmp, wbc_status);
60
61         for (i=0; i<sid->num_auths; i++) {
62                 char *tmp2 =
63                 tmp2 = talloc_asprintf_append(tmp, "-%u", sid->sub_auths[i]);
64                 BAIL_ON_PTR_ERROR(tmp2, wbc_status);
65
66                 tmp = tmp2;
67         }
68
69         *sid_string=talloc_strdup(NULL, tmp);
70         BAIL_ON_PTR_ERROR((*sid_string), wbc_status);
71
72         wbc_status = WBC_ERR_SUCCESS;
73
74 done:
75         talloc_free(ctx);
76
77         return wbc_status;
78 }
79
80 /** @brief Convert a character string to a binary SID
81  *
82  * @param *str          Character string in the form of S-...
83  * @param sid           Resulting binary SID
84  *
85  * @return #wbcErr
86  **/
87
88 wbcErr wbcStringToSid(const char *str,
89                       struct wbcDomainSid *sid)
90 {
91         const char *p;
92         char *q;
93         uint32_t x;
94         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
95
96         if (!sid) {
97                 wbc_status = WBC_ERR_INVALID_PARAM;
98                 BAIL_ON_WBC_ERROR(wbc_status);
99         }
100
101         /* Sanity check for either "S-" or "s-" */
102
103         if (!str
104             || (str[0]!='S' && str[0]!='s')
105             || (str[1]!='-')
106             || (strlen(str)<2))
107         {
108                 wbc_status = WBC_ERR_INVALID_PARAM;
109                 BAIL_ON_WBC_ERROR(wbc_status);
110         }
111
112         /* Get the SID revision number */
113
114         p = str+2;
115         x = (uint32_t)strtol(p, &q, 10);
116         if (x==0 || !q || *q!='-') {
117                 wbc_status = WBC_ERR_INVALID_SID;
118                 BAIL_ON_WBC_ERROR(wbc_status);
119         }
120         sid->sid_rev_num = (uint8_t)x;
121
122         /* Next the Identifier Authority.  This is stored in big-endian
123            in a 6 byte array. */
124
125         p = q+1;
126         x = (uint32_t)strtol(p, &q, 10);
127         if (x==0 || !q || *q!='-') {
128                 wbc_status = WBC_ERR_INVALID_SID;
129                 BAIL_ON_WBC_ERROR(wbc_status);
130         }
131         sid->id_auth[5] = (x & 0x000000ff);
132         sid->id_auth[4] = (x & 0x0000ff00) >> 8;
133         sid->id_auth[3] = (x & 0x00ff0000) >> 16;
134         sid->id_auth[2] = (x & 0xff000000) >> 24;
135         sid->id_auth[1] = 0;
136         sid->id_auth[0] = 0;
137
138         /* now read the the subauthorities */
139
140         p = q +1;
141         sid->num_auths = 0;
142         while (sid->num_auths < MAXSUBAUTHS) {
143                 if ((x=(uint32_t)strtoul(p, &q, 10)) == 0)
144                         break;
145                 sid->sub_auths[sid->num_auths++] = x;
146
147                 if (q && ((*q!='-') || (*q=='\0')))
148                         break;
149                 p = q + 1;
150         }
151
152         /* IF we ended early, then the SID could not be converted */
153
154         if (q && *q!='\0') {
155                 wbc_status = WBC_ERR_INVALID_SID;
156                 BAIL_ON_WBC_ERROR(wbc_status);
157         }
158
159         wbc_status = WBC_ERR_SUCCESS;
160
161 done:
162         return wbc_status;
163
164 }
165
166 /** @brief Convert a domain and name to SID
167  *
168  * @param domain      Domain name (possibly "")
169  * @param name        User or group name
170  * @param *sid        Pointer to the resolved domain SID
171  * @param *name_type  Pointet to the SID type
172  *
173  * @return #wbcErr
174  *
175  **/
176
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 /** @brief Convert a SID to a domain and name
220  *
221  * @param *sid        Pointer to the domain SID to be resolved
222  * @param domain      Resolved Domain name (possibly "")
223  * @param name        Resolved User or group name
224  * @param *name_type  Pointet to the resolved SID type
225  *
226  * @return #wbcErr
227  *
228  **/
229
230 wbcErr wbcLookupSid(const struct wbcDomainSid *sid,
231                     char **domain,
232                     char **name,
233                     enum wbcSidType *name_type)
234 {
235         struct winbindd_request request;
236         struct winbindd_response response;
237         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
238         char *sid_string = NULL;
239
240         if (!sid) {
241                 wbc_status = WBC_ERR_INVALID_PARAM;
242                 BAIL_ON_WBC_ERROR(wbc_status);
243         }
244
245         /* Initialize request */
246
247         ZERO_STRUCT(request);
248         ZERO_STRUCT(response);
249
250         /* dst is already null terminated from the memset above */
251
252         wbc_status = wbcSidToString(sid, &sid_string);
253         BAIL_ON_WBC_ERROR(wbc_status);
254
255         strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
256         wbcFreeMemory(sid_string);
257
258         /* Make request */
259
260         wbc_status = wbcRequestResponse(WINBINDD_LOOKUPSID,
261                                            &request,
262                                            &response);
263         BAIL_ON_WBC_ERROR(wbc_status);
264
265         /* Copy out result */
266
267         if (domain != NULL) {
268                 *domain = talloc_strdup(NULL, response.data.name.dom_name);
269                 BAIL_ON_PTR_ERROR((*domain), wbc_status);
270         }
271
272         if (name != NULL) {
273                 *name = talloc_strdup(NULL, response.data.name.name);
274                 BAIL_ON_PTR_ERROR((*name), wbc_status);
275         }
276
277         if (name_type) {
278                 *name_type = (enum wbcSidType)response.data.name.type;
279         }
280
281         wbc_status = WBC_ERR_SUCCESS;
282
283  done:
284         if (!WBC_ERROR_IS_OK(wbc_status)) {
285                 if (*domain)
286                         talloc_free(*domain);
287                 if (*name)
288                         talloc_free(*name);
289         }
290
291         return wbc_status;
292 }
293
294 /** @brief Translate a collection of RIDs within a domain to names
295  *
296  **/
297
298 wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid,
299                      int num_rids,
300                      uint32_t *rids,
301                      const char **pp_domain_name,
302                      const char ***names,
303                      enum wbcSidType **types)
304 {
305         size_t i, len, ridbuf_size;
306         char *ridlist;
307         char *p;
308         struct winbindd_request request;
309         struct winbindd_response response;
310         char *sid_string = NULL;
311         char *domain_name = NULL;
312         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
313
314         /* Initialise request */
315
316         ZERO_STRUCT(request);
317         ZERO_STRUCT(response);
318
319         if (!dom_sid || (num_rids == 0)) {
320                 wbc_status = WBC_ERR_INVALID_PARAM;
321                 BAIL_ON_WBC_ERROR(wbc_status);
322         }
323
324         wbc_status = wbcSidToString(dom_sid, &sid_string);
325         BAIL_ON_WBC_ERROR(wbc_status);
326
327         strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
328         wbcFreeMemory(sid_string);
329
330         /* Even if all the Rids were of maximum 32bit values,
331            we would only have 11 bytes per rid in the final array
332            ("4294967296" + \n).  Add one more byte for the
333            terminating '\0' */
334
335         ridbuf_size = (sizeof(char)*11) * num_rids + 1;
336
337         ridlist = talloc_zero_array(NULL, char, ridbuf_size);
338         BAIL_ON_PTR_ERROR(ridlist, wbc_status);
339
340         len = 0;
341         for (i=0; i<num_rids && (len-1)>0; i++) {
342                 char ridstr[12];
343
344                 len = strlen(ridlist);
345                 p = ridlist + len;
346
347                 snprintf( ridstr, sizeof(ridstr)-1, "%u\n", rids[i]);
348                 strncat(p, ridstr, ridbuf_size-len-1);
349         }
350
351         request.extra_data.data = ridlist;
352         request.extra_len = strlen(ridlist)+1;
353
354         wbc_status = wbcRequestResponse(WINBINDD_LOOKUPRIDS,
355                                         &request,
356                                         &response);
357         talloc_free(ridlist);
358         BAIL_ON_WBC_ERROR(wbc_status);
359
360         domain_name = talloc_strdup(NULL, response.data.domain_name);
361         BAIL_ON_PTR_ERROR(domain_name, wbc_status);
362
363         *names = talloc_array(NULL, const char*, num_rids);
364         BAIL_ON_PTR_ERROR((*names), wbc_status);
365
366         *types = talloc_array(NULL, enum wbcSidType, num_rids);
367         BAIL_ON_PTR_ERROR((*types), wbc_status);
368
369         p = (char *)response.extra_data.data;
370
371         for (i=0; i<num_rids; i++) {
372                 char *q;
373
374                 if (*p == '\0') {
375                         wbc_status = WBC_ERR_INVALID_RESPONSE;
376                         BAIL_ON_WBC_ERROR(wbc_status);
377                 }
378
379                 (*types)[i] = (enum wbcSidType)strtoul(p, &q, 10);
380
381                 if (*q != ' ') {
382                         wbc_status = WBC_ERR_INVALID_RESPONSE;
383                         BAIL_ON_WBC_ERROR(wbc_status);
384                 }
385
386                 p = q+1;
387
388                 if ((q = strchr(p, '\n')) == NULL) {
389                         wbc_status = WBC_ERR_INVALID_RESPONSE;
390                         BAIL_ON_WBC_ERROR(wbc_status);
391                 }
392
393                 *q = '\0';
394
395                 (*names)[i] = talloc_strdup((*names), p);
396                 BAIL_ON_PTR_ERROR(((*names)[i]), wbc_status);
397
398                 p = q+1;
399         }
400
401         if (*p != '\0') {
402                 wbc_status = WBC_ERR_INVALID_RESPONSE;
403                 BAIL_ON_WBC_ERROR(wbc_status);
404         }
405
406         wbc_status = WBC_ERR_SUCCESS;
407
408  done:
409         if (response.extra_data.data) {
410                 free(response.extra_data.data);
411         }
412
413         if (!WBC_ERROR_IS_OK(wbc_status)) {
414                 if (domain_name)
415                         talloc_free(domain_name);
416                 if (*names)
417                         talloc_free(*names);
418                 if (*types)
419                         talloc_free(*types);
420         } else {
421                 *pp_domain_name = domain_name;
422         }
423
424         return wbc_status;
425 }
426
427 /** @brief Get the groups a user belongs to
428  *
429  **/
430
431 wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid,
432                          bool domain_groups_only,
433                          uint32_t *num_sids,
434                          struct wbcDomainSid **_sids)
435 {
436         uint32_t i;
437         const char *s;
438         struct winbindd_request request;
439         struct winbindd_response response;
440         char *sid_string = NULL;
441         struct wbcDomainSid *sids = NULL;
442         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
443         int cmd;
444
445         /* Initialise request */
446
447         ZERO_STRUCT(request);
448         ZERO_STRUCT(response);
449
450         if (!user_sid) {
451                 wbc_status = WBC_ERR_INVALID_PARAM;
452                 BAIL_ON_WBC_ERROR(wbc_status);
453         }
454
455         wbc_status = wbcSidToString(user_sid, &sid_string);
456         BAIL_ON_WBC_ERROR(wbc_status);
457
458         strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
459         wbcFreeMemory(sid_string);
460
461         if (domain_groups_only) {
462                 cmd = WINBINDD_GETUSERDOMGROUPS;
463         } else {
464                 cmd = WINBINDD_GETUSERSIDS;
465         }
466
467         wbc_status = wbcRequestResponse(cmd,
468                                         &request,
469                                         &response);
470         BAIL_ON_WBC_ERROR(wbc_status);
471
472         if (response.data.num_entries &&
473             !response.extra_data.data) {
474                 wbc_status = WBC_ERR_INVALID_RESPONSE;
475                 BAIL_ON_WBC_ERROR(wbc_status);
476         }
477
478         sids = talloc_array(NULL, struct wbcDomainSid,
479                             response.data.num_entries);
480         BAIL_ON_PTR_ERROR(sids, wbc_status);
481
482         s = (const char *)response.extra_data.data;
483         for (i = 0; i < response.data.num_entries; i++) {
484                 char *n = strchr(s, '\n');
485                 if (n) {
486                         *n = '\0';
487                 }
488                 wbc_status = wbcStringToSid(s, &sids[i]);
489                 BAIL_ON_WBC_ERROR(wbc_status);
490                 s += strlen(s) + 1;
491         }
492
493         *num_sids = response.data.num_entries;
494         *_sids = sids;
495         sids = NULL;
496         wbc_status = WBC_ERR_SUCCESS;
497
498  done:
499         if (response.extra_data.data) {
500                 free(response.extra_data.data);
501         }
502         if (sids) {
503                 talloc_free(sids);
504         }
505
506         return wbc_status;
507 }
508
509 /** @brief Lists Users
510  *
511  **/
512
513 wbcErr wbcListUsers(const char *domain_name,
514                     uint32_t *_num_users,
515                     const char ***_users)
516 {
517         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
518         struct winbindd_request request;
519         struct winbindd_response response;
520         uint32_t num_users = 0;
521         const char **users = NULL;
522         const char *next;
523
524         /* Initialise request */
525
526         ZERO_STRUCT(request);
527         ZERO_STRUCT(response);
528
529         if (domain_name) {
530                 strncpy(request.domain_name, domain_name,
531                         sizeof(request.domain_name)-1);
532         }
533
534         wbc_status = wbcRequestResponse(WINBINDD_LIST_USERS,
535                                         &request,
536                                         &response);
537         BAIL_ON_WBC_ERROR(wbc_status);
538
539         /* Look through extra data */
540
541         next = (const char *)response.extra_data.data;
542         while (next) {
543                 const char **tmp;
544                 const char *current = next;
545                 char *k = strchr(next, ',');
546                 if (k) {
547                         k[0] = '\0';
548                         next = k+1;
549                 } else {
550                         next = NULL;
551                 }
552
553                 tmp = talloc_realloc(NULL, users,
554                                      const char *,
555                                      num_users+1);
556                 BAIL_ON_PTR_ERROR(tmp, wbc_status);
557                 users = tmp;
558
559                 users[num_users] = talloc_strdup(users, current);
560                 BAIL_ON_PTR_ERROR(users[num_users], wbc_status);
561
562                 num_users++;
563         }
564
565         *_num_users = num_users;
566         *_users = users;
567         users = NULL;
568         wbc_status = WBC_ERR_SUCCESS;
569
570  done:
571         if (response.extra_data.data) {
572                 free(response.extra_data.data);
573         }
574         if (users) {
575                 talloc_free(users);
576         }
577         return wbc_status;
578 }
579
580 /** @brief Lists Groups
581  *
582  **/
583
584 wbcErr wbcListGroups(const char *domain_name,
585                      uint32_t *_num_groups,
586                      const char ***_groups)
587 {
588         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
589         struct winbindd_request request;
590         struct winbindd_response response;
591         uint32_t num_groups = 0;
592         const char **groups = NULL;
593         const char *next;
594
595         /* Initialise request */
596
597         ZERO_STRUCT(request);
598         ZERO_STRUCT(response);
599
600         if (domain_name) {
601                 strncpy(request.domain_name, domain_name,
602                         sizeof(request.domain_name)-1);
603         }
604
605         wbc_status = wbcRequestResponse(WINBINDD_LIST_GROUPS,
606                                         &request,
607                                         &response);
608         BAIL_ON_WBC_ERROR(wbc_status);
609
610         /* Look through extra data */
611
612         next = (const char *)response.extra_data.data;
613         while (next) {
614                 const char **tmp;
615                 const char *current = next;
616                 char *k = strchr(next, ',');
617                 if (k) {
618                         k[0] = '\0';
619                         next = k+1;
620                 } else {
621                         next = NULL;
622                 }
623
624                 tmp = talloc_realloc(NULL, groups,
625                                      const char *,
626                                      num_groups+1);
627                 BAIL_ON_PTR_ERROR(tmp, wbc_status);
628                 groups = tmp;
629
630                 groups[num_groups] = talloc_strdup(groups, current);
631                 BAIL_ON_PTR_ERROR(groups[num_groups], wbc_status);
632
633                 num_groups++;
634         }
635
636         *_num_groups = num_groups;
637         *_groups = groups;
638         groups = NULL;
639         wbc_status = WBC_ERR_SUCCESS;
640
641  done:
642         if (response.extra_data.data) {
643                 free(response.extra_data.data);
644         }
645         if (groups) {
646                 talloc_free(groups);
647         }
648         return wbc_status;
649 }