static int seed_cache_user(struct seed_ctx *sctx) { bool in_transaction = false; int ret = EOK; errno_t sret; ret = sysdb_transaction_start(sctx->sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("sysdb transaction start failure\n")); goto done; } in_transaction = true; if (sctx->user_cached == false) { ret = sysdb_add_user(sctx->sysdb, sctx->domain, sctx->uctx->name, sctx->uctx->uid, sctx->uctx->gid, sctx->uctx->gecos, sctx->uctx->home, sctx->uctx->shell, NULL, NULL, 0, 0); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to add user to the cache. (%d)[%s]\n", ret, strerror(ret))); ERROR("Failed to create user cache entry\n"); goto done; } } ret = sysdb_cache_password(sctx->sysdb, sctx->domain, sctx->uctx->name, sctx->uctx->password); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to cache password. (%d)[%s]\n", ret, strerror(ret))); ERROR("Failed to cache password\n"); goto done; } ret = sysdb_transaction_commit(sctx->sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("sysdb transaction commit failure\n")); goto done; } in_transaction = false; done: if (in_transaction == true) { sret = sysdb_transaction_cancel(sctx->sysdb); if (sret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Failed to cancel transaction\n")); } } return ret; }
int main(int argc, const char *argv[]) { errno_t ret; struct cache_tool_ctx *tctx = NULL; struct sysdb_ctx *sysdb; bool skipped = true; struct sss_domain_info *dinfo; ret = init_context(argc, argv, &tctx); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Error initializing context for the application\n"); goto done; } for (dinfo = tctx->domains; dinfo; dinfo = get_next_domain(dinfo, true)) { sysdb = dinfo->sysdb; if (!IS_SUBDOMAIN(dinfo)) { /* Update list of subdomains for this domain */ ret = sysdb_update_subdomains(dinfo); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, "Failed to update subdomains for domain %s.\n", dinfo->name); } } sysdb = dinfo->sysdb; /* Update filters for each domain */ ret = update_all_filters(tctx, dinfo); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to update filters.\n"); goto done; } ret = sysdb_transaction_start(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Could not start the transaction!\n"); goto done; } skipped &= !invalidate_entries(tctx, dinfo, TYPE_USER, tctx->user_filter, tctx->user_name); skipped &= !invalidate_entries(tctx, dinfo, TYPE_GROUP, tctx->group_filter, tctx->group_name); skipped &= !invalidate_entries(tctx, dinfo, TYPE_NETGROUP, tctx->netgroup_filter, tctx->netgroup_name); skipped &= !invalidate_entries(tctx, dinfo, TYPE_SERVICE, tctx->service_filter, tctx->service_name); skipped &= !invalidate_entries(tctx, dinfo, TYPE_AUTOFSMAP, tctx->autofs_filter, tctx->autofs_name); ret = sysdb_transaction_commit(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Could not commit the transaction!\n"); ret = sysdb_transaction_cancel(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n"); } } } if (skipped == true) { ERROR("No cache object matched the specified search\n"); ret = ENOENT; goto done; } else { ret = sss_memcache_clear_all(); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to clear memory cache.\n"); goto done; } } ret = EOK; done: if (tctx) talloc_free(tctx); return ret; }
errno_t enum_services(struct proxy_id_ctx *ctx, struct sysdb_ctx *sysdb, struct sss_domain_info *dom) { TALLOC_CTX *tmpctx; bool in_transaction = false; struct servent *svc; enum nss_status status; size_t buflen; char *buffer; char *newbuf; errno_t ret, sret; time_t now = time(NULL); const char **protocols; const char **cased_aliases; bool again; DEBUG(SSSDBG_TRACE_FUNC, "Enumerating services\n"); tmpctx = talloc_new(NULL); if (!tmpctx) { return ENOMEM; } svc = talloc(tmpctx, struct servent); if (!svc) { ret = ENOMEM; goto done; } buflen = DEFAULT_BUFSIZE; buffer = talloc_size(tmpctx, buflen); if (!buffer) { ret = ENOMEM; goto done; } protocols = talloc_zero_array(tmpctx, const char *, 2); if (protocols == NULL) { ret = ENOMEM; goto done; } ret = sysdb_transaction_start(sysdb); if (ret) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n"); goto done; } in_transaction = true; status = ctx->ops.setservent(); if (status != NSS_STATUS_SUCCESS) { ret = EIO; goto done; } do { again = false; /* always zero out the svc structure */ memset(svc, 0, sizeof(struct servent)); /* get entry */ status = ctx->ops.getservent_r(svc, 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) { ret = ENOMEM; goto done; } buffer = newbuf; again = true; break; case NSS_STATUS_NOTFOUND: /* we are done here */ DEBUG(SSSDBG_TRACE_FUNC, "Enumeration completed.\n"); ret = sysdb_transaction_commit(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n"); goto done; } in_transaction = false; break; case NSS_STATUS_SUCCESS: DEBUG(SSSDBG_TRACE_INTERNAL, "Service found (%s, %d/%s)\n", svc->s_name, svc->s_port, svc->s_proto); protocols[0] = sss_get_cased_name(protocols, svc->s_proto, dom->case_sensitive); if (!protocols[0]) { ret = ENOMEM; goto done; } protocols[1] = NULL; ret = sss_get_cased_name_list(tmpctx, (const char * const *) svc->s_aliases, dom->case_sensitive, &cased_aliases); if (ret != EOK) { /* Do not fail completely on errors. * Just report the failure to save and go on */ DEBUG(SSSDBG_OP_FAILURE, "Failed to store service [%s]. Ignoring.\n", strerror(ret)); again = true; break; } ret = sysdb_store_service(dom, svc->s_name, svc->s_port, cased_aliases, protocols, NULL, NULL, dom->service_timeout, now); if (ret) { /* Do not fail completely on errors. * Just report the failure to save and go on */ DEBUG(SSSDBG_OP_FAILURE, "Failed to store service [%s]. Ignoring.\n", strerror(ret)); } again = true; break; case NSS_STATUS_UNAVAIL: /* "remote" backend unavailable. Enter offline mode */ ret = ENXIO; break; default: ret = EIO; DEBUG(SSSDBG_CRIT_FAILURE, "proxy -> getservent_r failed (%d)[%s]\n", ret, strerror(ret)); break; } } while (again); done: talloc_zfree(tmpctx); if (in_transaction) { sret = sysdb_transaction_cancel(sysdb); if (sret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction! [%s]\n", strerror(sret)); } } ctx->ops.endservent(); return ret; }
static int krb5_mod_ccname(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, struct sss_domain_info *domain, const char *name, const char *ccname, int mod_op) { TALLOC_CTX *tmpctx; struct sysdb_attrs *attrs; int ret; errno_t sret; bool in_transaction = false; if (name == NULL || ccname == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, "Missing user or ccache name.\n"); return EINVAL; } if (mod_op != SYSDB_MOD_REP && mod_op != SYSDB_MOD_DEL) { DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported operation [%d].\n", mod_op); return EINVAL; } DEBUG(SSSDBG_TRACE_ALL, "%s ccname [%s] for user [%s].\n", mod_op == SYSDB_MOD_REP ? "Save" : "Delete", ccname, name); tmpctx = talloc_new(mem_ctx); if (!tmpctx) { return ENOMEM; } attrs = sysdb_new_attrs(tmpctx); if (!attrs) { ret = ENOMEM; goto done; } ret = sysdb_attrs_add_string(attrs, SYSDB_CCACHE_FILE, ccname); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_attrs_add_string failed.\n"); goto done; } ret = sysdb_transaction_start(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Error %d starting transaction (%s)\n", ret, strerror(ret)); goto done; } in_transaction = true; ret = sysdb_set_user_attr(domain, name, attrs, mod_op); if (ret != EOK) { DEBUG(SSSDBG_TRACE_FUNC, "Error: %d (%s)\n", ret, 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, "Failed to cancel transaction\n"); } } talloc_zfree(tmpctx); return ret; }
static int krb5_mod_ccname(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, const char *name, const char *ccname, int mod_op) { TALLOC_CTX *tmpctx; struct sysdb_attrs *attrs; int ret; if (name == NULL || ccname == NULL) { DEBUG(1, ("Missing user or ccache name.\n")); return EINVAL; } if (mod_op != SYSDB_MOD_REP && mod_op != SYSDB_MOD_DEL) { DEBUG(1, ("Unsupported operation [%d].\n", mod_op)); return EINVAL; } DEBUG(9, ("%s ccname [%s] for user [%s].\n", mod_op == SYSDB_MOD_REP ? "Save" : "Delete", ccname, name)); tmpctx = talloc_new(mem_ctx); if (!tmpctx) { return ENOMEM; } attrs = sysdb_new_attrs(mem_ctx); if (!attrs) { ret = ENOMEM; goto done; } ret = sysdb_attrs_add_string(attrs, SYSDB_CCACHE_FILE, ccname); if (ret != EOK) { DEBUG(1, ("sysdb_attrs_add_string failed.\n")); goto done; } ret = sysdb_transaction_start(sysdb); if (ret != EOK) { DEBUG(6, ("Error %d starting transaction (%s)\n", ret, strerror(ret))); goto done; } ret = sysdb_set_user_attr(sysdb, name, attrs, mod_op); if (ret != EOK) { DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret))); sysdb_transaction_cancel(sysdb); goto done; } ret = sysdb_transaction_commit(sysdb); if (ret != EOK) { DEBUG(1, ("Failed to commit transaction!\n")); } done: talloc_zfree(tmpctx); 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 int get_initgr(TALLOC_CTX *mem_ctx, struct proxy_id_ctx *ctx, struct sysdb_ctx *sysdb, struct sss_domain_info *dom, const char *name) { TALLOC_CTX *tmpctx; bool in_transaction = false; struct passwd *pwd; enum nss_status status; char *buffer; size_t buflen; int ret; errno_t sret; bool del_user; uid_t uid; struct ldb_result *cached_pwd = NULL; const char *real_name = NULL; tmpctx = talloc_new(mem_ctx); if (!tmpctx) { return ENOMEM; } pwd = talloc_zero(tmpctx, struct passwd); if (!pwd) { ret = ENOMEM; goto fail; } buflen = DEFAULT_BUFSIZE; buffer = talloc_size(tmpctx, buflen); if (!buffer) { ret = ENOMEM; goto fail; } ret = sysdb_transaction_start(sysdb); if (ret) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n"); 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); 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) { ret = delete_user(dom, name, 0); if (ret) { DEBUG(SSSDBG_OP_FAILURE, "Could not delete user\n"); goto fail; } goto done; } uid = pwd->pw_uid; memset(buffer, 0, buflen); /* Canonicalize the username in case it was actually an alias */ if (ctx->fast_alias == true) { ret = sysdb_getpwuid(tmpctx, dom, uid, &cached_pwd); if (ret != EOK) { /* Non-fatal, attempt to canonicalize online */ DEBUG(SSSDBG_TRACE_FUNC, "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) { ret = delete_user(dom, name, uid); if (ret) { DEBUG(SSSDBG_OP_FAILURE, "Could not delete user\n"); goto fail; } goto done; } ret = save_user(dom, !dom->case_sensitive, pwd, real_name, 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) { sret = sysdb_transaction_cancel(sysdb); if (sret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n"); } } return ret; }
static int save_group(struct sysdb_ctx *sysdb, struct sss_domain_info *dom, struct group *grp, const char *real_name, const char *alias, uint64_t cache_timeout) { errno_t ret, sret; struct sysdb_attrs *attrs = NULL; const char *cased_alias; const char *lc_gr_name = NULL; TALLOC_CTX *tmp_ctx; time_t now = time(NULL); bool in_transaction = false; tmp_ctx = talloc_new(NULL); if (!tmp_ctx) { return ENOMEM; } DEBUG_GR_MEM(SSSDBG_TRACE_LIBS, grp); ret = sysdb_transaction_start(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n"); goto done; } in_transaction = true; if (grp->gr_mem && grp->gr_mem[0]) { attrs = sysdb_new_attrs(tmp_ctx); if (!attrs) { DEBUG(SSSDBG_CRIT_FAILURE, "Allocation error ?!\n"); ret = ENOMEM; goto done; } ret = sysdb_attrs_users_from_str_list( attrs, SYSDB_MEMBER, dom->name, (const char *const *)grp->gr_mem); if (ret) { DEBUG(SSSDBG_OP_FAILURE, "Could not add group members\n"); goto done; } /* Create ghost users */ ret = proxy_process_missing_users(sysdb, dom, attrs, grp, now); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "Could not add missing members\n"); goto done; } } if (dom->case_sensitive == false || alias) { if (!attrs) { attrs = sysdb_new_attrs(tmp_ctx); if (!attrs) { DEBUG(SSSDBG_CRIT_FAILURE, "Allocation error ?!\n"); ret = ENOMEM; goto done; } } } if (dom->case_sensitive == false) { lc_gr_name = sss_tc_utf8_str_tolower(attrs, grp->gr_name); if (lc_gr_name == NULL) { DEBUG(SSSDBG_OP_FAILURE, "Cannot convert name to lowercase.\n"); ret = ENOMEM; goto done; } ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, lc_gr_name); if (ret != EOK) { goto done; } } if (alias) { cased_alias = sss_get_cased_name(attrs, alias, dom->case_sensitive); if (!cased_alias) { ret = ENOMEM; DEBUG(SSSDBG_OP_FAILURE, "Could not add name alias\n"); goto done; } if (lc_gr_name == NULL || strcmp(cased_alias, lc_gr_name)) { ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, cased_alias); if (ret) { DEBUG(SSSDBG_OP_FAILURE, "Could not add name alias\n"); goto done; } } } ret = sysdb_store_group(dom, real_name, grp->gr_gid, attrs, cache_timeout, now); if (ret) { DEBUG(SSSDBG_OP_FAILURE, "Could not add group to cache\n"); goto done; } ret = sysdb_transaction_commit(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Could not commit transaction: [%s]\n", strerror(ret)); 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 int enum_users(TALLOC_CTX *mem_ctx, struct proxy_id_ctx *ctx, struct sysdb_ctx *sysdb, struct sss_domain_info *dom) { TALLOC_CTX *tmpctx; bool in_transaction = false; struct passwd *pwd; enum nss_status status; size_t buflen; char *buffer; char *newbuf; int ret; errno_t sret; bool again; char *name; DEBUG(SSSDBG_TRACE_LIBS, "Enumerating users\n"); tmpctx = talloc_new(mem_ctx); if (!tmpctx) { return ENOMEM; } pwd = talloc_zero(tmpctx, struct passwd); if (!pwd) { ret = ENOMEM; goto done; } buflen = DEFAULT_BUFSIZE; buffer = talloc_size(tmpctx, buflen); if (!buffer) { ret = ENOMEM; goto done; } ret = sysdb_transaction_start(sysdb); if (ret) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n"); goto done; } in_transaction = true; status = ctx->ops.setpwent(); if (status != NSS_STATUS_SUCCESS) { ret = EIO; goto done; } do { again = false; /* always zero out the pwd structure */ memset(pwd, 0, sizeof(struct passwd)); /* get entry */ status = ctx->ops.getpwent_r(pwd, 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) { ret = ENOMEM; goto done; } buffer = newbuf; again = true; break; case NSS_STATUS_NOTFOUND: /* we are done here */ DEBUG(SSSDBG_TRACE_LIBS, "Enumeration completed.\n"); ret = sysdb_transaction_commit(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n"); goto done; } in_transaction = false; break; case NSS_STATUS_SUCCESS: DEBUG(SSSDBG_TRACE_LIBS, "User found (%s, %"SPRIuid", %"SPRIgid")\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(SSSDBG_OP_FAILURE, "User [%s] filtered out! (id out" " of range)\n", pwd->pw_name); again = true; break; } name = sss_create_internal_fqname(tmpctx, pwd->pw_name, dom->name); if (name == NULL) { DEBUG(SSSDBG_OP_FAILURE, "failed to create internal name '%s'\n", pwd->pw_name); goto done; } ret = save_user(dom, pwd, name, NULL); if (ret) { /* Do not fail completely on errors. * Just report the failure to save and go on */ DEBUG(SSSDBG_OP_FAILURE, "Failed to store user %s." " Ignoring.\n", pwd->pw_name); } again = true; break; case NSS_STATUS_UNAVAIL: /* "remote" backend unavailable. Enter offline mode */ ret = ENXIO; break; default: ret = EIO; DEBUG(SSSDBG_OP_FAILURE, "proxy -> getpwent_r failed (%d)[%s]" "\n", ret, strerror(ret)); break; } } while (again); done: talloc_zfree(tmpctx); if (in_transaction) { sret = sysdb_transaction_cancel(sysdb); if (sret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n"); } } ctx->ops.endpwent(); return ret; }
static int save_group(struct sysdb_ctx *sysdb, struct sss_domain_info *dom, struct group *grp, const char *real_name, /* already qualified */ const char *alias) /* already qualified */ { errno_t ret, sret; struct sysdb_attrs *attrs = NULL; TALLOC_CTX *tmp_ctx; time_t now = time(NULL); bool in_transaction = false; char **fq_gr_mem; tmp_ctx = talloc_new(NULL); if (!tmp_ctx) { return ENOMEM; } DEBUG_GR_MEM(SSSDBG_TRACE_LIBS, grp); ret = sysdb_transaction_start(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n"); goto done; } in_transaction = true; if (grp->gr_mem && grp->gr_mem[0]) { attrs = sysdb_new_attrs(tmp_ctx); if (!attrs) { DEBUG(SSSDBG_CRIT_FAILURE, "Allocation error ?!\n"); ret = ENOMEM; goto done; } fq_gr_mem = sss_create_internal_fqname_list( tmp_ctx, (const char *const*) grp->gr_mem, dom->name); if (fq_gr_mem == NULL) { ret = ENOMEM; goto done; } ret = sysdb_attrs_users_from_str_list( attrs, SYSDB_MEMBER, dom->name, (const char *const *) fq_gr_mem); if (ret) { DEBUG(SSSDBG_OP_FAILURE, "Could not add group members\n"); goto done; } /* Create ghost users */ ret = proxy_process_missing_users(sysdb, dom, attrs, (const char *const*) fq_gr_mem, now); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "Could not add missing members\n"); goto done; } } ret = prepare_attrs_for_saving_ops(tmp_ctx, dom->case_sensitive, real_name, alias, &attrs); if (ret != EOK) { goto done; } ret = sysdb_store_group(dom, real_name, grp->gr_gid, attrs, dom->group_timeout, now); if (ret) { DEBUG(SSSDBG_OP_FAILURE, "Could not add group to cache\n"); goto done; } ret = sysdb_transaction_commit(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Could not commit transaction: [%s]\n", strerror(ret)); 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; }
errno_t ipa_hbac_sysdb_save(struct sss_domain_info *domain, const char *primary_subdir, const char *attr_name, size_t primary_count, struct sysdb_attrs **primary, const char *group_subdir, const char *groupattr_name, size_t group_count, struct sysdb_attrs **groups) { errno_t ret, sret; bool in_transaction = false; if ((primary_count == 0 || primary == NULL) || (group_count > 0 && groups == NULL)) { /* There always has to be at least one * primary entry. */ return EINVAL; } /* Save the entries and groups to the cache */ ret = sysdb_transaction_start(domain->sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n")); goto done; }; in_transaction = true; /* First, save the specific entries */ ret = ipa_hbac_save_list(domain, true, primary_subdir, attr_name, primary_count, primary); if (ret != EOK) { DEBUG(1, ("Could not save %s. [%d][%s]\n", primary_subdir, ret, strerror(ret))); goto done; } /* Second, save the groups */ if (group_count > 0) { ret = ipa_hbac_save_list(domain, true, group_subdir, groupattr_name, group_count, groups); if (ret != EOK) { DEBUG(1, ("Could not save %s. [%d][%s]\n", group_subdir, ret, strerror(ret))); goto done; } } ret = sysdb_transaction_commit(domain->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(domain->sysdb); if (sret != EOK) { DEBUG(0, ("Could not cancel sysdb transaction\n")); } } if (ret != EOK) { DEBUG(3, ("Error [%d][%s]\n", ret, strerror(ret))); } return ret; }
static void hbac_sysdb_save(struct tevent_req *req) { errno_t ret; bool in_transaction = false; struct hbac_ctx *hbac_ctx = tevent_req_callback_data(req, struct hbac_ctx); struct be_ctx *be_ctx = be_req_get_be_ctx(hbac_ctx->be_req); struct sss_domain_info *domain = be_ctx->domain; struct ldb_dn *base_dn; struct ipa_access_ctx *access_ctx = talloc_get_type(be_ctx->bet_info[BET_ACCESS].pvt_bet_data, struct ipa_access_ctx); TALLOC_CTX *tmp_ctx; ret = ipa_hbac_rule_info_recv(req, hbac_ctx, &hbac_ctx->rule_count, &hbac_ctx->rules); talloc_zfree(req); if (ret == ENOENT) { /* No rules were found that apply to this * host. */ tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR); return; } /* Delete any rules in the sysdb so offline logins * are also denied. */ base_dn = sysdb_custom_subtree_dn(domain->sysdb, tmp_ctx, domain, HBAC_RULES_SUBDIR); if (base_dn == NULL) { talloc_free(tmp_ctx); ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR); return; } ret = sysdb_delete_recursive(domain->sysdb, base_dn, true); talloc_free(tmp_ctx); if (ret != EOK) { DEBUG(1, ("sysdb_delete_recursive failed.\n")); ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR); return; } /* If no rules are found, we default to DENY */ ipa_access_reply(hbac_ctx, PAM_PERM_DENIED); return; } if (!hbac_check_step_result(hbac_ctx, ret)) { return; } ret = sysdb_transaction_start(domain->sysdb); if (ret != EOK) { DEBUG(0, ("Could not start transaction\n")); goto fail; } in_transaction = true; /* Save the hosts */ ret = ipa_hbac_sysdb_save(domain, HBAC_HOSTS_SUBDIR, SYSDB_FQDN, hbac_ctx->host_count, hbac_ctx->hosts, HBAC_HOSTGROUPS_SUBDIR, SYSDB_NAME, hbac_ctx->hostgroup_count, hbac_ctx->hostgroups); if (ret != EOK) { DEBUG(1, ("Error saving hosts: [%d][%s]\n", ret, strerror(ret))); goto fail; } /* Save the services */ ret = ipa_hbac_sysdb_save(domain, HBAC_SERVICES_SUBDIR, IPA_CN, hbac_ctx->service_count, hbac_ctx->services, HBAC_SERVICEGROUPS_SUBDIR, IPA_CN, hbac_ctx->servicegroup_count, hbac_ctx->servicegroups); if (ret != EOK) { DEBUG(1, ("Error saving services: [%d][%s]\n", ret, strerror(ret))); goto fail; } /* Save the rules */ ret = ipa_hbac_sysdb_save(domain, HBAC_RULES_SUBDIR, IPA_UNIQUE_ID, hbac_ctx->rule_count, hbac_ctx->rules, NULL, NULL, 0, NULL); if (ret != EOK) { DEBUG(1, ("Error saving rules: [%d][%s]\n", ret, strerror(ret))); goto fail; } ret = sysdb_transaction_commit(domain->sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to commit transaction\n")); goto fail; } in_transaction = false; /* We don't need the rule data any longer, * the rest of the processing relies on * sysdb lookups. */ hbac_clear_rule_data(hbac_ctx); access_ctx->last_update = time(NULL); /* Now evaluate the request against the rules */ ipa_hbac_evaluate_rules(hbac_ctx); return; fail: if (in_transaction) { ret = sysdb_transaction_cancel(domain->sysdb); if (ret != EOK) { DEBUG(0, ("Could not cancel transaction\n")); } } ipa_access_reply(hbac_ctx, PAM_SYSTEM_ERR); }
errno_t sysdb_invalidate_autofs_maps(struct sysdb_ctx *sysdb, struct sss_domain_info *domain) { errno_t ret; TALLOC_CTX *tmp_ctx; const char *filter; struct sysdb_attrs *sys_attrs = NULL; const char *attrs[] = { SYSDB_OBJECTCLASS, SYSDB_NAME, SYSDB_CACHE_EXPIRE, NULL }; size_t count; struct ldb_message **msgs; const char *name; bool in_transaction = false; int sret; int i; tmp_ctx = talloc_new(NULL); if (!tmp_ctx) return ENOMEM; filter = talloc_asprintf(tmp_ctx, "(&(objectclass=%s)(%s=*))", SYSDB_AUTOFS_MAP_OC, SYSDB_NAME); if (!filter) { ret = ENOMEM; goto done; } ret = sysdb_search_custom(tmp_ctx, sysdb, domain, filter, AUTOFS_MAP_SUBDIR, attrs, &count, &msgs); if (ret != EOK && ret != ENOENT) { DEBUG(SSSDBG_CRIT_FAILURE, ("Error looking up autofs maps")); goto done; } else if (ret == ENOENT) { ret = EOK; goto done; } sys_attrs = sysdb_new_attrs(tmp_ctx); if (!sys_attrs) { ret = ENOMEM; goto done; } ret = sysdb_attrs_add_time_t(sys_attrs, SYSDB_CACHE_EXPIRE, 1); if (ret != EOK) { goto done; } ret = sysdb_transaction_start(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n")); goto done; } in_transaction = true; for (i = 0; i < count; i++) { name = ldb_msg_find_attr_as_string(msgs[i], SYSDB_NAME, NULL); if (!name) { DEBUG(SSSDBG_MINOR_FAILURE, ("A map with no name?\n")); continue; } ret = sysdb_set_autofsmap_attr(sysdb, domain, name, sys_attrs, SYSDB_MOD_REP); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, ("Could not expire map %s\n", name)); continue; } } ret = sysdb_transaction_commit(sysdb); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Could not commit transaction\n")); goto done; } in_transaction = false; ret = EOK; done: if (in_transaction) { sret = sysdb_transaction_cancel(sysdb); if (sret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Could not cancel transaction\n")); } } talloc_free(tmp_ctx); return ret; }
int main(int argc, const char **argv) { uid_t pc_uid = 0; const char *pc_gecos = NULL; const char *pc_home = NULL; char *pc_shell = NULL; int pc_debug = SSSDBG_DEFAULT; int pc_create_home = 0; const char *pc_username = NULL; const char *pc_skeldir = NULL; const char *pc_selinux_user = NULL; struct poptOption long_options[] = { POPT_AUTOHELP { "debug", '\0', POPT_ARG_INT | POPT_ARGFLAG_DOC_HIDDEN, &pc_debug, 0, _("The debug level to run with"), NULL }, { "uid", 'u', POPT_ARG_INT, &pc_uid, 0, _("The UID of the user"), NULL }, { "gecos", 'c', POPT_ARG_STRING, &pc_gecos, 0, _("The comment string"), NULL }, { "home", 'h', POPT_ARG_STRING, &pc_home, 0, _("Home directory"), NULL }, { "shell", 's', POPT_ARG_STRING, &pc_shell, 0, _("Login shell"), NULL }, { "groups", 'G', POPT_ARG_STRING, NULL, 'G', _("Groups"), NULL }, { "create-home", 'm', POPT_ARG_NONE, NULL, 'm', _("Create user's directory if it does not exist"), NULL }, { "no-create-home", 'M', POPT_ARG_NONE, NULL, 'M', _("Never create user's directory, overrides config"), NULL }, { "skel", 'k', POPT_ARG_STRING, &pc_skeldir, 0, _("Specify an alternative skeleton directory"), NULL }, { "selinux-user", 'Z', POPT_ARG_STRING, &pc_selinux_user, 0, _("The SELinux user for user's login"), NULL }, POPT_TABLEEND }; poptContext pc = NULL; struct tools_ctx *tctx = NULL; char *groups = NULL; char *badgroup = NULL; int ret; errno_t sret; bool in_transaction = false; debug_prg_name = argv[0]; ret = set_locale(); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "set_locale failed (%d): %s\n", ret, strerror(ret)); ERROR("Error setting the locale\n"); ret = EXIT_FAILURE; goto fini; } /* parse parameters */ pc = poptGetContext(NULL, argc, argv, long_options, 0); poptSetOtherOptionHelp(pc, "USERNAME"); while ((ret = poptGetNextOpt(pc)) > 0) { switch (ret) { case 'G': groups = poptGetOptArg(pc); if (!groups) { BAD_POPT_PARAMS(pc, _("Specify group to add to\n"), ret, fini); } break; case 'm': pc_create_home = DO_CREATE_HOME; break; case 'M': pc_create_home = DO_NOT_CREATE_HOME; break; } } DEBUG_CLI_INIT(pc_debug); if (ret != -1) { BAD_POPT_PARAMS(pc, poptStrerror(ret), ret, fini); } /* username is an argument without --option */ pc_username = poptGetArg(pc); if (pc_username == NULL) { BAD_POPT_PARAMS(pc, _("Specify user to add\n"), ret, fini); } CHECK_ROOT(ret, debug_prg_name); ret = init_sss_tools(&tctx); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "init_sss_tools failed (%d): %s\n", ret, strerror(ret)); if (ret == ENOENT) { ERROR("Error initializing the tools - no local domain\n"); } else { ERROR("Error initializing the tools\n"); } ret = EXIT_FAILURE; goto fini; } /* if the domain was not given as part of FQDN, default to local domain */ ret = parse_name_domain(tctx, pc_username); if (ret != EOK) { ERROR("Invalid domain specified in FQDN\n"); ret = EXIT_FAILURE; goto fini; } if (groups) { ret = parse_groups(tctx, groups, &tctx->octx->addgroups); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Cannot parse groups to add the user to\n"); ERROR("Internal error while parsing parameters\n"); ret = EXIT_FAILURE; goto fini; } ret = parse_group_name_domain(tctx, tctx->octx->addgroups); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Cannot parse FQDN groups to add the user to\n"); ERROR("Groups must be in the same domain as user\n"); ret = EXIT_FAILURE; goto fini; } /* Check group names in the LOCAL domain */ ret = check_group_names(tctx, tctx->octx->addgroups, &badgroup); if (ret != EOK) { ERROR("Cannot find group %1$s in local domain\n", badgroup); ret = EXIT_FAILURE; goto fini; } } tctx->octx->uid = pc_uid; /* * Fills in defaults for ops_ctx user did not specify. */ ret = useradd_defaults(tctx, tctx->confdb, tctx->octx, pc_gecos, pc_home, pc_shell, pc_create_home, pc_skeldir); if (ret != EOK) { ERROR("Cannot set default values\n"); ret = EXIT_FAILURE; goto fini; } /* arguments processed, go on to actual work */ if (id_in_range(tctx->octx->uid, tctx->octx->domain) != EOK) { ERROR("The selected UID is outside the allowed range\n"); ret = EXIT_FAILURE; goto fini; } tctx->error = sysdb_transaction_start(tctx->sysdb); if (tctx->error != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n"); goto done; } in_transaction = true; /* useradd */ tctx->error = useradd(tctx, tctx->octx); if (tctx->error) { goto done; } tctx->error = sysdb_transaction_commit(tctx->sysdb); if (tctx->error) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n"); goto done; } in_transaction = false; /* Set SELinux login context - must be done after transaction is done * b/c libselinux calls getpwnam */ ret = set_seuser(tctx->octx->name, pc_selinux_user, NULL); if (ret != EOK) { ERROR("Cannot set SELinux login context\n"); ret = EXIT_FAILURE; goto fini; } /* Create user's home directory and/or mail spool */ if (tctx->octx->create_homedir) { /* We need to know the UID of the user, if * sysdb did assign it automatically, do a lookup */ if (tctx->octx->uid == 0) { ret = sysdb_getpwnam_sync(tctx, tctx->octx->name, tctx->octx); if (ret != EOK) { ERROR("Cannot get info about the user\n"); ret = EXIT_FAILURE; goto fini; } } ret = create_homedir(tctx->octx->skeldir, tctx->octx->home, tctx->octx->uid, tctx->octx->gid, tctx->octx->umask); if (ret == EEXIST) { ERROR("User's home directory already exists, not copying " "data from skeldir\n"); } else if (ret != EOK) { ERROR("Cannot create user's home directory: %1$s\n", strerror(ret)); ret = EXIT_FAILURE; goto fini; } ret = create_mail_spool(tctx, tctx->octx->name, tctx->octx->maildir, tctx->octx->uid, tctx->octx->gid); if (ret != EOK) { ERROR("Cannot create user's mail spool: %1$s\n", strerror(ret)); DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create user's mail spool: [%d][%s].\n", ret, strerror(ret)); ret = EXIT_FAILURE; goto fini; } } done: if (in_transaction) { sret = sysdb_transaction_cancel(tctx->sysdb); if (sret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n"); } } if (tctx->error) { switch (tctx->error) { case ERANGE: ERROR("Could not allocate ID for the user - domain full?\n"); break; case EEXIST: ERROR("A user or group with the same name or ID already exists\n"); break; default: DEBUG(SSSDBG_CRIT_FAILURE, "sysdb operation failed (%d)[%s]\n", tctx->error, strerror(tctx->error)); ERROR("Transaction error. Could not add user.\n"); break; } ret = EXIT_FAILURE; goto fini; } ret = EXIT_SUCCESS; fini: poptFreeContext(pc); talloc_free(tctx); free(groups); exit(ret); }
static int enum_groups(TALLOC_CTX *mem_ctx, struct proxy_id_ctx *ctx, struct sysdb_ctx *sysdb, struct sss_domain_info *dom) { TALLOC_CTX *tmpctx; bool in_transaction = false; struct group *grp; enum nss_status status; size_t buflen; char *buffer; char *newbuf; int ret; errno_t sret; bool again; DEBUG(SSSDBG_TRACE_LIBS, "Enumerating groups\n"); tmpctx = talloc_new(mem_ctx); if (!tmpctx) { return ENOMEM; } grp = talloc(tmpctx, struct group); if (!grp) { ret = ENOMEM; goto done; } buflen = DEFAULT_BUFSIZE; buffer = talloc_size(tmpctx, buflen); if (!buffer) { ret = ENOMEM; goto done; } ret = sysdb_transaction_start(sysdb); if (ret) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n"); goto done; } in_transaction = true; status = ctx->ops.setgrent(); if (status != NSS_STATUS_SUCCESS) { ret = EIO; goto done; } do { again = false; /* always zero out the grp structure */ memset(grp, 0, sizeof(struct group)); /* get entry */ status = ctx->ops.getgrent_r(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) { ret = ENOMEM; goto done; } buffer = newbuf; again = true; break; case NSS_STATUS_NOTFOUND: /* we are done here */ DEBUG(SSSDBG_TRACE_LIBS, "Enumeration completed.\n"); ret = sysdb_transaction_commit(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n"); goto done; } in_transaction = false; break; case NSS_STATUS_SUCCESS: DEBUG(SSSDBG_OP_FAILURE, "Group found (%s, %"SPRIgid")\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_OP_FAILURE, "Group [%s] filtered out! (id" "out of range)\n", grp->gr_name); again = true; break; } 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 */ DEBUG(SSSDBG_OP_FAILURE, "Failed to store group." "Ignoring\n"); } again = true; break; case NSS_STATUS_UNAVAIL: /* "remote" backend unavailable. Enter offline mode */ ret = ENXIO; break; default: ret = EIO; DEBUG(SSSDBG_OP_FAILURE, "proxy -> getgrent_r failed (%d)[%s]" "\n", ret, strerror(ret)); break; } } while (again); done: talloc_zfree(tmpctx); if (in_transaction) { sret = sysdb_transaction_cancel(sysdb); if (sret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n"); } } ctx->ops.endgrent(); return ret; }
errno_t sysdb_store_ssh_host(struct sysdb_ctx *sysdb, struct sss_domain_info *domain, const char *name, const char *alias, time_t now, struct sysdb_attrs *attrs) { TALLOC_CTX *tmp_ctx; errno_t ret, sret; bool in_transaction = false; const char *search_attrs[] = { SYSDB_NAME_ALIAS, NULL }; bool new_alias; struct ldb_message *host = NULL; struct ldb_message_element *el; unsigned int i; DEBUG(SSSDBG_TRACE_FUNC, ("Storing host %s\n", name)); tmp_ctx = talloc_new(NULL); if (!tmp_ctx) { return ENOMEM; } ret = sysdb_transaction_start(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n")); goto done; } in_transaction = true; ret = sysdb_get_ssh_host(tmp_ctx, sysdb, domain, name, search_attrs, &host); if (ret != EOK && ret != ENOENT) { goto done; } ret = sysdb_attrs_add_string(attrs, SYSDB_OBJECTCLASS, SYSDB_SSH_HOST_OC); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Could not set object class [%d]: %s\n", ret, strerror(ret))); goto done; } ret = sysdb_attrs_add_string(attrs, SYSDB_NAME, name); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Could not set name attribute [%d]: %s\n", ret, strerror(ret))); goto done; } if (alias) { new_alias = true; /* copy aliases from the existing entry */ if (host) { el = ldb_msg_find_element(host, SYSDB_NAME_ALIAS); if (el) { for (i = 0; i < el->num_values; i++) { if (strcmp((char *)el->values[i].data, alias) == 0) { new_alias = false; } ret = sysdb_attrs_add_val(attrs, SYSDB_NAME_ALIAS, &el->values[i]); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Could not add name alias %s [%d]: %s\n", el->values[i].data, ret, strerror(ret))); goto done; } } } } /* add alias only if it is not already present */ if (new_alias) { ret = sysdb_attrs_add_string(attrs, SYSDB_NAME_ALIAS, alias); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Could not add name alias %s [%d]: %s\n", alias, ret, strerror(ret))); goto done; } } } /* make sure sshPublicKey is present when modifying an existing host */ if (host) { ret = sysdb_attrs_get_el(attrs, SYSDB_SSH_PUBKEY, &el); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Could not get sysdb sshPublicKey [%d]: %s\n", ret, strerror(ret))); goto done; } } ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_UPDATE, now); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, ("Could not set sysdb lastUpdate [%d]: %s\n", ret, strerror(ret))); goto done; } ret = sysdb_update_ssh_host(sysdb, domain, name, attrs); if (ret != EOK) { goto done; } ret = sysdb_transaction_commit(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_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, ("Could not cancel transaction\n")); } } talloc_free(tmp_ctx); return ret; }
errno_t sdap_save_native_sudorule_list(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb_ctx, struct sss_domain_info *domain, struct sdap_attr_map *map, struct sysdb_attrs **replies, size_t replies_count, int cache_timeout, time_t now, char **_usn) { TALLOC_CTX *tmp_ctx = NULL; char *higher_usn = NULL; char *usn_value = NULL; errno_t ret, tret; bool in_transaction = false; size_t i; tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { DEBUG(SSSDBG_FATAL_FAILURE, ("talloc_new() failed\n")); return ENOMEM; } ret = sysdb_transaction_start(sysdb_ctx); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Could not start transaction\n")); goto fail; } in_transaction = true; for (i=0; i<replies_count; i++) { usn_value = NULL; ret = sdap_save_native_sudorule(tmp_ctx, sysdb_ctx, domain, map, replies[i], cache_timeout, now, &usn_value); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to save sudo rule, " "will continue with next...\n")); continue; } /* find highest usn */ if (usn_value) { if (higher_usn) { if ((strlen(usn_value) > strlen(higher_usn)) || (strcmp(usn_value, higher_usn) > 0)) { talloc_zfree(higher_usn); higher_usn = usn_value; } else { talloc_zfree(usn_value); } } else { higher_usn = usn_value; } } } ret = sysdb_transaction_commit(sysdb_ctx); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to commit transaction\n")); goto fail; } in_transaction = false; if (higher_usn != NULL) { *_usn = talloc_steal(mem_ctx, higher_usn); } ret = EOK; fail: if (in_transaction) { tret = sysdb_transaction_cancel(sysdb_ctx); if (tret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Could not cancel transaction\n")); } } talloc_free(tmp_ctx); return ret; }
int sdap_save_users(TALLOC_CTX *memctx, struct sysdb_ctx *sysdb, struct sss_domain_info *dom, struct sdap_options *opts, struct sysdb_attrs **users, int num_users, char **_usn_value) { TALLOC_CTX *tmpctx; char *higher_usn = NULL; char *usn_value; int ret; errno_t sret; int i; time_t now; bool in_transaction = false; if (num_users == 0) { /* Nothing to do if there are no users */ return EOK; } tmpctx = talloc_new(memctx); if (!tmpctx) { return ENOMEM; } ret = sysdb_transaction_start(sysdb); if (ret) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n"); goto done; } in_transaction = true; now = time(NULL); for (i = 0; i < num_users; i++) { usn_value = NULL; ret = sdap_save_user(tmpctx, opts, dom, users[i], &usn_value, now); /* Do not fail completely on errors. * Just report the failure to save and go on */ if (ret) { DEBUG(SSSDBG_OP_FAILURE, "Failed to store user %d. Ignoring.\n", i); } else { DEBUG(SSSDBG_TRACE_ALL, "User %d processed!\n", i); } if (usn_value) { if (higher_usn) { if ((strlen(usn_value) > strlen(higher_usn)) || (strcmp(usn_value, higher_usn) > 0)) { talloc_zfree(higher_usn); higher_usn = usn_value; } else { talloc_zfree(usn_value); } } else { higher_usn = usn_value; } } } ret = sysdb_transaction_commit(sysdb); if (ret) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction!\n"); goto done; } in_transaction = false; if (_usn_value) { *_usn_value = talloc_steal(memctx, higher_usn); } done: if (in_transaction) { sret = sysdb_transaction_cancel(sysdb); if (sret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n"); } } talloc_zfree(tmpctx); return ret; }
int main(int argc, const char **argv) { gid_t pc_gid = 0; int pc_debug = SSSDBG_DEFAULT; struct poptOption long_options[] = { POPT_AUTOHELP { "debug", '\0', POPT_ARG_INT | POPT_ARGFLAG_DOC_HIDDEN, &pc_debug, 0, _("The debug level to run with"), NULL }, { "append-group", 'a', POPT_ARG_STRING, NULL, 'a', _("Groups to add this group to"), NULL }, { "remove-group", 'r', POPT_ARG_STRING, NULL, 'r', _("Groups to remove this group from"), NULL }, { "gid", 'g', POPT_ARG_INT | POPT_ARGFLAG_DOC_HIDDEN, &pc_gid, 0, _("The GID of the group"), NULL }, POPT_TABLEEND }; poptContext pc = NULL; struct tools_ctx *tctx = NULL; char *addgroups = NULL, *rmgroups = NULL; int ret; errno_t sret; const char *pc_groupname = NULL; char *badgroup = NULL; bool in_transaction = false; debug_prg_name = argv[0]; ret = set_locale(); if (ret != EOK) { DEBUG(1, ("set_locale failed (%d): %s\n", ret, strerror(ret))); ERROR("Error setting the locale\n"); ret = EXIT_FAILURE; goto fini; } /* parse parameters */ pc = poptGetContext(NULL, argc, argv, long_options, 0); poptSetOtherOptionHelp(pc, "GROUPNAME"); while ((ret = poptGetNextOpt(pc)) > 0) { switch (ret) { case 'a': addgroups = poptGetOptArg(pc); if (addgroups == NULL) { BAD_POPT_PARAMS(pc, _("Specify group to add to\n"), ret, fini); } break; case 'r': rmgroups = poptGetOptArg(pc); if (rmgroups == NULL) { BAD_POPT_PARAMS(pc, _("Specify group to remove from\n"), ret, fini); } break; } } if (ret != -1) { BAD_POPT_PARAMS(pc, poptStrerror(ret), ret, fini); } /* groupname is an argument without --option */ pc_groupname = poptGetArg(pc); if (pc_groupname == NULL) { BAD_POPT_PARAMS(pc, _("Specify group to modify\n"), ret, fini); } DEBUG_INIT(pc_debug); CHECK_ROOT(ret, debug_prg_name); ret = init_sss_tools(&tctx); if (ret != EOK) { DEBUG(1, ("init_sss_tools failed (%d): %s\n", ret, strerror(ret))); if (ret == ENOENT) { ERROR("Error initializing the tools - no local domain\n"); } else { ERROR("Error initializing the tools\n"); } ret = EXIT_FAILURE; goto fini; } ret = parse_name_domain(tctx, pc_groupname); if (ret != EOK) { ERROR("Invalid domain specified in FQDN\n"); ret = EXIT_FAILURE; goto fini; } /* check the username to be able to give sensible error message */ ret = sysdb_getgrnam_sync(tctx, tctx->sysdb, tctx->octx->name, tctx->octx); if (ret != EOK) { ERROR("Cannot find group in local domain, " "modifying groups is allowed only in local domain\n"); ret = EXIT_FAILURE; goto fini; } tctx->octx->gid = pc_gid; if (addgroups) { ret = parse_groups(tctx, addgroups, &tctx->octx->addgroups); if (ret != EOK) { DEBUG(1, ("Cannot parse groups to add the group to\n")); ERROR("Internal error while parsing parameters\n"); ret = EXIT_FAILURE; goto fini; } ret = parse_group_name_domain(tctx, tctx->octx->addgroups); if (ret != EOK) { DEBUG(1, ("Cannot parse FQDN groups to add the group to\n")); ERROR("Member groups must be in the same domain as parent group\n"); ret = EXIT_FAILURE; goto fini; } /* Check group names in the LOCAL domain */ ret = check_group_names(tctx, tctx->octx->addgroups, &badgroup); if (ret != EOK) { ERROR("Cannot find group %1$s in local domain, " "only groups in local domain are allowed\n", badgroup); ret = EXIT_FAILURE; goto fini; } } if (rmgroups) { ret = parse_groups(tctx, rmgroups, &tctx->octx->rmgroups); if (ret != EOK) { DEBUG(1, ("Cannot parse groups to remove the group from\n")); ERROR("Internal error while parsing parameters\n"); ret = EXIT_FAILURE; goto fini; } ret = parse_group_name_domain(tctx, tctx->octx->rmgroups); if (ret != EOK) { DEBUG(1, ("Cannot parse FQDN groups to remove the group from\n")); ERROR("Member groups must be in the same domain as parent group\n"); ret = EXIT_FAILURE; goto fini; } /* Check group names in the LOCAL domain */ ret = check_group_names(tctx, tctx->octx->rmgroups, &badgroup); if (ret != EOK) { ERROR("Cannot find group %1$s in local domain, " "only groups in local domain are allowed\n", badgroup); ret = EXIT_FAILURE; goto fini; } } if (id_in_range(tctx->octx->gid, tctx->octx->domain) != EOK) { ERROR("The selected GID is outside the allowed range\n"); ret = EXIT_FAILURE; goto fini; } tctx->error = sysdb_transaction_start(tctx->sysdb); if (tctx->error != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n")); goto done; } in_transaction = true; /* groupmod */ tctx->error = groupmod(tctx, tctx->sysdb, tctx->octx); if (tctx->error) { goto done; } tctx->error = sysdb_transaction_commit(tctx->sysdb); if (tctx->error != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to commit transaction\n")); goto done; } in_transaction = false; ret = sss_mc_refresh_group(pc_groupname); if (ret != EOK) { ERROR("NSS request failed (%1$d). Entry might remain in memory " "cache.\n", ret); /* Nothing we can do about it */ } ret = sss_mc_refresh_grouplist(tctx, tctx->octx->addgroups); if (ret != EOK) { ERROR("NSS request failed (%1$d). Entry might remain in memory " "cache.\n", ret); /* Nothing we can do about it */ } ret = sss_mc_refresh_grouplist(tctx, tctx->octx->rmgroups); if (ret != EOK) { ERROR("NSS request failed (%1$d). Entry might remain in memory " "cache.\n", ret); /* Nothing we can do about it */ } done: if (in_transaction) { sret = sysdb_transaction_cancel(tctx->sysdb); if (sret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to cancel transaction\n")); } } if (tctx->error) { ret = tctx->error; DEBUG(1, ("sysdb operation failed (%d)[%s]\n", ret, strerror(ret))); switch (ret) { case ENOENT: ERROR("Could not modify group - check if member group names are correct\n"); break; case EFAULT: ERROR("Could not modify group - check if groupname is correct\n"); break; default: ERROR("Transaction error. Could not modify group.\n"); break; } ret = EXIT_FAILURE; goto fini; } ret = EXIT_SUCCESS; fini: free(addgroups); free(rmgroups); poptFreeContext(pc); talloc_free(tctx); exit(ret); }
errno_t sysdb_svc_delete(struct sss_domain_info *domain, const char *name, int port, const char *proto) { errno_t ret, sret; TALLOC_CTX *tmp_ctx; struct ldb_result *res; unsigned int i; bool in_transaction = false; struct sysdb_ctx *sysdb = domain->sysdb; tmp_ctx = talloc_new(NULL); if (!tmp_ctx) { return ENOMEM; } ret = sysdb_transaction_start(sysdb); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n"); goto done; } in_transaction = true; if (name) { ret = sysdb_getservbyname(tmp_ctx, domain, name, proto, &res); if (ret != EOK && ret != ENOENT) goto done; if (ret == ENOENT) { /* Doesn't exist in the DB. Nothing to do */ ret = EOK; goto done; } } else { ret = sysdb_getservbyport(tmp_ctx, domain, port, proto, &res); if (ret != EOK && ret != ENOENT) goto done; if (ret == ENOENT) { /* Doesn't exist in the DB. Nothing to do */ ret = EOK; goto done; } } /* There should only be one matching entry, * but if there are multiple, we should delete * them all to de-corrupt the DB. */ for (i = 0; i < res->count; i++) { ret = sysdb_delete_entry(sysdb, res->msgs[i]->dn, false); if (ret != EOK) 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"); } } if (ret != EOK && ret != ENOENT) { DEBUG(SSSDBG_TRACE_INTERNAL, "Error: %d (%s)\n", ret, strerror(ret)); } talloc_zfree(tmp_ctx); return ret; }
int main(int argc, const char **argv) { gid_t pc_gid = 0; int pc_debug = SSSDBG_DEFAULT; struct poptOption long_options[] = { POPT_AUTOHELP { "debug",'\0', POPT_ARG_INT | POPT_ARGFLAG_DOC_HIDDEN, &pc_debug, 0, _("The debug level to run with"), NULL }, { "gid", 'g', POPT_ARG_INT, &pc_gid, 0, _("The GID of the group"), NULL }, POPT_TABLEEND }; poptContext pc = NULL; struct tools_ctx *tctx = NULL; int ret = EXIT_SUCCESS; errno_t sret; const char *pc_groupname = NULL; bool in_transaction = false; debug_prg_name = argv[0]; ret = set_locale(); if (ret != EOK) { DEBUG(1, ("set_locale failed (%d): %s\n", ret, strerror(ret))); ERROR("Error setting the locale\n"); ret = EXIT_FAILURE; goto fini; } /* parse params */ pc = poptGetContext(NULL, argc, argv, long_options, 0); poptSetOtherOptionHelp(pc, "GROUPNAME"); if ((ret = poptGetNextOpt(pc)) < -1) { BAD_POPT_PARAMS(pc, poptStrerror(ret), ret, fini); } DEBUG_INIT(pc_debug); /* groupname is an argument, not option */ pc_groupname = poptGetArg(pc); if (pc_groupname == NULL) { BAD_POPT_PARAMS(pc, _("Specify group to add\n"), ret, fini); } CHECK_ROOT(ret, debug_prg_name); ret = init_sss_tools(&tctx); if (ret != EOK) { DEBUG(1, ("init_sss_tools failed (%d): %s\n", ret, strerror(ret))); if (ret == ENOENT) { ERROR("Error initializing the tools - no local domain\n"); } else { ERROR("Error initializing the tools\n"); } ret = EXIT_FAILURE; goto fini; } /* if the domain was not given as part of FQDN, default to local domain */ ret = parse_name_domain(tctx, pc_groupname); if (ret != EOK) { ERROR("Invalid domain specified in FQDN\n"); ret = EXIT_FAILURE; goto fini; } tctx->octx->gid = pc_gid; /* arguments processed, go on to actual work */ if (id_in_range(tctx->octx->gid, tctx->octx->domain) != EOK) { ERROR("The selected GID is outside the allowed range\n"); ret = EXIT_FAILURE; goto fini; } tctx->error = sysdb_transaction_start(tctx->sysdb); if (tctx->error != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n")); goto done; } in_transaction = true; /* groupadd */ tctx->error = groupadd(tctx->sysdb, tctx->octx); if (tctx->error) { goto done; } tctx->error = sysdb_transaction_commit(tctx->sysdb); if (tctx->error != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to commit transaction\n")); goto done; } in_transaction = false; done: if (in_transaction) { sret = sysdb_transaction_cancel(tctx->sysdb); if (sret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to cancel transaction\n")); } } if (tctx->error) { ret = tctx->error; switch (ret) { case ERANGE: ERROR("Could not allocate ID for the group - domain full?\n"); break; case EEXIST: ERROR("A group with the same name or GID already exists\n"); break; default: DEBUG(1, ("sysdb operation failed (%d)[%s]\n", ret, strerror(ret))); ERROR("Transaction error. Could not add group.\n"); break; } ret = EXIT_FAILURE; goto fini; } ret = EXIT_SUCCESS; fini: talloc_free(tctx); poptFreeContext(pc); exit(ret); }