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"
27 #include "../winbind_client.h"
29 /** @brief The maximum number of pwent structs to get from winbindd
32 #define MAX_GETPWENT_USERS 500
34 /** @brief The maximum number of grent structs to get from winbindd
37 #define MAX_GETGRENT_GROUPS 500
43 static void wbcPasswdDestructor(void *ptr
)
45 struct passwd
*pw
= (struct passwd
*)ptr
;
53 static struct passwd
*copy_passwd_entry(struct winbindd_pw
*p
)
55 struct passwd
*pw
= NULL
;
57 pw
= (struct passwd
*)wbcAllocateMemory(1, sizeof(struct passwd
),
62 pw
->pw_name
= strdup(p
->pw_name
);
63 if (pw
->pw_name
== NULL
) {
66 pw
->pw_passwd
= strdup(p
->pw_passwd
);
67 if (pw
->pw_passwd
== NULL
) {
70 pw
->pw_gecos
= strdup(p
->pw_gecos
);
71 if (pw
->pw_gecos
== NULL
) {
74 pw
->pw_shell
= strdup(p
->pw_shell
);
75 if (pw
->pw_shell
== NULL
) {
78 pw
->pw_dir
= strdup(p
->pw_dir
);
79 if (pw
->pw_dir
== NULL
) {
82 pw
->pw_uid
= p
->pw_uid
;
83 pw
->pw_gid
= p
->pw_gid
;
95 static void wbcGroupDestructor(void *ptr
)
97 struct group
*gr
= (struct group
*)ptr
;
103 for (i
=0; gr
->gr_mem
[i
] != NULL
; i
++) {
109 static struct group
*copy_group_entry(struct winbindd_gr
*g
,
112 struct group
*gr
= NULL
;
116 gr
= (struct group
*)wbcAllocateMemory(
117 1, sizeof(struct group
), wbcGroupDestructor
);
122 gr
->gr_name
= strdup(g
->gr_name
);
123 if (gr
->gr_name
== NULL
) {
126 gr
->gr_passwd
= strdup(g
->gr_passwd
);
127 if (gr
->gr_passwd
== NULL
) {
130 gr
->gr_gid
= g
->gr_gid
;
132 gr
->gr_mem
= (char **)calloc(g
->num_gr_mem
+1, sizeof(char *));
133 if (gr
->gr_mem
== NULL
) {
137 mem_p
= mem_q
= mem_buf
;
138 for (i
=0; i
<g
->num_gr_mem
&& mem_p
; i
++) {
139 mem_q
= strchr(mem_p
, ',');
144 gr
->gr_mem
[i
] = strdup(mem_p
);
145 if (gr
->gr_mem
[i
] == NULL
) {
155 gr
->gr_mem
[i
] = NULL
;
164 /* Fill in a struct passwd* for a domain user based on username */
165 wbcErr
wbcGetpwnam(const char *name
, struct passwd
**pwd
)
167 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
168 struct winbindd_request request
;
169 struct winbindd_response response
;
172 wbc_status
= WBC_ERR_INVALID_PARAM
;
173 BAIL_ON_WBC_ERROR(wbc_status
);
176 /* Initialize request */
178 ZERO_STRUCT(request
);
179 ZERO_STRUCT(response
);
181 /* dst is already null terminated from the memset above */
183 strncpy(request
.data
.username
, name
, sizeof(request
.data
.username
)-1);
185 wbc_status
= wbcRequestResponse(WINBINDD_GETPWNAM
,
188 BAIL_ON_WBC_ERROR(wbc_status
);
190 *pwd
= copy_passwd_entry(&response
.data
.pw
);
191 BAIL_ON_PTR_ERROR(*pwd
, wbc_status
);
197 /* Fill in a struct passwd* for a domain user based on uid */
198 wbcErr
wbcGetpwuid(uid_t uid
, struct passwd
**pwd
)
200 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
201 struct winbindd_request request
;
202 struct winbindd_response response
;
205 wbc_status
= WBC_ERR_INVALID_PARAM
;
206 BAIL_ON_WBC_ERROR(wbc_status
);
209 /* Initialize request */
211 ZERO_STRUCT(request
);
212 ZERO_STRUCT(response
);
214 request
.data
.uid
= uid
;
216 wbc_status
= wbcRequestResponse(WINBINDD_GETPWUID
,
219 BAIL_ON_WBC_ERROR(wbc_status
);
221 *pwd
= copy_passwd_entry(&response
.data
.pw
);
222 BAIL_ON_PTR_ERROR(*pwd
, wbc_status
);
228 /* Fill in a struct passwd* for a domain user based on sid */
229 wbcErr
wbcGetpwsid(struct wbcDomainSid
*sid
, struct passwd
**pwd
)
231 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
232 struct winbindd_request request
;
233 struct winbindd_response response
;
234 char * sid_string
= NULL
;
237 wbc_status
= WBC_ERR_INVALID_PARAM
;
238 BAIL_ON_WBC_ERROR(wbc_status
);
241 wbc_status
= wbcSidToString(sid
, &sid_string
);
242 BAIL_ON_WBC_ERROR(wbc_status
);
244 /* Initialize request */
246 ZERO_STRUCT(request
);
247 ZERO_STRUCT(response
);
249 strncpy(request
.data
.sid
, sid_string
, sizeof(request
.data
.sid
));
251 wbc_status
= wbcRequestResponse(WINBINDD_GETPWSID
,
254 BAIL_ON_WBC_ERROR(wbc_status
);
256 *pwd
= copy_passwd_entry(&response
.data
.pw
);
257 BAIL_ON_PTR_ERROR(*pwd
, wbc_status
);
260 wbcFreeMemory(sid_string
);
264 /* Fill in a struct passwd* for a domain user based on username */
265 wbcErr
wbcGetgrnam(const char *name
, struct group
**grp
)
267 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
268 struct winbindd_request request
;
269 struct winbindd_response response
;
271 /* Initialize request */
273 ZERO_STRUCT(request
);
274 ZERO_STRUCT(response
);
277 wbc_status
= WBC_ERR_INVALID_PARAM
;
278 BAIL_ON_WBC_ERROR(wbc_status
);
281 /* dst is already null terminated from the memset above */
283 strncpy(request
.data
.groupname
, name
, sizeof(request
.data
.groupname
)-1);
285 wbc_status
= wbcRequestResponse(WINBINDD_GETGRNAM
,
288 BAIL_ON_WBC_ERROR(wbc_status
);
290 *grp
= copy_group_entry(&response
.data
.gr
,
291 (char*)response
.extra_data
.data
);
292 BAIL_ON_PTR_ERROR(*grp
, wbc_status
);
295 winbindd_free_response(&response
);
300 /* Fill in a struct passwd* for a domain user based on uid */
301 wbcErr
wbcGetgrgid(gid_t gid
, struct group
**grp
)
303 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
304 struct winbindd_request request
;
305 struct winbindd_response response
;
307 /* Initialize request */
309 ZERO_STRUCT(request
);
310 ZERO_STRUCT(response
);
313 wbc_status
= WBC_ERR_INVALID_PARAM
;
314 BAIL_ON_WBC_ERROR(wbc_status
);
317 request
.data
.gid
= gid
;
319 wbc_status
= wbcRequestResponse(WINBINDD_GETGRGID
,
322 BAIL_ON_WBC_ERROR(wbc_status
);
324 *grp
= copy_group_entry(&response
.data
.gr
,
325 (char*)response
.extra_data
.data
);
326 BAIL_ON_PTR_ERROR(*grp
, wbc_status
);
329 winbindd_free_response(&response
);
334 /** @brief Number of cached passwd structs
337 static uint32_t pw_cache_size
;
339 /** @brief Position of the pwent context
342 static uint32_t pw_cache_idx
;
344 /** @brief Winbindd response containing the passwd structs
347 static struct winbindd_response pw_response
;
349 /* Reset the passwd iterator */
350 wbcErr
wbcSetpwent(void)
352 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
354 if (pw_cache_size
> 0) {
355 pw_cache_idx
= pw_cache_size
= 0;
356 winbindd_free_response(&pw_response
);
359 ZERO_STRUCT(pw_response
);
361 wbc_status
= wbcRequestResponse(WINBINDD_SETPWENT
,
363 BAIL_ON_WBC_ERROR(wbc_status
);
369 /* Close the passwd iterator */
370 wbcErr
wbcEndpwent(void)
372 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
374 if (pw_cache_size
> 0) {
375 pw_cache_idx
= pw_cache_size
= 0;
376 winbindd_free_response(&pw_response
);
379 wbc_status
= wbcRequestResponse(WINBINDD_ENDPWENT
,
381 BAIL_ON_WBC_ERROR(wbc_status
);
387 /* Return the next struct passwd* entry from the pwent iterator */
388 wbcErr
wbcGetpwent(struct passwd
**pwd
)
390 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
391 struct winbindd_request request
;
392 struct winbindd_pw
*wb_pw
;
394 /* If there's a cached result, return that. */
395 if (pw_cache_idx
< pw_cache_size
) {
399 /* Otherwise, query winbindd for some entries. */
403 winbindd_free_response(&pw_response
);
405 ZERO_STRUCT(request
);
406 request
.data
.num_entries
= MAX_GETPWENT_USERS
;
408 wbc_status
= wbcRequestResponse(WINBINDD_GETPWENT
, &request
,
411 BAIL_ON_WBC_ERROR(wbc_status
);
413 pw_cache_size
= pw_response
.data
.num_entries
;
417 wb_pw
= (struct winbindd_pw
*) pw_response
.extra_data
.data
;
419 *pwd
= copy_passwd_entry(&wb_pw
[pw_cache_idx
]);
421 BAIL_ON_PTR_ERROR(*pwd
, wbc_status
);
429 /** @brief Number of cached group structs
432 static uint32_t gr_cache_size
;
434 /** @brief Position of the grent context
437 static uint32_t gr_cache_idx
;
439 /** @brief Winbindd response containing the group structs
442 static struct winbindd_response gr_response
;
444 /* Reset the group iterator */
445 wbcErr
wbcSetgrent(void)
447 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
449 if (gr_cache_size
> 0) {
450 gr_cache_idx
= gr_cache_size
= 0;
451 winbindd_free_response(&gr_response
);
454 ZERO_STRUCT(gr_response
);
456 wbc_status
= wbcRequestResponse(WINBINDD_SETGRENT
,
458 BAIL_ON_WBC_ERROR(wbc_status
);
464 /* Close the group iterator */
465 wbcErr
wbcEndgrent(void)
467 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
469 if (gr_cache_size
> 0) {
470 gr_cache_idx
= gr_cache_size
= 0;
471 winbindd_free_response(&gr_response
);
474 wbc_status
= wbcRequestResponse(WINBINDD_ENDGRENT
,
476 BAIL_ON_WBC_ERROR(wbc_status
);
482 /* Return the next struct group* entry from the pwent iterator */
483 wbcErr
wbcGetgrent(struct group
**grp
)
485 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
486 struct winbindd_request request
;
487 struct winbindd_gr
*wb_gr
;
490 /* If there's a cached result, return that. */
491 if (gr_cache_idx
< gr_cache_size
) {
495 /* Otherwise, query winbindd for some entries. */
499 winbindd_free_response(&gr_response
);
501 ZERO_STRUCT(request
);
502 request
.data
.num_entries
= MAX_GETGRENT_GROUPS
;
504 wbc_status
= wbcRequestResponse(WINBINDD_GETGRENT
, &request
,
507 BAIL_ON_WBC_ERROR(wbc_status
);
509 gr_cache_size
= gr_response
.data
.num_entries
;
513 wb_gr
= (struct winbindd_gr
*) gr_response
.extra_data
.data
;
515 mem_ofs
= wb_gr
[gr_cache_idx
].gr_mem_ofs
+
516 gr_cache_size
* sizeof(struct winbindd_gr
);
518 *grp
= copy_group_entry(&wb_gr
[gr_cache_idx
],
519 ((char *)gr_response
.extra_data
.data
)+mem_ofs
);
521 BAIL_ON_PTR_ERROR(*grp
, wbc_status
);
529 /* Return the next struct group* entry from the pwent iterator */
530 wbcErr
wbcGetgrlist(struct group
**grp
)
532 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
533 struct winbindd_request request
;
534 struct winbindd_gr
*wb_gr
;
536 /* If there's a cached result, return that. */
537 if (gr_cache_idx
< gr_cache_size
) {
541 /* Otherwise, query winbindd for some entries. */
545 winbindd_free_response(&gr_response
);
546 ZERO_STRUCT(gr_response
);
548 ZERO_STRUCT(request
);
549 request
.data
.num_entries
= MAX_GETGRENT_GROUPS
;
551 wbc_status
= wbcRequestResponse(WINBINDD_GETGRLST
, &request
,
554 BAIL_ON_WBC_ERROR(wbc_status
);
556 gr_cache_size
= gr_response
.data
.num_entries
;
560 wb_gr
= (struct winbindd_gr
*) gr_response
.extra_data
.data
;
562 *grp
= copy_group_entry(&wb_gr
[gr_cache_idx
], NULL
);
564 BAIL_ON_PTR_ERROR(*grp
, wbc_status
);
572 /* Return the unix group array belonging to the given user */
573 wbcErr
wbcGetGroups(const char *account
,
574 uint32_t *num_groups
,
577 wbcErr wbc_status
= WBC_ERR_UNKNOWN_FAILURE
;
578 struct winbindd_request request
;
579 struct winbindd_response response
;
581 gid_t
*groups
= NULL
;
583 /* Initialize request */
585 ZERO_STRUCT(request
);
586 ZERO_STRUCT(response
);
589 wbc_status
= WBC_ERR_INVALID_PARAM
;
590 BAIL_ON_WBC_ERROR(wbc_status
);
595 strncpy(request
.data
.username
, account
, sizeof(request
.data
.username
)-1);
597 wbc_status
= wbcRequestResponse(WINBINDD_GETGROUPS
,
600 BAIL_ON_WBC_ERROR(wbc_status
);
602 groups
= (gid_t
*)wbcAllocateMemory(
603 sizeof(gid_t
), response
.data
.num_entries
, NULL
);
604 BAIL_ON_PTR_ERROR(groups
, wbc_status
);
606 for (i
= 0; i
< response
.data
.num_entries
; i
++) {
607 groups
[i
] = ((gid_t
*)response
.extra_data
.data
)[i
];
610 *num_groups
= response
.data
.num_entries
;
614 wbc_status
= WBC_ERR_SUCCESS
;
617 winbindd_free_response(&response
);
618 wbcFreeMemory(groups
);