r19158: Remove root and nobody users from ldif, from Björn Jacke
[Samba/nascimento.git] / source3 / nsswitch / wb_client.c
blob77e2645b74331daea880a9d3bb2d518efbece974
1 /*
2 Unix SMB/CIFS implementation.
4 winbind client code
6 Copyright (C) Tim Potter 2000
7 Copyright (C) Andrew Tridgell 2000
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Library General Public
11 License as published by the Free Software Foundation; either
12 version 2 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 Library General Public
20 License along with this library; if not, write to the
21 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.
25 #include "includes.h"
26 #include "nsswitch/winbind_nss.h"
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_WINBIND
31 NSS_STATUS winbindd_request_response(int req_type,
32 struct winbindd_request *request,
33 struct winbindd_response *response);
35 /* Call winbindd to convert a name to a sid */
37 BOOL winbind_lookup_name(const char *dom_name, const char *name, DOM_SID *sid,
38 enum lsa_SidType *name_type)
40 struct winbindd_request request;
41 struct winbindd_response response;
42 NSS_STATUS result;
44 if (!sid || !name_type)
45 return False;
47 /* Send off request */
49 ZERO_STRUCT(request);
50 ZERO_STRUCT(response);
52 fstrcpy(request.data.name.dom_name, dom_name);
53 fstrcpy(request.data.name.name, name);
55 if ((result = winbindd_request_response(WINBINDD_LOOKUPNAME, &request,
56 &response)) == NSS_STATUS_SUCCESS) {
57 if (!string_to_sid(sid, response.data.sid.sid))
58 return False;
59 *name_type = (enum lsa_SidType)response.data.sid.type;
62 return result == NSS_STATUS_SUCCESS;
65 /* Call winbindd to convert sid to name */
67 BOOL winbind_lookup_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid,
68 const char **domain, const char **name,
69 enum lsa_SidType *name_type)
71 struct winbindd_request request;
72 struct winbindd_response response;
73 NSS_STATUS result;
75 /* Initialise request */
77 ZERO_STRUCT(request);
78 ZERO_STRUCT(response);
80 fstrcpy(request.data.sid, sid_string_static(sid));
82 /* Make request */
84 result = winbindd_request_response(WINBINDD_LOOKUPSID, &request,
85 &response);
87 if (result != NSS_STATUS_SUCCESS) {
88 return False;
91 /* Copy out result */
93 if (domain != NULL) {
94 *domain = talloc_strdup(mem_ctx, response.data.name.dom_name);
95 if (*domain == NULL) {
96 DEBUG(0, ("talloc failed\n"));
97 return False;
100 if (name != NULL) {
101 *name = talloc_strdup(mem_ctx, response.data.name.name);
102 if (*name == NULL) {
103 DEBUG(0, ("talloc failed\n"));
104 return False;
108 *name_type = (enum lsa_SidType)response.data.name.type;
110 DEBUG(10, ("winbind_lookup_sid: SUCCESS: SID %s -> %s %s\n",
111 sid_string_static(sid), response.data.name.dom_name,
112 response.data.name.name));
113 return True;
116 BOOL winbind_lookup_rids(TALLOC_CTX *mem_ctx,
117 const DOM_SID *domain_sid,
118 int num_rids, uint32 *rids,
119 const char **domain_name,
120 const char ***names, enum lsa_SidType **types)
122 size_t i, buflen;
123 ssize_t len;
124 char *ridlist;
125 char *p;
126 struct winbindd_request request;
127 struct winbindd_response response;
128 NSS_STATUS result;
130 if (num_rids == 0) {
131 return False;
134 /* Initialise request */
136 ZERO_STRUCT(request);
137 ZERO_STRUCT(response);
139 fstrcpy(request.data.sid, sid_string_static(domain_sid));
141 len = 0;
142 buflen = 0;
143 ridlist = NULL;
145 for (i=0; i<num_rids; i++) {
146 sprintf_append(mem_ctx, &ridlist, &len, &buflen,
147 "%ld\n", rids[i]);
150 if ((num_rids != 0) && (ridlist == NULL)) {
151 return False;
154 request.extra_data.data = ridlist;
155 request.extra_len = strlen(ridlist)+1;
157 result = winbindd_request_response(WINBINDD_LOOKUPRIDS,
158 &request, &response);
160 TALLOC_FREE(ridlist);
162 if (result != NSS_STATUS_SUCCESS) {
163 return False;
166 *domain_name = talloc_strdup(mem_ctx, response.data.domain_name);
168 *names = TALLOC_ARRAY(mem_ctx, const char *, num_rids);
169 *types = TALLOC_ARRAY(mem_ctx, enum lsa_SidType, num_rids);
171 if ((*names == NULL) || (*types == NULL)) {
172 goto fail;
175 p = (char *)response.extra_data.data;
177 for (i=0; i<num_rids; i++) {
178 char *q;
180 if (*p == '\0') {
181 DEBUG(10, ("Got invalid reply: %s\n",
182 (char *)response.extra_data.data));
183 goto fail;
186 (*types)[i] = (enum lsa_SidType)strtoul(p, &q, 10);
188 if (*q != ' ') {
189 DEBUG(10, ("Got invalid reply: %s\n",
190 (char *)response.extra_data.data));
191 goto fail;
194 p = q+1;
196 q = strchr(p, '\n');
197 if (q == NULL) {
198 DEBUG(10, ("Got invalid reply: %s\n",
199 (char *)response.extra_data.data));
200 goto fail;
203 *q = '\0';
205 (*names)[i] = talloc_strdup(*names, p);
207 p = q+1;
210 if (*p != '\0') {
211 DEBUG(10, ("Got invalid reply: %s\n",
212 (char *)response.extra_data.data));
213 goto fail;
216 SAFE_FREE(response.extra_data.data);
218 return True;
220 fail:
221 TALLOC_FREE(*names);
222 TALLOC_FREE(*types);
223 return False;
226 /* Call winbindd to convert SID to uid */
228 BOOL winbind_sid_to_uid(uid_t *puid, const DOM_SID *sid)
230 struct winbindd_request request;
231 struct winbindd_response response;
232 int result;
233 fstring sid_str;
235 if (!puid)
236 return False;
238 /* Initialise request */
240 ZERO_STRUCT(request);
241 ZERO_STRUCT(response);
243 sid_to_string(sid_str, sid);
244 fstrcpy(request.data.sid, sid_str);
246 /* Make request */
248 result = winbindd_request_response(WINBINDD_SID_TO_UID, &request, &response);
250 /* Copy out result */
252 if (result == NSS_STATUS_SUCCESS) {
253 *puid = response.data.uid;
256 return (result == NSS_STATUS_SUCCESS);
259 /* Call winbindd to convert uid to sid */
261 BOOL winbind_uid_to_sid(DOM_SID *sid, uid_t uid)
263 struct winbindd_request request;
264 struct winbindd_response response;
265 int result;
267 if (!sid)
268 return False;
270 /* Initialise request */
272 ZERO_STRUCT(request);
273 ZERO_STRUCT(response);
275 request.data.uid = uid;
277 /* Make request */
279 result = winbindd_request_response(WINBINDD_UID_TO_SID, &request, &response);
281 /* Copy out result */
283 if (result == NSS_STATUS_SUCCESS) {
284 if (!string_to_sid(sid, response.data.sid.sid))
285 return False;
286 } else {
287 sid_copy(sid, &global_sid_NULL);
290 return (result == NSS_STATUS_SUCCESS);
293 /* Call winbindd to convert SID to gid */
295 BOOL winbind_sid_to_gid(gid_t *pgid, const DOM_SID *sid)
297 struct winbindd_request request;
298 struct winbindd_response response;
299 int result;
300 fstring sid_str;
302 if (!pgid)
303 return False;
305 /* Initialise request */
307 ZERO_STRUCT(request);
308 ZERO_STRUCT(response);
310 sid_to_string(sid_str, sid);
311 fstrcpy(request.data.sid, sid_str);
313 /* Make request */
315 result = winbindd_request_response(WINBINDD_SID_TO_GID, &request, &response);
317 /* Copy out result */
319 if (result == NSS_STATUS_SUCCESS) {
320 *pgid = response.data.gid;
323 return (result == NSS_STATUS_SUCCESS);
326 /* Call winbindd to convert gid to sid */
328 BOOL winbind_gid_to_sid(DOM_SID *sid, gid_t gid)
330 struct winbindd_request request;
331 struct winbindd_response response;
332 int result;
334 if (!sid)
335 return False;
337 /* Initialise request */
339 ZERO_STRUCT(request);
340 ZERO_STRUCT(response);
342 request.data.gid = gid;
344 /* Make request */
346 result = winbindd_request_response(WINBINDD_GID_TO_SID, &request, &response);
348 /* Copy out result */
350 if (result == NSS_STATUS_SUCCESS) {
351 if (!string_to_sid(sid, response.data.sid.sid))
352 return False;
353 } else {
354 sid_copy(sid, &global_sid_NULL);
357 return (result == NSS_STATUS_SUCCESS);
360 BOOL winbind_allocate_uid(uid_t *uid)
362 struct winbindd_request request;
363 struct winbindd_response response;
364 int result;
366 /* Initialise request */
368 ZERO_STRUCT(request);
369 ZERO_STRUCT(response);
371 /* Make request */
373 result = winbindd_request_response(WINBINDD_ALLOCATE_UID,
374 &request, &response);
376 if (result != NSS_STATUS_SUCCESS)
377 return False;
379 /* Copy out result */
380 *uid = response.data.uid;
382 return True;
385 BOOL winbind_allocate_gid(gid_t *gid)
387 struct winbindd_request request;
388 struct winbindd_response response;
389 int result;
391 /* Initialise request */
393 ZERO_STRUCT(request);
394 ZERO_STRUCT(response);
396 /* Make request */
398 result = winbindd_request_response(WINBINDD_ALLOCATE_GID,
399 &request, &response);
401 if (result != NSS_STATUS_SUCCESS)
402 return False;
404 /* Copy out result */
405 *gid = response.data.gid;
407 return True;
410 /* Fetch the list of groups a user is a member of from winbindd. This is
411 used by winbind_getgroups. */
413 static int wb_getgroups(const char *user, gid_t **groups)
415 struct winbindd_request request;
416 struct winbindd_response response;
417 int result;
419 /* Call winbindd */
421 ZERO_STRUCT(request);
422 fstrcpy(request.data.username, user);
424 ZERO_STRUCT(response);
426 result = winbindd_request_response(WINBINDD_GETGROUPS, &request, &response);
428 if (result == NSS_STATUS_SUCCESS) {
430 /* Return group list. Don't forget to free the group list
431 when finished. */
433 *groups = (gid_t *)response.extra_data.data;
434 return response.data.num_entries;
437 return -1;
440 /* Call winbindd to initialise group membership. This is necessary for
441 some systems (i.e RH5.2) that do not have an initgroups function as part
442 of the nss extension. In RH5.2 this is implemented using getgrent()
443 which can be amazingly inefficient as well as having problems with
444 username case. */
446 int winbind_initgroups(char *user, gid_t gid)
448 gid_t *groups = NULL;
449 int result;
451 /* Call normal initgroups if we are a local user */
453 if (!strchr(user, *lp_winbind_separator())) {
454 return initgroups(user, gid);
457 result = wb_getgroups(user, &groups);
459 DEBUG(10,("winbind_getgroups: %s: result = %s\n", user,
460 result == -1 ? "FAIL" : "SUCCESS"));
462 if (result != -1) {
463 int ngroups = result, i;
464 BOOL is_member = False;
466 /* Check to see if the passed gid is already in the list */
468 for (i = 0; i < ngroups; i++) {
469 if (groups[i] == gid) {
470 is_member = True;
474 /* Add group to list if necessary */
476 if (!is_member) {
477 groups = SMB_REALLOC_ARRAY(groups, gid_t, ngroups + 1);
478 if (!groups) {
479 errno = ENOMEM;
480 result = -1;
481 goto done;
484 groups[ngroups] = gid;
485 ngroups++;
488 /* Set the groups */
490 if (sys_setgroups(ngroups, groups) == -1) {
491 errno = EPERM;
492 result = -1;
493 goto done;
496 } else {
498 /* The call failed. Set errno to something so we don't get
499 a bogus value from the last failed system call. */
501 errno = EIO;
504 /* Free response data if necessary */
506 done:
507 SAFE_FREE(groups);
509 return result;
512 /* Return a list of groups the user is a member of. This function is
513 useful for large systems where inverting the group database would be too
514 time consuming. If size is zero, list is not modified and the total
515 number of groups for the user is returned. */
517 int winbind_getgroups(const char *user, gid_t **list)
520 * Don't do the lookup if the name has no separator _and_ we are not in
521 * 'winbind use default domain' mode.
524 if (!(strchr(user, *lp_winbind_separator()) || lp_winbind_use_default_domain()))
525 return -1;
527 /* Fetch list of groups */
529 return wb_getgroups(user, list);
532 /**********************************************************************
533 simple wrapper function to see if winbindd is alive
534 **********************************************************************/
536 BOOL winbind_ping( void )
538 NSS_STATUS result;
540 result = winbindd_request_response(WINBINDD_PING, NULL, NULL);
542 return result == NSS_STATUS_SUCCESS;
545 /**********************************************************************
546 Is a domain trusted?
548 result == NSS_STATUS_UNAVAIL: winbind not around
549 result == NSS_STATUS_NOTFOUND: winbind around, but domain missing
551 Due to a bad API NSS_STATUS_NOTFOUND is returned both when winbind_off and
552 when winbind return WINBINDD_ERROR. So the semantics of this routine depends
553 on winbind_on. Grepping for winbind_off I just found 3 places where winbind
554 is turned off, and this does not conflict (as far as I have seen) with the
555 callers of is_trusted_domains.
557 I *hate* global variables....
559 Volker
561 **********************************************************************/
563 NSS_STATUS wb_is_trusted_domain(const char *domain)
565 struct winbindd_request request;
566 struct winbindd_response response;
568 /* Call winbindd */
570 ZERO_STRUCT(request);
571 ZERO_STRUCT(response);
573 fstrcpy(request.domain_name, domain);
575 return winbindd_request_response(WINBINDD_DOMAIN_INFO, &request, &response);