diff options
-rw-r--r-- | daemons/configure.ac | 19 | ||||
-rw-r--r-- | daemons/ipa-slapi-plugins/Makefile.am | 1 | ||||
-rw-r--r-- | daemons/ipa-slapi-plugins/ipa-extdom-extop/Makefile.am | 74 | ||||
-rw-r--r-- | daemons/ipa-slapi-plugins/ipa-extdom-extop/README | 0 | ||||
-rw-r--r-- | daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa-extdom-extop-conf.ldif | 16 | ||||
-rw-r--r-- | daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h | 154 | ||||
-rw-r--r-- | daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c | 498 | ||||
-rw-r--r-- | daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c | 234 | ||||
-rw-r--r-- | daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_tests.c | 203 | ||||
-rw-r--r-- | freeipa.spec.in | 7 | ||||
-rw-r--r-- | ipaserver/install/adtrustinstance.py | 23 | ||||
-rw-r--r-- | ipaserver/install/service.py | 3 |
12 files changed, 1225 insertions, 7 deletions
diff --git a/daemons/configure.ac b/daemons/configure.ac index 9ee77e47..76ebaa67 100644 --- a/daemons/configure.ac +++ b/daemons/configure.ac @@ -237,8 +237,19 @@ PKG_CHECK_MODULES([NDRPAC], [ndr_krb5pac]) PKG_CHECK_MODULES([NDRNBT], [ndr_nbt]) PKG_CHECK_MODULES([NDR], [ndr]) PKG_CHECK_MODULES([SAMBAUTIL], [samba-util]) -SAMBA40EXTRA_LIBPATH="-L`$PKG_CONFIG --variable=libdir samba-util`/samba" +SAMBA40EXTRA_LIBPATH="-L`$PKG_CONFIG --variable=libdir samba-util`/samba -Wl,-rpath=`$PKG_CONFIG --variable=libdir samba-util`/samba" AC_SUBST(SAMBA40EXTRA_LIBPATH) +AC_CHECK_HEADERS([samba-4.0/wbclient.h], + , + [AC_MSG_ERROR([samba-4.0/wbclient.h not found])], + [#include <stdbool.h> + #include <stdint.h>]) +AC_CHECK_LIB([wbclient], + [wbcLookupSid], + [WBCLIENT_LIBS="$SAMBA40EXTRA_LIBPATH -lwbclient"], + [AC_MSG_ERROR([libwbclient does not have wbcLookupSid])], + [$SAMBA40EXTRA_LIBPATH]) +AC_SUBST(WBCLIENT_LIBS) dnl --------------------------------------------------------------------------- dnl - Check for check unit test framework http://check.sourceforge.net/ @@ -251,6 +262,11 @@ else fi AM_CONDITIONAL([HAVE_CHECK], [test x$have_check != x]) +dnl -- dirsrv is needed for the extdom unit tests -- +PKG_CHECK_MODULES([DIRSRV], [dirsrv]) +dnl -- sss_idmap is needed by the extdom exop -- +PKG_CHECK_MODULES([SSSIDMAP], [sss_idmap]) + dnl --------------------------------------------------------------------------- dnl - Set the data install directory since we don't use pkgdatadir dnl --------------------------------------------------------------------------- @@ -320,6 +336,7 @@ AC_CONFIG_FILES([ ipa-slapi-plugins/ipa-enrollment/Makefile ipa-slapi-plugins/ipa-lockout/Makefile ipa-slapi-plugins/ipa-pwd-extop/Makefile + ipa-slapi-plugins/ipa-extdom-extop/Makefile ipa-slapi-plugins/ipa-winsync/Makefile ipa-slapi-plugins/ipa-version/Makefile ipa-slapi-plugins/ipa-uuid/Makefile diff --git a/daemons/ipa-slapi-plugins/Makefile.am b/daemons/ipa-slapi-plugins/Makefile.am index 58df1a09..5a3c9e70 100644 --- a/daemons/ipa-slapi-plugins/Makefile.am +++ b/daemons/ipa-slapi-plugins/Makefile.am @@ -6,6 +6,7 @@ SUBDIRS = \ ipa-lockout \ ipa-modrdn \ ipa-pwd-extop \ + ipa-extdom-extop \ ipa-uuid \ ipa-version \ ipa-winsync \ diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/Makefile.am b/daemons/ipa-slapi-plugins/ipa-extdom-extop/Makefile.am new file mode 100644 index 00000000..d93e094b --- /dev/null +++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/Makefile.am @@ -0,0 +1,74 @@ +NULL = + +PLUGIN_COMMON_DIR=../common + +INCLUDES = \ + -I. \ + -I$(srcdir) \ + -I$(PLUGIN_COMMON_DIR) \ + -I$(KRB5_UTIL_DIR) \ + -I$(COMMON_BER_DIR) \ + -DPREFIX=\""$(prefix)"\" \ + -DBINDIR=\""$(bindir)"\" \ + -DLIBDIR=\""$(libdir)"\" \ + -DLIBEXECDIR=\""$(libexecdir)"\" \ + -DDATADIR=\""$(datadir)"\" \ + $(AM_CFLAGS) \ + $(LDAP_CFLAGS) \ + $(WBCLIENT_CFLAGS) \ + $(WARN_CFLAGS) \ + $(SSSIDMAP_CFLAGS) \ + $(NULL) + +plugindir = $(libdir)/dirsrv/plugins +plugin_LTLIBRARIES = \ + libipa_extdom_extop.la \ + $(NULL) + +libipa_extdom_extop_la_SOURCES = \ + ipa_extdom_extop.c \ + ipa_extdom_common.c \ + $(NULL) + +libipa_extdom_extop_la_LDFLAGS = -avoid-version + +libipa_extdom_extop_la_LIBADD = \ + $(LDAP_LIBS) \ + $(WBCLIENT_LIBS) \ + $(SSSIDMAP_LIBS) \ + $(NULL) + +if HAVE_CHECK +TESTS = extdom_tests +check_PROGRAMS = extdom_tests +endif + +extdom_tests_SOURCES = \ + ipa_extdom_tests.c \ + ipa_extdom_common.c \ + $(NULL) +extdom_tests_CFLAGS = $(CHECK_CFLAGS) +extdom_tests_LDFLAGS = \ + -rpath $(shell pkg-config --libs-only-L dirsrv | sed -e 's/-L//') \ + $(NULL) +extdom_tests_LDADD = \ + $(CHECK_LIBS) \ + $(LDAP_LIBS) \ + $(WBCLIENT_LIBS) \ + $(DIRSRV_LIBS) \ + $(SSSIDMAP_LIBS) \ + $(NULL) + +appdir = $(IPA_DATA_DIR) +app_DATA = \ + ipa-extdom-extop-conf.ldif \ + $(NULL) + +EXTRA_DIST = \ + README \ + $(app_DATA) \ + $(NULL) + +MAINTAINERCLEANFILES = \ + *~ \ + Makefile.in diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/README b/daemons/ipa-slapi-plugins/ipa-extdom-extop/README new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/README diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa-extdom-extop-conf.ldif b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa-extdom-extop-conf.ldif new file mode 100644 index 00000000..ec51ed26 --- /dev/null +++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa-extdom-extop-conf.ldif @@ -0,0 +1,16 @@ +dn: cn=ipa_extdom_extop,cn=plugins,cn=config +changetype: add +objectclass: top +objectclass: nsSlapdPlugin +objectclass: extensibleObject +cn: ipa_extdom_extop +nsslapd-pluginpath: libipa_extdom_extop +nsslapd-plugininitfunc: ipa_extdom_init +nsslapd-plugintype: extendedop +nsslapd-pluginenabled: on +nsslapd-pluginid: ipa_extdom_extop +nsslapd-pluginversion: 1.0 +nsslapd-pluginvendor: RedHat +nsslapd-plugindescription: Support resolving IDs in trusted domains to names and back +nsslapd-plugin-depends-on-type: database +nsslapd-basedn: $SUFFIX diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h new file mode 100644 index 00000000..5c2eeddc --- /dev/null +++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h @@ -0,0 +1,154 @@ +/** BEGIN COPYRIGHT BLOCK + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Additional permission under GPLv3 section 7: + * + * In the following paragraph, "GPL" means the GNU General Public + * License, version 3 or any later version, and "Non-GPL Code" means + * code that is governed neither by the GPL nor a license + * compatible with the GPL. + * + * You may link the code of this Program with Non-GPL Code and convey + * linked combinations including the two, provided that such Non-GPL + * Code only links to the code of this Program through those well + * defined interfaces identified in the file named EXCEPTION found in + * the source code files (the "Approved Interfaces"). The files of + * Non-GPL Code may instantiate templates or use macros or inline + * functions from the Approved Interfaces without causing the resulting + * work to be covered by the GPL. Only the copyright holders of this + * Program may make changes or additions to the list of Approved + * Interfaces. + * + * Authors: + * Sumit Bose <sbose@redhat.com> + * + * Copyright (C) 2011 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +#ifndef _IPA_EXTDOM_H_ +#define _IPA_EXTDOM_H_ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdbool.h> +#include <stdlib.h> +#include <stdint.h> + +#include <samba-4.0/wbclient.h> + +#include <dirsrv/slapi-plugin.h> +#include <lber.h> +#include <time.h> + +#include <sss_idmap.h> + +#define EXOP_EXTDOM_OID "2.16.840.1.113730.3.8.10.4" + +#define IPA_EXTDOM_PLUGIN_NAME "ipa-extdom-extop" +#define IPA_EXTDOM_FEATURE_DESC "IPA trusted domain ID mapper" +#define IPA_EXTDOM_PLUGIN_DESC "Support resolving IDs in trusted domains to names and back" + +#define IPA_PLUGIN_NAME IPA_EXTDOM_PLUGIN_NAME + +enum input_types { + INP_SID = 1, + INP_NAME, + INP_POSIX_UID, + INP_POSIX_GID +}; + +enum request_types { + REQ_SIMPLE = 1, + REQ_FULL +}; + +enum response_types { + RESP_SID = 1, + RESP_NAME, + RESP_USER, + RESP_GROUP +}; + +struct extdom_req { + enum input_types input_type; + enum request_types request_type; + union { + char *sid; + struct { + char *domain_name; + char *object_name; + } name; + struct { + char *domain_name; + uid_t uid; + } posix_uid; + struct { + char *domain_name; + gid_t gid; + } posix_gid; + } data; +}; + +struct extdom_res { + enum response_types response_type; + union { + char *sid; + struct { + const char *domain_name; + const char *object_name; + } name; + struct { + const char *domain_name; + const char *user_name; + uid_t uid; + gid_t gid; + } user; + struct { + const char *domain_name; + const char *group_name; + gid_t gid; + } group; + } data; +}; + +struct ipa_extdom_ctx { + Slapi_ComponentId *plugin_id; + char *base_dn; +}; + +struct domain_info { + char *flat_name; + char *sid; + char *guid; + struct sss_idmap_ctx *idmap_ctx; +}; + +int parse_request_data(struct berval *req_val, struct extdom_req **_req); +int handle_request(struct ipa_extdom_ctx *ctx, struct extdom_req *req, + struct extdom_res **res); +int create_response(struct extdom_req *req, struct domain_info *domain_info, + const char *domain_name, + const char *name, struct wbcDomainSid *sid, + enum wbcSidType name_type, struct extdom_res **_res); +int pack_response(struct extdom_res *res, struct berval **ret_val); +#endif /* _IPA_EXTDOM_H_ */ diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c new file mode 100644 index 00000000..294b00d5 --- /dev/null +++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c @@ -0,0 +1,498 @@ +/** BEGIN COPYRIGHT BLOCK + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Additional permission under GPLv3 section 7: + * + * In the following paragraph, "GPL" means the GNU General Public + * License, version 3 or any later version, and "Non-GPL Code" means + * code that is governed neither by the GPL nor a license + * compatible with the GPL. + * + * You may link the code of this Program with Non-GPL Code and convey + * linked combinations including the two, provided that such Non-GPL + * Code only links to the code of this Program through those well + * defined interfaces identified in the file named EXCEPTION found in + * the source code files (the "Approved Interfaces"). The files of + * Non-GPL Code may instantiate templates or use macros or inline + * functions from the Approved Interfaces without causing the resulting + * work to be covered by the GPL. Only the copyright holders of this + * Program may make changes or additions to the list of Approved + * Interfaces. + * + * Authors: + * Sumit Bose <sbose@redhat.com> + * + * Copyright (C) 2011 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 /* for asprintf() */ +#endif + +#include <errno.h> +#include <stdio.h> + +#include "ipa_extdom.h" +#include "util.h" + +int parse_request_data(struct berval *req_val, struct extdom_req **_req) +{ + BerElement *ber = NULL; + ber_tag_t tag; + ber_int_t input_type; + ber_int_t request_type; + ber_int_t id; + struct extdom_req *req; + +/* We expect the following request: + * ExtdomRequestValue ::= SEQUENCE { + * inputType ENUMERATED { + * sid (1), + * name (2), + * posix uid (3), + * posix gid (3) + * }, + * requestType ENUMERATED { + * simple (1), + * full (2) + * }, + * data InputData + * } + * + * InputData ::= CHOICE { + * sid OCTET STRING, + * name NameDomainData + * uid PosixUid, + * gid PosixGid + * } + * + * NameDomainData ::= SEQUENCE { + * domain_name OCTET STRING, + * object_name OCTET STRING + * } + * + * PosixUid ::= SEQUENCE { + * domain_name OCTET STRING, + * uid INTEGER + * } + * + * PosixGid ::= SEQUENCE { + * domain_name OCTET STRING, + * gid INTEGER + * } + */ + + if (req_val == NULL || req_val->bv_val == NULL || req_val->bv_len == 0) { + return LDAP_PROTOCOL_ERROR; + } + + ber = ber_init(req_val); + if (ber == NULL) { + return LDAP_PROTOCOL_ERROR; + } + + tag = ber_scanf(ber, "{ee", &input_type, &request_type); + if (tag == LBER_ERROR) { + ber_free(ber, 1); + return LDAP_PROTOCOL_ERROR; + } + + req = calloc(sizeof(struct extdom_req), 1); + if (req == NULL) { + return LDAP_OPERATIONS_ERROR; + } + + req->input_type = input_type; + req->request_type = request_type; + + switch (req->input_type) { + case INP_NAME: + tag = ber_scanf(ber, "{aa}}", &req->data.name.domain_name, + &req->data.name.object_name); + break; + case INP_SID: + tag = ber_scanf(ber, "a}", &req->data.sid); + break; + case INP_POSIX_UID: + tag = ber_scanf(ber, "{ai}}", &req->data.posix_uid.domain_name, + &id); + req->data.posix_uid.uid = (uid_t) id; + break; + case INP_POSIX_GID: + tag = ber_scanf(ber, "{ai}}", &req->data.posix_gid.domain_name, + &id); + req->data.posix_gid.gid = (gid_t) id; + break; + default: + ber_free(ber, 1); + return LDAP_PROTOCOL_ERROR; + } + ber_free(ber, 1); + if (tag == LBER_ERROR) { + return LDAP_PROTOCOL_ERROR; + } + + *_req = req; + + return LDAP_SUCCESS; +} + +static void free_domain_info(struct domain_info *domain_info) +{ + if (domain_info == NULL) { + return; + } + + sss_idmap_free(domain_info->idmap_ctx); + slapi_ch_free((void **) &domain_info->guid); + slapi_ch_free((void **) &domain_info->sid); + slapi_ch_free((void **) &domain_info->flat_name); + free(domain_info); +} + +/* TODO: A similar call is used in ipa_cldap_netlogon.c, maybe a candidate for + * a common library */ +static int get_domain_info(struct ipa_extdom_ctx *ctx, const char *domain_name, + struct domain_info **_domain_info) +{ + struct domain_info *domain_info = NULL; + Slapi_PBlock *pb = NULL; + Slapi_Entry **e = NULL; + char *filter = NULL; + int ret; + enum idmap_error_code err; + struct sss_idmap_range range; + + pb = slapi_pblock_new(); + if (pb == NULL) { + return ENOMEM; + } + + ret = asprintf(&filter, "(&(|(cn=%s)(ipaNTTrustPartner=%s)(ipaNTFlatName=%s))(objectclass=ipaNTTrustedDomain))", + domain_name, domain_name, domain_name); + if (ret == -1) { + ret = ENOMEM; + goto done; + } + + slapi_search_internal_set_pb(pb, ctx->base_dn, + LDAP_SCOPE_SUBTREE, filter, + NULL, 0, NULL, NULL, ctx->plugin_id, 0); + + slapi_search_internal_pb(pb); + slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret); + + if (ret != EOK) { + ret = ENOENT; + goto done; + } + + slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &e); + if (!e || !e[0] || e[1]) { + /* no matches or too many matches */ + ret = ENOENT; + goto done; + } + + domain_info = calloc(1, sizeof(struct domain_info)); + if (domain_info == NULL) { + ret = ENOMEM; + goto done; + } + + domain_info->guid = slapi_entry_attr_get_charptr(e[0], "ipaNTDomainGUID"); + domain_info->sid = slapi_entry_attr_get_charptr(e[0], + "ipaNTTrustedDomainSID"); + domain_info->flat_name = slapi_entry_attr_get_charptr(e[0], + "ipaNTFlatName"); + + /* TODO: read range from LDAP server */ + range.min = 200000; + range.max = 400000; + + err = sss_idmap_init(NULL, NULL, NULL, &domain_info->idmap_ctx); + if (err == IDMAP_SUCCESS) { + err = sss_idmap_add_domain(domain_info->idmap_ctx, domain_name, + domain_info->sid, &range); + } + if (err != IDMAP_SUCCESS) { + free_domain_info(domain_info); + ret = EFAULT; + goto done; + } + + *_domain_info = domain_info; + + ret = 0; + +done: + slapi_free_search_results_internal(pb); + slapi_pblock_destroy(pb); + free(filter); + return ret; + +} + +int handle_request(struct ipa_extdom_ctx *ctx, struct extdom_req *req, + struct extdom_res **res) +{ + wbcErr werr; + int ret; + struct wbcDomainSid sid; + char *domain_name; + char *name; + enum wbcSidType name_type; + struct domain_info *domain_info = NULL; + + ret = get_domain_info(ctx, req->data.name.domain_name, &domain_info); + if (ret != 0) { + return LDAP_OPERATIONS_ERROR; + } + + switch (req->input_type) { + case INP_SID: + werr = wbcStringToSid(req->data.sid, &sid); + if (!WBC_ERROR_IS_OK(werr)) { + ret = LDAP_OPERATIONS_ERROR; + goto done; + } + + werr = wbcLookupSid(&sid, &domain_name, &name, &name_type); + if (!WBC_ERROR_IS_OK(werr)) { + ret = LDAP_OPERATIONS_ERROR; + goto done; + } + + ret = create_response(req, domain_info, domain_name, name, &sid, + name_type, res); + if (ret != 0) { + ret = LDAP_OPERATIONS_ERROR; + goto done; + } + + break; + case INP_NAME: + werr = wbcLookupName(domain_info->flat_name, + req->data.name.object_name, &sid, &name_type); + if (!WBC_ERROR_IS_OK(werr)) { + ret = LDAP_OPERATIONS_ERROR; + goto done; + } + + ret = create_response(req, domain_info, req->data.name.domain_name, + req->data.name.object_name, &sid, name_type, + res); + if (ret != 0) { + ret = LDAP_OPERATIONS_ERROR; + goto done; + } + + break; + default: + ret = LDAP_PROTOCOL_ERROR; + goto done; + } + + ret = LDAP_SUCCESS; + +done: + free_domain_info(domain_info); + + return ret; +} + +int create_response(struct extdom_req *req, struct domain_info *domain_info, + const char *domain_name, + const char *name, struct wbcDomainSid *sid, + enum wbcSidType name_type, struct extdom_res **_res) +{ + int ret = EFAULT; + int len; + struct extdom_res *res; + uint32_t id; + enum idmap_error_code err; + char sid_str[WBC_SID_STRING_BUFLEN + 1]; + + res = malloc(sizeof(struct extdom_res)); + if (res == NULL) { + return ENOMEM; + } + + switch (req->request_type) { + case REQ_SIMPLE: + switch (req->input_type) { + case INP_SID: + res->response_type = RESP_NAME; + res->data.name.domain_name = domain_name; + res->data.name.object_name = name; + break; + case INP_NAME: + res->response_type = RESP_SID; + + len = wbcSidToStringBuf(sid, sid_str, + WBC_SID_STRING_BUFLEN); + if (len + 1 > WBC_SID_STRING_BUFLEN) { + ret = EINVAL; + goto done; + } + + res->data.sid = sid_str; + break; + default: + ret = EINVAL; + goto done; + } + break; + case REQ_FULL: + len = wbcSidToStringBuf(sid, sid_str, WBC_SID_STRING_BUFLEN); + if (len + 1 > WBC_SID_STRING_BUFLEN) { + ret = EINVAL; + goto done; + } + + err = sss_idmap_sid_to_unix(domain_info->idmap_ctx, sid_str, &id); + if (err != IDMAP_SUCCESS) { + ret = EINVAL; + goto done; + } + switch (name_type) { + case WBC_SID_NAME_USER: + res->response_type = RESP_USER; + res->data.user.domain_name = domain_name; + res->data.user.user_name = name; + + res->data.user.uid = (uid_t) id; + + /* We use MPGs for external users */ + res->data.user.gid = (gid_t) id; + break; + case WBC_SID_NAME_DOM_GRP: + res->response_type = RESP_GROUP; + res->data.group.domain_name = domain_name; + res->data.group.group_name = name; + + res->data.group.gid = (gid_t) id; + break; + default: + ret = EINVAL; + goto done; + } + break; + default: + ret = EINVAL; + goto done; + } + + ret = 0; + +done: + if (ret == 0) { + *_res = res; + } else { + free(res); + } + + return ret; +} + +int pack_response(struct extdom_res *res, struct berval **ret_val) +{ + BerElement *ber = NULL; + int ret; + +/* We send to follwing response: + * ExtdomResponseValue ::= SEQUENCE { + * responseType ENUMERATED { + * sid (1), + * name (2), + * posix_user (3), + * posix_group (4) + * }, + * data OutputData + * } + * + * OutputData ::= CHOICE { + * sid OCTET STRING, + * name NameDomainData, + * user PosixUser, + * group PosixGroup + * } + * + * NameDomainData ::= SEQUENCE { + * domain_name OCTET STRING, + * object_name OCTET STRING + * } + * + * PosixUser ::= SEQUENCE { + * domain_name OCTET STRING, + * user_name OCTET STRING, + * uid INTEGER + * gid INTEGER + * } + * + * PosixGroup ::= SEQUENCE { + * domain_name OCTET STRING, + * group_name OCTET STRING, + * gid INTEGER + * } + */ + + ber = ber_alloc_t( LBER_USE_DER ); + if (ber == NULL) { + return LDAP_OPERATIONS_ERROR; + } + + switch (res->response_type) { + case RESP_SID: + ret = ber_printf(ber,"{es}", res->response_type, res->data.sid); + break; + case RESP_NAME: + ret = ber_printf(ber,"{e{ss}}", res->response_type, + res->data.name.domain_name, + res->data.name.object_name); + break; + case RESP_USER: + ret = ber_printf(ber,"{e{ssii}}", res->response_type, + res->data.user.domain_name, + res->data.user.user_name, + res->data.user.uid, + res->data.user.gid); + break; + case RESP_GROUP: + ret = ber_printf(ber,"{e{ssi}}", res->response_type, + res->data.group.domain_name, + res->data.group.group_name, + res->data.group.gid); + break; + default: + ber_free(ber, 1); + return LDAP_OPERATIONS_ERROR; + } + + if (ret == -1) { + ber_free(ber, 1); + return LDAP_OPERATIONS_ERROR; + } + + ret = ber_flatten(ber, ret_val); + if (ret == -1) { + ber_free(ber, 1); + return LDAP_OPERATIONS_ERROR; + } + + ber_free(ber, 1); + + return LDAP_SUCCESS; +} diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c new file mode 100644 index 00000000..d5a2f604 --- /dev/null +++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c @@ -0,0 +1,234 @@ +/** BEGIN COPYRIGHT BLOCK + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Additional permission under GPLv3 section 7: + * + * In the following paragraph, "GPL" means the GNU General Public + * License, version 3 or any later version, and "Non-GPL Code" means + * code that is governed neither by the GPL nor a license + * compatible with the GPL. + * + * You may link the code of this Program with Non-GPL Code and convey + * linked combinations including the two, provided that such Non-GPL + * Code only links to the code of this Program through those well + * defined interfaces identified in the file named EXCEPTION found in + * the source code files (the "Approved Interfaces"). The files of + * Non-GPL Code may instantiate templates or use macros or inline + * functions from the Approved Interfaces without causing the resulting + * work to be covered by the GPL. Only the copyright holders of this + * Program may make changes or additions to the list of Approved + * Interfaces. + * + * Authors: + * Sumit Bose <sbose@redhat.com> + * + * Copyright (C) 2011 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +#include "ipa_extdom.h" +#include "util.h" + +Slapi_PluginDesc ipa_extdom_plugin_desc = { + IPA_EXTDOM_FEATURE_DESC, + "FreeIPA project", + "FreeIPA/1.0", + IPA_EXTDOM_PLUGIN_DESC +}; + +static char *ipa_extdom_oid_list[] = { + EXOP_EXTDOM_OID, + NULL +}; + +static char *ipa_extdom_name_list[] = { + IPA_EXTDOM_PLUGIN_DESC, + NULL +}; + +static int ipa_extdom_start(Slapi_PBlock *pb) +{ + return LDAP_SUCCESS; +} + +static int ipa_extdom_extop(Slapi_PBlock *pb) +{ + char *oid = NULL; + char *err_msg = NULL; + int rc; + int ret; + struct berval *req_val = NULL; + struct berval *ret_val = NULL; + struct extdom_req *req = NULL; + struct extdom_res *res = NULL; + struct ipa_extdom_ctx *ctx; + + ret = slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &oid); + if (ret != 0) { + rc = LDAP_OPERATIONS_ERROR; + err_msg = "Could not get OID value from request.\n"; + goto done; + } + LOG("Received extended operation request with OID %s\n", oid); + + if (strcasecmp(oid, EXOP_EXTDOM_OID) != 0) { + return SLAPI_PLUGIN_EXTENDED_NOT_HANDLED; + } + + ret = slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &req_val); + if (ret != 0) { + rc = LDAP_UNWILLING_TO_PERFORM; + err_msg = "Missing request data.\n"; + goto done; + } + + ret = slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &ctx); + if (ret != 0) { + rc = LDAP_OPERATIONS_ERROR; + err_msg = "Missing plugin context.\n"; + goto done; + } + + ret = parse_request_data(req_val, &req); + if (ret != LDAP_SUCCESS) { + rc = LDAP_UNWILLING_TO_PERFORM; + err_msg = "Cannot parse request data.\n"; + goto done; + } + + ret = handle_request(ctx, req, &res); + if (ret != LDAP_SUCCESS) { + rc = LDAP_OPERATIONS_ERROR; + err_msg = "Failed to handle the request.\n"; + goto done; + } + + ret = pack_response(res, &ret_val); + if (ret != LDAP_SUCCESS) { + rc = LDAP_OPERATIONS_ERROR; + err_msg = "Failed to pack the response.\n"; + goto done; + } + + ret = slapi_pblock_set(pb, SLAPI_EXT_OP_RET_OID, EXOP_EXTDOM_OID); + if (ret != 0) { + rc = LDAP_OPERATIONS_ERROR; + err_msg = "Failed to set the OID for the response.\n"; + goto done; + } + + ret = slapi_pblock_set( pb, SLAPI_EXT_OP_RET_VALUE, ret_val); + if (ret != 0) { + rc = LDAP_OPERATIONS_ERROR; + err_msg = "Failed to set the value for the response.\n"; + goto done; + } + + rc = LDAP_SUCCESS; + +done: + free(req); + free(res); + if (err_msg != NULL) { + LOG(err_msg); + } + slapi_send_ldap_result(pb, rc, NULL, err_msg, 0, NULL); + return SLAPI_PLUGIN_EXTENDED_SENT_RESULT; +} + +static int ipa_extdom_init_ctx(Slapi_PBlock *pb, struct ipa_extdom_ctx **_ctx) +{ + struct ipa_extdom_ctx *ctx; + Slapi_Entry *e; + int ret; + + ctx = calloc(1, sizeof(struct ipa_extdom_ctx)); + if (!ctx) { + return LDAP_OPERATIONS_ERROR; + } + + ret = slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &ctx->plugin_id); + if ((ret != 0) || (NULL == ctx->plugin_id)) { + LOG_FATAL("Could not get identity or identity was NULL\n"); + if (ret == 0) { + ret = -1; + } + goto done; + } + + slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &e); + if (!e) { + LOG_FATAL("Plugin configuration not found!\n"); + return -1; + } + + ctx->base_dn = slapi_entry_attr_get_charptr(e, "nsslapd-basedn"); + if (!ctx->base_dn) { + LOG_FATAL("Base DN not found in plugin configuration not found!\n"); + return -1; + } + + +done: + if (ret) { + free(ctx); + } else { + *_ctx = ctx; + } + return ret; +} + +int ipa_extdom_init(Slapi_PBlock *pb) +{ + int ret; + struct ipa_extdom_ctx *extdom_ctx; + + ret = ipa_extdom_init_ctx(pb, &extdom_ctx); + if (ret) { + LOG_FATAL("Failed ot initialize external domain extended operation.\n"); + /* do not cause DS to stop, simply do nothing */ + return 0; + } + + ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01); + if (!ret) { + ret = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, + (void *)&ipa_extdom_plugin_desc); + } + if (!ret) { + ret = slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN, + (void *)ipa_extdom_start); + } + if (!ret) { + ret = slapi_pblock_set(pb, SLAPI_PLUGIN_EXT_OP_OIDLIST, + ipa_extdom_oid_list); + } + if (!ret) { + ret = slapi_pblock_set(pb, SLAPI_PLUGIN_EXT_OP_NAMELIST, + ipa_extdom_name_list); + } + if (!ret) { + ret = slapi_pblock_set(pb, SLAPI_PLUGIN_EXT_OP_FN, + (void *)ipa_extdom_extop); + } + if (!ret) { + ret = slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, extdom_ctx); + } + if (ret) { + LOG("Failed to set plug-in version, function, and OID.\n" ); + return -1; + } + + return 0; +} diff --git a/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_tests.c b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_tests.c new file mode 100644 index 00000000..acb6ae28 --- /dev/null +++ b/daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_tests.c @@ -0,0 +1,203 @@ +/** BEGIN COPYRIGHT BLOCK + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Additional permission under GPLv3 section 7: + * + * In the following paragraph, "GPL" means the GNU General Public + * License, version 3 or any later version, and "Non-GPL Code" means + * code that is governed neither by the GPL nor a license + * compatible with the GPL. + * + * You may link the code of this Program with Non-GPL Code and convey + * linked combinations including the two, provided that such Non-GPL + * Code only links to the code of this Program through those well + * defined interfaces identified in the file named EXCEPTION found in + * the source code files (the "Approved Interfaces"). The files of + * Non-GPL Code may instantiate templates or use macros or inline + * functions from the Approved Interfaces without causing the resulting + * work to be covered by the GPL. Only the copyright holders of this + * Program may make changes or additions to the list of Approved + * Interfaces. + * + * Authors: + * Sumit Bose <sbose@redhat.com> + * + * Copyright (C) 2011 Red Hat, Inc. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +#include <check.h> + +#include "ipa_extdom.h" +#include "util.h" + +char req_sid[] = {0x30, 0x11, 0x0a, 0x01, 0x01, 0x0a, 0x01, 0x01, 0x04, 0x09, \ + 0x53, 0x2d, 0x31, 0x2d, 0x32, 0x2d, 0x33, 0x2d, 0x34}; +char req_nam[] = {0x30, 0x16, 0x0a, 0x01, 0x02, 0x0a, 0x01, 0x01, 0x30, 0x0e, \ + 0x04, 0x06, 0x44, 0x4f, 0x4d, 0x41, 0x49, 0x4e, 0x04, 0x04, \ + 0x74, 0x65, 0x73, 0x74}; +char req_uid[] = {0x30, 0x14, 0x0a, 0x01, 0x03, 0x0a, 0x01, 0x01, 0x30, 0x0c, \ + 0x04, 0x06, 0x44, 0x4f, 0x4d, 0x41, 0x49, 0x4e, 0x02, 0x02, \ + 0x30, 0x39}; +char req_gid[] = {0x30, 0x15, 0x0a, 0x01, 0x04, 0x0a, 0x01, 0x01, 0x30, 0x0d, \ + 0x04, 0x06, 0x44, 0x4f, 0x4d, 0x41, 0x49, 0x4e, 0x02, 0x03, \ + 0x00, 0xd4, 0x31}; + +char res_sid[] = {0x30, 0x0e, 0x0a, 0x01, 0x01, 0x04, 0x09, 0x53, 0x2d, 0x31, \ + 0x2d, 0x32, 0x2d, 0x33, 0x2d, 0x34}; +char res_nam[] = {0x30, 0x13, 0x0a, 0x01, 0x02, 0x30, 0x0e, 0x04, 0x06, 0x44, \ + 0x4f, 0x4d, 0x41, 0x49, 0x4e, 0x04, 0x04, 0x74, 0x65, 0x73, \ + 0x74}; +char res_uid[] = {0x30, 0x17, 0x0a, 0x01, 0x03, 0x30, 0x12, 0x04, 0x06, 0x44, \ + 0x4f, 0x4d, 0x41, 0x49, 0x4e, 0x04, 0x04, 0x74, 0x65, 0x73, \ + 0x74, 0x02, 0x02, 0x30, 0x39}; +char res_gid[] = {0x30, 0x1e, 0x0a, 0x01, 0x04, 0x30, 0x19, 0x04, 0x06, 0x44, \ + 0x4f, 0x4d, 0x41, 0x49, 0x4e, 0x04, 0x0a, 0x74, 0x65, 0x73, \ + 0x74, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x02, 0x03, 0x00, \ + 0xd4, 0x31}; + +#define TEST_SID "S-1-2-3-4" +#define TEST_DOMAIN_NAME "DOMAIN" + +START_TEST(test_encode) +{ + int ret; + struct extdom_res res; + struct berval *resp_val; + + res.response_type = RESP_SID; + res.data.sid = TEST_SID; + + ret = pack_response(&res, &resp_val); + + fail_unless(ret == LDAP_SUCCESS, "pack_response() failed."); + fail_unless(sizeof(res_sid) == resp_val->bv_len && + memcmp(res_sid, resp_val->bv_val, resp_val->bv_len) == 0, + "Unexpected BER blob."); + ber_memfree(resp_val); + + res.response_type = RESP_NAME; + res.data.name.domain_name = TEST_DOMAIN_NAME; + res.data.name.object_name = "test"; + + ret = pack_response(&res, &resp_val); + + fail_unless(ret == LDAP_SUCCESS, "pack_response() failed."); + fail_unless(sizeof(res_nam) == resp_val->bv_len && + memcmp(res_nam, resp_val->bv_val, resp_val->bv_len) == 0, + "Unexpected BER blob."); + ber_memfree(resp_val); +} +END_TEST + +START_TEST(test_decode) +{ + struct berval req_val; + struct extdom_req *req; + int ret; + + req_val.bv_val = req_sid; + req_val.bv_len = sizeof(req_sid); + + ret = parse_request_data(&req_val, &req); + + fail_unless(ret == LDAP_SUCCESS, "parse_request_data() failed."); + fail_unless(req->input_type == INP_SID, + "parse_request_data() returned unexpected input type"); + fail_unless(req->request_type == REQ_SIMPLE, + "parse_request_data() returned unexpected request type"); + fail_unless(strcmp(req->data.sid, "S-1-2-3-4") == 0, + "parse_request_data() returned unexpected sid"); + free(req); + + req_val.bv_val = req_nam; + req_val.bv_len = sizeof(req_nam); + + ret = parse_request_data(&req_val, &req); + + fail_unless(ret == LDAP_SUCCESS, + "parse_request_data() failed."); + fail_unless(req->input_type == INP_NAME, + "parse_request_data() returned unexpected input type"); + fail_unless(req->request_type == REQ_SIMPLE, + "parse_request_data() returned unexpected request type"); + fail_unless(strcmp(req->data.name.domain_name, "DOMAIN") == 0, + "parse_request_data() returned unexpected domain name"); + fail_unless(strcmp(req->data.name.object_name, "test") == 0, + "parse_request_data() returned unexpected object name"); + free(req); + + req_val.bv_val = req_uid; + req_val.bv_len = sizeof(req_uid); + + ret = parse_request_data(&req_val, &req); + + fail_unless(ret == LDAP_SUCCESS, + "parse_request_data() failed."); + fail_unless(req->input_type == INP_POSIX_UID, + "parse_request_data() returned unexpected input type"); + fail_unless(req->request_type == REQ_SIMPLE, + "parse_request_data() returned unexpected request type"); + fail_unless(strcmp(req->data.posix_uid.domain_name, "DOMAIN") == 0, + "parse_request_data() returned unexpected domain name"); + fail_unless(req->data.posix_uid.uid == 12345, + "parse_request_data() returned unexpected uid [%d]", + req->data.posix_uid.uid); + free(req); + + req_val.bv_val = req_gid; + req_val.bv_len = sizeof(req_gid); + + ret = parse_request_data(&req_val, &req); + + fail_unless(ret == LDAP_SUCCESS, + "parse_request_data() failed."); + fail_unless(req->input_type == INP_POSIX_GID, + "parse_request_data() returned unexpected input type"); + fail_unless(req->request_type == REQ_SIMPLE, + "parse_request_data() returned unexpected request type"); + fail_unless(strcmp(req->data.posix_gid.domain_name, "DOMAIN") == 0, + "parse_request_data() returned unexpected domain name"); + fail_unless(req->data.posix_gid.gid == 54321, + "parse_request_data() returned unexpected gid [%d]", + req->data.posix_gid.gid); + free(req); +} +END_TEST + +Suite * ipa_extdom_suite(void) +{ + Suite *s = suite_create("IPA extdom"); + + TCase *tc_core = tcase_create("Core"); + tcase_add_test(tc_core, test_decode); + tcase_add_test(tc_core, test_encode); + /* TODO: add test for create_response() */ + suite_add_tcase(s, tc_core); + + return s; +} + +int main(void) +{ + int number_failed; + + Suite *s = ipa_extdom_suite (); + SRunner *sr = srunner_create (s); + srunner_run_all (sr, CK_VERBOSE); + number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/freeipa.spec.in b/freeipa.spec.in index 32fe6457..72ac0e7a 100644 --- a/freeipa.spec.in +++ b/freeipa.spec.in @@ -81,6 +81,8 @@ BuildRequires: python-lxml BuildRequires: python-pyasn1 >= 0.0.9a BuildRequires: python-dns BuildRequires: python-crypto +BuildRequires: check >= 0.9.5 +BuildRequires: libsss_idmap-devel %description IPA is an integrated solution to provide centrally managed Identity (machine, @@ -361,6 +363,7 @@ rm %{buildroot}/%{plugin_dir}/libipa_lockout.la rm %{buildroot}/%{plugin_dir}/libipa_cldap.la rm %{buildroot}/%{plugin_dir}/libipa_sidgen.la rm %{buildroot}/%{plugin_dir}/libipa_sidgen_task.la +rm %{buildroot}/%{plugin_dir}/libipa_extdom_extop.la rm %{buildroot}/%{_libdir}/krb5/plugins/kdb/ipadb.la rm %{buildroot}/%{_libdir}/samba/pdb/ipasam.la @@ -668,6 +671,7 @@ fi %files server-trust-ad %{_sbindir}/ipa-adtrust-install +%attr(755,root,root) %{plugin_dir}/libipa_extdom_extop.so %{_usr}/share/ipa/smb.conf.empty %attr(755,root,root) %{_libdir}/samba/pdb/ipasam.so %attr(755,root,root) %{plugin_dir}/libipa_sidgen.so @@ -728,6 +732,9 @@ fi %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/ca.crt %changelog +* Fri Jun 21 2012 Sumit Bose <sbose@redhat.com> - 2.99.0-36 +- Add extdom extop plugin + * Fri Jun 21 2012 Rob Crittenden <rcritten@redhat.com> - 2.99.0-35 - Add client requires on libsss-autofs, autofs, libnfsidmap and nfs-utils for configuring automount and NFS. diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py index ba2e6ef5..967b54e2 100644 --- a/ipaserver/install/adtrustinstance.py +++ b/ipaserver/install/adtrustinstance.py @@ -230,6 +230,12 @@ class ADTRUSTInstance(service.Service): except: pass + def __add_extdom_module(self): + try: + self._ldap_mod("ipa-extdom-extop-conf.ldif", self.sub_dict) + except: + pass + def __write_smb_registry(self): template = os.path.join(ipautil.SHARE_DIR, "smb.conf.template") conf = ipautil.template_file(template, self.sub_dict) @@ -361,8 +367,9 @@ class ADTRUSTInstance(service.Service): def __start(self): try: self.start() + ipaservices.service('winbind').start() except: - root_logger.critical("smbd service failed to start") + root_logger.critical("CIFS services failed to start") def __stop(self): self.backup_state("running", self.is_running()) @@ -387,7 +394,12 @@ class ADTRUSTInstance(service.Service): self.suffix) except (ldap.ALREADY_EXISTS, errors.DuplicateEntry), e: root_logger.info("ADTRUST Service startup entry already exists.") - pass + + try: + self.ldap_enable('EXTID', self.fqdn, self.dm_password, \ + self.suffix) + except (ldap.ALREADY_EXISTS, errors.DuplicateEntry), e: + root_logger.info("EXTID Service startup entry already exists.") def __setup_sub_dict(self): self.sub_dict = dict(REALM = self.realm_name, @@ -438,17 +450,18 @@ class ADTRUSTInstance(service.Service): self.step("adding admin(group) SIDs", self.__add_admin_sids) self.step("activating CLDAP plugin", self.__add_cldap_module) self.step("activating sidgen plugin and task", self.__add_sidgen_module) + self.step("activating extdom plugin", self.__add_extdom_module) self.step("configuring smbd to start on boot", self.__enable) if not self.no_msdcs: self.step("adding special DNS service records", \ self.__add_dns_service_records) - self.step("restarting Directory Server to take MS PAC and CLDAP changes into account", \ + self.step("restarting Directory Server to take MS PAC and LDAP plugins changes into account", \ self.__restart_dirsrv) self.step("setting SELinux booleans", \ self.__configure_selinux_for_smbd) - self.step("starting smbd", self.__start) + self.step("starting CIFS services", self.__start) - self.start_creation("Configuring smbd:") + self.start_creation("Configuring CIFS:") def uninstall(self): if self.is_configured(): diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py index a3d09fcd..5cc7ae63 100644 --- a/ipaserver/install/service.py +++ b/ipaserver/install/service.py @@ -42,7 +42,8 @@ SERVICE_LIST = { 'MEMCACHE':('ipa_memcached', 39), 'HTTP':('httpd', 40), 'CA':('pki-cad', 50), - 'ADTRUST':('smb', 60) + 'ADTRUST':('smb', 60), + 'EXTID':('winbind', 70) } def print_msg(message, output_fd=sys.stdout): |