2 Unix SMB/CIFS implementation.
6 Copyright (C) Gerald (Jerry) Carter 2007
7 Copyright (C) Volker Lendecke 2010
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 3 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Library General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 /* Required Headers */
27 #include "libwbclient.h"
28 #include "../winbind_client.h"
30 /* Convert a sid to a string into a buffer. Return the string
31 * length. If buflen is too small, return the string length that would
32 * result if it was long enough. */
33 int wbcSidToStringBuf(const struct wbcDomainSid
*sid
, char *buf
, int buflen
)
39 strlcpy(buf
, "(NULL SID)", buflen
);
40 return 10; /* strlen("(NULL SID)") */
44 * BIG NOTE: this function only does SIDS where the identauth is not
45 * >= ^32 in a range of 2^48.
48 id_auth
= sid
->id_auth
[5] +
49 (sid
->id_auth
[4] << 8) +
50 (sid
->id_auth
[3] << 16) +
51 (sid
->id_auth
[2] << 24);
53 ofs
= snprintf(buf
, buflen
, "S-%u-%lu",
54 (unsigned int)sid
->sid_rev_num
, (unsigned long)id_auth
);
56 for (i
= 0; i
< sid
->num_auths
; i
++) {
57 ofs
+= snprintf(buf
+ ofs
, MAX(buflen
- ofs
, 0), "-%lu",
58 (unsigned long)sid
->sub_auths
[i
]);
63 /* Convert a binary SID to a character string */
64 wbcErr
wbcSidToString(const struct wbcDomainSid
*sid
,
67 char buf
[WBC_SID_STRING_BUFLEN
];
72 return WBC_ERR_INVALID_SID
;
75 len
= wbcSidToStringBuf(sid
, buf
, sizeof(buf
));
77 if (len
+1 > sizeof(buf
)) {
78 return WBC_ERR_INVALID_SID
;
81 result
= (char *)wbcAllocateMemory(len
+1, 1, NULL
);
83 return WBC_ERR_NO_MEMORY
;
85 memcpy(result
, buf
, len
+1);
88 return WBC_ERR_SUCCESS
;
91 /* Convert a character string to a binary SID */
92 wbcErr
wbcStringToSid(const char *str
,
93 struct wbcDomainSid
*sid
)
98 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
101 wbc_status
= WBC_ERR_INVALID_PARAM
;
102 BAIL_ON_WBC_ERROR(wbc_status
);
105 /* Sanity check for either "S-" or "s-" */
108 || (str
[0]!='S' && str
[0]!='s')
111 wbc_status
= WBC_ERR_INVALID_PARAM
;
112 BAIL_ON_WBC_ERROR(wbc_status
);
115 /* Get the SID revision number */
118 x
= (uint32_t)strtol(p
, &q
, 10);
119 if (x
==0 || !q
|| *q
!='-') {
120 wbc_status
= WBC_ERR_INVALID_SID
;
121 BAIL_ON_WBC_ERROR(wbc_status
);
123 sid
->sid_rev_num
= (uint8_t)x
;
125 /* Next the Identifier Authority. This is stored in big-endian
126 in a 6 byte array. */
129 x
= (uint32_t)strtol(p
, &q
, 10);
131 wbc_status
= WBC_ERR_INVALID_SID
;
132 BAIL_ON_WBC_ERROR(wbc_status
);
134 sid
->id_auth
[5] = (x
& 0x000000ff);
135 sid
->id_auth
[4] = (x
& 0x0000ff00) >> 8;
136 sid
->id_auth
[3] = (x
& 0x00ff0000) >> 16;
137 sid
->id_auth
[2] = (x
& 0xff000000) >> 24;
141 /* now read the the subauthorities */
145 while (sid
->num_auths
< WBC_MAXSUBAUTHS
) {
146 x
=(uint32_t)strtoul(p
, &q
, 10);
150 wbc_status
= WBC_ERR_INVALID_SID
;
151 BAIL_ON_WBC_ERROR(wbc_status
);
153 sid
->sub_auths
[sid
->num_auths
++] = x
;
161 /* IF we ended early, then the SID could not be converted */
164 wbc_status
= WBC_ERR_INVALID_SID
;
165 BAIL_ON_WBC_ERROR(wbc_status
);
168 wbc_status
= WBC_ERR_SUCCESS
;
176 /* Convert a domain and name to SID */
177 wbcErr
wbcLookupName(const char *domain
,
179 struct wbcDomainSid
*sid
,
180 enum wbcSidType
*name_type
)
182 struct winbindd_request request
;
183 struct winbindd_response response
;
184 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
186 if (!sid
|| !name_type
) {
187 wbc_status
= WBC_ERR_INVALID_PARAM
;
188 BAIL_ON_WBC_ERROR(wbc_status
);
191 /* Initialize request */
193 ZERO_STRUCT(request
);
194 ZERO_STRUCT(response
);
196 /* dst is already null terminated from the memset above */
198 strncpy(request
.data
.name
.dom_name
, domain
,
199 sizeof(request
.data
.name
.dom_name
)-1);
200 strncpy(request
.data
.name
.name
, name
,
201 sizeof(request
.data
.name
.name
)-1);
203 wbc_status
= wbcRequestResponse(WINBINDD_LOOKUPNAME
,
206 BAIL_ON_WBC_ERROR(wbc_status
);
208 wbc_status
= wbcStringToSid(response
.data
.sid
.sid
, sid
);
209 BAIL_ON_WBC_ERROR(wbc_status
);
211 *name_type
= (enum wbcSidType
)response
.data
.sid
.type
;
213 wbc_status
= WBC_ERR_SUCCESS
;
220 /* Convert a SID to a domain and name */
221 wbcErr
wbcLookupSid(const struct wbcDomainSid
*sid
,
224 enum wbcSidType
*pname_type
)
226 struct winbindd_request request
;
227 struct winbindd_response response
;
228 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
232 return WBC_ERR_INVALID_PARAM
;
235 /* Initialize request */
237 ZERO_STRUCT(request
);
238 ZERO_STRUCT(response
);
240 wbcSidToStringBuf(sid
, request
.data
.sid
, sizeof(request
.data
.sid
));
244 wbc_status
= wbcRequestResponse(WINBINDD_LOOKUPSID
, &request
,
246 if (!WBC_ERROR_IS_OK(wbc_status
)) {
250 /* Copy out result */
252 wbc_status
= WBC_ERR_NO_MEMORY
;
256 domain
= wbcStrDup(response
.data
.name
.dom_name
);
257 if (domain
== NULL
) {
260 name
= wbcStrDup(response
.data
.name
.name
);
264 if (pdomain
!= NULL
) {
272 if (pname_type
!= NULL
) {
273 *pname_type
= (enum wbcSidType
)response
.data
.name
.type
;
275 wbc_status
= WBC_ERR_SUCCESS
;
278 wbcFreeMemory(domain
);
282 /* Translate a collection of RIDs within a domain to names */
284 wbcErr
wbcLookupRids(struct wbcDomainSid
*dom_sid
,
287 const char **pp_domain_name
,
288 const char ***pnames
,
289 enum wbcSidType
**ptypes
)
291 size_t i
, len
, ridbuf_size
;
294 struct winbindd_request request
;
295 struct winbindd_response response
;
296 char *domain_name
= NULL
;
297 const char **names
= NULL
;
298 enum wbcSidType
*types
= NULL
;
299 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
301 /* Initialise request */
303 ZERO_STRUCT(request
);
304 ZERO_STRUCT(response
);
306 if (!dom_sid
|| (num_rids
== 0)) {
307 wbc_status
= WBC_ERR_INVALID_PARAM
;
308 BAIL_ON_WBC_ERROR(wbc_status
);
311 wbcSidToStringBuf(dom_sid
, request
.data
.sid
, sizeof(request
.data
.sid
));
313 /* Even if all the Rids were of maximum 32bit values,
314 we would only have 11 bytes per rid in the final array
315 ("4294967296" + \n). Add one more byte for the
318 ridbuf_size
= (sizeof(char)*11) * num_rids
+ 1;
320 ridlist
= (char *)malloc(ridbuf_size
);
321 BAIL_ON_PTR_ERROR(ridlist
, wbc_status
);
324 for (i
=0; i
<num_rids
; i
++) {
325 len
+= snprintf(ridlist
+ len
, ridbuf_size
- len
, "%u\n",
331 request
.extra_data
.data
= ridlist
;
332 request
.extra_len
= len
;
334 wbc_status
= wbcRequestResponse(WINBINDD_LOOKUPRIDS
,
338 BAIL_ON_WBC_ERROR(wbc_status
);
340 domain_name
= wbcStrDup(response
.data
.domain_name
);
341 BAIL_ON_PTR_ERROR(domain_name
, wbc_status
);
343 names
= wbcAllocateStringArray(num_rids
);
344 BAIL_ON_PTR_ERROR(names
, wbc_status
);
346 types
= (enum wbcSidType
*)wbcAllocateMemory(
347 num_rids
, sizeof(enum wbcSidType
), NULL
);
348 BAIL_ON_PTR_ERROR(types
, wbc_status
);
350 p
= (char *)response
.extra_data
.data
;
352 for (i
=0; i
<num_rids
; i
++) {
356 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
360 types
[i
] = (enum wbcSidType
)strtoul(p
, &q
, 10);
363 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
369 if ((q
= strchr(p
, '\n')) == NULL
) {
370 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
376 names
[i
] = strdup(p
);
377 BAIL_ON_PTR_ERROR(names
[i
], wbc_status
);
383 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
387 wbc_status
= WBC_ERR_SUCCESS
;
390 winbindd_free_response(&response
);
392 if (WBC_ERROR_IS_OK(wbc_status
)) {
393 *pp_domain_name
= domain_name
;
398 wbcFreeMemory(domain_name
);
399 wbcFreeMemory(names
);
400 wbcFreeMemory(types
);
406 /* Get the groups a user belongs to */
407 wbcErr
wbcLookupUserSids(const struct wbcDomainSid
*user_sid
,
408 bool domain_groups_only
,
410 struct wbcDomainSid
**_sids
)
414 struct winbindd_request request
;
415 struct winbindd_response response
;
416 struct wbcDomainSid
*sids
= NULL
;
417 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
420 /* Initialise request */
422 ZERO_STRUCT(request
);
423 ZERO_STRUCT(response
);
426 wbc_status
= WBC_ERR_INVALID_PARAM
;
427 BAIL_ON_WBC_ERROR(wbc_status
);
430 wbcSidToStringBuf(user_sid
, request
.data
.sid
, sizeof(request
.data
.sid
));
432 if (domain_groups_only
) {
433 cmd
= WINBINDD_GETUSERDOMGROUPS
;
435 cmd
= WINBINDD_GETUSERSIDS
;
438 wbc_status
= wbcRequestResponse(cmd
,
441 BAIL_ON_WBC_ERROR(wbc_status
);
443 if (response
.data
.num_entries
&&
444 !response
.extra_data
.data
) {
445 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
446 BAIL_ON_WBC_ERROR(wbc_status
);
449 sids
= (struct wbcDomainSid
*)wbcAllocateMemory(
450 response
.data
.num_entries
, sizeof(struct wbcDomainSid
),
452 BAIL_ON_PTR_ERROR(sids
, wbc_status
);
454 s
= (const char *)response
.extra_data
.data
;
455 for (i
= 0; i
< response
.data
.num_entries
; i
++) {
456 char *n
= strchr(s
, '\n');
460 wbc_status
= wbcStringToSid(s
, &sids
[i
]);
461 BAIL_ON_WBC_ERROR(wbc_status
);
465 *num_sids
= response
.data
.num_entries
;
468 wbc_status
= WBC_ERR_SUCCESS
;
471 winbindd_free_response(&response
);
480 wbcErr
_sid_to_rid(struct wbcDomainSid
*sid
, uint32_t *rid
)
482 if (sid
->num_auths
< 1) {
483 return WBC_ERR_INVALID_RESPONSE
;
485 *rid
= sid
->sub_auths
[sid
->num_auths
- 1];
487 return WBC_ERR_SUCCESS
;
490 /* Get alias membership for sids */
491 wbcErr
wbcGetSidAliases(const struct wbcDomainSid
*dom_sid
,
492 struct wbcDomainSid
*sids
,
494 uint32_t **alias_rids
,
495 uint32_t *num_alias_rids
)
499 struct winbindd_request request
;
500 struct winbindd_response response
;
501 ssize_t extra_data_len
= 0;
502 char * extra_data
= NULL
;
504 struct wbcDomainSid sid
;
505 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
506 uint32_t * rids
= NULL
;
508 /* Initialise request */
510 ZERO_STRUCT(request
);
511 ZERO_STRUCT(response
);
514 wbc_status
= WBC_ERR_INVALID_PARAM
;
518 wbcSidToStringBuf(dom_sid
, request
.data
.sid
, sizeof(request
.data
.sid
));
520 /* Lets assume each sid is around 57 characters
521 * S-1-5-21-AAAAAAAAAAA-BBBBBBBBBBB-CCCCCCCCCCC-DDDDDDDDDDD\n */
522 buflen
= 57 * num_sids
;
523 extra_data
= (char *)malloc(buflen
);
525 wbc_status
= WBC_ERR_NO_MEMORY
;
529 /* Build the sid list */
530 for (i
=0; i
<num_sids
; i
++) {
531 char sid_str
[WBC_SID_STRING_BUFLEN
];
534 sid_len
= wbcSidToStringBuf(&sids
[i
], sid_str
, sizeof(sid_str
));
536 if (buflen
< extra_data_len
+ sid_len
+ 2) {
538 extra_data
= (char *)realloc(extra_data
, buflen
);
540 wbc_status
= WBC_ERR_NO_MEMORY
;
541 BAIL_ON_WBC_ERROR(wbc_status
);
545 strncpy(&extra_data
[extra_data_len
], sid_str
,
546 buflen
- extra_data_len
);
547 extra_data_len
+= sid_len
;
548 extra_data
[extra_data_len
++] = '\n';
549 extra_data
[extra_data_len
] = '\0';
553 request
.extra_data
.data
= extra_data
;
554 request
.extra_len
= extra_data_len
;
556 wbc_status
= wbcRequestResponse(WINBINDD_GETSIDALIASES
,
559 BAIL_ON_WBC_ERROR(wbc_status
);
561 if (response
.data
.num_entries
&&
562 !response
.extra_data
.data
) {
563 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
567 rids
= (uint32_t *)wbcAllocateMemory(response
.data
.num_entries
,
568 sizeof(uint32_t), NULL
);
569 BAIL_ON_PTR_ERROR(sids
, wbc_status
);
571 s
= (const char *)response
.extra_data
.data
;
572 for (i
= 0; i
< response
.data
.num_entries
; i
++) {
573 char *n
= strchr(s
, '\n');
577 wbc_status
= wbcStringToSid(s
, &sid
);
578 BAIL_ON_WBC_ERROR(wbc_status
);
579 wbc_status
= _sid_to_rid(&sid
, &rids
[i
]);
580 BAIL_ON_WBC_ERROR(wbc_status
);
584 *num_alias_rids
= response
.data
.num_entries
;
587 wbc_status
= WBC_ERR_SUCCESS
;
591 winbindd_free_response(&response
);
598 wbcErr
wbcListUsers(const char *domain_name
,
599 uint32_t *_num_users
,
600 const char ***_users
)
602 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
603 struct winbindd_request request
;
604 struct winbindd_response response
;
605 uint32_t num_users
= 0;
606 const char **users
= NULL
;
609 /* Initialise request */
611 ZERO_STRUCT(request
);
612 ZERO_STRUCT(response
);
615 strncpy(request
.domain_name
, domain_name
,
616 sizeof(request
.domain_name
)-1);
619 wbc_status
= wbcRequestResponse(WINBINDD_LIST_USERS
,
622 BAIL_ON_WBC_ERROR(wbc_status
);
624 users
= wbcAllocateStringArray(response
.data
.num_entries
);
626 return WBC_ERR_NO_MEMORY
;
629 /* Look through extra data */
631 next
= (const char *)response
.extra_data
.data
;
636 if (num_users
>= response
.data
.num_entries
) {
637 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
642 k
= strchr(next
, ',');
651 users
[num_users
] = strdup(current
);
652 BAIL_ON_PTR_ERROR(users
[num_users
], wbc_status
);
655 if (num_users
!= response
.data
.num_entries
) {
656 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
660 *_num_users
= response
.data
.num_entries
;
663 wbc_status
= WBC_ERR_SUCCESS
;
666 winbindd_free_response(&response
);
667 wbcFreeMemory(users
);
672 wbcErr
wbcListGroups(const char *domain_name
,
673 uint32_t *_num_groups
,
674 const char ***_groups
)
676 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
677 struct winbindd_request request
;
678 struct winbindd_response response
;
679 uint32_t num_groups
= 0;
680 const char **groups
= NULL
;
683 /* Initialise request */
685 ZERO_STRUCT(request
);
686 ZERO_STRUCT(response
);
689 strncpy(request
.domain_name
, domain_name
,
690 sizeof(request
.domain_name
)-1);
693 wbc_status
= wbcRequestResponse(WINBINDD_LIST_GROUPS
,
696 BAIL_ON_WBC_ERROR(wbc_status
);
698 groups
= wbcAllocateStringArray(response
.data
.num_entries
);
699 if (groups
== NULL
) {
700 return WBC_ERR_NO_MEMORY
;
703 /* Look through extra data */
705 next
= (const char *)response
.extra_data
.data
;
710 if (num_groups
>= response
.data
.num_entries
) {
711 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
716 k
= strchr(next
, ',');
725 groups
[num_groups
] = strdup(current
);
726 BAIL_ON_PTR_ERROR(groups
[num_groups
], wbc_status
);
729 if (num_groups
!= response
.data
.num_entries
) {
730 wbc_status
= WBC_ERR_INVALID_RESPONSE
;
734 *_num_groups
= response
.data
.num_entries
;
737 wbc_status
= WBC_ERR_SUCCESS
;
740 winbindd_free_response(&response
);
741 wbcFreeMemory(groups
);
745 wbcErr
wbcGetDisplayName(const struct wbcDomainSid
*sid
,
748 enum wbcSidType
*pname_type
)
753 enum wbcSidType name_type
;
755 wbc_status
= wbcLookupSid(sid
, &domain
, &name
, &name_type
);
756 BAIL_ON_WBC_ERROR(wbc_status
);
758 if (name_type
== WBC_SID_NAME_USER
) {
762 wbc_status
= wbcSidToUid(sid
, &uid
);
763 BAIL_ON_WBC_ERROR(wbc_status
);
765 wbc_status
= wbcGetpwuid(uid
, &pwd
);
766 BAIL_ON_WBC_ERROR(wbc_status
);
770 name
= wbcStrDup(pwd
->pw_gecos
);
772 BAIL_ON_PTR_ERROR(name
, wbc_status
);
775 wbc_status
= WBC_ERR_SUCCESS
;
778 if (WBC_ERROR_IS_OK(wbc_status
)) {
781 *pname_type
= name_type
;
783 wbcFreeMemory(domain
);
790 const char* wbcSidTypeString(enum wbcSidType type
)
793 case WBC_SID_NAME_USE_NONE
: return "SID_NONE";
794 case WBC_SID_NAME_USER
: return "SID_USER";
795 case WBC_SID_NAME_DOM_GRP
: return "SID_DOM_GROUP";
796 case WBC_SID_NAME_DOMAIN
: return "SID_DOMAIN";
797 case WBC_SID_NAME_ALIAS
: return "SID_ALIAS";
798 case WBC_SID_NAME_WKN_GRP
: return "SID_WKN_GROUP";
799 case WBC_SID_NAME_DELETED
: return "SID_DELETED";
800 case WBC_SID_NAME_INVALID
: return "SID_INVALID";
801 case WBC_SID_NAME_UNKNOWN
: return "SID_UNKNOWN";
802 case WBC_SID_NAME_COMPUTER
: return "SID_COMPUTER";
803 default: return "Unknown type";