s3 swat: Allow getting the user's HTTP auth password
[Samba.git] / nsswitch / libwbclient / wbc_pwd.c
blobdacd9499dd4ab459e23469ccaa84fea6764cf4cc
1 /*
2 Unix SMB/CIFS implementation.
4 Winbind client API
6 Copyright (C) Gerald (Jerry) Carter 2007
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.
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.
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/>.
23 /* Required Headers */
25 #include "libwbclient.h"
27 /** @brief The maximum number of pwent structs to get from winbindd
30 #define MAX_GETPWENT_USERS 500
32 /** @brief The maximum number of grent structs to get from winbindd
35 #define MAX_GETGRENT_GROUPS 500
37 /**
39 **/
41 static struct passwd *copy_passwd_entry(struct winbindd_pw *p)
43 struct passwd *pwd = NULL;
44 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
46 pwd = talloc(NULL, struct passwd);
47 BAIL_ON_PTR_ERROR(pwd, wbc_status);
49 pwd->pw_name = talloc_strdup(pwd,p->pw_name);
50 BAIL_ON_PTR_ERROR(pwd->pw_name, wbc_status);
52 pwd->pw_passwd = talloc_strdup(pwd, p->pw_passwd);
53 BAIL_ON_PTR_ERROR(pwd->pw_passwd, wbc_status);
55 pwd->pw_gecos = talloc_strdup(pwd, p->pw_gecos);
56 BAIL_ON_PTR_ERROR(pwd->pw_gecos, wbc_status);
58 pwd->pw_shell = talloc_strdup(pwd, p->pw_shell);
59 BAIL_ON_PTR_ERROR(pwd->pw_shell, wbc_status);
61 pwd->pw_dir = talloc_strdup(pwd, p->pw_dir);
62 BAIL_ON_PTR_ERROR(pwd->pw_dir, wbc_status);
64 pwd->pw_uid = p->pw_uid;
65 pwd->pw_gid = p->pw_gid;
67 done:
68 if (!WBC_ERROR_IS_OK(wbc_status)) {
69 talloc_free(pwd);
70 pwd = NULL;
73 return pwd;
76 /**
78 **/
80 static struct group *copy_group_entry(struct winbindd_gr *g,
81 char *mem_buf)
83 struct group *grp = NULL;
84 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
85 int i;
86 char *mem_p, *mem_q;
88 grp = talloc(NULL, struct group);
89 BAIL_ON_PTR_ERROR(grp, wbc_status);
91 grp->gr_name = talloc_strdup(grp, g->gr_name);
92 BAIL_ON_PTR_ERROR(grp->gr_name, wbc_status);
94 grp->gr_passwd = talloc_strdup(grp, g->gr_passwd);
95 BAIL_ON_PTR_ERROR(grp->gr_passwd, wbc_status);
97 grp->gr_gid = g->gr_gid;
99 grp->gr_mem = talloc_array(grp, char*, g->num_gr_mem+1);
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';
107 grp->gr_mem[i] = talloc_strdup(grp, mem_p);
108 BAIL_ON_PTR_ERROR(grp->gr_mem[i], wbc_status);
110 if (mem_q == NULL) {
111 i += 1;
112 break;
114 mem_p = mem_q + 1;
116 grp->gr_mem[i] = NULL;
118 wbc_status = WBC_ERR_SUCCESS;
120 done:
121 if (!WBC_ERROR_IS_OK(wbc_status)) {
122 talloc_free(grp);
123 grp = NULL;
126 return grp;
129 /* Fill in a struct passwd* for a domain user based on username */
130 wbcErr wbcGetpwnam(const char *name, struct passwd **pwd)
132 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
133 struct winbindd_request request;
134 struct winbindd_response response;
136 if (!name || !pwd) {
137 wbc_status = WBC_ERR_INVALID_PARAM;
138 BAIL_ON_WBC_ERROR(wbc_status);
141 /* Initialize request */
143 ZERO_STRUCT(request);
144 ZERO_STRUCT(response);
146 /* dst is already null terminated from the memset above */
148 strncpy(request.data.username, name, sizeof(request.data.username)-1);
150 wbc_status = wbcRequestResponse(WINBINDD_GETPWNAM,
151 &request,
152 &response);
153 BAIL_ON_WBC_ERROR(wbc_status);
155 *pwd = copy_passwd_entry(&response.data.pw);
156 BAIL_ON_PTR_ERROR(*pwd, wbc_status);
158 done:
159 return wbc_status;
162 /* Fill in a struct passwd* for a domain user based on uid */
163 wbcErr wbcGetpwuid(uid_t uid, struct passwd **pwd)
165 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
166 struct winbindd_request request;
167 struct winbindd_response response;
169 if (!pwd) {
170 wbc_status = WBC_ERR_INVALID_PARAM;
171 BAIL_ON_WBC_ERROR(wbc_status);
174 /* Initialize request */
176 ZERO_STRUCT(request);
177 ZERO_STRUCT(response);
179 request.data.uid = uid;
181 wbc_status = wbcRequestResponse(WINBINDD_GETPWUID,
182 &request,
183 &response);
184 BAIL_ON_WBC_ERROR(wbc_status);
186 *pwd = copy_passwd_entry(&response.data.pw);
187 BAIL_ON_PTR_ERROR(*pwd, wbc_status);
189 done:
190 return wbc_status;
193 /* Fill in a struct passwd* for a domain user based on sid */
194 wbcErr wbcGetpwsid(struct wbcDomainSid *sid, struct passwd **pwd)
196 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
197 struct winbindd_request request;
198 struct winbindd_response response;
199 char * sid_string = NULL;
201 if (!pwd) {
202 wbc_status = WBC_ERR_INVALID_PARAM;
203 BAIL_ON_WBC_ERROR(wbc_status);
206 wbc_status = wbcSidToString(sid, &sid_string);
207 BAIL_ON_WBC_ERROR(wbc_status);
209 /* Initialize request */
211 ZERO_STRUCT(request);
212 ZERO_STRUCT(response);
214 strncpy(request.data.sid, sid_string, sizeof(request.data.sid));
216 wbc_status = wbcRequestResponse(WINBINDD_GETPWSID,
217 &request,
218 &response);
219 BAIL_ON_WBC_ERROR(wbc_status);
221 *pwd = copy_passwd_entry(&response.data.pw);
222 BAIL_ON_PTR_ERROR(*pwd, wbc_status);
224 done:
225 if (sid_string) {
226 wbcFreeMemory(sid_string);
229 return wbc_status;
232 /* Fill in a struct passwd* for a domain user based on username */
233 wbcErr wbcGetgrnam(const char *name, struct group **grp)
235 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
236 struct winbindd_request request;
237 struct winbindd_response response;
239 /* Initialize request */
241 ZERO_STRUCT(request);
242 ZERO_STRUCT(response);
244 if (!name || !grp) {
245 wbc_status = WBC_ERR_INVALID_PARAM;
246 BAIL_ON_WBC_ERROR(wbc_status);
249 /* dst is already null terminated from the memset above */
251 strncpy(request.data.groupname, name, sizeof(request.data.groupname)-1);
253 wbc_status = wbcRequestResponse(WINBINDD_GETGRNAM,
254 &request,
255 &response);
256 BAIL_ON_WBC_ERROR(wbc_status);
258 *grp = copy_group_entry(&response.data.gr,
259 (char*)response.extra_data.data);
260 BAIL_ON_PTR_ERROR(*grp, wbc_status);
262 done:
263 if (response.extra_data.data)
264 free(response.extra_data.data);
266 return wbc_status;
269 /* Fill in a struct passwd* for a domain user based on uid */
270 wbcErr wbcGetgrgid(gid_t gid, struct group **grp)
272 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
273 struct winbindd_request request;
274 struct winbindd_response response;
276 /* Initialize request */
278 ZERO_STRUCT(request);
279 ZERO_STRUCT(response);
281 if (!grp) {
282 wbc_status = WBC_ERR_INVALID_PARAM;
283 BAIL_ON_WBC_ERROR(wbc_status);
286 request.data.gid = gid;
288 wbc_status = wbcRequestResponse(WINBINDD_GETGRGID,
289 &request,
290 &response);
291 BAIL_ON_WBC_ERROR(wbc_status);
293 *grp = copy_group_entry(&response.data.gr,
294 (char*)response.extra_data.data);
295 BAIL_ON_PTR_ERROR(*grp, wbc_status);
297 done:
298 if (response.extra_data.data)
299 free(response.extra_data.data);
301 return wbc_status;
304 /** @brief Number of cached passwd structs
307 static uint32_t pw_cache_size;
309 /** @brief Position of the pwent context
312 static uint32_t pw_cache_idx;
314 /** @brief Winbindd response containing the passwd structs
317 static struct winbindd_response pw_response;
319 /* Reset the passwd iterator */
320 wbcErr wbcSetpwent(void)
322 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
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);
331 ZERO_STRUCT(pw_response);
333 wbc_status = wbcRequestResponse(WINBINDD_SETPWENT,
334 NULL, NULL);
335 BAIL_ON_WBC_ERROR(wbc_status);
337 done:
338 return wbc_status;
341 /* Close the passwd iterator */
342 wbcErr wbcEndpwent(void)
344 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
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);
353 wbc_status = wbcRequestResponse(WINBINDD_ENDPWENT,
354 NULL, NULL);
355 BAIL_ON_WBC_ERROR(wbc_status);
357 done:
358 return wbc_status;
361 /* Return the next struct passwd* entry from the pwent iterator */
362 wbcErr wbcGetpwent(struct passwd **pwd)
364 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
365 struct winbindd_request request;
366 struct winbindd_pw *wb_pw;
368 /* If there's a cached result, return that. */
369 if (pw_cache_idx < pw_cache_size) {
370 goto return_result;
373 /* Otherwise, query winbindd for some entries. */
375 pw_cache_idx = 0;
377 if (pw_response.extra_data.data) {
378 free(pw_response.extra_data.data);
379 ZERO_STRUCT(pw_response);
382 ZERO_STRUCT(request);
383 request.data.num_entries = MAX_GETPWENT_USERS;
385 wbc_status = wbcRequestResponse(WINBINDD_GETPWENT, &request,
386 &pw_response);
388 BAIL_ON_WBC_ERROR(wbc_status);
390 pw_cache_size = pw_response.data.num_entries;
392 return_result:
394 wb_pw = (struct winbindd_pw *) pw_response.extra_data.data;
396 *pwd = copy_passwd_entry(&wb_pw[pw_cache_idx]);
398 BAIL_ON_PTR_ERROR(*pwd, wbc_status);
400 pw_cache_idx++;
402 done:
403 return wbc_status;
406 /** @brief Number of cached group structs
409 static uint32_t gr_cache_size;
411 /** @brief Position of the grent context
414 static uint32_t gr_cache_idx;
416 /** @brief Winbindd response containing the group structs
419 static struct winbindd_response gr_response;
421 /* Reset the group iterator */
422 wbcErr wbcSetgrent(void)
424 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
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);
433 ZERO_STRUCT(gr_response);
435 wbc_status = wbcRequestResponse(WINBINDD_SETGRENT,
436 NULL, NULL);
437 BAIL_ON_WBC_ERROR(wbc_status);
439 done:
440 return wbc_status;
443 /* Close the group iterator */
444 wbcErr wbcEndgrent(void)
446 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
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);
455 wbc_status = wbcRequestResponse(WINBINDD_ENDGRENT,
456 NULL, NULL);
457 BAIL_ON_WBC_ERROR(wbc_status);
459 done:
460 return wbc_status;
463 /* Return the next struct group* entry from the pwent iterator */
464 wbcErr wbcGetgrent(struct group **grp)
466 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
467 struct winbindd_request request;
468 struct winbindd_gr *wb_gr;
469 uint32_t mem_ofs;
471 /* If there's a cached result, return that. */
472 if (gr_cache_idx < gr_cache_size) {
473 goto return_result;
476 /* Otherwise, query winbindd for some entries. */
478 gr_cache_idx = 0;
480 if (gr_response.extra_data.data) {
481 free(gr_response.extra_data.data);
482 ZERO_STRUCT(gr_response);
485 ZERO_STRUCT(request);
486 request.data.num_entries = MAX_GETGRENT_GROUPS;
488 wbc_status = wbcRequestResponse(WINBINDD_GETGRENT, &request,
489 &gr_response);
491 BAIL_ON_WBC_ERROR(wbc_status);
493 gr_cache_size = gr_response.data.num_entries;
495 return_result:
497 wb_gr = (struct winbindd_gr *) gr_response.extra_data.data;
499 mem_ofs = wb_gr[gr_cache_idx].gr_mem_ofs +
500 gr_cache_size * sizeof(struct winbindd_gr);
502 *grp = copy_group_entry(&wb_gr[gr_cache_idx],
503 ((char *)gr_response.extra_data.data)+mem_ofs);
505 BAIL_ON_PTR_ERROR(*grp, wbc_status);
507 gr_cache_idx++;
509 done:
510 return wbc_status;
513 /* Return the next struct group* entry from the pwent iterator */
514 wbcErr wbcGetgrlist(struct group **grp)
516 wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
517 struct winbindd_request request;
518 struct winbindd_gr *wb_gr;
520 /* If there's a cached result, return that. */
521 if (gr_cache_idx < gr_cache_size) {
522 goto return_result;
525 /* Otherwise, query winbindd for some entries. */
527 gr_cache_idx = 0;
529 if (gr_response.extra_data.data) {
530 free(gr_response.extra_data.data);
531 ZERO_STRUCT(gr_response);
534 ZERO_STRUCT(request);
535 request.data.num_entries = MAX_GETGRENT_GROUPS;
537 wbc_status = wbcRequestResponse(WINBINDD_GETGRLST, &request,
538 &gr_response);
540 BAIL_ON_WBC_ERROR(wbc_status);
542 gr_cache_size = gr_response.data.num_entries;
544 return_result:
546 wb_gr = (struct winbindd_gr *) gr_response.extra_data.data;
548 *grp = copy_group_entry(&wb_gr[gr_cache_idx], NULL);
550 BAIL_ON_PTR_ERROR(*grp, wbc_status);
552 gr_cache_idx++;
554 done:
555 return wbc_status;
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)
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;
569 /* Initialize request */
571 ZERO_STRUCT(request);
572 ZERO_STRUCT(response);
574 if (!account) {
575 wbc_status = WBC_ERR_INVALID_PARAM;
576 BAIL_ON_WBC_ERROR(wbc_status);
579 /* Send request */
581 strncpy(request.data.username, account, sizeof(request.data.username)-1);
583 wbc_status = wbcRequestResponse(WINBINDD_GETGROUPS,
584 &request,
585 &response);
586 BAIL_ON_WBC_ERROR(wbc_status);
588 groups = talloc_array(NULL, gid_t, response.data.num_entries);
589 BAIL_ON_PTR_ERROR(groups, wbc_status);
591 for (i = 0; i < response.data.num_entries; i++) {
592 groups[i] = ((gid_t *)response.extra_data.data)[i];
595 *num_groups = response.data.num_entries;
596 *_groups = groups;
597 groups = NULL;
599 wbc_status = WBC_ERR_SUCCESS;
601 done:
602 if (response.extra_data.data) {
603 free(response.extra_data.data);
605 if (groups) {
606 talloc_free(groups);
609 return wbc_status;