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"
27 /** @brief The maximum number of pwent structs to get from winbindd
30 #define MAX_GETPWENT_USERS 500
32 /** @brief The maximum number of grent structs to get from winbindd
35 #define MAX_GETGRENT_GROUPS 500
41 static struct passwd
*copy_passwd_entry(struct winbindd_pw
*p
)
43 struct passwd
*pwd
= NULL
;
44 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
46 pwd
= talloc(NULL
, struct passwd
);
47 BAIL_ON_PTR_ERROR(pwd
, wbc_status
);
49 pwd
->pw_name
= talloc_strdup(pwd
,p
->pw_name
);
50 BAIL_ON_PTR_ERROR(pwd
->pw_name
, wbc_status
);
52 pwd
->pw_passwd
= talloc_strdup(pwd
, p
->pw_passwd
);
53 BAIL_ON_PTR_ERROR(pwd
->pw_passwd
, wbc_status
);
55 pwd
->pw_gecos
= talloc_strdup(pwd
, p
->pw_gecos
);
56 BAIL_ON_PTR_ERROR(pwd
->pw_gecos
, wbc_status
);
58 pwd
->pw_shell
= talloc_strdup(pwd
, p
->pw_shell
);
59 BAIL_ON_PTR_ERROR(pwd
->pw_shell
, wbc_status
);
61 pwd
->pw_dir
= talloc_strdup(pwd
, p
->pw_dir
);
62 BAIL_ON_PTR_ERROR(pwd
->pw_dir
, wbc_status
);
64 pwd
->pw_uid
= p
->pw_uid
;
65 pwd
->pw_gid
= p
->pw_gid
;
68 if (!WBC_ERROR_IS_OK(wbc_status
)) {
80 static struct group
*copy_group_entry(struct winbindd_gr
*g
,
83 struct group
*grp
= NULL
;
84 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
88 grp
= talloc(NULL
, struct group
);
89 BAIL_ON_PTR_ERROR(grp
, wbc_status
);
91 grp
->gr_name
= talloc_strdup(grp
, g
->gr_name
);
92 BAIL_ON_PTR_ERROR(grp
->gr_name
, wbc_status
);
94 grp
->gr_passwd
= talloc_strdup(grp
, g
->gr_passwd
);
95 BAIL_ON_PTR_ERROR(grp
->gr_passwd
, wbc_status
);
97 grp
->gr_gid
= g
->gr_gid
;
99 grp
->gr_mem
= talloc_array(grp
, char*, g
->num_gr_mem
+1);
101 mem_p
= mem_q
= mem_buf
;
102 for (i
=0; i
<g
->num_gr_mem
&& mem_p
; i
++) {
103 if ((mem_q
= strchr(mem_p
, ',')) != NULL
) {
107 grp
->gr_mem
[i
] = talloc_strdup(grp
, mem_p
);
108 BAIL_ON_PTR_ERROR(grp
->gr_mem
[i
], wbc_status
);
116 grp
->gr_mem
[i
] = NULL
;
118 wbc_status
= WBC_ERR_SUCCESS
;
121 if (!WBC_ERROR_IS_OK(wbc_status
)) {
129 /** @brief Fill in a struct passwd* for a domain user based
132 * @param *name Username to lookup
133 * @param **pwd Pointer to resulting struct passwd* from the query.
138 wbcErr
wbcGetpwnam(const char *name
, struct passwd
**pwd
)
140 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
141 struct winbindd_request request
;
142 struct winbindd_response response
;
145 wbc_status
= WBC_ERR_INVALID_PARAM
;
146 BAIL_ON_WBC_ERROR(wbc_status
);
149 /* Initialize request */
151 ZERO_STRUCT(request
);
152 ZERO_STRUCT(response
);
154 /* dst is already null terminated from the memset above */
156 strncpy(request
.data
.username
, name
, sizeof(request
.data
.username
)-1);
158 wbc_status
= wbcRequestResponse(WINBINDD_GETPWNAM
,
161 BAIL_ON_WBC_ERROR(wbc_status
);
163 *pwd
= copy_passwd_entry(&response
.data
.pw
);
164 BAIL_ON_PTR_ERROR(*pwd
, wbc_status
);
170 /** @brief Fill in a struct passwd* for a domain user based
173 * @param uid Uid to lookup
174 * @param **pwd Pointer to resulting struct passwd* from the query.
179 wbcErr
wbcGetpwuid(uid_t uid
, struct passwd
**pwd
)
181 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
182 struct winbindd_request request
;
183 struct winbindd_response response
;
186 wbc_status
= WBC_ERR_INVALID_PARAM
;
187 BAIL_ON_WBC_ERROR(wbc_status
);
190 /* Initialize request */
192 ZERO_STRUCT(request
);
193 ZERO_STRUCT(response
);
195 request
.data
.uid
= uid
;
197 wbc_status
= wbcRequestResponse(WINBINDD_GETPWUID
,
200 BAIL_ON_WBC_ERROR(wbc_status
);
202 *pwd
= copy_passwd_entry(&response
.data
.pw
);
203 BAIL_ON_PTR_ERROR(*pwd
, wbc_status
);
209 /** @brief Fill in a struct passwd* for a domain user based
212 * @param *name Username to lookup
213 * @param **grp Pointer to resulting struct group* from the query.
218 wbcErr
wbcGetgrnam(const char *name
, struct group
**grp
)
220 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
221 struct winbindd_request request
;
222 struct winbindd_response response
;
224 /* Initialize request */
226 ZERO_STRUCT(request
);
227 ZERO_STRUCT(response
);
230 wbc_status
= WBC_ERR_INVALID_PARAM
;
231 BAIL_ON_WBC_ERROR(wbc_status
);
234 /* dst is already null terminated from the memset above */
236 strncpy(request
.data
.groupname
, name
, sizeof(request
.data
.groupname
)-1);
238 wbc_status
= wbcRequestResponse(WINBINDD_GETGRNAM
,
241 BAIL_ON_WBC_ERROR(wbc_status
);
243 *grp
= copy_group_entry(&response
.data
.gr
,
244 (char*)response
.extra_data
.data
);
245 BAIL_ON_PTR_ERROR(*grp
, wbc_status
);
248 if (response
.extra_data
.data
)
249 free(response
.extra_data
.data
);
254 /** @brief Fill in a struct passwd* for a domain user based
257 * @param gid Uid to lookup
258 * @param **grp Pointer to resulting struct group* from the query.
263 wbcErr
wbcGetgrgid(gid_t gid
, struct group
**grp
)
265 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
266 struct winbindd_request request
;
267 struct winbindd_response response
;
269 /* Initialize request */
271 ZERO_STRUCT(request
);
272 ZERO_STRUCT(response
);
275 wbc_status
= WBC_ERR_INVALID_PARAM
;
276 BAIL_ON_WBC_ERROR(wbc_status
);
279 request
.data
.gid
= gid
;
281 wbc_status
= wbcRequestResponse(WINBINDD_GETGRGID
,
284 BAIL_ON_WBC_ERROR(wbc_status
);
286 *grp
= copy_group_entry(&response
.data
.gr
,
287 (char*)response
.extra_data
.data
);
288 BAIL_ON_PTR_ERROR(*grp
, wbc_status
);
291 if (response
.extra_data
.data
)
292 free(response
.extra_data
.data
);
297 /** @brief Number of cached passwd structs
300 static uint32_t pw_cache_size
;
302 /** @brief Position of the pwent context
305 static uint32_t pw_cache_idx
;
307 /** @brief Winbindd response containing the passwd structs
310 static struct winbindd_response pw_response
;
312 /** @brief Reset the passwd iterator
317 wbcErr
wbcSetpwent(void)
319 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
321 if (pw_cache_size
> 0) {
322 pw_cache_idx
= pw_cache_size
= 0;
323 if (pw_response
.extra_data
.data
) {
324 free(pw_response
.extra_data
.data
);
328 ZERO_STRUCT(pw_response
);
330 wbc_status
= wbcRequestResponse(WINBINDD_SETPWENT
,
332 BAIL_ON_WBC_ERROR(wbc_status
);
338 /** @brief Close the passwd iterator
343 wbcErr
wbcEndpwent(void)
345 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
347 if (pw_cache_size
> 0) {
348 pw_cache_idx
= pw_cache_size
= 0;
349 if (pw_response
.extra_data
.data
) {
350 free(pw_response
.extra_data
.data
);
354 wbc_status
= wbcRequestResponse(WINBINDD_ENDPWENT
,
356 BAIL_ON_WBC_ERROR(wbc_status
);
362 /** @brief Return the next struct passwd* entry from the pwent iterator
364 * @param **pwd Pointer to resulting struct passwd* from the query.
369 wbcErr
wbcGetpwent(struct passwd
**pwd
)
371 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
372 struct winbindd_request request
;
373 struct winbindd_pw
*wb_pw
;
375 /* If there's a cached result, return that. */
376 if (pw_cache_idx
< pw_cache_size
) {
380 /* Otherwise, query winbindd for some entries. */
384 if (pw_response
.extra_data
.data
) {
385 free(pw_response
.extra_data
.data
);
386 ZERO_STRUCT(pw_response
);
389 ZERO_STRUCT(request
);
390 request
.data
.num_entries
= MAX_GETPWENT_USERS
;
392 wbc_status
= wbcRequestResponse(WINBINDD_GETPWENT
, &request
,
395 BAIL_ON_WBC_ERROR(wbc_status
);
397 pw_cache_size
= pw_response
.data
.num_entries
;
401 wb_pw
= (struct winbindd_pw
*) pw_response
.extra_data
.data
;
403 *pwd
= copy_passwd_entry(&wb_pw
[pw_cache_idx
]);
405 BAIL_ON_PTR_ERROR(*pwd
, wbc_status
);
413 /** @brief Number of cached group structs
416 static uint32_t gr_cache_size
;
418 /** @brief Position of the grent context
421 static uint32_t gr_cache_idx
;
423 /** @brief Winbindd response containing the group structs
426 static struct winbindd_response gr_response
;
428 /** @brief Reset the group iterator
433 wbcErr
wbcSetgrent(void)
435 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
437 if (gr_cache_size
> 0) {
438 gr_cache_idx
= gr_cache_size
= 0;
439 if (gr_response
.extra_data
.data
) {
440 free(gr_response
.extra_data
.data
);
444 ZERO_STRUCT(gr_response
);
446 wbc_status
= wbcRequestResponse(WINBINDD_SETGRENT
,
448 BAIL_ON_WBC_ERROR(wbc_status
);
454 /** @brief Close the group iterator
459 wbcErr
wbcEndgrent(void)
461 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
463 if (gr_cache_size
> 0) {
464 gr_cache_idx
= gr_cache_size
= 0;
465 if (gr_response
.extra_data
.data
) {
466 free(gr_response
.extra_data
.data
);
470 wbc_status
= wbcRequestResponse(WINBINDD_ENDGRENT
,
472 BAIL_ON_WBC_ERROR(wbc_status
);
478 /** @brief Return the next struct group* entry from the pwent iterator
480 * @param **grp Pointer to resulting struct group* from the query.
485 wbcErr
wbcGetgrent(struct group
**grp
)
487 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
488 struct winbindd_request request
;
489 struct winbindd_gr
*wb_gr
;
492 /* If there's a cached result, return that. */
493 if (gr_cache_idx
< gr_cache_size
) {
497 /* Otherwise, query winbindd for some entries. */
501 if (gr_response
.extra_data
.data
) {
502 free(gr_response
.extra_data
.data
);
503 ZERO_STRUCT(gr_response
);
506 ZERO_STRUCT(request
);
507 request
.data
.num_entries
= MAX_GETGRENT_GROUPS
;
509 wbc_status
= wbcRequestResponse(WINBINDD_GETGRENT
, &request
,
512 BAIL_ON_WBC_ERROR(wbc_status
);
514 gr_cache_size
= gr_response
.data
.num_entries
;
518 wb_gr
= (struct winbindd_gr
*) gr_response
.extra_data
.data
;
520 mem_ofs
= wb_gr
[gr_cache_idx
].gr_mem_ofs
+
521 gr_cache_size
* sizeof(struct winbindd_gr
);
523 *grp
= copy_group_entry(&wb_gr
[gr_cache_idx
],
524 ((char *)gr_response
.extra_data
.data
)+mem_ofs
);
526 BAIL_ON_PTR_ERROR(*grp
, wbc_status
);
534 /** @brief Return the next struct group* entry from the pwent iterator
536 * This is similar to #wbcGetgrent, just that the member list is empty
538 * @param **grp Pointer to resulting struct group* from the query.
543 wbcErr
wbcGetgrlist(struct group
**grp
)
545 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
546 struct winbindd_request request
;
547 struct winbindd_gr
*wb_gr
;
549 /* If there's a cached result, return that. */
550 if (gr_cache_idx
< gr_cache_size
) {
554 /* Otherwise, query winbindd for some entries. */
558 if (gr_response
.extra_data
.data
) {
559 free(gr_response
.extra_data
.data
);
560 ZERO_STRUCT(gr_response
);
563 ZERO_STRUCT(request
);
564 request
.data
.num_entries
= MAX_GETGRENT_GROUPS
;
566 wbc_status
= wbcRequestResponse(WINBINDD_GETGRLST
, &request
,
569 BAIL_ON_WBC_ERROR(wbc_status
);
571 gr_cache_size
= gr_response
.data
.num_entries
;
575 wb_gr
= (struct winbindd_gr
*) gr_response
.extra_data
.data
;
577 *grp
= copy_group_entry(&wb_gr
[gr_cache_idx
], NULL
);
579 BAIL_ON_PTR_ERROR(*grp
, wbc_status
);
587 /** @brief Return the unix group array belonging to the given user
589 * @param *account The given user name
590 * @param *num_groups Number of elements returned in the groups array
591 * @param **_groups Pointer to resulting gid_t array.
595 wbcErr
wbcGetGroups(const char *account
,
596 uint32_t *num_groups
,
599 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
600 struct winbindd_request request
;
601 struct winbindd_response response
;
603 gid_t
*groups
= NULL
;
605 /* Initialize request */
607 ZERO_STRUCT(request
);
608 ZERO_STRUCT(response
);
611 wbc_status
= WBC_ERR_INVALID_PARAM
;
612 BAIL_ON_WBC_ERROR(wbc_status
);
617 strncpy(request
.data
.username
, account
, sizeof(request
.data
.username
)-1);
619 wbc_status
= wbcRequestResponse(WINBINDD_GETGROUPS
,
622 BAIL_ON_WBC_ERROR(wbc_status
);
624 groups
= talloc_array(NULL
, gid_t
, response
.data
.num_entries
);
625 BAIL_ON_PTR_ERROR(groups
, wbc_status
);
627 for (i
= 0; i
< response
.data
.num_entries
; i
++) {
628 groups
[i
] = ((gid_t
*)response
.extra_data
.data
)[i
];
631 *num_groups
= response
.data
.num_entries
;
635 wbc_status
= WBC_ERR_SUCCESS
;
638 if (response
.extra_data
.data
) {
639 free(response
.extra_data
.data
);