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"
27 #include "../winbind_client.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 winbindd_free_response(&response
);
401 if (WBC_ERROR_IS_OK(wbc_status
)) {
402 *pp_domain_name
= domain_name
;
408 talloc_free(domain_name
);
418 /* Get the groups a user belongs to */
419 wbcErr
wbcLookupUserSids(const struct wbcDomainSid
*user_sid
,
420 bool domain_groups_only
,
422 struct wbcDomainSid
**_sids
)
426 struct winbindd_request request
;
427 struct winbindd_response response
;
428 char *sid_string
= NULL
;
429 struct wbcDomainSid
*sids
= NULL
;
430 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
433 /* Initialise request */
435 ZERO_STRUCT(request
);
436 ZERO_STRUCT(response
);
439 wbc_status
= WBC_ERR_INVALID_PARAM
;
440 BAIL_ON_WBC_ERROR(wbc_status
);
443 wbc_status
= wbcSidToString(user_sid
, &sid_string
);
444 BAIL_ON_WBC_ERROR(wbc_status
);
446 strncpy(request
.data
.sid
, sid_string
, sizeof(request
.data
.sid
)-1);
447 wbcFreeMemory(sid_string
);
449 if (domain_groups_only
) {
450 cmd
= WINBINDD_GETUSERDOMGROUPS
;
452 cmd
= WINBINDD_GETUSERSIDS
;
455 wbc_status
= wbcRequestResponse(cmd
,
458 BAIL_ON_WBC_ERROR(wbc_status
);
460 if (response
.data
.num_entries
&&
461 !response
.extra_data
.data
) {
462 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
463 BAIL_ON_WBC_ERROR(wbc_status
);
466 sids
= talloc_array(NULL
, struct wbcDomainSid
,
467 response
.data
.num_entries
);
468 BAIL_ON_PTR_ERROR(sids
, wbc_status
);
470 s
= (const char *)response
.extra_data
.data
;
471 for (i
= 0; i
< response
.data
.num_entries
; i
++) {
472 char *n
= strchr(s
, '\n');
476 wbc_status
= wbcStringToSid(s
, &sids
[i
]);
477 BAIL_ON_WBC_ERROR(wbc_status
);
481 *num_sids
= response
.data
.num_entries
;
484 wbc_status
= WBC_ERR_SUCCESS
;
487 winbindd_free_response(&response
);
496 wbcErr
_sid_to_rid(struct wbcDomainSid
*sid
, uint32_t *rid
)
498 if (sid
->num_auths
< 1) {
499 return WBC_ERR_INVALID_RESPONSE
;
501 *rid
= sid
->sub_auths
[sid
->num_auths
- 1];
503 return WBC_ERR_SUCCESS
;
506 /* Get alias membership for sids */
507 wbcErr
wbcGetSidAliases(const struct wbcDomainSid
*dom_sid
,
508 struct wbcDomainSid
*sids
,
510 uint32_t **alias_rids
,
511 uint32_t *num_alias_rids
)
515 struct winbindd_request request
;
516 struct winbindd_response response
;
517 char *sid_string
= NULL
;
519 ssize_t extra_data_len
= 0;
520 char * extra_data
= NULL
;
522 struct wbcDomainSid sid
;
523 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
524 uint32_t * rids
= NULL
;
526 /* Initialise request */
528 ZERO_STRUCT(request
);
529 ZERO_STRUCT(response
);
532 wbc_status
= WBC_ERR_INVALID_PARAM
;
533 BAIL_ON_WBC_ERROR(wbc_status
);
536 wbc_status
= wbcSidToString(dom_sid
, &sid_string
);
537 BAIL_ON_WBC_ERROR(wbc_status
);
539 strncpy(request
.data
.sid
, sid_string
, sizeof(request
.data
.sid
)-1);
540 wbcFreeMemory(sid_string
);
543 /* Lets assume each sid is around 54 characters
544 * S-1-5-AAAAAAAAAAA-BBBBBBBBBBB-CCCCCCCCCCC-DDDDDDDDDDD\n */
545 buflen
= 54 * num_sids
;
546 extra_data
= talloc_array(NULL
, char, buflen
);
548 wbc_status
= WBC_ERR_NO_MEMORY
;
549 BAIL_ON_WBC_ERROR(wbc_status
);
552 /* Build the sid list */
553 for (i
=0; i
<num_sids
; i
++) {
555 wbcFreeMemory(sid_string
);
558 wbc_status
= wbcSidToString(&sids
[i
], &sid_string
);
559 BAIL_ON_WBC_ERROR(wbc_status
);
561 sid_len
= strlen(sid_string
);
563 if (buflen
< extra_data_len
+ sid_len
+ 2) {
565 extra_data
= talloc_realloc(NULL
, extra_data
,
568 wbc_status
= WBC_ERR_NO_MEMORY
;
569 BAIL_ON_WBC_ERROR(wbc_status
);
573 strncpy(&extra_data
[extra_data_len
], sid_string
,
574 buflen
- extra_data_len
);
575 extra_data_len
+= sid_len
;
576 extra_data
[extra_data_len
++] = '\n';
577 extra_data
[extra_data_len
] = '\0';
580 request
.extra_data
.data
= extra_data
;
581 request
.extra_len
= extra_data_len
;
583 wbc_status
= wbcRequestResponse(WINBINDD_GETSIDALIASES
,
586 BAIL_ON_WBC_ERROR(wbc_status
);
588 if (response
.data
.num_entries
&&
589 !response
.extra_data
.data
) {
590 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
591 BAIL_ON_WBC_ERROR(wbc_status
);
594 rids
= talloc_array(NULL
, uint32_t,
595 response
.data
.num_entries
);
596 BAIL_ON_PTR_ERROR(sids
, wbc_status
);
598 s
= (const char *)response
.extra_data
.data
;
599 for (i
= 0; i
< response
.data
.num_entries
; i
++) {
600 char *n
= strchr(s
, '\n');
604 wbc_status
= wbcStringToSid(s
, &sid
);
605 BAIL_ON_WBC_ERROR(wbc_status
);
606 wbc_status
= _sid_to_rid(&sid
, &rids
[i
]);
607 BAIL_ON_WBC_ERROR(wbc_status
);
611 *num_alias_rids
= response
.data
.num_entries
;
614 wbc_status
= WBC_ERR_SUCCESS
;
618 wbcFreeMemory(sid_string
);
621 talloc_free(extra_data
);
623 winbindd_free_response(&response
);
633 wbcErr
wbcListUsers(const char *domain_name
,
634 uint32_t *_num_users
,
635 const char ***_users
)
637 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
638 struct winbindd_request request
;
639 struct winbindd_response response
;
640 uint32_t num_users
= 0;
641 const char **users
= NULL
;
644 /* Initialise request */
646 ZERO_STRUCT(request
);
647 ZERO_STRUCT(response
);
650 strncpy(request
.domain_name
, domain_name
,
651 sizeof(request
.domain_name
)-1);
654 wbc_status
= wbcRequestResponse(WINBINDD_LIST_USERS
,
657 BAIL_ON_WBC_ERROR(wbc_status
);
659 /* Look through extra data */
661 next
= (const char *)response
.extra_data
.data
;
664 const char *current
= next
;
665 char *k
= strchr(next
, ',');
673 tmp
= talloc_realloc(NULL
, users
,
676 BAIL_ON_PTR_ERROR(tmp
, wbc_status
);
679 users
[num_users
] = talloc_strdup(users
, current
);
680 BAIL_ON_PTR_ERROR(users
[num_users
], wbc_status
);
685 *_num_users
= num_users
;
688 wbc_status
= WBC_ERR_SUCCESS
;
691 winbindd_free_response(&response
);
699 wbcErr
wbcListGroups(const char *domain_name
,
700 uint32_t *_num_groups
,
701 const char ***_groups
)
703 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
704 struct winbindd_request request
;
705 struct winbindd_response response
;
706 uint32_t num_groups
= 0;
707 const char **groups
= NULL
;
710 /* Initialise request */
712 ZERO_STRUCT(request
);
713 ZERO_STRUCT(response
);
716 strncpy(request
.domain_name
, domain_name
,
717 sizeof(request
.domain_name
)-1);
720 wbc_status
= wbcRequestResponse(WINBINDD_LIST_GROUPS
,
723 BAIL_ON_WBC_ERROR(wbc_status
);
725 /* Look through extra data */
727 next
= (const char *)response
.extra_data
.data
;
730 const char *current
= next
;
731 char *k
= strchr(next
, ',');
739 tmp
= talloc_realloc(NULL
, groups
,
742 BAIL_ON_PTR_ERROR(tmp
, wbc_status
);
745 groups
[num_groups
] = talloc_strdup(groups
, current
);
746 BAIL_ON_PTR_ERROR(groups
[num_groups
], wbc_status
);
751 *_num_groups
= num_groups
;
754 wbc_status
= WBC_ERR_SUCCESS
;
757 winbindd_free_response(&response
);
764 wbcErr
wbcGetDisplayName(const struct wbcDomainSid
*sid
,
767 enum wbcSidType
*pname_type
)
772 enum wbcSidType name_type
;
774 wbc_status
= wbcLookupSid(sid
, &domain
, &name
, &name_type
);
775 BAIL_ON_WBC_ERROR(wbc_status
);
777 if (name_type
== WBC_SID_NAME_USER
) {
781 wbc_status
= wbcSidToUid(sid
, &uid
);
782 BAIL_ON_WBC_ERROR(wbc_status
);
784 wbc_status
= wbcGetpwuid(uid
, &pwd
);
785 BAIL_ON_WBC_ERROR(wbc_status
);
789 name
= talloc_strdup(NULL
, pwd
->pw_gecos
);
790 BAIL_ON_PTR_ERROR(name
, wbc_status
);
793 wbc_status
= WBC_ERR_SUCCESS
;
796 if (WBC_ERROR_IS_OK(wbc_status
)) {
799 *pname_type
= name_type
;
801 wbcFreeMemory(domain
);
808 const char* wbcSidTypeString(enum wbcSidType type
)
811 case WBC_SID_NAME_USE_NONE
: return "SID_NONE";
812 case WBC_SID_NAME_USER
: return "SID_USER";
813 case WBC_SID_NAME_DOM_GRP
: return "SID_DOM_GROUP";
814 case WBC_SID_NAME_DOMAIN
: return "SID_DOMAIN";
815 case WBC_SID_NAME_ALIAS
: return "SID_ALIAS";
816 case WBC_SID_NAME_WKN_GRP
: return "SID_WKN_GROUP";
817 case WBC_SID_NAME_DELETED
: return "SID_DELETED";
818 case WBC_SID_NAME_INVALID
: return "SID_INVALID";
819 case WBC_SID_NAME_UNKNOWN
: return "SID_UNKNOWN";
820 case WBC_SID_NAME_COMPUTER
: return "SID_COMPUTER";
821 default: return "Unknown type";