2 Unix SMB/CIFS implementation.
6 Copyright (C) Gerald (Jerry) Carter 2007
7 Copyright (C) Matthew Newton 2015
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 /** @brief The maximum number of pwent structs to get from winbindd
33 #define MAX_GETPWENT_USERS 500
35 /** @brief The maximum number of grent structs to get from winbindd
38 #define MAX_GETGRENT_GROUPS 500
44 static void wbcPasswdDestructor(void *ptr
)
46 struct passwd
*pw
= (struct passwd
*)ptr
;
54 static struct passwd
*copy_passwd_entry(struct winbindd_pw
*p
)
56 struct passwd
*pw
= NULL
;
58 pw
= (struct passwd
*)wbcAllocateMemory(1, sizeof(struct passwd
),
63 pw
->pw_name
= strdup(p
->pw_name
);
64 if (pw
->pw_name
== NULL
) {
67 pw
->pw_passwd
= strdup(p
->pw_passwd
);
68 if (pw
->pw_passwd
== NULL
) {
71 pw
->pw_gecos
= strdup(p
->pw_gecos
);
72 if (pw
->pw_gecos
== NULL
) {
75 pw
->pw_shell
= strdup(p
->pw_shell
);
76 if (pw
->pw_shell
== NULL
) {
79 pw
->pw_dir
= strdup(p
->pw_dir
);
80 if (pw
->pw_dir
== NULL
) {
83 pw
->pw_uid
= p
->pw_uid
;
84 pw
->pw_gid
= p
->pw_gid
;
96 static void wbcGroupDestructor(void *ptr
)
98 struct group
*gr
= (struct group
*)ptr
;
104 /* if the array was partly created this can be NULL */
105 if (gr
->gr_mem
== NULL
) {
109 for (i
=0; gr
->gr_mem
[i
] != NULL
; i
++) {
115 static struct group
*copy_group_entry(struct winbindd_gr
*g
,
118 struct group
*gr
= NULL
;
122 gr
= (struct group
*)wbcAllocateMemory(
123 1, sizeof(struct group
), wbcGroupDestructor
);
128 gr
->gr_name
= strdup(g
->gr_name
);
129 if (gr
->gr_name
== NULL
) {
132 gr
->gr_passwd
= strdup(g
->gr_passwd
);
133 if (gr
->gr_passwd
== NULL
) {
136 gr
->gr_gid
= g
->gr_gid
;
138 gr
->gr_mem
= (char **)calloc(g
->num_gr_mem
+1, sizeof(char *));
139 if (gr
->gr_mem
== NULL
) {
143 mem_p
= mem_q
= mem_buf
;
144 for (i
=0; i
<g
->num_gr_mem
&& mem_p
; i
++) {
145 mem_q
= strchr(mem_p
, ',');
150 gr
->gr_mem
[i
] = strdup(mem_p
);
151 if (gr
->gr_mem
[i
] == NULL
) {
161 gr
->gr_mem
[i
] = NULL
;
170 /* Fill in a struct passwd* for a domain user based on username */
171 wbcErr
wbcCtxGetpwnam(struct wbcContext
*ctx
,
172 const char *name
, struct passwd
**pwd
)
174 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
175 struct winbindd_request request
;
176 struct winbindd_response response
;
179 wbc_status
= WBC_ERR_INVALID_PARAM
;
180 BAIL_ON_WBC_ERROR(wbc_status
);
183 /* Initialize request */
185 ZERO_STRUCT(request
);
186 ZERO_STRUCT(response
);
188 /* dst is already null terminated from the memset above */
190 strncpy(request
.data
.username
, name
, sizeof(request
.data
.username
)-1);
192 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_GETPWNAM
,
195 BAIL_ON_WBC_ERROR(wbc_status
);
197 *pwd
= copy_passwd_entry(&response
.data
.pw
);
198 BAIL_ON_PTR_ERROR(*pwd
, wbc_status
);
204 wbcErr
wbcGetpwnam(const char *name
, struct passwd
**pwd
)
206 return wbcCtxGetpwnam(NULL
, name
, pwd
);
209 /* Fill in a struct passwd* for a domain user based on uid */
210 wbcErr
wbcCtxGetpwuid(struct wbcContext
*ctx
, uid_t uid
, struct passwd
**pwd
)
212 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
213 struct winbindd_request request
;
214 struct winbindd_response response
;
217 wbc_status
= WBC_ERR_INVALID_PARAM
;
218 BAIL_ON_WBC_ERROR(wbc_status
);
221 /* Initialize request */
223 ZERO_STRUCT(request
);
224 ZERO_STRUCT(response
);
226 request
.data
.uid
= uid
;
228 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_GETPWUID
,
231 BAIL_ON_WBC_ERROR(wbc_status
);
233 *pwd
= copy_passwd_entry(&response
.data
.pw
);
234 BAIL_ON_PTR_ERROR(*pwd
, wbc_status
);
240 wbcErr
wbcGetpwuid(uid_t uid
, struct passwd
**pwd
)
242 return wbcCtxGetpwuid(NULL
, uid
, pwd
);
245 /* Fill in a struct passwd* for a domain user based on sid */
246 wbcErr
wbcCtxGetpwsid(struct wbcContext
*ctx
,
247 struct wbcDomainSid
*sid
, struct passwd
**pwd
)
249 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
250 struct winbindd_request request
;
251 struct winbindd_response response
;
254 wbc_status
= WBC_ERR_INVALID_PARAM
;
255 BAIL_ON_WBC_ERROR(wbc_status
);
258 /* Initialize request */
260 ZERO_STRUCT(request
);
261 ZERO_STRUCT(response
);
263 wbcSidToStringBuf(sid
, request
.data
.sid
, sizeof(request
.data
.sid
));
265 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_GETPWSID
,
268 BAIL_ON_WBC_ERROR(wbc_status
);
270 *pwd
= copy_passwd_entry(&response
.data
.pw
);
271 BAIL_ON_PTR_ERROR(*pwd
, wbc_status
);
277 wbcErr
wbcGetpwsid(struct wbcDomainSid
*sid
, struct passwd
**pwd
)
279 return wbcCtxGetpwsid(NULL
, sid
, pwd
);
282 /* Fill in a struct passwd* for a domain user based on username */
283 wbcErr
wbcCtxGetgrnam(struct wbcContext
*ctx
,
284 const char *name
, struct group
**grp
)
286 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
287 struct winbindd_request request
;
288 struct winbindd_response response
;
290 /* Initialize request */
292 ZERO_STRUCT(request
);
293 ZERO_STRUCT(response
);
296 wbc_status
= WBC_ERR_INVALID_PARAM
;
297 BAIL_ON_WBC_ERROR(wbc_status
);
300 /* dst is already null terminated from the memset above */
302 strncpy(request
.data
.groupname
, name
, sizeof(request
.data
.groupname
)-1);
304 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_GETGRNAM
,
307 BAIL_ON_WBC_ERROR(wbc_status
);
309 *grp
= copy_group_entry(&response
.data
.gr
,
310 (char*)response
.extra_data
.data
);
311 BAIL_ON_PTR_ERROR(*grp
, wbc_status
);
314 winbindd_free_response(&response
);
319 wbcErr
wbcGetgrnam(const char *name
, struct group
**grp
)
321 return wbcCtxGetgrnam(NULL
, name
, grp
);
324 /* Fill in a struct passwd* for a domain user based on uid */
325 wbcErr
wbcCtxGetgrgid(struct wbcContext
*ctx
, gid_t gid
, struct group
**grp
)
327 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
328 struct winbindd_request request
;
329 struct winbindd_response response
;
331 /* Initialize request */
333 ZERO_STRUCT(request
);
334 ZERO_STRUCT(response
);
337 wbc_status
= WBC_ERR_INVALID_PARAM
;
338 BAIL_ON_WBC_ERROR(wbc_status
);
341 request
.data
.gid
= gid
;
343 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_GETGRGID
,
346 BAIL_ON_WBC_ERROR(wbc_status
);
348 *grp
= copy_group_entry(&response
.data
.gr
,
349 (char*)response
.extra_data
.data
);
350 BAIL_ON_PTR_ERROR(*grp
, wbc_status
);
353 winbindd_free_response(&response
);
358 wbcErr
wbcGetgrgid(gid_t gid
, struct group
**grp
)
360 return wbcCtxGetgrgid(NULL
, gid
, grp
);
363 /** @brief Winbindd response containing the passwd structs
366 static struct winbindd_response pw_response
;
368 /* Reset the passwd iterator */
369 wbcErr
wbcCtxSetpwent(struct wbcContext
*ctx
)
371 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
374 ctx
= wbcGetGlobalCtx();
377 if (ctx
->pw_cache_size
> 0) {
378 ctx
->pw_cache_idx
= ctx
->pw_cache_size
= 0;
379 winbindd_free_response(&pw_response
);
382 ZERO_STRUCT(pw_response
);
384 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_SETPWENT
,
386 BAIL_ON_WBC_ERROR(wbc_status
);
392 wbcErr
wbcSetpwent(void)
394 return wbcCtxSetpwent(NULL
);
397 /* Close the passwd iterator */
398 wbcErr
wbcCtxEndpwent(struct wbcContext
*ctx
)
400 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
403 ctx
= wbcGetGlobalCtx();
406 if (ctx
->pw_cache_size
> 0) {
407 ctx
->pw_cache_idx
= ctx
->pw_cache_size
= 0;
408 winbindd_free_response(&pw_response
);
411 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_ENDPWENT
,
413 BAIL_ON_WBC_ERROR(wbc_status
);
419 wbcErr
wbcEndpwent(void)
421 return wbcCtxEndpwent(NULL
);
424 /* Return the next struct passwd* entry from the pwent iterator */
425 wbcErr
wbcCtxGetpwent(struct wbcContext
*ctx
, struct passwd
**pwd
)
427 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
428 struct winbindd_request request
;
429 struct winbindd_pw
*wb_pw
;
432 ctx
= wbcGetGlobalCtx();
435 /* If there's a cached result, return that. */
436 if (ctx
->pw_cache_idx
< ctx
->pw_cache_size
) {
440 /* Otherwise, query winbindd for some entries. */
442 ctx
->pw_cache_idx
= 0;
444 winbindd_free_response(&pw_response
);
446 ZERO_STRUCT(request
);
447 request
.data
.num_entries
= MAX_GETPWENT_USERS
;
449 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_GETPWENT
, &request
,
452 BAIL_ON_WBC_ERROR(wbc_status
);
454 ctx
->pw_cache_size
= pw_response
.data
.num_entries
;
458 wb_pw
= (struct winbindd_pw
*) pw_response
.extra_data
.data
;
460 *pwd
= copy_passwd_entry(&wb_pw
[ctx
->pw_cache_idx
]);
462 BAIL_ON_PTR_ERROR(*pwd
, wbc_status
);
470 wbcErr
wbcGetpwent(struct passwd
**pwd
)
472 return wbcCtxGetpwent(NULL
, pwd
);
475 /** @brief Winbindd response containing the group structs
478 static struct winbindd_response gr_response
;
480 /* Reset the group iterator */
481 wbcErr
wbcCtxSetgrent(struct wbcContext
*ctx
)
483 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
486 ctx
= wbcGetGlobalCtx();
489 if (ctx
->gr_cache_size
> 0) {
490 ctx
->gr_cache_idx
= ctx
->gr_cache_size
= 0;
491 winbindd_free_response(&gr_response
);
494 ZERO_STRUCT(gr_response
);
496 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_SETGRENT
,
498 BAIL_ON_WBC_ERROR(wbc_status
);
504 wbcErr
wbcSetgrent(void)
506 return wbcCtxSetgrent(NULL
);
509 /* Close the group iterator */
510 wbcErr
wbcCtxEndgrent(struct wbcContext
*ctx
)
512 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
515 ctx
= wbcGetGlobalCtx();
518 if (ctx
->gr_cache_size
> 0) {
519 ctx
->gr_cache_idx
= ctx
->gr_cache_size
= 0;
520 winbindd_free_response(&gr_response
);
523 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_ENDGRENT
,
525 BAIL_ON_WBC_ERROR(wbc_status
);
531 wbcErr
wbcEndgrent(void)
533 return wbcCtxEndgrent(NULL
);
536 /* Return the next struct group* entry from the pwent iterator */
537 wbcErr
wbcCtxGetgrent(struct wbcContext
*ctx
, struct group
**grp
)
539 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
540 struct winbindd_request request
;
541 struct winbindd_gr
*wb_gr
;
545 ctx
= wbcGetGlobalCtx();
548 /* If there's a cached result, return that. */
549 if (ctx
->gr_cache_idx
< ctx
->gr_cache_size
) {
553 /* Otherwise, query winbindd for some entries. */
555 ctx
->gr_cache_idx
= 0;
557 winbindd_free_response(&gr_response
);
559 ZERO_STRUCT(request
);
560 request
.data
.num_entries
= MAX_GETGRENT_GROUPS
;
562 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_GETGRENT
,
563 &request
, &gr_response
);
565 BAIL_ON_WBC_ERROR(wbc_status
);
567 ctx
->gr_cache_size
= gr_response
.data
.num_entries
;
571 wb_gr
= (struct winbindd_gr
*) gr_response
.extra_data
.data
;
573 mem_ofs
= wb_gr
[ctx
->gr_cache_idx
].gr_mem_ofs
+
574 ctx
->gr_cache_size
* sizeof(struct winbindd_gr
);
576 *grp
= copy_group_entry(&wb_gr
[ctx
->gr_cache_idx
],
577 ((char *)gr_response
.extra_data
.data
)+mem_ofs
);
579 BAIL_ON_PTR_ERROR(*grp
, wbc_status
);
587 wbcErr
wbcGetgrent(struct group
**grp
)
589 return wbcCtxGetgrent(NULL
, grp
);
592 /* Return the next struct group* entry from the pwent iterator */
593 wbcErr
wbcCtxGetgrlist(struct wbcContext
*ctx
, struct group
**grp
)
595 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
596 struct winbindd_request request
;
597 struct winbindd_gr
*wb_gr
;
600 ctx
= wbcGetGlobalCtx();
603 /* If there's a cached result, return that. */
604 if (ctx
->gr_cache_idx
< ctx
->gr_cache_size
) {
608 /* Otherwise, query winbindd for some entries. */
610 ctx
->gr_cache_idx
= 0;
612 winbindd_free_response(&gr_response
);
613 ZERO_STRUCT(gr_response
);
615 ZERO_STRUCT(request
);
616 request
.data
.num_entries
= MAX_GETGRENT_GROUPS
;
618 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_GETGRLST
,
619 &request
, &gr_response
);
621 BAIL_ON_WBC_ERROR(wbc_status
);
623 ctx
->gr_cache_size
= gr_response
.data
.num_entries
;
627 wb_gr
= (struct winbindd_gr
*) gr_response
.extra_data
.data
;
629 *grp
= copy_group_entry(&wb_gr
[ctx
->gr_cache_idx
], NULL
);
631 BAIL_ON_PTR_ERROR(*grp
, wbc_status
);
639 wbcErr
wbcGetgrlist(struct group
**grp
)
641 return wbcCtxGetgrlist(NULL
, grp
);
644 /* Return the unix group array belonging to the given user */
645 wbcErr
wbcCtxGetGroups(struct wbcContext
*ctx
, const char *account
,
646 uint32_t *num_groups
, gid_t
**_groups
)
648 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
649 struct winbindd_request request
;
650 struct winbindd_response response
;
652 gid_t
*groups
= NULL
;
654 /* Initialize request */
656 ZERO_STRUCT(request
);
657 ZERO_STRUCT(response
);
660 wbc_status
= WBC_ERR_INVALID_PARAM
;
661 BAIL_ON_WBC_ERROR(wbc_status
);
666 strncpy(request
.data
.username
, account
, sizeof(request
.data
.username
)-1);
668 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_GETGROUPS
,
671 BAIL_ON_WBC_ERROR(wbc_status
);
673 groups
= (gid_t
*)wbcAllocateMemory(
674 response
.data
.num_entries
, sizeof(gid_t
), NULL
);
675 BAIL_ON_PTR_ERROR(groups
, wbc_status
);
677 for (i
= 0; i
< response
.data
.num_entries
; i
++) {
678 groups
[i
] = ((gid_t
*)response
.extra_data
.data
)[i
];
681 *num_groups
= response
.data
.num_entries
;
685 wbc_status
= WBC_ERR_SUCCESS
;
688 winbindd_free_response(&response
);
689 wbcFreeMemory(groups
);
693 wbcErr
wbcGetGroups(const char *account
, uint32_t *num_groups
, gid_t
**_groups
)
695 return wbcCtxGetGroups(NULL
, account
, num_groups
, _groups
);