1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-29 02:50:28 +03:00

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)
This commit is contained in:
Andrew Tridgell 2003-11-19 08:11:14 +00:00
parent 2d41ca7198
commit 53dfaac5fb
6 changed files with 292 additions and 7 deletions

View File

@ -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;

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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
};

View File

@ -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",