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
;
154 /* Convert a domain and name to SID */
155 wbcErr
wbcLookupName(const char *domain
,
157 struct wbcDomainSid
*sid
,
158 enum wbcSidType
*name_type
)
160 struct winbindd_request request
;
161 struct winbindd_response response
;
162 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
164 if (!sid
|| !name_type
) {
165 wbc_status
= WBC_ERR_INVALID_PARAM
;
166 BAIL_ON_WBC_ERROR(wbc_status
);
169 /* Initialize request */
171 ZERO_STRUCT(request
);
172 ZERO_STRUCT(response
);
174 /* dst is already null terminated from the memset above */
176 strncpy(request
.data
.name
.dom_name
, domain
,
177 sizeof(request
.data
.name
.dom_name
)-1);
178 strncpy(request
.data
.name
.name
, name
,
179 sizeof(request
.data
.name
.name
)-1);
181 wbc_status
= wbcRequestResponse(WINBINDD_LOOKUPNAME
,
184 BAIL_ON_WBC_ERROR(wbc_status
);
186 wbc_status
= wbcStringToSid(response
.data
.sid
.sid
, sid
);
187 BAIL_ON_WBC_ERROR(wbc_status
);
189 *name_type
= (enum wbcSidType
)response
.data
.sid
.type
;
191 wbc_status
= WBC_ERR_SUCCESS
;
198 /* Convert a SID to a domain and name */
199 wbcErr
wbcLookupSid(const struct wbcDomainSid
*sid
,
202 enum wbcSidType
*pname_type
)
204 struct winbindd_request request
;
205 struct winbindd_response response
;
206 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
207 char *sid_string
= NULL
;
210 enum wbcSidType name_type
= WBC_SID_NAME_USE_NONE
;
213 wbc_status
= WBC_ERR_INVALID_PARAM
;
214 BAIL_ON_WBC_ERROR(wbc_status
);
217 /* Initialize request */
219 ZERO_STRUCT(request
);
220 ZERO_STRUCT(response
);
222 /* dst is already null terminated from the memset above */
224 wbc_status
= wbcSidToString(sid
, &sid_string
);
225 BAIL_ON_WBC_ERROR(wbc_status
);
227 strncpy(request
.data
.sid
, sid_string
, sizeof(request
.data
.sid
)-1);
228 wbcFreeMemory(sid_string
);
232 wbc_status
= wbcRequestResponse(WINBINDD_LOOKUPSID
,
235 BAIL_ON_WBC_ERROR(wbc_status
);
237 /* Copy out result */
239 domain
= talloc_strdup(NULL
, response
.data
.name
.dom_name
);
240 BAIL_ON_PTR_ERROR(domain
, wbc_status
);
242 name
= talloc_strdup(NULL
, response
.data
.name
.name
);
243 BAIL_ON_PTR_ERROR(name
, wbc_status
);
245 name_type
= (enum wbcSidType
)response
.data
.name
.type
;
247 wbc_status
= WBC_ERR_SUCCESS
;
250 if (WBC_ERROR_IS_OK(wbc_status
)) {
251 if (pdomain
!= NULL
) {
261 if (pname_type
!= NULL
) {
262 *pname_type
= name_type
;
268 * Found by Coverity: In this particular routine we can't end
269 * up here with a non-NULL name. Further up there are just two
270 * exit paths that lead here, neither of which leave an
271 * allocated name. If you add more paths up there, re-activate
278 if (domain
!= NULL
) {
286 /* Translate a collection of RIDs within a domain to names */
288 wbcErr
wbcLookupRids(struct wbcDomainSid
*dom_sid
,
291 const char **pp_domain_name
,
292 const char ***pnames
,
293 enum wbcSidType
**ptypes
)
295 size_t i
, len
, ridbuf_size
;
298 struct winbindd_request request
;
299 struct winbindd_response response
;
300 char *sid_string
= NULL
;
301 char *domain_name
= NULL
;
302 const char **names
= NULL
;
303 enum wbcSidType
*types
= NULL
;
304 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
306 /* Initialise request */
308 ZERO_STRUCT(request
);
309 ZERO_STRUCT(response
);
311 if (!dom_sid
|| (num_rids
== 0)) {
312 wbc_status
= WBC_ERR_INVALID_PARAM
;
313 BAIL_ON_WBC_ERROR(wbc_status
);
316 wbc_status
= wbcSidToString(dom_sid
, &sid_string
);
317 BAIL_ON_WBC_ERROR(wbc_status
);
319 strncpy(request
.data
.sid
, sid_string
, sizeof(request
.data
.sid
)-1);
320 wbcFreeMemory(sid_string
);
322 /* Even if all the Rids were of maximum 32bit values,
323 we would only have 11 bytes per rid in the final array
324 ("4294967296" + \n). Add one more byte for the
327 ridbuf_size
= (sizeof(char)*11) * num_rids
+ 1;
329 ridlist
= talloc_zero_array(NULL
, char, ridbuf_size
);
330 BAIL_ON_PTR_ERROR(ridlist
, wbc_status
);
333 for (i
=0; i
<num_rids
&& (len
-1)>0; i
++) {
336 len
= strlen(ridlist
);
339 snprintf( ridstr
, sizeof(ridstr
)-1, "%u\n", rids
[i
]);
340 strncat(p
, ridstr
, ridbuf_size
-len
-1);
343 request
.extra_data
.data
= ridlist
;
344 request
.extra_len
= strlen(ridlist
)+1;
346 wbc_status
= wbcRequestResponse(WINBINDD_LOOKUPRIDS
,
349 talloc_free(ridlist
);
350 BAIL_ON_WBC_ERROR(wbc_status
);
352 domain_name
= talloc_strdup(NULL
, response
.data
.domain_name
);
353 BAIL_ON_PTR_ERROR(domain_name
, wbc_status
);
355 names
= talloc_array(NULL
, const char*, num_rids
);
356 BAIL_ON_PTR_ERROR(names
, wbc_status
);
358 types
= talloc_array(NULL
, enum wbcSidType
, num_rids
);
359 BAIL_ON_PTR_ERROR(types
, wbc_status
);
361 p
= (char *)response
.extra_data
.data
;
363 for (i
=0; i
<num_rids
; i
++) {
367 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
368 BAIL_ON_WBC_ERROR(wbc_status
);
371 types
[i
] = (enum wbcSidType
)strtoul(p
, &q
, 10);
374 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
375 BAIL_ON_WBC_ERROR(wbc_status
);
380 if ((q
= strchr(p
, '\n')) == NULL
) {
381 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
382 BAIL_ON_WBC_ERROR(wbc_status
);
387 names
[i
] = talloc_strdup(names
, p
);
388 BAIL_ON_PTR_ERROR(names
[i
], wbc_status
);
394 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
395 BAIL_ON_WBC_ERROR(wbc_status
);
398 wbc_status
= WBC_ERR_SUCCESS
;
401 winbindd_free_response(&response
);
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 winbindd_free_response(&response
);
498 wbcErr
_sid_to_rid(struct wbcDomainSid
*sid
, uint32_t *rid
)
500 if (sid
->num_auths
< 1) {
501 return WBC_ERR_INVALID_RESPONSE
;
503 *rid
= sid
->sub_auths
[sid
->num_auths
- 1];
505 return WBC_ERR_SUCCESS
;
508 /* Get alias membership for sids */
509 wbcErr
wbcGetSidAliases(const struct wbcDomainSid
*dom_sid
,
510 struct wbcDomainSid
*sids
,
512 uint32_t **alias_rids
,
513 uint32_t *num_alias_rids
)
517 struct winbindd_request request
;
518 struct winbindd_response response
;
519 char *sid_string
= NULL
;
521 ssize_t extra_data_len
= 0;
522 char * extra_data
= NULL
;
524 struct wbcDomainSid sid
;
525 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
526 uint32_t * rids
= NULL
;
528 /* Initialise request */
530 ZERO_STRUCT(request
);
531 ZERO_STRUCT(response
);
534 wbc_status
= WBC_ERR_INVALID_PARAM
;
535 BAIL_ON_WBC_ERROR(wbc_status
);
538 wbc_status
= wbcSidToString(dom_sid
, &sid_string
);
539 BAIL_ON_WBC_ERROR(wbc_status
);
541 strncpy(request
.data
.sid
, sid_string
, sizeof(request
.data
.sid
)-1);
542 wbcFreeMemory(sid_string
);
545 /* Lets assume each sid is around 54 characters
546 * S-1-5-AAAAAAAAAAA-BBBBBBBBBBB-CCCCCCCCCCC-DDDDDDDDDDD\n */
547 buflen
= 54 * num_sids
;
548 extra_data
= talloc_array(NULL
, char, buflen
);
550 wbc_status
= WBC_ERR_NO_MEMORY
;
551 BAIL_ON_WBC_ERROR(wbc_status
);
554 /* Build the sid list */
555 for (i
=0; i
<num_sids
; i
++) {
557 wbcFreeMemory(sid_string
);
560 wbc_status
= wbcSidToString(&sids
[i
], &sid_string
);
561 BAIL_ON_WBC_ERROR(wbc_status
);
563 sid_len
= strlen(sid_string
);
565 if (buflen
< extra_data_len
+ sid_len
+ 2) {
567 extra_data
= talloc_realloc(NULL
, extra_data
,
570 wbc_status
= WBC_ERR_NO_MEMORY
;
571 BAIL_ON_WBC_ERROR(wbc_status
);
575 strncpy(&extra_data
[extra_data_len
], sid_string
,
576 buflen
- extra_data_len
);
577 extra_data_len
+= sid_len
;
578 extra_data
[extra_data_len
++] = '\n';
579 extra_data
[extra_data_len
] = '\0';
582 request
.extra_data
.data
= extra_data
;
583 request
.extra_len
= extra_data_len
;
585 wbc_status
= wbcRequestResponse(WINBINDD_GETSIDALIASES
,
588 BAIL_ON_WBC_ERROR(wbc_status
);
590 if (response
.data
.num_entries
&&
591 !response
.extra_data
.data
) {
592 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
593 BAIL_ON_WBC_ERROR(wbc_status
);
596 rids
= talloc_array(NULL
, uint32_t,
597 response
.data
.num_entries
);
598 BAIL_ON_PTR_ERROR(sids
, wbc_status
);
600 s
= (const char *)response
.extra_data
.data
;
601 for (i
= 0; i
< response
.data
.num_entries
; i
++) {
602 char *n
= strchr(s
, '\n');
606 wbc_status
= wbcStringToSid(s
, &sid
);
607 BAIL_ON_WBC_ERROR(wbc_status
);
608 wbc_status
= _sid_to_rid(&sid
, &rids
[i
]);
609 BAIL_ON_WBC_ERROR(wbc_status
);
613 *num_alias_rids
= response
.data
.num_entries
;
616 wbc_status
= WBC_ERR_SUCCESS
;
620 wbcFreeMemory(sid_string
);
623 talloc_free(extra_data
);
625 winbindd_free_response(&response
);
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 winbindd_free_response(&response
);
701 wbcErr
wbcListGroups(const char *domain_name
,
702 uint32_t *_num_groups
,
703 const char ***_groups
)
705 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
706 struct winbindd_request request
;
707 struct winbindd_response response
;
708 uint32_t num_groups
= 0;
709 const char **groups
= NULL
;
712 /* Initialise request */
714 ZERO_STRUCT(request
);
715 ZERO_STRUCT(response
);
718 strncpy(request
.domain_name
, domain_name
,
719 sizeof(request
.domain_name
)-1);
722 wbc_status
= wbcRequestResponse(WINBINDD_LIST_GROUPS
,
725 BAIL_ON_WBC_ERROR(wbc_status
);
727 /* Look through extra data */
729 next
= (const char *)response
.extra_data
.data
;
732 const char *current
= next
;
733 char *k
= strchr(next
, ',');
741 tmp
= talloc_realloc(NULL
, groups
,
744 BAIL_ON_PTR_ERROR(tmp
, wbc_status
);
747 groups
[num_groups
] = talloc_strdup(groups
, current
);
748 BAIL_ON_PTR_ERROR(groups
[num_groups
], wbc_status
);
753 *_num_groups
= num_groups
;
756 wbc_status
= WBC_ERR_SUCCESS
;
759 winbindd_free_response(&response
);
766 wbcErr
wbcGetDisplayName(const struct wbcDomainSid
*sid
,
769 enum wbcSidType
*pname_type
)
774 enum wbcSidType name_type
;
776 wbc_status
= wbcLookupSid(sid
, &domain
, &name
, &name_type
);
777 BAIL_ON_WBC_ERROR(wbc_status
);
779 if (name_type
== WBC_SID_NAME_USER
) {
783 wbc_status
= wbcSidToUid(sid
, &uid
);
784 BAIL_ON_WBC_ERROR(wbc_status
);
786 wbc_status
= wbcGetpwuid(uid
, &pwd
);
787 BAIL_ON_WBC_ERROR(wbc_status
);
791 name
= talloc_strdup(NULL
, pwd
->pw_gecos
);
792 BAIL_ON_PTR_ERROR(name
, wbc_status
);
795 wbc_status
= WBC_ERR_SUCCESS
;
798 if (WBC_ERROR_IS_OK(wbc_status
)) {
801 *pname_type
= name_type
;
803 wbcFreeMemory(domain
);
810 const char* wbcSidTypeString(enum wbcSidType type
)
813 case WBC_SID_NAME_USE_NONE
: return "SID_NONE";
814 case WBC_SID_NAME_USER
: return "SID_USER";
815 case WBC_SID_NAME_DOM_GRP
: return "SID_DOM_GROUP";
816 case WBC_SID_NAME_DOMAIN
: return "SID_DOMAIN";
817 case WBC_SID_NAME_ALIAS
: return "SID_ALIAS";
818 case WBC_SID_NAME_WKN_GRP
: return "SID_WKN_GROUP";
819 case WBC_SID_NAME_DELETED
: return "SID_DELETED";
820 case WBC_SID_NAME_INVALID
: return "SID_INVALID";
821 case WBC_SID_NAME_UNKNOWN
: return "SID_UNKNOWN";
822 case WBC_SID_NAME_COMPUTER
: return "SID_COMPUTER";
823 default: return "Unknown type";