diff options
Diffstat (limited to 'usr/src/cmd')
| -rw-r--r-- | usr/src/cmd/idmap/idmap/Makefile | 14 | ||||
| -rw-r--r-- | usr/src/cmd/idmap/idmap/idmap.c | 16 | ||||
| -rw-r--r-- | usr/src/cmd/idmap/idmap/namemaps.c | 1067 | ||||
| -rw-r--r-- | usr/src/cmd/idmap/idmap/namemaps.h | 62 | ||||
| -rw-r--r-- | usr/src/cmd/idmap/idmapd/idmap_config.c | 214 | ||||
| -rw-r--r-- | usr/src/cmd/idmap/idmapd/idmapd.c | 18 | ||||
| -rw-r--r-- | usr/src/cmd/smbsrv/smbd/smbd_doorsvc.c | 53 | ||||
| -rw-r--r-- | usr/src/cmd/smbsrv/smbd/smbd_logon.c | 17 | ||||
| -rw-r--r-- | usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c | 15 |
9 files changed, 1352 insertions, 124 deletions
diff --git a/usr/src/cmd/idmap/idmap/Makefile b/usr/src/cmd/idmap/idmap/Makefile index 44c2cf7dc7..fa12170f8a 100644 --- a/usr/src/cmd/idmap/idmap/Makefile +++ b/usr/src/cmd/idmap/idmap/Makefile @@ -19,12 +19,11 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. # PROG = idmap -CLIENTOBJS = idmap.o idmap_engine.o +CLIENTOBJS = idmap.o idmap_engine.o namemaps.o # idmap_clnt.o CLIENTSRCS = $(CLIENTOBJS:%.o=%.c) POFILES = $(CLIENTOBJS:.o=.po) @@ -35,11 +34,16 @@ IDMAP_PROT_DIR = $(SRC)/head/rpcsvc include ../../Makefile.cmd POFILE = $(PROG)_all.po -LDLIBS += -lidmap +LDLIBS += -lidmap -ladutils -lsldap -lldap FILEMODE = 0555 -INCS += -I. -I../../../lib/libidmap/common -I$(IDMAP_PROT_DIR) +INCS += -I. \ + -I../../../lib/libidmap/common \ + -I../../../lib/libadutils/common \ + -I../../../lib/libsldap/common \ + -I$(IDMAP_PROT_DIR) +CFLAGS += $(CCVERBOSE) $(OBJS) := CPPFLAGS += $(INCS) -D_REENTRANT $(POFILE) := CPPFLAGS += $(INCS) diff --git a/usr/src/cmd/idmap/idmap/idmap.c b/usr/src/cmd/idmap/idmap/idmap.c index 7543f6acc9..57c6b3bfe5 100644 --- a/usr/src/cmd/idmap/idmap/idmap.c +++ b/usr/src/cmd/idmap/idmap/idmap.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ @@ -35,6 +34,8 @@ #include <note.h> #include "idmap_engine.h" #include "idmap_priv.h" +#include "namemaps.h" +#include "libadutils.h" /* Initialization values for pids/rids: */ @@ -3541,12 +3542,16 @@ cleanup: /* printflike */ +static void -/* LINTED E_FUNC_ARG_UNUSED */ -logger(int pri, const char *format, ...) +idmap_cli_logger(int pri, const char *format, ...) { + NOTE(ARGUNUSED(pri)) va_list args; + if (pri == LOG_DEBUG) + return; + va_start(args, format); (void) vfprintf(stderr, format, args); @@ -3567,7 +3572,8 @@ main(int argc, char *argv[]) (void) textdomain(TEXT_DOMAIN); /* Redirect logging */ - idmap_set_logger(logger); + idmap_set_logger(idmap_cli_logger); + adutils_set_logger(idmap_cli_logger); /* idmap_engine determines the batch_mode: */ rc = engine_init(sizeof (commands) / sizeof (cmd_ops_t), diff --git a/usr/src/cmd/idmap/idmap/namemaps.c b/usr/src/cmd/idmap/idmap/namemaps.c new file mode 100644 index 0000000000..53c89f1554 --- /dev/null +++ b/usr/src/cmd/idmap/idmap/namemaps.c @@ -0,0 +1,1067 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + + +#include <errno.h> +#include <ldap.h> +#include <sasl/sasl.h> +#include <libintl.h> +#include <strings.h> +#include <syslog.h> +#include <stdarg.h> + +#include "addisc.h" +#include "libadutils.h" +#include "idmap_priv.h" +#include "ns_sldap.h" +#include "namemaps.h" + +/* From adutils.c: */ + +/* A single DS */ +struct idmap_nm_handle { + LDAP *ad; /* LDAP connection */ + /* LDAP DS info */ + char *ad_host; + int ad_port; + + /* hardwired to SASL GSSAPI only for now */ + char *saslmech; + unsigned saslflags; + char *windomain; + char *ad_unixuser_attr; + char *ad_unixgroup_attr; + char *nldap_winname_attr; + char *default_domain; + bool_t is_nldap; + bool_t is_ad; + int direction; + ns_cred_t nsc; +}; + +/* PRINTFLIKE1 */ +static +void +namemap_log(char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + (void) vfprintf(stderr, fmt, va); + va_end(va); + (void) fprintf(stderr, "\n"); +} + +static +idmap_stat +string2auth(const char *from, ns_auth_t *na) +{ + if (from == NULL) { + na->type = NS_LDAP_AUTH_SASL; + na->tlstype = NS_LDAP_TLS_SASL; + na->saslmech = NS_LDAP_SASL_GSSAPI; + na->saslopt = NS_LDAP_SASLOPT_PRIV | + NS_LDAP_SASLOPT_INT; + return (IDMAP_SUCCESS); + } + + if (strcasecmp(from, "simple") == 0) { + na->type = NS_LDAP_AUTH_SIMPLE; + na->tlstype = NS_LDAP_TLS_NONE; + na->saslmech = NS_LDAP_SASL_NONE; + na->saslopt = NS_LDAP_SASLOPT_NONE; + } else if (strcasecmp(from, "sasl/CRAM-MD5") == 0) { + na->type = NS_LDAP_AUTH_SASL; + na->tlstype = NS_LDAP_TLS_SASL; + na->saslmech = NS_LDAP_SASL_CRAM_MD5; + na->saslopt = NS_LDAP_SASLOPT_NONE; + } else if (strcasecmp(from, "sasl/DIGEST-MD5") == 0) { + na->type = NS_LDAP_AUTH_SASL; + na->tlstype = NS_LDAP_TLS_SASL; + na->saslmech = NS_LDAP_SASL_DIGEST_MD5; + na->saslopt = NS_LDAP_SASLOPT_NONE; + } else if (strcasecmp(from, "sasl/GSSAPI") == 0) { + na->type = NS_LDAP_AUTH_SASL; + na->tlstype = NS_LDAP_TLS_SASL; + na->saslmech = NS_LDAP_SASL_GSSAPI; + na->saslopt = NS_LDAP_SASLOPT_PRIV | + NS_LDAP_SASLOPT_INT; + } else if (strcasecmp(from, "tls:simple") == 0) { + na->type = NS_LDAP_AUTH_TLS; + na->tlstype = NS_LDAP_TLS_SIMPLE; + na->saslmech = NS_LDAP_SASL_NONE; + na->saslopt = NS_LDAP_SASLOPT_NONE; + } else if (strcasecmp(from, "tls:sasl/CRAM-MD5") == 0) { + na->type = NS_LDAP_AUTH_TLS; + na->tlstype = NS_LDAP_TLS_SASL; + na->saslmech = NS_LDAP_SASL_CRAM_MD5; + na->saslopt = NS_LDAP_SASLOPT_NONE; + } else if (strcasecmp(from, "tls:sasl/DIGEST-MD5") == 0) { + na->type = NS_LDAP_AUTH_TLS; + na->tlstype = NS_LDAP_TLS_SASL; + na->saslmech = NS_LDAP_SASL_DIGEST_MD5; + na->saslopt = NS_LDAP_SASLOPT_NONE; + } else { + namemap_log( + gettext("Invalid authentication method \"%s\" specified\n"), + from); + return (IDMAP_ERR_ARG); + } + + return (IDMAP_SUCCESS); +} + + + +static +idmap_stat +strings2cred(ns_cred_t *nsc, char *user, char *passwd, char *auth) +{ + idmap_stat rc; + (void) memset(nsc, 0, sizeof (ns_cred_t)); + + if ((rc = string2auth(auth, &nsc->auth)) != IDMAP_SUCCESS) + return (rc); + + if (user != NULL) { + nsc->cred.unix_cred.userID = strdup(user); + if (nsc->cred.unix_cred.userID == NULL) + return (IDMAP_ERR_MEMORY); + } + + if (passwd != NULL) { + nsc->cred.unix_cred.passwd = strdup(passwd); + if (nsc->cred.unix_cred.passwd == NULL) { + free(nsc->cred.unix_cred.userID); + return (IDMAP_ERR_MEMORY); + } + } + + return (IDMAP_SUCCESS); +} + + + + + +/*ARGSUSED*/ +static int +idmap_saslcallback(LDAP *ld, unsigned flags, void *defaults, void *prompts) +{ + sasl_interact_t *interact; + + if (prompts == NULL || flags != LDAP_SASL_INTERACTIVE) + return (LDAP_PARAM_ERROR); + + /* There should be no extra arguemnts for SASL/GSSAPI authentication */ + for (interact = prompts; interact->id != SASL_CB_LIST_END; + interact++) { + interact->result = NULL; + interact->len = 0; + } + return (LDAP_SUCCESS); +} + +static +idmap_stat +idmap_open_ad_conn(idmap_nm_handle_t *adh) +{ + int zero = 0; + int timeoutms = 30 * 1000; + int ldversion, ldap_rc; + idmap_stat rc = IDMAP_SUCCESS; + + /* Open and bind an LDAP connection */ + adh->ad = ldap_init(adh->ad_host, adh->ad_port); + if (adh->ad == NULL) { + namemap_log( + gettext("ldap_init() to server %s port %d failed. (%s)"), + CHECK_NULL(adh->ad_host), + adh->ad_port, strerror(errno)); + rc = IDMAP_ERR_INTERNAL; + goto out; + } + ldversion = LDAP_VERSION3; + (void) ldap_set_option(adh->ad, LDAP_OPT_PROTOCOL_VERSION, &ldversion); + (void) ldap_set_option(adh->ad, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); + (void) ldap_set_option(adh->ad, LDAP_OPT_TIMELIMIT, &zero); + (void) ldap_set_option(adh->ad, LDAP_OPT_SIZELIMIT, &zero); + (void) ldap_set_option(adh->ad, LDAP_X_OPT_CONNECT_TIMEOUT, &timeoutms); + (void) ldap_set_option(adh->ad, LDAP_OPT_RESTART, LDAP_OPT_ON); + ldap_rc = ldap_sasl_interactive_bind_s(adh->ad, "" /* binddn */, + adh->saslmech, NULL, NULL, adh->saslflags, &idmap_saslcallback, + NULL); + + if (ldap_rc != LDAP_SUCCESS) { + (void) ldap_unbind(adh->ad); + adh->ad = NULL; + namemap_log( + gettext("ldap_sasl_interactive_bind_s() to server " + "%s port %d failed. (%s)"), CHECK_NULL(adh->ad_host), + adh->ad_port, ldap_err2string(ldap_rc)); + rc = IDMAP_ERR_INTERNAL; + } + +out: + return (rc); +} + +static +idmap_stat +idmap_init_nldap(idmap_nm_handle_t *p) +{ +/* + * For now, there is nothing to initialize in nldap. This is just to + * make it future-proof, especially standalone libsldap-proof + */ + p->is_nldap = TRUE; + return (0); +} + +static +idmap_stat +idmap_init_ad(idmap_nm_handle_t *p) +{ + idmap_stat rc = IDMAP_SUCCESS; + idmap_ad_disc_ds_t *dc = NULL; + ad_disc_t ad_ctx; + + ad_ctx = ad_disc_init(); + if (ad_ctx == NULL) { + namemap_log( + gettext("AD autodiscovery initialization failed")); + return (IDMAP_ERR_INTERNAL); + } + ad_disc_refresh(ad_ctx); + + + /* Based on the supplied or default domain, find the proper AD: */ + if (ad_disc_set_DomainName(ad_ctx, p->windomain)) { + rc = IDMAP_ERR_INTERNAL; + namemap_log( + gettext("Setting a domain name \"%s\" for autodiscovery" + " failed, most likely not enough memory"), p->windomain); + goto cleanup; + } + + dc = ad_disc_get_DomainController(ad_ctx, AD_DISC_GLOBAL, NULL); + if (dc == NULL) { + rc = IDMAP_ERR_ARG; + namemap_log( + gettext("A domain controller for the " + "domain \"%s\" not found."), p->windomain); + goto cleanup; + } + + + p->ad_port = dc->port; + p->ad_host = strdup(dc->host); + + if (p->ad_host == NULL) { + rc = IDMAP_ERR_MEMORY; + goto cleanup; + } + + p->saslflags = LDAP_SASL_INTERACTIVE; + p->saslmech = strdup("GSSAPI"); + + if (p->saslmech == NULL) { + rc = IDMAP_ERR_MEMORY; + goto cleanup; + } + + rc = idmap_open_ad_conn(p); + + if (rc != IDMAP_SUCCESS) + goto cleanup; + + p->is_ad = TRUE; + +cleanup: + ad_disc_fini(ad_ctx); + free(dc); + return (rc); +} + +void +idmap_fini_namemaps(idmap_nm_handle_t *p) +{ + if (p == NULL) + return; + + if (p->ad_unixgroup_attr != NULL) + free(p->ad_unixgroup_attr); + + if (p->ad_unixuser_attr != NULL) + free(p->ad_unixuser_attr); + + if (p->nldap_winname_attr) + free(p->nldap_winname_attr); + + if (p->windomain != NULL) + free(p->windomain); + + if (p->default_domain != NULL) + free(p->default_domain); + + if (p->saslmech != NULL) + free(p->saslmech); + + if (p->ad_host != NULL) + free(p->ad_host); + + if (p->nsc.cred.unix_cred.userID != NULL) { + free(p->nsc.cred.unix_cred.userID); + } + + if (p->nsc.cred.unix_cred.passwd != NULL) { + /* No archeology: */ + (void) memset(p->nsc.cred.unix_cred.passwd, 0, + strlen(p->nsc.cred.unix_cred.passwd)); + free(p->nsc.cred.unix_cred.passwd); + } + + if (p->ad) + (void) ldap_unbind(p->ad); + free(p); + +} + + + +idmap_stat +idmap_init_namemaps(idmap_handle_t *handle, idmap_nm_handle_t **adh, + char *user, char *passwd, char *auth, char *windomain, + int direction) +{ + idmap_stat rc; + idmap_nm_handle_t *p; + + p = (idmap_nm_handle_t *)calloc(1, sizeof (idmap_nm_handle_t)); + if (p == NULL) + return (IDMAP_ERR_MEMORY); + + rc = idmap_get_prop_str(handle, PROP_DEFAULT_DOMAIN, + &p->default_domain); + if (rc != IDMAP_SUCCESS) { + namemap_log( + gettext("Error obtaining default domain from idmapd (%s)"), + idmap_stat2string(NULL, rc)); + goto cleanup; + } + + rc = idmap_get_prop_str(handle, PROP_AD_UNIXUSER_ATTR, + &p->ad_unixuser_attr); + if (rc != IDMAP_SUCCESS) { + namemap_log( + gettext("Error obtaining AD unixuser attribute (%s)"), + idmap_stat2string(NULL, rc)); + goto cleanup; + } + + rc = idmap_get_prop_str(handle, PROP_AD_UNIXGROUP_ATTR, + &p->ad_unixgroup_attr); + if (rc != IDMAP_SUCCESS) { + namemap_log( + gettext("Error obtaining AD unixgroup attribute (%s)"), + idmap_stat2string(NULL, rc)); + goto cleanup; + } + + + rc = idmap_get_prop_str(handle, PROP_NLDAP_WINNAME_ATTR, + &p->nldap_winname_attr); + if (rc != IDMAP_SUCCESS) { + namemap_log( + gettext("Error obtaining AD unixgroup attribute (%s)"), + idmap_stat2string(NULL, rc)); + goto cleanup; + } + + if (windomain != NULL) { + p->windomain = strdup(windomain); + if (p->windomain == NULL) { + rc = IDMAP_ERR_MEMORY; + goto cleanup; + } + } else if (!EMPTY_STRING(p->default_domain)) { + p->windomain = strdup(p->default_domain); + if (p->windomain == NULL) { + rc = IDMAP_ERR_MEMORY; + goto cleanup; + } + } else if (direction == IDMAP_DIRECTION_W2U) { + namemap_log( + gettext("Windows domain not given and idmapd daemon" + " didn't provide a default one")); + rc = IDMAP_ERR_ARG; + goto cleanup; + } + + p->direction = direction; + + if ((p->ad_unixuser_attr != NULL || p->ad_unixgroup_attr != NULL) && + direction != IDMAP_DIRECTION_U2W) { + rc = idmap_init_ad(p); + if (rc != IDMAP_SUCCESS) { + goto cleanup; + } + } + + if (p->nldap_winname_attr != NULL && direction != IDMAP_DIRECTION_W2U) { + rc = idmap_init_nldap(p); + if (rc != IDMAP_SUCCESS) { + goto cleanup; + } + + rc = strings2cred(&p->nsc, user, passwd, auth); + if (rc != IDMAP_SUCCESS) { + goto cleanup; + } + } + +cleanup: + + if (rc == IDMAP_SUCCESS) { + *adh = p; + return (IDMAP_SUCCESS); + } + + /* There was an error: */ + idmap_fini_namemaps(*adh); + return (rc); +} + +static +char * +dns2dn(const char *dns, const char *prefix) +{ + int num_lvl = 1; + char *buf; + const char *it, *new_it; + + for (it = dns; it != NULL; it = strchr(it, '.')) { + it ++; + num_lvl ++; + } + + buf = (char *)malloc(strlen(prefix) + strlen(dns) + 4 * num_lvl); + (void) strcpy(buf, prefix); + + + it = dns; + for (;;) { + new_it = strchr(it, '.'); + (void) strcat(buf, "DC="); + if (new_it == NULL) { + (void) strcat(buf, it); + break; + } else { + (void) strncat(buf, it, new_it - it); + (void) strcat(buf, ","); + } + + it = new_it + 1; + } + + return (buf); +} + + +static +idmap_stat +extract_attribute(idmap_nm_handle_t *p, LDAPMessage *entry, char *name, + char **value) +{ + char **values = NULL; + idmap_stat rc = IDMAP_SUCCESS; + /* No value means it is not requested */ + if (value == NULL) + return (IDMAP_SUCCESS); + + values = ldap_get_values(p->ad, entry, name); + if (values == NULL || values[0] == NULL) + *value = NULL; + else { + *value = strdup(values[0]); + if (*value == NULL) + rc = IDMAP_ERR_MEMORY; + } +errout: + ldap_value_free(values); + return (rc); +} + + +/* Split winname to its name and domain part */ +static +idmap_stat +split_fqwn(char *fqwn, char **name, char **domain) +{ + char *at; + + *name = NULL; + *domain = NULL; + + at = strchr(fqwn, '@'); + if (at == NULL) { + at = strchr(fqwn, '\\'); + } + if (at == NULL) { + /* There is no domain - leave domain NULL */ + *name = strdup(fqwn); + if (*name == NULL) + goto errout; + return (IDMAP_SUCCESS); + } + + + *domain = strdup(at+1); + if (*domain == NULL) + goto errout; + *name = (char *)malloc(at - fqwn + 1); + if (*name == NULL) + goto errout; + (void) strlcpy(*name, fqwn, at - fqwn + 1); + + if (*at == '\\') { + char *it = *name; + *name = *domain; + *domain = it; + } + + return (IDMAP_SUCCESS); + + +errout: + free(*name); + *name = NULL; + free(*domain); + *domain = NULL; + return (IDMAP_ERR_MEMORY); +} + +static +idmap_stat +unixname2dn(idmap_nm_handle_t *p, char *unixname, int is_user, char **dn, + char **winname, char **windomain) +{ + idmap_stat rc = IDMAP_SUCCESS; + int rc_ns; + + + char filter[255]; + static const char *attribs[3]; + ns_ldap_result_t *res; + ns_ldap_error_t *errorp = NULL; + char **attrs; + + + attribs[0] = p->nldap_winname_attr; + attribs[1] = "dn"; + attribs[2] = NULL; + + (void) snprintf(filter, sizeof (filter), is_user ? "uid=%s" : "cn=%s", + unixname); + + rc_ns = __ns_ldap_list(is_user ? "passwd" : "group", + filter, NULL, attribs, NULL, 0, &res, &errorp, NULL, NULL); + + + if (rc_ns == NS_LDAP_NOTFOUND) { + namemap_log(is_user ? gettext("User %s not found.") + : gettext("Group %s not found."), unixname); + return (IDMAP_ERR_NOTFOUND); + } else if (rc_ns != NS_LDAP_SUCCESS) { + char *msg = "Cause unidentified"; + if (errorp != NULL) { + (void) __ns_ldap_err2str(errorp->status, &msg); + } + namemap_log(gettext("Ldap list failed (%s)."), msg); + return (IDMAP_ERR_ARG); + } + + if (res == NULL) { + namemap_log(gettext("User %s not found"), unixname); + return (IDMAP_ERR_ARG); + } + + if (winname != NULL && windomain != NULL) { + attrs = __ns_ldap_getAttr(&res->entry[0], + p->nldap_winname_attr); + if (attrs != NULL && attrs[0] != NULL) { + rc = split_fqwn(attrs[0], winname, windomain); + } else { + *winname = *windomain = NULL; + } + } + + if (dn != NULL) { + attrs = __ns_ldap_getAttr(&res->entry[0], "dn"); + if (attrs == NULL || attrs[0] == NULL) { + namemap_log(gettext("dn for %s not found"), + unixname); + return (IDMAP_ERR_ARG); + } + *dn = strdup(attrs[0]); + } + + + return (rc); + +} + +#define FILTER "(sAMAccountName=%s)" + +/* Puts the values of attributes to unixuser and unixgroup, unless NULL */ + +static +idmap_stat +winname2dn(idmap_nm_handle_t *p, char *winname, + int *is_wuser, char **dn, char **unixuser, char **unixgroup) +{ + idmap_stat rc = IDMAP_SUCCESS; + char *base; + char *filter; + int flen; + char *attribs[4]; + int i; + LDAPMessage *results = NULL; + LDAPMessage *entry; + int ldap_rc; + + /* Query: */ + + base = dns2dn(p->windomain, ""); + if (base == NULL) { + return (IDMAP_ERR_MEMORY); + } + + i = 0; + attribs[i++] = "objectClass"; + if (unixuser != NULL) + attribs[i++] = p->ad_unixuser_attr; + if (unixgroup != NULL) + attribs[i++] = p->ad_unixgroup_attr; + attribs[i] = NULL; + + flen = snprintf(NULL, 0, FILTER, winname) + 1; + if ((filter = (char *)malloc(flen)) == NULL) { + free(base); + return (IDMAP_ERR_MEMORY); + } + (void) snprintf(filter, flen, FILTER, winname); + + ldap_rc = ldap_search_s(p->ad, base, LDAP_SCOPE_SUBTREE, filter, + attribs, 0, &results); + + free(base); + free(filter); + + if (ldap_rc != LDAP_SUCCESS) { + namemap_log( + gettext("Ldap query to server %s port %d failed. (%s)"), + p->ad_host, p->ad_port, ldap_err2string(ldap_rc)); + (void) ldap_msgfree(results); + return (IDMAP_ERR_OTHER); + } + + + for (entry = ldap_first_entry(p->ad, results), *dn = NULL; + entry != NULL; + entry = ldap_next_entry(p->ad, entry)) { + char **values = NULL; + int i = 0; + values = ldap_get_values(p->ad, entry, "objectClass"); + + if (values == NULL) { + (void) ldap_msgfree(results); + return (IDMAP_ERR_MEMORY); + } + + for (i = 0; i < ldap_count_values(values); i++) { + /* + * is_wuser can be IDMAP_UNKNOWN, in that case we accept + * both User/Group + */ + if (*is_wuser != IDMAP_NO && + strcasecmp(values[i], "User") == 0 || + *is_wuser != IDMAP_YES && + strcasecmp(values[i], "Group") == 0) { + *dn = ldap_get_dn(p->ad, entry); + if (*dn == NULL) { + ldap_value_free(values); + (void) ldap_msgfree(results); + return (IDMAP_ERR_MEMORY); + } + *is_wuser = strcasecmp(values[i], "User") == 0 + ? IDMAP_YES : IDMAP_NO; + break; + } + } + + ldap_value_free(values); + if (*dn != NULL) + break; + } + + if (*dn == NULL) { + namemap_log( + *is_wuser == IDMAP_YES ? gettext("User %s@%s not found") : + *is_wuser == IDMAP_NO ? gettext("Group %s@%s not found") : + gettext("%s@%s not found"), winname, p->windomain); + return (IDMAP_ERR_NOTFOUND); + } + + if (unixuser != NULL) + rc = extract_attribute(p, entry, p->ad_unixuser_attr, + unixuser); + + if (rc == IDMAP_SUCCESS && unixgroup != NULL) + rc = extract_attribute(p, entry, p->ad_unixgroup_attr, + unixgroup); + + (void) ldap_msgfree(results); + + return (rc); +} + + +/* set the given attribute to the given value. If value is NULL, unset it */ +static +idmap_stat +idmap_ad_set(idmap_nm_handle_t *p, char *dn, char *attr, char *value) +{ + idmap_stat rc = IDMAP_SUCCESS; + int ldap_rc; + char *new_values[2] = {NULL, NULL}; + LDAPMod *mods[2] = {NULL, NULL}; + + mods[0] = (LDAPMod *)calloc(1, sizeof (LDAPMod)); + mods[0]->mod_type = strdup(attr); + if (value != NULL) { + mods[0]->mod_op = LDAP_MOD_REPLACE; + new_values[0] = strdup(value); + mods[0]->mod_values = new_values; + } else { + mods[0]->mod_op = LDAP_MOD_DELETE; + mods[0]->mod_values = NULL; + } + + ldap_rc = ldap_modify_s(p->ad, dn, mods); + if (ldap_rc != LDAP_SUCCESS) { + namemap_log( + gettext("Ldap modify of %s, attribute %s failed. (%s)"), + dn, attr, ldap_err2string(ldap_rc)); + rc = IDMAP_ERR_INTERNAL; + } + + + ldap_mods_free(mods, 0); + return (rc); +} + + +/* + * This function takes the p argument just for the beauty of the symmetry + * with idmap_ad_set (and for future enhancements). + */ +static +idmap_stat +/* LINTED E_FUNC_ARG_UNUSED */ +idmap_nldap_set(idmap_nm_handle_t *p, ns_cred_t *nsc, char *dn, char *attr, + char *value, bool_t is_new, int is_user) +{ + int ldaprc; + ns_ldap_error_t *errorp = NULL; + ns_ldap_attr_t *attrs[2]; + + + + attrs[0] = (ns_ldap_attr_t *)malloc(sizeof (ns_ldap_attr_t)); + if (attrs == NULL) + return (IDMAP_ERR_MEMORY); + + attrs[0]->attrname = attr; + + if (value != NULL) { + char **newattr = (char **)calloc(2, sizeof (char *)); + if (newattr == NULL) { + free(attrs[0]); + return (IDMAP_ERR_MEMORY); + } + newattr[0] = value; + newattr[1] = NULL; + + attrs[0]->attrvalue = newattr; + attrs[0]->value_count = 1; + } else { + attrs[0]->attrvalue = NULL; + attrs[0]->value_count = 0; + } + + + attrs[1] = NULL; + + if (value == NULL) { + ldaprc = __ns_ldap_delAttr( + is_user == IDMAP_YES ? "passwd": "group", + dn, (const ns_ldap_attr_t * const *)attrs, + nsc, 0, &errorp); + } else if (is_new) + ldaprc = __ns_ldap_addAttr( + is_user == IDMAP_YES ? "passwd": "group", + dn, (const ns_ldap_attr_t * const *)attrs, + nsc, 0, &errorp); + else + ldaprc = __ns_ldap_repAttr( + is_user == IDMAP_YES ? "passwd": "group", + dn, (const ns_ldap_attr_t * const *)attrs, + nsc, 0, &errorp); + + if (ldaprc != NS_LDAP_SUCCESS) { + char *msg = "Cause unidentified"; + if (errorp != NULL) { + (void) __ns_ldap_err2str(errorp->status, &msg); + } + namemap_log( + gettext("__ns_ldap_addAttr/rep/delAttr failed (%s)"), + msg); + return (IDMAP_ERR_ARG); + } + + return (IDMAP_SUCCESS); +} + +idmap_stat +idmap_set_namemap(idmap_nm_handle_t *p, char *winname, char *unixname, + int is_user, int is_wuser, int direction) +{ + idmap_stat rc = IDMAP_SUCCESS; + char *dn = NULL; + char *oldwinname = NULL; + char *oldwindomain = NULL; + + if (direction == IDMAP_DIRECTION_W2U) { + if (!p->is_ad) { + rc = IDMAP_ERR_ARG; + namemap_log( + gettext("AD namemaps aren't set up.")); + goto cleanup; + } + + rc = winname2dn(p, winname, &is_wuser, + &dn, NULL, NULL); + if (rc != IDMAP_SUCCESS) + goto cleanup; + + rc = idmap_ad_set(p, dn, is_user ? p->ad_unixuser_attr : + p->ad_unixgroup_attr, unixname); + if (rc != IDMAP_SUCCESS) + goto cleanup; + + } + + + if (direction == IDMAP_DIRECTION_U2W) { + char *fullname; + + if (!p->is_nldap) { + rc = IDMAP_ERR_ARG; + namemap_log( + gettext("Native ldap namemaps aren't set up.")); + goto cleanup; + } + + + rc = unixname2dn(p, unixname, is_user, &dn, + &oldwinname, &oldwindomain); + if (rc != IDMAP_SUCCESS) + goto cleanup; + + if (p->windomain == NULL) { + fullname = strdup(winname); + if (fullname == NULL) + rc = IDMAP_ERR_MEMORY; + goto cleanup; + } else { + fullname = malloc(strlen(winname) + + strlen(p->windomain) + 2); + if (fullname == NULL) { + rc = IDMAP_ERR_MEMORY; + goto cleanup; + } + + (void) snprintf(fullname, + strlen(winname) + strlen(p->windomain) + 2, + "%s\\%s", p->windomain, winname); + } + rc = idmap_nldap_set(p, &p->nsc, dn, p->nldap_winname_attr, + fullname, oldwinname == NULL ? TRUE : FALSE, is_user); + + free(fullname); + free(oldwindomain); + free(oldwinname); + + if (rc != IDMAP_SUCCESS) + goto cleanup; + + } + +cleanup: + if (dn != NULL) + free(dn); + + if (oldwindomain != NULL) + free(oldwindomain); + + if (oldwinname != NULL) + free(oldwinname); + + return (rc); + +} + + +idmap_stat +idmap_unset_namemap(idmap_nm_handle_t *p, char *winname, char *unixname, + int is_user, int is_wuser, int direction) +{ + idmap_stat rc = IDMAP_SUCCESS; + char *dn = NULL; + char *oldwinname = NULL; + char *oldwindomain = NULL; + + if (direction == IDMAP_DIRECTION_W2U) { + if (!p->is_ad) { + rc = IDMAP_ERR_ARG; + namemap_log( + gettext("AD namemaps aren't set up.")); + goto cleanup; + } + + rc = winname2dn(p, winname, &is_wuser, + &dn, NULL, NULL); + if (rc != IDMAP_SUCCESS) + goto cleanup; + + rc = idmap_ad_set(p, dn, is_user ? p->ad_unixuser_attr : + p->ad_unixgroup_attr, unixname); + if (rc != IDMAP_SUCCESS) + goto cleanup; + + } else { /* direction == IDMAP_DIRECTION_U2W */ + if (!p->is_nldap) { + rc = IDMAP_ERR_ARG; + namemap_log( + gettext("Native ldap namemaps aren't set up.")); + goto cleanup; + } + + rc = unixname2dn(p, unixname, is_user, &dn, NULL, NULL); + if (rc != IDMAP_SUCCESS) + goto cleanup; + + rc = idmap_nldap_set(p, &p->nsc, dn, p->nldap_winname_attr, + NULL, TRUE, is_user); + if (rc != IDMAP_SUCCESS) + goto cleanup; + + } + +cleanup: + if (oldwindomain != NULL) + free(oldwindomain); + if (oldwinname != NULL) + free(oldwinname); + if (dn != NULL) + free(dn); + return (rc); +} + +idmap_stat +idmap_get_namemap(idmap_nm_handle_t *p, int *is_source_ad, char **winname, + char **windomain, int *is_wuser, char **unixuser, char **unixgroup) +{ + idmap_stat rc = IDMAP_SUCCESS; + char *dn = NULL; + + *is_source_ad = IDMAP_UNKNOWN; + if (*winname != NULL) { + *is_source_ad = IDMAP_YES; + + if (p->is_ad == NULL) { + rc = IDMAP_ERR_ARG; + namemap_log( + gettext("AD namemaps are not active.")); + goto cleanup; + /* In future maybe resolve winname and try nldap? */ + } + + rc = winname2dn(p, *winname, is_wuser, &dn, unixuser, + unixgroup); + if (rc != IDMAP_SUCCESS) { + namemap_log( + gettext("Winname %s@%s not found in AD."), + *winname, p->windomain); + } + } else if (*unixuser != NULL || *unixgroup != NULL) { + char *unixname; + int is_user; + + *is_source_ad = IDMAP_NO; + + if (p->is_nldap == NULL) { + rc = IDMAP_ERR_ARG; + namemap_log( + gettext("Native ldap namemaps aren't active.")); + goto cleanup; + /* In future maybe resolve unixname and try AD? */ + } + + if (*unixuser != NULL) { + is_user = IDMAP_YES; + unixname = *unixuser; + } else if (*unixgroup != NULL) { + is_user = IDMAP_NO; + unixname = *unixgroup; + } + + rc = unixname2dn(p, unixname, is_user, NULL, winname, + windomain); + if (rc != IDMAP_SUCCESS) { + namemap_log( + gettext("%s %s not found in native ldap."), + is_user == IDMAP_YES ? "UNIX user" : "UNIX group", + unixname); + goto cleanup; + } + } else { + rc = IDMAP_ERR_ARG; + goto cleanup; + } + +cleanup: + return (rc); +} diff --git a/usr/src/cmd/idmap/idmap/namemaps.h b/usr/src/cmd/idmap/idmap/namemaps.h new file mode 100644 index 0000000000..4587406d6c --- /dev/null +++ b/usr/src/cmd/idmap/idmap/namemaps.h @@ -0,0 +1,62 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +/* + * Additional API for Identity Mapping Service + */ + +#ifndef NAMEMAPS_H +#define NAMEMAPS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Directory based name map API + */ + +typedef struct idmap_nm_handle idmap_nm_handle_t; + +/* Set namemap */ +extern idmap_stat idmap_set_namemap(idmap_nm_handle_t *, char *, char *, + int, int, int); + +/* Unset namemap */ +extern idmap_stat idmap_unset_namemap(idmap_nm_handle_t *, char *, char *, + int, int, int); + +extern idmap_stat idmap_get_namemap(idmap_nm_handle_t *p, int *, char **, + char **, int *, char **, char **); + +extern void idmap_fini_namemaps(idmap_nm_handle_t *); + +extern idmap_stat idmap_init_namemaps(idmap_handle_t *, idmap_nm_handle_t **, + char *, char *, char *, char *, int); + +#ifdef __cplusplus +} +#endif + +#endif /* NAMEMAPS_H */ diff --git a/usr/src/cmd/idmap/idmapd/idmap_config.c b/usr/src/cmd/idmap/idmapd/idmap_config.c index e11d0f8d47..c25f6da2fc 100644 --- a/usr/src/cmd/idmap/idmapd/idmap_config.c +++ b/usr/src/cmd/idmap/idmapd/idmap_config.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ @@ -50,6 +49,14 @@ #define RECONFIGURE 1 #define POKE_AUTO_DISCOVERY 2 +enum event_type { + EVENT_NOTHING, /* Woke up for no good reason */ + EVENT_TIMEOUT, /* Timeout expired */ + EVENT_ROUTING, /* An interesting routing event happened */ + EVENT_DEGRADE, /* An error occurred in the mainline */ + EVENT_REFRESH, /* SMF refresh */ +}; + /*LINTLIBRARY*/ @@ -893,8 +900,6 @@ enum_lookup(int value, struct enum_lookup_map *map) return ("(invalid)"); } -#define MAX_CHECK_TIME (20 * 60) - /* * Returns 1 if the PF_ROUTE socket event indicates that we should rescan the * interfaces. @@ -902,13 +907,13 @@ enum_lookup(int value, struct enum_lookup_map *map) * Shamelessly based on smb_nics_changed() and other PF_ROUTE uses in ON. */ static -int +boolean_t pfroute_event_is_interesting(int rt_sock) { int nbytes; int64_t msg[2048 / 8]; struct rt_msghdr *rtm; - int is_interesting = FALSE; + boolean_t is_interesting = B_FALSE; for (;;) { if ((nbytes = read(rt_sock, msg, sizeof (msg))) <= 0) @@ -922,7 +927,7 @@ pfroute_event_is_interesting(int rt_sock) case RTM_NEWADDR: case RTM_DELADDR: case RTM_IFINFO: - is_interesting = TRUE; + is_interesting = B_TRUE; break; default: break; @@ -932,131 +937,161 @@ pfroute_event_is_interesting(int rt_sock) } /* - * Returns 1 if SIGHUP has been received (see hup_handler() elsewhere) or if an - * interface address was added or removed; otherwise it returns 0. + * Wait for an event, and report what kind of event occurred. * - * Note that port_get() does not update its timeout argument when EINTR, unlike - * nanosleep(). We probably don't care very much here, but if we did care then - * we could always use a timer event and associate it with the same event port, - * then we could get accurate waiting regardless of EINTRs. + * Note that there are cases where we are awoken but don't care about + * the lower-level event. We can't just loop here because we can't + * readily calculate how long to sleep the next time. We return + * EVENT_NOTHING and let the caller loop. */ static -int -wait_for_event(int poke_is_interesting, struct timespec *timeoutp) +enum event_type +wait_for_event(struct timespec *timeoutp) { port_event_t pe; -retry: memset(&pe, 0, sizeof (pe)); if (port_get(idmapd_ev_port, &pe, timeoutp) != 0) { switch (errno) { case EINTR: - goto retry; + return (EVENT_NOTHING); case ETIME: /* Timeout */ - return (FALSE); + return (EVENT_TIMEOUT); default: /* EBADF, EBADFD, EFAULT, EINVAL (end of time?)? */ idmapdlog(LOG_ERR, "Event port failed: %s", strerror(errno)); exit(1); /* NOTREACHED */ - break; } } - if (pe.portev_source == PORT_SOURCE_USER && - pe.portev_events == POKE_AUTO_DISCOVERY) - return (poke_is_interesting ? TRUE : FALSE); - if (pe.portev_source == PORT_SOURCE_FD && pe.portev_object == rt_sock) { - /* PF_ROUTE socket read event, re-associate fd, handle event */ - if (port_associate(idmapd_ev_port, PORT_SOURCE_FD, rt_sock, - POLLIN, NULL) != 0) { - idmapdlog(LOG_ERR, "Failed to re-associate the " - "routing socket with the event port: %s", - strerror(errno)); - exit(1); - } + switch (pe.portev_source) { + case 0: /* - * The network configuration may still be in flux. No matter, - * the resolver will re-transmit and timout if need be. + * This isn't documented, but seems to be what you get if + * the timeout is zero seconds and there are no events + * pending. */ - return (pfroute_event_is_interesting(rt_sock)); - } + return (EVENT_TIMEOUT); - if (pe.portev_source == PORT_SOURCE_USER && - pe.portev_events == RECONFIGURE) { - int rc; + case PORT_SOURCE_USER: + if (pe.portev_events == POKE_AUTO_DISCOVERY) + return (EVENT_DEGRADE); + if (pe.portev_events == RECONFIGURE) + return (EVENT_REFRESH); + break; - /* - * Blow away the ccache, we might have re-joined the - * domain or joined a new one - */ - (void) unlink(IDMAP_CACHEDIR "/ccache"); - /* HUP is the refresh method, so re-read SMF config */ - idmapdlog(LOG_INFO, "SMF refresh"); - rc = idmap_cfg_load(_idmapdstate.cfg, CFG_DISCOVER|CFG_LOG); - if (rc < -1) { - idmapdlog(LOG_ERR, "Fatal errors while reading " - "SMF properties"); - exit(1); - } else if (rc == -1) { - idmapdlog(LOG_WARNING, "Various errors " - "re-loading configuration may cause AD lookups " - "to fail"); + case PORT_SOURCE_FD: + if (pe.portev_object == rt_sock) { + /* + * PF_ROUTE socket read event: + * re-associate fd + * handle event + */ + if (port_associate(idmapd_ev_port, PORT_SOURCE_FD, + rt_sock, POLLIN, NULL) != 0) { + idmapdlog(LOG_ERR, "Failed to re-associate the " + "routing socket with the event port: %s", + strerror(errno)); + abort(); + } + /* + * The network configuration may still be in flux. + * No matter, the resolver will re-transmit and + * timeout if need be. + */ + if (pfroute_event_is_interesting(rt_sock)) { + idmapdlog(LOG_DEBUG, + "Interesting routing event"); + return (EVENT_ROUTING); + } else { + idmapdlog(LOG_DEBUG, + "Boring routing event"); + return (EVENT_NOTHING); + } } - return (FALSE); + /* Event on an FD other than the routing FD? Ignore it. */ + break; } - return (FALSE); + return (EVENT_NOTHING); } void * idmap_cfg_update_thread(void *arg) { - int ttl, changed, poke_is_interesting; - idmap_cfg_handles_t *handles = &_idmapdstate.cfg->handles; - ad_disc_t ad_ctx = handles->ad_ctx; - struct timespec timeout, *timeoutp; + const ad_disc_t ad_ctx = _idmapdstate.cfg->handles.ad_ctx; - poke_is_interesting = 1; - for (ttl = 0, changed = TRUE; ; ttl = ad_disc_get_TTL(ad_ctx)) { - /* - * If ttl < 0 then we can wait for an event without timing out. - * If idmapd needs to notice that the system has been joined to - * a Windows domain then idmapd needs to be refreshed. - */ - timeoutp = (ttl < 0) ? NULL : &timeout; - if (ttl > MAX_CHECK_TIME) - ttl = MAX_CHECK_TIME; - timeout.tv_sec = ttl; - timeout.tv_nsec = 0; - changed = wait_for_event(poke_is_interesting, timeoutp); - - /* - * If there are no interesting events, and this is not the first - * time through the loop, and we haven't waited the most that - * we're willing to wait, so do nothing but wait some more. - */ - if (changed == FALSE && ttl > 0 && ttl < MAX_CHECK_TIME) - continue; + for (;;) { + struct timespec timeout; + struct timespec *timeoutp; + int rc; + int ttl; (void) ad_disc_SubnetChanged(ad_ctx); - if (idmap_cfg_load(_idmapdstate.cfg, CFG_DISCOVER) < -1) { + rc = idmap_cfg_load(_idmapdstate.cfg, CFG_DISCOVER); + if (rc < -1) { idmapdlog(LOG_ERR, "Fatal errors while reading " "SMF properties"); exit(1); + } else if (rc == -1) { + idmapdlog(LOG_WARNING, + "Errors re-loading configuration may cause AD " + "lookups to fail"); } - if (_idmapdstate.cfg->pgcfg.global_catalog == NULL || - _idmapdstate.cfg->pgcfg.global_catalog[0].host[0] == '\0') - poke_is_interesting = 1; - else - poke_is_interesting = 0; + /* + * Wait for an interesting event. Note that we might get + * boring events between interesting events. If so, we loop. + */ + for (;;) { + ttl = ad_disc_get_TTL(ad_ctx); + + if (ttl < 0) { + timeoutp = NULL; + } else { + timeoutp = &timeout; + timeout.tv_sec = ttl; + timeout.tv_nsec = 0; + } + + switch (wait_for_event(timeoutp)) { + case EVENT_NOTHING: + idmapdlog(LOG_DEBUG, "Boring event."); + continue; + case EVENT_REFRESH: + idmapdlog(LOG_INFO, "SMF refresh"); + /* + * Blow away the ccache, we might have + * re-joined the domain or joined a new one + */ + (void) unlink(IDMAP_CACHEDIR "/ccache"); + break; + case EVENT_DEGRADE: + idmapdlog(LOG_DEBUG, + "Service degraded"); + break; + case EVENT_TIMEOUT: + idmapdlog(LOG_DEBUG, "TTL expired"); + break; + case EVENT_ROUTING: + /* Already logged to DEBUG */ + break; + } + /* An interesting event! */ + break; + } } + /* + * Lint isn't happy with the concept of a function declared to + * return something, that doesn't return. Of course, merely adding + * the return isn't enough, because it's never reached... + */ /*NOTREACHED*/ return (NULL); } @@ -1356,6 +1391,8 @@ idmap_cfg_discover(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg) idmap_trustedforest_t *trustedforests; ad_disc_domainsinforest_t *domainsinforest; + idmapdlog(LOG_DEBUG, "Running discovery."); + ad_disc_refresh(ad_ctx); if (pgcfg->default_domain == NULL) @@ -1524,6 +1561,9 @@ idmap_cfg_discover(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg) "unable to discover Domains in the Forest"); if (pgcfg->trusted_domains == NULL) idmapdlog(LOG_DEBUG, "unable to discover Trusted Domains"); + + ad_disc_done(ad_ctx); + idmapdlog(LOG_DEBUG, "Discovery done."); } diff --git a/usr/src/cmd/idmap/idmapd/idmapd.c b/usr/src/cmd/idmap/idmapd/idmapd.c index 720b209240..5ea3292acd 100644 --- a/usr/src/cmd/idmap/idmapd/idmapd.c +++ b/usr/src/cmd/idmap/idmapd/idmapd.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ @@ -293,6 +292,7 @@ main(int argc, char **argv) (void) textdomain(TEXT_DOMAIN); idmap_set_logger(idmapdlog); + adutils_set_logger(idmapdlog); idmap_log_syslog(B_TRUE); idmap_log_stderr(_idmapdstate.daemon_mode ? -1 : LOG_DEBUG); @@ -488,13 +488,6 @@ degrade_svc(int poke_discovery, const char *reason) { const char *fmri; - /* - * If the config update thread is in a state where auto-discovery could - * be re-tried, then this will make it try it -- a sort of auto-refresh. - */ - if (poke_discovery) - idmap_cfg_poke_updates(); - membar_consumer(); if (degraded) return; @@ -509,6 +502,13 @@ degrade_svc(int poke_discovery, const char *reason) if ((fmri = get_fmri()) != NULL) (void) smf_degrade_instance(fmri, 0); + + /* + * If the config update thread is in a state where auto-discovery could + * be re-tried, then this will make it try it -- a sort of auto-refresh. + */ + if (poke_discovery) + idmap_cfg_poke_updates(); } void diff --git a/usr/src/cmd/smbsrv/smbd/smbd_doorsvc.c b/usr/src/cmd/smbsrv/smbd/smbd_doorsvc.c index 7dc3eef535..e936029edc 100644 --- a/usr/src/cmd/smbsrv/smbd/smbd_doorsvc.c +++ b/usr/src/cmd/smbsrv/smbd/smbd_doorsvc.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <sys/list.h> @@ -45,10 +44,13 @@ #include <smbsrv/libsmbns.h> #include "smbd.h" +#define SMBD_ARG_MAGIC 0x53415247 /* 'SARG' */ + /* * Parameter for door operations. */ typedef struct smbd_arg { + uint32_t magic; list_node_t lnd; smb_doorhdr_t hdr; const char *opname; @@ -56,6 +58,8 @@ typedef struct smbd_arg { size_t datalen; char *rbuf; size_t rsize; + boolean_t response_ready; + boolean_t response_abort; uint32_t status; } smbd_arg_t; @@ -254,7 +258,6 @@ smbd_door_dispatch(void *cookie, char *argp, size_t arg_size, door_desc_t *dp, hdr->dh_door_rc = SMB_DOP_SUCCESS; else hdr->dh_door_rc = SMB_DOP_NOT_CALLED; - } else { (void) smbd_door_dispatch_op(&dop_arg); } @@ -318,6 +321,7 @@ smbd_door_dispatch_async(smbd_arg_t *req_arg) } (void) mutex_lock(&smbd_doorsvc.sd_mutex); + arg->magic = SMBD_ARG_MAGIC; list_insert_tail(&smbd_doorsvc.sd_async_list, arg); ++smbd_doorsvc.sd_async_count; (void) mutex_unlock(&smbd_doorsvc.sd_mutex); @@ -346,9 +350,13 @@ static void smbd_door_release_async(smbd_arg_t *arg) { if (arg != NULL) { + assert(arg->magic == SMBD_ARG_MAGIC); + arg->magic = (uint32_t)~SMBD_ARG_MAGIC; + list_remove(&smbd_doorsvc.sd_async_list, arg); --smbd_doorsvc.sd_async_count; free(arg->data); + arg->data = NULL; free(arg); } } @@ -358,6 +366,10 @@ smbd_door_release_async(smbd_arg_t *arg) * - synchronous calls are invoked by direct function call * - asynchronous calls are invoked from a launched thread * + * If the kernel has attempted to collect a response before the op + * has completed, the arg will have been marked as response_abort + * and we can discard the response data and release the arg. + * * We send a notification when asynchronous (ASYNC) door calls * from the kernel (SYSSPACE) have completed. */ @@ -385,6 +397,17 @@ smbd_door_dispatch_op(void *thread_arg) if ((hdr->dh_flags & SMB_DF_SYSSPACE) && (hdr->dh_flags & SMB_DF_ASYNC)) { assert(hdr->dh_op != SMB_DR_ASYNC_RESPONSE); + + (void) mutex_lock(&smbd_doorsvc.sd_mutex); + if (arg->response_abort) { + free(arg->rbuf); + arg->rbuf = NULL; + smbd_door_release_async(arg); + } else { + arg->response_ready = B_TRUE; + } + (void) mutex_unlock(&smbd_doorsvc.sd_mutex); + (void) smb_kmod_event_notify(hdr->dh_txid); } @@ -484,6 +507,10 @@ smbd_dop_null(smbd_arg_t *arg) * Async response handler: setup the rbuf and rsize for the specified * transaction. This function is used by the kernel to collect the * response half of an asynchronous door call. + * + * If a door client attempts to collect a response before the op has + * completed (!response_ready), mark the arg as response_abort and + * set an error. The response will be discarded when the op completes. */ static int smbd_dop_async_response(smbd_arg_t *rsp_arg) @@ -495,7 +522,17 @@ smbd_dop_async_response(smbd_arg_t *rsp_arg) arg = list_head(arg_list); while (arg != NULL) { + assert(arg->magic == SMBD_ARG_MAGIC); + if (arg->hdr.dh_txid == rsp_arg->hdr.dh_txid) { + if (!arg->response_ready) { + arg->response_abort = B_TRUE; + rsp_arg->hdr.dh_door_rc = SMB_DOP_NOT_CALLED; + syslog(LOG_NOTICE, "doorsvc[%s]: %u not ready", + arg->opname, arg->hdr.dh_txid); + break; + } + rsp_arg->rbuf = arg->rbuf; rsp_arg->rsize = arg->rsize; arg->rbuf = NULL; @@ -514,7 +551,7 @@ smbd_dop_async_response(smbd_arg_t *rsp_arg) static int smbd_dop_user_nonauth_logon(smbd_arg_t *arg) { - uint32_t sid; + uint32_t sid = 0; if (smb_common_decode(arg->data, arg->datalen, xdr_uint32_t, &sid) != 0) @@ -527,7 +564,7 @@ smbd_dop_user_nonauth_logon(smbd_arg_t *arg) static int smbd_dop_user_auth_logoff(smbd_arg_t *arg) { - uint32_t sid; + uint32_t sid = 0; if (smb_common_decode(arg->data, arg->datalen, xdr_uint32_t, &sid) != 0) @@ -574,6 +611,8 @@ smbd_dop_lookup_name(smbd_arg_t *arg) lsa_account_t acct; char buf[MAXNAMELEN]; + bzero(&acct, sizeof (lsa_account_t)); + if (smb_common_decode(arg->data, arg->datalen, lsa_account_xdr, &acct) != 0) return (SMB_DOP_DECODE_ERROR); @@ -617,6 +656,8 @@ smbd_dop_lookup_sid(smbd_arg_t *arg) lsa_account_t acct; smb_sid_t *sid; + bzero(&acct, sizeof (lsa_account_t)); + if (smb_common_decode(arg->data, arg->datalen, lsa_account_xdr, &acct) != 0) return (SMB_DOP_DECODE_ERROR); @@ -653,6 +694,8 @@ smbd_dop_join(smbd_arg_t *arg) smb_joininfo_t jdi; uint32_t status; + bzero(&jdi, sizeof (smb_joininfo_t)); + if (smb_common_decode(arg->data, arg->datalen, smb_joininfo_xdr, &jdi) != 0) return (SMB_DOP_DECODE_ERROR); diff --git a/usr/src/cmd/smbsrv/smbd/smbd_logon.c b/usr/src/cmd/smbsrv/smbd/smbd_logon.c index 97f9e47b51..fe27e9cd7f 100644 --- a/usr/src/cmd/smbsrv/smbd/smbd_logon.c +++ b/usr/src/cmd/smbsrv/smbd/smbd_logon.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <sys/types.h> @@ -36,6 +35,9 @@ #include <bsm/adt.h> #include <bsm/adt_event.h> #include <bsm/audit_uevents.h> +#include <pwd.h> +#include <nss_dbdefs.h> +#include <sys/idmap.h> #include "smbd.h" @@ -212,11 +214,20 @@ smbd_user_auth_logoff(uint32_t audit_sid) smb_audit_t *entry; adt_session_data_t *ah; adt_event_data_t *event; + struct passwd pw; + char buf[NSS_LINELEN_PASSWD]; if ((entry = smbd_audit_unlink(audit_sid)) == NULL) return; - smb_autohome_remove(entry->sa_username); + if (IDMAP_ID_IS_EPHEMERAL(entry->sa_uid)) { + smb_autohome_remove(entry->sa_username); + } else { + if (getpwuid_r(entry->sa_uid, &pw, buf, sizeof (buf)) == NULL) + return; + + smb_autohome_remove(pw.pw_name); + } ah = entry->sa_handle; diff --git a/usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c b/usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c index 5ec93bd59f..3792e23853 100644 --- a/usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c +++ b/usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -257,16 +256,12 @@ smbd_share_dispatch(void *cookie, char *ptr, size_t size, door_desc_t *dp, case SMB_SHROP_ENUM: esi.es_bufsize = smb_dr_get_ushort(dec_ctx); - esi.es_username = smb_dr_get_string(dec_ctx); - if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) { - smb_dr_free_string(esi.es_username); + esi.es_posix_uid = smb_dr_get_uint32(dec_ctx); + if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) goto decode_error; - } rc = smbd_share_enum(&esi); - smb_dr_free_string(esi.es_username); - smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS); smb_dr_put_uint32(enc_ctx, rc); if (rc == NERR_Success) { @@ -380,7 +375,7 @@ smbd_share_enum(smb_enumshare_info_t *esi) continue; if ((si->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) { - if (strcasecmp(esi->es_username, si->shr_name) == 0) + if (esi->es_posix_uid == si->shr_uid) autohome_added = B_TRUE; else continue; @@ -417,7 +412,7 @@ smbd_share_enum(smb_enumshare_info_t *esi) continue; if ((si->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) { - if (strcasecmp(esi->es_username, si->shr_name) == 0) + if (esi->es_posix_uid == si->shr_uid) autohome_added = B_TRUE; else continue; |
