2 Unix SMB/CIFS implementation.
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.
26 #include "nsswitch/winbind_nss.h"
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 SID_NAME_USE *name_type)
40 struct winbindd_request request;
41 struct winbindd_response response;
44 if (!sid || !name_type)
47 /* Send off 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))
59 *name_type = (enum SID_NAME_USE)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 SID_NAME_USE *name_type)
71 struct winbindd_request request;
72 struct winbindd_response response;
75 /* Initialise request */
78 ZERO_STRUCT(response);
80 fstrcpy(request.data.sid, sid_string_static(sid));
84 result = winbindd_request_response(WINBINDD_LOOKUPSID, &request,
87 if (result != NSS_STATUS_SUCCESS) {
94 *domain = talloc_strdup(mem_ctx, response.data.name.dom_name);
95 if (*domain == NULL) {
96 DEBUG(0, ("talloc failed\n"));
101 *name = talloc_strdup(mem_ctx, response.data.name.name);
103 DEBUG(0, ("talloc failed\n"));
108 *name_type = (enum SID_NAME_USE)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));
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 SID_NAME_USE **types)
126 struct winbindd_request request;
127 struct winbindd_response response;
134 /* Initialise request */
136 ZERO_STRUCT(request);
137 ZERO_STRUCT(response);
139 fstrcpy(request.data.sid, sid_string_static(domain_sid));
145 for (i=0; i<num_rids; i++) {
146 sprintf_append(mem_ctx, &ridlist, &len, &buflen,
150 if ((num_rids != 0) && (ridlist == NULL)) {
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) {
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 SID_NAME_USE, num_rids);
171 if ((*names == NULL) || (*types == NULL)) {
175 p = response.extra_data.data;
177 for (i=0; i<num_rids; i++) {
181 DEBUG(10, ("Got invalid reply: %s\n",
182 (char *)response.extra_data.data));
186 (*types)[i] = (enum SID_NAME_USE)strtoul(p, &q, 10);
189 DEBUG(10, ("Got invalid reply: %s\n",
190 (char *)response.extra_data.data));
198 DEBUG(10, ("Got invalid reply: %s\n",
199 (char *)response.extra_data.data));
205 (*names)[i] = talloc_strdup(*names, p);
211 DEBUG(10, ("Got invalid reply: %s\n",
212 (char *)response.extra_data.data));
216 SAFE_FREE(response.extra_data.data);
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;
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);
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;
270 /* Initialise request */
272 ZERO_STRUCT(request);
273 ZERO_STRUCT(response);
275 request.data.uid = uid;
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))
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;
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);
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;
337 /* Initialise request */
339 ZERO_STRUCT(request);
340 ZERO_STRUCT(response);
342 request.data.gid = gid;
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))
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;
366 /* Initialise request */
368 ZERO_STRUCT(request);
369 ZERO_STRUCT(response);
373 result = winbindd_request_response(WINBINDD_ALLOCATE_UID,
374 &request, &response);
376 if (result != NSS_STATUS_SUCCESS)
379 /* Copy out result */
380 *uid = response.data.uid;
385 BOOL winbind_allocate_gid(gid_t *gid)
387 struct winbindd_request request;
388 struct winbindd_response response;
391 /* Initialise request */
393 ZERO_STRUCT(request);
394 ZERO_STRUCT(response);
398 result = winbindd_request_response(WINBINDD_ALLOCATE_GID,
399 &request, &response);
401 if (result != NSS_STATUS_SUCCESS)
404 /* Copy out result */
405 *gid = response.data.gid;
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;
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
433 *groups = (gid_t *)response.extra_data.data;
434 return response.data.num_entries;
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
446 int winbind_initgroups(char *user, gid_t gid)
448 gid_t *groups = NULL;
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"));
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) {
474 /* Add group to list if necessary */
477 groups = SMB_REALLOC_ARRAY(groups, gid_t, ngroups + 1);
484 groups[ngroups] = gid;
490 if (sys_setgroups(ngroups, groups) == -1) {
498 /* The call failed. Set errno to something so we don't get
499 a bogus value from the last failed system call. */
504 /* Free response data if necessary */
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()))
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 )
540 result = winbindd_request_response(WINBINDD_PING, NULL, NULL);
542 return result == NSS_STATUS_SUCCESS;
545 /**********************************************************************
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....
561 **********************************************************************/
563 NSS_STATUS wb_is_trusted_domain(const char *domain)
565 struct winbindd_request request;
566 struct winbindd_response response;
570 ZERO_STRUCT(request);
571 ZERO_STRUCT(response);
573 fstrcpy(request.domain_name, domain);
575 return winbindd_request_response(WINBINDD_DOMAIN_INFO, &request, &response);