winbindd: winbindd_ccache_ntlm_auth() -> bool_dispatch_table
[samba.git] / nsswitch / libwbclient / wbc_pwd.c
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
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
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
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
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 */
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
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 */
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
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 */
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
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 */
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
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 */
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
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 */
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
392 wbcErr wbcSetpwent(void)
393 {
394         return wbcCtxSetpwent(NULL);
395 }
396
397 /* Close the passwd iterator */
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
419 wbcErr wbcEndpwent(void)
420 {
421         return wbcCtxEndpwent(NULL);
422 }
423
424 /* Return the next struct passwd* entry from the pwent iterator */
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
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 */
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
504 wbcErr wbcSetgrent(void)
505 {
506         return wbcCtxSetgrent(NULL);
507 }
508
509 /* Close the group iterator */
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
531 wbcErr wbcEndgrent(void)
532 {
533         return wbcCtxEndgrent(NULL);
534 }
535
536 /* Return the next struct group* entry from the pwent iterator */
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
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 */
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
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 */
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
693 wbcErr wbcGetGroups(const char *account, uint32_t *num_groups, gid_t **_groups)
694 {
695         return wbcCtxGetGroups(NULL, account, num_groups, _groups);
696 }