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