1 /*
2 Unix SMB/CIFS implementation.
3
4 Winbind client API
5
6 Copyright (C) Gerald (Jerry) Carter 2007
7 Copyright (C) Matthew Newton 2015
8
9
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.
14
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.
19
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/>.
22 */
23
24 /* Required Headers */
25
26 #include "replace.h"
27 #include "libwbclient.h"
28 #include "../winbind_client.h"
29
30 /** @brief The maximum number of pwent structs to get from winbindd
31 *
32 */
33 #define MAX_GETPWENT_USERS 500
34
35 /** @brief The maximum number of grent structs to get from winbindd
36 *
37 */
38 #define MAX_GETGRENT_GROUPS 500
39
40 /**
41 *
42 **/
43
wbcPasswdDestructor(void * ptr)44 static void wbcPasswdDestructor(void *ptr)
45 {
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);
52 }
53
copy_passwd_entry(struct winbindd_pw * p)54 static struct passwd *copy_passwd_entry(struct winbindd_pw *p)
55 {
56 struct passwd *pw = NULL;
57
58 pw = (struct passwd *)wbcAllocateMemory(1, sizeof(struct passwd),
59 wbcPasswdDestructor);
60 if (pw == NULL) {
61 return NULL;
62 }
63 pw->pw_name = strdup(p->pw_name);
64 if (pw->pw_name == NULL) {
65 goto fail;
66 }
67 pw->pw_passwd = strdup(p->pw_passwd);
68 if (pw->pw_passwd == NULL) {
69 goto fail;
70 }
71 pw->pw_gecos = strdup(p->pw_gecos);
72 if (pw->pw_gecos == NULL) {
73 goto fail;
74 }
75 pw->pw_shell = strdup(p->pw_shell);
76 if (pw->pw_shell == NULL) {
77 goto fail;
78 }
79 pw->pw_dir = strdup(p->pw_dir);
80 if (pw->pw_dir == NULL) {
81 goto fail;
82 }
83 pw->pw_uid = p->pw_uid;
84 pw->pw_gid = p->pw_gid;
85 return pw;
86
87 fail:
88 wbcFreeMemory(pw);
89 return NULL;
90 }
91
92 /**
93 *
94 **/
95
wbcGroupDestructor(void * ptr)96 static void wbcGroupDestructor(void *ptr)
97 {
98 struct group *gr = (struct group *)ptr;
99 int i;
100
101 free(gr->gr_name);
102 free(gr->gr_passwd);
103
104 /* if the array was partly created this can be NULL */
105 if (gr->gr_mem == NULL) {
106 return;
107 }
108
109 for (i=0; gr->gr_mem[i] != NULL; i++) {
110 free(gr->gr_mem[i]);
111 }
112 free(gr->gr_mem);
113 }
114
copy_group_entry(struct winbindd_gr * g,char * mem_buf)115 static struct group *copy_group_entry(struct winbindd_gr *g,
116 char *mem_buf)
117 {
118 struct group *gr = NULL;
119 int i;
120 char *mem_p, *mem_q;
121
122 gr = (struct group *)wbcAllocateMemory(
123 1, sizeof(struct group), wbcGroupDestructor);
124 if (gr == NULL) {
125 return NULL;
126 }
127
128 gr->gr_name = strdup(g->gr_name);
129 if (gr->gr_name == NULL) {
130 goto fail;
131 }
132 gr->gr_passwd = strdup(g->gr_passwd);
133 if (gr->gr_passwd == NULL) {
134 goto fail;
135 }
136 gr->gr_gid = g->gr_gid;
137
138 gr->gr_mem = (char **)calloc(g->num_gr_mem+1, sizeof(char *));
139 if (gr->gr_mem == NULL) {
140 goto fail;
141 }
142
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';
148 }
149
150 gr->gr_mem[i] = strdup(mem_p);
151 if (gr->gr_mem[i] == NULL) {
152 goto fail;
153 }
154
155 if (mem_q == NULL) {
156 i += 1;
157 break;
158 }
159 mem_p = mem_q + 1;
160 }
161 gr->gr_mem[i] = NULL;
162
163 return gr;
164
165 fail:
166 wbcFreeMemory(gr);
167 return NULL;
168 }
169
170 /* Fill in a struct passwd* for a domain user based on username */
wbcCtxGetpwnam(struct wbcContext * ctx,const char * name,struct passwd ** pwd)171 wbcErr wbcCtxGetpwnam(struct wbcContext *ctx,
172 const char *name, struct passwd **pwd)
173 {
174 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
175 struct winbindd_request request;
176 struct winbindd_response response;
177
178 if (!name || !pwd) {
179 wbc_status = WBC_ERR_INVALID_PARAM;
180 BAIL_ON_WBC_ERROR(wbc_status);
181 }
182
183 /* Initialize request */
184
185 ZERO_STRUCT(request);
186 ZERO_STRUCT(response);
187
188 /* dst is already null terminated from the memset above */
189
190 strncpy(request.data.username, name, sizeof(request.data.username)-1);
191
192 wbc_status = wbcRequestResponse(ctx, WINBINDD_GETPWNAM,
193 &request,
194 &response);
195 BAIL_ON_WBC_ERROR(wbc_status);
196
197 *pwd = copy_passwd_entry(&response.data.pw);
198 BAIL_ON_PTR_ERROR(*pwd, wbc_status);
199
200 done:
201 return wbc_status;
202 }
203
wbcGetpwnam(const char * name,struct passwd ** pwd)204 wbcErr wbcGetpwnam(const char *name, struct passwd **pwd)
205 {
206 return wbcCtxGetpwnam(NULL, name, pwd);
207 }
208
209 /* Fill in a struct passwd* for a domain user based on uid */
wbcCtxGetpwuid(struct wbcContext * ctx,uid_t uid,struct passwd ** pwd)210 wbcErr wbcCtxGetpwuid(struct wbcContext *ctx, uid_t uid, struct passwd **pwd)
211 {
212 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
213 struct winbindd_request request;
214 struct winbindd_response response;
215
216 if (!pwd) {
217 wbc_status = WBC_ERR_INVALID_PARAM;
218 BAIL_ON_WBC_ERROR(wbc_status);
219 }
220
221 /* Initialize request */
222
223 ZERO_STRUCT(request);
224 ZERO_STRUCT(response);
225
226 request.data.uid = uid;
227
228 wbc_status = wbcRequestResponse(ctx, WINBINDD_GETPWUID,
229 &request,
230 &response);
231 BAIL_ON_WBC_ERROR(wbc_status);
232
233 *pwd = copy_passwd_entry(&response.data.pw);
234 BAIL_ON_PTR_ERROR(*pwd, wbc_status);
235
236 done:
237 return wbc_status;
238 }
239
wbcGetpwuid(uid_t uid,struct passwd ** pwd)240 wbcErr wbcGetpwuid(uid_t uid, struct passwd **pwd)
241 {
242 return wbcCtxGetpwuid(NULL, uid, pwd);
243 }
244
245 /* Fill in a struct passwd* for a domain user based on sid */
wbcCtxGetpwsid(struct wbcContext * ctx,struct wbcDomainSid * sid,struct passwd ** pwd)246 wbcErr wbcCtxGetpwsid(struct wbcContext *ctx,
247 struct wbcDomainSid *sid, struct passwd **pwd)
248 {
249 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
250 struct winbindd_request request;
251 struct winbindd_response response;
252
253 if (!pwd) {
254 wbc_status = WBC_ERR_INVALID_PARAM;
255 BAIL_ON_WBC_ERROR(wbc_status);
256 }
257
258 /* Initialize request */
259
260 ZERO_STRUCT(request);
261 ZERO_STRUCT(response);
262
263 wbcSidToStringBuf(sid, request.data.sid, sizeof(request.data.sid));
264
265 wbc_status = wbcRequestResponse(ctx, WINBINDD_GETPWSID,
266 &request,
267 &response);
268 BAIL_ON_WBC_ERROR(wbc_status);
269
270 *pwd = copy_passwd_entry(&response.data.pw);
271 BAIL_ON_PTR_ERROR(*pwd, wbc_status);
272
273 done:
274 return wbc_status;
275 }
276
wbcGetpwsid(struct wbcDomainSid * sid,struct passwd ** pwd)277 wbcErr wbcGetpwsid(struct wbcDomainSid *sid, struct passwd **pwd)
278 {
279 return wbcCtxGetpwsid(NULL, sid, pwd);
280 }
281
282 /* Fill in a struct passwd* for a domain user based on username */
wbcCtxGetgrnam(struct wbcContext * ctx,const char * name,struct group ** grp)283 wbcErr wbcCtxGetgrnam(struct wbcContext *ctx,
284 const char *name, struct group **grp)
285 {
286 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
287 struct winbindd_request request;
288 struct winbindd_response response;
289
290 /* Initialize request */
291
292 ZERO_STRUCT(request);
293 ZERO_STRUCT(response);
294
295 if (!name || !grp) {
296 wbc_status = WBC_ERR_INVALID_PARAM;
297 BAIL_ON_WBC_ERROR(wbc_status);
298 }
299
300 /* dst is already null terminated from the memset above */
301
302 strncpy(request.data.groupname, name, sizeof(request.data.groupname)-1);
303
304 wbc_status = wbcRequestResponse(ctx, WINBINDD_GETGRNAM,
305 &request,
306 &response);
307 BAIL_ON_WBC_ERROR(wbc_status);
308
309 *grp = copy_group_entry(&response.data.gr,
310 (char*)response.extra_data.data);
311 BAIL_ON_PTR_ERROR(*grp, wbc_status);
312
313 done:
314 winbindd_free_response(&response);
315
316 return wbc_status;
317 }
318
wbcGetgrnam(const char * name,struct group ** grp)319 wbcErr wbcGetgrnam(const char *name, struct group **grp)
320 {
321 return wbcCtxGetgrnam(NULL, name, grp);
322 }
323
324 /* Fill in a struct passwd* for a domain user based on uid */
wbcCtxGetgrgid(struct wbcContext * ctx,gid_t gid,struct group ** grp)325 wbcErr wbcCtxGetgrgid(struct wbcContext *ctx, gid_t gid, struct group **grp)
326 {
327 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
328 struct winbindd_request request;
329 struct winbindd_response response;
330
331 /* Initialize request */
332
333 ZERO_STRUCT(request);
334 ZERO_STRUCT(response);
335
336 if (!grp) {
337 wbc_status = WBC_ERR_INVALID_PARAM;
338 BAIL_ON_WBC_ERROR(wbc_status);
339 }
340
341 request.data.gid = gid;
342
343 wbc_status = wbcRequestResponse(ctx, WINBINDD_GETGRGID,
344 &request,
345 &response);
346 BAIL_ON_WBC_ERROR(wbc_status);
347
348 *grp = copy_group_entry(&response.data.gr,
349 (char*)response.extra_data.data);
350 BAIL_ON_PTR_ERROR(*grp, wbc_status);
351
352 done:
353 winbindd_free_response(&response);
354
355 return wbc_status;
356 }
357
wbcGetgrgid(gid_t gid,struct group ** grp)358 wbcErr wbcGetgrgid(gid_t gid, struct group **grp)
359 {
360 return wbcCtxGetgrgid(NULL, gid, grp);
361 }
362
363 /** @brief Winbindd response containing the passwd structs
364 *
365 */
366 static struct winbindd_response pw_response;
367
368 /* Reset the passwd iterator */
wbcCtxSetpwent(struct wbcContext * ctx)369 wbcErr wbcCtxSetpwent(struct wbcContext *ctx)
370 {
371 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
372
373 if (!ctx) {
374 ctx = wbcGetGlobalCtx();
375 }
376
377 if (ctx->pw_cache_size > 0) {
378 ctx->pw_cache_idx = ctx->pw_cache_size = 0;
379 winbindd_free_response(&pw_response);
380 }
381
382 ZERO_STRUCT(pw_response);
383
384 wbc_status = wbcRequestResponse(ctx, WINBINDD_SETPWENT,
385 NULL, NULL);
386 BAIL_ON_WBC_ERROR(wbc_status);
387
388 done:
389 return wbc_status;
390 }
391
wbcSetpwent(void)392 wbcErr wbcSetpwent(void)
393 {
394 return wbcCtxSetpwent(NULL);
395 }
396
397 /* Close the passwd iterator */
wbcCtxEndpwent(struct wbcContext * ctx)398 wbcErr wbcCtxEndpwent(struct wbcContext *ctx)
399 {
400 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
401
402 if (!ctx) {
403 ctx = wbcGetGlobalCtx();
404 }
405
406 if (ctx->pw_cache_size > 0) {
407 ctx->pw_cache_idx = ctx->pw_cache_size = 0;
408 winbindd_free_response(&pw_response);
409 }
410
411 wbc_status = wbcRequestResponse(ctx, WINBINDD_ENDPWENT,
412 NULL, NULL);
413 BAIL_ON_WBC_ERROR(wbc_status);
414
415 done:
416 return wbc_status;
417 }
418
wbcEndpwent(void)419 wbcErr wbcEndpwent(void)
420 {
421 return wbcCtxEndpwent(NULL);
422 }
423
424 /* Return the next struct passwd* entry from the pwent iterator */
wbcCtxGetpwent(struct wbcContext * ctx,struct passwd ** pwd)425 wbcErr wbcCtxGetpwent(struct wbcContext *ctx, struct passwd **pwd)
426 {
427 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
428 struct winbindd_request request;
429 struct winbindd_pw *wb_pw;
430
431 if (!ctx) {
432 ctx = wbcGetGlobalCtx();
433 }
434
435 /* If there's a cached result, return that. */
436 if (ctx->pw_cache_idx < ctx->pw_cache_size) {
437 goto return_result;
438 }
439
440 /* Otherwise, query winbindd for some entries. */
441
442 ctx->pw_cache_idx = 0;
443
444 winbindd_free_response(&pw_response);
445
446 ZERO_STRUCT(request);
447 request.data.num_entries = MAX_GETPWENT_USERS;
448
449 wbc_status = wbcRequestResponse(ctx, WINBINDD_GETPWENT, &request,
450 &pw_response);
451
452 BAIL_ON_WBC_ERROR(wbc_status);
453
454 ctx->pw_cache_size = pw_response.data.num_entries;
455
456 return_result:
457
458 wb_pw = (struct winbindd_pw *) pw_response.extra_data.data;
459
460 *pwd = copy_passwd_entry(&wb_pw[ctx->pw_cache_idx]);
461
462 BAIL_ON_PTR_ERROR(*pwd, wbc_status);
463
464 ctx->pw_cache_idx++;
465
466 done:
467 return wbc_status;
468 }
469
wbcGetpwent(struct passwd ** pwd)470 wbcErr wbcGetpwent(struct passwd **pwd)
471 {
472 return wbcCtxGetpwent(NULL, pwd);
473 }
474
475 /** @brief Winbindd response containing the group structs
476 *
477 */
478 static struct winbindd_response gr_response;
479
480 /* Reset the group iterator */
wbcCtxSetgrent(struct wbcContext * ctx)481 wbcErr wbcCtxSetgrent(struct wbcContext *ctx)
482 {
483 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
484
485 if (!ctx) {
486 ctx = wbcGetGlobalCtx();
487 }
488
489 if (ctx->gr_cache_size > 0) {
490 ctx->gr_cache_idx = ctx->gr_cache_size = 0;
491 winbindd_free_response(&gr_response);
492 }
493
494 ZERO_STRUCT(gr_response);
495
496 wbc_status = wbcRequestResponse(ctx, WINBINDD_SETGRENT,
497 NULL, NULL);
498 BAIL_ON_WBC_ERROR(wbc_status);
499
500 done:
501 return wbc_status;
502 }
503
wbcSetgrent(void)504 wbcErr wbcSetgrent(void)
505 {
506 return wbcCtxSetgrent(NULL);
507 }
508
509 /* Close the group iterator */
wbcCtxEndgrent(struct wbcContext * ctx)510 wbcErr wbcCtxEndgrent(struct wbcContext *ctx)
511 {
512 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
513
514 if (!ctx) {
515 ctx = wbcGetGlobalCtx();
516 }
517
518 if (ctx->gr_cache_size > 0) {
519 ctx->gr_cache_idx = ctx->gr_cache_size = 0;
520 winbindd_free_response(&gr_response);
521 }
522
523 wbc_status = wbcRequestResponse(ctx, WINBINDD_ENDGRENT,
524 NULL, NULL);
525 BAIL_ON_WBC_ERROR(wbc_status);
526
527 done:
528 return wbc_status;
529 }
530
wbcEndgrent(void)531 wbcErr wbcEndgrent(void)
532 {
533 return wbcCtxEndgrent(NULL);
534 }
535
536 /* Return the next struct group* entry from the pwent iterator */
wbcCtxGetgrent(struct wbcContext * ctx,struct group ** grp)537 wbcErr wbcCtxGetgrent(struct wbcContext *ctx, struct group **grp)
538 {
539 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
540 struct winbindd_request request;
541 struct winbindd_gr *wb_gr;
542 uint32_t mem_ofs;
543
544 if (!ctx) {
545 ctx = wbcGetGlobalCtx();
546 }
547
548 /* If there's a cached result, return that. */
549 if (ctx->gr_cache_idx < ctx->gr_cache_size) {
550 goto return_result;
551 }
552
553 /* Otherwise, query winbindd for some entries. */
554
555 ctx->gr_cache_idx = 0;
556
557 winbindd_free_response(&gr_response);
558
559 ZERO_STRUCT(request);
560 request.data.num_entries = MAX_GETGRENT_GROUPS;
561
562 wbc_status = wbcRequestResponse(ctx, WINBINDD_GETGRENT,
563 &request, &gr_response);
564
565 BAIL_ON_WBC_ERROR(wbc_status);
566
567 ctx->gr_cache_size = gr_response.data.num_entries;
568
569 return_result:
570
571 wb_gr = (struct winbindd_gr *) gr_response.extra_data.data;
572
573 mem_ofs = wb_gr[ctx->gr_cache_idx].gr_mem_ofs +
574 ctx->gr_cache_size * sizeof(struct winbindd_gr);
575
576 *grp = copy_group_entry(&wb_gr[ctx->gr_cache_idx],
577 ((char *)gr_response.extra_data.data)+mem_ofs);
578
579 BAIL_ON_PTR_ERROR(*grp, wbc_status);
580
581 ctx->gr_cache_idx++;
582
583 done:
584 return wbc_status;
585 }
586
wbcGetgrent(struct group ** grp)587 wbcErr wbcGetgrent(struct group **grp)
588 {
589 return wbcCtxGetgrent(NULL, grp);
590 }
591
592 /* Return the next struct group* entry from the pwent iterator */
wbcCtxGetgrlist(struct wbcContext * ctx,struct group ** grp)593 wbcErr wbcCtxGetgrlist(struct wbcContext *ctx, struct group **grp)
594 {
595 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
596 struct winbindd_request request;
597 struct winbindd_gr *wb_gr;
598
599 if (!ctx) {
600 ctx = wbcGetGlobalCtx();
601 }
602
603 /* If there's a cached result, return that. */
604 if (ctx->gr_cache_idx < ctx->gr_cache_size) {
605 goto return_result;
606 }
607
608 /* Otherwise, query winbindd for some entries. */
609
610 ctx->gr_cache_idx = 0;
611
612 winbindd_free_response(&gr_response);
613 ZERO_STRUCT(gr_response);
614
615 ZERO_STRUCT(request);
616 request.data.num_entries = MAX_GETGRENT_GROUPS;
617
618 wbc_status = wbcRequestResponse(ctx, WINBINDD_GETGRLST,
619 &request, &gr_response);
620
621 BAIL_ON_WBC_ERROR(wbc_status);
622
623 ctx->gr_cache_size = gr_response.data.num_entries;
624
625 return_result:
626
627 wb_gr = (struct winbindd_gr *) gr_response.extra_data.data;
628
629 *grp = copy_group_entry(&wb_gr[ctx->gr_cache_idx], NULL);
630
631 BAIL_ON_PTR_ERROR(*grp, wbc_status);
632
633 ctx->gr_cache_idx++;
634
635 done:
636 return wbc_status;
637 }
638
wbcGetgrlist(struct group ** grp)639 wbcErr wbcGetgrlist(struct group **grp)
640 {
641 return wbcCtxGetgrlist(NULL, grp);
642 }
643
644 /* Return the unix group array belonging to the given user */
wbcCtxGetGroups(struct wbcContext * ctx,const char * account,uint32_t * num_groups,gid_t ** _groups)645 wbcErr wbcCtxGetGroups(struct wbcContext *ctx, const char *account,
646 uint32_t *num_groups, gid_t **_groups)
647 {
648 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
649 struct winbindd_request request;
650 struct winbindd_response response;
651 uint32_t i;
652 gid_t *groups = NULL;
653
654 /* Initialize request */
655
656 ZERO_STRUCT(request);
657 ZERO_STRUCT(response);
658
659 if (!account) {
660 wbc_status = WBC_ERR_INVALID_PARAM;
661 BAIL_ON_WBC_ERROR(wbc_status);
662 }
663
664 /* Send request */
665
666 strncpy(request.data.username, account, sizeof(request.data.username)-1);
667
668 wbc_status = wbcRequestResponse(ctx, WINBINDD_GETGROUPS,
669 &request,
670 &response);
671 BAIL_ON_WBC_ERROR(wbc_status);
672
673 groups = (gid_t *)wbcAllocateMemory(
674 response.data.num_entries, sizeof(gid_t), NULL);
675 BAIL_ON_PTR_ERROR(groups, wbc_status);
676
677 for (i = 0; i < response.data.num_entries; i++) {
678 groups[i] = ((gid_t *)response.extra_data.data)[i];
679 }
680
681 *num_groups = response.data.num_entries;
682 *_groups = groups;
683 groups = NULL;
684
685 wbc_status = WBC_ERR_SUCCESS;
686
687 done:
688 winbindd_free_response(&response);
689 wbcFreeMemory(groups);
690 return wbc_status;
691 }
692
wbcGetGroups(const char * account,uint32_t * num_groups,gid_t ** _groups)693 wbcErr wbcGetGroups(const char *account, uint32_t *num_groups, gid_t **_groups)
694 {
695 return wbcCtxGetGroups(NULL, account, num_groups, _groups);
696 }
697