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
= 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');
457 wbc_status
= wbcStringToSid(s
, &sids
[i
]);
458 BAIL_ON_WBC_ERROR(wbc_status
);
462 *num_sids
= response
.data
.num_entries
;
465 wbc_status
= WBC_ERR_SUCCESS
;
468 winbindd_free_response(&response
);
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
,
491 uint32_t **alias_rids
,
492 uint32_t *num_alias_rids
)
496 struct winbindd_request request
;
497 struct winbindd_response response
;
498 char *sid_string
= NULL
;
500 ssize_t extra_data_len
= 0;
501 char * extra_data
= NULL
;
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
);
513 wbc_status
= WBC_ERR_INVALID_PARAM
;
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
);
524 /* Lets assume each sid is around 57 characters
525 * S-1-5-21-AAAAAAAAAAA-BBBBBBBBBBB-CCCCCCCCCCC-DDDDDDDDDDD\n */
526 buflen
= 57 * num_sids
;
527 extra_data
= (char *)malloc(buflen
);
529 wbc_status
= WBC_ERR_NO_MEMORY
;
533 /* Build the sid list */
534 for (i
=0; i
<num_sids
; i
++) {
535 wbcFreeMemory(sid_string
);
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) {
544 extra_data
= talloc_realloc(NULL
, 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';
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
= 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');
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
);
598 talloc_free(extra_data
);
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 /* Look through extra data */
634 next
= (const char *)response
.extra_data
.data
;
637 const char *current
= next
;
638 char *k
= strchr(next
, ',');
646 tmp
= talloc_realloc(NULL
, users
,
649 BAIL_ON_PTR_ERROR(tmp
, wbc_status
);
652 users
[num_users
] = talloc_strdup(users
, current
);
653 BAIL_ON_PTR_ERROR(users
[num_users
], wbc_status
);
658 *_num_users
= num_users
;
661 wbc_status
= WBC_ERR_SUCCESS
;
664 winbindd_free_response(&response
);
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
;
683 /* Initialise request */
685 ZERO_STRUCT(request
);
686 ZERO_STRUCT(response
);
689 strncpy(request
.domain_name
, domain_name
,
690 sizeof(request
.domain_name
)-1);
693 wbc_status
= wbcRequestResponse(WINBINDD_LIST_GROUPS
,
696 BAIL_ON_WBC_ERROR(wbc_status
);
698 /* Look through extra data */
700 next
= (const char *)response
.extra_data
.data
;
703 const char *current
= next
;
704 char *k
= strchr(next
, ',');
712 tmp
= talloc_realloc(NULL
, groups
,
715 BAIL_ON_PTR_ERROR(tmp
, wbc_status
);
718 groups
[num_groups
] = talloc_strdup(groups
, current
);
719 BAIL_ON_PTR_ERROR(groups
[num_groups
], wbc_status
);
724 *_num_groups
= num_groups
;
727 wbc_status
= WBC_ERR_SUCCESS
;
730 winbindd_free_response(&response
);
737 wbcErr
wbcGetDisplayName(const struct wbcDomainSid
*sid
,
740 enum wbcSidType
*pname_type
)
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
) {
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
);
762 name
= talloc_strdup(NULL
, pwd
->pw_gecos
);
763 BAIL_ON_PTR_ERROR(name
, wbc_status
);
767 wbc_status
= WBC_ERR_SUCCESS
;
770 if (WBC_ERROR_IS_OK(wbc_status
)) {
773 *pname_type
= name_type
;
775 wbcFreeMemory(domain
);
782 const char* wbcSidTypeString(enum wbcSidType 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";