s3: piddir creation fix part 2.
[ira/wip.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         /* if the array was partly created this can be NULL */
104         if (gr->gr_mem == NULL) {
105                 return;
106         }
107
108         for (i=0; gr->gr_mem[i] != NULL; i++) {
109                 free(gr->gr_mem[i]);
110         }
111         free(gr->gr_mem);
112 }
113
114 static struct group *copy_group_entry(struct winbindd_gr *g,
115                                       char *mem_buf)
116 {
117         struct group *gr = NULL;
118         int i;
119         char *mem_p, *mem_q;
120
121         gr = (struct group *)wbcAllocateMemory(
122                 1, sizeof(struct group), wbcGroupDestructor);
123         if (gr == NULL) {
124                 return NULL;
125         }
126
127         gr->gr_name = strdup(g->gr_name);
128         if (gr->gr_name == NULL) {
129                 goto fail;
130         }
131         gr->gr_passwd = strdup(g->gr_passwd);
132         if (gr->gr_passwd == NULL) {
133                 goto fail;
134         }
135         gr->gr_gid = g->gr_gid;
136
137         gr->gr_mem = (char **)calloc(g->num_gr_mem+1, sizeof(char *));
138         if (gr->gr_mem == NULL) {
139                 goto fail;
140         }
141
142         mem_p = mem_q = mem_buf;
143         for (i=0; i<g->num_gr_mem && mem_p; i++) {
144                 mem_q = strchr(mem_p, ',');
145                 if (mem_q != NULL) {
146                         *mem_q = '\0';
147                 }
148
149                 gr->gr_mem[i] = strdup(mem_p);
150                 if (gr->gr_mem[i] == NULL) {
151                         goto fail;
152                 }
153
154                 if (mem_q == NULL) {
155                         i += 1;
156                         break;
157                 }
158                 mem_p = mem_q + 1;
159         }
160         gr->gr_mem[i] = NULL;
161
162         return gr;
163
164 fail:
165         wbcFreeMemory(gr);
166         return NULL;
167 }
168
169 /* Fill in a struct passwd* for a domain user based on username */
170 wbcErr wbcGetpwnam(const char *name, struct passwd **pwd)
171 {
172         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
173         struct winbindd_request request;
174         struct winbindd_response response;
175
176         if (!name || !pwd) {
177                 wbc_status = WBC_ERR_INVALID_PARAM;
178                 BAIL_ON_WBC_ERROR(wbc_status);
179         }
180
181         /* Initialize request */
182
183         ZERO_STRUCT(request);
184         ZERO_STRUCT(response);
185
186         /* dst is already null terminated from the memset above */
187
188         strncpy(request.data.username, name, sizeof(request.data.username)-1);
189
190         wbc_status = wbcRequestResponse(WINBINDD_GETPWNAM,
191                                         &request,
192                                         &response);
193         BAIL_ON_WBC_ERROR(wbc_status);
194
195         *pwd = copy_passwd_entry(&response.data.pw);
196         BAIL_ON_PTR_ERROR(*pwd, wbc_status);
197
198  done:
199         return wbc_status;
200 }
201
202 /* Fill in a struct passwd* for a domain user based on uid */
203 wbcErr wbcGetpwuid(uid_t uid, struct passwd **pwd)
204 {
205         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
206         struct winbindd_request request;
207         struct winbindd_response response;
208
209         if (!pwd) {
210                 wbc_status = WBC_ERR_INVALID_PARAM;
211                 BAIL_ON_WBC_ERROR(wbc_status);
212         }
213
214         /* Initialize request */
215
216         ZERO_STRUCT(request);
217         ZERO_STRUCT(response);
218
219         request.data.uid = uid;
220
221         wbc_status = wbcRequestResponse(WINBINDD_GETPWUID,
222                                         &request,
223                                         &response);
224         BAIL_ON_WBC_ERROR(wbc_status);
225
226         *pwd = copy_passwd_entry(&response.data.pw);
227         BAIL_ON_PTR_ERROR(*pwd, wbc_status);
228
229  done:
230         return wbc_status;
231 }
232
233 /* Fill in a struct passwd* for a domain user based on sid */
234 wbcErr wbcGetpwsid(struct wbcDomainSid *sid, struct passwd **pwd)
235 {
236         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
237         struct winbindd_request request;
238         struct winbindd_response response;
239
240         if (!pwd) {
241                 wbc_status = WBC_ERR_INVALID_PARAM;
242                 BAIL_ON_WBC_ERROR(wbc_status);
243         }
244
245         /* Initialize request */
246
247         ZERO_STRUCT(request);
248         ZERO_STRUCT(response);
249
250         wbcSidToStringBuf(sid, request.data.sid, sizeof(request.data.sid));
251
252         wbc_status = wbcRequestResponse(WINBINDD_GETPWSID,
253                                         &request,
254                                         &response);
255         BAIL_ON_WBC_ERROR(wbc_status);
256
257         *pwd = copy_passwd_entry(&response.data.pw);
258         BAIL_ON_PTR_ERROR(*pwd, wbc_status);
259
260  done:
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 = (gid_t *)wbcAllocateMemory(
603                 response.data.num_entries, sizeof(gid_t), NULL);
604         BAIL_ON_PTR_ERROR(groups, wbc_status);
605
606         for (i = 0; i < response.data.num_entries; i++) {
607                 groups[i] = ((gid_t *)response.extra_data.data)[i];
608         }
609
610         *num_groups = response.data.num_entries;
611         *_groups = groups;
612         groups = NULL;
613
614         wbc_status = WBC_ERR_SUCCESS;
615
616  done:
617         winbindd_free_response(&response);
618         wbcFreeMemory(groups);
619         return wbc_status;
620 }