libwbclient: Make wbcLookupRids not use talloc
[Samba/ekacnet.git] / nsswitch / libwbclient / wbc_sid.c
bloba2ed5e1d3f3a1455562e0feec7ea5bf3771ce6be
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind client API
6 Copyright (C) Gerald (Jerry) Carter 2007
7 Copyright (C) Volker Lendecke 2010
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.
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.
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/>.
24 /* Required Headers */
26 #include "replace.h"
27 #include "libwbclient.h"
28 #include "../winbind_client.h"
30 /* Convert a binary SID to a character string */
31 wbcErr wbcSidToString(const struct wbcDomainSid *sid,
32 char **sid_string)
34 uint32_t id_auth;
35 int i, ofs, maxlen;
36 char *result;
38 if (!sid) {
39 return WBC_ERR_INVALID_SID;
42 maxlen = sid->num_auths * 11 + 25;
44 result = (char *)wbcAllocateMemory(maxlen, 1, NULL);
45 if (result == NULL) {
46 return WBC_ERR_NO_MEMORY;
50 * BIG NOTE: this function only does SIDS where the identauth is not
51 * >= ^32 in a range of 2^48.
54 id_auth = sid->id_auth[5] +
55 (sid->id_auth[4] << 8) +
56 (sid->id_auth[3] << 16) +
57 (sid->id_auth[2] << 24);
59 ofs = snprintf(result, maxlen, "S-%u-%lu",
60 (unsigned int)sid->sid_rev_num, (unsigned long)id_auth);
62 for (i = 0; i < sid->num_auths; i++) {
63 ofs += snprintf(result + ofs, maxlen - ofs, "-%lu",
64 (unsigned long)sid->sub_auths[i]);
67 *sid_string = result;
68 return WBC_ERR_SUCCESS;
71 /* Convert a character string to a binary SID */
72 wbcErr wbcStringToSid(const char *str,
73 struct wbcDomainSid *sid)
75 const char *p;
76 char *q;
77 uint32_t x;
78 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
80 if (!sid) {
81 wbc_status = WBC_ERR_INVALID_PARAM;
82 BAIL_ON_WBC_ERROR(wbc_status);
85 /* Sanity check for either "S-" or "s-" */
87 if (!str
88 || (str[0]!='S' && str[0]!='s')
89 || (str[1]!='-'))
91 wbc_status = WBC_ERR_INVALID_PARAM;
92 BAIL_ON_WBC_ERROR(wbc_status);
95 /* Get the SID revision number */
97 p = str+2;
98 x = (uint32_t)strtol(p, &q, 10);
99 if (x==0 || !q || *q!='-') {
100 wbc_status = WBC_ERR_INVALID_SID;
101 BAIL_ON_WBC_ERROR(wbc_status);
103 sid->sid_rev_num = (uint8_t)x;
105 /* Next the Identifier Authority. This is stored in big-endian
106 in a 6 byte array. */
108 p = q+1;
109 x = (uint32_t)strtol(p, &q, 10);
110 if (!q || *q!='-') {
111 wbc_status = WBC_ERR_INVALID_SID;
112 BAIL_ON_WBC_ERROR(wbc_status);
114 sid->id_auth[5] = (x & 0x000000ff);
115 sid->id_auth[4] = (x & 0x0000ff00) >> 8;
116 sid->id_auth[3] = (x & 0x00ff0000) >> 16;
117 sid->id_auth[2] = (x & 0xff000000) >> 24;
118 sid->id_auth[1] = 0;
119 sid->id_auth[0] = 0;
121 /* now read the the subauthorities */
123 p = q +1;
124 sid->num_auths = 0;
125 while (sid->num_auths < WBC_MAXSUBAUTHS) {
126 x=(uint32_t)strtoul(p, &q, 10);
127 if (p == q)
128 break;
129 if (q == NULL) {
130 wbc_status = WBC_ERR_INVALID_SID;
131 BAIL_ON_WBC_ERROR(wbc_status);
133 sid->sub_auths[sid->num_auths++] = x;
135 if ((*q!='-') || (*q=='\0'))
136 break;
137 p = q + 1;
140 /* IF we ended early, then the SID could not be converted */
142 if (q && *q!='\0') {
143 wbc_status = WBC_ERR_INVALID_SID;
144 BAIL_ON_WBC_ERROR(wbc_status);
147 wbc_status = WBC_ERR_SUCCESS;
149 done:
150 return wbc_status;
155 /* Convert a domain and name to SID */
156 wbcErr wbcLookupName(const char *domain,
157 const char *name,
158 struct wbcDomainSid *sid,
159 enum wbcSidType *name_type)
161 struct winbindd_request request;
162 struct winbindd_response response;
163 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
165 if (!sid || !name_type) {
166 wbc_status = WBC_ERR_INVALID_PARAM;
167 BAIL_ON_WBC_ERROR(wbc_status);
170 /* Initialize request */
172 ZERO_STRUCT(request);
173 ZERO_STRUCT(response);
175 /* dst is already null terminated from the memset above */
177 strncpy(request.data.name.dom_name, domain,
178 sizeof(request.data.name.dom_name)-1);
179 strncpy(request.data.name.name, name,
180 sizeof(request.data.name.name)-1);
182 wbc_status = wbcRequestResponse(WINBINDD_LOOKUPNAME,
183 &request,
184 &response);
185 BAIL_ON_WBC_ERROR(wbc_status);
187 wbc_status = wbcStringToSid(response.data.sid.sid, sid);
188 BAIL_ON_WBC_ERROR(wbc_status);
190 *name_type = (enum wbcSidType)response.data.sid.type;
192 wbc_status = WBC_ERR_SUCCESS;
194 done:
195 return wbc_status;
199 /* Convert a SID to a domain and name */
200 wbcErr wbcLookupSid(const struct wbcDomainSid *sid,
201 char **pdomain,
202 char **pname,
203 enum wbcSidType *pname_type)
205 struct winbindd_request request;
206 struct winbindd_response response;
207 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
208 char *sid_string = NULL;
209 char *domain, *name;
211 if (!sid) {
212 return WBC_ERR_INVALID_PARAM;
215 /* Initialize request */
217 ZERO_STRUCT(request);
218 ZERO_STRUCT(response);
220 /* dst is already null terminated from the memset above */
222 wbc_status = wbcSidToString(sid, &sid_string);
223 if (!WBC_ERROR_IS_OK(wbc_status)) {
224 return wbc_status;
227 strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
228 wbcFreeMemory(sid_string);
230 /* Make request */
232 wbc_status = wbcRequestResponse(WINBINDD_LOOKUPSID, &request,
233 &response);
234 if (!WBC_ERROR_IS_OK(wbc_status)) {
235 return wbc_status;
238 /* Copy out result */
240 wbc_status = WBC_ERR_NO_MEMORY;
241 domain = NULL;
242 name = NULL;
244 domain = wbcStrDup(response.data.name.dom_name);
245 if (domain == NULL) {
246 goto done;
248 name = wbcStrDup(response.data.name.name);
249 if (name == NULL) {
250 goto done;
252 if (pdomain != NULL) {
253 *pdomain = domain;
254 domain = NULL;
256 if (pname != NULL) {
257 *pname = name;
258 name = NULL;
260 if (pname_type != NULL) {
261 *pname_type = (enum wbcSidType)response.data.name.type;
263 wbc_status = WBC_ERR_SUCCESS;
264 done:
265 wbcFreeMemory(name);
266 wbcFreeMemory(domain);
267 return wbc_status;
270 /* Translate a collection of RIDs within a domain to names */
272 wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid,
273 int num_rids,
274 uint32_t *rids,
275 const char **pp_domain_name,
276 const char ***pnames,
277 enum wbcSidType **ptypes)
279 size_t i, len, ridbuf_size;
280 char *ridlist;
281 char *p;
282 struct winbindd_request request;
283 struct winbindd_response response;
284 char *sid_string = NULL;
285 char *domain_name = NULL;
286 const char **names = NULL;
287 enum wbcSidType *types = NULL;
288 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
290 /* Initialise request */
292 ZERO_STRUCT(request);
293 ZERO_STRUCT(response);
295 if (!dom_sid || (num_rids == 0)) {
296 wbc_status = WBC_ERR_INVALID_PARAM;
297 BAIL_ON_WBC_ERROR(wbc_status);
300 wbc_status = wbcSidToString(dom_sid, &sid_string);
301 BAIL_ON_WBC_ERROR(wbc_status);
303 strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
304 wbcFreeMemory(sid_string);
306 /* Even if all the Rids were of maximum 32bit values,
307 we would only have 11 bytes per rid in the final array
308 ("4294967296" + \n). Add one more byte for the
309 terminating '\0' */
311 ridbuf_size = (sizeof(char)*11) * num_rids + 1;
313 ridlist = (char *)malloc(ridbuf_size);
314 BAIL_ON_PTR_ERROR(ridlist, wbc_status);
316 len = 0;
317 for (i=0; i<num_rids; i++) {
318 len += snprintf(ridlist + len, ridbuf_size - len, "%u\n",
319 rids[i]);
321 ridlist[len] = '\0';
322 len += 1;
324 request.extra_data.data = ridlist;
325 request.extra_len = len;
327 wbc_status = wbcRequestResponse(WINBINDD_LOOKUPRIDS,
328 &request,
329 &response);
330 free(ridlist);
331 BAIL_ON_WBC_ERROR(wbc_status);
333 domain_name = wbcStrDup(response.data.domain_name);
334 BAIL_ON_PTR_ERROR(domain_name, wbc_status);
336 names = wbcAllocateStringArray(num_rids);
337 BAIL_ON_PTR_ERROR(names, wbc_status);
339 types = (enum wbcSidType *)wbcAllocateMemory(
340 num_rids, sizeof(enum wbcSidType), NULL);
341 BAIL_ON_PTR_ERROR(types, wbc_status);
343 p = (char *)response.extra_data.data;
345 for (i=0; i<num_rids; i++) {
346 char *q;
348 if (*p == '\0') {
349 wbc_status = WBC_ERR_INVALID_RESPONSE;
350 BAIL_ON_WBC_ERROR(wbc_status);
353 types[i] = (enum wbcSidType)strtoul(p, &q, 10);
355 if (*q != ' ') {
356 wbc_status = WBC_ERR_INVALID_RESPONSE;
357 BAIL_ON_WBC_ERROR(wbc_status);
360 p = q+1;
362 if ((q = strchr(p, '\n')) == NULL) {
363 wbc_status = WBC_ERR_INVALID_RESPONSE;
364 BAIL_ON_WBC_ERROR(wbc_status);
367 *q = '\0';
369 names[i] = strdup(p);
370 BAIL_ON_PTR_ERROR(names[i], wbc_status);
372 p = q+1;
375 if (*p != '\0') {
376 wbc_status = WBC_ERR_INVALID_RESPONSE;
377 BAIL_ON_WBC_ERROR(wbc_status);
380 wbc_status = WBC_ERR_SUCCESS;
382 done:
383 winbindd_free_response(&response);
385 if (WBC_ERROR_IS_OK(wbc_status)) {
386 *pp_domain_name = domain_name;
387 *pnames = names;
388 *ptypes = types;
390 else {
391 wbcFreeMemory(domain_name);
392 wbcFreeMemory(names);
393 wbcFreeMemory(types);
396 return wbc_status;
399 /* Get the groups a user belongs to */
400 wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid,
401 bool domain_groups_only,
402 uint32_t *num_sids,
403 struct wbcDomainSid **_sids)
405 uint32_t i;
406 const char *s;
407 struct winbindd_request request;
408 struct winbindd_response response;
409 char *sid_string = NULL;
410 struct wbcDomainSid *sids = NULL;
411 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
412 int cmd;
414 /* Initialise request */
416 ZERO_STRUCT(request);
417 ZERO_STRUCT(response);
419 if (!user_sid) {
420 wbc_status = WBC_ERR_INVALID_PARAM;
421 BAIL_ON_WBC_ERROR(wbc_status);
424 wbc_status = wbcSidToString(user_sid, &sid_string);
425 BAIL_ON_WBC_ERROR(wbc_status);
427 strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
428 wbcFreeMemory(sid_string);
430 if (domain_groups_only) {
431 cmd = WINBINDD_GETUSERDOMGROUPS;
432 } else {
433 cmd = WINBINDD_GETUSERSIDS;
436 wbc_status = wbcRequestResponse(cmd,
437 &request,
438 &response);
439 BAIL_ON_WBC_ERROR(wbc_status);
441 if (response.data.num_entries &&
442 !response.extra_data.data) {
443 wbc_status = WBC_ERR_INVALID_RESPONSE;
444 BAIL_ON_WBC_ERROR(wbc_status);
447 sids = talloc_array(NULL, struct wbcDomainSid,
448 response.data.num_entries);
449 BAIL_ON_PTR_ERROR(sids, wbc_status);
451 s = (const char *)response.extra_data.data;
452 for (i = 0; i < response.data.num_entries; i++) {
453 char *n = strchr(s, '\n');
454 if (n) {
455 *n = '\0';
457 wbc_status = wbcStringToSid(s, &sids[i]);
458 BAIL_ON_WBC_ERROR(wbc_status);
459 s += strlen(s) + 1;
462 *num_sids = response.data.num_entries;
463 *_sids = sids;
464 sids = NULL;
465 wbc_status = WBC_ERR_SUCCESS;
467 done:
468 winbindd_free_response(&response);
469 if (sids) {
470 talloc_free(sids);
473 return wbc_status;
476 static inline
477 wbcErr _sid_to_rid(struct wbcDomainSid *sid, uint32_t *rid)
479 if (sid->num_auths < 1) {
480 return WBC_ERR_INVALID_RESPONSE;
482 *rid = sid->sub_auths[sid->num_auths - 1];
484 return WBC_ERR_SUCCESS;
487 /* Get alias membership for sids */
488 wbcErr wbcGetSidAliases(const struct wbcDomainSid *dom_sid,
489 struct wbcDomainSid *sids,
490 uint32_t num_sids,
491 uint32_t **alias_rids,
492 uint32_t *num_alias_rids)
494 uint32_t i;
495 const char *s;
496 struct winbindd_request request;
497 struct winbindd_response response;
498 char *sid_string = NULL;
499 ssize_t sid_len;
500 ssize_t extra_data_len = 0;
501 char * extra_data = NULL;
502 ssize_t buflen = 0;
503 struct wbcDomainSid sid;
504 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
505 uint32_t * rids = NULL;
507 /* Initialise request */
509 ZERO_STRUCT(request);
510 ZERO_STRUCT(response);
512 if (!dom_sid) {
513 wbc_status = WBC_ERR_INVALID_PARAM;
514 BAIL_ON_WBC_ERROR(wbc_status);
517 wbc_status = wbcSidToString(dom_sid, &sid_string);
518 BAIL_ON_WBC_ERROR(wbc_status);
520 strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
521 wbcFreeMemory(sid_string);
522 sid_string = NULL;
524 /* Lets assume each sid is around 54 characters
525 * S-1-5-AAAAAAAAAAA-BBBBBBBBBBB-CCCCCCCCCCC-DDDDDDDDDDD\n */
526 buflen = 54 * num_sids;
527 extra_data = talloc_array(NULL, char, buflen);
528 if (!extra_data) {
529 wbc_status = WBC_ERR_NO_MEMORY;
530 BAIL_ON_WBC_ERROR(wbc_status);
533 /* Build the sid list */
534 for (i=0; i<num_sids; i++) {
535 wbcFreeMemory(sid_string);
536 sid_string = NULL;
537 wbc_status = wbcSidToString(&sids[i], &sid_string);
538 BAIL_ON_WBC_ERROR(wbc_status);
540 sid_len = strlen(sid_string);
542 if (buflen < extra_data_len + sid_len + 2) {
543 buflen *= 2;
544 extra_data = talloc_realloc(NULL, extra_data,
545 char, buflen);
546 if (!extra_data) {
547 wbc_status = WBC_ERR_NO_MEMORY;
548 BAIL_ON_WBC_ERROR(wbc_status);
552 strncpy(&extra_data[extra_data_len], sid_string,
553 buflen - extra_data_len);
554 extra_data_len += sid_len;
555 extra_data[extra_data_len++] = '\n';
556 extra_data[extra_data_len] = '\0';
558 extra_data_len += 1;
560 request.extra_data.data = extra_data;
561 request.extra_len = extra_data_len;
563 wbc_status = wbcRequestResponse(WINBINDD_GETSIDALIASES,
564 &request,
565 &response);
566 BAIL_ON_WBC_ERROR(wbc_status);
568 if (response.data.num_entries &&
569 !response.extra_data.data) {
570 wbc_status = WBC_ERR_INVALID_RESPONSE;
571 BAIL_ON_WBC_ERROR(wbc_status);
574 rids = talloc_array(NULL, uint32_t,
575 response.data.num_entries);
576 BAIL_ON_PTR_ERROR(sids, wbc_status);
578 s = (const char *)response.extra_data.data;
579 for (i = 0; i < response.data.num_entries; i++) {
580 char *n = strchr(s, '\n');
581 if (n) {
582 *n = '\0';
584 wbc_status = wbcStringToSid(s, &sid);
585 BAIL_ON_WBC_ERROR(wbc_status);
586 wbc_status = _sid_to_rid(&sid, &rids[i]);
587 BAIL_ON_WBC_ERROR(wbc_status);
588 s += strlen(s) + 1;
591 *num_alias_rids = response.data.num_entries;
592 *alias_rids = rids;
593 rids = NULL;
594 wbc_status = WBC_ERR_SUCCESS;
596 done:
597 wbcFreeMemory(sid_string);
598 talloc_free(extra_data);
599 winbindd_free_response(&response);
600 talloc_free(rids);
601 return wbc_status;
605 /* Lists Users */
606 wbcErr wbcListUsers(const char *domain_name,
607 uint32_t *_num_users,
608 const char ***_users)
610 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
611 struct winbindd_request request;
612 struct winbindd_response response;
613 uint32_t num_users = 0;
614 const char **users = NULL;
615 const char *next;
617 /* Initialise request */
619 ZERO_STRUCT(request);
620 ZERO_STRUCT(response);
622 if (domain_name) {
623 strncpy(request.domain_name, domain_name,
624 sizeof(request.domain_name)-1);
627 wbc_status = wbcRequestResponse(WINBINDD_LIST_USERS,
628 &request,
629 &response);
630 BAIL_ON_WBC_ERROR(wbc_status);
632 /* Look through extra data */
634 next = (const char *)response.extra_data.data;
635 while (next) {
636 const char **tmp;
637 const char *current = next;
638 char *k = strchr(next, ',');
639 if (k) {
640 k[0] = '\0';
641 next = k+1;
642 } else {
643 next = NULL;
646 tmp = talloc_realloc(NULL, users,
647 const char *,
648 num_users+1);
649 BAIL_ON_PTR_ERROR(tmp, wbc_status);
650 users = tmp;
652 users[num_users] = talloc_strdup(users, current);
653 BAIL_ON_PTR_ERROR(users[num_users], wbc_status);
655 num_users++;
658 *_num_users = num_users;
659 *_users = users;
660 users = NULL;
661 wbc_status = WBC_ERR_SUCCESS;
663 done:
664 winbindd_free_response(&response);
665 if (users) {
666 talloc_free(users);
668 return wbc_status;
671 /* Lists Groups */
672 wbcErr wbcListGroups(const char *domain_name,
673 uint32_t *_num_groups,
674 const char ***_groups)
676 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
677 struct winbindd_request request;
678 struct winbindd_response response;
679 uint32_t num_groups = 0;
680 const char **groups = NULL;
681 const char *next;
683 /* Initialise request */
685 ZERO_STRUCT(request);
686 ZERO_STRUCT(response);
688 if (domain_name) {
689 strncpy(request.domain_name, domain_name,
690 sizeof(request.domain_name)-1);
693 wbc_status = wbcRequestResponse(WINBINDD_LIST_GROUPS,
694 &request,
695 &response);
696 BAIL_ON_WBC_ERROR(wbc_status);
698 /* Look through extra data */
700 next = (const char *)response.extra_data.data;
701 while (next) {
702 const char **tmp;
703 const char *current = next;
704 char *k = strchr(next, ',');
705 if (k) {
706 k[0] = '\0';
707 next = k+1;
708 } else {
709 next = NULL;
712 tmp = talloc_realloc(NULL, groups,
713 const char *,
714 num_groups+1);
715 BAIL_ON_PTR_ERROR(tmp, wbc_status);
716 groups = tmp;
718 groups[num_groups] = talloc_strdup(groups, current);
719 BAIL_ON_PTR_ERROR(groups[num_groups], wbc_status);
721 num_groups++;
724 *_num_groups = num_groups;
725 *_groups = groups;
726 groups = NULL;
727 wbc_status = WBC_ERR_SUCCESS;
729 done:
730 winbindd_free_response(&response);
731 if (groups) {
732 talloc_free(groups);
734 return wbc_status;
737 wbcErr wbcGetDisplayName(const struct wbcDomainSid *sid,
738 char **pdomain,
739 char **pfullname,
740 enum wbcSidType *pname_type)
742 wbcErr wbc_status;
743 char *domain = NULL;
744 char *name = NULL;
745 enum wbcSidType name_type;
747 wbc_status = wbcLookupSid(sid, &domain, &name, &name_type);
748 BAIL_ON_WBC_ERROR(wbc_status);
750 if (name_type == WBC_SID_NAME_USER) {
751 uid_t uid;
752 struct passwd *pwd;
754 wbc_status = wbcSidToUid(sid, &uid);
755 BAIL_ON_WBC_ERROR(wbc_status);
757 wbc_status = wbcGetpwuid(uid, &pwd);
758 BAIL_ON_WBC_ERROR(wbc_status);
760 wbcFreeMemory(name);
762 name = talloc_strdup(NULL, pwd->pw_gecos);
763 BAIL_ON_PTR_ERROR(name, wbc_status);
764 wbcFreeMemory(pwd);
767 wbc_status = WBC_ERR_SUCCESS;
769 done:
770 if (WBC_ERROR_IS_OK(wbc_status)) {
771 *pdomain = domain;
772 *pfullname = name;
773 *pname_type = name_type;
774 } else {
775 wbcFreeMemory(domain);
776 wbcFreeMemory(name);
779 return wbc_status;
782 const char* wbcSidTypeString(enum wbcSidType type)
784 switch (type) {
785 case WBC_SID_NAME_USE_NONE: return "SID_NONE";
786 case WBC_SID_NAME_USER: return "SID_USER";
787 case WBC_SID_NAME_DOM_GRP: return "SID_DOM_GROUP";
788 case WBC_SID_NAME_DOMAIN: return "SID_DOMAIN";
789 case WBC_SID_NAME_ALIAS: return "SID_ALIAS";
790 case WBC_SID_NAME_WKN_GRP: return "SID_WKN_GROUP";
791 case WBC_SID_NAME_DELETED: return "SID_DELETED";
792 case WBC_SID_NAME_INVALID: return "SID_INVALID";
793 case WBC_SID_NAME_UNKNOWN: return "SID_UNKNOWN";
794 case WBC_SID_NAME_COMPUTER: return "SID_COMPUTER";
795 default: return "Unknown type";