vfs: Remove "sbuf" from readdir_fn()
[Samba.git] / nsswitch / libwbclient / wbc_pwd.c
blob4e83fbf073f3f894f5344a2f3f58e21f29157a53
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind client API
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 */
26 #include "replace.h"
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
40 /**
42 **/
44 static void wbcPasswdDestructor(void *ptr)
46 struct passwd *pw = (struct passwd *)ptr;
47 free(pw->pw_name);
48 free(pw->pw_passwd);
49 free(pw->pw_gecos);
50 free(pw->pw_shell);
51 free(pw->pw_dir);
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),
59 wbcPasswdDestructor);
60 if (pw == NULL) {
61 return NULL;
63 pw->pw_name = strdup(p->pw_name);
64 if (pw->pw_name == NULL) {
65 goto fail;
67 pw->pw_passwd = strdup(p->pw_passwd);
68 if (pw->pw_passwd == NULL) {
69 goto fail;
71 pw->pw_gecos = strdup(p->pw_gecos);
72 if (pw->pw_gecos == NULL) {
73 goto fail;
75 pw->pw_shell = strdup(p->pw_shell);
76 if (pw->pw_shell == NULL) {
77 goto fail;
79 pw->pw_dir = strdup(p->pw_dir);
80 if (pw->pw_dir == NULL) {
81 goto fail;
83 pw->pw_uid = p->pw_uid;
84 pw->pw_gid = p->pw_gid;
85 return pw;
87 fail:
88 wbcFreeMemory(pw);
89 return NULL;
92 /**
94 **/
96 static void wbcGroupDestructor(void *ptr)
98 struct group *gr = (struct group *)ptr;
99 int i;
101 free(gr->gr_name);
102 free(gr->gr_passwd);
104 /* if the array was partly created this can be NULL */
105 if (gr->gr_mem == NULL) {
106 return;
109 for (i=0; gr->gr_mem[i] != NULL; i++) {
110 free(gr->gr_mem[i]);
112 free(gr->gr_mem);
115 static struct group *copy_group_entry(struct winbindd_gr *g,
116 char *mem_buf)
118 struct group *gr = NULL;
119 int i;
120 char *mem_p, *mem_q;
122 gr = (struct group *)wbcAllocateMemory(
123 1, sizeof(struct group), wbcGroupDestructor);
124 if (gr == NULL) {
125 return NULL;
128 gr->gr_name = strdup(g->gr_name);
129 if (gr->gr_name == NULL) {
130 goto fail;
132 gr->gr_passwd = strdup(g->gr_passwd);
133 if (gr->gr_passwd == NULL) {
134 goto fail;
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) {
140 goto fail;
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, ',');
146 if (mem_q != NULL) {
147 *mem_q = '\0';
150 gr->gr_mem[i] = strdup(mem_p);
151 if (gr->gr_mem[i] == NULL) {
152 goto fail;
155 if (mem_q == NULL) {
156 i += 1;
157 break;
159 mem_p = mem_q + 1;
161 gr->gr_mem[i] = NULL;
163 return gr;
165 fail:
166 wbcFreeMemory(gr);
167 return NULL;
170 /* Fill in a struct passwd* for a domain user based on username */
171 _PUBLIC_
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;
179 if (!name || !pwd) {
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,
194 &request,
195 &response);
196 BAIL_ON_WBC_ERROR(wbc_status);
198 *pwd = copy_passwd_entry(&response.data.pw);
199 BAIL_ON_PTR_ERROR(*pwd, wbc_status);
201 done:
202 return wbc_status;
205 _PUBLIC_
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 */
212 _PUBLIC_
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;
219 if (!pwd) {
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,
232 &request,
233 &response);
234 BAIL_ON_WBC_ERROR(wbc_status);
236 *pwd = copy_passwd_entry(&response.data.pw);
237 BAIL_ON_PTR_ERROR(*pwd, wbc_status);
239 done:
240 return wbc_status;
243 _PUBLIC_
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 */
250 _PUBLIC_
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;
258 if (!pwd) {
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,
271 &request,
272 &response);
273 BAIL_ON_WBC_ERROR(wbc_status);
275 *pwd = copy_passwd_entry(&response.data.pw);
276 BAIL_ON_PTR_ERROR(*pwd, wbc_status);
278 done:
279 return wbc_status;
282 _PUBLIC_
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 */
289 _PUBLIC_
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);
302 if (!name || !grp) {
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,
312 &request,
313 &response);
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);
320 done:
321 winbindd_free_response(&response);
323 return wbc_status;
326 _PUBLIC_
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 */
333 _PUBLIC_
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);
345 if (!grp) {
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,
353 &request,
354 &response);
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);
361 done:
362 winbindd_free_response(&response);
364 return wbc_status;
367 _PUBLIC_
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 */
379 _PUBLIC_
380 wbcErr wbcCtxSetpwent(struct wbcContext *ctx)
382 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
384 if (!ctx) {
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,
396 NULL, NULL);
397 BAIL_ON_WBC_ERROR(wbc_status);
399 done:
400 return wbc_status;
403 _PUBLIC_
404 wbcErr wbcSetpwent(void)
406 return wbcCtxSetpwent(NULL);
409 /* Close the passwd iterator */
410 _PUBLIC_
411 wbcErr wbcCtxEndpwent(struct wbcContext *ctx)
413 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
415 if (!ctx) {
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,
425 NULL, NULL);
426 BAIL_ON_WBC_ERROR(wbc_status);
428 done:
429 return wbc_status;
432 _PUBLIC_
433 wbcErr wbcEndpwent(void)
435 return wbcCtxEndpwent(NULL);
438 /* Return the next struct passwd* entry from the pwent iterator */
439 _PUBLIC_
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;
446 if (!ctx) {
447 ctx = wbcGetGlobalCtx();
450 /* If there's a cached result, return that. */
451 if (ctx->pw_cache_idx < ctx->pw_cache_size) {
452 goto return_result;
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,
465 &pw_response);
467 BAIL_ON_WBC_ERROR(wbc_status);
469 ctx->pw_cache_size = pw_response.data.num_entries;
471 return_result:
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);
479 ctx->pw_cache_idx++;
481 done:
482 return wbc_status;
485 _PUBLIC_
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 */
497 _PUBLIC_
498 wbcErr wbcCtxSetgrent(struct wbcContext *ctx)
500 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
502 if (!ctx) {
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,
514 NULL, NULL);
515 BAIL_ON_WBC_ERROR(wbc_status);
517 done:
518 return wbc_status;
521 _PUBLIC_
522 wbcErr wbcSetgrent(void)
524 return wbcCtxSetgrent(NULL);
527 /* Close the group iterator */
528 _PUBLIC_
529 wbcErr wbcCtxEndgrent(struct wbcContext *ctx)
531 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
533 if (!ctx) {
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,
543 NULL, NULL);
544 BAIL_ON_WBC_ERROR(wbc_status);
546 done:
547 return wbc_status;
550 _PUBLIC_
551 wbcErr wbcEndgrent(void)
553 return wbcCtxEndgrent(NULL);
556 /* Return the next struct group* entry from the pwent iterator */
557 _PUBLIC_
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;
563 uint32_t mem_ofs;
565 if (!ctx) {
566 ctx = wbcGetGlobalCtx();
569 /* If there's a cached result, return that. */
570 if (ctx->gr_cache_idx < ctx->gr_cache_size) {
571 goto return_result;
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;
590 return_result:
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);
602 ctx->gr_cache_idx++;
604 done:
605 return wbc_status;
608 _PUBLIC_
609 wbcErr wbcGetgrent(struct group **grp)
611 return wbcCtxGetgrent(NULL, grp);
614 /* Return the next struct group* entry from the pwent iterator */
615 _PUBLIC_
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;
622 if (!ctx) {
623 ctx = wbcGetGlobalCtx();
626 /* If there's a cached result, return that. */
627 if (ctx->gr_cache_idx < ctx->gr_cache_size) {
628 goto return_result;
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;
648 return_result:
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);
656 ctx->gr_cache_idx++;
658 done:
659 return wbc_status;
662 _PUBLIC_
663 wbcErr wbcGetgrlist(struct group **grp)
665 return wbcCtxGetgrlist(NULL, grp);
668 /* Return the unix group array belonging to the given user */
669 _PUBLIC_
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;
676 uint32_t i;
677 gid_t *groups = NULL;
679 /* Initialize request */
681 ZERO_STRUCT(request);
682 ZERO_STRUCT(response);
684 if (!account) {
685 wbc_status = WBC_ERR_INVALID_PARAM;
686 BAIL_ON_WBC_ERROR(wbc_status);
689 /* Send request */
691 strncpy(request.data.username, account, sizeof(request.data.username)-1);
693 wbc_status = wbcRequestResponse(ctx, WINBINDD_GETGROUPS,
694 &request,
695 &response);
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;
707 *_groups = groups;
708 groups = NULL;
710 wbc_status = WBC_ERR_SUCCESS;
712 done:
713 winbindd_free_response(&response);
714 wbcFreeMemory(groups);
715 return wbc_status;
718 _PUBLIC_
719 wbcErr wbcGetGroups(const char *account, uint32_t *num_groups, gid_t **_groups)
721 return wbcCtxGetGroups(NULL, account, num_groups, _groups);