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
) {
255 if (pname_type
!= NULL
) {
256 *pname_type
= name_type
;
262 * Found by Coverity: In this particular routine we can't end
263 * up here with a non-NULL name. Further up there are just two
264 * exit paths that lead here, neither of which leave an
265 * allocated name. If you add more paths up there, re-activate
272 if (domain
!= NULL
) {
280 /* Translate a collection of RIDs within a domain to names */
282 wbcErr
wbcLookupRids(struct wbcDomainSid
*dom_sid
,
285 const char **pp_domain_name
,
286 const char ***pnames
,
287 enum wbcSidType
**ptypes
)
289 size_t i
, len
, ridbuf_size
;
292 struct winbindd_request request
;
293 struct winbindd_response response
;
294 char *sid_string
= NULL
;
295 char *domain_name
= NULL
;
296 const char **names
= NULL
;
297 enum wbcSidType
*types
= NULL
;
298 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
300 /* Initialise request */
302 ZERO_STRUCT(request
);
303 ZERO_STRUCT(response
);
305 if (!dom_sid
|| (num_rids
== 0)) {
306 wbc_status
= WBC_ERR_INVALID_PARAM
;
307 BAIL_ON_WBC_ERROR(wbc_status
);
310 wbc_status
= wbcSidToString(dom_sid
, &sid_string
);
311 BAIL_ON_WBC_ERROR(wbc_status
);
313 strncpy(request
.data
.sid
, sid_string
, sizeof(request
.data
.sid
)-1);
314 wbcFreeMemory(sid_string
);
316 /* Even if all the Rids were of maximum 32bit values,
317 we would only have 11 bytes per rid in the final array
318 ("4294967296" + \n). Add one more byte for the
321 ridbuf_size
= (sizeof(char)*11) * num_rids
+ 1;
323 ridlist
= talloc_zero_array(NULL
, char, ridbuf_size
);
324 BAIL_ON_PTR_ERROR(ridlist
, wbc_status
);
327 for (i
=0; i
<num_rids
&& (len
-1)>0; i
++) {
330 len
= strlen(ridlist
);
333 snprintf( ridstr
, sizeof(ridstr
)-1, "%u\n", rids
[i
]);
334 strncat(p
, ridstr
, ridbuf_size
-len
-1);
337 request
.extra_data
.data
= ridlist
;
338 request
.extra_len
= strlen(ridlist
)+1;
340 wbc_status
= wbcRequestResponse(WINBINDD_LOOKUPRIDS
,
343 talloc_free(ridlist
);
344 BAIL_ON_WBC_ERROR(wbc_status
);
346 domain_name
= talloc_strdup(NULL
, response
.data
.domain_name
);
347 BAIL_ON_PTR_ERROR(domain_name
, wbc_status
);
349 names
= talloc_array(NULL
, const char*, num_rids
);
350 BAIL_ON_PTR_ERROR(names
, wbc_status
);
352 types
= talloc_array(NULL
, enum wbcSidType
, num_rids
);
353 BAIL_ON_PTR_ERROR(types
, wbc_status
);
355 p
= (char *)response
.extra_data
.data
;
357 for (i
=0; i
<num_rids
; i
++) {
361 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
362 BAIL_ON_WBC_ERROR(wbc_status
);
365 types
[i
] = (enum wbcSidType
)strtoul(p
, &q
, 10);
368 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
369 BAIL_ON_WBC_ERROR(wbc_status
);
374 if ((q
= strchr(p
, '\n')) == NULL
) {
375 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
376 BAIL_ON_WBC_ERROR(wbc_status
);
381 names
[i
] = talloc_strdup(names
, p
);
382 BAIL_ON_PTR_ERROR(names
[i
], wbc_status
);
388 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
389 BAIL_ON_WBC_ERROR(wbc_status
);
392 wbc_status
= WBC_ERR_SUCCESS
;
395 if (response
.extra_data
.data
) {
396 free(response
.extra_data
.data
);
399 if (WBC_ERROR_IS_OK(wbc_status
)) {
400 *pp_domain_name
= domain_name
;
406 talloc_free(domain_name
);
416 /* Get the groups a user belongs to */
417 wbcErr
wbcLookupUserSids(const struct wbcDomainSid
*user_sid
,
418 bool domain_groups_only
,
420 struct wbcDomainSid
**_sids
)
424 struct winbindd_request request
;
425 struct winbindd_response response
;
426 char *sid_string
= NULL
;
427 struct wbcDomainSid
*sids
= NULL
;
428 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
431 /* Initialise request */
433 ZERO_STRUCT(request
);
434 ZERO_STRUCT(response
);
437 wbc_status
= WBC_ERR_INVALID_PARAM
;
438 BAIL_ON_WBC_ERROR(wbc_status
);
441 wbc_status
= wbcSidToString(user_sid
, &sid_string
);
442 BAIL_ON_WBC_ERROR(wbc_status
);
444 strncpy(request
.data
.sid
, sid_string
, sizeof(request
.data
.sid
)-1);
445 wbcFreeMemory(sid_string
);
447 if (domain_groups_only
) {
448 cmd
= WINBINDD_GETUSERDOMGROUPS
;
450 cmd
= WINBINDD_GETUSERSIDS
;
453 wbc_status
= wbcRequestResponse(cmd
,
456 BAIL_ON_WBC_ERROR(wbc_status
);
458 if (response
.data
.num_entries
&&
459 !response
.extra_data
.data
) {
460 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
461 BAIL_ON_WBC_ERROR(wbc_status
);
464 sids
= talloc_array(NULL
, struct wbcDomainSid
,
465 response
.data
.num_entries
);
466 BAIL_ON_PTR_ERROR(sids
, wbc_status
);
468 s
= (const char *)response
.extra_data
.data
;
469 for (i
= 0; i
< response
.data
.num_entries
; i
++) {
470 char *n
= strchr(s
, '\n');
474 wbc_status
= wbcStringToSid(s
, &sids
[i
]);
475 BAIL_ON_WBC_ERROR(wbc_status
);
479 *num_sids
= response
.data
.num_entries
;
482 wbc_status
= WBC_ERR_SUCCESS
;
485 if (response
.extra_data
.data
) {
486 free(response
.extra_data
.data
);
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 if (response
.extra_data
.data
) {
624 free(response
.extra_data
.data
);
635 wbcErr
wbcListUsers(const char *domain_name
,
636 uint32_t *_num_users
,
637 const char ***_users
)
639 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
640 struct winbindd_request request
;
641 struct winbindd_response response
;
642 uint32_t num_users
= 0;
643 const char **users
= NULL
;
646 /* Initialise request */
648 ZERO_STRUCT(request
);
649 ZERO_STRUCT(response
);
652 strncpy(request
.domain_name
, domain_name
,
653 sizeof(request
.domain_name
)-1);
656 wbc_status
= wbcRequestResponse(WINBINDD_LIST_USERS
,
659 BAIL_ON_WBC_ERROR(wbc_status
);
661 /* Look through extra data */
663 next
= (const char *)response
.extra_data
.data
;
666 const char *current
= next
;
667 char *k
= strchr(next
, ',');
675 tmp
= talloc_realloc(NULL
, users
,
678 BAIL_ON_PTR_ERROR(tmp
, wbc_status
);
681 users
[num_users
] = talloc_strdup(users
, current
);
682 BAIL_ON_PTR_ERROR(users
[num_users
], wbc_status
);
687 *_num_users
= num_users
;
690 wbc_status
= WBC_ERR_SUCCESS
;
693 if (response
.extra_data
.data
) {
694 free(response
.extra_data
.data
);
703 wbcErr
wbcListGroups(const char *domain_name
,
704 uint32_t *_num_groups
,
705 const char ***_groups
)
707 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
708 struct winbindd_request request
;
709 struct winbindd_response response
;
710 uint32_t num_groups
= 0;
711 const char **groups
= NULL
;
714 /* Initialise request */
716 ZERO_STRUCT(request
);
717 ZERO_STRUCT(response
);
720 strncpy(request
.domain_name
, domain_name
,
721 sizeof(request
.domain_name
)-1);
724 wbc_status
= wbcRequestResponse(WINBINDD_LIST_GROUPS
,
727 BAIL_ON_WBC_ERROR(wbc_status
);
729 /* Look through extra data */
731 next
= (const char *)response
.extra_data
.data
;
734 const char *current
= next
;
735 char *k
= strchr(next
, ',');
743 tmp
= talloc_realloc(NULL
, groups
,
746 BAIL_ON_PTR_ERROR(tmp
, wbc_status
);
749 groups
[num_groups
] = talloc_strdup(groups
, current
);
750 BAIL_ON_PTR_ERROR(groups
[num_groups
], wbc_status
);
755 *_num_groups
= num_groups
;
758 wbc_status
= WBC_ERR_SUCCESS
;
761 if (response
.extra_data
.data
) {
762 free(response
.extra_data
.data
);
770 wbcErr
wbcGetDisplayName(const struct wbcDomainSid
*sid
,
773 enum wbcSidType
*pname_type
)
778 enum wbcSidType name_type
;
780 wbc_status
= wbcLookupSid(sid
, &domain
, &name
, &name_type
);
781 BAIL_ON_WBC_ERROR(wbc_status
);
783 if (name_type
== WBC_SID_NAME_USER
) {
787 wbc_status
= wbcSidToUid(sid
, &uid
);
788 BAIL_ON_WBC_ERROR(wbc_status
);
790 wbc_status
= wbcGetpwuid(uid
, &pwd
);
791 BAIL_ON_WBC_ERROR(wbc_status
);
795 name
= talloc_strdup(NULL
, pwd
->pw_gecos
);
796 BAIL_ON_PTR_ERROR(name
, wbc_status
);
799 wbc_status
= WBC_ERR_SUCCESS
;
802 if (WBC_ERROR_IS_OK(wbc_status
)) {
805 *pname_type
= name_type
;
807 wbcFreeMemory(domain
);
814 const char* wbcSidTypeString(enum wbcSidType type
)
817 case WBC_SID_NAME_USE_NONE
: return "SID_NONE";
818 case WBC_SID_NAME_USER
: return "SID_USER";
819 case WBC_SID_NAME_DOM_GRP
: return "SID_DOM_GROUP";
820 case WBC_SID_NAME_DOMAIN
: return "SID_DOMAIN";
821 case WBC_SID_NAME_ALIAS
: return "SID_ALIAS";
822 case WBC_SID_NAME_WKN_GRP
: return "SID_WKN_GROUP";
823 case WBC_SID_NAME_DELETED
: return "SID_DELETED";
824 case WBC_SID_NAME_INVALID
: return "SID_INVALID";
825 case WBC_SID_NAME_UNKNOWN
: return "SID_UNKNOWN";
826 case WBC_SID_NAME_COMPUTER
: return "SID_COMPUTER";
827 default: return "Unknown type";