summaryrefslogtreecommitdiff
path: root/source3/nsswitch/winbindd_user.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/nsswitch/winbindd_user.c')
-rw-r--r--source3/nsswitch/winbindd_user.c384
1 files changed, 246 insertions, 138 deletions
diff --git a/source3/nsswitch/winbindd_user.c b/source3/nsswitch/winbindd_user.c
index 7a9b5cf96a..d192793993 100644
--- a/source3/nsswitch/winbindd_user.c
+++ b/source3/nsswitch/winbindd_user.c
@@ -106,174 +106,295 @@ static BOOL winbindd_fill_pwent(char *dom_name, char *user_name,
return True;
}
-/* Return a password structure from a username. */
+/* Wrapper for domain->methods->query_user, only on the parent->child pipe */
-enum winbindd_result winbindd_getpwnam(struct winbindd_cli_state *state)
+enum winbindd_result winbindd_dual_userinfo(struct winbindd_domain *domain,
+ struct winbindd_cli_state *state)
{
+ DOM_SID sid;
WINBIND_USERINFO user_info;
- DOM_SID user_sid;
NTSTATUS status;
- fstring name_domain, name_user;
- enum SID_NAME_USE name_type;
- struct winbindd_domain *domain;
- TALLOC_CTX *mem_ctx;
-
+
/* Ensure null termination */
- state->request.data.username[sizeof(state->request.data.username)-1]='\0';
+ state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
- DEBUG(3, ("[%5lu]: getpwnam %s\n", (unsigned long)state->pid,
- state->request.data.username));
-
- /* Parse domain and username */
+ DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid,
+ state->request.data.sid));
- parse_domain_user(state->request.data.username,
- name_domain, name_user);
-
- /* should we deal with users for our domain? */
-
- if ((domain = find_domain_from_name(name_domain)) == NULL) {
- DEBUG(5, ("no such domain: %s\n", name_domain));
+ if (!string_to_sid(&sid, state->request.data.sid)) {
+ DEBUG(5, ("%s not a SID\n", state->request.data.sid));
return WINBINDD_ERROR;
}
-
- if ( domain->primary && lp_winbind_trusted_domains_only()) {
- DEBUG(7,("winbindd_getpwnam: My domain -- rejecting getpwnam() for %s\\%s.\n",
- name_domain, name_user));
- return WINBINDD_ERROR;
- }
-
- /* Get rid and name type from name */
- if (!winbindd_lookup_sid_by_name(domain, domain->name, name_user, &user_sid, &name_type)) {
- DEBUG(1, ("user '%s' does not exist\n", name_user));
+ status = domain->methods->query_user(domain, state->mem_ctx,
+ &sid, &user_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("error getting user info for sid %s\n",
+ sid_string_static(&sid)));
return WINBINDD_ERROR;
}
- if (name_type != SID_NAME_USER && name_type != SID_NAME_COMPUTER) {
- DEBUG(1, ("name '%s' is not a user name: %d\n", name_user,
- name_type));
- return WINBINDD_ERROR;
- }
-
- /* Get some user info. */
-
- if (!(mem_ctx = talloc_init("winbindd_getpwnam([%s]\\[%s])",
- name_domain, name_user))) {
- DEBUG(1, ("out of memory\n"));
+ fstrcpy(state->response.data.user_info.acct_name, user_info.acct_name);
+ fstrcpy(state->response.data.user_info.full_name, user_info.full_name);
+ if (!sid_peek_check_rid(&domain->sid, &user_info.group_sid,
+ &state->response.data.user_info.group_rid)) {
+ DEBUG(1, ("Could not extract group rid out of %s\n",
+ sid_string_static(&sid)));
return WINBINDD_ERROR;
}
- status = domain->methods->query_user(domain, mem_ctx, &user_sid,
- &user_info);
+ return WINBINDD_OK;
+}
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("error getting user info for user '[%s]\\[%s]'\n",
- name_domain, name_user));
- talloc_destroy(mem_ctx);
- return WINBINDD_ERROR;
+struct getpwsid_state {
+ struct winbindd_cli_state *state;
+ struct winbindd_domain *domain;
+ char *username;
+ char *fullname;
+ DOM_SID user_sid;
+ uid_t uid;
+ DOM_SID group_sid;
+ gid_t gid;
+};
+
+static void getpwsid_queryuser_recv(void *private, BOOL success,
+ const char *acct_name,
+ const char *full_name, uint32 group_rid);
+static void getpwsid_sid2uid_recv(void *private, BOOL success, uid_t uid);
+static void getpwsid_sid2gid_recv(void *private, BOOL success, gid_t gid);
+
+static void winbindd_getpwsid(struct winbindd_cli_state *state,
+ const DOM_SID *sid)
+{
+ struct getpwsid_state *s;
+
+ s = TALLOC_P(state->mem_ctx, struct getpwsid_state);
+ if (s == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ goto error;
}
-
- /* Now take all this information and fill in a passwd structure */
- if (!winbindd_fill_pwent(name_domain, user_info.acct_name,
- user_info.user_sid, user_info.group_sid,
- user_info.full_name,
- &state->response.data.pw)) {
- talloc_destroy(mem_ctx);
- return WINBINDD_ERROR;
+
+ s->state = state;
+ s->domain = find_domain_from_sid_noinit(sid);
+ if (s->domain == NULL) {
+ DEBUG(3, ("Could not find domain for sid %s\n",
+ sid_string_static(sid)));
+ goto error;
}
- talloc_destroy(mem_ctx);
+ sid_copy(&s->user_sid, sid);
+
+ query_user_async(s->state->mem_ctx, s->domain, sid,
+ getpwsid_queryuser_recv, s);
+ return;
+
+ error:
+ s->state->response.result = WINBINDD_ERROR;
+ request_finished(state);
+}
- return WINBINDD_OK;
-}
+static void getpwsid_queryuser_recv(void *private, BOOL success,
+ const char *acct_name,
+ const char *full_name, uint32 group_rid)
+{
+ struct getpwsid_state *s =
+ talloc_get_type_abort(private, struct getpwsid_state);
+
+ if (!success) {
+ DEBUG(5, ("Could not query user %s\\%s\n", s->domain->name,
+ s->username));
+ s->state->response.result = WINBINDD_ERROR;
+ request_finished(s->state);
+ return;
+ }
-/* Return a password structure given a uid number */
+ s->username = talloc_strdup(s->state->mem_ctx, acct_name);
+ s->fullname = talloc_strdup(s->state->mem_ctx, full_name);
+ sid_copy(&s->group_sid, &s->domain->sid);
+ sid_append_rid(&s->group_sid, group_rid);
-enum winbindd_result winbindd_getpwuid(struct winbindd_cli_state *state)
+ winbindd_sid2uid_async(s->state->mem_ctx, &s->user_sid,
+ getpwsid_sid2uid_recv, s);
+}
+
+static void getpwsid_sid2uid_recv(void *private, BOOL success, uid_t uid)
{
- DOM_SID user_sid;
- struct winbindd_domain *domain;
- fstring dom_name;
- fstring user_name;
- enum SID_NAME_USE name_type;
- WINBIND_USERINFO user_info;
- TALLOC_CTX *mem_ctx;
- NTSTATUS status;
- gid_t gid;
-
- /* Bug out if the uid isn't in the winbind range */
+ struct getpwsid_state *s =
+ talloc_get_type_abort(private, struct getpwsid_state);
+
+ if (!success) {
+ DEBUG(5, ("Could not query user's %s\\%s uid\n",
+ s->domain->name, s->username));
+ s->state->response.result = WINBINDD_ERROR;
+ request_finished(s->state);
+ return;
+ }
- if ((state->request.data.uid < server_state.uid_low ) ||
- (state->request.data.uid > server_state.uid_high))
- return WINBINDD_ERROR;
+ s->uid = uid;
+ winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid,
+ getpwsid_sid2gid_recv, s);
+}
- DEBUG(3, ("[%5lu]: getpwuid %lu\n", (unsigned long)state->pid,
- (unsigned long)state->request.data.uid));
+static void getpwsid_sid2gid_recv(void *private, BOOL success, gid_t gid)
+{
+ struct getpwsid_state *s =
+ talloc_get_type_abort(private, struct getpwsid_state);
+ struct winbindd_pw *pw;
+ fstring output_username;
+ char *homedir;
+ char *shell;
- /* Get rid from uid */
+ s->state->response.result = WINBINDD_ERROR;
- if (!NT_STATUS_IS_OK(idmap_uid_to_sid(&user_sid, state->request.data.uid))) {
- DEBUG(1, ("could not convert uid %lu to SID\n",
- (unsigned long)state->request.data.uid));
- return WINBINDD_ERROR;
+ if (!success) {
+ DEBUG(5, ("Could not query user's %s\\%s\n gid",
+ s->domain->name, s->username));
+ goto done;
}
+
+ s->gid = gid;
+
+ pw = &s->state->response.data.pw;
+ pw->pw_uid = s->uid;
+ pw->pw_gid = s->gid;
+ fill_domain_username(output_username, s->domain->name, s->username);
+ safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1);
+ safe_strcpy(pw->pw_gecos, s->fullname, sizeof(pw->pw_gecos) - 1);
+
+ /* Home directory and shell - use template config parameters. The
+ defaults are /tmp for the home directory and /bin/false for
+ shell. */
- /* Get name and name type from rid */
+ /* The substitution of %U and %D in the 'template homedir' is done
+ by alloc_sub_specified() below. */
- if (!winbindd_lookup_name_by_sid(&user_sid, dom_name, user_name, &name_type)) {
- fstring temp;
-
- sid_to_string(temp, &user_sid);
- DEBUG(1, ("could not lookup sid %s\n", temp));
- return WINBINDD_ERROR;
+ fstrcpy(current_user_info.domain, s->domain->name);
+
+ homedir = alloc_sub_specified(lp_template_homedir(), s->username,
+ s->domain->name, pw->pw_uid, pw->pw_gid);
+ if (homedir == NULL) {
+ DEBUG(5, ("Could not compose homedir\n"));
+ goto done;
}
+ safe_strcpy(pw->pw_dir, homedir, sizeof(pw->pw_dir) - 1);
+ SAFE_FREE(homedir);
- domain = find_domain_from_sid(&user_sid);
+ shell = alloc_sub_specified(lp_template_shell(), s->username,
+ s->domain->name, pw->pw_uid, pw->pw_gid);
+ if (shell == NULL) {
+ DEBUG(5, ("Could not compose shell\n"));
+ goto done;
+ }
+ safe_strcpy(pw->pw_shell, shell, sizeof(pw->pw_shell) - 1);
+ SAFE_FREE(shell);
+
+ /* Password - set to "x" as we can't generate anything useful here.
+ Authentication can be done using the pam_winbind module. */
+
+ safe_strcpy(pw->pw_passwd, "x", sizeof(pw->pw_passwd) - 1);
+
+ s->state->response.result = WINBINDD_OK;
+
+ done:
+ request_finished(s->state);
+}
- if (!domain) {
- DEBUG(1,("Can't find domain from sid\n"));
+/* Return a password structure from a username. */
+
+static void getpwnam_name2sid_recv(void *private, BOOL success,
+ const DOM_SID *sid, enum SID_NAME_USE type);
+
+enum winbindd_result winbindd_getpwnam(struct winbindd_cli_state *state)
+{
+ struct winbindd_domain *domain;
+ fstring domname, username;
+
+ /* Ensure null termination */
+ state->request.data.username[sizeof(state->request.data.username)-1]='\0';
+
+ DEBUG(3, ("[%5lu]: getpwnam %s\n", (unsigned long)state->pid,
+ state->request.data.username));
+
+ if (!parse_domain_user(state->request.data.username, domname,
+ username)) {
+ DEBUG(0, ("Could not parse domain user: %s\n",
+ state->request.data.username));
return WINBINDD_ERROR;
}
-
- /* Get some user info */
- if (!(mem_ctx = talloc_init("winbind_getpwuid(%lu)",
- (unsigned long)state->request.data.uid))) {
+ /* Get info for the domain */
- DEBUG(1, ("out of memory\n"));
+ domain = find_lookup_domain_from_name(domname);
+
+ if (domain == NULL) {
+ DEBUG(7, ("could not find domain entry for domain %s\n",
+ domname));
return WINBINDD_ERROR;
}
- status = domain->methods->query_user(domain, mem_ctx, &user_sid,
- &user_info);
-
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("error getting user info for user '%s'\n",
- user_name));
- talloc_destroy(mem_ctx);
+ if ( domain->primary && lp_winbind_trusted_domains_only()) {
+ DEBUG(7,("winbindd_getpwnam: My domain -- rejecting "
+ "getgroups() for %s\\%s.\n", domname, username));
return WINBINDD_ERROR;
+ }
+
+ /* Get rid and name type from name. The following costs 1 packet */
+
+ winbindd_lookupname_async(state->mem_ctx, domname, username,
+ getpwnam_name2sid_recv, state);
+ return WINBINDD_PENDING;
+}
+
+static void getpwnam_name2sid_recv(void *private, BOOL success,
+ const DOM_SID *sid, enum SID_NAME_USE type)
+{
+ struct winbindd_cli_state *state = private;
+
+ if (!success) {
+ DEBUG(5, ("Could not lookup name for user %s\n",
+ state->request.data.username));
+ state->response.result = WINBINDD_ERROR;
+ request_finished(state);
+ return;
+ }
+
+ if ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER)) {
+ DEBUG(5, ("%s is not a user\n", state->request.data.username));
+ state->response.result = WINBINDD_ERROR;
+ request_finished(state);
+ return;
}
+
+ winbindd_getpwsid(state, sid);
+}
+
+/* Return a password structure given a uid number */
+
+enum winbindd_result winbindd_getpwuid(struct winbindd_cli_state *state)
+{
+ DOM_SID user_sid;
+ NTSTATUS status;
- /* Check group has a gid number */
+ /* Bug out if the uid isn't in the winbind range */
- if (!NT_STATUS_IS_OK(idmap_sid_to_gid(user_info.group_sid, &gid, 0))) {
- DEBUG(1, ("error getting group id for user %s\n", user_name));
- talloc_destroy(mem_ctx);
+ if ((state->request.data.uid < server_state.uid_low ) ||
+ (state->request.data.uid > server_state.uid_high))
return WINBINDD_ERROR;
- }
- /* Fill in password structure */
+ DEBUG(3, ("[%5lu]: getpwuid %lu\n", (unsigned long)state->pid,
+ (unsigned long)state->request.data.uid));
- if (!winbindd_fill_pwent(domain->name, user_info.acct_name, user_info.user_sid,
- user_info.group_sid,
- user_info.full_name, &state->response.data.pw)) {
- talloc_destroy(mem_ctx);
+ status = idmap_uid_to_sid(&user_sid, state->request.data.uid,
+ ID_QUERY_ONLY | ID_CACHE_ONLY);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5, ("Could not find SID for uid %lu\n",
+ (unsigned long)state->request.data.uid));
return WINBINDD_ERROR;
}
-
- talloc_destroy(mem_ctx);
- return WINBINDD_OK;
+ winbindd_getpwsid(state, &user_sid);
+ return WINBINDD_PENDING;
}
/*
@@ -365,14 +486,13 @@ enum winbindd_result winbindd_endpwent(struct winbindd_cli_state *state)
field is incremented to the index of the next user to fetch. Return True if
some users were returned, False otherwise. */
-static BOOL get_sam_user_entries(struct getent_state *ent)
+static BOOL get_sam_user_entries(struct getent_state *ent, TALLOC_CTX *mem_ctx)
{
NTSTATUS status;
uint32 num_entries;
WINBIND_USERINFO *info;
struct getpwent_user *name_list = NULL;
BOOL result = False;
- TALLOC_CTX *mem_ctx;
struct winbindd_domain *domain;
struct winbindd_methods *methods;
unsigned int i;
@@ -380,10 +500,6 @@ static BOOL get_sam_user_entries(struct getent_state *ent)
if (ent->num_sam_entries)
return False;
- if (!(mem_ctx = talloc_init("get_sam_user_entries(%s)",
- ent->domain_name)))
- return False;
-
if (!(domain = find_domain_from_name(ent->domain_name))) {
DEBUG(3, ("no such domain %s in get_sam_user_entries\n",
ent->domain_name));
@@ -433,8 +549,10 @@ static BOOL get_sam_user_entries(struct getent_state *ent)
}
/* User and group ids */
- sid_copy(&name_list[ent->num_sam_entries+i].user_sid, info[i].user_sid);
- sid_copy(&name_list[ent->num_sam_entries+i].group_sid, info[i].group_sid);
+ sid_copy(&name_list[ent->num_sam_entries+i].user_sid,
+ &info[i].user_sid);
+ sid_copy(&name_list[ent->num_sam_entries+i].group_sid,
+ &info[i].group_sid);
}
ent->num_sam_entries += num_entries;
@@ -447,8 +565,6 @@ static BOOL get_sam_user_entries(struct getent_state *ent)
done:
- talloc_destroy(mem_ctx);
-
return result;
}
@@ -497,7 +613,8 @@ enum winbindd_result winbindd_getpwent(struct winbindd_cli_state *state)
if (ent->num_sam_entries == ent->sam_entry_index) {
- while(ent && !get_sam_user_entries(ent)) {
+ while(ent &&
+ !get_sam_user_entries(ent, state->mem_ctx)) {
struct getent_state *next_ent;
/* Free state information for this domain */
@@ -560,14 +677,10 @@ enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state)
uint32 num_entries = 0, total_entries = 0;
char *ted, *extra_data = NULL;
int extra_data_len = 0;
- TALLOC_CTX *mem_ctx;
enum winbindd_result rv = WINBINDD_ERROR;
DEBUG(3, ("[%5lu]: list users\n", (unsigned long)state->pid));
- if (!(mem_ctx = talloc_init("winbindd_list_users")))
- return WINBINDD_ERROR;
-
/* Ensure null termination */
state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
which_domain = state->request.domain_name;
@@ -585,14 +698,11 @@ enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state)
if ( *which_domain && !strequal(which_domain, domain->name) )
continue;
-
- if ( !domain->initialized )
- set_dc_type_and_flags( domain );
methods = domain->methods;
/* Query display info */
- status = methods->query_user_list(domain, mem_ctx,
+ status = methods->query_user_list(domain, state->mem_ctx,
&num_entries, &info);
if (num_entries == 0)
@@ -646,7 +756,5 @@ enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state)
done:
- talloc_destroy(mem_ctx);
-
return rv;
}