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
;
641 const char *current
= next
;
642 char *k
= strchr(next
, ',');
650 users
[num_users
] = strdup(current
);
651 BAIL_ON_PTR_ERROR(users
[num_users
], wbc_status
);
653 if (num_users
> response
.data
.num_entries
) {
654 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
658 if (num_users
!= response
.data
.num_entries
) {
659 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
663 *_num_users
= response
.data
.num_entries
;
666 wbc_status
= WBC_ERR_SUCCESS
;
669 winbindd_free_response(&response
);
671 wbcFreeMemory(users
);
677 wbcErr
wbcListGroups(const char *domain_name
,
678 uint32_t *_num_groups
,
679 const char ***_groups
)
681 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
682 struct winbindd_request request
;
683 struct winbindd_response response
;
684 uint32_t num_groups
= 0;
685 const char **groups
= NULL
;
688 /* Initialise request */
690 ZERO_STRUCT(request
);
691 ZERO_STRUCT(response
);
694 strncpy(request
.domain_name
, domain_name
,
695 sizeof(request
.domain_name
)-1);
698 wbc_status
= wbcRequestResponse(WINBINDD_LIST_GROUPS
,
701 BAIL_ON_WBC_ERROR(wbc_status
);
703 groups
= wbcAllocateStringArray(response
.data
.num_entries
);
704 if (groups
== NULL
) {
705 return WBC_ERR_NO_MEMORY
;
708 /* Look through extra data */
710 next
= (const char *)response
.extra_data
.data
;
712 const char *current
= next
;
713 char *k
= strchr(next
, ',');
721 groups
[num_groups
] = strdup(current
);
722 BAIL_ON_PTR_ERROR(groups
[num_groups
], wbc_status
);
724 if (num_groups
> response
.data
.num_entries
) {
725 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
729 if (num_groups
!= response
.data
.num_entries
) {
730 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
734 *_num_groups
= response
.data
.num_entries
;
737 wbc_status
= WBC_ERR_SUCCESS
;
740 winbindd_free_response(&response
);
741 wbcFreeMemory(groups
);
745 wbcErr
wbcGetDisplayName(const struct wbcDomainSid
*sid
,
748 enum wbcSidType
*pname_type
)
753 enum wbcSidType name_type
;
755 wbc_status
= wbcLookupSid(sid
, &domain
, &name
, &name_type
);
756 BAIL_ON_WBC_ERROR(wbc_status
);
758 if (name_type
== WBC_SID_NAME_USER
) {
762 wbc_status
= wbcSidToUid(sid
, &uid
);
763 BAIL_ON_WBC_ERROR(wbc_status
);
765 wbc_status
= wbcGetpwuid(uid
, &pwd
);
766 BAIL_ON_WBC_ERROR(wbc_status
);
770 name
= wbcStrDup(pwd
->pw_gecos
);
771 BAIL_ON_PTR_ERROR(name
, wbc_status
);
775 wbc_status
= WBC_ERR_SUCCESS
;
778 if (WBC_ERROR_IS_OK(wbc_status
)) {
781 *pname_type
= name_type
;
783 wbcFreeMemory(domain
);
790 const char* wbcSidTypeString(enum wbcSidType type
)
793 case WBC_SID_NAME_USE_NONE
: return "SID_NONE";
794 case WBC_SID_NAME_USER
: return "SID_USER";
795 case WBC_SID_NAME_DOM_GRP
: return "SID_DOM_GROUP";
796 case WBC_SID_NAME_DOMAIN
: return "SID_DOMAIN";
797 case WBC_SID_NAME_ALIAS
: return "SID_ALIAS";
798 case WBC_SID_NAME_WKN_GRP
: return "SID_WKN_GROUP";
799 case WBC_SID_NAME_DELETED
: return "SID_DELETED";
800 case WBC_SID_NAME_INVALID
: return "SID_INVALID";
801 case WBC_SID_NAME_UNKNOWN
: return "SID_UNKNOWN";
802 case WBC_SID_NAME_COMPUTER
: return "SID_COMPUTER";
803 default: return "Unknown type";