diff options
author | Andrew Tridgell <tridge@samba.org> | 2003-11-19 08:11:14 +0000 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2003-11-19 08:11:14 +0000 |
commit | 53dfaac5fbaa137700ccc304f9f90e0b0d15e631 (patch) | |
tree | 075141fc59d616303b9762850760473c6314a71a /source3/nsswitch | |
parent | 2d41ca7198a5a490c45a08953d16df86f36724de (diff) | |
download | samba-53dfaac5fbaa137700ccc304f9f90e0b0d15e631.tar.gz samba-53dfaac5fbaa137700ccc304f9f90e0b0d15e631.tar.bz2 samba-53dfaac5fbaa137700ccc304f9f90e0b0d15e631.zip |
as discussed on irc, this is a small patch that allows a few more
winbind functions to be accessed via NSS. This provides a much cleaner
way for applications that need (for example) to provide name->sid
mappings to do this via NSS rather than having to know the winbindd
pipe protocol (as this might change).
This patch also adds a varient of the winbindd_getgroups() call called
winbindd_getusersids() that provides direct SID->SIDs listing of a
users supplementary groups. This is enough to allow non-Samba
applications to do ACL checking.
A test program for the new functionality will be committed shortly.
I also added the 'wbinfo --user-sids' option to expose the new
function in wbinfo.
(This used to be commit 702b35da0ac7c73aa5a6603f871d865565bbe278)
Diffstat (limited to 'source3/nsswitch')
-rw-r--r-- | source3/nsswitch/wbinfo.c | 42 | ||||
-rw-r--r-- | source3/nsswitch/winbind_nss_linux.c | 149 | ||||
-rw-r--r-- | source3/nsswitch/winbindd.c | 1 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_group.c | 85 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_nss.h | 3 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_sid.c | 19 |
6 files changed, 292 insertions, 7 deletions
diff --git a/source3/nsswitch/wbinfo.c b/source3/nsswitch/wbinfo.c index 04233bb85c..1256ec3a3b 100644 --- a/source3/nsswitch/wbinfo.c +++ b/source3/nsswitch/wbinfo.c @@ -136,6 +136,37 @@ static BOOL wbinfo_get_usergroups(char *user) return True; } + +/* List group SIDs a user SID is a member of */ +static BOOL wbinfo_get_usersids(char *user_sid) +{ + struct winbindd_request request; + struct winbindd_response response; + NSS_STATUS result; + int i; + const char *s; + + ZERO_STRUCT(response); + + /* Send request */ + fstrcpy(request.data.sid, user_sid); + + result = winbindd_request(WINBINDD_GETUSERSIDS, &request, &response); + + if (result != NSS_STATUS_SUCCESS) + return False; + + s = response.extra_data; + for (i = 0; i < response.data.num_entries; i++) { + d_printf("%s\n", s); + s += strlen(s) + 1; + } + + SAFE_FREE(response.extra_data); + + return True; +} + /* Convert NetBIOS name to IP */ static BOOL wbinfo_wins_byname(char *name) @@ -884,7 +915,8 @@ enum { OPT_SET_AUTH_USER = 1000, OPT_GET_AUTH_USER, OPT_DOMAIN_NAME, - OPT_SEQUENCE + OPT_SEQUENCE, + OPT_USERSIDS }; int main(int argc, char **argv) @@ -923,6 +955,7 @@ int main(int argc, char **argv) { "trusted-domains", 'm', POPT_ARG_NONE, 0, 'm', "List trusted domains" }, { "sequence", 0, POPT_ARG_NONE, 0, OPT_SEQUENCE, "Show sequence numbers of all domains" }, { "user-groups", 'r', POPT_ARG_STRING, &string_arg, 'r', "Get user groups", "USER" }, + { "user-sids", 0, POPT_ARG_STRING, &string_arg, OPT_USERSIDS, "Get user group sids for user SID", "SID" }, { "authenticate", 'a', POPT_ARG_STRING, &string_arg, 'a', "authenticate user", "user%password" }, { "set-auth-user", 0, POPT_ARG_STRING, &string_arg, OPT_SET_AUTH_USER, "Store user and password used by winbindd (root only)", "user%password" }, { "get-auth-user", 0, POPT_ARG_NONE, NULL, OPT_GET_AUTH_USER, "Retrieve user and password used by winbindd (root only)", NULL }, @@ -1055,6 +1088,13 @@ int main(int argc, char **argv) goto done; } break; + case OPT_USERSIDS: + if (!wbinfo_get_usersids(string_arg)) { + d_printf("Could not get group SIDs for user SID %s\n", + string_arg); + goto done; + } + break; case 'a': { BOOL got_error = False; diff --git a/source3/nsswitch/winbind_nss_linux.c b/source3/nsswitch/winbind_nss_linux.c index 125bc8ccda..ac4a861ff1 100644 --- a/source3/nsswitch/winbind_nss_linux.c +++ b/source3/nsswitch/winbind_nss_linux.c @@ -860,3 +860,152 @@ _nss_winbind_initgroups_dyn(char *user, gid_t group, long int *start, done: return ret; } + + +/* return a list of group SIDs for a user SID */ +NSS_STATUS +_nss_winbind_getusersids(const char *user_sid, char **group_sids, + int *num_groups, + char *buffer, size_t buf_size, int *errnop) +{ + NSS_STATUS ret; + struct winbindd_request request; + struct winbindd_response response; + +#ifdef DEBUG_NSS + fprintf(stderr, "[%5d]: getusersids %s\n", getpid(), user_sid); +#endif + + ZERO_STRUCT(request); + ZERO_STRUCT(response); + + strncpy(request.data.sid, user_sid,sizeof(request.data.sid) - 1); + request.data.sid[sizeof(request.data.sid) - 1] = '\0'; + + ret = winbindd_request(WINBINDD_GETUSERSIDS, &request, &response); + + if (ret != NSS_STATUS_SUCCESS) { + goto done; + } + + if (buf_size < response.length - sizeof(response)) { + ret = NSS_STATUS_TRYAGAIN; + errno = *errnop = ERANGE; + goto done; + } + + *num_groups = response.data.num_entries; + *group_sids = buffer; + memcpy(buffer, response.extra_data, response.length - sizeof(response)); + errno = *errnop = 0; + + done: + free_response(&response); + return ret; +} + + +/* map a user or group name to a SID string */ +NSS_STATUS +_nss_winbind_nametosid(const char *name, char **sid, char *buffer, + size_t buflen, int *errnop) +{ + NSS_STATUS ret; + struct winbindd_response response; + struct winbindd_request request; + +#ifdef DEBUG_NSS + fprintf(stderr, "[%5d]: nametosid %s\n", getpid(), name); +#endif + + ZERO_STRUCT(response); + ZERO_STRUCT(request); + + strncpy(request.data.name.name, name, + sizeof(request.data.name.name) - 1); + request.data.name.name[sizeof(request.data.name.name) - 1] = '\0'; + + ret = winbindd_request(WINBINDD_LOOKUPNAME, &request, &response); + if (ret != NSS_STATUS_SUCCESS) { + *errnop = errno = EINVAL; + goto failed; + } + + if (buflen < strlen(response.data.sid.sid)+1) { + ret = NSS_STATUS_TRYAGAIN; + *errnop = errno = ERANGE; + goto failed; + } + + *errnop = errno = 0; + *sid = buffer; + strcpy(*sid, response.data.sid.sid); + +failed: + free_response(&response); + return ret; +} + +/* map a sid string to a user or group name */ +NSS_STATUS +_nss_winbind_sidtoname(const char *sid, char **name, char *buffer, + size_t buflen, int *errnop) +{ + NSS_STATUS ret; + struct winbindd_response response; + struct winbindd_request request; + static char sep_char; + unsigned needed; + +#ifdef DEBUG_NSS + fprintf(stderr, "[%5d]: sidtoname %s\n", getpid(), sid); +#endif + + /* we need to fetch the separator first time through */ + if (!sep_char) { + ZERO_STRUCT(response); + ZERO_STRUCT(request); + + ret = winbindd_request(WINBINDD_INFO, &request, &response); + if (ret != NSS_STATUS_SUCCESS) { + *errnop = errno = EINVAL; + goto failed; + } + + sep_char = response.data.info.winbind_separator; + free_response(&response); + } + + + strncpy(request.data.sid, sid, + sizeof(request.data.sid) - 1); + request.data.sid[sizeof(request.data.sid) - 1] = '\0'; + + ret = winbindd_request(WINBINDD_LOOKUPSID, &request, &response); + if (ret != NSS_STATUS_SUCCESS) { + *errnop = errno = EINVAL; + goto failed; + } + + needed = + strlen(response.data.name.dom_name) + + strlen(response.data.name.name) + 2; + + if (buflen < needed) { + ret = NSS_STATUS_TRYAGAIN; + *errnop = errno = ERANGE; + goto failed; + } + + snprintf(buffer, needed, "%s%c%s", + response.data.name.dom_name, + sep_char, + response.data.name.name); + + *name = buffer; + *errnop = errno = 0; + +failed: + free_response(&response); + return ret; +} diff --git a/source3/nsswitch/winbindd.c b/source3/nsswitch/winbindd.c index d8e233a3a8..bf83867e81 100644 --- a/source3/nsswitch/winbindd.c +++ b/source3/nsswitch/winbindd.c @@ -221,6 +221,7 @@ static struct dispatch_table dispatch_table[] = { { WINBINDD_GETPWENT, winbindd_getpwent, "GETPWENT" }, { WINBINDD_GETGROUPS, winbindd_getgroups, "GETGROUPS" }, + { WINBINDD_GETUSERSIDS, winbindd_getusersids, "GETUSERSIDS" }, /* Group functions */ diff --git a/source3/nsswitch/winbindd_group.c b/source3/nsswitch/winbindd_group.c index d951b3433e..15bdc11036 100644 --- a/source3/nsswitch/winbindd_group.c +++ b/source3/nsswitch/winbindd_group.c @@ -1082,3 +1082,88 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state) return result; } + + +/* Get user supplementary sids. This is equivalent to the + winbindd_getgroups() function but it involves a SID->SIDs mapping + rather than a NAME->SID->SIDS->GIDS mapping, which means we avoid + idmap. This call is designed to be used with applications that need + to do ACL evaluation themselves. Note that the cached info3 data is + not used + + this function assumes that the SID that comes in is a user SID. If + you pass in another type of SID then you may get unpredictable + results. +*/ +enum winbindd_result winbindd_getusersids(struct winbindd_cli_state *state) +{ + DOM_SID user_sid; + NTSTATUS status; + DOM_SID **user_grpsids; + struct winbindd_domain *domain; + enum winbindd_result result = WINBINDD_ERROR; + unsigned int i; + TALLOC_CTX *mem_ctx; + char *ret; + uint32 num_groups; + unsigned ofs, ret_size = 0; + + /* Ensure null termination */ + state->request.data.sid[sizeof(state->request.data.sid)-1]='\0'; + + if (!string_to_sid(&user_sid, state->request.data.sid)) { + DEBUG(1, ("Could not get convert sid %s from string\n", state->request.data.sid)); + return WINBINDD_ERROR; + } + + if (!(mem_ctx = talloc_init("winbindd_getusersids(%s)", + state->request.data.username))) { + return WINBINDD_ERROR; + } + + /* Get info for the domain */ + if ((domain = find_domain_from_sid(&user_sid)) == NULL) { + DEBUG(0,("could not find domain entry for sid %s\n", + sid_string_static(&user_sid))); + goto done; + } + + status = domain->methods->lookup_usergroups(domain, mem_ctx, + &user_sid, &num_groups, + &user_grpsids); + if (!NT_STATUS_IS_OK(status)) + goto done; + + if (num_groups == 0) { + goto no_groups; + } + + /* work out the response size */ + for (i = 0; i < num_groups; i++) { + const char *s = sid_string_static(user_grpsids[i]); + ret_size += strlen(s) + 1; + } + + /* build the reply */ + ret = malloc(ret_size); + if (!ret) goto done; + ofs = 0; + for (i = 0; i < num_groups; i++) { + const char *s = sid_string_static(user_grpsids[i]); + safe_strcpy(ret + ofs, s, ret_size - ofs); + ofs += strlen(ret+ofs) + 1; + } + +no_groups: + /* Send data back to client */ + state->response.data.num_entries = num_groups; + state->response.extra_data = ret; + state->response.length += ret_size; + result = WINBINDD_OK; + + done: + talloc_destroy(mem_ctx); + + return result; +} + diff --git a/source3/nsswitch/winbindd_nss.h b/source3/nsswitch/winbindd_nss.h index 41fecd2816..76243c57ef 100644 --- a/source3/nsswitch/winbindd_nss.h +++ b/source3/nsswitch/winbindd_nss.h @@ -118,6 +118,9 @@ enum winbindd_cmd { /* find the location of our privileged pipe */ WINBINDD_PRIV_PIPE_DIR, + /* return a list of group sids for a user sid */ + WINBINDD_GETUSERSIDS, + WINBINDD_NUM_CMDS }; diff --git a/source3/nsswitch/winbindd_sid.c b/source3/nsswitch/winbindd_sid.c index 6400a23b7b..7c4c8d804a 100644 --- a/source3/nsswitch/winbindd_sid.c +++ b/source3/nsswitch/winbindd_sid.c @@ -84,6 +84,7 @@ enum winbindd_result winbindd_lookupname(struct winbindd_cli_state *state) char *name_domain, *name_user; DOM_SID sid; struct winbindd_domain *domain; + char *p; /* Ensure null termination */ state->request.data.sid[sizeof(state->request.data.name.dom_name)-1]='\0'; @@ -91,13 +92,19 @@ enum winbindd_result winbindd_lookupname(struct winbindd_cli_state *state) /* Ensure null termination */ state->request.data.sid[sizeof(state->request.data.name.name)-1]='\0'; - DEBUG(3, ("[%5lu]: lookupname %s%s%s\n", (unsigned long)state->pid, - state->request.data.name.dom_name, - lp_winbind_separator(), - state->request.data.name.name)); + /* cope with the name being a fully qualified name */ + p = strstr(state->request.data.name.name, lp_winbind_separator()); + if (p) { + *p = 0; + name_domain = state->request.data.name.name; + name_user = p+1; + } else { + name_domain = state->request.data.name.dom_name; + name_user = state->request.data.name.name; + } - name_domain = state->request.data.name.dom_name; - name_user = state->request.data.name.name; + DEBUG(3, ("[%5lu]: lookupname %s%s%s\n", (unsigned long)state->pid, + name_domain, lp_winbind_separator(), name_user)); if ((domain = find_domain_from_name(name_domain)) == NULL) { DEBUG(0, ("could not find domain entry for domain %s\n", |