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:
parent
2d41ca7198
commit
53dfaac5fb
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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",
|
||||
|
Loading…
x
Reference in New Issue
Block a user