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 */
26 #include "libwbclient.h"
28 /** @brief The maximum number of pwent structs to get from winbindd
31 #define MAX_GETPWENT_USERS 500
33 /** @brief The maximum number of grent structs to get from winbindd
36 #define MAX_GETGRENT_GROUPS 500
42 static struct passwd
*copy_passwd_entry(struct winbindd_pw
*p
)
44 struct passwd
*pwd
= NULL
;
45 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
47 pwd
= talloc(NULL
, struct passwd
);
48 BAIL_ON_PTR_ERROR(pwd
, wbc_status
);
50 pwd
->pw_name
= talloc_strdup(pwd
,p
->pw_name
);
51 BAIL_ON_PTR_ERROR(pwd
->pw_name
, wbc_status
);
53 pwd
->pw_passwd
= talloc_strdup(pwd
, p
->pw_passwd
);
54 BAIL_ON_PTR_ERROR(pwd
->pw_passwd
, wbc_status
);
56 pwd
->pw_gecos
= talloc_strdup(pwd
, p
->pw_gecos
);
57 BAIL_ON_PTR_ERROR(pwd
->pw_gecos
, wbc_status
);
59 pwd
->pw_shell
= talloc_strdup(pwd
, p
->pw_shell
);
60 BAIL_ON_PTR_ERROR(pwd
->pw_shell
, wbc_status
);
62 pwd
->pw_dir
= talloc_strdup(pwd
, p
->pw_dir
);
63 BAIL_ON_PTR_ERROR(pwd
->pw_dir
, wbc_status
);
65 pwd
->pw_uid
= p
->pw_uid
;
66 pwd
->pw_gid
= p
->pw_gid
;
69 if (!WBC_ERROR_IS_OK(wbc_status
)) {
81 static struct group
*copy_group_entry(struct winbindd_gr
*g
,
84 struct group
*grp
= NULL
;
85 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
89 grp
= talloc(NULL
, struct group
);
90 BAIL_ON_PTR_ERROR(grp
, wbc_status
);
92 grp
->gr_name
= talloc_strdup(grp
, g
->gr_name
);
93 BAIL_ON_PTR_ERROR(grp
->gr_name
, wbc_status
);
95 grp
->gr_passwd
= talloc_strdup(grp
, g
->gr_passwd
);
96 BAIL_ON_PTR_ERROR(grp
->gr_passwd
, wbc_status
);
98 grp
->gr_gid
= g
->gr_gid
;
100 grp
->gr_mem
= talloc_array(grp
, char*, g
->num_gr_mem
+1);
102 mem_p
= mem_q
= mem_buf
;
103 for (i
=0; i
<g
->num_gr_mem
&& mem_p
; i
++) {
104 if ((mem_q
= strchr(mem_p
, ',')) != NULL
) {
108 grp
->gr_mem
[i
] = talloc_strdup(grp
, mem_p
);
109 BAIL_ON_PTR_ERROR(grp
->gr_mem
[i
], wbc_status
);
117 grp
->gr_mem
[i
] = NULL
;
119 wbc_status
= WBC_ERR_SUCCESS
;
122 if (!WBC_ERROR_IS_OK(wbc_status
)) {
130 /* Fill in a struct passwd* for a domain user based on username */
131 wbcErr
wbcGetpwnam(const char *name
, struct passwd
**pwd
)
133 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
134 struct winbindd_request request
;
135 struct winbindd_response response
;
138 wbc_status
= WBC_ERR_INVALID_PARAM
;
139 BAIL_ON_WBC_ERROR(wbc_status
);
142 /* Initialize request */
144 ZERO_STRUCT(request
);
145 ZERO_STRUCT(response
);
147 /* dst is already null terminated from the memset above */
149 strncpy(request
.data
.username
, name
, sizeof(request
.data
.username
)-1);
151 wbc_status
= wbcRequestResponse(WINBINDD_GETPWNAM
,
154 BAIL_ON_WBC_ERROR(wbc_status
);
156 *pwd
= copy_passwd_entry(&response
.data
.pw
);
157 BAIL_ON_PTR_ERROR(*pwd
, wbc_status
);
163 /* Fill in a struct passwd* for a domain user based on uid */
164 wbcErr
wbcGetpwuid(uid_t uid
, struct passwd
**pwd
)
166 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
167 struct winbindd_request request
;
168 struct winbindd_response response
;
171 wbc_status
= WBC_ERR_INVALID_PARAM
;
172 BAIL_ON_WBC_ERROR(wbc_status
);
175 /* Initialize request */
177 ZERO_STRUCT(request
);
178 ZERO_STRUCT(response
);
180 request
.data
.uid
= uid
;
182 wbc_status
= wbcRequestResponse(WINBINDD_GETPWUID
,
185 BAIL_ON_WBC_ERROR(wbc_status
);
187 *pwd
= copy_passwd_entry(&response
.data
.pw
);
188 BAIL_ON_PTR_ERROR(*pwd
, wbc_status
);
194 /* Fill in a struct passwd* for a domain user based on sid */
195 wbcErr
wbcGetpwsid(struct wbcDomainSid
*sid
, struct passwd
**pwd
)
197 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
198 struct winbindd_request request
;
199 struct winbindd_response response
;
200 char * sid_string
= NULL
;
203 wbc_status
= WBC_ERR_INVALID_PARAM
;
204 BAIL_ON_WBC_ERROR(wbc_status
);
207 wbc_status
= wbcSidToString(sid
, &sid_string
);
208 BAIL_ON_WBC_ERROR(wbc_status
);
210 /* Initialize request */
212 ZERO_STRUCT(request
);
213 ZERO_STRUCT(response
);
215 strncpy(request
.data
.sid
, sid_string
, sizeof(request
.data
.sid
));
217 wbc_status
= wbcRequestResponse(WINBINDD_GETPWSID
,
220 BAIL_ON_WBC_ERROR(wbc_status
);
222 *pwd
= copy_passwd_entry(&response
.data
.pw
);
223 BAIL_ON_PTR_ERROR(*pwd
, wbc_status
);
227 wbcFreeMemory(sid_string
);
233 /* Fill in a struct passwd* for a domain user based on username */
234 wbcErr
wbcGetgrnam(const char *name
, struct group
**grp
)
236 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
237 struct winbindd_request request
;
238 struct winbindd_response response
;
240 /* Initialize request */
242 ZERO_STRUCT(request
);
243 ZERO_STRUCT(response
);
246 wbc_status
= WBC_ERR_INVALID_PARAM
;
247 BAIL_ON_WBC_ERROR(wbc_status
);
250 /* dst is already null terminated from the memset above */
252 strncpy(request
.data
.groupname
, name
, sizeof(request
.data
.groupname
)-1);
254 wbc_status
= wbcRequestResponse(WINBINDD_GETGRNAM
,
257 BAIL_ON_WBC_ERROR(wbc_status
);
259 *grp
= copy_group_entry(&response
.data
.gr
,
260 (char*)response
.extra_data
.data
);
261 BAIL_ON_PTR_ERROR(*grp
, wbc_status
);
264 if (response
.extra_data
.data
)
265 free(response
.extra_data
.data
);
270 /* Fill in a struct passwd* for a domain user based on uid */
271 wbcErr
wbcGetgrgid(gid_t gid
, struct group
**grp
)
273 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
274 struct winbindd_request request
;
275 struct winbindd_response response
;
277 /* Initialize request */
279 ZERO_STRUCT(request
);
280 ZERO_STRUCT(response
);
283 wbc_status
= WBC_ERR_INVALID_PARAM
;
284 BAIL_ON_WBC_ERROR(wbc_status
);
287 request
.data
.gid
= gid
;
289 wbc_status
= wbcRequestResponse(WINBINDD_GETGRGID
,
292 BAIL_ON_WBC_ERROR(wbc_status
);
294 *grp
= copy_group_entry(&response
.data
.gr
,
295 (char*)response
.extra_data
.data
);
296 BAIL_ON_PTR_ERROR(*grp
, wbc_status
);
299 if (response
.extra_data
.data
)
300 free(response
.extra_data
.data
);
305 /** @brief Number of cached passwd structs
308 static uint32_t pw_cache_size
;
310 /** @brief Position of the pwent context
313 static uint32_t pw_cache_idx
;
315 /** @brief Winbindd response containing the passwd structs
318 static struct winbindd_response pw_response
;
320 /* Reset the passwd iterator */
321 wbcErr
wbcSetpwent(void)
323 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
325 if (pw_cache_size
> 0) {
326 pw_cache_idx
= pw_cache_size
= 0;
327 if (pw_response
.extra_data
.data
) {
328 free(pw_response
.extra_data
.data
);
332 ZERO_STRUCT(pw_response
);
334 wbc_status
= wbcRequestResponse(WINBINDD_SETPWENT
,
336 BAIL_ON_WBC_ERROR(wbc_status
);
342 /* 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 /* Return the next struct passwd* entry from the pwent iterator */
363 wbcErr
wbcGetpwent(struct passwd
**pwd
)
365 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
366 struct winbindd_request request
;
367 struct winbindd_pw
*wb_pw
;
369 /* If there's a cached result, return that. */
370 if (pw_cache_idx
< pw_cache_size
) {
374 /* Otherwise, query winbindd for some entries. */
378 if (pw_response
.extra_data
.data
) {
379 free(pw_response
.extra_data
.data
);
380 ZERO_STRUCT(pw_response
);
383 ZERO_STRUCT(request
);
384 request
.data
.num_entries
= MAX_GETPWENT_USERS
;
386 wbc_status
= wbcRequestResponse(WINBINDD_GETPWENT
, &request
,
389 BAIL_ON_WBC_ERROR(wbc_status
);
391 pw_cache_size
= pw_response
.data
.num_entries
;
395 wb_pw
= (struct winbindd_pw
*) pw_response
.extra_data
.data
;
397 *pwd
= copy_passwd_entry(&wb_pw
[pw_cache_idx
]);
399 BAIL_ON_PTR_ERROR(*pwd
, wbc_status
);
407 /** @brief Number of cached group structs
410 static uint32_t gr_cache_size
;
412 /** @brief Position of the grent context
415 static uint32_t gr_cache_idx
;
417 /** @brief Winbindd response containing the group structs
420 static struct winbindd_response gr_response
;
422 /* Reset the group iterator */
423 wbcErr
wbcSetgrent(void)
425 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
427 if (gr_cache_size
> 0) {
428 gr_cache_idx
= gr_cache_size
= 0;
429 if (gr_response
.extra_data
.data
) {
430 free(gr_response
.extra_data
.data
);
434 ZERO_STRUCT(gr_response
);
436 wbc_status
= wbcRequestResponse(WINBINDD_SETGRENT
,
438 BAIL_ON_WBC_ERROR(wbc_status
);
444 /* Close the group iterator */
445 wbcErr
wbcEndgrent(void)
447 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
449 if (gr_cache_size
> 0) {
450 gr_cache_idx
= gr_cache_size
= 0;
451 if (gr_response
.extra_data
.data
) {
452 free(gr_response
.extra_data
.data
);
456 wbc_status
= wbcRequestResponse(WINBINDD_ENDGRENT
,
458 BAIL_ON_WBC_ERROR(wbc_status
);
464 /* Return the next struct group* entry from the pwent iterator */
465 wbcErr
wbcGetgrent(struct group
**grp
)
467 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
468 struct winbindd_request request
;
469 struct winbindd_gr
*wb_gr
;
472 /* If there's a cached result, return that. */
473 if (gr_cache_idx
< gr_cache_size
) {
477 /* Otherwise, query winbindd for some entries. */
481 if (gr_response
.extra_data
.data
) {
482 free(gr_response
.extra_data
.data
);
483 ZERO_STRUCT(gr_response
);
486 ZERO_STRUCT(request
);
487 request
.data
.num_entries
= MAX_GETGRENT_GROUPS
;
489 wbc_status
= wbcRequestResponse(WINBINDD_GETGRENT
, &request
,
492 BAIL_ON_WBC_ERROR(wbc_status
);
494 gr_cache_size
= gr_response
.data
.num_entries
;
498 wb_gr
= (struct winbindd_gr
*) gr_response
.extra_data
.data
;
500 mem_ofs
= wb_gr
[gr_cache_idx
].gr_mem_ofs
+
501 gr_cache_size
* sizeof(struct winbindd_gr
);
503 *grp
= copy_group_entry(&wb_gr
[gr_cache_idx
],
504 ((char *)gr_response
.extra_data
.data
)+mem_ofs
);
506 BAIL_ON_PTR_ERROR(*grp
, wbc_status
);
514 /* Return the next struct group* entry from the pwent iterator */
515 wbcErr
wbcGetgrlist(struct group
**grp
)
517 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
518 struct winbindd_request request
;
519 struct winbindd_gr
*wb_gr
;
521 /* If there's a cached result, return that. */
522 if (gr_cache_idx
< gr_cache_size
) {
526 /* Otherwise, query winbindd for some entries. */
530 if (gr_response
.extra_data
.data
) {
531 free(gr_response
.extra_data
.data
);
532 ZERO_STRUCT(gr_response
);
535 ZERO_STRUCT(request
);
536 request
.data
.num_entries
= MAX_GETGRENT_GROUPS
;
538 wbc_status
= wbcRequestResponse(WINBINDD_GETGRLST
, &request
,
541 BAIL_ON_WBC_ERROR(wbc_status
);
543 gr_cache_size
= gr_response
.data
.num_entries
;
547 wb_gr
= (struct winbindd_gr
*) gr_response
.extra_data
.data
;
549 *grp
= copy_group_entry(&wb_gr
[gr_cache_idx
], NULL
);
551 BAIL_ON_PTR_ERROR(*grp
, wbc_status
);
559 /* Return the unix group array belonging to the given user */
560 wbcErr
wbcGetGroups(const char *account
,
561 uint32_t *num_groups
,
564 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
565 struct winbindd_request request
;
566 struct winbindd_response response
;
568 gid_t
*groups
= NULL
;
570 /* Initialize request */
572 ZERO_STRUCT(request
);
573 ZERO_STRUCT(response
);
576 wbc_status
= WBC_ERR_INVALID_PARAM
;
577 BAIL_ON_WBC_ERROR(wbc_status
);
582 strncpy(request
.data
.username
, account
, sizeof(request
.data
.username
)-1);
584 wbc_status
= wbcRequestResponse(WINBINDD_GETGROUPS
,
587 BAIL_ON_WBC_ERROR(wbc_status
);
589 groups
= talloc_array(NULL
, gid_t
, response
.data
.num_entries
);
590 BAIL_ON_PTR_ERROR(groups
, wbc_status
);
592 for (i
= 0; i
< response
.data
.num_entries
; i
++) {
593 groups
[i
] = ((gid_t
*)response
.extra_data
.data
)[i
];
596 *num_groups
= response
.data
.num_entries
;
600 wbc_status
= WBC_ERR_SUCCESS
;
603 if (response
.extra_data
.data
) {
604 free(response
.extra_data
.data
);