From 1a3c4b9f378e3b04161e4f35b2efa5fae3d56a7b Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Oct 13 2010 13:49:37 +0000 Subject: Netgroups sysdb API --- diff --git a/src/db/sysdb.c b/src/db/sysdb.c index a2a94a5..4549226 100644 --- a/src/db/sysdb.c +++ b/src/db/sysdb.c @@ -52,6 +52,12 @@ struct ldb_dn *sysdb_group_dn(struct sysdb_ctx *ctx, void *memctx, return ldb_dn_new_fmt(memctx, ctx->ldb, SYSDB_TMPL_GROUP, name, domain); } +struct ldb_dn *sysdb_netgroup_dn(struct sysdb_ctx *ctx, void *memctx, + const char *domain, const char *name) +{ + return ldb_dn_new_fmt(memctx, ctx->ldb, SYSDB_TMPL_NETGROUP, name, domain); +} + errno_t sysdb_group_dn_name(struct sysdb_ctx *ctx, void *memctx, const char *_dn, char **_name) { diff --git a/src/db/sysdb.h b/src/db/sysdb.h index d8a78ba..a2b842f 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -35,12 +35,15 @@ #define SYSDB_USERS_CONTAINER "cn=users" #define SYSDB_GROUPS_CONTAINER "cn=groups" #define SYSDB_CUSTOM_CONTAINER "cn=custom" +#define SYSDB_NETGROUP_CONTAINER "cn=Netgroups" #define SYSDB_TMPL_USER_BASE SYSDB_USERS_CONTAINER",cn=%s,"SYSDB_BASE #define SYSDB_TMPL_GROUP_BASE SYSDB_GROUPS_CONTAINER",cn=%s,"SYSDB_BASE #define SYSDB_TMPL_CUSTOM_BASE SYSDB_CUSTOM_CONTAINER",cn=%s,"SYSDB_BASE +#define SYSDB_TMPL_NETGROUP_BASE SYSDB_NETGROUP_CONTAINER",cn=%s,"SYSDB_BASE #define SYSDB_USER_CLASS "user" #define SYSDB_GROUP_CLASS "group" +#define SYSDB_NETGROUP_CLASS "netgroup" #define SYSDB_NAME "name" #define SYSDB_OBJECTCLASS "objectClass" @@ -75,6 +78,9 @@ #define SYSDB_CACHE_EXPIRE "dataExpireTimestamp" #define SYSDB_INITGR_EXPIRE "initgrExpireTimestamp" +#define SYSDB_NETGROUP_TRIPLE "netgroupTriple" +#define SYSDB_DESCRIPTION "description" + #define SYSDB_CACHEDPWD "cachedPassword" #define SYSDB_UUID "uniqueID" @@ -92,6 +98,7 @@ #define SYSDB_UC "objectclass="SYSDB_USER_CLASS #define SYSDB_GC "objectclass="SYSDB_GROUP_CLASS +#define SYSDB_NC "objectclass="SYSDB_NETGROUP_CLASS #define SYSDB_MPGC "|("SYSDB_UC")("SYSDB_GC")" #define SYSDB_PWNAM_FILTER "(&("SYSDB_UC")("SYSDB_NAME"=%s))" @@ -110,6 +117,9 @@ #define SYSDB_GETCACHED_FILTER "(&"SYSDB_UC")("SYSDB_LAST_LOGIN">=%lu))" +#define SYSDB_NETGR_FILTER "(&("SYSDB_NC")("SYSDB_NAME"=%s))" +#define SYSDB_NETGR_TRIPLES_FILTER "(|("SYSDB_NAME"=%s)("SYSDB_MEMBEROF"=%s))" + #define SYSDB_DEFAULT_ATTRS SYSDB_LAST_UPDATE, \ SYSDB_CACHE_EXPIRE, \ SYSDB_INITGR_EXPIRE, \ @@ -131,6 +141,10 @@ SYSDB_DEFAULT_ATTRS, \ NULL} +#define SYSDB_NETGR_ATTRS {SYSDB_NAME, SYSDB_NETGROUP_TRIPLE, \ + SYSDB_DEFAULT_ATTRS, \ + NULL} + #define SYSDB_INITGR_ATTR SYSDB_MEMBEROF #define SYSDB_INITGR_ATTRS {SYSDB_GIDNUM, \ SYSDB_DEFAULT_ATTRS, \ @@ -138,6 +152,7 @@ #define SYSDB_TMPL_USER SYSDB_NAME"=%s,"SYSDB_TMPL_USER_BASE #define SYSDB_TMPL_GROUP SYSDB_NAME"=%s,"SYSDB_TMPL_GROUP_BASE +#define SYSDB_TMPL_NETGROUP SYSDB_NAME"=%s,"SYSDB_TMPL_NETGROUP_BASE #define SYSDB_TMPL_CUSTOM_SUBTREE "cn=%s,"SYSDB_TMPL_CUSTOM_BASE #define SYSDB_TMPL_CUSTOM SYSDB_NAME"=%s,cn=%s,"SYSDB_TMPL_CUSTOM_BASE @@ -200,6 +215,8 @@ struct ldb_dn *sysdb_user_dn(struct sysdb_ctx *ctx, void *memctx, const char *domain, const char *name); struct ldb_dn *sysdb_group_dn(struct sysdb_ctx *ctx, void *memctx, const char *domain, const char *name); +struct ldb_dn *sysdb_netgroup_dn(struct sysdb_ctx *ctx, void *memctx, + const char *domain, const char *name); errno_t sysdb_group_dn_name(struct sysdb_ctx *ctx, void *memctx, const char *dn_str, char **name); struct ldb_dn *sysdb_domain_dn(struct sysdb_ctx *ctx, void *memctx, @@ -282,6 +299,17 @@ int sysdb_enumgrent(TALLOC_CTX *mem_ctx, struct sss_domain_info *domain, struct ldb_result **res); +struct sysdb_netgroup_ctx { + char *hostname; + char *username; + char *domainname; +}; +errno_t sysdb_getnetgr(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *ctx, + struct sss_domain_info *domain, + const char *netgroup, + struct ldb_result **res); + int sysdb_initgroups(TALLOC_CTX *mem_ctx, struct sysdb_ctx *ctx, struct sss_domain_info *domain, @@ -295,6 +323,12 @@ int sysdb_get_user_attr(TALLOC_CTX *mem_ctx, const char **attributes, struct ldb_result **res); +int sysdb_get_netgroup_attr(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *ctx, + struct sss_domain_info *domain, + const char *netgrname, + const char **attributes, + struct ldb_result **res); /* functions that modify the databse * they have to be called within a transaction @@ -336,7 +370,7 @@ int sysdb_search_user_by_uid(TALLOC_CTX *mem_ctx, const char **attrs, struct ldb_message **msg); -/* Search Group (gy gid or name) */ +/* Search Group (by gid or name) */ int sysdb_search_group_by_name(TALLOC_CTX *mem_ctx, struct sysdb_ctx *ctx, struct sss_domain_info *domain, @@ -351,6 +385,14 @@ int sysdb_search_group_by_gid(TALLOC_CTX *mem_ctx, const char **attrs, struct ldb_message **msg); +/* Search Netgroup (by name) */ +int sysdb_search_netgroup_by_name(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *ctx, + struct sss_domain_info *domain, + const char *name, + const char **attrs, + struct ldb_message **msg); + /* Replace entry attrs */ int sysdb_set_entry_attr(TALLOC_CTX *mem_ctx, struct sysdb_ctx *ctx, @@ -374,6 +416,13 @@ int sysdb_set_group_attr(TALLOC_CTX *mem_ctx, struct sysdb_attrs *attrs, int mod_op); +/* Replace netgroup attrs */ +int sysdb_set_netgroup_attr(struct sysdb_ctx *ctx, + struct sss_domain_info *domain, + const char *name, + struct sysdb_attrs *attrs, + int mod_op); + /* Allocate a new id */ int sysdb_get_new_id(TALLOC_CTX *mem_ctx, struct sysdb_ctx *ctx, @@ -416,6 +465,18 @@ int sysdb_add_group(TALLOC_CTX *mem_ctx, struct sysdb_attrs *attrs, int cache_timeout); +/* Add netgroup (only basic attrs and w/o checks) */ +int sysdb_add_basic_netgroup(struct sysdb_ctx *ctx, + struct sss_domain_info *domain, + const char *name, const char *description); + +int sysdb_add_netgroup(struct sysdb_ctx *ctx, + struct sss_domain_info *domain, + const char *name, + const char *description, + struct sysdb_attrs *attrs, + int cache_timeout); + /* mod_op must be either LDB_FLAG_MOD_ADD or LDB_FLAG_MOD_DELETE */ int sysdb_mod_group_member(TALLOC_CTX *mem_ctx, struct sysdb_ctx *ctx, @@ -460,6 +521,44 @@ errno_t sysdb_update_members(struct sysdb_ctx *sysdb, const char **add_groups, const char **del_groups); +errno_t sysdb_add_netgroup_tuple(struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, + const char *netgroup, + const char *hostname, + const char *username, + const char *domainname); + +errno_t sysdb_remove_netgroup_tuple(struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, + const char *netgroup, + const char *hostname, + const char *username, + const char *domainname); + +errno_t sysdb_mod_netgroup_tuple(struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, + const char *netgroup, + const char *hostname, + const char *username, + const char *domainname, + int mod_op); + +errno_t sysdb_add_netgroup_member(struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, + const char *netgroup, + const char *member_netgroup); + +errno_t sysdb_remove_netgroup_member(struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, + const char *netgroup, + const char *member_netgroup); + +errno_t sysdb_mod_netgroup_member(struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, + const char *netgroup, + const char *member_netgroup, + int mod_op); + /* Password caching function. * If you are in a transaction ignore sysdb and pass in the handle. * If you are not in a transaction pass NULL in handle and provide sysdb, @@ -554,10 +653,18 @@ int sysdb_delete_group(TALLOC_CTX *mem_ctx, struct sss_domain_info *domain, const char *name, gid_t gid); +int sysdb_delete_netgroup(struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, + const char *name); + errno_t sysdb_attrs_to_list(TALLOC_CTX *memctx, struct sysdb_attrs **attrs, int attr_count, const char *attr_name, char ***_list); +errno_t sysdb_netgr_to_triples(TALLOC_CTX *mem_ctx, + struct ldb_result *res, + struct sysdb_netgroup_ctx ***triples); + #endif /* __SYS_DB_H__ */ diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c index 14af948..373ce37 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -377,6 +377,49 @@ done: } +/* =Search-Group-by-Name============================================ */ + +int sysdb_search_netgroup_by_name(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *ctx, + struct sss_domain_info *domain, + const char *name, + const char **attrs, + struct ldb_message **msg) +{ + TALLOC_CTX *tmpctx; + static const char *def_attrs[] = { SYSDB_NAME, NULL }; + struct ldb_message **msgs = NULL; + struct ldb_dn *basedn; + size_t msgs_count = 0; + int ret; + + tmpctx = talloc_new(mem_ctx); + if (!tmpctx) { + return ENOMEM; + } + + basedn = sysdb_netgroup_dn(ctx, tmpctx, domain->name, name); + if (!basedn) { + ret = ENOMEM; + goto done; + } + + ret = sysdb_search_entry(tmpctx, ctx, basedn, LDB_SCOPE_BASE, NULL, + attrs?attrs:def_attrs, &msgs_count, &msgs); + if (ret) { + goto done; + } + + *msg = talloc_steal(mem_ctx, msgs[0]); + +done: + if (ret) { + DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret))); + } + talloc_zfree(tmpctx); + return ret; +} + /* =Replace-Attributes-On-Entry=========================================== */ int sysdb_set_entry_attr(TALLOC_CTX *mem_ctx, @@ -463,6 +506,35 @@ int sysdb_set_group_attr(TALLOC_CTX *mem_ctx, return sysdb_set_entry_attr(mem_ctx, ctx, dn, attrs, mod_op); } +/* =Replace-Attributes-On-Netgroup=========================================== */ + +int sysdb_set_netgroup_attr(struct sysdb_ctx *ctx, + 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_netgroup_dn(ctx, tmp_ctx, domain->name, name); + if (!dn) { + ret = ENOMEM; + goto done; + } + + ret = sysdb_set_entry_attr(tmp_ctx, ctx, dn, attrs, mod_op); + +done: + talloc_free(tmp_ctx); + return ret; +} /* =Get-New-ID============================================================ */ @@ -860,7 +932,7 @@ int sysdb_add_basic_group(TALLOC_CTX *mem_ctx, return ENOMEM; } - /* user dn */ + /* group dn */ msg->dn = sysdb_group_dn(ctx, msg, domain->name, name); if (!msg->dn) { ERROR_OUT(ret, ENOMEM, done); @@ -1049,6 +1121,118 @@ fail: return ret; } +/* =Add-Basic-Netgroup-NO-CHECKS============================================= */ + +int sysdb_add_basic_netgroup(struct sysdb_ctx *ctx, + struct sss_domain_info *domain, + const char *name, const char *description) +{ + struct ldb_message *msg; + int ret; + + msg = ldb_msg_new(NULL); + if (!msg) { + return ENOMEM; + } + + /* netgroup dn */ + msg->dn = sysdb_netgroup_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_NETGROUP_CLASS); + if (ret) goto done; + + ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_NAME, name); + if (ret) goto done; + + if (description && *description) { + ret = add_string(msg, LDB_FLAG_MOD_ADD, + SYSDB_DESCRIPTION, description); + if (ret) goto done; + } + + /* creation time */ + ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_CREATE_TIME, + (unsigned long) time(NULL)); + if (ret) goto done; + + ret = ldb_add(ctx->ldb, msg); + ret = sysdb_error_to_errno(ret); + +done: + if (ret) { + DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret))); + } + talloc_zfree(msg); + return ret; +} + + +/* =Add-Netgroup-Function==================================================== */ + +int sysdb_add_netgroup(struct sysdb_ctx *ctx, + struct sss_domain_info *domain, + const char *name, + const char *description, + struct sysdb_attrs *attrs, + int cache_timeout) +{ + TALLOC_CTX *tmp_ctx; + time_t now; + int ret; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) { + return ENOMEM; + } + + ret = ldb_transaction_start(ctx->ldb); + if (ret) { + ret = sysdb_error_to_errno(ret); + talloc_free(tmp_ctx); + return ret; + } + + /* try to add the netgroup */ + ret = sysdb_add_basic_netgroup(ctx, domain, name, description); + if (ret) goto done; + + if (!attrs) { + attrs = sysdb_new_attrs(tmp_ctx); + if (!attrs) { + ret = ENOMEM; + goto done; + } + } + + now = time(NULL); + + 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_netgroup_attr(ctx, domain, name, attrs, SYSDB_MOD_REP); + +done: + if (ret == EOK) { + ret = ldb_transaction_commit(ctx->ldb); + ret = sysdb_error_to_errno(ret); + } + + if (ret != EOK) { + DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret))); + ldb_transaction_cancel(ctx->ldb); + } + talloc_zfree(tmp_ctx); + return ret; +} /* =Store-Users-(Native/Legacy)-(replaces-existing-data)================== */ @@ -1917,6 +2101,44 @@ fail: return ret; } +/* =Delete-Netgroup-by-Name============================================== */ + +int sysdb_delete_netgroup(struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, + const char *name) +{ + TALLOC_CTX *tmp_ctx; + struct ldb_message *msg; + int ret; + + if (!name) return EINVAL; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) { + return ENOMEM; + } + + ret = sysdb_search_netgroup_by_name(tmp_ctx, sysdb, + domain, name, NULL, &msg); + if (ret != EOK) { + DEBUG(6, ("sysdb_search_netgroup_by_name failed: %d (%s)\n", + ret, strerror(ret))); + goto done; + } + + ret = sysdb_delete_entry(sysdb, msg->dn, false); + if (ret != EOK) { + goto done; + } + +done: + if (ret != EOK) { + DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret))); + } + talloc_free(tmp_ctx); + return ret; +} + /* ========= Authentication against cached password ============ */ @@ -2255,3 +2477,132 @@ done: talloc_free(tmp_ctx); return ret; } + +errno_t sysdb_add_netgroup_tuple(struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, + const char *netgroup, + const char *hostname, + const char *username, + const char *domainname) +{ + return sysdb_mod_netgroup_tuple(sysdb, domain, netgroup, hostname, + username, domainname, SYSDB_MOD_ADD); +} + +errno_t sysdb_remove_netgroup_tuple(struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, + const char *netgroup, + const char *hostname, + const char *username, + const char *domainname) +{ + return sysdb_mod_netgroup_tuple(sysdb, domain, netgroup, hostname, + username, domainname, SYSDB_MOD_DEL); +} + +errno_t sysdb_mod_netgroup_tuple(struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, + const char *netgroup, + const char *hostname, + const char *username, + const char *domainname, + int mod_op) +{ + errno_t ret; + int lret; + struct ldb_message *msg; + char *triple; + + msg = ldb_msg_new(NULL); + if (!msg) { + ERROR_OUT(ret, ENOMEM, done); + } + + msg->dn = sysdb_netgroup_dn(sysdb, msg, domain->name, netgroup); + if (!msg->dn) { + ERROR_OUT(ret, ENOMEM, done); + } + + triple = talloc_asprintf(msg, "(%s,%s,%s)", + hostname, username, domainname); + if (!triple) { + ERROR_OUT(ret, ENOMEM, done); + } + + ret = add_string(msg, mod_op, SYSDB_NETGROUP_TRIPLE, triple); + if (ret != EOK) { + goto done; + } + + lret = ldb_modify(sysdb->ldb, msg); + ret = sysdb_error_to_errno(lret); + +done: + if (ret) { + DEBUG(3, ("Error: %d (%s)\n", ret, strerror(ret))); + } + talloc_free(msg); + return ret; +} + +errno_t sysdb_add_netgroup_member(struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, + const char *netgroup, + const char *member_netgroup) +{ + return sysdb_mod_netgroup_member(sysdb, domain, netgroup, + member_netgroup, SYSDB_MOD_ADD); +} + +errno_t sysdb_remove_netgroup_member(struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, + const char *netgroup, + const char *member_netgroup) +{ + return sysdb_mod_netgroup_member(sysdb, domain, netgroup, + member_netgroup, SYSDB_MOD_DEL); +} + +errno_t sysdb_mod_netgroup_member(struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, + const char *netgroup, + const char *member_netgroup, + int mod_op) +{ + errno_t ret; + int lret; + struct ldb_message *msg; + char *member; + + msg = ldb_msg_new(NULL); + if (!msg) { + ERROR_OUT(ret, ENOMEM, done); + } + + msg->dn = sysdb_netgroup_dn(sysdb, msg, domain->name, netgroup); + if (!msg->dn) { + ERROR_OUT(ret, ENOMEM, done); + } + + member = talloc_asprintf(msg, SYSDB_TMPL_NETGROUP, + member_netgroup, domain->name); + if (!member) { + ret = ENOMEM; + goto done; + } + + ret = add_string(msg, mod_op, SYSDB_MEMBER, member); + if (ret != EOK) { + goto done; + } + + lret = ldb_modify(sysdb->ldb, msg); + ret = sysdb_error_to_errno(lret); + +done: + if (ret) { + DEBUG(3, ("Error: %d (%s)\n", ret, strerror(ret))); + } + talloc_free(msg); + return ret; +} diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c index a24ea5b..91519e3 100644 --- a/src/db/sysdb_search.c +++ b/src/db/sysdb_search.c @@ -23,6 +23,7 @@ #include "db/sysdb_private.h" #include "confdb/confdb.h" #include +#include /* users */ @@ -503,3 +504,338 @@ done: talloc_zfree(tmpctx); return ret; } + +/* This function splits a three-tuple into three strings + * It assumes that any whitespace between the parentheses + * and commas are intentional and does not attempt to + * strip them out. Leading and trailing whitespace is + * ignored. + * + * This behavior is compatible with nss_ldap's + * implementation. + */ +static errno_t sysdb_netgr_split_triple(TALLOC_CTX *mem_ctx, + const char *triple, + char **hostname, + char **username, + char **domainname) +{ + errno_t ret; + TALLOC_CTX *tmp_ctx; + const char *p = triple; + const char *p_host; + const char *p_user; + const char *p_domain; + size_t len; + + char *host = NULL; + char *user = NULL; + char *domain = NULL; + + /* Pre-set the values to NULL here so if they are not + * copied, we don't return garbage below. + */ + *hostname = NULL; + *username = NULL; + *domainname = NULL; + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) { + return ENOMEM; + } + + /* Remove any leading whitespace */ + while (*p && isspace(*p)) p++; + + if (*p != '(') { + /* Triple must start and end with parentheses */ + ret = EINVAL; + goto done; + } + p++; + p_host = p; + + /* Find the first comma */ + while (*p && *p != ',') p++; + + if (!*p) { + /* No comma was found: parse error */ + ret = EINVAL; + goto done; + } + + len = p - p_host; + + if (len > 0) { + /* Copy the host string */ + host = talloc_strndup(tmp_ctx, p_host, len); + if (!host) { + ret = ENOMEM; + goto done; + } + } + p++; + p_user = p; + + /* Find the second comma */ + while (*p && *p != ',') p++; + + if (!*p) { + /* No comma was found: parse error */ + ret = EINVAL; + goto done; + } + + len = p - p_user; + + if (len > 0) { + /* Copy the user string */ + user = talloc_strndup(tmp_ctx, p_user, len); + if (!user) { + ret = ENOMEM; + goto done; + } + } + p++; + p_domain = p; + + /* Find the closing parenthesis */ + while (*p && *p != ')') p++; + if (*p != ')') { + /* No trailing parenthesis: parse error */ + ret = EINVAL; + goto done; + } + + len = p - p_domain; + + if (len > 0) { + /* Copy the domain string */ + domain = talloc_strndup(tmp_ctx, p_domain, len); + if (!domain) { + ret = ENOMEM; + goto done; + } + } + p++; + + /* skip trailing whitespace */ + while (*p && isspace(*p)) p++; + + if (*p) { + /* Extra data after the closing parenthesis + * is a parse error + */ + ret = EINVAL; + goto done; + } + + /* Return any non-NULL values */ + if (host) { + *hostname = talloc_steal(mem_ctx, host); + } + + if (user) { + *username = talloc_steal(mem_ctx, user); + } + + if (domain) { + *domainname = talloc_steal(mem_ctx, domain); + } + + ret = EOK; + +done: + talloc_free(tmp_ctx); + return ret; +} + +errno_t sysdb_netgr_to_triples(TALLOC_CTX *mem_ctx, + struct ldb_result *res, + struct sysdb_netgroup_ctx ***triples) +{ + errno_t ret; + size_t size = 0; + char *triple_str; + TALLOC_CTX *tmp_ctx; + struct sysdb_netgroup_ctx **tmp_triples = NULL; + struct ldb_message_element *el; + int i, j; + + if(!res || res->count == 0) { + return ENOENT; + } + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) { + return ENOMEM; + } + + for (i=0; i < res->count; i++) { + el = ldb_msg_find_element(res->msgs[i], SYSDB_NETGROUP_TRIPLE); + if (!el) { + /* No triples in this netgroup. It might be a nesting + * container only. + * Skip it and continue on. + */ + continue; + } + + /* Enlarge the array by the value count + * Always keep one extra entry for the NULL terminator + */ + tmp_triples = talloc_realloc(tmp_ctx, tmp_triples, + struct sysdb_netgroup_ctx *, + size+el->num_values+1); + if (!tmp_triples) { + ret = ENOMEM; + goto done; + } + + /* Copy in all of the triples */ + for(j = 0; j < el->num_values; j++) { + triple_str = talloc_strndup(tmp_ctx, + (const char *)el->values[j].data, + el->values[j].length); + if (!triple_str) { + ret = ENOMEM; + goto done; + } + + tmp_triples[size] = talloc_zero(tmp_triples, + struct sysdb_netgroup_ctx); + if (!tmp_triples[size]) { + ret = ENOMEM; + goto done; + } + + ret = sysdb_netgr_split_triple(tmp_triples[size], + triple_str, + &tmp_triples[size]->hostname, + &tmp_triples[size]->username, + &tmp_triples[size]->domainname); + if (ret != EOK) { + goto done; + } + + size++; + } + } + + if (!tmp_triples) { + /* No entries were found + * Create a dummy reply + */ + tmp_triples = talloc_array(tmp_ctx, struct sysdb_netgroup_ctx *, 1); + if (!tmp_triples) { + ret = ENOMEM; + goto done; + } + } + /* Add NULL terminator */ + tmp_triples[size] = NULL; + + *triples = talloc_steal(mem_ctx, tmp_triples); + ret = EOK; + +done: + talloc_free(tmp_ctx); + return ret; +} + +errno_t sysdb_getnetgr(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *ctx, + struct sss_domain_info *domain, + const char *netgroup, + struct ldb_result **res) +{ + TALLOC_CTX *tmp_ctx; + static const char *attrs[] = SYSDB_NETGR_ATTRS; + struct ldb_dn *base_dn; + struct ldb_result *result; + char *netgroup_dn; + int lret; + errno_t ret; + + if (!domain) { + return EINVAL; + } + + tmp_ctx = talloc_new(NULL); + if (!tmp_ctx) { + return ENOMEM; + } + + base_dn = ldb_dn_new_fmt(tmp_ctx, ctx->ldb, + SYSDB_TMPL_NETGROUP_BASE, + domain->name); + if (!base_dn) { + ret = ENOMEM; + goto done; + } + + netgroup_dn = talloc_asprintf(tmp_ctx, SYSDB_TMPL_NETGROUP, + netgroup, domain->name); + if (!netgroup_dn) { + ret = ENOMEM; + goto done; + } + + lret = ldb_search(ctx->ldb, tmp_ctx, &result, base_dn, + LDB_SCOPE_SUBTREE, attrs, + SYSDB_NETGR_TRIPLES_FILTER, + netgroup, netgroup_dn); + ret = sysdb_error_to_errno(lret); + if (ret != EOK) { + goto done; + } + + *res = talloc_steal(mem_ctx, result); + ret = EOK; + +done: + talloc_zfree(tmp_ctx); + return ret; +} + +int sysdb_get_netgroup_attr(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *ctx, + struct sss_domain_info *domain, + const char *netgrname, + const char **attributes, + struct ldb_result **res) +{ + TALLOC_CTX *tmpctx; + struct ldb_dn *base_dn; + struct ldb_result *result; + int ret; + + if (!domain) { + return EINVAL; + } + + tmpctx = talloc_new(mem_ctx); + if (!tmpctx) { + return ENOMEM; + } + + base_dn = ldb_dn_new_fmt(tmpctx, ctx->ldb, + SYSDB_TMPL_NETGROUP_BASE, domain->name); + if (!base_dn) { + ret = ENOMEM; + goto done; + } + + ret = ldb_search(ctx->ldb, tmpctx, &result, base_dn, + LDB_SCOPE_SUBTREE, attributes, + SYSDB_NETGR_FILTER, netgrname); + if (ret) { + ret = sysdb_error_to_errno(ret); + goto done; + } + + *res = talloc_steal(mem_ctx, result); +done: + talloc_zfree(tmpctx); + return ret; +}