Move the doxygen comments of wbclient to the header file.
[abartlet/samba.git/.git] / source3 / 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 username */
194 wbcErr wbcGetgrnam(const char *name, struct group **grp)
195 {
196         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
197         struct winbindd_request request;
198         struct winbindd_response response;
199
200         /* Initialize request */
201
202         ZERO_STRUCT(request);
203         ZERO_STRUCT(response);
204
205         if (!name || !grp) {
206                 wbc_status = WBC_ERR_INVALID_PARAM;
207                 BAIL_ON_WBC_ERROR(wbc_status);
208         }
209
210         /* dst is already null terminated from the memset above */
211
212         strncpy(request.data.groupname, name, sizeof(request.data.groupname)-1);
213
214         wbc_status = wbcRequestResponse(WINBINDD_GETGRNAM,
215                                         &request,
216                                         &response);
217         BAIL_ON_WBC_ERROR(wbc_status);
218
219         *grp = copy_group_entry(&response.data.gr,
220                                 (char*)response.extra_data.data);
221         BAIL_ON_PTR_ERROR(*grp, wbc_status);
222
223  done:
224         if (response.extra_data.data)
225                 free(response.extra_data.data);
226
227         return wbc_status;
228 }
229
230 /* Fill in a struct passwd* for a domain user based on uid */
231 wbcErr wbcGetgrgid(gid_t gid, struct group **grp)
232 {
233         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
234         struct winbindd_request request;
235         struct winbindd_response response;
236
237         /* Initialize request */
238
239         ZERO_STRUCT(request);
240         ZERO_STRUCT(response);
241
242         if (!grp) {
243                 wbc_status = WBC_ERR_INVALID_PARAM;
244                 BAIL_ON_WBC_ERROR(wbc_status);
245         }
246
247         request.data.gid = gid;
248
249         wbc_status = wbcRequestResponse(WINBINDD_GETGRGID,
250                                         &request,
251                                         &response);
252         BAIL_ON_WBC_ERROR(wbc_status);
253
254         *grp = copy_group_entry(&response.data.gr,
255                                 (char*)response.extra_data.data);
256         BAIL_ON_PTR_ERROR(*grp, wbc_status);
257
258  done:
259         if (response.extra_data.data)
260                 free(response.extra_data.data);
261
262         return wbc_status;
263 }
264
265 /** @brief Number of cached passwd structs
266  *
267  */
268 static uint32_t pw_cache_size;
269
270 /** @brief Position of the pwent context
271  *
272  */
273 static uint32_t pw_cache_idx;
274
275 /** @brief Winbindd response containing the passwd structs
276  *
277  */
278 static struct winbindd_response pw_response;
279
280 /* Reset the passwd iterator */
281 wbcErr wbcSetpwent(void)
282 {
283         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
284
285         if (pw_cache_size > 0) {
286                 pw_cache_idx = pw_cache_size = 0;
287                 if (pw_response.extra_data.data) {
288                         free(pw_response.extra_data.data);
289                 }
290         }
291
292         ZERO_STRUCT(pw_response);
293
294         wbc_status = wbcRequestResponse(WINBINDD_SETPWENT,
295                                         NULL, NULL);
296         BAIL_ON_WBC_ERROR(wbc_status);
297
298  done:
299         return wbc_status;
300 }
301
302 /* Close the passwd iterator */
303 wbcErr wbcEndpwent(void)
304 {
305         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
306
307         if (pw_cache_size > 0) {
308                 pw_cache_idx = pw_cache_size = 0;
309                 if (pw_response.extra_data.data) {
310                         free(pw_response.extra_data.data);
311                 }
312         }
313
314         wbc_status = wbcRequestResponse(WINBINDD_ENDPWENT,
315                                         NULL, NULL);
316         BAIL_ON_WBC_ERROR(wbc_status);
317
318  done:
319         return wbc_status;
320 }
321
322 /* Return the next struct passwd* entry from the pwent iterator */
323 wbcErr wbcGetpwent(struct passwd **pwd)
324 {
325         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
326         struct winbindd_request request;
327         struct winbindd_pw *wb_pw;
328
329         /* If there's a cached result, return that. */
330         if (pw_cache_idx < pw_cache_size) {
331                 goto return_result;
332         }
333
334         /* Otherwise, query winbindd for some entries. */
335
336         pw_cache_idx = 0;
337
338         if (pw_response.extra_data.data) {
339                 free(pw_response.extra_data.data);
340                 ZERO_STRUCT(pw_response);
341         }
342
343         ZERO_STRUCT(request);
344         request.data.num_entries = MAX_GETPWENT_USERS;
345
346         wbc_status = wbcRequestResponse(WINBINDD_GETPWENT, &request,
347                                         &pw_response);
348
349         BAIL_ON_WBC_ERROR(wbc_status);
350
351         pw_cache_size = pw_response.data.num_entries;
352
353 return_result:
354
355         wb_pw = (struct winbindd_pw *) pw_response.extra_data.data;
356
357         *pwd = copy_passwd_entry(&wb_pw[pw_cache_idx]);
358
359         BAIL_ON_PTR_ERROR(*pwd, wbc_status);
360
361         pw_cache_idx++;
362
363 done:
364         return wbc_status;
365 }
366
367 /** @brief Number of cached group structs
368  *
369  */
370 static uint32_t gr_cache_size;
371
372 /** @brief Position of the grent context
373  *
374  */
375 static uint32_t gr_cache_idx;
376
377 /** @brief Winbindd response containing the group structs
378  *
379  */
380 static struct winbindd_response gr_response;
381
382 /* Reset the group iterator */
383 wbcErr wbcSetgrent(void)
384 {
385         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
386
387         if (gr_cache_size > 0) {
388                 gr_cache_idx = gr_cache_size = 0;
389                 if (gr_response.extra_data.data) {
390                         free(gr_response.extra_data.data);
391                 }
392         }
393
394         ZERO_STRUCT(gr_response);
395
396         wbc_status = wbcRequestResponse(WINBINDD_SETGRENT,
397                                         NULL, NULL);
398         BAIL_ON_WBC_ERROR(wbc_status);
399
400  done:
401         return wbc_status;
402 }
403
404 /* Close the group iterator */
405 wbcErr wbcEndgrent(void)
406 {
407         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
408
409         if (gr_cache_size > 0) {
410                 gr_cache_idx = gr_cache_size = 0;
411                 if (gr_response.extra_data.data) {
412                         free(gr_response.extra_data.data);
413                 }
414         }
415
416         wbc_status = wbcRequestResponse(WINBINDD_ENDGRENT,
417                                         NULL, NULL);
418         BAIL_ON_WBC_ERROR(wbc_status);
419
420  done:
421         return wbc_status;
422 }
423
424 /* Return the next struct group* entry from the pwent iterator */
425 wbcErr wbcGetgrent(struct group **grp)
426 {
427         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
428         struct winbindd_request request;
429         struct winbindd_gr *wb_gr;
430         uint32_t mem_ofs;
431
432         /* If there's a cached result, return that. */
433         if (gr_cache_idx < gr_cache_size) {
434                 goto return_result;
435         }
436
437         /* Otherwise, query winbindd for some entries. */
438
439         gr_cache_idx = 0;
440
441         if (gr_response.extra_data.data) {
442                 free(gr_response.extra_data.data);
443                 ZERO_STRUCT(gr_response);
444         }
445
446         ZERO_STRUCT(request);
447         request.data.num_entries = MAX_GETGRENT_GROUPS;
448
449         wbc_status = wbcRequestResponse(WINBINDD_GETGRENT, &request,
450                                         &gr_response);
451
452         BAIL_ON_WBC_ERROR(wbc_status);
453
454         gr_cache_size = gr_response.data.num_entries;
455
456 return_result:
457
458         wb_gr = (struct winbindd_gr *) gr_response.extra_data.data;
459
460         mem_ofs = wb_gr[gr_cache_idx].gr_mem_ofs +
461                   gr_cache_size * sizeof(struct winbindd_gr);
462
463         *grp = copy_group_entry(&wb_gr[gr_cache_idx],
464                                 ((char *)gr_response.extra_data.data)+mem_ofs);
465
466         BAIL_ON_PTR_ERROR(*grp, wbc_status);
467
468         gr_cache_idx++;
469
470 done:
471         return wbc_status;
472 }
473
474 /* Return the next struct group* entry from the pwent iterator */
475 wbcErr wbcGetgrlist(struct group **grp)
476 {
477         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
478         struct winbindd_request request;
479         struct winbindd_gr *wb_gr;
480
481         /* If there's a cached result, return that. */
482         if (gr_cache_idx < gr_cache_size) {
483                 goto return_result;
484         }
485
486         /* Otherwise, query winbindd for some entries. */
487
488         gr_cache_idx = 0;
489
490         if (gr_response.extra_data.data) {
491                 free(gr_response.extra_data.data);
492                 ZERO_STRUCT(gr_response);
493         }
494
495         ZERO_STRUCT(request);
496         request.data.num_entries = MAX_GETGRENT_GROUPS;
497
498         wbc_status = wbcRequestResponse(WINBINDD_GETGRLST, &request,
499                                         &gr_response);
500
501         BAIL_ON_WBC_ERROR(wbc_status);
502
503         gr_cache_size = gr_response.data.num_entries;
504
505 return_result:
506
507         wb_gr = (struct winbindd_gr *) gr_response.extra_data.data;
508
509         *grp = copy_group_entry(&wb_gr[gr_cache_idx], NULL);
510
511         BAIL_ON_PTR_ERROR(*grp, wbc_status);
512
513         gr_cache_idx++;
514
515 done:
516         return wbc_status;
517 }
518
519 /* Return the unix group array belonging to the given user */
520 wbcErr wbcGetGroups(const char *account,
521                     uint32_t *num_groups,
522                     gid_t **_groups)
523 {
524         wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
525         struct winbindd_request request;
526         struct winbindd_response response;
527         uint32_t i;
528         gid_t *groups = NULL;
529
530         /* Initialize request */
531
532         ZERO_STRUCT(request);
533         ZERO_STRUCT(response);
534
535         if (!account) {
536                 wbc_status = WBC_ERR_INVALID_PARAM;
537                 BAIL_ON_WBC_ERROR(wbc_status);
538         }
539
540         /* Send request */
541
542         strncpy(request.data.username, account, sizeof(request.data.username)-1);
543
544         wbc_status = wbcRequestResponse(WINBINDD_GETGROUPS,
545                                         &request,
546                                         &response);
547         BAIL_ON_WBC_ERROR(wbc_status);
548
549         groups = talloc_array(NULL, gid_t, response.data.num_entries);
550         BAIL_ON_PTR_ERROR(groups, wbc_status);
551
552         for (i = 0; i < response.data.num_entries; i++) {
553                 groups[i] = ((gid_t *)response.extra_data.data)[i];
554         }
555
556         *num_groups = response.data.num_entries;
557         *_groups = groups;
558         groups = NULL;
559
560         wbc_status = WBC_ERR_SUCCESS;
561
562  done:
563         if (response.extra_data.data) {
564                 free(response.extra_data.data);
565         }
566         if (groups) {
567                 talloc_free(groups);
568         }
569
570         return wbc_status;
571 }