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 */
25 #include "libwbclient.h"
28 /* Convert a binary SID to a character string */
29 wbcErr
wbcSidToString(const struct wbcDomainSid
*sid
,
32 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
38 wbc_status
= WBC_ERR_INVALID_SID
;
39 BAIL_ON_WBC_ERROR(wbc_status
);
42 id_auth
= sid
->id_auth
[5] +
43 (sid
->id_auth
[4] << 8) +
44 (sid
->id_auth
[3] << 16) +
45 (sid
->id_auth
[2] << 24);
47 tmp
= talloc_asprintf(NULL
, "S-%d-%d", sid
->sid_rev_num
, id_auth
);
48 BAIL_ON_PTR_ERROR(tmp
, wbc_status
);
50 for (i
=0; i
<sid
->num_auths
; i
++) {
52 tmp2
= talloc_asprintf_append(tmp
, "-%u", sid
->sub_auths
[i
]);
53 BAIL_ON_PTR_ERROR(tmp2
, wbc_status
);
61 wbc_status
= WBC_ERR_SUCCESS
;
69 /* Convert a character string to a binary SID */
70 wbcErr
wbcStringToSid(const char *str
,
71 struct wbcDomainSid
*sid
)
76 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
79 wbc_status
= WBC_ERR_INVALID_PARAM
;
80 BAIL_ON_WBC_ERROR(wbc_status
);
83 /* Sanity check for either "S-" or "s-" */
86 || (str
[0]!='S' && str
[0]!='s')
89 wbc_status
= WBC_ERR_INVALID_PARAM
;
90 BAIL_ON_WBC_ERROR(wbc_status
);
93 /* Get the SID revision number */
96 x
= (uint32_t)strtol(p
, &q
, 10);
97 if (x
==0 || !q
|| *q
!='-') {
98 wbc_status
= WBC_ERR_INVALID_SID
;
99 BAIL_ON_WBC_ERROR(wbc_status
);
101 sid
->sid_rev_num
= (uint8_t)x
;
103 /* Next the Identifier Authority. This is stored in big-endian
104 in a 6 byte array. */
107 x
= (uint32_t)strtol(p
, &q
, 10);
109 wbc_status
= WBC_ERR_INVALID_SID
;
110 BAIL_ON_WBC_ERROR(wbc_status
);
112 sid
->id_auth
[5] = (x
& 0x000000ff);
113 sid
->id_auth
[4] = (x
& 0x0000ff00) >> 8;
114 sid
->id_auth
[3] = (x
& 0x00ff0000) >> 16;
115 sid
->id_auth
[2] = (x
& 0xff000000) >> 24;
119 /* now read the the subauthorities */
123 while (sid
->num_auths
< WBC_MAXSUBAUTHS
) {
124 x
=(uint32_t)strtoul(p
, &q
, 10);
128 wbc_status
= WBC_ERR_INVALID_SID
;
129 BAIL_ON_WBC_ERROR(wbc_status
);
131 sid
->sub_auths
[sid
->num_auths
++] = x
;
133 if ((*q
!='-') || (*q
=='\0'))
138 /* IF we ended early, then the SID could not be converted */
141 wbc_status
= WBC_ERR_INVALID_SID
;
142 BAIL_ON_WBC_ERROR(wbc_status
);
145 wbc_status
= WBC_ERR_SUCCESS
;
152 /* Convert a domain and name to SID */
153 wbcErr
wbcLookupName(const char *domain
,
155 struct wbcDomainSid
*sid
,
156 enum wbcSidType
*name_type
)
158 struct winbindd_request request
;
159 struct winbindd_response response
;
160 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
162 if (!sid
|| !name_type
) {
163 wbc_status
= WBC_ERR_INVALID_PARAM
;
164 BAIL_ON_WBC_ERROR(wbc_status
);
167 /* Initialize request */
169 ZERO_STRUCT(request
);
170 ZERO_STRUCT(response
);
172 /* dst is already null terminated from the memset above */
174 strncpy(request
.data
.name
.dom_name
, domain
,
175 sizeof(request
.data
.name
.dom_name
)-1);
176 strncpy(request
.data
.name
.name
, name
,
177 sizeof(request
.data
.name
.name
)-1);
179 wbc_status
= wbcRequestResponse(WINBINDD_LOOKUPNAME
,
182 BAIL_ON_WBC_ERROR(wbc_status
);
184 wbc_status
= wbcStringToSid(response
.data
.sid
.sid
, sid
);
185 BAIL_ON_WBC_ERROR(wbc_status
);
187 *name_type
= (enum wbcSidType
)response
.data
.sid
.type
;
189 wbc_status
= WBC_ERR_SUCCESS
;
195 /* Convert a SID to a domain and name */
196 wbcErr
wbcLookupSid(const struct wbcDomainSid
*sid
,
199 enum wbcSidType
*pname_type
)
201 struct winbindd_request request
;
202 struct winbindd_response response
;
203 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
204 char *sid_string
= NULL
;
207 enum wbcSidType name_type
= WBC_SID_NAME_USE_NONE
;
210 wbc_status
= WBC_ERR_INVALID_PARAM
;
211 BAIL_ON_WBC_ERROR(wbc_status
);
214 /* Initialize request */
216 ZERO_STRUCT(request
);
217 ZERO_STRUCT(response
);
219 /* dst is already null terminated from the memset above */
221 wbc_status
= wbcSidToString(sid
, &sid_string
);
222 BAIL_ON_WBC_ERROR(wbc_status
);
224 strncpy(request
.data
.sid
, sid_string
, sizeof(request
.data
.sid
)-1);
225 wbcFreeMemory(sid_string
);
229 wbc_status
= wbcRequestResponse(WINBINDD_LOOKUPSID
,
232 BAIL_ON_WBC_ERROR(wbc_status
);
234 /* Copy out result */
236 domain
= talloc_strdup(NULL
, response
.data
.name
.dom_name
);
237 BAIL_ON_PTR_ERROR(domain
, wbc_status
);
239 name
= talloc_strdup(NULL
, response
.data
.name
.name
);
240 BAIL_ON_PTR_ERROR(name
, wbc_status
);
242 name_type
= (enum wbcSidType
)response
.data
.name
.type
;
244 wbc_status
= WBC_ERR_SUCCESS
;
247 if (WBC_ERROR_IS_OK(wbc_status
)) {
248 if (pdomain
!= NULL
) {
254 if (pname_type
!= NULL
) {
255 *pname_type
= name_type
;
261 * Found by Coverity: In this particular routine we can't end
262 * up here with a non-NULL name. Further up there are just two
263 * exit paths that lead here, neither of which leave an
264 * allocated name. If you add more paths up there, re-activate
271 if (domain
!= NULL
) {
279 /* Translate a collection of RIDs within a domain to names */
281 wbcErr
wbcLookupRids(struct wbcDomainSid
*dom_sid
,
284 const char **pp_domain_name
,
285 const char ***pnames
,
286 enum wbcSidType
**ptypes
)
288 size_t i
, len
, ridbuf_size
;
291 struct winbindd_request request
;
292 struct winbindd_response response
;
293 char *sid_string
= NULL
;
294 char *domain_name
= NULL
;
295 const char **names
= NULL
;
296 enum wbcSidType
*types
= NULL
;
297 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
299 /* Initialise request */
301 ZERO_STRUCT(request
);
302 ZERO_STRUCT(response
);
304 if (!dom_sid
|| (num_rids
== 0)) {
305 wbc_status
= WBC_ERR_INVALID_PARAM
;
306 BAIL_ON_WBC_ERROR(wbc_status
);
309 wbc_status
= wbcSidToString(dom_sid
, &sid_string
);
310 BAIL_ON_WBC_ERROR(wbc_status
);
312 strncpy(request
.data
.sid
, sid_string
, sizeof(request
.data
.sid
)-1);
313 wbcFreeMemory(sid_string
);
315 /* Even if all the Rids were of maximum 32bit values,
316 we would only have 11 bytes per rid in the final array
317 ("4294967296" + \n). Add one more byte for the
320 ridbuf_size
= (sizeof(char)*11) * num_rids
+ 1;
322 ridlist
= talloc_zero_array(NULL
, char, ridbuf_size
);
323 BAIL_ON_PTR_ERROR(ridlist
, wbc_status
);
326 for (i
=0; i
<num_rids
&& (len
-1)>0; i
++) {
329 len
= strlen(ridlist
);
332 snprintf( ridstr
, sizeof(ridstr
)-1, "%u\n", rids
[i
]);
333 strncat(p
, ridstr
, ridbuf_size
-len
-1);
336 request
.extra_data
.data
= ridlist
;
337 request
.extra_len
= strlen(ridlist
)+1;
339 wbc_status
= wbcRequestResponse(WINBINDD_LOOKUPRIDS
,
342 talloc_free(ridlist
);
343 BAIL_ON_WBC_ERROR(wbc_status
);
345 domain_name
= talloc_strdup(NULL
, response
.data
.domain_name
);
346 BAIL_ON_PTR_ERROR(domain_name
, wbc_status
);
348 names
= talloc_array(NULL
, const char*, num_rids
);
349 BAIL_ON_PTR_ERROR(names
, wbc_status
);
351 types
= talloc_array(NULL
, enum wbcSidType
, num_rids
);
352 BAIL_ON_PTR_ERROR(types
, wbc_status
);
354 p
= (char *)response
.extra_data
.data
;
356 for (i
=0; i
<num_rids
; i
++) {
360 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
361 BAIL_ON_WBC_ERROR(wbc_status
);
364 types
[i
] = (enum wbcSidType
)strtoul(p
, &q
, 10);
367 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
368 BAIL_ON_WBC_ERROR(wbc_status
);
373 if ((q
= strchr(p
, '\n')) == NULL
) {
374 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
375 BAIL_ON_WBC_ERROR(wbc_status
);
380 names
[i
] = talloc_strdup(names
, p
);
381 BAIL_ON_PTR_ERROR(names
[i
], wbc_status
);
387 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
388 BAIL_ON_WBC_ERROR(wbc_status
);
391 wbc_status
= WBC_ERR_SUCCESS
;
394 if (response
.extra_data
.data
) {
395 free(response
.extra_data
.data
);
398 if (WBC_ERROR_IS_OK(wbc_status
)) {
399 *pp_domain_name
= domain_name
;
405 talloc_free(domain_name
);
415 /* Get the groups a user belongs to */
416 wbcErr
wbcLookupUserSids(const struct wbcDomainSid
*user_sid
,
417 bool domain_groups_only
,
419 struct wbcDomainSid
**_sids
)
423 struct winbindd_request request
;
424 struct winbindd_response response
;
425 char *sid_string
= NULL
;
426 struct wbcDomainSid
*sids
= NULL
;
427 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
430 /* Initialise request */
432 ZERO_STRUCT(request
);
433 ZERO_STRUCT(response
);
436 wbc_status
= WBC_ERR_INVALID_PARAM
;
437 BAIL_ON_WBC_ERROR(wbc_status
);
440 wbc_status
= wbcSidToString(user_sid
, &sid_string
);
441 BAIL_ON_WBC_ERROR(wbc_status
);
443 strncpy(request
.data
.sid
, sid_string
, sizeof(request
.data
.sid
)-1);
444 wbcFreeMemory(sid_string
);
446 if (domain_groups_only
) {
447 cmd
= WINBINDD_GETUSERDOMGROUPS
;
449 cmd
= WINBINDD_GETUSERSIDS
;
452 wbc_status
= wbcRequestResponse(cmd
,
455 BAIL_ON_WBC_ERROR(wbc_status
);
457 if (response
.data
.num_entries
&&
458 !response
.extra_data
.data
) {
459 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
460 BAIL_ON_WBC_ERROR(wbc_status
);
463 sids
= talloc_array(NULL
, struct wbcDomainSid
,
464 response
.data
.num_entries
);
465 BAIL_ON_PTR_ERROR(sids
, wbc_status
);
467 s
= (const char *)response
.extra_data
.data
;
468 for (i
= 0; i
< response
.data
.num_entries
; i
++) {
469 char *n
= strchr(s
, '\n');
473 wbc_status
= wbcStringToSid(s
, &sids
[i
]);
474 BAIL_ON_WBC_ERROR(wbc_status
);
478 *num_sids
= response
.data
.num_entries
;
481 wbc_status
= WBC_ERR_SUCCESS
;
484 if (response
.extra_data
.data
) {
485 free(response
.extra_data
.data
);
495 wbcErr
_sid_to_rid(struct wbcDomainSid
*sid
, uint32_t *rid
)
497 if (sid
->num_auths
< 1) {
498 return WBC_ERR_INVALID_RESPONSE
;
500 *rid
= sid
->sub_auths
[sid
->num_auths
- 1];
502 return WBC_ERR_SUCCESS
;
505 /* Get alias membership for sids */
506 wbcErr
wbcGetSidAliases(const struct wbcDomainSid
*dom_sid
,
507 struct wbcDomainSid
*sids
,
509 uint32_t **alias_rids
,
510 uint32_t *num_alias_rids
)
514 struct winbindd_request request
;
515 struct winbindd_response response
;
516 char *sid_string
= NULL
;
518 ssize_t extra_data_len
= 0;
519 char * extra_data
= NULL
;
521 struct wbcDomainSid sid
;
522 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
523 uint32_t * rids
= NULL
;
525 /* Initialise request */
527 ZERO_STRUCT(request
);
528 ZERO_STRUCT(response
);
531 wbc_status
= WBC_ERR_INVALID_PARAM
;
532 BAIL_ON_WBC_ERROR(wbc_status
);
535 wbc_status
= wbcSidToString(dom_sid
, &sid_string
);
536 BAIL_ON_WBC_ERROR(wbc_status
);
538 strncpy(request
.data
.sid
, sid_string
, sizeof(request
.data
.sid
)-1);
539 wbcFreeMemory(sid_string
);
542 /* Lets assume each sid is around 54 characters
543 * S-1-5-AAAAAAAAAAA-BBBBBBBBBBB-CCCCCCCCCCC-DDDDDDDDDDD\n */
544 buflen
= 54 * num_sids
;
545 extra_data
= talloc_array(NULL
, char, buflen
);
547 wbc_status
= WBC_ERR_NO_MEMORY
;
548 BAIL_ON_WBC_ERROR(wbc_status
);
551 /* Build the sid list */
552 for (i
=0; i
<num_sids
; i
++) {
554 wbcFreeMemory(sid_string
);
557 wbc_status
= wbcSidToString(&sids
[i
], &sid_string
);
558 BAIL_ON_WBC_ERROR(wbc_status
);
560 sid_len
= strlen(sid_string
);
562 if (buflen
< extra_data_len
+ sid_len
+ 2) {
564 extra_data
= talloc_realloc(NULL
, extra_data
,
567 wbc_status
= WBC_ERR_NO_MEMORY
;
568 BAIL_ON_WBC_ERROR(wbc_status
);
572 strncpy(&extra_data
[extra_data_len
], sid_string
,
573 buflen
- extra_data_len
);
574 extra_data_len
+= sid_len
;
575 extra_data
[extra_data_len
++] = '\n';
576 extra_data
[extra_data_len
] = '\0';
579 request
.extra_data
.data
= extra_data
;
580 request
.extra_len
= extra_data_len
;
582 wbc_status
= wbcRequestResponse(WINBINDD_GETSIDALIASES
,
585 BAIL_ON_WBC_ERROR(wbc_status
);
587 if (response
.data
.num_entries
&&
588 !response
.extra_data
.data
) {
589 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
590 BAIL_ON_WBC_ERROR(wbc_status
);
593 rids
= talloc_array(NULL
, uint32_t,
594 response
.data
.num_entries
);
595 BAIL_ON_PTR_ERROR(sids
, wbc_status
);
597 s
= (const char *)response
.extra_data
.data
;
598 for (i
= 0; i
< response
.data
.num_entries
; i
++) {
599 char *n
= strchr(s
, '\n');
603 wbc_status
= wbcStringToSid(s
, &sid
);
604 BAIL_ON_WBC_ERROR(wbc_status
);
605 wbc_status
= _sid_to_rid(&sid
, &rids
[i
]);
606 BAIL_ON_WBC_ERROR(wbc_status
);
610 *num_alias_rids
= response
.data
.num_entries
;
613 wbc_status
= WBC_ERR_SUCCESS
;
617 wbcFreeMemory(sid_string
);
620 talloc_free(extra_data
);
622 if (response
.extra_data
.data
) {
623 free(response
.extra_data
.data
);
634 wbcErr
wbcListUsers(const char *domain_name
,
635 uint32_t *_num_users
,
636 const char ***_users
)
638 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
639 struct winbindd_request request
;
640 struct winbindd_response response
;
641 uint32_t num_users
= 0;
642 const char **users
= NULL
;
645 /* Initialise request */
647 ZERO_STRUCT(request
);
648 ZERO_STRUCT(response
);
651 strncpy(request
.domain_name
, domain_name
,
652 sizeof(request
.domain_name
)-1);
655 wbc_status
= wbcRequestResponse(WINBINDD_LIST_USERS
,
658 BAIL_ON_WBC_ERROR(wbc_status
);
660 /* Look through extra data */
662 next
= (const char *)response
.extra_data
.data
;
665 const char *current
= next
;
666 char *k
= strchr(next
, ',');
674 tmp
= talloc_realloc(NULL
, users
,
677 BAIL_ON_PTR_ERROR(tmp
, wbc_status
);
680 users
[num_users
] = talloc_strdup(users
, current
);
681 BAIL_ON_PTR_ERROR(users
[num_users
], wbc_status
);
686 *_num_users
= num_users
;
689 wbc_status
= WBC_ERR_SUCCESS
;
692 if (response
.extra_data
.data
) {
693 free(response
.extra_data
.data
);
702 wbcErr
wbcListGroups(const char *domain_name
,
703 uint32_t *_num_groups
,
704 const char ***_groups
)
706 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
707 struct winbindd_request request
;
708 struct winbindd_response response
;
709 uint32_t num_groups
= 0;
710 const char **groups
= NULL
;
713 /* Initialise request */
715 ZERO_STRUCT(request
);
716 ZERO_STRUCT(response
);
719 strncpy(request
.domain_name
, domain_name
,
720 sizeof(request
.domain_name
)-1);
723 wbc_status
= wbcRequestResponse(WINBINDD_LIST_GROUPS
,
726 BAIL_ON_WBC_ERROR(wbc_status
);
728 /* Look through extra data */
730 next
= (const char *)response
.extra_data
.data
;
733 const char *current
= next
;
734 char *k
= strchr(next
, ',');
742 tmp
= talloc_realloc(NULL
, groups
,
745 BAIL_ON_PTR_ERROR(tmp
, wbc_status
);
748 groups
[num_groups
] = talloc_strdup(groups
, current
);
749 BAIL_ON_PTR_ERROR(groups
[num_groups
], wbc_status
);
754 *_num_groups
= num_groups
;
757 wbc_status
= WBC_ERR_SUCCESS
;
760 if (response
.extra_data
.data
) {
761 free(response
.extra_data
.data
);
769 wbcErr
wbcGetDisplayName(const struct wbcDomainSid
*sid
,
772 enum wbcSidType
*pname_type
)
777 enum wbcSidType name_type
;
779 wbc_status
= wbcLookupSid(sid
, &domain
, &name
, &name_type
);
780 BAIL_ON_WBC_ERROR(wbc_status
);
782 if (name_type
== WBC_SID_NAME_USER
) {
786 wbc_status
= wbcSidToUid(sid
, &uid
);
787 BAIL_ON_WBC_ERROR(wbc_status
);
789 wbc_status
= wbcGetpwuid(uid
, &pwd
);
790 BAIL_ON_WBC_ERROR(wbc_status
);
794 name
= talloc_strdup(NULL
, pwd
->pw_gecos
);
795 BAIL_ON_PTR_ERROR(name
, wbc_status
);
798 wbc_status
= WBC_ERR_SUCCESS
;
801 if (WBC_ERROR_IS_OK(wbc_status
)) {
804 *pname_type
= name_type
;
806 wbcFreeMemory(domain
);