-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi, these two patches add the same functionality we have in the 1.2 branch into master. I think they read much better b/c of the synchronous sysdb interface. Both must be applied on top of Ralf's patches in the "Behaviour of getgrnam/getgrgid" thread.
Jakub -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/ iEYEARECAAYFAkyy+pAACgkQHsardTLnvCXwFACfYqJBydSwz/K7PD1hBu7Nh/OM aokAn0qlwTlezT4DLTFqp/e8fkkIRYUu =rqOw -----END PGP SIGNATURE-----
From 484ecb2b221225544303eee82f05362ef0f64da4 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek <jhro...@redhat.com> Date: Wed, 29 Sep 2010 22:15:39 +0200 Subject: [PATCH 1/2] sysdb interface for adding fake users --- src/db/sysdb.h | 4 ++ src/db/sysdb_ops.c | 61 ++++++++++++++++++++++++++++++++++ src/providers/ldap/ldap_id_cleanup.c | 7 ++-- src/responder/nss/nsssrv_cmd.c | 2 +- 4 files changed, 70 insertions(+), 4 deletions(-) diff --git a/src/db/sysdb.h b/src/db/sysdb.h index aaea1ea..0c8a7c6 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -402,6 +402,10 @@ int sysdb_add_user(TALLOC_CTX *mem_ctx, struct sysdb_attrs *attrs, int cache_timeout); +int sysdb_add_fake_user(struct sysdb_ctx *ctx, + struct sss_domain_info *domain, + const char *name); + /* Add group (only basic attrs and w/o checks) */ int sysdb_add_basic_group(TALLOC_CTX *mem_ctx, struct sysdb_ctx *ctx, diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c index b3be055..a625d20 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -844,6 +844,67 @@ done: return ret; } +int sysdb_add_fake_user(struct sysdb_ctx *ctx, + struct sss_domain_info *domain, + const char *name) +{ + TALLOC_CTX *tmpctx; + struct ldb_message *msg; + time_t now; + int ret; + + tmpctx = talloc_new(NULL); + if (!tmpctx) { + return ENOMEM; + } + + msg = ldb_msg_new(tmpctx); + if (!msg) { + ERROR_OUT(ret, ENOMEM, done); + } + + /* user dn */ + msg->dn = sysdb_user_dn(ctx, msg, domain->name, name); + if (!msg->dn) { + ERROR_OUT(ret, ENOMEM, done); + } + + ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_OBJECTCLASS, SYSDB_USER_CLASS); + if (ret) goto done; + + ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_NAME, name); + if (ret) goto done; + + now = time(NULL); + + ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_CREATE_TIME, + (unsigned long) now); + if (ret) goto done; + + /* set last login so that the fake entry does not get cleaned up + * immediately */ + ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_LAST_LOGIN, + (unsigned long) now); + if (ret) return ret; + + ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_LAST_UPDATE, + (unsigned long) now); + if (ret) goto done; + + ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_CACHE_EXPIRE, + (unsigned long) now-1); + if (ret) goto done; + + ret = ldb_add(ctx->ldb, msg); + ret = sysdb_error_to_errno(ret); + +done: + if (ret != EOK) { + DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret))); + } + talloc_zfree(tmpctx); + return ret; +} /* =Add-Basic-Group-NO-CHECKS============================================= */ diff --git a/src/providers/ldap/ldap_id_cleanup.c b/src/providers/ldap/ldap_id_cleanup.c index 60bc171..6357708 100644 --- a/src/providers/ldap/ldap_id_cleanup.c +++ b/src/providers/ldap/ldap_id_cleanup.c @@ -306,7 +306,8 @@ static int cleanup_users(TALLOC_CTX *memctx, struct sdap_id_ctx *ctx) ret = cleanup_users_logged_in(uid_table, msgs[i]); if (ret == EOK) { /* If the user is logged in, proceed to the next one */ - DEBUG(5, ("User %s is still logged in, keeping data\n", name)); + DEBUG(5, ("User %s is still logged in or a dummy entry, " + "keeping data\n", name)); continue; } else if (ret != ENOENT) { goto done; @@ -337,9 +338,9 @@ static int cleanup_users_logged_in(hash_table_t *table, uid = ldb_msg_find_attr_as_uint64(msg, SYSDB_UIDNUM, 0); if (!uid) { - DEBUG(2, ("Entry %s has no UID Attribute ?!?\n", + DEBUG(2, ("Entry %s has no UID Attribute, fake user perhaps?\n", ldb_dn_get_linearized(msg->dn))); - return EFAULT; + return ENOENT; } key.type = HASH_KEY_ULONG; diff --git a/src/responder/nss/nsssrv_cmd.c b/src/responder/nss/nsssrv_cmd.c index b093da0..078a52f 100644 --- a/src/responder/nss/nsssrv_cmd.c +++ b/src/responder/nss/nsssrv_cmd.c @@ -274,7 +274,7 @@ static int fill_pwent(struct sss_packet *packet, gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0); if (!name || !uid || !gid) { - DEBUG(1, ("Incomplete user object for %s[%llu]! Skipping\n", + DEBUG(2, ("Incomplete or fake user object for %s[%llu]! Skipping\n", name?name:"<NULL>", (unsigned long long int)uid)); continue; } -- 1.7.2.3
From 07a4c76c40d2df2afd05cf7719cc802eab508787 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek <jhro...@redhat.com> Date: Sat, 2 Oct 2010 12:43:07 +0200 Subject: [PATCH 2/2] Save dummy member users during RFC2307 getgr{nam,uid} --- src/providers/ldap/sdap_async_accounts.c | 361 +++++++++++++++++++++++------- 1 files changed, 279 insertions(+), 82 deletions(-) diff --git a/src/providers/ldap/sdap_async_accounts.c b/src/providers/ldap/sdap_async_accounts.c index 1ff3e9e..8845cce 100644 --- a/src/providers/ldap/sdap_async_accounts.c +++ b/src/providers/ldap/sdap_async_accounts.c @@ -931,6 +931,7 @@ struct sdap_process_group_state { struct sysdb_attrs **new_members; struct ldb_message_element* sysdb_dns; char **queued_members; + int queue_len; const char **attrs; const char *filter; size_t member_idx; @@ -942,6 +943,12 @@ struct sdap_process_group_state { #define GROUPMEMBER_REQ_PARALLEL 50 static void sdap_process_group_members(struct tevent_req *subreq); +static int sdap_process_group_members_2307bis(struct tevent_req *req, + struct sdap_process_group_state *state, + struct ldb_message_element *memberel); +static int sdap_process_group_members_2307(struct sdap_process_group_state *state, + struct ldb_message_element *memberel); + struct tevent_req *sdap_process_group_send(TALLOC_CTX *memctx, struct tevent_context *ev, struct sss_domain_info *dom, @@ -955,9 +962,7 @@ struct tevent_req *sdap_process_group_send(TALLOC_CTX *memctx, struct tevent_req *req = NULL; const char **attrs; char* filter; - int queue_len; int ret; - int i; req = tevent_req_create(memctx, &grp_state, struct sdap_process_group_state); @@ -987,6 +992,7 @@ struct tevent_req *sdap_process_group_send(TALLOC_CTX *memctx, grp_state->member_idx = 0; grp_state->queue_idx = 0; grp_state->queued_members = NULL; + grp_state->queue_len = 0; grp_state->filter = filter; grp_state->attrs = attrs; @@ -1016,112 +1022,303 @@ struct tevent_req *sdap_process_group_send(TALLOC_CTX *memctx, return NULL; } grp_state->sysdb_dns->num_values = 0; - queue_len = 0; - /* - * For each member check if it is already present in sysdb, - * if it isn't read it from LDAP - */ - for (i = 0; i < el->num_values; i++) { - char *sysdb_dn; - DEBUG(7, ("checking member: %s\n", (const char*)el->values[i].data)); - ret = sdap_find_entry_by_origDN(grp_state->sysdb_dns->values, sysdb, - dom, (const char *)el->values[i].data, - &sysdb_dn); - if (ret == ENOENT) { - if (opts->schema_type != SDAP_SCHEMA_RFC2307BIS) { - continue; - } + switch (opts->schema_type) { + case SDAP_SCHEMA_RFC2307: + ret = sdap_process_group_members_2307(grp_state, el); + break; - DEBUG(7, ("member #%d (%s): not found in sysdb, searching LDAP\n", - i, (char *)el->values[i].data)); + case SDAP_SCHEMA_IPA_V1: + case SDAP_SCHEMA_AD: + case SDAP_SCHEMA_RFC2307BIS: + ret = sdap_process_group_members_2307bis(req, grp_state, el); + break; - /* - * Issue at most GROUPMEMBER_REQ_PARALLEL LDAP searches at once. - * The rest is sent while the results are being processed. - * We limit the number as of request here, as the Server might - * enforce limits on the number of pending operations per - * connection. - */ - if (grp_state->check_count > GROUPMEMBER_REQ_PARALLEL) { - DEBUG(7, (" queueing search for: %s\n", - (char*)el->values[i].data)); - if (!grp_state->queued_members) { - DEBUG(7,("Allocating queue for %d members\n", - el->num_values - grp_state->check_count)); - grp_state->queued_members = talloc_array(grp_state, char *, - el->num_values - grp_state->check_count + 1); - if (!grp_state->queued_members) { - ret = ENOMEM; - goto done; - } - } - grp_state->queued_members[queue_len] = (char*)el->values[i].data; - queue_len++; - } else { - struct tevent_req *subreq = - sdap_get_generic_send(grp_state, - ev, opts, sh, - (char *)el->values[i].data, - LDAP_SCOPE_BASE, - filter, attrs, - opts->user_map, - SDAP_OPTS_USER); - if (!subreq) { - ret = ENOMEM; - goto done; - } - tevent_req_set_callback(subreq, sdap_process_group_members, req); - } - grp_state->check_count++; - } else { + default: + DEBUG(1, ("Unknown schema type %d\n", opts->schema_type)); + ret = EINVAL; + break; + } + +done: + /* We managed to process all the entries */ + /* EBUSY means we need to wait for entries in LDAP */ + if (ret == EOK) { + DEBUG(7, ("All group members processed\n")); + tevent_req_done(req); + tevent_req_post(req, ev); + } + + if (ret != EOK && ret != EBUSY) { + tevent_req_error(req, ret); + tevent_req_post(req, ev); + } + return req; +} + +static int +sdap_process_missing_member_2307bis(struct tevent_req *req, + char *user_dn, + int num_users); + +static int +sdap_process_group_members_2307bis(struct tevent_req *req, + struct sdap_process_group_state *state, + struct ldb_message_element *memberel) +{ + char *member_dn; + char *strdn; + int ret; + int i; + + for (i=0; i < memberel->num_values; i++) { + member_dn = (char *)memberel->values[i].data; + + ret = sdap_find_entry_by_origDN(state->sysdb_dns->values, + state->sysdb, + state->dom, + member_dn, + &strdn); + if (ret == EOK) { /* * User already cached in sysdb. Remember the sysdb DN for later * use by sdap_save_groups() */ - DEBUG(7, ("sysdbdn: %s\n", sysdb_dn)); - grp_state->sysdb_dns->values[grp_state->sysdb_dns->num_values].data = - (uint8_t*)sysdb_dn; - grp_state->sysdb_dns->values[grp_state->sysdb_dns->num_values].length = - strlen(sysdb_dn); - grp_state->sysdb_dns->num_values++; + DEBUG(7, ("sysdbdn: %s\n", strdn)); + state->sysdb_dns->values[state->sysdb_dns->num_values].data = + (uint8_t*) strdn; + state->sysdb_dns->values[state->sysdb_dns->num_values].length = + strlen(strdn); + state->sysdb_dns->num_values++; + } else if (ret == ENOENT) { + /* The user is not in sysdb, need to add it */ + DEBUG(7, ("Searching LDAP for missing user entry\n")); + ret = sdap_process_missing_member_2307bis(req, + member_dn, + memberel->num_values); + if (ret != EOK) { + DEBUG(1, ("Error processing missing member #%d (%s):\n", + i, member_dn)); + return ret; + } + } else { + DEBUG(1, ("Error checking cache for member #%d (%s):\n", + i, (char *)memberel->values[i].data)); + return ret; } } - if (queue_len > 0) { - grp_state->queued_members[queue_len] = NULL; + + if (state->queue_len > 0) { + state->queued_members[state->queue_len]=NULL; } - if (grp_state->check_count == 0) { + if (state->check_count == 0) { /* * All group members are already cached in sysdb, we are done * with this group. To avoid redundant sysdb lookups, populate the * "member" attribute of the group entry with the sysdb DNs of * the members. */ - el->values = grp_state->sysdb_dns->values; - el->num_values = grp_state->sysdb_dns->num_values; ret = EOK; - goto done; + memberel->values = state->sysdb_dns->values; + memberel->num_values = state->sysdb_dns->num_values; } else { - grp_state->count = grp_state->check_count; - grp_state->new_members = talloc_zero_array(grp_state, - struct sysdb_attrs *, - grp_state->count + 1); - if (!grp_state->new_members) { - ret = ENOMEM; + state->count = state->check_count; + state->new_members = talloc_zero_array(state, + struct sysdb_attrs *, + state->count + 1); + if (!state->new_members) { + return ENOMEM; + } + ret = EBUSY; + } + + return ret; +} + +static int +sdap_process_missing_member_2307(struct sdap_process_group_state *state, + char *username, bool *in_transaction); + +static int +sdap_process_group_members_2307(struct sdap_process_group_state *state, + struct ldb_message_element *memberel) +{ + struct ldb_message *msg; + bool in_transaction; + char *member_name; + char *strdn; + int ret; + int i; + + for (i=0; i < memberel->num_values; i++) { + member_name = (char *)memberel->values[i].data; + ret = sysdb_search_user_by_name(state, state->sysdb, + state->dom, member_name, + NULL, &msg); + if (ret == EOK) { + strdn = sysdb_user_strdn(state->sysdb_dns->values, + state->dom->name, + member_name); + if (!strdn) { + ret = ENOMEM; + goto done; + } + /* + * User already cached in sysdb. Remember the sysdb DN for later + * use by sdap_save_groups() + */ + DEBUG(7,("Member already cached in sysdb: %s\n", strdn)); + state->sysdb_dns->values[state->sysdb_dns->num_values].data = + (uint8_t *) strdn; + state->sysdb_dns->values[state->sysdb_dns->num_values].length = + strlen(strdn); + state->sysdb_dns->num_values++; + } else if (ret == ENOENT) { + /* The user is not in sysdb, need to add it */ + DEBUG(7, ("member #%d (%s): not found in sysdb\n", + i, member_name)); + + ret = sdap_process_missing_member_2307(state, member_name, + &in_transaction); + if (ret != EOK) { + DEBUG(1, ("Error processing missing member #%d (%s):\n", + i, member_name)); + goto done; + } + } else { + DEBUG(1, ("Error checking cache for member #%d (%s):\n", + i, (char *) memberel->values[i].data)); + goto done; + } + } + + /* sdap_process_missing_member_2307 starts transaction */ + if (in_transaction) { + ret = sysdb_transaction_commit(state->sysdb); + if (ret) { + DEBUG(2, ("Cannot commit sysdb transaction\n")); goto done; } } - return req; + ret = EOK; + memberel->values = state->sysdb_dns->values; + memberel->num_values = state->sysdb_dns->num_values; done: - if (ret) { - tevent_req_error(req, ret); + return ret; +} + + +static int +sdap_process_missing_member_2307bis(struct tevent_req *req, + char *user_dn, + int num_users) +{ + struct sdap_process_group_state *grp_state = + tevent_req_data(req, struct sdap_process_group_state); + struct tevent_req *subreq; + + /* + * Issue at most GROUPMEMBER_REQ_PARALLEL LDAP searches at once. + * The rest is sent while the results are being processed. + * We limit the number as of request here, as the Server might + * enforce limits on the number of pending operations per + * connection. + */ + if (grp_state->check_count > GROUPMEMBER_REQ_PARALLEL) { + DEBUG(7, (" queueing search for: %s\n", user_dn)); + if (!grp_state->queued_members) { + DEBUG(7, ("Allocating queue for %d members\n", + num_users - grp_state->check_count)); + + grp_state->queued_members = talloc_array(grp_state, char *, + num_users - grp_state->check_count + 1); + if (!grp_state->queued_members) { + return ENOMEM; + } + } + grp_state->queued_members[grp_state->queue_len] = user_dn; + grp_state->queue_len++; } else { - tevent_req_done(req); + subreq = sdap_get_generic_send(grp_state, + grp_state->ev, + grp_state->opts, + grp_state->sh, + user_dn, + LDAP_SCOPE_BASE, + grp_state->filter, + grp_state->attrs, + grp_state->opts->user_map, + SDAP_OPTS_USER); + if (!subreq) { + return ENOMEM; + } + tevent_req_set_callback(subreq, sdap_process_group_members, req); } - tevent_req_post(req,ev); - return req; + + grp_state->check_count++; + return EOK; +} + +static int +sdap_process_missing_member_2307(struct sdap_process_group_state *state, + char *username, bool *in_transaction) +{ + int ret; + struct ldb_dn *dn; + char* dn_string; + + DEBUG(7, ("Adding a dummy entry\n")); + + if (!in_transaction) return EINVAL; + + if (!*in_transaction) { + ret = sysdb_transaction_start(state->sysdb); + if (ret != EOK) { + DEBUG(1, ("Cannot start sysdb transaction: [%d]: %s\n", + ret, strerror(ret))); + return ret; + } + *in_transaction = true; + } + + ret = sysdb_add_fake_user(state->sysdb, state->dom, username); + if (ret != EOK) { + DEBUG(1, ("Cannot store fake user entry: [%d]: %s\n", + ret, strerror(ret))); + goto fail; + } + + /* + * Convert the just received DN into the corresponding sysdb DN + * for saving into member attribute of the group + */ + dn = sysdb_user_dn(state->sysdb, state, state->dom->name, + (char*) username); + if (!dn) { + ret = ENOMEM; + goto fail; + } + + dn_string = ldb_dn_alloc_linearized(state->sysdb_dns->values, dn); + if (!dn_string) { + ret = ENOMEM; + goto fail; + } + + state->sysdb_dns->values[state->sysdb_dns->num_values].data = + (uint8_t *) dn_string; + state->sysdb_dns->values[state->sysdb_dns->num_values].length = + strlen(dn_string); + state->sysdb_dns->num_values++; + + return EOK; +fail: + if (*in_transaction) { + sysdb_transaction_cancel(state->sysdb); + } + return ret; } static void sdap_process_group_members(struct tevent_req *subreq) -- 1.7.2.3
0001-sysdb-interface-for-adding-fake-users.patch.sig
Description: PGP signature
0002-Save-dummy-member-users-during-RFC2307-getgr-nam-uid.patch.sig
Description: PGP signature
_______________________________________________ sssd-devel mailing list sssd-devel@lists.fedorahosted.org https://fedorahosted.org/mailman/listinfo/sssd-devel