On Thu, Apr 05, 2012 at 04:02:41PM -0700, Stephen Gallagher wrote: > On Thu, 2012-03-29 at 16:27 -0400, Jakub Hrozek wrote: > > https://fedorahosted.org/sssd/ticket/1249 > > > > The patch also reduces code duplication between several error handling > > switch/case statements and fixes a bug in get_initgr where we would try > > to cancel a transaction immediately after committing it. > > > > Do we also want to canonicalize group names in a similar fashion? To be > > honest, downloading the whole group twice just for the sake of > > determining the correct group name seems a little too much to me.. > > Nack. As Jakub and I discussed on IRC, we do need to canonicalize group > names for correctness' sake. We can also opt to add a new option to > prioritize speed over correctness.
I'm sorry for the delay. Attached are two patches - one that always canonicalizes group and user names and one that adds a new option to canonicalize from cache.
>From ea206860ba591c63882dc111d9d98b82768aad5e Mon Sep 17 00:00:00 2001 From: Jakub Hrozek <jhro...@redhat.com> Date: Wed, 28 Mar 2012 01:04:52 +0200 Subject: [PATCH 1/2] proxy: Canonicalize user and group names https://fedorahosted.org/sssd/ticket/1249 --- src/providers/proxy/proxy_id.c | 680 +++++++++++++++++++++------------------- 1 files changed, 361 insertions(+), 319 deletions(-) diff --git a/src/providers/proxy/proxy_id.c b/src/providers/proxy/proxy_id.c index 4f2dbd882df437a14b123de4d046590c2d52c733..d92fc4eacfc6f3801a19d6577e39d1b202b53bd0 100644 --- a/src/providers/proxy/proxy_id.c +++ b/src/providers/proxy/proxy_id.c @@ -27,11 +27,13 @@ /* =Getpwnam-wrapper======================================================*/ -static int delete_user(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, - struct sss_domain_info *domain, const char *name); - static int save_user(struct sysdb_ctx *sysdb, bool lowercase, - struct passwd *pwd, uint64_t cache_timeout); + struct passwd *pwd, const char *alias, + uint64_t cache_timeout); + +static int +handle_getpw_result(enum nss_status status, struct passwd *pwd, + struct sss_domain_info *dom, bool *del_user); static int get_pw_name(TALLOC_CTX *mem_ctx, struct proxy_id_ctx *ctx, @@ -45,10 +47,12 @@ static int get_pw_name(TALLOC_CTX *mem_ctx, char *buffer; size_t buflen; int ret; + uid_t uid; + bool del_user; - DEBUG(7, ("Searching user by name (%s)\n", name)); + DEBUG(SSSDBG_TRACE_FUNC, ("Searching user by name (%s)\n", name)); - tmpctx = talloc_new(mem_ctx); + tmpctx = talloc_new(NULL); if (!tmpctx) { return ENOMEM; } @@ -71,67 +75,114 @@ static int get_pw_name(TALLOC_CTX *mem_ctx, /* FIXME: should we move this call outside the transaction to keep the * transaction as short as possible ? */ status = ctx->ops.getpwnam_r(name, pwd, buffer, buflen, &ret); + ret = handle_getpw_result(status, pwd, dom, &del_user); + if (ret) { + DEBUG(SSSDBG_OP_FAILURE, + ("getpwnam failed [%d]: %s\n", ret, strerror(ret))); + goto done; + } + + if (del_user) { + DEBUG(SSSDBG_TRACE_FUNC, + ("User %s does not exist (or is invalid) on remote server," + " deleting!\n", name)); + ret = sysdb_delete_user(sysdb, name, 0); + goto done; + } + + uid = pwd->pw_uid; + memset(buffer, 0, buflen); + + /* Canonicalize the username in case it was actually an alias */ + status = ctx->ops.getpwuid_r(uid, pwd, buffer, buflen, &ret); + ret = handle_getpw_result(status, pwd, dom, &del_user); + if (ret) { + DEBUG(SSSDBG_OP_FAILURE, + ("getpwuid failed [%d]: %s\n", ret, strerror(ret))); + goto done; + } + + if (del_user) { + DEBUG(SSSDBG_TRACE_FUNC, + ("User %s does not exist (or is invalid) on remote server," + " deleting!\n", name)); + ret = sysdb_delete_user(sysdb, name, uid); + goto done; + } + + /* Both lookups went fine, we can save the user now */ + ret = save_user(sysdb, !dom->case_sensitive, pwd, + name, dom->user_timeout); + +done: + talloc_zfree(tmpctx); + if (ret) { + DEBUG(SSSDBG_OP_FAILURE, + ("proxy -> getpwnam_r failed for '%s' <%d>\n", + name, status)); + } + return ret; +} + +static int +handle_getpw_result(enum nss_status status, struct passwd *pwd, + struct sss_domain_info *dom, bool *del_user) +{ + int ret = EOK; + + if (!del_user) { + return EINVAL; + } + *del_user = false; switch (status) { case NSS_STATUS_NOTFOUND: - DEBUG(7, ("User %s not found.\n", name)); - ret = delete_user(tmpctx, sysdb, dom, name); - if (ret) { - goto done; - } + DEBUG(SSSDBG_MINOR_FAILURE, ("User not found.\n")); + *del_user = true; break; case NSS_STATUS_SUCCESS: - DEBUG(7, ("User %s found: (%s, %d, %d)\n", - name, pwd->pw_name, pwd->pw_uid, pwd->pw_gid)); + DEBUG(SSSDBG_TRACE_FUNC, ("User found: (%s, %d, %d)\n", + pwd->pw_name, pwd->pw_uid, pwd->pw_gid)); /* uid=0 or gid=0 are invalid values */ /* also check that the id is in the valid range for this domain */ if (OUT_OF_ID_RANGE(pwd->pw_uid, dom->id_min, dom->id_max) || OUT_OF_ID_RANGE(pwd->pw_gid, dom->id_min, dom->id_max)) { - DEBUG(2, ("User [%s] filtered out! (id out of range)\n", name)); - ret = delete_user(tmpctx, sysdb, dom, name); - if (ret) { - goto done; - } + DEBUG(SSSDBG_MINOR_FAILURE, + ("User filtered out! (id out of range)\n")); + *del_user = true; break; } - - ret = save_user(sysdb, !dom->case_sensitive, pwd, dom->user_timeout); - if (ret) { - goto done; - } break; case NSS_STATUS_UNAVAIL: - /* "remote" backend unavailable. Enter offline mode */ + DEBUG(SSSDBG_MINOR_FAILURE, + ("Remote back end is not available. Entering offline mode\n")); ret = ENXIO; - goto done; + break; default: + DEBUG(SSSDBG_OP_FAILURE, ("Unknown return code %d\n", status)); ret = EIO; - goto done; + break; } -done: - talloc_zfree(tmpctx); - if (ret) { - DEBUG(2, ("proxy -> getpwnam_r failed for '%s' <%d>\n", - name, status)); - } return ret; } static int save_user(struct sysdb_ctx *sysdb, bool lowercase, - struct passwd *pwd, uint64_t cache_timeout) + struct passwd *pwd, const char *alias, + uint64_t cache_timeout) { const char *shell; char *lower; struct sysdb_attrs *attrs = NULL; errno_t ret; + const char *cased_alias; if (pwd->pw_shell && pwd->pw_shell[0] != '\0') { shell = pwd->pw_shell; @@ -139,13 +190,15 @@ static int save_user(struct sysdb_ctx *sysdb, bool lowercase, shell = NULL; } - if (lowercase) { + if (!lowercase || alias) { attrs = sysdb_new_attrs(NULL); if (!attrs) { DEBUG(SSSDBG_CRIT_FAILURE, ("Allocation error ?!\n")); return ENOMEM; } + } + if (lowercase) { lower = sss_tc_utf8_str_tolower(attrs, pwd->pw_name); if (!lower) { DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot convert name to lowercase\n")); @@ -161,6 +214,21 @@ static int save_user(struct sysdb_ctx *sysdb, bool lowercase, } } + if (alias) { + cased_alias = sss_get_cased_name(attrs, alias, !lowercase); + if (!cased_alias) { + talloc_zfree(attrs); + return ENOMEM; + } + + ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, cased_alias); + if (ret) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not add name alias\n")); + talloc_zfree(attrs); + return ret; + } + } + ret = sysdb_store_user(sysdb, pwd->pw_name, pwd->pw_passwd, @@ -182,22 +250,6 @@ static int save_user(struct sysdb_ctx *sysdb, bool lowercase, return EOK; } -static int delete_user(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, - struct sss_domain_info *domain, const char *name) -{ - struct ldb_dn *dn; - - DEBUG(7, ("User %s does not exist (or is invalid) on remote server," - " deleting!\n", name)); - - dn = sysdb_user_dn(sysdb, mem_ctx, domain->name, name); - if (!dn) { - return ENOMEM; - } - - return sysdb_delete_entry(sysdb, dn, true); -} - /* =Getpwuid-wrapper======================================================*/ static int get_pw_uid(TALLOC_CTX *mem_ctx, @@ -214,9 +266,9 @@ static int get_pw_uid(TALLOC_CTX *mem_ctx, bool del_user = false; int ret; - DEBUG(7, ("Searching user by uid (%d)\n", uid)); + DEBUG(SSSDBG_TRACE_FUNC, ("Searching user by uid (%d)\n", uid)); - tmpctx = talloc_new(mem_ctx); + tmpctx = talloc_new(NULL); if (!tmpctx) { return ENOMEM; } @@ -224,75 +276,40 @@ static int get_pw_uid(TALLOC_CTX *mem_ctx, pwd = talloc_zero(tmpctx, struct passwd); if (!pwd) { ret = ENOMEM; - DEBUG(1, ("proxy -> getpwuid_r failed for '%d': [%d] %s\n", - uid, ret, strerror(ret))); - return ret; + goto done; } buflen = DEFAULT_BUFSIZE; buffer = talloc_size(tmpctx, buflen); if (!buffer) { ret = ENOMEM; - DEBUG(1, ("proxy -> getpwuid_r failed for '%d': [%d] %s\n", - uid, ret, strerror(ret))); - return ret; + goto done; } status = ctx->ops.getpwuid_r(uid, pwd, buffer, buflen, &ret); - - switch (status) { - case NSS_STATUS_NOTFOUND: - - DEBUG(7, ("User %d not found.\n", uid)); - del_user = true; - break; - - case NSS_STATUS_SUCCESS: - - DEBUG(7, ("User %d found (%s, %d, %d)\n", - uid, pwd->pw_name, pwd->pw_uid, pwd->pw_gid)); - - /* uid=0 or gid=0 are invalid values */ - /* also check that the id is in the valid range for this domain */ - if (OUT_OF_ID_RANGE(pwd->pw_uid, dom->id_min, dom->id_max) || - OUT_OF_ID_RANGE(pwd->pw_gid, dom->id_min, dom->id_max)) { - - DEBUG(2, ("User [%s] filtered out! (id out of range)\n", - pwd->pw_name)); - del_user = true; - break; - } - - ret = save_user(sysdb, !dom->case_sensitive, pwd, dom->user_timeout); - if (ret) { - goto done; - } - break; - - case NSS_STATUS_UNAVAIL: - /* "remote" backend unavailable. Enter offline mode */ - ret = ENXIO; - goto done; - - default: - ret = EIO; + ret = handle_getpw_result(status, pwd, dom, &del_user); + if (ret) { + DEBUG(SSSDBG_OP_FAILURE, + ("getpwuid failed [%d]: %s\n", ret, strerror(ret))); goto done; } if (del_user) { - DEBUG(7, ("User %d does not exist (or is invalid) on remote server," - " deleting!\n", uid)); - + DEBUG(SSSDBG_TRACE_FUNC, + ("User %d does not exist (or is invalid) on remote server," + " deleting!\n", uid)); ret = sysdb_delete_user(sysdb, NULL, uid); - if (ret) { - goto done; - } + goto done; } + ret = save_user(sysdb, !dom->case_sensitive, pwd, + NULL, dom->user_timeout); + done: talloc_zfree(tmpctx); if (ret) { - DEBUG(2, ("proxy -> getpwuid_r failed for '%d' <%d>\n", uid, status)); + DEBUG(SSSDBG_CRIT_FAILURE, + ("proxy -> getpwuid_r failed for '%d' <%d>\n", uid, status)); } return ret; } @@ -394,7 +411,8 @@ again: goto again; /* skip */ } - ret = save_user(sysdb, !dom->case_sensitive, pwd, dom->user_timeout); + ret = save_user(sysdb, !dom->case_sensitive, pwd, + NULL, dom->user_timeout); if (ret) { /* Do not fail completely on errors. * Just report the failure to save and go on */ @@ -448,11 +466,13 @@ static errno_t proxy_process_missing_users(struct sysdb_ctx *sysdb, struct group *grp, time_t now); static int save_group(struct sysdb_ctx *sysdb, struct sss_domain_info *dom, - struct group *grp, uint64_t cache_timeout) + struct group *grp, const char *alias, + uint64_t cache_timeout) { errno_t ret, sret; struct sysdb_attrs *attrs = NULL; char *lower; + const char *cased_alias; TALLOC_CTX *tmp_ctx; time_t now = time(NULL); bool in_transaction = false; @@ -492,7 +512,7 @@ static int save_group(struct sysdb_ctx *sysdb, struct sss_domain_info *dom, } } - if (dom->case_sensitive == false) { + if (dom->case_sensitive == false || alias) { if (!attrs) { attrs = sysdb_new_attrs(tmp_ctx); if (!attrs) { @@ -502,18 +522,35 @@ static int save_group(struct sysdb_ctx *sysdb, struct sss_domain_info *dom, } } - lower = sss_tc_utf8_str_tolower(attrs, grp->gr_name); - if (!lower) { - DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot convert name to lowercase\n")); - ret = ENOMEM; - goto done; + if (dom->case_sensitive == false) { + lower = sss_tc_utf8_str_tolower(attrs, grp->gr_name); + if (!lower) { + DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot convert name to lowercase\n")); + ret = ENOMEM; + goto done; + } + + ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, lower); + if (ret) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not add name alias\n")); + ret = ENOMEM; + goto done; + } } - ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, lower); - if (ret) { - DEBUG(SSSDBG_OP_FAILURE, ("Could not add name alias\n")); - ret = ENOMEM; - goto done; + if (alias) { + cased_alias = sss_get_cased_name(attrs, alias, dom->case_sensitive); + if (!cased_alias) { + talloc_zfree(attrs); + return ENOMEM; + } + + ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, cased_alias); + if (ret) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not add name alias\n")); + ret = ENOMEM; + goto done; + } } } @@ -600,6 +637,73 @@ done: } /* =Getgrnam-wrapper======================================================*/ +static char * +grow_group_buffer(TALLOC_CTX *mem_ctx, + char **buffer, size_t *buflen) +{ + char *newbuf; + + if (*buflen == 0) { + *buflen = DEFAULT_BUFSIZE; + } + if (*buflen < MAX_BUF_SIZE) { + *buflen *= 2; + } + if (*buflen > MAX_BUF_SIZE) { + *buflen = MAX_BUF_SIZE; + } + + newbuf = talloc_realloc_size(mem_ctx, *buffer, *buflen); + if (!newbuf) { + return NULL; + } + *buffer = newbuf; + + return *buffer; +} + +static errno_t +handle_getgr_result(enum nss_status status, struct group *grp, + struct sss_domain_info *dom, + bool *delete_group) +{ + switch (status) { + case NSS_STATUS_TRYAGAIN: + DEBUG(SSSDBG_MINOR_FAILURE, ("Buffer too small\n")); + return EAGAIN; + + case NSS_STATUS_NOTFOUND: + DEBUG(SSSDBG_MINOR_FAILURE, ("Group not found.\n")); + *delete_group = true; + break; + + case NSS_STATUS_SUCCESS: + DEBUG(SSSDBG_FUNC_DATA, ("Group found: (%s, %d)\n", + grp->gr_name, grp->gr_gid)); + + /* gid=0 is an invalid value */ + /* also check that the id is in the valid range for this domain */ + if (OUT_OF_ID_RANGE(grp->gr_gid, dom->id_min, dom->id_max)) { + DEBUG(SSSDBG_MINOR_FAILURE, + ("Group filtered out! (id out of range)\n")); + *delete_group = true; + break; + } + break; + + case NSS_STATUS_UNAVAIL: + DEBUG(SSSDBG_MINOR_FAILURE, + ("Remote back end is not available. Entering offline mode\n")); + return ENXIO; + + default: + DEBUG(SSSDBG_OP_FAILURE, ("Unknown return code %d\n", status)); + return EIO; + } + + return EOK; +} + static int get_gr_name(TALLOC_CTX *mem_ctx, struct proxy_id_ctx *ctx, struct sysdb_ctx *sysdb, @@ -609,15 +713,15 @@ static int get_gr_name(TALLOC_CTX *mem_ctx, TALLOC_CTX *tmpctx; struct group *grp; enum nss_status status; - char *buffer; - char *newbuf; - size_t buflen; + char *buffer = 0; + size_t buflen = 0; bool delete_group = false; int ret; + gid_t gid; - DEBUG(7, ("Searching group by name (%s)\n", name)); + DEBUG(SSSDBG_FUNC_DATA, ("Searching group by name (%s)\n", name)); - tmpctx = talloc_new(mem_ctx); + tmpctx = talloc_new(NULL); if (!tmpctx) { return ENOMEM; } @@ -625,111 +729,83 @@ static int get_gr_name(TALLOC_CTX *mem_ctx, grp = talloc(tmpctx, struct group); if (!grp) { ret = ENOMEM; - DEBUG(1, ("proxy -> getgrnam_r failed for '%s': [%d] %s\n", - name, ret, strerror(ret))); - return ret; - } - - buflen = DEFAULT_BUFSIZE; - buffer = talloc_size(tmpctx, buflen); - if (!buffer) { - ret = ENOMEM; - DEBUG(1, ("proxy -> getgrnam_r failed for '%s': [%d] %s\n", - name, ret, strerror(ret))); - return ret; + DEBUG(SSSDBG_CRIT_FAILURE, + ("proxy -> getgrnam_r failed for '%s': [%d] %s\n", + name, ret, strerror(ret))); + goto done; } - /* FIXME: should we move this call outside the transaction to keep the - * transaction as short as possible ? */ -again: - /* always zero out the grp structure */ - memset(grp, 0, sizeof(struct group)); - - status = ctx->ops.getgrnam_r(name, grp, buffer, buflen, &ret); - - switch (status) { - case NSS_STATUS_TRYAGAIN: - /* buffer too small ? */ - if (buflen < MAX_BUF_SIZE) { - buflen *= 2; - } - if (buflen > MAX_BUF_SIZE) { - buflen = MAX_BUF_SIZE; - } - newbuf = talloc_realloc_size(tmpctx, buffer, buflen); - if (!newbuf) { + do { + /* always zero out the grp structure */ + memset(grp, 0, sizeof(struct group)); + buffer = grow_group_buffer(tmpctx, &buffer, &buflen); + if (!buffer) { ret = ENOMEM; goto done; } - buffer = newbuf; - goto again; - - case NSS_STATUS_NOTFOUND: - DEBUG(7, ("Group %s not found.\n", name)); - delete_group = true; - break; + status = ctx->ops.getgrnam_r(name, grp, buffer, buflen, &ret); - case NSS_STATUS_SUCCESS: + ret = handle_getgr_result(status, grp, dom, &delete_group); + } while (ret == EAGAIN); - DEBUG(7, ("Group %s found: (%s, %d)\n", - name, grp->gr_name, grp->gr_gid)); - - /* gid=0 is an invalid value */ - /* also check that the id is in the valid range for this domain */ - if (OUT_OF_ID_RANGE(grp->gr_gid, dom->id_min, dom->id_max)) { + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + ("getgrnam failed [%d]: %s\n", ret, strerror(ret))); + goto done; + } - DEBUG(2, ("Group [%s] filtered out! (id out of range)\n", - name)); - delete_group = true; - break; - } + gid = grp->gr_gid; + talloc_zfree(buffer); + buflen = 0; - ret = save_group(sysdb, dom, grp, dom->group_timeout); - if (ret) { + /* Canonicalize the group name in case it was actually an alias */ + do { + memset(grp, 0, sizeof(struct group)); + buffer = grow_group_buffer(tmpctx, &buffer, &buflen); + if (!buffer) { + ret = ENOMEM; goto done; } - break; - case NSS_STATUS_UNAVAIL: - /* "remote" backend unavailable. Enter offline mode */ - ret = ENXIO; - goto done; + status = ctx->ops.getgrgid_r(gid, grp, buffer, buflen, &ret); + + ret = handle_getgr_result(status, grp, dom, &delete_group); + } while(ret == EAGAIN); - default: - ret = EIO; + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + ("getgrgid failed [%d]: %s\n", ret, strerror(ret))); goto done; } if (delete_group) { - struct ldb_dn *dn; + DEBUG(SSSDBG_TRACE_FUNC, + ("Group %s does not exist (or is invalid) on remote server," + " deleting!\n", name)); - DEBUG(7, ("Group %s does not exist (or is invalid) on remote server," - " deleting!\n", name)); + ret = sysdb_delete_group(sysdb, NULL, gid); + goto done; + } - dn = sysdb_group_dn(sysdb, tmpctx, dom->name, name); - if (!dn) { - ret = ENOMEM; - goto done; - } - - ret = sysdb_delete_entry(sysdb, dn, true); - if (ret) { - goto done; - } + ret = save_group(sysdb, dom, grp, name, dom->group_timeout); + if (ret) { + DEBUG(SSSDBG_OP_FAILURE, + ("Cannot save group [%d]: %s\n", ret, strerror(ret))); + goto done; } done: talloc_zfree(tmpctx); if (ret) { - DEBUG(2, ("proxy -> getgrnam_r failed for '%s' <%d>\n", - name, status)); + DEBUG(SSSDBG_OP_FAILURE, + ("proxy -> getgrnam_r failed for '%s' <%d>\n", + name, status)); } return ret; } /* =Getgrgid-wrapper======================================================*/ - static int get_gr_gid(TALLOC_CTX *mem_ctx, struct proxy_id_ctx *ctx, struct sysdb_ctx *sysdb, @@ -740,13 +816,12 @@ static int get_gr_gid(TALLOC_CTX *mem_ctx, TALLOC_CTX *tmpctx; struct group *grp; enum nss_status status; - char *buffer; - char *newbuf; - size_t buflen; + char *buffer = NULL; + size_t buflen = 0; bool delete_group = false; int ret; - DEBUG(7, ("Searching group by gid (%d)\n", gid)); + DEBUG(SSSDBG_TRACE_FUNC, ("Searching group by gid (%d)\n", gid)); tmpctx = talloc_new(mem_ctx); if (!tmpctx) { @@ -756,96 +831,45 @@ static int get_gr_gid(TALLOC_CTX *mem_ctx, grp = talloc(tmpctx, struct group); if (!grp) { ret = ENOMEM; - DEBUG(1, ("proxy -> getgrgid_r failed for '%d': [%d] %s\n", - gid, ret, strerror(ret))); - return ret; + goto done; } - buflen = DEFAULT_BUFSIZE; - buffer = talloc_size(tmpctx, buflen); - if (!buffer) { - ret = ENOMEM; - DEBUG(1, ("proxy -> getgrgid_r failed for '%d': [%d] %s\n", - gid, ret, strerror(ret))); - return ret; - } - -again: - /* always zero out the group structure */ - memset(grp, 0, sizeof(struct group)); - - status = ctx->ops.getgrgid_r(gid, grp, buffer, buflen, &ret); - - switch (status) { - case NSS_STATUS_TRYAGAIN: - /* buffer too small ? */ - if (buflen < MAX_BUF_SIZE) { - buflen *= 2; - } - if (buflen > MAX_BUF_SIZE) { - buflen = MAX_BUF_SIZE; - } - newbuf = talloc_realloc_size(tmpctx, buffer, buflen); - if (!newbuf) { + do { + /* always zero out the grp structure */ + memset(grp, 0, sizeof(struct group)); + buffer = grow_group_buffer(tmpctx, &buffer, &buflen); + if (!buffer) { ret = ENOMEM; goto done; } - buffer = newbuf; - goto again; - case NSS_STATUS_NOTFOUND: + status = ctx->ops.getgrgid_r(gid, grp, buffer, buflen, &ret); - DEBUG(7, ("Group %d not found.\n", gid)); - delete_group = true; - break; - - case NSS_STATUS_SUCCESS: - - DEBUG(7, ("Group %d found (%s, %d)\n", - gid, grp->gr_name, grp->gr_gid)); - - /* gid=0 is an invalid value */ - /* also check that the id is in the valid range for this domain */ - if (OUT_OF_ID_RANGE(grp->gr_gid, dom->id_min, dom->id_max)) { - - DEBUG(2, ("Group [%s] filtered out! (id out of range)\n", - grp->gr_name)); - delete_group = true; - break; - } - - ret = save_group(sysdb, dom, grp, dom->group_timeout); - if (ret) { - goto done; - } - break; - - case NSS_STATUS_UNAVAIL: - /* "remote" backend unavailable. Enter offline mode */ - ret = ENXIO; - goto done; - - default: - ret = EIO; - goto done; - } + ret = handle_getgr_result(status, grp, dom, &delete_group); + } while (ret == EAGAIN); if (delete_group) { - - DEBUG(7, ("Group %d does not exist (or is invalid) on remote server," - " deleting!\n", gid)); + DEBUG(SSSDBG_TRACE_FUNC, + ("Group %d does not exist (or is invalid) on remote server," + " deleting!\n", gid)); ret = sysdb_delete_group(sysdb, NULL, gid); - if (ret) { - goto done; - } + goto done; + } + + ret = save_group(sysdb, dom, grp, NULL, dom->group_timeout); + if (ret) { + DEBUG(SSSDBG_OP_FAILURE, + ("Cannot save user [%d]: %s\n", ret, strerror(ret))); + goto done; } done: talloc_zfree(tmpctx); if (ret) { - DEBUG(2, ("proxy -> getgrgid_r failed for '%d' <%d>\n", - gid, status)); + DEBUG(SSSDBG_OP_FAILURE, + ("proxy -> getgrgid_r failed for '%d' <%d>\n", + gid, status)); } return ret; } @@ -946,7 +970,7 @@ again: goto again; /* skip */ } - ret = save_group(sysdb, dom, grp, dom->group_timeout); + ret = save_group(sysdb, dom, grp, NULL, dom->group_timeout); if (ret) { /* Do not fail completely on errors. * Just report the failure to save and go on */ @@ -997,6 +1021,8 @@ static int get_initgr(TALLOC_CTX *mem_ctx, char *buffer; size_t buflen; int ret; + bool del_user; + uid_t uid; tmpctx = talloc_new(mem_ctx); if (!tmpctx) { @@ -1006,74 +1032,90 @@ static int get_initgr(TALLOC_CTX *mem_ctx, pwd = talloc_zero(tmpctx, struct passwd); if (!pwd) { ret = ENOMEM; - goto done; + goto fail; } buflen = DEFAULT_BUFSIZE; buffer = talloc_size(tmpctx, buflen); if (!buffer) { ret = ENOMEM; - goto done; + goto fail; } ret = sysdb_transaction_start(sysdb); if (ret) { - goto done; + goto fail; } in_transaction = true; /* FIXME: should we move this call outside the transaction to keep the * transaction as short as possible ? */ status = ctx->ops.getpwnam_r(name, pwd, buffer, buflen, &ret); - - switch (status) { - case NSS_STATUS_NOTFOUND: - - DEBUG(7, ("User %s not found.\n", name)); - ret = delete_user(tmpctx, sysdb, dom, name); + ret = handle_getpw_result(status, pwd, dom, &del_user); + if (ret) { + DEBUG(SSSDBG_OP_FAILURE, + ("getpwnam failed [%d]: %s\n", ret, strerror(ret))); + goto fail; + } + + if (del_user) { + DEBUG(SSSDBG_TRACE_FUNC, + ("User %s does not exist (or is invalid) on remote server," + " deleting!\n", name)); + ret = sysdb_delete_user(sysdb, name, 0); if (ret) { - goto done; - } - break; - - case NSS_STATUS_SUCCESS: - - /* uid=0 or gid=0 are invalid values */ - /* also check that the id is in the valid range for this domain */ - if (OUT_OF_ID_RANGE(pwd->pw_uid, dom->id_min, dom->id_max) || - OUT_OF_ID_RANGE(pwd->pw_gid, dom->id_min, dom->id_max)) { - - DEBUG(2, ("User [%s] filtered out! (id out of range)\n", - name)); - ret = delete_user(tmpctx, sysdb, dom, name); - break; + DEBUG(SSSDBG_OP_FAILURE, ("Could not delete user\n")); + goto fail; } - - ret = save_user(sysdb, !dom->case_sensitive, pwd, dom->user_timeout); + goto done; + } + + uid = pwd->pw_uid; + memset(buffer, 0, buflen); + + /* Canonicalize the username in case it was actually an alias */ + status = ctx->ops.getpwuid_r(uid, pwd, buffer, buflen, &ret); + ret = handle_getpw_result(status, pwd, dom, &del_user); + if (ret) { + DEBUG(SSSDBG_OP_FAILURE, + ("getpwuid failed [%d]: %s\n", ret, strerror(ret))); + goto fail; + } + + if (del_user) { + DEBUG(SSSDBG_TRACE_FUNC, + ("User %s does not exist (or is invalid) on remote server," + " deleting!\n", name)); + ret = sysdb_delete_user(sysdb, name, uid); if (ret) { - goto done; - } - - ret = get_initgr_groups_process(tmpctx, ctx, sysdb, dom, pwd); - if (ret == EOK) { - ret = sysdb_transaction_commit(sysdb); - in_transaction = true; + DEBUG(SSSDBG_OP_FAILURE, ("Could not delete user\n")); + goto fail; } - break; - - case NSS_STATUS_UNAVAIL: - /* "remote" backend unavailable. Enter offline mode */ - ret = ENXIO; - break; - - default: - DEBUG(2, ("proxy -> getpwnam_r failed for '%s' <%d>\n", - name, status)); - ret = EIO; - break; + goto done; + } + + ret = save_user(sysdb, !dom->case_sensitive, pwd, + name, dom->user_timeout); + if (ret) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not save user\n")); + goto fail; + } + + ret = get_initgr_groups_process(tmpctx, ctx, sysdb, dom, pwd); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, ("Could not process initgroups\n")); + goto fail; } done: + ret = sysdb_transaction_commit(sysdb); + if (ret) { + DEBUG(SSSDBG_OP_FAILURE, ("Failed to commit transaction\n")); + goto fail; + } + in_transaction = false; + +fail: talloc_zfree(tmpctx); if (in_transaction) { sysdb_transaction_cancel(sysdb); -- 1.7.7.6
>From 00e447db2df1ae7f2f205908113379447a201b3e Mon Sep 17 00:00:00 2001 From: Jakub Hrozek <jhro...@redhat.com> Date: Thu, 12 Apr 2012 18:21:48 +0200 Subject: [PATCH 2/2] proxy: new option proxy_fast_alias --- src/confdb/confdb.h | 1 + src/config/SSSDConfig.py | 1 + src/config/etc/sssd.api.d/sssd-proxy.conf | 1 + src/man/sssd.conf.5.xml | 17 +++ src/providers/proxy/proxy.h | 1 + src/providers/proxy/proxy_id.c | 163 +++++++++++++++++++++-------- src/providers/proxy/proxy_init.c | 4 + 7 files changed, 144 insertions(+), 44 deletions(-) diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h index aebf5d888002aa30af709ec57d3663de9f554a10..83a0fea90f4e2da8837a7bbb3643d520a74583ac 100644 --- a/src/confdb/confdb.h +++ b/src/confdb/confdb.h @@ -158,6 +158,7 @@ /* Proxy Provider */ #define CONFDB_PROXY_LIBNAME "proxy_lib_name" #define CONFDB_PROXY_PAM_TARGET "proxy_pam_target" +#define CONFDB_PROXY_FAST_ALIAS "proxy_fast_alias" struct confdb_ctx; struct config_file_ctx; diff --git a/src/config/SSSDConfig.py b/src/config/SSSDConfig.py index 488220a67fa94be7c96dc1a02487700ebfe89a40..f4987997248dfadc1383537b981d4797104affe1 100644 --- a/src/config/SSSDConfig.py +++ b/src/config/SSSDConfig.py @@ -300,6 +300,7 @@ option_strings = { # [provider/proxy/id] 'proxy_lib_name' : _('The name of the NSS library to use'), + 'proxy_fast_alias' : _('Whether to look up canonical group name from cache if possible'), # [provider/proxy/auth] 'proxy_pam_target' : _('PAM stack to use') diff --git a/src/config/etc/sssd.api.d/sssd-proxy.conf b/src/config/etc/sssd.api.d/sssd-proxy.conf index 7ecf6b33b66be979c06393de99f93df142552df2..39f6a63cdec8d5ac5b84e93b16bdd8b668cf7623 100644 --- a/src/config/etc/sssd.api.d/sssd-proxy.conf +++ b/src/config/etc/sssd.api.d/sssd-proxy.conf @@ -2,6 +2,7 @@ [provider/proxy/id] proxy_lib_name = str, None, true +proxy_fast_alias = bool, None, true [provider/proxy/auth] proxy_pam_target = str, None, true diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml index 63e396a545f04b28b1bfb0ccc69b454aa83686e9..ed3c3574379d6847a4a5e93f035158715a73dc34 100644 --- a/src/man/sssd.conf.5.xml +++ b/src/man/sssd.conf.5.xml @@ -1180,6 +1180,23 @@ </para> </listitem> </varlistentry> + + <varlistentry> + <term>proxy_fast_alias (boolean)</term> + <listitem> + <para> + When a user or group is looked up by name in + the proxy provider, a second lookup by ID is + performed to "canonicalize" the name in case + the requested name was an alias. Setting this + option to true would cause the SSSD to perform + the ID lookup from cache for performance reasons. + </para> + <para> + Default: false + </para> + </listitem> + </varlistentry> </variablelist> </para> diff --git a/src/providers/proxy/proxy.h b/src/providers/proxy/proxy.h index 3641d6ee544c69982d23e1f675c40da69b8de604..cea03382517231cdf2b96069ab93dfb7967b46a6 100644 --- a/src/providers/proxy/proxy.h +++ b/src/providers/proxy/proxy.h @@ -100,6 +100,7 @@ struct authtok_conv { struct proxy_id_ctx { struct be_ctx *be; + bool fast_alias; struct proxy_nss_ops ops; void *handle; }; diff --git a/src/providers/proxy/proxy_id.c b/src/providers/proxy/proxy_id.c index d92fc4eacfc6f3801a19d6577e39d1b202b53bd0..b7f1ee4d7657dababeb37146d18aa8e131a794b6 100644 --- a/src/providers/proxy/proxy_id.c +++ b/src/providers/proxy/proxy_id.c @@ -28,8 +28,8 @@ /* =Getpwnam-wrapper======================================================*/ static int save_user(struct sysdb_ctx *sysdb, bool lowercase, - struct passwd *pwd, const char *alias, - uint64_t cache_timeout); + struct passwd *pwd, const char *real_name, + const char *alias, uint64_t cache_timeout); static int handle_getpw_result(enum nss_status status, struct passwd *pwd, @@ -49,6 +49,8 @@ static int get_pw_name(TALLOC_CTX *mem_ctx, int ret; uid_t uid; bool del_user; + struct ldb_result *cached_pwd = NULL; + const char *real_name = NULL; DEBUG(SSSDBG_TRACE_FUNC, ("Searching user by name (%s)\n", name)); @@ -91,15 +93,38 @@ static int get_pw_name(TALLOC_CTX *mem_ctx, } uid = pwd->pw_uid; - memset(buffer, 0, buflen); /* Canonicalize the username in case it was actually an alias */ - status = ctx->ops.getpwuid_r(uid, pwd, buffer, buflen, &ret); - ret = handle_getpw_result(status, pwd, dom, &del_user); - if (ret) { - DEBUG(SSSDBG_OP_FAILURE, - ("getpwuid failed [%d]: %s\n", ret, strerror(ret))); - goto done; + + if (ctx->fast_alias == true) { + ret = sysdb_getpwuid(tmpctx, sysdb, uid, &cached_pwd); + if (ret != EOK) { + /* Non-fatal, attempt to canonicalize online */ + DEBUG(SSSDBG_MINOR_FAILURE, ("Request to cache failed [%d]: %s\n", + ret, strerror(ret))); + } + + if (ret == EOK && cached_pwd->count == 1) { + real_name = ldb_msg_find_attr_as_string(cached_pwd->msgs[0], + SYSDB_NAME, NULL); + if (!real_name) { + DEBUG(SSSDBG_MINOR_FAILURE, ("Cached user has no name?\n")); + } + } + } + + if (real_name == NULL) { + memset(buffer, 0, buflen); + + status = ctx->ops.getpwuid_r(uid, pwd, buffer, buflen, &ret); + ret = handle_getpw_result(status, pwd, dom, &del_user); + if (ret) { + DEBUG(SSSDBG_OP_FAILURE, + ("getpwuid failed [%d]: %s\n", ret, strerror(ret))); + goto done; + } + + real_name = pwd->pw_name; } if (del_user) { @@ -112,7 +137,7 @@ static int get_pw_name(TALLOC_CTX *mem_ctx, /* Both lookups went fine, we can save the user now */ ret = save_user(sysdb, !dom->case_sensitive, pwd, - name, dom->user_timeout); + real_name, name, dom->user_timeout); done: talloc_zfree(tmpctx); @@ -175,8 +200,8 @@ handle_getpw_result(enum nss_status status, struct passwd *pwd, } static int save_user(struct sysdb_ctx *sysdb, bool lowercase, - struct passwd *pwd, const char *alias, - uint64_t cache_timeout) + struct passwd *pwd, const char *real_name, + const char *alias, uint64_t cache_timeout) { const char *shell; char *lower; @@ -230,7 +255,7 @@ static int save_user(struct sysdb_ctx *sysdb, bool lowercase, } ret = sysdb_store_user(sysdb, - pwd->pw_name, + real_name, pwd->pw_passwd, pwd->pw_uid, pwd->pw_gid, @@ -303,7 +328,7 @@ static int get_pw_uid(TALLOC_CTX *mem_ctx, } ret = save_user(sysdb, !dom->case_sensitive, pwd, - NULL, dom->user_timeout); + pwd->pw_name, NULL, dom->user_timeout); done: talloc_zfree(tmpctx); @@ -412,7 +437,7 @@ again: } ret = save_user(sysdb, !dom->case_sensitive, pwd, - NULL, dom->user_timeout); + pwd->pw_name, NULL, dom->user_timeout); if (ret) { /* Do not fail completely on errors. * Just report the failure to save and go on */ @@ -466,8 +491,8 @@ static errno_t proxy_process_missing_users(struct sysdb_ctx *sysdb, struct group *grp, time_t now); static int save_group(struct sysdb_ctx *sysdb, struct sss_domain_info *dom, - struct group *grp, const char *alias, - uint64_t cache_timeout) + struct group *grp, const char *real_name, + const char *alias, uint64_t cache_timeout) { errno_t ret, sret; struct sysdb_attrs *attrs = NULL; @@ -555,7 +580,7 @@ static int save_group(struct sysdb_ctx *sysdb, struct sss_domain_info *dom, } ret = sysdb_store_group(sysdb, - grp->gr_name, + real_name, grp->gr_gid, attrs, cache_timeout, @@ -718,6 +743,8 @@ static int get_gr_name(TALLOC_CTX *mem_ctx, bool delete_group = false; int ret; gid_t gid; + struct ldb_result *cached_grp = NULL; + const char *real_name = NULL; DEBUG(SSSDBG_FUNC_DATA, ("Searching group by name (%s)\n", name)); @@ -756,27 +783,49 @@ static int get_gr_name(TALLOC_CTX *mem_ctx, } gid = grp->gr_gid; - talloc_zfree(buffer); - buflen = 0; /* Canonicalize the group name in case it was actually an alias */ - do { - memset(grp, 0, sizeof(struct group)); - buffer = grow_group_buffer(tmpctx, &buffer, &buflen); - if (!buffer) { - ret = ENOMEM; + if (ctx->fast_alias == true) { + ret = sysdb_getgrgid(tmpctx, sysdb, gid, &cached_grp); + if (ret != EOK) { + /* Non-fatal, attempt to canonicalize online */ + DEBUG(SSSDBG_MINOR_FAILURE, ("Request to cache failed [%d]: %s\n", + ret, strerror(ret))); + } + + if (ret == EOK && cached_grp->count == 1) { + real_name = ldb_msg_find_attr_as_string(cached_grp->msgs[0], + SYSDB_NAME, NULL); + if (!real_name) { + DEBUG(SSSDBG_MINOR_FAILURE, ("Cached group has no name?\n")); + } + } + } + + if (real_name == NULL) { + talloc_zfree(buffer); + buflen = 0; + + do { + memset(grp, 0, sizeof(struct group)); + buffer = grow_group_buffer(tmpctx, &buffer, &buflen); + if (!buffer) { + ret = ENOMEM; + goto done; + } + + status = ctx->ops.getgrgid_r(gid, grp, buffer, buflen, &ret); + + ret = handle_getgr_result(status, grp, dom, &delete_group); + } while (ret == EAGAIN); + + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + ("getgrgid failed [%d]: %s\n", ret, strerror(ret))); goto done; } - status = ctx->ops.getgrgid_r(gid, grp, buffer, buflen, &ret); - - ret = handle_getgr_result(status, grp, dom, &delete_group); - } while(ret == EAGAIN); - - if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - ("getgrgid failed [%d]: %s\n", ret, strerror(ret))); - goto done; + real_name = grp->gr_name; } if (delete_group) { @@ -788,7 +837,7 @@ static int get_gr_name(TALLOC_CTX *mem_ctx, goto done; } - ret = save_group(sysdb, dom, grp, name, dom->group_timeout); + ret = save_group(sysdb, dom, grp, real_name, name, dom->group_timeout); if (ret) { DEBUG(SSSDBG_OP_FAILURE, ("Cannot save group [%d]: %s\n", ret, strerror(ret))); @@ -857,7 +906,7 @@ static int get_gr_gid(TALLOC_CTX *mem_ctx, goto done; } - ret = save_group(sysdb, dom, grp, NULL, dom->group_timeout); + ret = save_group(sysdb, dom, grp, grp->gr_name, NULL, dom->group_timeout); if (ret) { DEBUG(SSSDBG_OP_FAILURE, ("Cannot save user [%d]: %s\n", ret, strerror(ret))); @@ -970,7 +1019,8 @@ again: goto again; /* skip */ } - ret = save_group(sysdb, dom, grp, NULL, dom->group_timeout); + ret = save_group(sysdb, dom, grp, grp->gr_name, + NULL, dom->group_timeout); if (ret) { /* Do not fail completely on errors. * Just report the failure to save and go on */ @@ -1023,6 +1073,8 @@ static int get_initgr(TALLOC_CTX *mem_ctx, int ret; bool del_user; uid_t uid; + struct ldb_result *cached_pwd = NULL; + const char *real_name = NULL; tmpctx = talloc_new(mem_ctx); if (!tmpctx) { @@ -1074,12 +1126,35 @@ static int get_initgr(TALLOC_CTX *mem_ctx, memset(buffer, 0, buflen); /* Canonicalize the username in case it was actually an alias */ - status = ctx->ops.getpwuid_r(uid, pwd, buffer, buflen, &ret); - ret = handle_getpw_result(status, pwd, dom, &del_user); - if (ret) { - DEBUG(SSSDBG_OP_FAILURE, - ("getpwuid failed [%d]: %s\n", ret, strerror(ret))); - goto fail; + if (ctx->fast_alias == true) { + ret = sysdb_getpwuid(tmpctx, sysdb, uid, &cached_pwd); + if (ret != EOK) { + /* Non-fatal, attempt to canonicalize online */ + DEBUG(SSSDBG_MINOR_FAILURE, ("Request to cache failed [%d]: %s\n", + ret, strerror(ret))); + } + + if (ret == EOK && cached_pwd->count == 1) { + real_name = ldb_msg_find_attr_as_string(cached_pwd->msgs[0], + SYSDB_NAME, NULL); + if (!real_name) { + DEBUG(SSSDBG_MINOR_FAILURE, ("Cached user has no name?\n")); + } + } + } + + if (real_name == NULL) { + memset(buffer, 0, buflen); + + status = ctx->ops.getpwuid_r(uid, pwd, buffer, buflen, &ret); + ret = handle_getpw_result(status, pwd, dom, &del_user); + if (ret) { + DEBUG(SSSDBG_OP_FAILURE, + ("getpwuid failed [%d]: %s\n", ret, strerror(ret))); + goto done; + } + + real_name = pwd->pw_name; } if (del_user) { @@ -1095,7 +1170,7 @@ static int get_initgr(TALLOC_CTX *mem_ctx, } ret = save_user(sysdb, !dom->case_sensitive, pwd, - name, dom->user_timeout); + real_name, name, dom->user_timeout); if (ret) { DEBUG(SSSDBG_OP_FAILURE, ("Could not save user\n")); goto fail; diff --git a/src/providers/proxy/proxy_init.c b/src/providers/proxy/proxy_init.c index 46b2e7c36e5515b737c1f0e4e887ad5897b8d332..de4d7b615aabb1d151a55c5eb6ac620be1f244cf 100644 --- a/src/providers/proxy/proxy_init.c +++ b/src/providers/proxy/proxy_init.c @@ -109,6 +109,10 @@ int sssm_proxy_id_init(struct be_ctx *bectx, goto done; } + ret = confdb_get_bool(bectx->cdb, bectx->conf_path, + CONFDB_PROXY_FAST_ALIAS, false, &ctx->fast_alias); + if (ret != EOK) goto done; + libpath = talloc_asprintf(ctx, "libnss_%s.so.2", libname); if (!libpath) { ret = ENOMEM; -- 1.7.7.6
_______________________________________________ sssd-devel mailing list sssd-devel@lists.fedorahosted.org https://fedorahosted.org/mailman/listinfo/sssd-devel