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