2 Unix SMB/CIFS implementation.
6 Copyright (C) Gerald (Jerry) Carter 2007
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.
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.
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/>.
23 /* Required Headers */
26 #include "libwbclient.h"
29 /* Convert a binary SID to a character string */
30 wbcErr
wbcSidToString(const struct wbcDomainSid
*sid
,
33 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
39 wbc_status
= WBC_ERR_INVALID_SID
;
40 BAIL_ON_WBC_ERROR(wbc_status
);
43 id_auth
= sid
->id_auth
[5] +
44 (sid
->id_auth
[4] << 8) +
45 (sid
->id_auth
[3] << 16) +
46 (sid
->id_auth
[2] << 24);
48 tmp
= talloc_asprintf(NULL
, "S-%d-%d", sid
->sid_rev_num
, id_auth
);
49 BAIL_ON_PTR_ERROR(tmp
, wbc_status
);
51 for (i
=0; i
<sid
->num_auths
; i
++) {
53 tmp2
= talloc_asprintf_append(tmp
, "-%u", sid
->sub_auths
[i
]);
54 BAIL_ON_PTR_ERROR(tmp2
, wbc_status
);
62 wbc_status
= WBC_ERR_SUCCESS
;
70 /* Convert a character string to a binary SID */
71 wbcErr
wbcStringToSid(const char *str
,
72 struct wbcDomainSid
*sid
)
77 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
80 wbc_status
= WBC_ERR_INVALID_PARAM
;
81 BAIL_ON_WBC_ERROR(wbc_status
);
84 /* Sanity check for either "S-" or "s-" */
87 || (str
[0]!='S' && str
[0]!='s')
90 wbc_status
= WBC_ERR_INVALID_PARAM
;
91 BAIL_ON_WBC_ERROR(wbc_status
);
94 /* Get the SID revision number */
97 x
= (uint32_t)strtol(p
, &q
, 10);
98 if (x
==0 || !q
|| *q
!='-') {
99 wbc_status
= WBC_ERR_INVALID_SID
;
100 BAIL_ON_WBC_ERROR(wbc_status
);
102 sid
->sid_rev_num
= (uint8_t)x
;
104 /* Next the Identifier Authority. This is stored in big-endian
105 in a 6 byte array. */
108 x
= (uint32_t)strtol(p
, &q
, 10);
110 wbc_status
= WBC_ERR_INVALID_SID
;
111 BAIL_ON_WBC_ERROR(wbc_status
);
113 sid
->id_auth
[5] = (x
& 0x000000ff);
114 sid
->id_auth
[4] = (x
& 0x0000ff00) >> 8;
115 sid
->id_auth
[3] = (x
& 0x00ff0000) >> 16;
116 sid
->id_auth
[2] = (x
& 0xff000000) >> 24;
120 /* now read the the subauthorities */
124 while (sid
->num_auths
< WBC_MAXSUBAUTHS
) {
125 x
=(uint32_t)strtoul(p
, &q
, 10);
129 wbc_status
= WBC_ERR_INVALID_SID
;
130 BAIL_ON_WBC_ERROR(wbc_status
);
132 sid
->sub_auths
[sid
->num_auths
++] = x
;
134 if ((*q
!='-') || (*q
=='\0'))
139 /* IF we ended early, then the SID could not be converted */
142 wbc_status
= WBC_ERR_INVALID_SID
;
143 BAIL_ON_WBC_ERROR(wbc_status
);
146 wbc_status
= WBC_ERR_SUCCESS
;
153 /* Convert a domain and name to SID */
154 wbcErr
wbcLookupName(const char *domain
,
156 struct wbcDomainSid
*sid
,
157 enum wbcSidType
*name_type
)
159 struct winbindd_request request
;
160 struct winbindd_response response
;
161 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
163 if (!sid
|| !name_type
) {
164 wbc_status
= WBC_ERR_INVALID_PARAM
;
165 BAIL_ON_WBC_ERROR(wbc_status
);
168 /* Initialize request */
170 ZERO_STRUCT(request
);
171 ZERO_STRUCT(response
);
173 /* dst is already null terminated from the memset above */
175 strncpy(request
.data
.name
.dom_name
, domain
,
176 sizeof(request
.data
.name
.dom_name
)-1);
177 strncpy(request
.data
.name
.name
, name
,
178 sizeof(request
.data
.name
.name
)-1);
180 wbc_status
= wbcRequestResponse(WINBINDD_LOOKUPNAME
,
183 BAIL_ON_WBC_ERROR(wbc_status
);
185 wbc_status
= wbcStringToSid(response
.data
.sid
.sid
, sid
);
186 BAIL_ON_WBC_ERROR(wbc_status
);
188 *name_type
= (enum wbcSidType
)response
.data
.sid
.type
;
190 wbc_status
= WBC_ERR_SUCCESS
;
196 /* Convert a SID to a domain and name */
197 wbcErr
wbcLookupSid(const struct wbcDomainSid
*sid
,
200 enum wbcSidType
*pname_type
)
202 struct winbindd_request request
;
203 struct winbindd_response response
;
204 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
205 char *sid_string
= NULL
;
208 enum wbcSidType name_type
= WBC_SID_NAME_USE_NONE
;
211 wbc_status
= WBC_ERR_INVALID_PARAM
;
212 BAIL_ON_WBC_ERROR(wbc_status
);
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 BAIL_ON_WBC_ERROR(wbc_status
);
225 strncpy(request
.data
.sid
, sid_string
, sizeof(request
.data
.sid
)-1);
226 wbcFreeMemory(sid_string
);
230 wbc_status
= wbcRequestResponse(WINBINDD_LOOKUPSID
,
233 BAIL_ON_WBC_ERROR(wbc_status
);
235 /* Copy out result */
237 domain
= talloc_strdup(NULL
, response
.data
.name
.dom_name
);
238 BAIL_ON_PTR_ERROR(domain
, wbc_status
);
240 name
= talloc_strdup(NULL
, response
.data
.name
.name
);
241 BAIL_ON_PTR_ERROR(name
, wbc_status
);
243 name_type
= (enum wbcSidType
)response
.data
.name
.type
;
245 wbc_status
= WBC_ERR_SUCCESS
;
248 if (WBC_ERROR_IS_OK(wbc_status
)) {
249 if (pdomain
!= NULL
) {
259 if (pname_type
!= NULL
) {
260 *pname_type
= name_type
;
266 * Found by Coverity: In this particular routine we can't end
267 * up here with a non-NULL name. Further up there are just two
268 * exit paths that lead here, neither of which leave an
269 * allocated name. If you add more paths up there, re-activate
276 if (domain
!= NULL
) {
284 /* Translate a collection of RIDs within a domain to names */
286 wbcErr
wbcLookupRids(struct wbcDomainSid
*dom_sid
,
289 const char **pp_domain_name
,
290 const char ***pnames
,
291 enum wbcSidType
**ptypes
)
293 size_t i
, len
, ridbuf_size
;
296 struct winbindd_request request
;
297 struct winbindd_response response
;
298 char *sid_string
= NULL
;
299 char *domain_name
= NULL
;
300 const char **names
= NULL
;
301 enum wbcSidType
*types
= NULL
;
302 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
304 /* Initialise request */
306 ZERO_STRUCT(request
);
307 ZERO_STRUCT(response
);
309 if (!dom_sid
|| (num_rids
== 0)) {
310 wbc_status
= WBC_ERR_INVALID_PARAM
;
311 BAIL_ON_WBC_ERROR(wbc_status
);
314 wbc_status
= wbcSidToString(dom_sid
, &sid_string
);
315 BAIL_ON_WBC_ERROR(wbc_status
);
317 strncpy(request
.data
.sid
, sid_string
, sizeof(request
.data
.sid
)-1);
318 wbcFreeMemory(sid_string
);
320 /* Even if all the Rids were of maximum 32bit values,
321 we would only have 11 bytes per rid in the final array
322 ("4294967296" + \n). Add one more byte for the
325 ridbuf_size
= (sizeof(char)*11) * num_rids
+ 1;
327 ridlist
= talloc_zero_array(NULL
, char, ridbuf_size
);
328 BAIL_ON_PTR_ERROR(ridlist
, wbc_status
);
331 for (i
=0; i
<num_rids
&& (len
-1)>0; i
++) {
334 len
= strlen(ridlist
);
337 snprintf( ridstr
, sizeof(ridstr
)-1, "%u\n", rids
[i
]);
338 strncat(p
, ridstr
, ridbuf_size
-len
-1);
341 request
.extra_data
.data
= ridlist
;
342 request
.extra_len
= strlen(ridlist
)+1;
344 wbc_status
= wbcRequestResponse(WINBINDD_LOOKUPRIDS
,
347 talloc_free(ridlist
);
348 BAIL_ON_WBC_ERROR(wbc_status
);
350 domain_name
= talloc_strdup(NULL
, response
.data
.domain_name
);
351 BAIL_ON_PTR_ERROR(domain_name
, wbc_status
);
353 names
= talloc_array(NULL
, const char*, num_rids
);
354 BAIL_ON_PTR_ERROR(names
, wbc_status
);
356 types
= talloc_array(NULL
, enum wbcSidType
, num_rids
);
357 BAIL_ON_PTR_ERROR(types
, wbc_status
);
359 p
= (char *)response
.extra_data
.data
;
361 for (i
=0; i
<num_rids
; i
++) {
365 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
366 BAIL_ON_WBC_ERROR(wbc_status
);
369 types
[i
] = (enum wbcSidType
)strtoul(p
, &q
, 10);
372 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
373 BAIL_ON_WBC_ERROR(wbc_status
);
378 if ((q
= strchr(p
, '\n')) == NULL
) {
379 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
380 BAIL_ON_WBC_ERROR(wbc_status
);
385 names
[i
] = talloc_strdup(names
, p
);
386 BAIL_ON_PTR_ERROR(names
[i
], wbc_status
);
392 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
393 BAIL_ON_WBC_ERROR(wbc_status
);
396 wbc_status
= WBC_ERR_SUCCESS
;
399 if (response
.extra_data
.data
) {
400 free(response
.extra_data
.data
);
403 if (WBC_ERROR_IS_OK(wbc_status
)) {
404 *pp_domain_name
= domain_name
;
410 talloc_free(domain_name
);
420 /* Get the groups a user belongs to */
421 wbcErr
wbcLookupUserSids(const struct wbcDomainSid
*user_sid
,
422 bool domain_groups_only
,
424 struct wbcDomainSid
**_sids
)
428 struct winbindd_request request
;
429 struct winbindd_response response
;
430 char *sid_string
= NULL
;
431 struct wbcDomainSid
*sids
= NULL
;
432 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
435 /* Initialise request */
437 ZERO_STRUCT(request
);
438 ZERO_STRUCT(response
);
441 wbc_status
= WBC_ERR_INVALID_PARAM
;
442 BAIL_ON_WBC_ERROR(wbc_status
);
445 wbc_status
= wbcSidToString(user_sid
, &sid_string
);
446 BAIL_ON_WBC_ERROR(wbc_status
);
448 strncpy(request
.data
.sid
, sid_string
, sizeof(request
.data
.sid
)-1);
449 wbcFreeMemory(sid_string
);
451 if (domain_groups_only
) {
452 cmd
= WINBINDD_GETUSERDOMGROUPS
;
454 cmd
= WINBINDD_GETUSERSIDS
;
457 wbc_status
= wbcRequestResponse(cmd
,
460 BAIL_ON_WBC_ERROR(wbc_status
);
462 if (response
.data
.num_entries
&&
463 !response
.extra_data
.data
) {
464 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
465 BAIL_ON_WBC_ERROR(wbc_status
);
468 sids
= talloc_array(NULL
, struct wbcDomainSid
,
469 response
.data
.num_entries
);
470 BAIL_ON_PTR_ERROR(sids
, wbc_status
);
472 s
= (const char *)response
.extra_data
.data
;
473 for (i
= 0; i
< response
.data
.num_entries
; i
++) {
474 char *n
= strchr(s
, '\n');
478 wbc_status
= wbcStringToSid(s
, &sids
[i
]);
479 BAIL_ON_WBC_ERROR(wbc_status
);
483 *num_sids
= response
.data
.num_entries
;
486 wbc_status
= WBC_ERR_SUCCESS
;
489 if (response
.extra_data
.data
) {
490 free(response
.extra_data
.data
);
500 wbcErr
_sid_to_rid(struct wbcDomainSid
*sid
, uint32_t *rid
)
502 if (sid
->num_auths
< 1) {
503 return WBC_ERR_INVALID_RESPONSE
;
505 *rid
= sid
->sub_auths
[sid
->num_auths
- 1];
507 return WBC_ERR_SUCCESS
;
510 /* Get alias membership for sids */
511 wbcErr
wbcGetSidAliases(const struct wbcDomainSid
*dom_sid
,
512 struct wbcDomainSid
*sids
,
514 uint32_t **alias_rids
,
515 uint32_t *num_alias_rids
)
519 struct winbindd_request request
;
520 struct winbindd_response response
;
521 char *sid_string
= NULL
;
523 ssize_t extra_data_len
= 0;
524 char * extra_data
= NULL
;
526 struct wbcDomainSid sid
;
527 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
528 uint32_t * rids
= NULL
;
530 /* Initialise request */
532 ZERO_STRUCT(request
);
533 ZERO_STRUCT(response
);
536 wbc_status
= WBC_ERR_INVALID_PARAM
;
537 BAIL_ON_WBC_ERROR(wbc_status
);
540 wbc_status
= wbcSidToString(dom_sid
, &sid_string
);
541 BAIL_ON_WBC_ERROR(wbc_status
);
543 strncpy(request
.data
.sid
, sid_string
, sizeof(request
.data
.sid
)-1);
544 wbcFreeMemory(sid_string
);
547 /* Lets assume each sid is around 54 characters
548 * S-1-5-AAAAAAAAAAA-BBBBBBBBBBB-CCCCCCCCCCC-DDDDDDDDDDD\n */
549 buflen
= 54 * num_sids
;
550 extra_data
= talloc_array(NULL
, char, buflen
);
552 wbc_status
= WBC_ERR_NO_MEMORY
;
553 BAIL_ON_WBC_ERROR(wbc_status
);
556 /* Build the sid list */
557 for (i
=0; i
<num_sids
; i
++) {
559 wbcFreeMemory(sid_string
);
562 wbc_status
= wbcSidToString(&sids
[i
], &sid_string
);
563 BAIL_ON_WBC_ERROR(wbc_status
);
565 sid_len
= strlen(sid_string
);
567 if (buflen
< extra_data_len
+ sid_len
+ 2) {
569 extra_data
= talloc_realloc(NULL
, extra_data
,
572 wbc_status
= WBC_ERR_NO_MEMORY
;
573 BAIL_ON_WBC_ERROR(wbc_status
);
577 strncpy(&extra_data
[extra_data_len
], sid_string
,
578 buflen
- extra_data_len
);
579 extra_data_len
+= sid_len
;
580 extra_data
[extra_data_len
++] = '\n';
581 extra_data
[extra_data_len
] = '\0';
584 request
.extra_data
.data
= extra_data
;
585 request
.extra_len
= extra_data_len
;
587 wbc_status
= wbcRequestResponse(WINBINDD_GETSIDALIASES
,
590 BAIL_ON_WBC_ERROR(wbc_status
);
592 if (response
.data
.num_entries
&&
593 !response
.extra_data
.data
) {
594 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
595 BAIL_ON_WBC_ERROR(wbc_status
);
598 rids
= talloc_array(NULL
, uint32_t,
599 response
.data
.num_entries
);
600 BAIL_ON_PTR_ERROR(sids
, wbc_status
);
602 s
= (const char *)response
.extra_data
.data
;
603 for (i
= 0; i
< response
.data
.num_entries
; i
++) {
604 char *n
= strchr(s
, '\n');
608 wbc_status
= wbcStringToSid(s
, &sid
);
609 BAIL_ON_WBC_ERROR(wbc_status
);
610 wbc_status
= _sid_to_rid(&sid
, &rids
[i
]);
611 BAIL_ON_WBC_ERROR(wbc_status
);
615 *num_alias_rids
= response
.data
.num_entries
;
618 wbc_status
= WBC_ERR_SUCCESS
;
622 wbcFreeMemory(sid_string
);
625 talloc_free(extra_data
);
627 if (response
.extra_data
.data
) {
628 free(response
.extra_data
.data
);
639 wbcErr
wbcListUsers(const char *domain_name
,
640 uint32_t *_num_users
,
641 const char ***_users
)
643 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
644 struct winbindd_request request
;
645 struct winbindd_response response
;
646 uint32_t num_users
= 0;
647 const char **users
= NULL
;
650 /* Initialise request */
652 ZERO_STRUCT(request
);
653 ZERO_STRUCT(response
);
656 strncpy(request
.domain_name
, domain_name
,
657 sizeof(request
.domain_name
)-1);
660 wbc_status
= wbcRequestResponse(WINBINDD_LIST_USERS
,
663 BAIL_ON_WBC_ERROR(wbc_status
);
665 /* Look through extra data */
667 next
= (const char *)response
.extra_data
.data
;
670 const char *current
= next
;
671 char *k
= strchr(next
, ',');
679 tmp
= talloc_realloc(NULL
, users
,
682 BAIL_ON_PTR_ERROR(tmp
, wbc_status
);
685 users
[num_users
] = talloc_strdup(users
, current
);
686 BAIL_ON_PTR_ERROR(users
[num_users
], wbc_status
);
691 *_num_users
= num_users
;
694 wbc_status
= WBC_ERR_SUCCESS
;
697 if (response
.extra_data
.data
) {
698 free(response
.extra_data
.data
);
707 wbcErr
wbcListGroups(const char *domain_name
,
708 uint32_t *_num_groups
,
709 const char ***_groups
)
711 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
712 struct winbindd_request request
;
713 struct winbindd_response response
;
714 uint32_t num_groups
= 0;
715 const char **groups
= NULL
;
718 /* Initialise request */
720 ZERO_STRUCT(request
);
721 ZERO_STRUCT(response
);
724 strncpy(request
.domain_name
, domain_name
,
725 sizeof(request
.domain_name
)-1);
728 wbc_status
= wbcRequestResponse(WINBINDD_LIST_GROUPS
,
731 BAIL_ON_WBC_ERROR(wbc_status
);
733 /* Look through extra data */
735 next
= (const char *)response
.extra_data
.data
;
738 const char *current
= next
;
739 char *k
= strchr(next
, ',');
747 tmp
= talloc_realloc(NULL
, groups
,
750 BAIL_ON_PTR_ERROR(tmp
, wbc_status
);
753 groups
[num_groups
] = talloc_strdup(groups
, current
);
754 BAIL_ON_PTR_ERROR(groups
[num_groups
], wbc_status
);
759 *_num_groups
= num_groups
;
762 wbc_status
= WBC_ERR_SUCCESS
;
765 if (response
.extra_data
.data
) {
766 free(response
.extra_data
.data
);
774 wbcErr
wbcGetDisplayName(const struct wbcDomainSid
*sid
,
777 enum wbcSidType
*pname_type
)
782 enum wbcSidType name_type
;
784 wbc_status
= wbcLookupSid(sid
, &domain
, &name
, &name_type
);
785 BAIL_ON_WBC_ERROR(wbc_status
);
787 if (name_type
== WBC_SID_NAME_USER
) {
791 wbc_status
= wbcSidToUid(sid
, &uid
);
792 BAIL_ON_WBC_ERROR(wbc_status
);
794 wbc_status
= wbcGetpwuid(uid
, &pwd
);
795 BAIL_ON_WBC_ERROR(wbc_status
);
799 name
= talloc_strdup(NULL
, pwd
->pw_gecos
);
800 BAIL_ON_PTR_ERROR(name
, wbc_status
);
803 wbc_status
= WBC_ERR_SUCCESS
;
806 if (WBC_ERROR_IS_OK(wbc_status
)) {
809 *pname_type
= name_type
;
811 wbcFreeMemory(domain
);
818 const char* wbcSidTypeString(enum wbcSidType type
)
821 case WBC_SID_NAME_USE_NONE
: return "SID_NONE";
822 case WBC_SID_NAME_USER
: return "SID_USER";
823 case WBC_SID_NAME_DOM_GRP
: return "SID_DOM_GROUP";
824 case WBC_SID_NAME_DOMAIN
: return "SID_DOMAIN";
825 case WBC_SID_NAME_ALIAS
: return "SID_ALIAS";
826 case WBC_SID_NAME_WKN_GRP
: return "SID_WKN_GROUP";
827 case WBC_SID_NAME_DELETED
: return "SID_DELETED";
828 case WBC_SID_NAME_INVALID
: return "SID_INVALID";
829 case WBC_SID_NAME_UNKNOWN
: return "SID_UNKNOWN";
830 case WBC_SID_NAME_COMPUTER
: return "SID_COMPUTER";
831 default: return "Unknown type";