errno_t sysdb_set_service_attr(struct sss_domain_info *domain, const char *name, struct sysdb_attrs *attrs, int mod_op) { errno_t ret; struct ldb_dn *dn; TALLOC_CTX *tmp_ctx; tmp_ctx = talloc_new(NULL); if (!tmp_ctx) { return ENOMEM; } dn = sysdb_svc_dn(domain->sysdb, tmp_ctx, domain->name, name); if (!dn) { ret = ENOMEM; goto done; } ret = sysdb_set_entry_attr(domain->sysdb, dn, attrs, mod_op); done: talloc_free(tmp_ctx); return ret; }
errno_t check_if_cached_upn_needs_update(struct sysdb_ctx *sysdb, struct sss_domain_info *domain, const char *user, const char *upn) { TALLOC_CTX *tmp_ctx; int ret; int sret; const char *attrs[] = {SYSDB_UPN, SYSDB_CANONICAL_UPN, NULL}; struct sysdb_attrs *new_attrs; struct ldb_result *res; bool in_transaction = false; const char *cached_upn; const char *cached_canonical_upn; if (sysdb == NULL || user == NULL || upn == NULL) { return EINVAL; } tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); return ENOMEM; } ret = sysdb_get_user_attr(tmp_ctx, domain, user, attrs, &res); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_user_attr failed.\n"); goto done; } if (res->count != 1) { DEBUG(SSSDBG_OP_FAILURE, "[%d] user objects for name [%s] found, " \ "expected 1.\n", res->count, user); ret = EINVAL; goto done; } cached_upn = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_UPN, NULL); if (cached_upn != NULL && strcmp(cached_upn, upn) == 0) { DEBUG(SSSDBG_TRACE_ALL, "Cached UPN and new one match, " "nothing to do.\n"); ret = EOK; goto done; } cached_canonical_upn = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_CANONICAL_UPN, NULL); if (cached_canonical_upn != NULL && strcmp(cached_canonical_upn, upn) == 0) { DEBUG(SSSDBG_TRACE_ALL, "Cached canonical UPN and new one match, " "nothing to do.\n"); ret = EOK; goto done; } DEBUG(SSSDBG_TRACE_LIBS, "Replacing canonical UPN [%s] with [%s] " \ "for user [%s].\n", cached_canonical_upn == NULL ? "empty" : cached_canonical_upn, upn, user); new_attrs = sysdb_new_attrs(tmp_ctx); if (new_attrs == NULL) { DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n"); ret = ENOMEM; goto done; } ret = sysdb_attrs_add_string(new_attrs, SYSDB_CANONICAL_UPN, upn); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n"); goto done; } ret = sysdb_transaction_start(sysdb); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "Error %d starting transaction (%s)\n", ret, strerror(ret)); goto done; } in_transaction = true; ret = sysdb_set_entry_attr(sysdb, res->msgs[0]->dn, new_attrs, cached_canonical_upn == NULL ? SYSDB_MOD_ADD : SYSDB_MOD_REP); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "sysdb_set_entry_attr failed [%d][%s].\n", ret, strerror(ret)); goto done; } ret = sysdb_transaction_commit(sysdb); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "Failed to commit transaction!\n"); goto done; } in_transaction = false; ret = EOK; done: if (in_transaction) { sret = sysdb_transaction_cancel(sysdb); if (sret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n"); } } talloc_free(tmp_ctx); return ret; }
errno_t sysdb_store_service(struct sss_domain_info *domain, const char *primary_name, int port, const char **aliases, const char **protocols, struct sysdb_attrs *extra_attrs, char **remove_attrs, uint64_t cache_timeout, time_t now) { errno_t ret; errno_t sret; TALLOC_CTX *tmp_ctx; bool in_transaction = false; struct ldb_result *res = NULL; const char *name; unsigned int i; struct ldb_dn *update_dn = NULL; struct sysdb_attrs *attrs; struct sysdb_ctx *sysdb; tmp_ctx = talloc_new(NULL); if (!tmp_ctx) return ENOMEM; sysdb = domain->sysdb; ret = sysdb_transaction_start(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n"); goto done; } in_transaction = true; /* Check that the port is unique * If the port appears for any service other than * the one matching the primary_name, we need to * remove them so that getservbyport() can work * properly. Last entry saved to the cache should * always "win". */ ret = sysdb_getservbyport(tmp_ctx, domain, port, NULL, &res); if (ret != EOK && ret != ENOENT) { goto done; } else if (ret != ENOENT) { if (res->count != 1) { /* Somehow the cache has multiple entries with * the same port. This is corrupted. We'll delete * them all to sort it out. */ for (i = 0; i < res->count; i++) { DEBUG(SSSDBG_TRACE_FUNC, "Corrupt cache entry [%s] detected. Deleting\n", ldb_dn_canonical_string(tmp_ctx, res->msgs[i]->dn)); ret = sysdb_delete_entry(sysdb, res->msgs[i]->dn, true); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, "Could not delete corrupt cache entry [%s]\n", ldb_dn_canonical_string(tmp_ctx, res->msgs[i]->dn)); goto done; } } } else { /* Check whether this is the same name as we're currently * saving to the cache. */ name = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, NULL); if (!name || strcmp(name, primary_name) != 0) { if (!name) { DEBUG(SSSDBG_CRIT_FAILURE, "A service with no name?\n"); /* Corrupted */ } /* Either this is a corrupt entry or it's another service * claiming ownership of this port. In order to account * for port reassignments, we need to delete the old entry. */ DEBUG(SSSDBG_TRACE_FUNC, "Corrupt or replaced cache entry [%s] detected. " "Deleting\n", ldb_dn_canonical_string(tmp_ctx, res->msgs[0]->dn)); ret = sysdb_delete_entry(sysdb, res->msgs[0]->dn, true); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, "Could not delete cache entry [%s]\n", ldb_dn_canonical_string(tmp_ctx, res->msgs[0]->dn)); } } } } talloc_zfree(res); /* Ok, ports should now be unique. Now look * the service up by name to determine if we * need to update existing entries or modify * aliases. */ ret = sysdb_getservbyname(tmp_ctx, domain, primary_name, NULL, &res); if (ret != EOK && ret != ENOENT) { goto done; } else if (ret != ENOENT) { /* Found entries */ for (i = 0; i < res->count; i++) { /* Check whether this is the same name as we're currently * saving to the cache. */ name = ldb_msg_find_attr_as_string(res->msgs[i], SYSDB_NAME, NULL); if (!name) { /* Corrupted */ DEBUG(SSSDBG_CRIT_FAILURE, "A service with no name?\n"); DEBUG(SSSDBG_TRACE_FUNC, "Corrupt cache entry [%s] detected. Deleting\n", ldb_dn_canonical_string(tmp_ctx, res->msgs[i]->dn)); ret = sysdb_delete_entry(sysdb, res->msgs[i]->dn, true); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, "Could not delete corrupt cache entry [%s]\n", ldb_dn_canonical_string(tmp_ctx, res->msgs[i]->dn)); goto done; } } else if (strcmp(name, primary_name) == 0) { /* This is the same service name, so we need * to update this entry with the values * provided. */ if(update_dn) { DEBUG(SSSDBG_CRIT_FAILURE, "Two existing services with the same name: [%s]? " "Deleting both.\n", primary_name); /* Delete the entry from the previous pass */ ret = sysdb_delete_entry(sysdb, update_dn, true); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, "Could not delete cache entry [%s]\n", ldb_dn_canonical_string(tmp_ctx, update_dn)); goto done; } /* Delete the new entry as well */ ret = sysdb_delete_entry(sysdb, res->msgs[i]->dn, true); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, "Could not delete cache entry [%s]\n", ldb_dn_canonical_string(tmp_ctx, res->msgs[i]->dn)); goto done; } update_dn = NULL; } else { update_dn = talloc_steal(tmp_ctx, res->msgs[i]->dn); } } else { /* Another service is claiming this name as an alias. * In order to account for aliases being promoted to * primary names, we need to make sure to remove the * old alias entry. */ ret = sysdb_svc_remove_alias(sysdb, res->msgs[i]->dn, primary_name); if (ret != EOK) goto done; } } talloc_zfree(res); } if (update_dn) { /* Update the existing entry */ ret = sysdb_svc_update(sysdb, update_dn, port, aliases, protocols); } else { /* Add a new entry */ ret = sysdb_svc_add(tmp_ctx, domain, primary_name, port, aliases, protocols, &update_dn); } if (ret != EOK) goto done; /* Set the cache timeout */ if (!extra_attrs) { attrs = sysdb_new_attrs(tmp_ctx); if (!attrs) { ret = ENOMEM; goto done; } } else { attrs = extra_attrs; } ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_UPDATE, now); if (ret) goto done; ret = sysdb_attrs_add_time_t(attrs, SYSDB_CACHE_EXPIRE, ((cache_timeout) ? (now + cache_timeout) : 0)); if (ret) goto done; ret = sysdb_set_entry_attr(sysdb, update_dn, attrs, SYSDB_MOD_REP); if (ret != EOK) goto done; if (remove_attrs) { ret = sysdb_remove_attrs(domain, primary_name, SYSDB_MEMBER_SERVICE, remove_attrs); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, "Could not remove missing attributes: [%s]\n", strerror(ret)); goto done; } } ret = sysdb_transaction_commit(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n"); goto done; } in_transaction = false; done: if (in_transaction) { sret = sysdb_transaction_cancel(sysdb); if (sret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n"); } } talloc_free(tmp_ctx); return ret; }
static errno_t add_ad_user_to_cached_groups(struct ldb_dn *user_dn, struct sss_domain_info *user_dom, struct sss_domain_info *group_dom, char **groups, bool *missing_groups) { size_t c; struct sysdb_attrs *user_attrs; size_t msgs_count; struct ldb_message **msgs; char *subfilter; TALLOC_CTX *tmp_ctx; int ret; *missing_groups = false; tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); return ENOMEM; } for (c = 0; groups[c] != NULL; c++) { if (groups[c][0] == '\0') { continue; } subfilter = talloc_asprintf(tmp_ctx, "(%s=%s)", SYSDB_ORIG_DN, groups[c]); if (subfilter == NULL) { DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n"); ret = ENOMEM; goto done; } ret = sysdb_search_groups(tmp_ctx, group_dom, subfilter, NULL, &msgs_count, &msgs); if (ret != EOK) { if (ret == ENOENT) { DEBUG(SSSDBG_TRACE_ALL, "Group [%s] not in the cache.\n", groups[c]); *missing_groups = true; continue; } else { DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_entry failed.\n"); goto done; } } /* TODO? Do we have to remove members as well? I think not because the AD * query before removes all memberships. */ ret = sysdb_mod_group_member(group_dom, user_dn, msgs[0]->dn, LDB_FLAG_MOD_ADD); if (ret != EOK && ret != EEXIST) { DEBUG(SSSDBG_OP_FAILURE, "sysdb_mod_group_member failed.\n"); goto done; } user_attrs = sysdb_new_attrs(tmp_ctx); if (user_attrs == NULL) { DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n"); ret = ENOMEM; goto done; } ret = sysdb_attrs_add_string(user_attrs, SYSDB_ORIG_MEMBEROF, groups[c]); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n"); goto done; } ret = sysdb_set_entry_attr(user_dom->sysdb, user_dn, user_attrs, LDB_FLAG_MOD_ADD); if (ret != EOK && ret != EEXIST) { DEBUG(SSSDBG_OP_FAILURE, "sysdb_set_entry_attr failed.\n"); goto done; } /* mark group as already processed */ groups[c][0] = '\0'; } ret = EOK; done: talloc_free(tmp_ctx); return ret; }