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