2 Unix SMB/CIFS implementation.
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 */
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,
39 return WBC_ERR_INVALID_SID;
42 maxlen = sid->num_auths * 11 + 25;
44 result = (char *)wbcAllocateMemory(maxlen, 1, 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]);
68 return WBC_ERR_SUCCESS;
71 /* Convert a character string to a binary SID */
72 wbcErr wbcStringToSid(const char *str,
73 struct wbcDomainSid *sid)
78 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
81 wbc_status = WBC_ERR_INVALID_PARAM;
82 BAIL_ON_WBC_ERROR(wbc_status);
85 /* Sanity check for either "S-" or "s-" */
88 || (str[0]!='S' && str[0]!='s')
91 wbc_status = WBC_ERR_INVALID_PARAM;
92 BAIL_ON_WBC_ERROR(wbc_status);
95 /* Get the SID revision number */
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. */
109 x = (uint32_t)strtol(p, &q, 10);
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;
121 /* now read the the subauthorities */
125 while (sid->num_auths < WBC_MAXSUBAUTHS) {
126 x=(uint32_t)strtoul(p, &q, 10);
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'))
140 /* IF we ended early, then the SID could not be converted */
143 wbc_status = WBC_ERR_INVALID_SID;
144 BAIL_ON_WBC_ERROR(wbc_status);
147 wbc_status = WBC_ERR_SUCCESS;
155 /* Convert a domain and name to SID */
156 wbcErr wbcLookupName(const char *domain,
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,
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;
199 /* Convert a SID to a domain and name */
200 wbcErr wbcLookupSid(const struct wbcDomainSid *sid,
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;
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)) {
227 strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
228 wbcFreeMemory(sid_string);
232 wbc_status = wbcRequestResponse(WINBINDD_LOOKUPSID, &request,
234 if (!WBC_ERROR_IS_OK(wbc_status)) {
238 /* Copy out result */
240 wbc_status = WBC_ERR_NO_MEMORY;
244 domain = wbcStrDup(response.data.name.dom_name);
245 if (domain == NULL) {
248 name = wbcStrDup(response.data.name.name);
252 if (pdomain != NULL) {
260 if (pname_type != NULL) {
261 *pname_type = (enum wbcSidType)response.data.name.type;
263 wbc_status = WBC_ERR_SUCCESS;
266 wbcFreeMemory(domain);
270 /* Translate a collection of RIDs within a domain to names */
272 wbcErr wbcLookupRids(struct wbcDomainSid *dom_sid,
275 const char **pp_domain_name,
276 const char ***pnames,
277 enum wbcSidType **ptypes)
279 size_t i, len, ridbuf_size;
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
311 ridbuf_size = (sizeof(char)*11) * num_rids + 1;
313 ridlist = (char *)malloc(ridbuf_size);
314 BAIL_ON_PTR_ERROR(ridlist, wbc_status);
317 for (i=0; i<num_rids; i++) {
318 len += snprintf(ridlist + len, ridbuf_size - len, "%u\n",
324 request.extra_data.data = ridlist;
325 request.extra_len = len;
327 wbc_status = wbcRequestResponse(WINBINDD_LOOKUPRIDS,
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++) {
349 wbc_status = WBC_ERR_INVALID_RESPONSE;
353 types[i] = (enum wbcSidType)strtoul(p, &q, 10);
356 wbc_status = WBC_ERR_INVALID_RESPONSE;
362 if ((q = strchr(p, '\n')) == NULL) {
363 wbc_status = WBC_ERR_INVALID_RESPONSE;
369 names[i] = strdup(p);
370 BAIL_ON_PTR_ERROR(names[i], wbc_status);
376 wbc_status = WBC_ERR_INVALID_RESPONSE;
380 wbc_status = WBC_ERR_SUCCESS;
383 winbindd_free_response(&response);
385 if (WBC_ERROR_IS_OK(wbc_status)) {
386 *pp_domain_name = domain_name;
391 wbcFreeMemory(domain_name);
392 wbcFreeMemory(names);
393 wbcFreeMemory(types);
399 /* Get the groups a user belongs to */
400 wbcErr wbcLookupUserSids(const struct wbcDomainSid *user_sid,
401 bool domain_groups_only,
403 struct wbcDomainSid **_sids)
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;
414 /* Initialise request */
416 ZERO_STRUCT(request);
417 ZERO_STRUCT(response);
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;
433 cmd = WINBINDD_GETUSERSIDS;
436 wbc_status = wbcRequestResponse(cmd,
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 = (struct wbcDomainSid *)wbcAllocateMemory(
448 response.data.num_entries, sizeof(struct wbcDomainSid),
450 BAIL_ON_PTR_ERROR(sids, wbc_status);
452 s = (const char *)response.extra_data.data;
453 for (i = 0; i < response.data.num_entries; i++) {
454 char *n = strchr(s, '\n');
458 wbc_status = wbcStringToSid(s, &sids[i]);
459 BAIL_ON_WBC_ERROR(wbc_status);
463 *num_sids = response.data.num_entries;
466 wbc_status = WBC_ERR_SUCCESS;
469 winbindd_free_response(&response);
478 wbcErr _sid_to_rid(struct wbcDomainSid *sid, uint32_t *rid)
480 if (sid->num_auths < 1) {
481 return WBC_ERR_INVALID_RESPONSE;
483 *rid = sid->sub_auths[sid->num_auths - 1];
485 return WBC_ERR_SUCCESS;
488 /* Get alias membership for sids */
489 wbcErr wbcGetSidAliases(const struct wbcDomainSid *dom_sid,
490 struct wbcDomainSid *sids,
492 uint32_t **alias_rids,
493 uint32_t *num_alias_rids)
497 struct winbindd_request request;
498 struct winbindd_response response;
499 char *sid_string = NULL;
501 ssize_t extra_data_len = 0;
502 char * extra_data = NULL;
504 struct wbcDomainSid sid;
505 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
506 uint32_t * rids = NULL;
508 /* Initialise request */
510 ZERO_STRUCT(request);
511 ZERO_STRUCT(response);
514 wbc_status = WBC_ERR_INVALID_PARAM;
518 wbc_status = wbcSidToString(dom_sid, &sid_string);
519 BAIL_ON_WBC_ERROR(wbc_status);
521 strncpy(request.data.sid, sid_string, sizeof(request.data.sid)-1);
522 wbcFreeMemory(sid_string);
525 /* Lets assume each sid is around 57 characters
526 * S-1-5-21-AAAAAAAAAAA-BBBBBBBBBBB-CCCCCCCCCCC-DDDDDDDDDDD\n */
527 buflen = 57 * num_sids;
528 extra_data = (char *)malloc(buflen);
530 wbc_status = WBC_ERR_NO_MEMORY;
534 /* Build the sid list */
535 for (i=0; i<num_sids; i++) {
536 wbc_status = wbcSidToString(&sids[i], &sid_string);
537 BAIL_ON_WBC_ERROR(wbc_status);
539 sid_len = strlen(sid_string);
541 if (buflen < extra_data_len + sid_len + 2) {
543 extra_data = (char *)realloc(extra_data, buflen);
545 wbc_status = WBC_ERR_NO_MEMORY;
546 BAIL_ON_WBC_ERROR(wbc_status);
550 strncpy(&extra_data[extra_data_len], sid_string,
551 buflen - extra_data_len);
552 extra_data_len += sid_len;
553 extra_data[extra_data_len++] = '\n';
554 extra_data[extra_data_len] = '\0';
555 wbcFreeMemory(sid_string);
560 request.extra_data.data = extra_data;
561 request.extra_len = extra_data_len;
563 wbc_status = wbcRequestResponse(WINBINDD_GETSIDALIASES,
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;
574 rids = (uint32_t *)wbcAllocateMemory(response.data.num_entries,
575 sizeof(uint32_t), NULL);
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');
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);
591 *num_alias_rids = response.data.num_entries;
594 wbc_status = WBC_ERR_SUCCESS;
597 wbcFreeMemory(sid_string);
599 winbindd_free_response(&response);
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;
617 /* Initialise request */
619 ZERO_STRUCT(request);
620 ZERO_STRUCT(response);
623 strncpy(request.domain_name, domain_name,
624 sizeof(request.domain_name)-1);
627 wbc_status = wbcRequestResponse(WINBINDD_LIST_USERS,
630 BAIL_ON_WBC_ERROR(wbc_status);
632 users = wbcAllocateStringArray(response.data.num_entries);
634 return WBC_ERR_NO_MEMORY;
637 /* Look through extra data */
639 next = (const char *)response.extra_data.data;
644 if (num_users >= response.data.num_entries) {
645 wbc_status = WBC_ERR_INVALID_RESPONSE;
650 k = strchr(next, ',');
659 users[num_users] = strdup(current);
660 BAIL_ON_PTR_ERROR(users[num_users], wbc_status);
663 if (num_users != response.data.num_entries) {
664 wbc_status = WBC_ERR_INVALID_RESPONSE;
668 *_num_users = response.data.num_entries;
671 wbc_status = WBC_ERR_SUCCESS;
674 winbindd_free_response(&response);
675 wbcFreeMemory(users);
680 wbcErr wbcListGroups(const char *domain_name,
681 uint32_t *_num_groups,
682 const char ***_groups)
684 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
685 struct winbindd_request request;
686 struct winbindd_response response;
687 uint32_t num_groups = 0;
688 const char **groups = NULL;
691 /* Initialise request */
693 ZERO_STRUCT(request);
694 ZERO_STRUCT(response);
697 strncpy(request.domain_name, domain_name,
698 sizeof(request.domain_name)-1);
701 wbc_status = wbcRequestResponse(WINBINDD_LIST_GROUPS,
704 BAIL_ON_WBC_ERROR(wbc_status);
706 groups = wbcAllocateStringArray(response.data.num_entries);
707 if (groups == NULL) {
708 return WBC_ERR_NO_MEMORY;
711 /* Look through extra data */
713 next = (const char *)response.extra_data.data;
718 if (num_groups >= response.data.num_entries) {
719 wbc_status = WBC_ERR_INVALID_RESPONSE;
724 k = strchr(next, ',');
733 groups[num_groups] = strdup(current);
734 BAIL_ON_PTR_ERROR(groups[num_groups], wbc_status);
737 if (num_groups != response.data.num_entries) {
738 wbc_status = WBC_ERR_INVALID_RESPONSE;
742 *_num_groups = response.data.num_entries;
745 wbc_status = WBC_ERR_SUCCESS;
748 winbindd_free_response(&response);
749 wbcFreeMemory(groups);
753 wbcErr wbcGetDisplayName(const struct wbcDomainSid *sid,
756 enum wbcSidType *pname_type)
761 enum wbcSidType name_type;
763 wbc_status = wbcLookupSid(sid, &domain, &name, &name_type);
764 BAIL_ON_WBC_ERROR(wbc_status);
766 if (name_type == WBC_SID_NAME_USER) {
770 wbc_status = wbcSidToUid(sid, &uid);
771 BAIL_ON_WBC_ERROR(wbc_status);
773 wbc_status = wbcGetpwuid(uid, &pwd);
774 BAIL_ON_WBC_ERROR(wbc_status);
778 name = wbcStrDup(pwd->pw_gecos);
779 BAIL_ON_PTR_ERROR(name, wbc_status);
783 wbc_status = WBC_ERR_SUCCESS;
786 if (WBC_ERROR_IS_OK(wbc_status)) {
789 *pname_type = name_type;
791 wbcFreeMemory(domain);
798 const char* wbcSidTypeString(enum wbcSidType type)
801 case WBC_SID_NAME_USE_NONE: return "SID_NONE";
802 case WBC_SID_NAME_USER: return "SID_USER";
803 case WBC_SID_NAME_DOM_GRP: return "SID_DOM_GROUP";
804 case WBC_SID_NAME_DOMAIN: return "SID_DOMAIN";
805 case WBC_SID_NAME_ALIAS: return "SID_ALIAS";
806 case WBC_SID_NAME_WKN_GRP: return "SID_WKN_GROUP";
807 case WBC_SID_NAME_DELETED: return "SID_DELETED";
808 case WBC_SID_NAME_INVALID: return "SID_INVALID";
809 case WBC_SID_NAME_UNKNOWN: return "SID_UNKNOWN";
810 case WBC_SID_NAME_COMPUTER: return "SID_COMPUTER";
811 default: return "Unknown type";