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 */
172 wbcErr
wbcCtxGetpwnam(struct wbcContext
*ctx
,
173 const char *name
, struct passwd
**pwd
)
175 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
176 struct winbindd_request request
;
177 struct winbindd_response response
;
180 wbc_status
= WBC_ERR_INVALID_PARAM
;
181 BAIL_ON_WBC_ERROR(wbc_status
);
184 /* Initialize request */
186 ZERO_STRUCT(request
);
187 ZERO_STRUCT(response
);
189 /* dst is already null terminated from the memset above */
191 strncpy(request
.data
.username
, name
, sizeof(request
.data
.username
)-1);
193 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_GETPWNAM
,
196 BAIL_ON_WBC_ERROR(wbc_status
);
198 *pwd
= copy_passwd_entry(&response
.data
.pw
);
199 BAIL_ON_PTR_ERROR(*pwd
, wbc_status
);
206 wbcErr
wbcGetpwnam(const char *name
, struct passwd
**pwd
)
208 return wbcCtxGetpwnam(NULL
, name
, pwd
);
211 /* Fill in a struct passwd* for a domain user based on uid */
213 wbcErr
wbcCtxGetpwuid(struct wbcContext
*ctx
, uid_t uid
, struct passwd
**pwd
)
215 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
216 struct winbindd_request request
;
217 struct winbindd_response response
;
220 wbc_status
= WBC_ERR_INVALID_PARAM
;
221 BAIL_ON_WBC_ERROR(wbc_status
);
224 /* Initialize request */
226 ZERO_STRUCT(request
);
227 ZERO_STRUCT(response
);
229 request
.data
.uid
= uid
;
231 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_GETPWUID
,
234 BAIL_ON_WBC_ERROR(wbc_status
);
236 *pwd
= copy_passwd_entry(&response
.data
.pw
);
237 BAIL_ON_PTR_ERROR(*pwd
, wbc_status
);
244 wbcErr
wbcGetpwuid(uid_t uid
, struct passwd
**pwd
)
246 return wbcCtxGetpwuid(NULL
, uid
, pwd
);
249 /* Fill in a struct passwd* for a domain user based on sid */
251 wbcErr
wbcCtxGetpwsid(struct wbcContext
*ctx
,
252 struct wbcDomainSid
*sid
, struct passwd
**pwd
)
254 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
255 struct winbindd_request request
;
256 struct winbindd_response response
;
259 wbc_status
= WBC_ERR_INVALID_PARAM
;
260 BAIL_ON_WBC_ERROR(wbc_status
);
263 /* Initialize request */
265 ZERO_STRUCT(request
);
266 ZERO_STRUCT(response
);
268 wbcSidToStringBuf(sid
, request
.data
.sid
, sizeof(request
.data
.sid
));
270 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_GETPWSID
,
273 BAIL_ON_WBC_ERROR(wbc_status
);
275 *pwd
= copy_passwd_entry(&response
.data
.pw
);
276 BAIL_ON_PTR_ERROR(*pwd
, wbc_status
);
283 wbcErr
wbcGetpwsid(struct wbcDomainSid
*sid
, struct passwd
**pwd
)
285 return wbcCtxGetpwsid(NULL
, sid
, pwd
);
288 /* Fill in a struct passwd* for a domain user based on username */
290 wbcErr
wbcCtxGetgrnam(struct wbcContext
*ctx
,
291 const char *name
, struct group
**grp
)
293 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
294 struct winbindd_request request
;
295 struct winbindd_response response
;
297 /* Initialize request */
299 ZERO_STRUCT(request
);
300 ZERO_STRUCT(response
);
303 wbc_status
= WBC_ERR_INVALID_PARAM
;
304 BAIL_ON_WBC_ERROR(wbc_status
);
307 /* dst is already null terminated from the memset above */
309 strncpy(request
.data
.groupname
, name
, sizeof(request
.data
.groupname
)-1);
311 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_GETGRNAM
,
314 BAIL_ON_WBC_ERROR(wbc_status
);
316 *grp
= copy_group_entry(&response
.data
.gr
,
317 (char*)response
.extra_data
.data
);
318 BAIL_ON_PTR_ERROR(*grp
, wbc_status
);
321 winbindd_free_response(&response
);
327 wbcErr
wbcGetgrnam(const char *name
, struct group
**grp
)
329 return wbcCtxGetgrnam(NULL
, name
, grp
);
332 /* Fill in a struct passwd* for a domain user based on uid */
334 wbcErr
wbcCtxGetgrgid(struct wbcContext
*ctx
, gid_t gid
, struct group
**grp
)
336 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
337 struct winbindd_request request
;
338 struct winbindd_response response
;
340 /* Initialize request */
342 ZERO_STRUCT(request
);
343 ZERO_STRUCT(response
);
346 wbc_status
= WBC_ERR_INVALID_PARAM
;
347 BAIL_ON_WBC_ERROR(wbc_status
);
350 request
.data
.gid
= gid
;
352 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_GETGRGID
,
355 BAIL_ON_WBC_ERROR(wbc_status
);
357 *grp
= copy_group_entry(&response
.data
.gr
,
358 (char*)response
.extra_data
.data
);
359 BAIL_ON_PTR_ERROR(*grp
, wbc_status
);
362 winbindd_free_response(&response
);
368 wbcErr
wbcGetgrgid(gid_t gid
, struct group
**grp
)
370 return wbcCtxGetgrgid(NULL
, gid
, grp
);
373 /** @brief Winbindd response containing the passwd structs
376 static struct winbindd_response pw_response
;
378 /* Reset the passwd iterator */
380 wbcErr
wbcCtxSetpwent(struct wbcContext
*ctx
)
382 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
385 ctx
= wbcGetGlobalCtx();
388 if (ctx
->pw_cache_size
> 0) {
389 ctx
->pw_cache_idx
= ctx
->pw_cache_size
= 0;
390 winbindd_free_response(&pw_response
);
393 ZERO_STRUCT(pw_response
);
395 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_SETPWENT
,
397 BAIL_ON_WBC_ERROR(wbc_status
);
404 wbcErr
wbcSetpwent(void)
406 return wbcCtxSetpwent(NULL
);
409 /* Close the passwd iterator */
411 wbcErr
wbcCtxEndpwent(struct wbcContext
*ctx
)
413 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
416 ctx
= wbcGetGlobalCtx();
419 if (ctx
->pw_cache_size
> 0) {
420 ctx
->pw_cache_idx
= ctx
->pw_cache_size
= 0;
421 winbindd_free_response(&pw_response
);
424 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_ENDPWENT
,
426 BAIL_ON_WBC_ERROR(wbc_status
);
433 wbcErr
wbcEndpwent(void)
435 return wbcCtxEndpwent(NULL
);
438 /* Return the next struct passwd* entry from the pwent iterator */
440 wbcErr
wbcCtxGetpwent(struct wbcContext
*ctx
, struct passwd
**pwd
)
442 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
443 struct winbindd_request request
;
444 struct winbindd_pw
*wb_pw
;
447 ctx
= wbcGetGlobalCtx();
450 /* If there's a cached result, return that. */
451 if (ctx
->pw_cache_idx
< ctx
->pw_cache_size
) {
455 /* Otherwise, query winbindd for some entries. */
457 ctx
->pw_cache_idx
= 0;
459 winbindd_free_response(&pw_response
);
461 ZERO_STRUCT(request
);
462 request
.data
.num_entries
= MAX_GETPWENT_USERS
;
464 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_GETPWENT
, &request
,
467 BAIL_ON_WBC_ERROR(wbc_status
);
469 ctx
->pw_cache_size
= pw_response
.data
.num_entries
;
473 wb_pw
= (struct winbindd_pw
*) pw_response
.extra_data
.data
;
475 *pwd
= copy_passwd_entry(&wb_pw
[ctx
->pw_cache_idx
]);
477 BAIL_ON_PTR_ERROR(*pwd
, wbc_status
);
486 wbcErr
wbcGetpwent(struct passwd
**pwd
)
488 return wbcCtxGetpwent(NULL
, pwd
);
491 /** @brief Winbindd response containing the group structs
494 static struct winbindd_response gr_response
;
496 /* Reset the group iterator */
498 wbcErr
wbcCtxSetgrent(struct wbcContext
*ctx
)
500 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
503 ctx
= wbcGetGlobalCtx();
506 if (ctx
->gr_cache_size
> 0) {
507 ctx
->gr_cache_idx
= ctx
->gr_cache_size
= 0;
508 winbindd_free_response(&gr_response
);
511 ZERO_STRUCT(gr_response
);
513 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_SETGRENT
,
515 BAIL_ON_WBC_ERROR(wbc_status
);
522 wbcErr
wbcSetgrent(void)
524 return wbcCtxSetgrent(NULL
);
527 /* Close the group iterator */
529 wbcErr
wbcCtxEndgrent(struct wbcContext
*ctx
)
531 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
534 ctx
= wbcGetGlobalCtx();
537 if (ctx
->gr_cache_size
> 0) {
538 ctx
->gr_cache_idx
= ctx
->gr_cache_size
= 0;
539 winbindd_free_response(&gr_response
);
542 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_ENDGRENT
,
544 BAIL_ON_WBC_ERROR(wbc_status
);
551 wbcErr
wbcEndgrent(void)
553 return wbcCtxEndgrent(NULL
);
556 /* Return the next struct group* entry from the pwent iterator */
558 wbcErr
wbcCtxGetgrent(struct wbcContext
*ctx
, struct group
**grp
)
560 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
561 struct winbindd_request request
;
562 struct winbindd_gr
*wb_gr
;
566 ctx
= wbcGetGlobalCtx();
569 /* If there's a cached result, return that. */
570 if (ctx
->gr_cache_idx
< ctx
->gr_cache_size
) {
574 /* Otherwise, query winbindd for some entries. */
576 ctx
->gr_cache_idx
= 0;
578 winbindd_free_response(&gr_response
);
580 ZERO_STRUCT(request
);
581 request
.data
.num_entries
= MAX_GETGRENT_GROUPS
;
583 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_GETGRENT
,
584 &request
, &gr_response
);
586 BAIL_ON_WBC_ERROR(wbc_status
);
588 ctx
->gr_cache_size
= gr_response
.data
.num_entries
;
592 wb_gr
= (struct winbindd_gr
*) gr_response
.extra_data
.data
;
594 mem_ofs
= wb_gr
[ctx
->gr_cache_idx
].gr_mem_ofs
+
595 ctx
->gr_cache_size
* sizeof(struct winbindd_gr
);
597 *grp
= copy_group_entry(&wb_gr
[ctx
->gr_cache_idx
],
598 ((char *)gr_response
.extra_data
.data
)+mem_ofs
);
600 BAIL_ON_PTR_ERROR(*grp
, wbc_status
);
609 wbcErr
wbcGetgrent(struct group
**grp
)
611 return wbcCtxGetgrent(NULL
, grp
);
614 /* Return the next struct group* entry from the pwent iterator */
616 wbcErr
wbcCtxGetgrlist(struct wbcContext
*ctx
, struct group
**grp
)
618 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
619 struct winbindd_request request
;
620 struct winbindd_gr
*wb_gr
;
623 ctx
= wbcGetGlobalCtx();
626 /* If there's a cached result, return that. */
627 if (ctx
->gr_cache_idx
< ctx
->gr_cache_size
) {
631 /* Otherwise, query winbindd for some entries. */
633 ctx
->gr_cache_idx
= 0;
635 winbindd_free_response(&gr_response
);
636 ZERO_STRUCT(gr_response
);
638 ZERO_STRUCT(request
);
639 request
.data
.num_entries
= MAX_GETGRENT_GROUPS
;
641 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_GETGRLST
,
642 &request
, &gr_response
);
644 BAIL_ON_WBC_ERROR(wbc_status
);
646 ctx
->gr_cache_size
= gr_response
.data
.num_entries
;
650 wb_gr
= (struct winbindd_gr
*) gr_response
.extra_data
.data
;
652 *grp
= copy_group_entry(&wb_gr
[ctx
->gr_cache_idx
], NULL
);
654 BAIL_ON_PTR_ERROR(*grp
, wbc_status
);
663 wbcErr
wbcGetgrlist(struct group
**grp
)
665 return wbcCtxGetgrlist(NULL
, grp
);
668 /* Return the unix group array belonging to the given user */
670 wbcErr
wbcCtxGetGroups(struct wbcContext
*ctx
, const char *account
,
671 uint32_t *num_groups
, gid_t
**_groups
)
673 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
674 struct winbindd_request request
;
675 struct winbindd_response response
;
677 gid_t
*groups
= NULL
;
679 /* Initialize request */
681 ZERO_STRUCT(request
);
682 ZERO_STRUCT(response
);
685 wbc_status
= WBC_ERR_INVALID_PARAM
;
686 BAIL_ON_WBC_ERROR(wbc_status
);
691 strncpy(request
.data
.username
, account
, sizeof(request
.data
.username
)-1);
693 wbc_status
= wbcRequestResponse(ctx
, WINBINDD_GETGROUPS
,
696 BAIL_ON_WBC_ERROR(wbc_status
);
698 groups
= (gid_t
*)wbcAllocateMemory(
699 response
.data
.num_entries
, sizeof(gid_t
), NULL
);
700 BAIL_ON_PTR_ERROR(groups
, wbc_status
);
702 for (i
= 0; i
< response
.data
.num_entries
; i
++) {
703 groups
[i
] = ((gid_t
*)response
.extra_data
.data
)[i
];
706 *num_groups
= response
.data
.num_entries
;
710 wbc_status
= WBC_ERR_SUCCESS
;
713 winbindd_free_response(&response
);
714 wbcFreeMemory(groups
);
719 wbcErr
wbcGetGroups(const char *account
, uint32_t *num_groups
, gid_t
**_groups
)
721 return wbcCtxGetGroups(NULL
, account
, num_groups
, _groups
);