diff options
Diffstat (limited to 'usr/src/cmd')
32 files changed, 3648 insertions, 1198 deletions
diff --git a/usr/src/cmd/idmap/idmap/idmap.c b/usr/src/cmd/idmap/idmap/idmap.c index 57c6b3bfe5..1c05e3d76a 100644 --- a/usr/src/cmd/idmap/idmap/idmap.c +++ b/usr/src/cmd/idmap/idmap/idmap.c @@ -117,6 +117,7 @@ id_code_t identity2code[] = { #define n_FLAG 'n' #define c_FLAG 'c' #define v_FLAG 'v' +#define V_FLAG 'V' #define j_FLAG 'j' @@ -256,7 +257,7 @@ static int do_get_namemap(flag_t *f, int argc, char **argv, cmd_pos_t *pos); static cmd_ops_t commands[] = { { "show", - "c(create)v(verbose)", + "c(create)v(verbose)V(trace)", do_show_mapping }, { @@ -1462,9 +1463,6 @@ print_how(idmap_how *how) } - - - static void print_info(idmap_info *info) @@ -1489,6 +1487,11 @@ print_info(idmap_info *info) } print_how(&info->how); } + + if (info->trace != NULL) { + (void) printf(gettext("Trace:\n")); + idmap_trace_print(stdout, "\t", info->trace); + } } @@ -1571,6 +1574,11 @@ print_error_info(idmap_info *info) CHECK_NULL(how->idmap_how_u.idmu.value)); break; } + + if (info->trace != NULL) { + (void) printf(gettext("Trace:\n")); + idmap_trace_print(stderr, "\t", info->trace); + } } @@ -1627,7 +1635,7 @@ do_dump(flag_t *f, int argc, char **argv, cmd_pos_t *pos) if (stat >= 0) { (void) print_mapping(ph, nm); - (void) print_how(&info.how); + print_how(&info.how); idmap_info_free(&info); } name_mapping_fini(nm); @@ -2952,8 +2960,13 @@ do_show_mapping(flag_t *f, int argc, char **argv, cmd_pos_t *pos) return (-1); } - flag = f[c_FLAG] != NULL ? 0 : IDMAP_REQ_FLG_NO_NEW_ID_ALLOC; - flag |= f[v_FLAG] == NULL ? 0 : IDMAP_REQ_FLG_MAPPING_INFO; + flag = 0; + if (f[c_FLAG] == NULL) + flag |= IDMAP_REQ_FLG_NO_NEW_ID_ALLOC; + if (f[v_FLAG] != NULL) + flag |= IDMAP_REQ_FLG_MAPPING_INFO; + if (f[V_FLAG] != NULL) + flag |= IDMAP_REQ_FLG_TRACE; if (init_command()) return (-1); @@ -3182,8 +3195,9 @@ errormsg: print_error(pos, gettext("Error:\t%s\n"), idmap_stat2string(handle, map_stat)); print_error_info(&info); - } else + } else { print_info(&info); + } idmap_info_free(&info); cleanup: @@ -3546,7 +3560,6 @@ static void idmap_cli_logger(int pri, const char *format, ...) { - NOTE(ARGUNUSED(pri)) va_list args; if (pri == LOG_DEBUG) diff --git a/usr/src/cmd/idmap/idmapd/Makefile b/usr/src/cmd/idmap/idmapd/Makefile index 04bee240ae..e940895ede 100644 --- a/usr/src/cmd/idmap/idmapd/Makefile +++ b/usr/src/cmd/idmap/idmapd/Makefile @@ -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. # PROG = idmapd @@ -35,6 +34,7 @@ SERVEROBJS = \ idmap_config.o \ idmapd.o \ init.o \ + idmap_lsa.o \ nldaputils.o \ rpc_svc.o \ server.o \ @@ -71,7 +71,8 @@ $(ROOTMANIFEST) := FILEMODE= 444 INCS += -I. -I../../../lib/libidmap/common\ -I../../../lib/libsldap/common\ - -I../../../lib/libadutils/common + -I../../../lib/libadutils/common \ + -I../../../lib/smbsrv/libsmb/common $(OBJS) := CPPFLAGS += $(INCS) -D_REENTRANT $(POFILE) := CPPFLAGS += $(INCS) @@ -86,12 +87,16 @@ LDLIBS += -lsecdb \ -lldap \ -luuid \ -ladutils \ - -lumem + -lumem \ + -lnvpair \ + -L $(ROOT)/usr/lib/smbsrv \ + -lsmb rpc_svc.o := CFLAGS += $(RPC_MSGOUT_OPT) $(PROG) := MAPFILES = $(MAPFILE.INT) $(MAPFILE.NGB) -$(PROG) := LDFLAGS += $(MAPFILES:%=-M%) +$(PROG) := LDFLAGS += $(MAPFILES:%=-M%) \ + -R /usr/lib/smbsrv DIRMODE = 0755 FILEMODE = 0555 diff --git a/usr/src/cmd/idmap/idmapd/adutils.c b/usr/src/cmd/idmap/idmapd/adutils.c index cbc447e0c9..254ccc214d 100644 --- a/usr/src/cmd/idmap/idmapd/adutils.c +++ b/usr/src/cmd/idmap/idmapd/adutils.c @@ -20,8 +20,7 @@ */ /* - * 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. */ /* @@ -78,13 +77,13 @@ typedef struct idmap_q { */ char *ecanonname; /* expected canon name */ char *edomain; /* expected domain name */ - int eunixtype; /* expected unix type */ + idmap_id_type esidtype; /* expected SID type */ /* results */ char **canonname; /* actual canon name */ char **domain; /* name of domain of object */ char **sid; /* stringified SID */ rid_t *rid; /* RID */ - int *sid_type; /* user or group SID? */ + idmap_id_type *sid_type; /* user or group SID? */ char **unixname; /* unixname for name mapping */ char **dn; /* DN of entry */ char **attr; /* Attr for name mapping */ @@ -352,7 +351,7 @@ idmap_bv_objclass2sidtype(BerValue **bvalues, int *sid_type) { BerValue **cbval; - *sid_type = _IDMAP_T_OTHER; + *sid_type = IDMAP_SID; if (bvalues == NULL) return (0); @@ -363,14 +362,14 @@ idmap_bv_objclass2sidtype(BerValue **bvalues, int *sid_type) */ for (cbval = bvalues; *cbval != NULL; cbval++) { if (BVAL_CASEEQ(cbval, "group")) { - *sid_type = _IDMAP_T_GROUP; + *sid_type = IDMAP_GSID; break; } else if (BVAL_CASEEQ(cbval, "user")) { - *sid_type = _IDMAP_T_USER; + *sid_type = IDMAP_USID; break; } /* - * "else if (*sid_type = _IDMAP_T_USER)" then this is a + * "else if (*sid_type = IDMAP_USID)" then this is a * new sub-class of user -- what to do with it?? */ } @@ -426,9 +425,9 @@ idmap_extract_object(idmap_query_state_t *state, idmap_q_t *q, if (state->directory_based_mapping == DIRECTORY_MAPPING_IDMU && q->pid != NULL) { - if (sid_type == _IDMAP_T_USER) + if (sid_type == IDMAP_USID) attr = UIDNUMBER; - else if (sid_type == _IDMAP_T_GROUP) + else if (sid_type == IDMAP_GSID) attr = GIDNUMBER; if (attr != NULL) { bvalues = ldap_get_values_len(ld, res, attr); @@ -451,24 +450,20 @@ idmap_extract_object(idmap_query_state_t *state, idmap_q_t *q, * AD attribute name that will have the unixname, and retrieve * its value. */ - int unix_type; + idmap_id_type esidtype; /* - * Determine the target UNIX type. + * Determine the target type. * * If the caller specified one, use that. Otherwise, give the * same type that as we found for the Windows user. */ - unix_type = q->eunixtype; - if (unix_type == _IDMAP_T_UNDEF) { - if (sid_type == _IDMAP_T_USER) - unix_type = _IDMAP_T_USER; - else if (sid_type == _IDMAP_T_GROUP) - unix_type = _IDMAP_T_GROUP; - } + esidtype = q->esidtype; + if (esidtype == IDMAP_SID) + esidtype = sid_type; - if (unix_type == _IDMAP_T_USER) + if (esidtype == IDMAP_USID) attr = state->ad_unixuser_attr; - else if (unix_type == _IDMAP_T_GROUP) + else if (esidtype == IDMAP_GSID) attr = state->ad_unixgroup_attr; if (attr != NULL) { @@ -591,10 +586,10 @@ idmap_lookup_batch_end(idmap_query_state_t **state) static idmap_retcode idmap_batch_add1(idmap_query_state_t *state, const char *filter, - char *ecanonname, char *edomain, int eunixtype, + char *ecanonname, char *edomain, idmap_id_type esidtype, char **dn, char **attr, char **value, char **canonname, char **dname, - char **sid, rid_t *rid, int *sid_type, char **unixname, + char **sid, rid_t *rid, idmap_id_type *sid_type, char **unixname, posix_id_t *pid, idmap_retcode *rc) { @@ -614,7 +609,7 @@ idmap_batch_add1(idmap_query_state_t *state, const char *filter, */ q->ecanonname = ecanonname; q->edomain = edomain; - q->eunixtype = eunixtype; + q->esidtype = esidtype; /* Remember where to put the results */ q->canonname = canonname; @@ -637,18 +632,18 @@ idmap_batch_add1(idmap_query_state_t *state, const char *filter, if (unixname != NULL) { /* Add unixuser/unixgroup attribute names to the attrs list */ - if (eunixtype != _IDMAP_T_GROUP && + if (esidtype != IDMAP_GSID && state->ad_unixuser_attr != NULL) attrs[i++] = (char *)state->ad_unixuser_attr; - if (eunixtype != _IDMAP_T_USER && + if (esidtype != IDMAP_USID && state->ad_unixgroup_attr != NULL) attrs[i++] = (char *)state->ad_unixgroup_attr; } if (pid != NULL) { - if (eunixtype != _IDMAP_T_GROUP) + if (esidtype != IDMAP_GSID) attrs[i++] = UIDNUMBER; - if (eunixtype != _IDMAP_T_USER) + if (esidtype != IDMAP_USID) attrs[i++] = GIDNUMBER; } @@ -667,7 +662,7 @@ idmap_batch_add1(idmap_query_state_t *state, const char *filter, */ *rc = IDMAP_ERR_RETRIABLE_NET_ERR; if (sid_type != NULL) - *sid_type = _IDMAP_T_OTHER; + *sid_type = IDMAP_SID; if (sid != NULL) *sid = NULL; if (dname != NULL) @@ -698,10 +693,10 @@ idmap_batch_add1(idmap_query_state_t *state, const char *filter, idmap_retcode idmap_name2sid_batch_add1(idmap_query_state_t *state, - const char *name, const char *dname, int eunixtype, + const char *name, const char *dname, idmap_id_type esidtype, char **dn, char **attr, char **value, char **canonname, char **sid, rid_t *rid, - int *sid_type, char **unixname, + idmap_id_type *sid_type, char **unixname, posix_id_t *pid, idmap_retcode *rc) { idmap_retcode retcode; @@ -761,7 +756,7 @@ idmap_name2sid_batch_add1(idmap_query_state_t *state, } retcode = idmap_batch_add1(state, filter, ecanonname, edomain, - eunixtype, dn, attr, value, canonname, NULL, sid, rid, sid_type, + esidtype, dn, attr, value, canonname, NULL, sid, rid, sid_type, unixname, pid, rc); free(filter); @@ -771,9 +766,9 @@ idmap_name2sid_batch_add1(idmap_query_state_t *state, idmap_retcode idmap_sid2name_batch_add1(idmap_query_state_t *state, - const char *sid, const rid_t *rid, int eunixtype, + const char *sid, const rid_t *rid, idmap_id_type esidtype, char **dn, char **attr, char **value, - char **name, char **dname, int *sid_type, + char **name, char **dname, idmap_id_type *sid_type, char **unixname, posix_id_t *pid, idmap_retcode *rc) { idmap_retcode retcode; @@ -801,7 +796,7 @@ idmap_sid2name_batch_add1(idmap_query_state_t *state, if (filter == NULL) return (IDMAP_ERR_MEMORY); - retcode = idmap_batch_add1(state, filter, NULL, NULL, eunixtype, + retcode = idmap_batch_add1(state, filter, NULL, NULL, esidtype, dn, attr, value, name, dname, NULL, NULL, sid_type, unixname, pid, rc); @@ -815,7 +810,7 @@ idmap_unixname2sid_batch_add1(idmap_query_state_t *state, const char *unixname, int is_user, int is_wuser, char **dn, char **attr, char **value, char **sid, rid_t *rid, char **name, - char **dname, int *sid_type, idmap_retcode *rc) + char **dname, idmap_id_type *sid_type, idmap_retcode *rc) { idmap_retcode retcode; char *filter, *s_unixname; @@ -841,7 +836,7 @@ idmap_unixname2sid_batch_add1(idmap_query_state_t *state, } retcode = idmap_batch_add1(state, filter, NULL, NULL, - _IDMAP_T_UNDEF, dn, NULL, NULL, name, dname, sid, rid, sid_type, + IDMAP_POSIXID, dn, NULL, NULL, name, dname, sid, rid, sid_type, NULL, NULL, rc); if (retcode == IDMAP_SUCCESS && attr != NULL) { @@ -864,7 +859,7 @@ idmap_pid2sid_batch_add1(idmap_query_state_t *state, posix_id_t pid, int is_user, char **dn, char **attr, char **value, char **sid, rid_t *rid, char **name, - char **dname, int *sid_type, idmap_retcode *rc) + char **dname, idmap_id_type *sid_type, idmap_retcode *rc) { idmap_retcode retcode; char *filter; @@ -882,7 +877,7 @@ idmap_pid2sid_batch_add1(idmap_query_state_t *state, return (IDMAP_ERR_MEMORY); retcode = idmap_batch_add1(state, filter, NULL, NULL, - _IDMAP_T_UNDEF, dn, NULL, NULL, name, dname, sid, rid, sid_type, + IDMAP_POSIXID, dn, NULL, NULL, name, dname, sid, rid, sid_type, NULL, NULL, rc); if (retcode == IDMAP_SUCCESS && attr != NULL) { diff --git a/usr/src/cmd/idmap/idmapd/adutils.h b/usr/src/cmd/idmap/idmapd/adutils.h index 88807f01d8..b5d45b4a4d 100644 --- a/usr/src/cmd/idmap/idmapd/adutils.h +++ b/usr/src/cmd/idmap/idmapd/adutils.h @@ -20,8 +20,7 @@ */ /* - * 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. */ #ifndef _ADUTILS_H @@ -56,16 +55,6 @@ extern "C" { * idmapd interfaces stolen? from other idmapd code? */ -/* - * Eventually these should be an enum here, but instead we share a - * namespace with other things in idmapd. - */ -#define _IDMAP_T_OTHER 0 -#define _IDMAP_T_UNDEF -1 -#define _IDMAP_T_USER -1004 -#define _IDMAP_T_GROUP -1005 -#define _IDMAP_T_DOMAIN -1006 - typedef uint32_t rid_t; typedef uid_t posix_id_t; @@ -118,9 +107,10 @@ void idmap_lookup_release_batch(idmap_query_state_t **state); * The caller must free() *sid. */ idmap_retcode idmap_name2sid_batch_add1(idmap_query_state_t *state, - const char *name, const char *dname, int eunixtype, + const char *name, const char *dname, idmap_id_type esidtype, char **dn, char **attr, char **value, char **canonname, - char **sid, rid_t *rid, int *sid_type, char **unixname, + char **sid, rid_t *rid, idmap_id_type *sid_type, + char **unixname, posix_id_t *pid, idmap_retcode *rc); /* * Add a SID->name lookup @@ -137,9 +127,9 @@ idmap_retcode idmap_name2sid_batch_add1(idmap_query_state_t *state, * The caller must free() *name and *dname (if present). */ idmap_retcode idmap_sid2name_batch_add1(idmap_query_state_t *state, - const char *sid, const rid_t *rid, int eunixtype, + const char *sid, const rid_t *rid, idmap_id_type esidtype, char **dn, char **attr, char **value, char **name, - char **dname, int *sid_type, char **unixname, + char **dname, idmap_id_type *sid_type, char **unixname, posix_id_t *pid, idmap_retcode *rc); /* @@ -148,7 +138,8 @@ idmap_retcode idmap_sid2name_batch_add1(idmap_query_state_t *state, idmap_retcode idmap_unixname2sid_batch_add1(idmap_query_state_t *state, const char *unixname, int is_user, int is_wuser, char **dn, char **attr, char **value, char **sid, rid_t *rid, - char **name, char **dname, int *sid_type, idmap_retcode *rc); + char **name, char **dname, idmap_id_type *sid_type, + idmap_retcode *rc); /* * Add a PID->SID lookup @@ -156,7 +147,8 @@ idmap_retcode idmap_unixname2sid_batch_add1(idmap_query_state_t *state, idmap_retcode idmap_pid2sid_batch_add1(idmap_query_state_t *state, posix_id_t pid, int is_user, char **dn, char **attr, char **value, char **sid, rid_t *rid, - char **name, char **dname, int *sid_type, idmap_retcode *rc); + char **name, char **dname, idmap_id_type *sid_type, + idmap_retcode *rc); /* * Set unixname attribute names for the batch for AD-based name mapping diff --git a/usr/src/cmd/idmap/idmapd/dbutils.c b/usr/src/cmd/idmap/idmapd/dbutils.c index 3043c507db..d697ab154a 100644 --- a/usr/src/cmd/idmap/idmapd/dbutils.c +++ b/usr/src/cmd/idmap/idmapd/dbutils.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. */ /* @@ -42,6 +41,7 @@ #include <assert.h> #include <sys/u8_textprep.h> #include <alloca.h> +#include <note.h> #include "idmapd.h" #include "adutils.h" @@ -49,6 +49,7 @@ #include "idmap_priv.h" #include "schema.h" #include "nldaputils.h" +#include "idmap_lsa.h" #include "miscutils.h" @@ -56,7 +57,7 @@ static idmap_retcode sql_compile_n_step_once(sqlite *, char *, sqlite_vm **, int *, int, const char ***); static idmap_retcode lookup_localsid2pid(idmap_mapping *, idmap_id_res *); static idmap_retcode lookup_cache_name2sid(sqlite *, const char *, - const char *, char **, char **, idmap_rid_t *, int *); + const char *, char **, char **, idmap_rid_t *, idmap_id_type *); #define NELEM(a) (sizeof (a) / sizeof ((a)[0])) @@ -129,10 +130,13 @@ idmap_tsd_destroy(void *key) } } -int +void idmap_init_tsd_key(void) { - return (pthread_key_create(&idmap_tsd_key, idmap_tsd_destroy)); + int rc; + + rc = pthread_key_create(&idmap_tsd_key, idmap_tsd_destroy); + assert(rc == 0); } @@ -1412,7 +1416,7 @@ lookup_wksids_name2sid( char **canondomain, char **sidprefix, idmap_rid_t *rid, - int *type) + idmap_id_type *type) { const wksids_table_t *wksid; @@ -1463,7 +1467,7 @@ lookup_wksids_name2sid( if (type != NULL) *type = (wksid->is_wuser) ? - _IDMAP_T_USER : _IDMAP_T_GROUP; + IDMAP_USID : IDMAP_GSID; return (IDMAP_SUCCESS); @@ -1702,10 +1706,36 @@ out: return (retcode); } +/* + * Previous versions used two enumerations for representing types. + * One of those has largely been eliminated, but was used in the + * name cache table and so during an upgrade might still be visible. + * In addition, the test suite prepopulates the cache with these values. + * + * This function translates those old values into the new values. + * + * This code deliberately does not use symbolic values for the legacy + * values. This is the *only* place where they should be used. + */ +static +idmap_id_type +xlate_legacy_type(int type) +{ + switch (type) { + case -1004: /* _IDMAP_T_USER */ + return (IDMAP_USID); + case -1005: /* _IDMAP_T_GROUP */ + return (IDMAP_GSID); + default: + return (type); + } + NOTE(NOTREACHED) +} + static idmap_retcode lookup_cache_sid2name(sqlite *cache, const char *sidprefix, idmap_rid_t rid, - char **canonname, char **canondomain, int *type) + char **canonname, char **canondomain, idmap_id_type *type) { char *end; char *sql = NULL; @@ -1745,7 +1775,7 @@ lookup_cache_sid2name(sqlite *cache, const char *sidprefix, idmap_rid_t rid, retcode = IDMAP_ERR_CACHE; goto out; } - *type = strtol(values[2], &end, 10); + *type = xlate_legacy_type(strtol(values[2], &end, 10)); } if (canonname != NULL && values[0] != NULL) { @@ -1785,15 +1815,17 @@ static idmap_retcode lookup_name_cache(sqlite *cache, idmap_mapping *req, idmap_id_res *res) { - int type = -1; + idmap_id_type type = -1; idmap_retcode retcode; char *sidprefix = NULL; idmap_rid_t rid; char *name = NULL, *domain = NULL; /* Done if we've both sid and winname */ - if (req->id1.idmap_id_u.sid.prefix != NULL && req->id1name != NULL) + if (req->id1.idmap_id_u.sid.prefix != NULL && req->id1name != NULL) { + /* Don't bother TRACE()ing, too boring */ return (IDMAP_SUCCESS); + } if (req->id1.idmap_id_u.sid.prefix != NULL) { /* Lookup sid to winname */ @@ -1807,18 +1839,18 @@ lookup_name_cache(sqlite *cache, idmap_mapping *req, idmap_id_res *res) } if (retcode != IDMAP_SUCCESS) { + if (retcode == IDMAP_ERR_NOTFOUND) { + TRACE(req, res, "Not found in name cache"); + } else { + TRACE(req, res, "Name cache lookup error=%d", retcode); + } free(name); free(domain); free(sidprefix); return (retcode); } - if (res->id.idtype == IDMAP_POSIXID) { - res->id.idtype = (type == _IDMAP_T_USER) ? - IDMAP_UID : IDMAP_GID; - } - req->id1.idtype = (type == _IDMAP_T_USER) ? - IDMAP_USID : IDMAP_GSID; + req->id1.idtype = type; req->direction |= _IDMAP_F_DONT_UPDATE_NAMECACHE; @@ -1839,6 +1871,8 @@ lookup_name_cache(sqlite *cache, idmap_mapping *req, idmap_id_res *res) req->id1.idmap_id_u.sid.prefix = sidprefix; req->id1.idmap_id_u.sid.rid = rid; } + + TRACE(req, res, "Found in name cache"); return (retcode); } @@ -1852,7 +1886,7 @@ ad_lookup_batch_int(lookup_state_t *state, idmap_mapping_batch *batch, idmap_retcode retcode; int i, num_queued, is_wuser, is_user; int next_request; - int retries = 0, eunixtype; + int retries = 0, esidtype; char **unixname; idmap_mapping *req; idmap_id_res *res; @@ -1928,23 +1962,23 @@ retry: if (res->retcode != IDMAP_ERR_RETRIABLE_NET_ERR) continue; - if (IS_REQUEST_SID(*req, 1)) { + if (IS_ID_SID(req->id1)) { /* win2unix request: */ posix_id_t *pid = NULL; unixname = dn = attr = value = NULL; - eunixtype = _IDMAP_T_UNDEF; + esidtype = IDMAP_SID; if (state->directory_based_mapping == DIRECTORY_MAPPING_NAME && req->id2name == NULL) { if (res->id.idtype == IDMAP_UID && AD_OR_MIXED(state->nm_siduid)) { - eunixtype = _IDMAP_T_USER; + esidtype = IDMAP_USID; unixname = &req->id2name; } else if (res->id.idtype == IDMAP_GID && AD_OR_MIXED(state->nm_sidgid)) { - eunixtype = _IDMAP_T_GROUP; + esidtype = IDMAP_GSID; unixname = &req->id2name; } else if (AD_OR_MIXED(state->nm_siduid) || AD_OR_MIXED(state->nm_sidgid)) { @@ -1957,7 +1991,7 @@ retry: * mapping only if AD or MIXED * mode is enabled. */ - idmap_info_free(&res->info); + idmap_how_clear(&res->info.how); res->info.src = IDMAP_MAP_SRC_NEW; how->map_type = IDMAP_MAP_TYPE_DS_AD; dn = &how->idmap_how_u.ad.dn; @@ -1975,7 +2009,7 @@ retry: /* * Get how info for IDMU based mapping. */ - idmap_info_free(&res->info); + idmap_how_clear(&res->info.how); res->info.src = IDMAP_MAP_SRC_NEW; how->map_type = IDMAP_MAP_TYPE_IDMU; dn = &how->idmap_how_u.idmu.dn; @@ -1987,13 +2021,13 @@ retry: /* Lookup AD by SID */ retcode = idmap_sid2name_batch_add1( qs, req->id1.idmap_id_u.sid.prefix, - &req->id1.idmap_id_u.sid.rid, eunixtype, + &req->id1.idmap_id_u.sid.rid, esidtype, dn, attr, value, (req->id1name == NULL) ? &req->id1name : NULL, (req->id1domain == NULL) ? &req->id1domain : NULL, - (int *)&req->id2.idtype, unixname, + &req->id2.idtype, unixname, pid, &res->retcode); if (retcode == IDMAP_SUCCESS) @@ -2003,19 +2037,19 @@ retry: assert(req->id1name != NULL); retcode = idmap_name2sid_batch_add1( qs, req->id1name, req->id1domain, - eunixtype, + esidtype, dn, attr, value, &req->id1name, &req->id1.idmap_id_u.sid.prefix, &req->id1.idmap_id_u.sid.rid, - (int *)&req->id2.idtype, unixname, + &req->id2.idtype, unixname, pid, &res->retcode); if (retcode == IDMAP_SUCCESS) num_queued++; } - } else if (IS_REQUEST_UID(*req) || IS_REQUEST_GID(*req)) { + } else if (IS_ID_UID(req->id1) || IS_ID_GID(req->id1)) { /* unix2win request: */ @@ -2038,10 +2072,10 @@ retry: retcode = idmap_sid2name_batch_add1( qs, res->id.idmap_id_u.sid.prefix, &res->id.idmap_id_u.sid.rid, - _IDMAP_T_UNDEF, + IDMAP_POSIXID, NULL, NULL, NULL, &req->id2name, - &req->id2domain, (int *)&req->id2.idtype, + &req->id2domain, &req->id2.idtype, NULL, NULL, &res->retcode); if (retcode == IDMAP_SUCCESS) num_queued++; @@ -2055,11 +2089,11 @@ retry: */ retcode = idmap_name2sid_batch_add1( qs, req->id2name, req->id2domain, - _IDMAP_T_UNDEF, + IDMAP_POSIXID, NULL, NULL, NULL, NULL, &res->id.idmap_id_u.sid.prefix, &res->id.idmap_id_u.sid.rid, - (int *)&req->id2.idtype, NULL, + &req->id2.idtype, NULL, NULL, &res->retcode); if (retcode == IDMAP_SUCCESS) @@ -2069,7 +2103,7 @@ retry: (how_local & DOMAIN_IS_LOCAL)) { assert(req->id1.idmap_id_u.uid != IDMAP_SENTINEL_PID); - is_user = IS_REQUEST_UID(*req); + is_user = IS_ID_UID(req->id1); if (res->id.idtype == IDMAP_USID) is_wuser = 1; else if (res->id.idtype == IDMAP_GSID) @@ -2081,7 +2115,7 @@ retry: if (is_user != is_wuser) continue; - idmap_info_free(&res->info); + idmap_how_clear(&res->info.how); res->info.src = IDMAP_MAP_SRC_NEW; how->map_type = IDMAP_MAP_TYPE_IDMU; retcode = idmap_pid2sid_batch_add1( @@ -2092,7 +2126,7 @@ retry: &res->id.idmap_id_u.sid.prefix, &res->id.idmap_id_u.sid.rid, &req->id2name, &req->id2domain, - (int *)&req->id2.idtype, &res->retcode); + &req->id2.idtype, &res->retcode); if (retcode == IDMAP_SUCCESS) num_queued++; } else if (req->id1name != NULL) { @@ -2100,7 +2134,7 @@ retry: * No SID and no winname but we've unixname. * Lookup AD by unixname to get SID. */ - is_user = (IS_REQUEST_UID(*req)) ? 1 : 0; + is_user = (IS_ID_UID(req->id1)) ? 1 : 0; if (res->id.idtype == IDMAP_USID) is_wuser = 1; else if (res->id.idtype == IDMAP_GSID) @@ -2108,7 +2142,7 @@ retry: else is_wuser = is_user; - idmap_info_free(&res->info); + idmap_how_clear(&res->info.how); res->info.src = IDMAP_MAP_SRC_NEW; how->map_type = IDMAP_MAP_TYPE_DS_AD; retcode = idmap_unixname2sid_batch_add1( @@ -2119,7 +2153,7 @@ retry: &res->id.idmap_id_u.sid.prefix, &res->id.idmap_id_u.sid.rid, &req->id2name, &req->id2domain, - (int *)&req->id2.idtype, &res->retcode); + &req->id2.idtype, &res->retcode); if (retcode == IDMAP_SUCCESS) num_queued++; } @@ -2175,7 +2209,7 @@ out: * and update the idtype in request. */ for (i = 0; i < batch->idmap_mapping_batch_len; i++) { - int type; + idmap_id_type type; uid_t posix_id; req = &batch->idmap_mapping_batch_val[i]; @@ -2218,15 +2252,15 @@ out: if (res->retcode == IDMAP_ERR_NOTFOUND) { /* Nothing found - remove the preset info */ - idmap_info_free(&res->info); + idmap_how_clear(&res->info.how); } - if (IS_REQUEST_SID(*req, 1)) { + if (IS_ID_SID(req->id1)) { if (res->retcode != IDMAP_SUCCESS) continue; /* Evaluate result type */ switch (type) { - case _IDMAP_T_USER: + case IDMAP_USID: if (res->id.idtype == IDMAP_POSIXID) res->id.idtype = IDMAP_UID; /* @@ -2245,7 +2279,7 @@ out: req->id1.idtype = IDMAP_USID; break; - case _IDMAP_T_GROUP: + case IDMAP_GSID: if (res->id.idtype == IDMAP_POSIXID) res->id.idtype = IDMAP_GID; /* @@ -2276,7 +2310,7 @@ out: req->direction |= _IDMAP_F_LOOKUP_NLDAP; state->nldap_nqueries++; } - } else if (IS_REQUEST_UID(*req) || IS_REQUEST_GID(*req)) { + } else if (IS_ID_UID(req->id1) || IS_ID_GID(req->id1)) { if (res->retcode != IDMAP_SUCCESS) { if ((!(IDMAP_FATAL_ERROR(res->retcode))) && res->id.idmap_id_u.sid.prefix == NULL && @@ -2295,14 +2329,10 @@ out: } /* Evaluate result type */ switch (type) { - case _IDMAP_T_USER: + case IDMAP_USID: + case IDMAP_GSID: if (res->id.idtype == IDMAP_SID) - res->id.idtype = IDMAP_USID; - break; - - case _IDMAP_T_GROUP: - if (res->id.idtype == IDMAP_SID) - res->id.idtype = IDMAP_GSID; + res->id.idtype = type; break; default: @@ -2519,19 +2549,33 @@ sid2pid_first_pass(lookup_state_t *state, idmap_mapping *req, /* Lookup well-known SIDs table */ retcode = lookup_wksids_sid2pid(req, res, &wksid); - /* - * Note that IDMAP_SUCCESS means that we found a hardwired mapping. - * If we found a well-known identity but no mapping, wksid==true and - * retcode==IDMAP_ERR_NOTFOUND. - */ - if (retcode != IDMAP_ERR_NOTFOUND) + if (retcode == IDMAP_SUCCESS) { + /* Found a well-known account with a hardwired mapping */ + TRACE(req, res, "Hardwired mapping"); + goto out; + } else if (retcode != IDMAP_ERR_NOTFOUND) { + TRACE(req, res, + "Well-known account lookup failed, code %d", retcode); goto out; + } + + if (wksid) { + /* Found a well-known account, but no mapping */ + TRACE(req, res, "Well-known account"); + } else { + TRACE(req, res, "Not a well-known account"); - if (!wksid) { /* Check if this is a localsid */ retcode = lookup_localsid2pid(req, res); - if (retcode != IDMAP_ERR_NOTFOUND) + if (retcode == IDMAP_SUCCESS) { + TRACE(req, res, "Local SID"); + goto out; + } else if (retcode != IDMAP_ERR_NOTFOUND) { + TRACE(req, res, + "Local SID lookup error=%d", retcode); goto out; + } + TRACE(req, res, "Not a local SID"); if (ALLOW_WK_OR_LOCAL_SIDS_ONLY(req)) { retcode = IDMAP_ERR_NONE_GENERATED; @@ -2557,12 +2601,19 @@ sid2pid_first_pass(lookup_state_t *state, idmap_mapping *req, retcode = IDMAP_ERR_MEMORY; goto out; } + TRACE(req, res, "Added default domain"); } /* Lookup cache */ retcode = lookup_cache_sid2pid(state->cache, req, res); - if (retcode != IDMAP_ERR_NOTFOUND) + if (retcode == IDMAP_SUCCESS) { + TRACE(req, res, "Found in mapping cache"); goto out; + } else if (retcode != IDMAP_ERR_NOTFOUND) { + TRACE(req, res, "Mapping cache lookup error=%d", retcode); + goto out; + } + TRACE(req, res, "Not found in mapping cache"); if (DO_NOT_ALLOC_NEW_ID_MAPPING(req) || AVOID_NAMESERVICE(req)) { retcode = IDMAP_ERR_NONE_GENERATED; @@ -2579,9 +2630,64 @@ sid2pid_first_pass(lookup_state_t *state, idmap_mapping *req, * batched for AD lookup. */ retcode = lookup_name_cache(state->cache, req, res); - if (retcode != IDMAP_SUCCESS && retcode != IDMAP_ERR_NOTFOUND) + if (retcode == IDMAP_SUCCESS) { + if (res->id.idtype == IDMAP_POSIXID) { + if (req->id1.idtype == IDMAP_USID) + res->id.idtype = IDMAP_UID; + else + res->id.idtype = IDMAP_GID; + } + } else if (retcode != IDMAP_ERR_NOTFOUND) goto out; + if (_idmapdstate.cfg->pgcfg.use_lsa && + _idmapdstate.cfg->pgcfg.domain_name != NULL) { + /* + * If we don't have both name and SID, try looking up the + * entry with LSA. + */ + if (req->id1.idmap_id_u.sid.prefix != NULL && + req->id1name == NULL) { + + retcode = lookup_lsa_by_sid( + req->id1.idmap_id_u.sid.prefix, + req->id1.idmap_id_u.sid.rid, + &req->id1name, &req->id1domain, &req->id1.idtype); + if (retcode == IDMAP_SUCCESS) { + TRACE(req, res, "Found with LSA"); + } else if (retcode == IDMAP_ERR_NOTFOUND) { + TRACE(req, res, "Not found with LSA"); + } else { + TRACE(req, res, "LSA error %d", retcode); + goto out; + } + + } else if (req->id1name != NULL && + req->id1.idmap_id_u.sid.prefix == NULL) { + char *canonname; + char *canondomain; + + retcode = lookup_lsa_by_name( + req->id1name, req->id1domain, + &req->id1.idmap_id_u.sid.prefix, + &req->id1.idmap_id_u.sid.rid, + &canonname, &canondomain, + &req->id1.idtype); + if (retcode == IDMAP_SUCCESS) { + free(req->id1name); + req->id1name = canonname; + free(req->id1domain); + req->id1domain = canondomain; + TRACE(req, res, "Found with LSA"); + } else if (retcode == IDMAP_ERR_NOTFOUND) { + TRACE(req, res, "Not found with LSA"); + } else { + TRACE(req, res, "LSA error %d", retcode); + goto out; + } + } + } + /* * Set the flag to indicate that we are not done yet so that * subsequent passes considers this request for name-based @@ -2652,7 +2758,7 @@ generate_localsid(idmap_mapping *req, idmap_id_res *res, int is_user, RDLOCK_CONFIG(); /* * machine_sid is never NULL because if it is we won't be here. - * No need to assert because stdrup(NULL) will core anyways. + * No need to assert because strdup(NULL) will core anyways. */ res->id.idmap_id_u.sid.prefix = strdup(_idmapdstate.cfg->pgcfg.machine_sid); @@ -2956,6 +3062,12 @@ name_based_mapping_sid2pid(lookup_state_t *state, retcode = IDMAP_ERR_INTERNAL; goto out; } + + TRACE(req, res, "Matching rule: %s@%s -> %s", + values[2] == NULL ? "(null)" : values[2], + values[3] == NULL ? "(null)" : values[3], + values[0] == NULL ? "(null)" : values[0]); + if (values[0] == NULL) { retcode = IDMAP_ERR_INTERNAL; goto out; @@ -2969,6 +3081,7 @@ name_based_mapping_sid2pid(lookup_state_t *state, direction = IDMAP_DIRECTION_W2U; if (EMPTY_NAME(values[0])) { + TRACE(req, res, "Mapping inhibited"); idmap_namerule_set(rule, values[3], values[2], values[0], is_user, is_wuser, strtol(values[4], &end, 10), @@ -2987,11 +3100,18 @@ name_based_mapping_sid2pid(lookup_state_t *state, retcode = ns_lookup_byname(unixname, lower_unixname, &res->id); - if (retcode == IDMAP_ERR_NOTFOUND) { - if (values[0][0] == '*') + if (retcode == IDMAP_SUCCESS) { + break; + } else if (retcode == IDMAP_ERR_NOTFOUND) { + if (values[0][0] == '*') { + TRACE(req, res, + "%s not found, continuing", + unixname); /* Case 4 */ continue; - else { + } else { + TRACE(req, res, + "%s not found, error", unixname); /* Case 3 */ idmap_namerule_set(rule, values[3], values[2], values[0], is_user, @@ -3000,6 +3120,9 @@ name_based_mapping_sid2pid(lookup_state_t *state, direction); retcode = IDMAP_ERR_NOMAPPING; } + } else { + TRACE(req, res, "Looking up %s error=%d", + unixname, retcode); } goto out; } else if (r == SQLITE_DONE) { @@ -3016,29 +3139,36 @@ name_based_mapping_sid2pid(lookup_state_t *state, } } -out: - if (sql != NULL) - sqlite_freemem(sql); - if (retcode == IDMAP_SUCCESS) { - if (values[1] != NULL) - res->direction = - (strtol(values[1], &end, 10) == 0)? - IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI; - else - res->direction = IDMAP_DIRECTION_W2U; + /* Found */ - req->id2name = strdup(unixname); - if (req->id2name == NULL) { - retcode = IDMAP_ERR_MEMORY; - } + if (values[1] != NULL) + res->direction = + (strtol(values[1], &end, 10) == 0)? + IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI; + else + res->direction = IDMAP_DIRECTION_W2U; + + req->id2name = strdup(unixname); + if (req->id2name == NULL) { + retcode = IDMAP_ERR_MEMORY; + goto out; } + TRACE(req, res, "UNIX name found"); - if (retcode == IDMAP_SUCCESS) { - idmap_namerule_set(rule, values[3], values[2], - values[0], is_user, is_wuser, strtol(values[4], &end, 10), - res->direction); + idmap_namerule_set(rule, values[3], values[2], + values[0], is_user, is_wuser, strtol(values[4], &end, 10), + res->direction); + +out: + if (retcode != IDMAP_SUCCESS && + retcode != IDMAP_ERR_NOTFOUND && + retcode != IDMAP_ERR_NOMAPPING) { + TRACE(req, res, "Rule processing error, code=%d", retcode); } + if (sql != NULL) + sqlite_freemem(sql); + if (retcode != IDMAP_ERR_NOTFOUND) { res->info.how.map_type = IDMAP_MAP_TYPE_RULE_BASED; res->info.src = IDMAP_MAP_SRC_NEW; @@ -3224,6 +3354,7 @@ sid2pid_second_pass(lookup_state_t *state, idmap_mapping *req, idmap_id_res *res) { idmap_retcode retcode; + idmap_retcode retcode2; /* Check if second pass is needed */ if (ARE_WE_DONE(req->direction)) @@ -3242,8 +3373,14 @@ sid2pid_second_pass(lookup_state_t *state, */ if (req->id1.idtype == IDMAP_SID) req->id1.idtype = IDMAP_USID; - if (res->id.idtype == IDMAP_POSIXID) + if (res->id.idtype == IDMAP_POSIXID) { res->id.idtype = IDMAP_UID; + TRACE(req, res, "Assume unresolvable SID is user"); + } else if (res->id.idtype == IDMAP_UID) { + TRACE(req, res, "Must map unresolvable SID to user"); + } else if (res->id.idtype == IDMAP_GID) { + TRACE(req, res, "Must map unresolvable SID to group"); + } goto do_eph; } if (retcode != IDMAP_SUCCESS) @@ -3265,8 +3402,15 @@ sid2pid_second_pass(lookup_state_t *state, * have a UID or GID that isn't in the * name service. */ - (void) ns_lookup_bypid(res->id.idmap_id_u.uid, + retcode2 = ns_lookup_bypid(res->id.idmap_id_u.uid, res->id.idtype == IDMAP_UID, &req->id2name); + if (IDMAP_ERROR(retcode2)) { + TRACE(req, res, + "Getting UNIX name, error=%d (ignored)", + retcode2); + } else { + TRACE(req, res, "Found UNIX name"); + } } goto out; } @@ -3332,42 +3476,65 @@ sid2pid_second_pass(lookup_state_t *state, res->id.idtype == IDMAP_GID) || (req->id1.idtype == IDMAP_GSID && res->id.idtype == IDMAP_UID))) { + TRACE(req, res, "Ignoring UNIX name found in AD"); free(req->id2name); req->id2name = NULL; res->id.idmap_id_u.uid = IDMAP_SENTINEL_PID; /* fallback */ } else { - if (res->id.idmap_id_u.uid == IDMAP_SENTINEL_PID) + if (res->id.idmap_id_u.uid == IDMAP_SENTINEL_PID) { retcode = ns_lookup_byname(req->id2name, NULL, &res->id); - /* - * If ns_lookup_byname() fails that means the - * unixname (req->id2name), which was obtained - * from the AD object by directory-based mapping, - * is not a valid Unix user/group and therefore - * we return the error to the client instead of - * doing rule-based mapping or ephemeral mapping. - * This way the client can detect the issue. - */ + if (retcode != IDMAP_SUCCESS) { + /* + * If ns_lookup_byname() fails that + * means the unixname (req->id2name), + * which was obtained from the AD + * object by directory-based mapping, + * is not a valid Unix user/group and + * therefore we return the error to the + * client instead of doing rule-based + * mapping or ephemeral mapping. This + * way the client can detect the issue. + */ + TRACE(req, res, + "UNIX lookup error=%d", retcode); + goto out; + } + TRACE(req, res, "UNIX lookup"); + } goto out; } } /* Free any mapping info from Directory based mapping */ if (res->info.how.map_type != IDMAP_MAP_TYPE_UNKNOWN) - idmap_info_free(&res->info); + idmap_how_clear(&res->info.how); /* * If we don't have unixname then evaluate local name-based * mapping rules. */ retcode = name_based_mapping_sid2pid(state, req, res); - if (retcode != IDMAP_ERR_NOTFOUND) + if (retcode == IDMAP_SUCCESS) { + TRACE(req, res, "Rule-based mapping"); goto out; + } else if (retcode != IDMAP_ERR_NOTFOUND) { + TRACE(req, res, "Rule-based mapping error=%d", retcode); + goto out; + } + TRACE(req, res, "No matching rule"); do_eph: /* If not found, do ephemeral mapping */ retcode = dynamic_ephemeral_mapping(state, req, res); + if (retcode == IDMAP_SUCCESS) { + TRACE(req, res, "Ephemeral mapping"); + goto out; + } else if (retcode != IDMAP_ERR_NOTFOUND) { + TRACE(req, res, "Ephemeral mapping error=%d", retcode); + goto out; + } out: res->retcode = idmap_stat4prot(retcode); @@ -3386,6 +3553,7 @@ update_cache_pid2sid(lookup_state_t *state, { char *sql = NULL; idmap_retcode retcode; + idmap_retcode retcode2; char *map_dn = NULL; char *map_attr = NULL; char *map_value = NULL; @@ -3420,8 +3588,12 @@ update_cache_pid2sid(lookup_state_t *state, * If we can't find it... c'est la vie. */ if (req->id1name == NULL) { - (void) ns_lookup_bypid(req->id1.idmap_id_u.uid, + retcode2 = ns_lookup_bypid(req->id1.idmap_id_u.uid, req->id1.idtype == IDMAP_UID, &req->id1name); + if (retcode2 == IDMAP_SUCCESS) + TRACE(req, res, "Found UNIX name"); + else + TRACE(req, res, "Getting UNIX name error=%d", retcode2); } assert(res->info.how.map_type != IDMAP_MAP_TYPE_UNKNOWN); @@ -3458,7 +3630,7 @@ update_cache_pid2sid(lookup_state_t *state, break; default: - /* Dont cache other mapping types */ + /* Don't cache other mapping types */ assert(FALSE); } @@ -3508,7 +3680,7 @@ update_cache_pid2sid(lookup_state_t *state, "VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ", res->id.idmap_id_u.sid.prefix, res->id.idmap_id_u.sid.rid, req->id2name, req->id2domain, - (res->id.idtype == IDMAP_USID) ? _IDMAP_T_USER : _IDMAP_T_GROUP); + res->id.idtype); if (sql == NULL) { retcode = IDMAP_ERR_INTERNAL; @@ -3519,8 +3691,6 @@ update_cache_pid2sid(lookup_state_t *state, retcode = sql_exec_no_cb(state->cache, IDMAP_CACHENAME, sql); out: - if (!(req->flag & IDMAP_REQ_FLG_MAPPING_INFO)) - idmap_info_free(&res->info); if (sql != NULL) sqlite_freemem(sql); return (retcode); @@ -3612,7 +3782,7 @@ update_cache_sid2pid(lookup_state_t *state, break; default: - /* Dont cache other mapping types */ + /* Don't cache other mapping types */ assert(FALSE); } @@ -3659,7 +3829,7 @@ update_cache_sid2pid(lookup_state_t *state, "VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ", req->id1.idmap_id_u.sid.prefix, req->id1.idmap_id_u.sid.rid, req->id1name, req->id1domain, - (req->id1.idtype == IDMAP_USID) ? _IDMAP_T_USER : _IDMAP_T_GROUP); + req->id1.idtype); if (sql == NULL) { retcode = IDMAP_ERR_INTERNAL; @@ -3670,9 +3840,6 @@ update_cache_sid2pid(lookup_state_t *state, retcode = sql_exec_no_cb(state->cache, IDMAP_CACHENAME, sql); out: - if (!(req->flag & IDMAP_REQ_FLG_MAPPING_INFO)) - idmap_info_free(&res->info); - if (sql != NULL) sqlite_freemem(sql); return (retcode); @@ -3889,8 +4056,14 @@ out: */ static idmap_retcode -lookup_cache_name2sid(sqlite *cache, const char *name, const char *domain, - char **canonname, char **sidprefix, idmap_rid_t *rid, int *type) +lookup_cache_name2sid( + sqlite *cache, + const char *name, + const char *domain, + char **canonname, + char **sidprefix, + idmap_rid_t *rid, + idmap_id_type *type) { char *end, *lower_name; char *sql; @@ -3939,7 +4112,7 @@ lookup_cache_name2sid(sqlite *cache, const char *name, const char *domain, retcode = IDMAP_ERR_CACHE; goto out; } - *type = strtol(values[2], &end, 10); + *type = xlate_legacy_type(strtol(values[2], &end, 10)); } if (values[0] == NULL || values[1] == NULL) { @@ -3985,9 +4158,9 @@ out: static idmap_retcode ad_lookup_by_winname(lookup_state_t *state, - const char *name, const char *domain, int eunixtype, + const char *name, const char *domain, int esidtype, char **dn, char **attr, char **value, char **canonname, - char **sidprefix, idmap_rid_t *rid, int *wintype, + char **sidprefix, idmap_rid_t *rid, idmap_id_type *wintype, char **unixname) { int retries; @@ -4034,7 +4207,7 @@ retry: } retcode = idmap_name2sid_batch_add1(qs, name, domain, - eunixtype, dn, attr, value, canonname, sidprefix, + esidtype, dn, attr, value, canonname, sidprefix, rid, wintype, unixname, NULL, &rc); if (retcode == IDMAP_ERR_DOMAIN_NOTFOUND) { idmap_lookup_release_batch(&qs); @@ -4092,15 +4265,15 @@ lookup_name2sid( sqlite *cache, const char *name, const char *domain, - int *is_wuser, + int want_wuser, char **canonname, char **canondomain, char **sidprefix, idmap_rid_t *rid, + idmap_id_type *type, idmap_mapping *req, int local_only) { - int type; idmap_retcode retcode; *sidprefix = NULL; @@ -4111,7 +4284,7 @@ lookup_name2sid( /* Lookup well-known SIDs table */ retcode = lookup_wksids_name2sid(name, domain, canonname, canondomain, - sidprefix, rid, &type); + sidprefix, rid, type); if (retcode == IDMAP_SUCCESS) { req->direction |= _IDMAP_F_DONT_UPDATE_NAMECACHE; goto out; @@ -4121,7 +4294,7 @@ lookup_name2sid( /* Lookup cache */ retcode = lookup_cache_name2sid(cache, name, domain, canonname, - sidprefix, rid, &type); + sidprefix, rid, type); if (retcode == IDMAP_SUCCESS) { req->direction |= _IDMAP_F_DONT_UPDATE_NAMECACHE; goto out; @@ -4138,28 +4311,39 @@ lookup_name2sid( if (local_only) return (retcode); + if (_idmapdstate.cfg->pgcfg.use_lsa && + _idmapdstate.cfg->pgcfg.domain_name != NULL && + name != NULL && *sidprefix == NULL) { + retcode = lookup_lsa_by_name(name, domain, + sidprefix, rid, + canonname, canondomain, + type); + if (retcode == IDMAP_SUCCESS) + goto out; + else if (retcode != IDMAP_ERR_NOTFOUND) + return (retcode); + } + /* Lookup AD */ - retcode = ad_lookup_by_winname(NULL, name, domain, _IDMAP_T_UNDEF, - NULL, NULL, NULL, canonname, sidprefix, rid, &type, NULL); + retcode = ad_lookup_by_winname(NULL, name, domain, IDMAP_POSIXID, + NULL, NULL, NULL, canonname, sidprefix, rid, type, NULL); if (retcode != IDMAP_SUCCESS) return (retcode); out: /* * Entry found (cache or Windows lookup) - * is_wuser is both input as well as output parameter */ - if (*is_wuser == 1 && type != _IDMAP_T_USER) + if (want_wuser == 1 && *type != IDMAP_USID) retcode = IDMAP_ERR_NOTUSER; - else if (*is_wuser == 0 && type != _IDMAP_T_GROUP) + else if (want_wuser == 0 && *type != IDMAP_GSID) retcode = IDMAP_ERR_NOTGROUP; - else if (*is_wuser == -1) { - /* Caller wants to know if its user or group */ - if (type == _IDMAP_T_USER) - *is_wuser = 1; - else if (type == _IDMAP_T_GROUP) - *is_wuser = 0; - else + else if (want_wuser == -1) { + /* + * Caller wants to know if its user or group + * Verify that it's one or the other. + */ + if (*type != IDMAP_USID && *type != IDMAP_GSID) retcode = IDMAP_ERR_SID; } @@ -4204,7 +4388,7 @@ name_based_mapping_pid2sid(lookup_state_t *state, const char *unixname, const char **values; sqlite_vm *vm = NULL; int ncol, r; - int is_wuser; + int want_wuser; const char *me = "name_based_mapping_pid2sid"; int non_wild_match = FALSE; idmap_namerule *rule = &res->info.how.idmap_how_u.rule; @@ -4243,6 +4427,12 @@ name_based_mapping_pid2sid(lookup_state_t *state, const char *unixname, retcode = IDMAP_ERR_INTERNAL; goto out; } + + TRACE(req, res, "Matching rule: %s -> %s@%s", + values[4] == NULL ? "(null)" : values[4], + values[0] == NULL ? "(null)" : values[0], + values[1] == NULL ? "(null)" : values[1]); + if (values[0] == NULL) { /* values [1] and [2] can be null */ retcode = IDMAP_ERR_INTERNAL; @@ -4262,6 +4452,7 @@ name_based_mapping_pid2sid(lookup_state_t *state, const char *unixname, strtol(values[3], &end, 10), strtol(values[5], &end, 10), direction); + TRACE(req, res, "Mapping inhibited"); retcode = IDMAP_ERR_NOMAPPING; goto out; } @@ -4290,28 +4481,44 @@ name_based_mapping_pid2sid(lookup_state_t *state, const char *unixname, } winname = values[0]; } - is_wuser = res->id.idtype == IDMAP_USID ? 1 + want_wuser = res->id.idtype == IDMAP_USID ? 1 : res->id.idtype == IDMAP_GSID ? 0 : -1; if (values[1] != NULL) windomain = values[1]; - else if (state->defdom != NULL) + else if (state->defdom != NULL) { windomain = state->defdom; - else { + TRACE(req, res, + "Added default domain %s to rule", + windomain); + } else { idmapdlog(LOG_ERR, "%s: no domain", me); + TRACE(req, res, + "No domain in rule, and no default domain"); retcode = IDMAP_ERR_DOMAIN_NOTFOUND; goto out; } retcode = lookup_name2sid(state->cache, winname, windomain, - &is_wuser, &canonname, &canondomain, + want_wuser, &canonname, &canondomain, &res->id.idmap_id_u.sid.prefix, - &res->id.idmap_id_u.sid.rid, req, 0); + &res->id.idmap_id_u.sid.rid, + &res->id.idtype, req, 0); - if (retcode == IDMAP_ERR_NOTFOUND) { + if (retcode == IDMAP_SUCCESS) { + break; + } else if (retcode == IDMAP_ERR_NOTFOUND) { + TRACE(req, res, + "%s@%s not found, continuing", + winname, windomain); continue; + } else { + TRACE(req, res, + "Looking up %s@%s error=%d", + winname, windomain, retcode); } + goto out; } else if (r == SQLITE_DONE) { @@ -4336,29 +4543,25 @@ name_based_mapping_pid2sid(lookup_state_t *state, const char *unixname, } } -out: - if (sql != NULL) - sqlite_freemem(sql); - if (retcode == IDMAP_SUCCESS) { - res->id.idtype = is_wuser ? IDMAP_USID : IDMAP_GSID; + if (values[2] != NULL) + res->direction = + (strtol(values[2], &end, 10) == 0)? + IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI; + else + res->direction = IDMAP_DIRECTION_U2W; - if (values[2] != NULL) - res->direction = - (strtol(values[2], &end, 10) == 0)? - IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI; - else - res->direction = IDMAP_DIRECTION_U2W; + req->id2name = canonname; + req->id2domain = canondomain; - req->id2name = canonname; - req->id2domain = canondomain; - } + idmap_namerule_set(rule, values[1], values[0], values[4], + is_user, strtol(values[3], &end, 10), + strtol(values[5], &end, 10), + rule->direction); + TRACE(req, res, "Windows name found"); - if (retcode == IDMAP_SUCCESS) { - idmap_namerule_set(rule, values[1], values[0], values[4], - is_user, strtol(values[3], &end, 10), - strtol(values[5], &end, 10), - rule->direction); - } +out: + if (sql != NULL) + sqlite_freemem(sql); if (retcode != IDMAP_ERR_NOTFOUND) { res->info.how.map_type = IDMAP_MAP_TYPE_RULE_BASED; @@ -4432,6 +4635,7 @@ pid2sid_first_pass(lookup_state_t *state, idmap_mapping *req, idmap_id_res *res, int is_user) { idmap_retcode retcode; + idmap_retcode retcode2; bool_t gen_localsid_on_err = FALSE; /* Initialize result */ @@ -4451,26 +4655,42 @@ pid2sid_first_pass(lookup_state_t *state, idmap_mapping *req, goto out; } - if (ns_lookup_byname(req->id1name, NULL, &req->id1) - != IDMAP_SUCCESS) { + retcode = ns_lookup_byname(req->id1name, NULL, &req->id1); + if (retcode != IDMAP_SUCCESS) { + TRACE(req, res, "Getting UNIX ID error=%d", retcode); retcode = IDMAP_ERR_NOMAPPING; goto out; } + TRACE(req, res, "Found UNIX ID"); } /* Lookup in well-known SIDs table */ retcode = lookup_wksids_pid2sid(req, res, is_user); - if (retcode != IDMAP_ERR_NOTFOUND) + if (retcode == IDMAP_SUCCESS) { + TRACE(req, res, "Hardwired mapping"); + goto out; + } else if (retcode != IDMAP_ERR_NOTFOUND) { + TRACE(req, res, + "Well-known account lookup error=%d", retcode); goto out; + } /* Lookup in cache */ retcode = lookup_cache_pid2sid(state->cache, req, res, is_user); - if (retcode != IDMAP_ERR_NOTFOUND) + if (retcode == IDMAP_SUCCESS) { + TRACE(req, res, "Found in mapping cache"); + goto out; + } else if (retcode != IDMAP_ERR_NOTFOUND) { + TRACE(req, res, + "Mapping cache lookup error=%d", retcode); goto out; + } + TRACE(req, res, "Not found in mapping cache"); /* Ephemeral ids cannot be allocated during pid2sid */ if (IDMAP_ID_IS_EPHEMERAL(req->id1.idmap_id_u.uid)) { retcode = IDMAP_ERR_NOMAPPING; + TRACE(req, res, "Shouldn't have an ephemeral ID here"); goto out; } @@ -4500,9 +4720,12 @@ pid2sid_first_pass(lookup_state_t *state, idmap_mapping *req, retcode = ns_lookup_bypid(req->id1.idmap_id_u.uid, is_user, &req->id1name); if (retcode != IDMAP_SUCCESS) { + TRACE(req, res, + "Getting UNIX name error=%d", retcode); gen_localsid_on_err = TRUE; goto out; } + TRACE(req, res, "Found UNIX name"); } req->direction |= _IDMAP_F_LOOKUP_AD; state->ad_nqueries++; @@ -4526,9 +4749,16 @@ pid2sid_first_pass(lookup_state_t *state, idmap_mapping *req, out: res->retcode = idmap_stat4prot(retcode); - if (ARE_WE_DONE(req->direction) && res->retcode != IDMAP_SUCCESS) - if (gen_localsid_on_err == TRUE) - (void) generate_localsid(req, res, is_user, TRUE); + if (ARE_WE_DONE(req->direction) && res->retcode != IDMAP_SUCCESS) { + if (gen_localsid_on_err == TRUE) { + retcode2 = generate_localsid(req, res, is_user, TRUE); + if (retcode2 == IDMAP_SUCCESS) + TRACE(req, res, "Generate local SID"); + else + TRACE(req, res, + "Generate local SID error=%d", retcode2); + } + } return (retcode); } @@ -4538,6 +4768,7 @@ pid2sid_second_pass(lookup_state_t *state, idmap_mapping *req, { bool_t gen_localsid_on_err = TRUE; idmap_retcode retcode = IDMAP_SUCCESS; + idmap_retcode retcode2; /* Check if second pass is needed */ if (ARE_WE_DONE(req->direction)) @@ -4561,6 +4792,7 @@ pid2sid_second_pass(lookup_state_t *state, idmap_mapping *req, if (req->id2name != NULL) { /* Return notfound if we've winname but no SID. */ if (res->id.idmap_id_u.sid.prefix == NULL) { + TRACE(req, res, "Windows name but no SID"); retcode = IDMAP_ERR_NOTFOUND; goto out; } @@ -4583,21 +4815,28 @@ pid2sid_second_pass(lookup_state_t *state, idmap_mapping *req, /* Free any mapping info from Directory based mapping */ if (res->info.how.map_type != IDMAP_MAP_TYPE_UNKNOWN) - idmap_info_free(&res->info); + idmap_how_clear(&res->info.how); if (req->id1name == NULL) { /* Get unixname from name service */ retcode = ns_lookup_bypid(req->id1.idmap_id_u.uid, is_user, &req->id1name); - if (retcode != IDMAP_SUCCESS) + if (retcode != IDMAP_SUCCESS) { + TRACE(req, res, + "Getting UNIX name error=%d", retcode); goto out; + } + TRACE(req, res, "Found UNIX name"); } else if (req->id1.idmap_id_u.uid == IDMAP_SENTINEL_PID) { /* Get pid from name service */ retcode = ns_lookup_byname(req->id1name, NULL, &req->id1); if (retcode != IDMAP_SUCCESS) { + TRACE(req, res, + "Getting UNIX ID error=%d", retcode); gen_localsid_on_err = FALSE; goto out; } + TRACE(req, res, "Found UNIX ID"); } /* Use unixname to evaluate local name-based mapping rules */ @@ -4605,6 +4844,12 @@ pid2sid_second_pass(lookup_state_t *state, idmap_mapping *req, req, res); if (retcode == IDMAP_ERR_NOTFOUND) { retcode = generate_localsid(req, res, is_user, FALSE); + if (retcode == IDMAP_SUCCESS) { + TRACE(req, res, "Generated local SID"); + } else { + TRACE(req, res, + "Generating local SID error=%d", retcode); + } gen_localsid_on_err = FALSE; } @@ -4616,10 +4861,16 @@ out: req->id2name = NULL; free(req->id2domain); req->id2domain = NULL; - if (gen_localsid_on_err == TRUE) - (void) generate_localsid(req, res, is_user, TRUE); - else + if (gen_localsid_on_err == TRUE) { + retcode2 = generate_localsid(req, res, is_user, TRUE); + if (retcode2 == IDMAP_SUCCESS) + TRACE(req, res, "Generate local SID"); + else + TRACE(req, res, + "Generate local SID error=%d", retcode2); + } else { res->id.idtype = is_user ? IDMAP_USID : IDMAP_GSID; + } } if (!ARE_WE_DONE(req->direction)) state->pid2sid_done = FALSE; diff --git a/usr/src/cmd/idmap/idmapd/idmap.xml b/usr/src/cmd/idmap/idmapd/idmap.xml index b7400cc811..87933b5507 100644 --- a/usr/src/cmd/idmap/idmapd/idmap.xml +++ b/usr/src/cmd/idmap/idmapd/idmap.xml @@ -1,8 +1,7 @@ <?xml version="1.0"?> <!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> <!-- - Copyright 2007 Sun Microsystems, Inc. All rights reserved. - Use is subject to license terms. + Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. CDDL HEADER START @@ -23,8 +22,6 @@ CDDL HEADER END - ident "%Z%%M% %I% %E% SMI" - NOTE: This service manifest is not editable; its contents will be overwritten by package or patch operations, including operating system upgrade. Make customizations in a different @@ -101,6 +98,20 @@ value='solaris.smf.value.idmap' /> </property_group> + <property_group name='debug' type='application' > + <stability value='Unstable' /> + <propval name='all' type='integer' value='0' /> + <propval name='config' type='integer' value='0' /> + <propval name='mapping' type='integer' value='0' /> + <propval name='discovery' type='integer' value='0' /> + <propval name='dns' type='integer' value='0' /> + <propval name='ldap' type='integer' value='0' /> + <propval + name='value_authorization' + type='astring' + value='solaris.smf.value.idmap' /> + </property_group> + <stability value='Unstable' /> <template> diff --git a/usr/src/cmd/idmap/idmapd/idmap_config.c b/usr/src/cmd/idmap/idmapd/idmap_config.c index c25f6da2fc..cf5848aa0f 100644 --- a/usr/src/cmd/idmap/idmapd/idmap_config.c +++ b/usr/src/cmd/idmap/idmapd/idmap_config.c @@ -40,12 +40,13 @@ #include <port.h> #include <net/route.h> #include <sys/u8_textprep.h> +#include <note.h> #include "addisc.h" #define MACHINE_SID_LEN (9 + 3 * 11) #define FMRI_BASE "svc:/system/idmap" #define CONFIG_PG "config" -#define GENERAL_PG "general" +#define DEBUG_PG "debug" #define RECONFIGURE 1 #define POKE_AUTO_DISCOVERY 2 @@ -57,7 +58,6 @@ enum event_type { EVENT_REFRESH, /* SMF refresh */ }; -/*LINTLIBRARY*/ static pthread_t update_thread_handle = 0; @@ -72,6 +72,13 @@ struct enum_lookup_map directory_mapping_map[] = { { 0, NULL }, }; +struct enum_lookup_map trust_dir_map[] = { + { 1, "they trust us" }, + { 2, "we trust them" }, + { 3, "we trust each other" }, + { 0, NULL }, +}; + static int generate_machine_sid(char **machine_sid) { @@ -125,7 +132,6 @@ prop_exists(idmap_cfg_handles_t *handles, const char *name, boolean_t *exists) { scf_property_t *scf_prop; - scf_value_t *value; *exists = B_FALSE; @@ -135,6 +141,77 @@ prop_exists(idmap_cfg_handles_t *handles, const char *name, boolean_t *exists) scf_strerror(scf_error())); return (-1); } + + if (scf_pg_get_property(handles->config_pg, name, scf_prop) == 0) + *exists = B_TRUE; + + scf_property_destroy(scf_prop); + + return (0); +} + +static int +get_debug(idmap_cfg_handles_t *handles, const char *name) +{ + int64_t i64 = 0; + + scf_property_t *scf_prop; + scf_value_t *value; + + scf_prop = scf_property_create(handles->main); + if (scf_prop == NULL) { + idmapdlog(LOG_ERR, "scf_property_create() failed: %s", + scf_strerror(scf_error())); + abort(); + } + value = scf_value_create(handles->main); + if (value == NULL) { + idmapdlog(LOG_ERR, "scf_value_create() failed: %s", + scf_strerror(scf_error())); + abort(); + } + + if (scf_pg_get_property(handles->debug_pg, name, scf_prop) < 0) { + /* this is OK: the property is just undefined */ + goto destruction; + } + + + if (scf_property_get_value(scf_prop, value) < 0) { + /* It is still OK when a property doesn't have any value */ + goto destruction; + } + + if (scf_value_get_integer(value, &i64) != 0) { + idmapdlog(LOG_ERR, "Can not retrieve %s/%s: %s", + DEBUG_PG, name, scf_strerror(scf_error())); + abort(); + } + +destruction: + scf_value_destroy(value); + scf_property_destroy(scf_prop); + + return ((int)i64); +} + +static int +get_val_bool(idmap_cfg_handles_t *handles, const char *name, + boolean_t *val, boolean_t default_val) +{ + int rc = 0; + + scf_property_t *scf_prop; + scf_value_t *value; + + *val = default_val; + + scf_prop = scf_property_create(handles->main); + if (scf_prop == NULL) { + idmapdlog(LOG_ERR, "scf_property_create() failed: %s", + scf_strerror(scf_error())); + return (-1); + } value = scf_value_create(handles->main); if (value == NULL) { idmapdlog(LOG_ERR, "scf_value_create() failed: %s", @@ -143,16 +220,28 @@ prop_exists(idmap_cfg_handles_t *handles, const char *name, boolean_t *exists) return (-1); } - if (scf_pg_get_property(handles->config_pg, name, scf_prop) == 0) - *exists = B_TRUE; + /* It is OK if the property is undefined */ + if (scf_pg_get_property(handles->config_pg, name, scf_prop) < 0) + goto destruction; + + + /* It is still OK when a property doesn't have any value */ + if (scf_property_get_value(scf_prop, value) < 0) + goto destruction; + + uint8_t b; + rc = scf_value_get_boolean(value, &b); + if (rc == 0) + *val = (boolean_t)b; + +destruction: scf_value_destroy(value); scf_property_destroy(scf_prop); - return (0); + return (rc); } -/* Check if in the case of failure the original value of *val is preserved */ static int get_val_int(idmap_cfg_handles_t *handles, const char *name, void *val, scf_type_t type) @@ -161,12 +250,8 @@ get_val_int(idmap_cfg_handles_t *handles, const char *name, scf_property_t *scf_prop; scf_value_t *value; - uint8_t b; switch (type) { - case SCF_TYPE_BOOLEAN: - *(boolean_t *)val = B_FALSE; - break; case SCF_TYPE_COUNT: *(uint64_t *)val = 0; break; @@ -203,10 +288,6 @@ get_val_int(idmap_cfg_handles_t *handles, const char *name, goto destruction; switch (type) { - case SCF_TYPE_BOOLEAN: - rc = scf_value_get_boolean(value, &b); - *(boolean_t *)val = b; - break; case SCF_TYPE_COUNT: rc = scf_value_get_count(value, val); break; @@ -426,7 +507,10 @@ destruction: static int -del_val(idmap_cfg_handles_t *handles, const char *name) +del_val( + idmap_cfg_handles_t *handles, + scf_propertygroup_t *pg, + const char *name) { int rc = -1; int ret; @@ -447,13 +531,13 @@ del_val(idmap_cfg_handles_t *handles, const char *name) } do { - if (scf_pg_update(handles->config_pg) == -1) { + if (scf_pg_update(pg) == -1) { idmapdlog(LOG_ERR, "scf_pg_update(%s) failed: %s", name, scf_strerror(scf_error())); goto destruction; } - if (scf_transaction_start(tx, handles->config_pg) != 0) { + if (scf_transaction_start(tx, pg) != 0) { idmapdlog(LOG_ERR, "scf_transaction_start(%s) failed: %s", name, scf_strerror(scf_error())); @@ -496,18 +580,19 @@ destruction: static int -set_val_astring(idmap_cfg_handles_t *handles, const char *name, const char *val) +set_val( + idmap_cfg_handles_t *handles, + scf_propertygroup_t *pg, + const char *name, + scf_value_t *value) { int rc = -1; - int ret = -2; int i; - scf_property_t *scf_prop = NULL; - scf_value_t *value = NULL; + scf_property_t *prop = NULL; scf_transaction_t *tx = NULL; scf_transaction_entry_t *ent = NULL; - if ((scf_prop = scf_property_create(handles->main)) == NULL || - (value = scf_value_create(handles->main)) == NULL || + if ((prop = scf_property_create(handles->main)) == NULL || (tx = scf_transaction_create(handles->main)) == NULL || (ent = scf_entry_create(handles->main)) == NULL) { idmapdlog(LOG_ERR, "Unable to set property %s", @@ -515,26 +600,45 @@ set_val_astring(idmap_cfg_handles_t *handles, const char *name, const char *val) goto destruction; } - for (i = 0; i < MAX_TRIES && (ret == -2 || ret == 0); i++) { - if (scf_transaction_start(tx, handles->config_pg) == -1) { + for (i = 0; i < MAX_TRIES; i++) { + int ret; + + if (scf_pg_update(pg) == -1) { idmapdlog(LOG_ERR, - "scf_transaction_start(%s) failed: %s", - name, scf_strerror(scf_error())); + "scf_pg_update() failed: %s", + scf_strerror(scf_error())); goto destruction; } - if (scf_transaction_property_new(tx, ent, name, - SCF_TYPE_ASTRING) < 0) { + if (scf_transaction_start(tx, pg) == -1) { idmapdlog(LOG_ERR, - "scf_transaction_property_new() failed: %s", - scf_strerror(scf_error())); + "scf_transaction_start(%s) failed: %s", + name, scf_strerror(scf_error())); goto destruction; } - if (scf_value_set_astring(value, val) == -1) { + ret = scf_pg_get_property(pg, name, prop); + if (ret == SCF_SUCCESS) { + if (scf_transaction_property_change_type(tx, ent, name, + scf_value_type(value)) < 0) { + idmapdlog(LOG_ERR, + "scf_transaction_property_change_type(%s)" + " failed: %s", + name, scf_strerror(scf_error())); + goto destruction; + } + } else if (scf_error() == SCF_ERROR_NOT_FOUND) { + if (scf_transaction_property_new(tx, ent, name, + scf_value_type(value)) < 0) { + idmapdlog(LOG_ERR, + "scf_transaction_property_new() failed: %s", + scf_strerror(scf_error())); + goto destruction; + } + } else { idmapdlog(LOG_ERR, - "scf_value_set_astring() failed: %s", - scf_strerror(scf_error())); + "scf_pg_get_property(%s) failed: %s", + name, scf_strerror(scf_error())); goto destruction; } @@ -545,41 +649,90 @@ set_val_astring(idmap_cfg_handles_t *handles, const char *name, const char *val) goto destruction; } - if ((ret = scf_transaction_commit(tx)) == 1) - break; - - if (ret == 0 && i < MAX_TRIES - 1) { + ret = scf_transaction_commit(tx); + if (ret == 0) { /* * Property group set in scf_transaction_start() * is not the most recent. Update pg, reset tx and * retry tx. */ idmapdlog(LOG_WARNING, - "scf_transaction_commit(%s) failed - Retry: %s", + "scf_transaction_commit(%s) failed: %s", name, scf_strerror(scf_error())); - if (scf_pg_update(handles->config_pg) == -1) { - idmapdlog(LOG_ERR, - "scf_pg_update() failed: %s", - scf_strerror(scf_error())); - goto destruction; - } scf_transaction_reset(tx); + continue; + } + if (ret != 1) { + idmapdlog(LOG_ERR, + "scf_transaction_commit(%s) failed: %s", + name, scf_strerror(scf_error())); + goto destruction; } + /* Success! */ + rc = 0; + break; } +destruction: + scf_entry_destroy(ent); + scf_transaction_destroy(tx); + scf_property_destroy(prop); + return (rc); +} - if (ret == 1) - rc = 0; - else if (ret != -2) - idmapdlog(LOG_ERR, - "scf_transaction_commit(%s) failed: %s", +static int +set_val_integer( + idmap_cfg_handles_t *handles, + scf_propertygroup_t *pg, + const char *name, + int64_t val) +{ + scf_value_t *value = NULL; + int rc; + + if ((value = scf_value_create(handles->main)) == NULL) { + idmapdlog(LOG_ERR, "Unable to set property %s", name, scf_strerror(scf_error())); + return (-1); + } + + scf_value_set_integer(value, val); + + rc = set_val(handles, pg, name, value); -destruction: scf_value_destroy(value); - scf_entry_destroy(ent); - scf_transaction_destroy(tx); - scf_property_destroy(scf_prop); + + return (rc); +} + + +static int +set_val_astring( + idmap_cfg_handles_t *handles, + scf_propertygroup_t *pg, + const char *name, + const char *val) +{ + scf_value_t *value = NULL; + int rc = -1; + + if ((value = scf_value_create(handles->main)) == NULL) { + idmapdlog(LOG_ERR, "Unable to set property %s", + name, scf_strerror(scf_error())); + goto out; + } + + if (scf_value_set_astring(value, val) == -1) { + idmapdlog(LOG_ERR, + "scf_value_set_astring() failed: %s", + scf_strerror(scf_error())); + goto out; + } + + rc = set_val(handles, pg, name, value); + +out: + scf_value_destroy(value); return (rc); } @@ -595,12 +748,15 @@ update_bool(boolean_t *value, boolean_t *new, char *name) if (*value == *new) return (0); - idmapdlog(LOG_INFO, "change %s=%s", name, *new ? "true" : "false"); + if (DBG(CONFIG, 1)) { + idmapdlog(LOG_INFO, "change %s=%s", name, + *new ? "true" : "false"); + } + *value = *new; return (1); } - /* * This function updates a string value. * If nothing has changed it returns 0 else 1 @@ -608,21 +764,29 @@ update_bool(boolean_t *value, boolean_t *new, char *name) static int update_string(char **value, char **new, char *name) { - if (*new == NULL) - return (0); + int changed; + + if (*new == NULL && *value != NULL) + changed = 1; + else if (*new != NULL && *value == NULL) + changed = 1; + else if (*new != NULL && *value != NULL && strcmp(*new, *value) != 0) + changed = 1; + else + changed = 0; - if (*value != NULL && strcmp(*new, *value) == 0) { - free(*new); - *new = NULL; - return (0); - } + /* + * Note that even if unchanged we can't just return; we must free one + * of the values. + */ - idmapdlog(LOG_INFO, "change %s=%s", name, CHECK_NULL(*new)); - if (*value != NULL) - free(*value); + if (DBG(CONFIG, 1) && changed) + idmapdlog(LOG_INFO, "change %s=%s", name, CHECK_NULL(*new)); + + free(*value); *value = *new; *new = NULL; - return (1); + return (changed); } static int @@ -631,7 +795,10 @@ update_enum(int *value, int *new, char *name, struct enum_lookup_map *map) if (*value == *new) return (0); - idmapdlog(LOG_INFO, "change %s=%s", name, enum_lookup(*new, map)); + if (DBG(CONFIG, 1)) { + idmapdlog(LOG_INFO, "change %s=%s", name, + enum_lookup(*new, map)); + } *value = *new; @@ -666,14 +833,18 @@ update_dirs(idmap_ad_disc_ds_t **value, idmap_ad_disc_ds_t **new, char *name) if (*value == NULL) { /* We're unsetting this DS property */ - idmapdlog(LOG_INFO, "change %s=<none>", name); + if (DBG(CONFIG, 1)) + idmapdlog(LOG_INFO, "change %s=<none>", name); return (1); } - /* List all the new DSs */ - for (i = 0; (*value)[i].host[0] != '\0'; i++) - idmapdlog(LOG_INFO, "change %s=%s port=%d", name, - (*value)[i].host, (*value)[i].port); + if (DBG(CONFIG, 1)) { + /* List all the new DSs */ + for (i = 0; (*value)[i].host[0] != '\0'; i++) { + idmapdlog(LOG_INFO, "change %s=%s port=%d", name, + (*value)[i].host, (*value)[i].port); + } + } return (1); } @@ -706,15 +877,19 @@ update_trusted_domains(ad_disc_trusteddomains_t **value, if (*value == NULL) { /* We're unsetting this DS property */ - idmapdlog(LOG_INFO, "change %s=<none>", name); + if (DBG(CONFIG, 1)) + idmapdlog(LOG_INFO, "change %s=<none>", name); return (1); } - /* List all the new domains */ - for (i = 0; (*value)[i].domain[0] != '\0'; i++) - idmapdlog(LOG_INFO, "change %s=%s direction=%s", name, - (*value)[i].domain, - (*value)[i].direction == 3 ? "bi-directional" : "inbound"); + if (DBG(CONFIG, 1)) { + /* List all the new domains */ + for (i = 0; (*value)[i].domain[0] != '\0'; i++) { + idmapdlog(LOG_INFO, "change %s=%s direction=%s", name, + (*value)[i].domain, + enum_lookup((*value)[i].direction, trust_dir_map)); + } + } return (1); } @@ -748,14 +923,18 @@ update_domains_in_forest(ad_disc_domainsinforest_t **value, if (*value == NULL) { /* We're unsetting this DS property */ - idmapdlog(LOG_INFO, "change %s=<none>", name); + if (DBG(CONFIG, 1)) + idmapdlog(LOG_INFO, "change %s=<none>", name); return (1); } - /* List all the new domains */ - for (i = 0; (*value)[i].domain[0] != '\0'; i++) - idmapdlog(LOG_INFO, "change %s=%s", name, - (*value)[i].domain); + if (DBG(CONFIG, 1)) { + /* List all the new domains */ + for (i = 0; (*value)[i].domain[0] != '\0'; i++) { + idmapdlog(LOG_INFO, "change %s=%s", name, + (*value)[i].domain); + } + } return (1); } @@ -865,26 +1044,36 @@ not_equal: if (*value == NULL) { /* We're unsetting this DS property */ - idmapdlog(LOG_INFO, "change %s=<none>", name); + if (DBG(CONFIG, 1)) + idmapdlog(LOG_INFO, "change %s=<none>", name); return (1); } - /* List all the trusted forests */ - for (i = 0; i < *num_value; i++) { - for (j = 0; (*value)[i].domains_in_forest[j].domain[0] != '\0'; - j++) { - /* List trusted Domains in the forest. */ - if ((*value)[i].domains_in_forest[j].trusted) - idmapdlog(LOG_INFO, "change %s=%s domain=%s", - name, (*value)[i].forest_name, - (*value)[i].domains_in_forest[j].domain); + if (DBG(CONFIG, 1)) { + /* List all the trusted forests */ + for (i = 0; i < *num_value; i++) { + idmap_trustedforest_t *f = &(*value)[i]; + for (j = 0; + f->domains_in_forest[j].domain[0] != '\0'; + j++) { + /* List trusted Domains in the forest. */ + if (f->domains_in_forest[j].trusted) + idmapdlog(LOG_INFO, + "change %s=%s domain=%s", + name, f->forest_name, + f->domains_in_forest[j].domain); + } + /* List the hosts */ + for (j = 0; + f->global_catalog[j].host[0] != '\0'; + j++) { + idmapdlog(LOG_INFO, + "change %s=%s host=%s port=%d", + name, f->forest_name, + f->global_catalog[j].host, + f->global_catalog[j].port); + } } - /* List the hosts */ - for (j = 0; (*value)[i].global_catalog[j].host[0] != '\0'; j++) - idmapdlog(LOG_INFO, "change %s=%s host=%s port=%d", - name, (*value)[i].forest_name, - (*value)[i].global_catalog[j].host, - (*value)[i].global_catalog[j].port); } return (1); } @@ -950,7 +1139,7 @@ wait_for_event(struct timespec *timeoutp) { port_event_t pe; - memset(&pe, 0, sizeof (pe)); + (void) memset(&pe, 0, sizeof (pe)); if (port_get(idmapd_ev_port, &pe, timeoutp) != 0) { switch (errno) { case EINTR: @@ -1004,12 +1193,16 @@ wait_for_event(struct timespec *timeoutp) * timeout if need be. */ if (pfroute_event_is_interesting(rt_sock)) { - idmapdlog(LOG_DEBUG, - "Interesting routing event"); + if (DBG(CONFIG, 1)) { + idmapdlog(LOG_DEBUG, + "Interesting routing event"); + } return (EVENT_ROUTING); } else { - idmapdlog(LOG_DEBUG, - "Boring routing event"); + if (DBG(CONFIG, 2)) { + idmapdlog(LOG_DEBUG, + "Boring routing event"); + } return (EVENT_NOTHING); } } @@ -1023,6 +1216,7 @@ wait_for_event(struct timespec *timeoutp) void * idmap_cfg_update_thread(void *arg) { + NOTE(ARGUNUSED(arg)) const ad_disc_t ad_ctx = _idmapdstate.cfg->handles.ad_ctx; @@ -1062,10 +1256,12 @@ idmap_cfg_update_thread(void *arg) switch (wait_for_event(timeoutp)) { case EVENT_NOTHING: - idmapdlog(LOG_DEBUG, "Boring event."); + if (DBG(CONFIG, 2)) + idmapdlog(LOG_DEBUG, "Boring event."); continue; case EVENT_REFRESH: - idmapdlog(LOG_INFO, "SMF refresh"); + if (DBG(CONFIG, 1)) + idmapdlog(LOG_INFO, "SMF refresh"); /* * Blow away the ccache, we might have * re-joined the domain or joined a new one @@ -1073,11 +1269,14 @@ idmap_cfg_update_thread(void *arg) (void) unlink(IDMAP_CACHEDIR "/ccache"); break; case EVENT_DEGRADE: - idmapdlog(LOG_DEBUG, - "Service degraded"); + if (DBG(CONFIG, 1)) { + idmapdlog(LOG_DEBUG, + "Service degraded"); + } break; case EVENT_TIMEOUT: - idmapdlog(LOG_DEBUG, "TTL expired"); + if (DBG(CONFIG, 1)) + idmapdlog(LOG_DEBUG, "TTL expired"); break; case EVENT_ROUTING: /* Already logged to DEBUG */ @@ -1157,29 +1356,40 @@ valid_ldap_attr(const char *attr) { } static -int -check_smf_debug_mode(idmap_cfg_handles_t *handles) +void +idmapd_set_debug( + idmap_cfg_handles_t *handles, + enum idmapd_debug item, + const char *name) { - boolean_t new_debug_mode; - int rc; + int val; - rc = prop_exists(handles, "debug", &new_debug_mode); - if (rc != 0) - return (rc); + if (item < 0 || item > IDMAPD_DEBUG_MAX) + return; - if (_idmapdstate.debug_mode != new_debug_mode) { - if (!_idmapdstate.debug_mode) { - _idmapdstate.debug_mode = new_debug_mode; - idmap_log_stderr(LOG_DEBUG); - idmapdlog(LOG_DEBUG, "debug mode enabled"); - } else { - idmapdlog(LOG_DEBUG, "debug mode disabled"); - idmap_log_stderr(-1); - _idmapdstate.debug_mode = new_debug_mode; - } - } + val = get_debug(handles, name); - return (0); + if (val != _idmapdstate.debug[item]) + idmapdlog(LOG_DEBUG, "%s/%s = %d", DEBUG_PG, name, val); + + _idmapdstate.debug[item] = val; +} + +static +void +check_smf_debug_mode(idmap_cfg_handles_t *handles) +{ + idmapd_set_debug(handles, IDMAPD_DEBUG_ALL, "all"); + idmapd_set_debug(handles, IDMAPD_DEBUG_CONFIG, "config"); + idmapd_set_debug(handles, IDMAPD_DEBUG_MAPPING, "mapping"); + idmapd_set_debug(handles, IDMAPD_DEBUG_DISC, "discovery"); + idmapd_set_debug(handles, IDMAPD_DEBUG_DNS, "dns"); + idmapd_set_debug(handles, IDMAPD_DEBUG_LDAP, "ldap"); + + adutils_set_debug(AD_DEBUG_ALL, _idmapdstate.debug[IDMAPD_DEBUG_ALL]); + adutils_set_debug(AD_DEBUG_DISC, _idmapdstate.debug[IDMAPD_DEBUG_DISC]); + adutils_set_debug(AD_DEBUG_DNS, _idmapdstate.debug[IDMAPD_DEBUG_DNS]); + adutils_set_debug(AD_DEBUG_LDAP, _idmapdstate.debug[IDMAPD_DEBUG_LDAP]); } /* @@ -1206,18 +1416,26 @@ idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg, return (-2); } - if (scf_pg_update(handles->general_pg) < 0) { + if (scf_pg_update(handles->debug_pg) < 0) { idmapdlog(LOG_ERR, "scf_pg_update() failed: %s", scf_strerror(scf_error())); return (-2); } - rc = check_smf_debug_mode(handles); + check_smf_debug_mode(handles); + + rc = get_val_bool(handles, "unresolvable_sid_mapping", + &pgcfg->eph_map_unres_sids, B_TRUE); if (rc != 0) (*errors)++; - rc = get_val_int(handles, "unresolvable_sid_mapping", - &pgcfg->eph_map_unres_sids, SCF_TYPE_BOOLEAN); + rc = get_val_bool(handles, "use_lsa", + &pgcfg->use_lsa, B_TRUE); + if (rc != 0) + (*errors)++; + + rc = get_val_bool(handles, "disable_cross_forest_trusts", + &pgcfg->disable_cross_forest_trusts, B_TRUE); if (rc != 0) (*errors)++; @@ -1249,6 +1467,11 @@ idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg, if (rc != 0) (*errors)++; else { + if (pgcfg->domain_name != NULL && + pgcfg->domain_name[0] == '\0') { + free(pgcfg->domain_name); + pgcfg->domain_name = NULL; + } (void) ad_disc_set_DomainName(handles->ad_ctx, pgcfg->domain_name); pgcfg->domain_name_auto_disc = B_FALSE; @@ -1276,8 +1499,8 @@ idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg, /* If machine_sid not configured, generate one */ if (generate_machine_sid(&pgcfg->machine_sid) < 0) return (-2); - rc = set_val_astring(handles, "machine_sid", - pgcfg->machine_sid); + rc = set_val_astring(handles, handles->config_pg, + "machine_sid", pgcfg->machine_sid); if (rc != 0) (*errors)++; } @@ -1368,19 +1591,19 @@ idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg, } +static +void +log_if_unable(const void *val, const char *what) +{ + if (val == NULL) { + idmapdlog(LOG_DEBUG, "unable to discover %s", what); + } +} -/* - * This is the half of idmap_cfg_load() that auto-discovers values of - * discoverable properties that weren't already set via SMF properties. - * - * idmap_cfg_discover() is called *after* idmap_cfg_load_smf(), so it - * needs to be careful not to overwrite any properties set in SMF. - */ static void -idmap_cfg_discover(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg) +discover_trusted_domains(idmap_pg_config_t *pgcfg, ad_disc_t ad_ctx) { - ad_disc_t ad_ctx = handles->ad_ctx; ad_disc_t trusted_ctx; int i, j, k, l; char *forestname; @@ -1391,39 +1614,6 @@ 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) - pgcfg->default_domain = ad_disc_get_DomainName(ad_ctx, - NULL); - - if (pgcfg->domain_name == NULL) - pgcfg->domain_name = ad_disc_get_DomainName(ad_ctx, - &pgcfg->domain_name_auto_disc); - - if (pgcfg->domain_controller == NULL) - pgcfg->domain_controller = - ad_disc_get_DomainController(ad_ctx, AD_DISC_PREFER_SITE, - &pgcfg->domain_controller_auto_disc); - - if (pgcfg->forest_name == NULL) - pgcfg->forest_name = ad_disc_get_ForestName(ad_ctx, - &pgcfg->forest_name_auto_disc); - - if (pgcfg->site_name == NULL) - pgcfg->site_name = ad_disc_get_SiteName(ad_ctx, - &pgcfg->site_name_auto_disc); - - if (pgcfg->global_catalog == NULL) - pgcfg->global_catalog = - ad_disc_get_GlobalCatalog(ad_ctx, AD_DISC_PREFER_SITE, - &pgcfg->global_catalog_auto_disc); - - pgcfg->domains_in_forest = - ad_disc_get_DomainsInForest(ad_ctx, NULL); - pgcfg->trusted_domains = ad_disc_get_TrustedDomains(ad_ctx, NULL); @@ -1444,14 +1634,17 @@ idmap_cfg_discover(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg) for (i = 0; pgcfg->trusted_domains[i].domain[0] != '\0'; i++) { trusteddomain = pgcfg->trusted_domains[i].domain; trusted_ctx = ad_disc_init(); - ad_disc_set_DomainName(trusted_ctx, + (void) ad_disc_set_DomainName(trusted_ctx, trusteddomain); forestname = ad_disc_get_ForestName(trusted_ctx, NULL); if (forestname == NULL) { - idmapdlog(LOG_DEBUG, "unable to discover " - "Forest Name for the trusted domain %s", - trusteddomain); + if (DBG(CONFIG, 1)) { + idmapdlog(LOG_DEBUG, + "unable to discover Forest Name" + " for the trusted domain %s", + trusteddomain); + } ad_disc_fini(trusted_ctx); continue; } @@ -1501,10 +1694,12 @@ idmap_cfg_discover(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg) ad_disc_get_GlobalCatalog(trusted_ctx, AD_DISC_PREFER_SITE, NULL); if (globalcatalog == NULL) { - idmapdlog(LOG_DEBUG, - "unable to discover Global " - "Catalog for the trusted domain %s", - trusteddomain); + if (DBG(CONFIG, 1)) { + idmapdlog(LOG_DEBUG, + "unable to discover Global Catalog" + " for the trusted domain %s", + trusteddomain); + } free(forestname); ad_disc_fini(trusted_ctx); continue; @@ -1513,10 +1708,12 @@ idmap_cfg_discover(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg) ad_disc_get_DomainsInForest(trusted_ctx, NULL); if (domainsinforest == NULL) { - idmapdlog(LOG_DEBUG, - "unable to discover Domains in the Forest " - "for the trusted domain %s", - trusteddomain); + if (DBG(CONFIG, 1)) { + idmapdlog(LOG_DEBUG, + "unable to discover Domains in the" + " Forest for the trusted domain %s", + trusteddomain); + } free(globalcatalog); free(forestname); ad_disc_fini(trusted_ctx); @@ -1545,25 +1742,75 @@ idmap_cfg_discover(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg) free(trustedforests); } } +} - if (pgcfg->domain_name == NULL) - idmapdlog(LOG_DEBUG, "unable to discover Domain Name"); - if (pgcfg->domain_controller == NULL) - idmapdlog(LOG_DEBUG, "unable to discover Domain Controller"); - if (pgcfg->forest_name == NULL) - idmapdlog(LOG_DEBUG, "unable to discover Forest Name"); - if (pgcfg->site_name == NULL) - idmapdlog(LOG_DEBUG, "unable to discover Site Name"); - if (pgcfg->global_catalog == NULL) - idmapdlog(LOG_DEBUG, "unable to discover Global Catalog"); - if (pgcfg->domains_in_forest == NULL) - idmapdlog(LOG_DEBUG, - "unable to discover Domains in the Forest"); - if (pgcfg->trusted_domains == NULL) - idmapdlog(LOG_DEBUG, "unable to discover Trusted Domains"); +/* + * This is the half of idmap_cfg_load() that auto-discovers values of + * discoverable properties that weren't already set via SMF properties. + * + * idmap_cfg_discover() is called *after* idmap_cfg_load_smf(), so it + * needs to be careful not to overwrite any properties set in SMF. + */ +static +void +idmap_cfg_discover(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg) +{ + ad_disc_t ad_ctx = handles->ad_ctx; + + if (DBG(CONFIG, 1)) + idmapdlog(LOG_DEBUG, "Running discovery."); + + ad_disc_refresh(ad_ctx); + + if (pgcfg->domain_name == NULL) { + idmapdlog(LOG_DEBUG, "No domain name specified."); + } else { + if (pgcfg->domain_controller == NULL) + pgcfg->domain_controller = + ad_disc_get_DomainController(ad_ctx, + AD_DISC_PREFER_SITE, + &pgcfg->domain_controller_auto_disc); + + if (pgcfg->forest_name == NULL) + pgcfg->forest_name = ad_disc_get_ForestName(ad_ctx, + &pgcfg->forest_name_auto_disc); + + if (pgcfg->site_name == NULL) + pgcfg->site_name = ad_disc_get_SiteName(ad_ctx, + &pgcfg->site_name_auto_disc); + + if (pgcfg->global_catalog == NULL) + pgcfg->global_catalog = + ad_disc_get_GlobalCatalog(ad_ctx, + AD_DISC_PREFER_SITE, + &pgcfg->global_catalog_auto_disc); + + pgcfg->domains_in_forest = + ad_disc_get_DomainsInForest(ad_ctx, NULL); + + if (!pgcfg->disable_cross_forest_trusts) + discover_trusted_domains(pgcfg, ad_ctx); + + if (DBG(CONFIG, 1)) { + log_if_unable(pgcfg->domain_name, "Domain Name"); + log_if_unable(pgcfg->domain_controller, + "Domain Controller"); + log_if_unable(pgcfg->forest_name, "Forest Name"); + log_if_unable(pgcfg->site_name, "Site Name"); + log_if_unable(pgcfg->global_catalog, "Global Catalog"); + log_if_unable(pgcfg->domains_in_forest, + "Domains in the Forest"); + if (!pgcfg->disable_cross_forest_trusts) { + log_if_unable(pgcfg->trusted_domains, + "Trusted Domains"); + } + } + } ad_disc_done(ad_ctx); - idmapdlog(LOG_DEBUG, "Discovery done."); + + if (DBG(CONFIG, 1)) + idmapdlog(LOG_DEBUG, "Discovery done."); } @@ -1574,18 +1821,16 @@ idmap_cfg_discover(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg) * reads from SMF, but you still have to refresh the service after * changing the config pg in order for the changes to take effect. * - * There are two flags: + * There is one flag: * * - CFG_DISCOVER - * - CFG_LOG * * If CFG_DISCOVER is set then idmap_cfg_load() calls * idmap_cfg_discover() to discover, via DNS and LDAP lookups, property * values that weren't set in SMF. * - * If CFG_LOG is set then idmap_cfg_load() will log (to LOG_NOTICE) - * whether the configuration changed. This should be used only from the - * refresh method. + * idmap_cfg_load() will log (to LOG_NOTICE) whether the configuration + * changed. * * Return values: 0 -> success, -1 -> failure, -2 -> hard failures * reading from SMF. @@ -1599,10 +1844,13 @@ idmap_cfg_load(idmap_cfg_t *cfg, int flags) int ad_reload_required = 0; idmap_pg_config_t new_pgcfg, *live_pgcfg; + if (DBG(CONFIG, 1)) + idmapdlog(LOG_DEBUG, "Loading configuration."); + live_pgcfg = &cfg->pgcfg; (void) memset(&new_pgcfg, 0, sizeof (new_pgcfg)); - pthread_mutex_lock(&cfg->handles.mutex); + (void) pthread_mutex_lock(&cfg->handles.mutex); if ((rc = idmap_cfg_load_smf(&cfg->handles, &new_pgcfg, &errors)) < -1) goto err; @@ -1612,8 +1860,10 @@ idmap_cfg_load(idmap_cfg_t *cfg, int flags) WRLOCK_CONFIG(); if (live_pgcfg->list_size_limit != new_pgcfg.list_size_limit) { - idmapdlog(LOG_INFO, "change list_size=%d", - new_pgcfg.list_size_limit); + if (DBG(CONFIG, 1)) { + idmapdlog(LOG_INFO, "change list_size=%d", + new_pgcfg.list_size_limit); + } live_pgcfg->list_size_limit = new_pgcfg.list_size_limit; } @@ -1624,6 +1874,13 @@ idmap_cfg_load(idmap_cfg_t *cfg, int flags) changed += update_bool(&live_pgcfg->eph_map_unres_sids, &new_pgcfg.eph_map_unres_sids, "unresolvable_sid_mapping"); + changed += update_bool(&live_pgcfg->use_lsa, + &new_pgcfg.use_lsa, "use_lsa"); + + changed += update_bool(&live_pgcfg->disable_cross_forest_trusts, + &new_pgcfg.disable_cross_forest_trusts, + "disable_cross_forest_trusts"); + changed += update_enum(&live_pgcfg->directory_based_mapping, &new_pgcfg.directory_based_mapping, "directory_based_mapping", directory_mapping_map); @@ -1695,20 +1952,17 @@ idmap_cfg_load(idmap_cfg_t *cfg, int flags) idmap_cfg_unload(&new_pgcfg); - if (flags & CFG_LOG) { - /* - * If the config changes as a result of a refresh of the - * service, then logging about it can provide useful - * feedback to the sysadmin. - */ - idmapdlog(LOG_NOTICE, "Configuration %schanged", - changed ? "" : "un"); + if (DBG(CONFIG, 1)) { + if (changed) + idmapdlog(LOG_NOTICE, "Configuration changed"); + else + idmapdlog(LOG_NOTICE, "Configuration unchanged"); } UNLOCK_CONFIG(); err: - pthread_mutex_unlock(&cfg->handles.mutex); + (void) pthread_mutex_unlock(&cfg->handles.mutex); if (rc < -1) return (rc); @@ -1749,7 +2003,7 @@ idmap_cfg_init() if (!(handles->service = scf_service_create(handles->main)) || !(handles->instance = scf_instance_create(handles->main)) || !(handles->config_pg = scf_pg_create(handles->main)) || - !(handles->general_pg = scf_pg_create(handles->main))) { + !(handles->debug_pg = scf_pg_create(handles->main))) { idmapdlog(LOG_ERR, "scf handle creation failed: %s", scf_strerror(scf_error())); goto error; @@ -1769,14 +2023,13 @@ idmap_cfg_init() } if (scf_service_get_pg(handles->service, - GENERAL_PG, handles->general_pg) < 0) { - idmapdlog(LOG_ERR, "scf_service_get_pg() failed: %s", - scf_strerror(scf_error())); + DEBUG_PG, handles->debug_pg) < 0) { + idmapdlog(LOG_ERR, "Property group \"%s\": %s", + DEBUG_PG, scf_strerror(scf_error())); goto error; } - if (check_smf_debug_mode(handles) != 0) - goto error; + check_smf_debug_mode(handles); /* Initialize AD Auto Discovery context */ handles->ad_ctx = ad_disc_init(); @@ -1852,7 +2105,8 @@ idmap_cfg_fini(idmap_cfg_t *cfg) (void) pthread_mutex_destroy(&handles->mutex); scf_pg_destroy(handles->config_pg); - scf_pg_destroy(handles->general_pg); + if (handles->debug_pg != NULL) + scf_pg_destroy(handles->debug_pg); scf_instance_destroy(handles->instance); scf_service_destroy(handles->service); scf_handle_destroy(handles->main); @@ -1879,6 +2133,47 @@ idmap_cfg_hup_handler(int sig) } /* + * Upgrade the debug flags. + * + * We're replacing a single debug flag with a fine-grained mechanism that + * is also capable of considerably more verbosity. We'll take a stab at + * producing roughly the same level of output. + */ +static +int +upgrade_debug(idmap_cfg_handles_t *handles) +{ + boolean_t debug_present; + const char DEBUG_PROP[] = "debug"; + int rc; + + rc = prop_exists(handles, DEBUG_PROP, &debug_present); + + if (rc != 0) + return (rc); + + if (!debug_present) + return (0); + + idmapdlog(LOG_INFO, + "Upgrading old %s/%s setting to %s/* settings.", + CONFIG_PG, DEBUG_PROP, DEBUG_PG); + + rc = set_val_integer(handles, handles->debug_pg, "config", 1); + if (rc != 0) + return (rc); + rc = set_val_integer(handles, handles->debug_pg, "discovery", 1); + if (rc != 0) + return (rc); + + rc = del_val(handles, handles->config_pg, DEBUG_PROP); + if (rc != 0) + return (rc); + + return (0); +} + +/* * Upgrade the DS mapping flags. * * If the old ds_name_mapping_enabled flag is present, then @@ -1908,8 +2203,8 @@ upgrade_directory_mapping(idmap_cfg_handles_t *handles) return (0); boolean_t legacy_ds_name_mapping_enabled; - rc = get_val_int(handles, DS_NAME_MAPPING_ENABLED, - &legacy_ds_name_mapping_enabled, SCF_TYPE_BOOLEAN); + rc = get_val_bool(handles, DS_NAME_MAPPING_ENABLED, + &legacy_ds_name_mapping_enabled, B_FALSE); if (rc != 0) return (rc); @@ -1935,8 +2230,8 @@ upgrade_directory_mapping(idmap_cfg_handles_t *handles) "to %s=%s.", DS_NAME_MAPPING_ENABLED, legacy_bool_string, DIRECTORY_BASED_MAPPING, legacy_mode); - rc = set_val_astring(handles, DIRECTORY_BASED_MAPPING, - legacy_mode); + rc = set_val_astring(handles, handles->config_pg, + DIRECTORY_BASED_MAPPING, legacy_mode); if (rc != 0) return (rc); } else { @@ -1962,7 +2257,7 @@ upgrade_directory_mapping(idmap_cfg_handles_t *handles) free(directory_based_mapping); } - rc = del_val(handles, DS_NAME_MAPPING_ENABLED); + rc = del_val(handles, handles->config_pg, DS_NAME_MAPPING_ENABLED); if (rc != 0) return (rc); @@ -1982,5 +2277,9 @@ idmap_cfg_upgrade(idmap_cfg_t *cfg) if (rc != 0) return (rc); + rc = upgrade_debug(&cfg->handles); + if (rc != 0) + return (rc); + return (0); } diff --git a/usr/src/cmd/idmap/idmapd/idmap_config.h b/usr/src/cmd/idmap/idmapd/idmap_config.h index bdee366906..eb1c7ffb69 100644 --- a/usr/src/cmd/idmap/idmapd/idmap_config.h +++ b/usr/src/cmd/idmap/idmapd/idmap_config.h @@ -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. */ #ifndef _IDMAP_CONFIG_H @@ -57,7 +56,7 @@ typedef struct idmap_cfg_handles { scf_instance_t *instance; scf_service_t *service; scf_propertygroup_t *config_pg; - scf_propertygroup_t *general_pg; + scf_propertygroup_t *debug_pg; ad_disc_t ad_ctx; } idmap_cfg_handles_t; @@ -106,6 +105,8 @@ typedef struct idmap_pg_config { char *nldap_winname_attr; int directory_based_mapping; /* enum */ boolean_t eph_map_unres_sids; + boolean_t use_lsa; + boolean_t disable_cross_forest_trusts; } idmap_pg_config_t; typedef struct idmap_cfg { diff --git a/usr/src/cmd/idmap/idmapd/idmap_lsa.c b/usr/src/cmd/idmap/idmapd/idmap_lsa.c new file mode 100644 index 0000000000..256e8494d8 --- /dev/null +++ b/usr/src/cmd/idmap/idmapd/idmap_lsa.c @@ -0,0 +1,237 @@ +/* + * 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. + */ + +/* + * LSA lookups + */ + +#include <stdio.h> +#include <note.h> +#include <assert.h> + +#include "idmapd.h" +#include "libsmb.h" + +idmap_retcode +idmap_lsa_xlate_sid_type(const lsa_account_t *acct, idmap_id_type *ret_type) +{ + switch (acct->a_sidtype) { + case SidTypeUser: + case SidTypeComputer: + case SidTypeDomain: + case SidTypeDeletedAccount: + case SidTypeUnknown: + case SidTypeLabel: + *ret_type = IDMAP_USID; + return (IDMAP_SUCCESS); + case SidTypeGroup: + case SidTypeAlias: + case SidTypeWellKnownGroup: + *ret_type = IDMAP_GSID; + return (IDMAP_SUCCESS); + case SidTypeNull: + case SidTypeInvalid: + default: + idmapdlog(LOG_WARNING, + "LSA lookup: bad type %d for %s@%s", + acct->a_sidtype, acct->a_name, acct->a_domain); + return (IDMAP_ERR_OTHER); + } + NOTE(NOTREACHED) +} + +/* Given SID, look up name and type */ +idmap_retcode +lookup_lsa_by_sid( + const char *sidprefix, + uint32_t rid, + char **ret_name, + char **ret_domain, + idmap_id_type *ret_type) +{ + lsa_account_t acct; + char sid[SMB_SID_STRSZ + 1]; + idmap_retcode ret; + int rc; + + (void) memset(&acct, 0, sizeof (acct)); + *ret_name = NULL; + *ret_domain = NULL; + + (void) snprintf(sid, sizeof (sid), "%s-%u", sidprefix, rid); + + rc = smb_lookup_sid(sid, &acct); + if (rc != 0) { + idmapdlog(LOG_ERR, "Error: smb_lookup_sid failed."); + idmapdlog(LOG_ERR, + "Check SMB service (svc:/network/smb/server)."); + idmapdlog(LOG_ERR, + "Check connectivity to Active Directory."); + + ret = IDMAP_ERR_OTHER; + goto out; + } + if (acct.a_status == NT_STATUS_NONE_MAPPED) { + ret = IDMAP_ERR_NOTFOUND; + goto out; + } + if (acct.a_status != NT_STATUS_SUCCESS) { + idmapdlog(LOG_WARNING, + "Warning: smb_lookup_sid(%s) failed (0x%x)", + sid, acct.a_status); + /* Fail soft */ + ret = IDMAP_ERR_NOTFOUND; + goto out; + } + + ret = idmap_lsa_xlate_sid_type(&acct, ret_type); + if (ret != IDMAP_SUCCESS) + goto out; + + *ret_name = strdup(acct.a_name); + if (*ret_name == NULL) { + ret = IDMAP_ERR_MEMORY; + goto out; + } + + *ret_domain = strdup(acct.a_domain); + if (*ret_domain == NULL) { + ret = IDMAP_ERR_MEMORY; + goto out; + } + + ret = IDMAP_SUCCESS; + +out: + if (ret != IDMAP_SUCCESS) { + free(*ret_name); + *ret_name = NULL; + free(*ret_domain); + *ret_domain = NULL; + } + return (ret); +} + +/* Given name and optional domain, look up SID, type, and canonical name */ +idmap_retcode +lookup_lsa_by_name( + const char *name, + const char *domain, + char **ret_sidprefix, + uint32_t *ret_rid, + char **ret_name, + char **ret_domain, + idmap_id_type *ret_type) +{ + lsa_account_t acct; + char *namedom = NULL; + idmap_retcode ret; + int rc; + + (void) memset(&acct, 0, sizeof (acct)); + *ret_sidprefix = NULL; + if (ret_name != NULL) + *ret_name = NULL; + if (ret_domain != NULL) + *ret_domain = NULL; + + if (domain != NULL) + (void) asprintf(&namedom, "%s@%s", name, domain); + else + namedom = strdup(name); + if (namedom == NULL) { + ret = IDMAP_ERR_MEMORY; + goto out; + } + + rc = smb_lookup_name(namedom, SidTypeUnknown, &acct); + if (rc != 0) { + idmapdlog(LOG_ERR, "Error: smb_lookup_name failed."); + idmapdlog(LOG_ERR, + "Check SMB service (svc:/network/smb/server)."); + idmapdlog(LOG_ERR, + "Check connectivity to Active Directory."); + ret = IDMAP_ERR_OTHER; + goto out; + } + if (acct.a_status == NT_STATUS_NONE_MAPPED) { + ret = IDMAP_ERR_NOTFOUND; + goto out; + } + if (acct.a_status != NT_STATUS_SUCCESS) { + idmapdlog(LOG_WARNING, + "Warning: smb_lookup_name(%s) failed (0x%x)", + namedom, acct.a_status); + /* Fail soft */ + ret = IDMAP_ERR_NOTFOUND; + goto out; + } + + rc = smb_sid_splitstr(acct.a_sid, ret_rid); + assert(rc == 0); + *ret_sidprefix = strdup(acct.a_sid); + if (*ret_sidprefix == NULL) { + ret = IDMAP_ERR_MEMORY; + goto out; + } + + ret = idmap_lsa_xlate_sid_type(&acct, ret_type); + if (ret != IDMAP_SUCCESS) + goto out; + + if (ret_name != NULL) { + *ret_name = strdup(acct.a_name); + if (*ret_name == NULL) { + ret = IDMAP_ERR_MEMORY; + goto out; + } + } + + if (ret_domain != NULL) { + *ret_domain = strdup(acct.a_domain); + if (*ret_domain == NULL) { + ret = IDMAP_ERR_MEMORY; + goto out; + } + } + + ret = IDMAP_SUCCESS; + +out: + free(namedom); + if (ret != IDMAP_SUCCESS) { + if (ret_name != NULL) { + free(*ret_name); + *ret_name = NULL; + } + if (ret_domain != NULL) { + free(*ret_domain); + *ret_domain = NULL; + } + free(*ret_sidprefix); + *ret_sidprefix = NULL; + } + return (ret); +} diff --git a/usr/src/cmd/idmap/idmapd/idmap_lsa.h b/usr/src/cmd/idmap/idmapd/idmap_lsa.h new file mode 100644 index 0000000000..5dae07a6ab --- /dev/null +++ b/usr/src/cmd/idmap/idmapd/idmap_lsa.h @@ -0,0 +1,53 @@ +/* + * 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. + */ + +#ifndef IDMAP_LSA_H +#define IDMAP_LSA_H + +/* + * LSA lookups + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <rpcsvc/idmap_prot.h> + +/* Given SID, look up name and type */ +idmap_retcode +lookup_lsa_by_sid(const char *sidprefix, uint32_t rid, char **ret_name, + char **ret_domain, idmap_id_type *ret_type); + +/* Given name and optional domain, look up SID, type, and canonical name */ +idmap_retcode lookup_lsa_by_name(const char *name, const char *domain, + char **ret_sidprefix, uint32_t *ret_rid, char **ret_name, + char **ret_domain, idmap_id_type *ret_type); + +#ifdef __cplusplus +} +#endif + +#endif /* IDMAP_LSA_H */ diff --git a/usr/src/cmd/idmap/idmapd/idmapd.c b/usr/src/cmd/idmap/idmapd/idmapd.c index 5ea3292acd..828bfc6545 100644 --- a/usr/src/cmd/idmap/idmapd/idmapd.c +++ b/usr/src/cmd/idmap/idmapd/idmapd.c @@ -53,6 +53,9 @@ #include <sys/sid.h> #include <sys/idmap.h> #include <pthread.h> +#include <stdarg.h> +#include <assert.h> +#include <note.h> static void term_handler(int); static void init_idmapd(); @@ -63,31 +66,13 @@ idmapd_state_t _idmapdstate; SVCXPRT *xprt = NULL; static int dfd = -1; /* our door server fildes, for unregistration */ -static int degraded = 0; /* whether the FMRI has been marked degraded */ +static boolean_t degraded = B_FALSE; static uint32_t num_threads = 0; static pthread_key_t create_threads_key; static uint32_t max_threads = 40; - -/* - * The following structure determines where the log messages from idmapdlog() - * go to. It can be stderr (idmapd -d) and/or the real idmapdlog (idmapd). - * - * logstate.max_pri is integer cutoff necessary to silence low-priority - * messages to stderr. idmapdlog has its own means so there a boolean - * logstate.write_idmapdlog is enough. - * - * logstate.degraded is a mode used by idmapd in its degraded state. - */ - -static struct { - boolean_t write_syslog; - int max_pri; /* Max priority written to stderr */ - boolean_t degraded; -} logstate = {B_FALSE, LOG_DEBUG, B_FALSE}; - /* * Server door thread start routine. * @@ -193,16 +178,8 @@ term_handler(int sig) static void usr1_handler(int sig) { - boolean_t saved_debug_mode = _idmapdstate.debug_mode; - - _idmapdstate.debug_mode = B_TRUE; - idmap_log_stderr(LOG_DEBUG); - + NOTE(ARGUNUSED(sig)) print_idmapdstate(); - - _idmapdstate.debug_mode = saved_debug_mode; - idmap_log_stderr(_idmapdstate.daemon_mode ? -1 : LOG_DEBUG); - } static int pipe_fd = -1; @@ -274,7 +251,6 @@ main(int argc, char **argv) struct rlimit rl; _idmapdstate.daemon_mode = TRUE; - _idmapdstate.debug_mode = FALSE; while ((c = getopt(argc, argv, "d")) != -1) { switch (c) { case 'd': @@ -293,8 +269,6 @@ main(int argc, char **argv) idmap_set_logger(idmapdlog); adutils_set_logger(idmapdlog); - idmap_log_syslog(B_TRUE); - idmap_log_stderr(_idmapdstate.daemon_mode ? -1 : LOG_DEBUG); if (is_system_labeled() && getzoneid() != GLOBAL_ZONEID) { idmapdlog(LOG_ERR, @@ -373,7 +347,7 @@ init_idmapd() * one. */ (void) unlink(IDMAP_CACHEDIR "/ccache"); - putenv("KRB5CCNAME=" IDMAP_CACHEDIR "/ccache"); + (void) putenv("KRB5CCNAME=" IDMAP_CACHEDIR "/ccache"); if (sysinfo(SI_HOSTNAME, _idmapdstate.hostname, sizeof (_idmapdstate.hostname)) == -1) { @@ -433,7 +407,8 @@ init_idmapd() _idmapdstate.limit_gid = _idmapdstate.next_gid + 8192; } - print_idmapdstate(); + if (DBG(CONFIG, 1)) + print_idmapdstate(); return; @@ -445,7 +420,7 @@ errout: static void fini_idmapd() { - __idmap_unreg(dfd); + (void) __idmap_unreg(dfd); fini_mapping_system(); if (xprt != NULL) svc_destroy(xprt); @@ -492,13 +467,10 @@ degrade_svc(int poke_discovery, const char *reason) if (degraded) return; - idmapdlog(LOG_ERR, "Degraded operation (%s). If you are running an " - "SMB server in workgroup mode, or if you're not running an SMB " - "server, then you can ignore this message", reason); + idmapdlog(LOG_ERR, "Degraded operation (%s).", reason); membar_producer(); - degraded = 1; - idmap_log_degraded(B_TRUE); + degraded = B_TRUE; if ((fmri = get_fmri()) != NULL) (void) smf_degrade_instance(fmri, 0); @@ -524,8 +496,7 @@ restore_svc(void) (void) smf_restore_instance(fmri); membar_producer(); - degraded = 0; - idmap_log_degraded(B_FALSE); + degraded = B_FALSE; idmapdlog(LOG_NOTICE, "Normal operation restored"); } @@ -536,41 +507,152 @@ void idmapdlog(int pri, const char *format, ...) { va_list args; - if (pri <= logstate.max_pri) { - va_start(args, format); - (void) vfprintf(stderr, format, args); - (void) fprintf(stderr, "\n"); - va_end(args); - } + va_start(args, format); + (void) vfprintf(stderr, format, args); + (void) fprintf(stderr, "\n"); + va_end(args); /* * We don't want to fill up the logs with useless messages when * we're degraded, but we still want to log. */ - if (logstate.degraded) + if (degraded) pri = LOG_DEBUG; - if (logstate.write_syslog) { - va_start(args, format); - vsyslog(pri, format, args); - va_end(args); - } + va_start(args, format); + vsyslog(pri, format, args); + va_end(args); } -void -idmap_log_stderr(int pri) +static void +trace_str(nvlist_t *entry, char *n1, char *n2, char *str) { - logstate.max_pri = pri; + char name[IDMAP_TRACE_NAME_MAX+1]; /* Max used is only about 11 */ + + (void) strlcpy(name, n1, sizeof (name)); + if (n2 != NULL) + (void) strlcat(name, n2, sizeof (name)); + + (void) nvlist_add_string(entry, name, str); } -void -idmap_log_syslog(boolean_t what) +static void +trace_int(nvlist_t *entry, char *n1, char *n2, int64_t i) { - logstate.write_syslog = what; + char name[IDMAP_TRACE_NAME_MAX+1]; /* Max used is only about 11 */ + + (void) strlcpy(name, n1, sizeof (name)); + if (n2 != NULL) + (void) strlcat(name, n2, sizeof (name)); + + (void) nvlist_add_int64(entry, name, i); } -void -idmap_log_degraded(boolean_t what) +static void +trace_sid(nvlist_t *entry, char *n1, char *n2, idmap_sid *sid) +{ + char *str; + + (void) asprintf(&str, "%s-%u", sid->prefix, sid->rid); + if (str == NULL) + return; + + trace_str(entry, n1, n2, str); + free(str); +} + +static void +trace_id(nvlist_t *entry, char *fromto, idmap_id *id, char *name, char *domain) +{ + trace_int(entry, fromto, IDMAP_TRACE_TYPE, (int64_t)id->idtype); + if (IS_ID_SID(*id)) { + if (name != NULL) { + char *str; + + (void) asprintf(&str, "%s%s%s", name, + domain == NULL ? "" : "@", + domain == NULL ? "" : domain); + if (str != NULL) { + trace_str(entry, fromto, IDMAP_TRACE_NAME, str); + free(str); + } + } + if (id->idmap_id_u.sid.prefix != NULL) { + trace_sid(entry, fromto, IDMAP_TRACE_SID, + &id->idmap_id_u.sid); + } + } else if (IS_ID_POSIX(*id)) { + if (name != NULL) + trace_str(entry, fromto, IDMAP_TRACE_NAME, name); + if (id->idmap_id_u.uid != IDMAP_SENTINEL_PID) { + trace_int(entry, fromto, IDMAP_TRACE_UNIXID, + (int64_t)id->idmap_id_u.uid); + } + } +} + +/* + * Record a trace event. TRACE() has already decided whether or not + * tracing is required; what we do here is collect the data and send it + * to its destination - to the trace log in the response, if + * IDMAP_REQ_FLG_TRACE is set, and to the SMF service log, if debug/mapping + * is greater than zero. + */ +int +trace(idmap_mapping *req, idmap_id_res *res, char *fmt, ...) { - logstate.degraded = what; + va_list va; + char *buf; + int err; + nvlist_t *entry; + + assert(req != NULL); + assert(res != NULL); + + err = nvlist_alloc(&entry, NV_UNIQUE_NAME, 0); + if (err != 0) { + (void) fprintf(stderr, "trace nvlist_alloc(entry): %s\n", + strerror(err)); + return (0); + } + + trace_id(entry, "from", &req->id1, req->id1name, req->id1domain); + trace_id(entry, "to", &res->id, req->id2name, req->id2domain); + + if (IDMAP_ERROR(res->retcode)) { + trace_int(entry, IDMAP_TRACE_ERROR, NULL, + (int64_t)res->retcode); + } + + va_start(va, fmt); + (void) vasprintf(&buf, fmt, va); + va_end(va); + if (buf != NULL) { + trace_str(entry, IDMAP_TRACE_MESSAGE, NULL, buf); + free(buf); + } + + if (DBG(MAPPING, 1)) + idmap_trace_print_1(stderr, "", entry); + + if (req->flag & IDMAP_REQ_FLG_TRACE) { + /* Lazily allocate the trace list */ + if (res->info.trace == NULL) { + err = nvlist_alloc(&res->info.trace, 0, 0); + if (err != 0) { + res->info.trace = NULL; /* just in case */ + (void) fprintf(stderr, + "trace nvlist_alloc(trace): %s\n", + strerror(err)); + nvlist_free(entry); + return (0); + } + } + (void) nvlist_add_nvlist(res->info.trace, "", entry); + /* Note that entry is copied, so we must still free our copy */ + } + + nvlist_free(entry); + + return (0); } diff --git a/usr/src/cmd/idmap/idmapd/idmapd.h b/usr/src/cmd/idmap/idmapd/idmapd.h index fe62e0468b..4e59ee49ae 100644 --- a/usr/src/cmd/idmap/idmapd/idmapd.h +++ b/usr/src/cmd/idmap/idmapd/idmapd.h @@ -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. */ #ifndef _IDMAPD_H @@ -59,13 +58,41 @@ typedef enum idmap_namemap_mode { } idmap_namemap_mode_t; /* + * Debugging output. + * + * There are some number of areas - configuration, mapping, discovery, et + * cetera - and for each area there is a verbosity level controlled through + * an SMF property. The default is zero, and "debug/all" provides a master + * control allowing you to turn on all debugging output with one setting. + * + * A typical debugging output sequence would look like + * + * if (DBG(CONFIG, 2)) { + * idmapdlog(LOG_DEBUG, + * "some message about config at verbosity 2"); + * } + */ +enum idmapd_debug { + IDMAPD_DEBUG_ALL = 0, + IDMAPD_DEBUG_CONFIG = 1, + IDMAPD_DEBUG_MAPPING = 2, + IDMAPD_DEBUG_DISC = 3, + IDMAPD_DEBUG_DNS = 4, + IDMAPD_DEBUG_LDAP = 5, + IDMAPD_DEBUG_MAX = 5 +}; + +#define DBG(type, lev) \ + (_idmapdstate.debug[IDMAPD_DEBUG_##type] >= (lev) || \ + _idmapdstate.debug[IDMAPD_DEBUG_ALL] >= (lev)) + +/* * Global state of idmapd daemon. */ typedef struct idmapd_state { rwlock_t rwlk_cfg; /* config lock */ idmap_cfg_t *cfg; /* config */ bool_t daemon_mode; - bool_t debug_mode; char hostname[MAX_NAME_LEN]; /* my hostname */ uid_t next_uid; gid_t next_gid; @@ -76,6 +103,7 @@ typedef struct idmapd_state { adutils_ad_t **gcs; int num_dcs; adutils_ad_t **dcs; + int debug[IDMAPD_DEBUG_MAX+1]; } idmapd_state_t; extern idmapd_state_t _idmapdstate; @@ -207,30 +235,24 @@ typedef struct wksids_table { #define IDMAP_DBNAME IDMAP_DBDIR "/idmap.db" #define IDMAP_CACHENAME IDMAP_CACHEDIR "/idmap.db" -#define IS_BATCH_SID(batch, i) \ - (batch.idmap_mapping_batch_val[i].id1.idtype == IDMAP_SID || \ - batch.idmap_mapping_batch_val[i].id1.idtype == IDMAP_USID || \ - batch.idmap_mapping_batch_val[i].id1.idtype == IDMAP_GSID) - -#define IS_BATCH_UID(batch, i) \ - (batch.idmap_mapping_batch_val[i].id1.idtype == IDMAP_UID) - -#define IS_BATCH_GID(batch, i) \ - (batch.idmap_mapping_batch_val[i].id1.idtype == IDMAP_GID) +#define IS_ID_NONE(id) \ + ((id).idtype == IDMAP_NONE) #define IS_ID_SID(id) \ ((id).idtype == IDMAP_SID || \ (id).idtype == IDMAP_USID || \ (id).idtype == IDMAP_GSID) \ -#define IS_REQUEST_SID(req, n) IS_ID_SID((req).id##n) - +#define IS_ID_UID(id) \ + ((id).idtype == IDMAP_UID) -#define IS_REQUEST_UID(request) \ - ((request).id1.idtype == IDMAP_UID) +#define IS_ID_GID(id) \ + ((id).idtype == IDMAP_GID) -#define IS_REQUEST_GID(request) \ - ((request).id1.idtype == IDMAP_GID) +#define IS_ID_POSIX(id) \ + ((id).idtype == IDMAP_UID || \ + (id).idtype == IDMAP_GID || \ + (id).idtype == IDMAP_POSIXID) \ /* * Local RID ranges @@ -240,6 +262,32 @@ typedef struct wksids_table { #define LOCALRID_GID_MIN (((uint32_t)INT32_MAX) + 1) #define LOCALRID_GID_MAX UINT32_MAX +/* + * Tracing. + * + * The tracing mechanism is intended to help the administrator understand + * why their mapping configuration is doing what it is. Each interesting + * decision point during the mapping process calls TRACE() with the current + * request and response and a printf-style message. The message, plus + * data from the request and the response, is logged to the service log + * (if debug/mapping is greater than zero) or reported to the caller + * (if IDMAP_REQ_FLG_TRACE was set in the request. The primary consumer + * is the "-V" option to "idmap show". + * + * TRACING(req) says whether tracing is appropriate for the request, and + * is used to determine and record whether any request in a batch requested + * tracing, to control whether later code loops over the batch to do tracing + * for any of the requests. + * + * TRACE(req, res, fmt, ...) generates a trace entry if appropriate. + */ +#define TRACING(req) \ + (DBG(MAPPING, 1) || \ + ((req)->flag & IDMAP_REQ_FLG_TRACE) != 0) +#define TRACE(req, res, ...) \ + ((void)(TRACING(req) && trace(req, res, __VA_ARGS__))) +extern int trace(idmap_mapping *req, idmap_id_res *res, char *fmt, ...); + typedef idmap_retcode (*update_list_res_cb)(void *, const char **, uint64_t); typedef int (*list_svc_cb)(void *, int, char **, char **); @@ -251,7 +299,7 @@ extern void print_idmapdstate(); extern int create_directory(const char *, uid_t, gid_t); extern int load_config(); extern void reload_ad(); -extern int idmap_init_tsd_key(void); +extern void idmap_init_tsd_key(void); extern void degrade_svc(int, const char *); extern void restore_svc(void); @@ -294,22 +342,19 @@ extern void cleanup_lookup_state(lookup_state_t *); extern idmap_retcode ad_lookup_batch(lookup_state_t *, idmap_mapping_batch *, idmap_ids_res *); extern idmap_retcode lookup_name2sid(sqlite *, const char *, const char *, - int *, char **, char **, char **, - idmap_rid_t *, idmap_mapping *, int); + int, char **, char **, char **, + idmap_rid_t *, idmap_id_type *, + idmap_mapping *, int); extern idmap_retcode lookup_wksids_name2sid(const char *, const char *, char **, char **, char **, idmap_rid_t *, - int *); + idmap_id_type *); extern idmap_retcode idmap_cache_flush(idmap_flush_op); -extern void idmap_log_stderr(int); -extern void idmap_log_syslog(boolean_t); -extern void idmap_log_degraded(boolean_t); - extern const wksids_table_t *find_wksid_by_pid(posix_id_t pid, int is_user); extern const wksids_table_t *find_wksid_by_sid(const char *sid, int rid, - int type); + idmap_id_type type); extern const wksids_table_t *find_wksid_by_name(const char *name, - const char *domain, int type); + const char *domain, idmap_id_type type); extern const wksids_table_t *find_wk_by_sid(char *sid); #ifdef __cplusplus diff --git a/usr/src/cmd/idmap/idmapd/init.c b/usr/src/cmd/idmap/idmapd/init.c index c661ede558..43c18b6293 100644 --- a/usr/src/cmd/idmap/idmapd/init.c +++ b/usr/src/cmd/idmap/idmapd/init.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. */ /* @@ -100,7 +99,8 @@ load_config() return (rc); } - idmapdlog(LOG_DEBUG, "Initial configuration loaded"); + if (DBG(CONFIG, 1)) + idmapdlog(LOG_DEBUG, "Initial configuration loaded"); return (0); } @@ -111,14 +111,21 @@ reload_gcs() { int i, j; adutils_ad_t **new_gcs; - adutils_ad_t **old_gcs; + adutils_ad_t **old_gcs = _idmapdstate.gcs; int new_num_gcs; - int old_num_gcs; + int old_num_gcs = _idmapdstate.num_gcs; idmap_pg_config_t *pgcfg = &_idmapdstate.cfg->pgcfg; idmap_trustedforest_t *trustfor = pgcfg->trusted_forests; int num_trustfor = pgcfg->num_trusted_forests; ad_disc_domainsinforest_t *domain_in_forest; + if (pgcfg->domain_name == NULL) { + /* No domain name specified - workgroup mode. */ + new_gcs = NULL; + new_num_gcs = 0; + goto out; + } + if (pgcfg->global_catalog == NULL || pgcfg->global_catalog[0].host[0] == '\0') { /* @@ -132,9 +139,6 @@ reload_gcs() return; } - old_gcs = _idmapdstate.gcs; - old_num_gcs = _idmapdstate.num_gcs; - new_num_gcs = 1 + num_trustfor; new_gcs = calloc(new_num_gcs, sizeof (adutils_ad_t *)); if (new_gcs == NULL) { @@ -220,7 +224,6 @@ out: _idmapdstate.gcs = new_gcs; _idmapdstate.num_gcs = new_num_gcs; - if (old_gcs != NULL) { for (i = 0; i < old_num_gcs; i++) adutils_ad_free(&old_gcs[i]); @@ -240,11 +243,18 @@ reload_dcs(void) { int i; adutils_ad_t **new_dcs; - adutils_ad_t **old_dcs; + adutils_ad_t **old_dcs = _idmapdstate.dcs; int new_num_dcs; - int old_num_dcs; + int old_num_dcs = _idmapdstate.num_dcs; idmap_pg_config_t *pgcfg = &_idmapdstate.cfg->pgcfg; + if (pgcfg->domain_name == NULL) { + /* No domain name specified - workgroup mode. */ + new_dcs = NULL; + new_num_dcs = 0; + goto out; + } + if (pgcfg->domain_controller == NULL || pgcfg->domain_controller[0].host[0] == '\0') { /* @@ -258,9 +268,6 @@ reload_dcs(void) return; } - old_dcs = _idmapdstate.dcs; - old_num_dcs = _idmapdstate.num_dcs; - new_num_dcs = 1; new_dcs = calloc(new_num_dcs, sizeof (adutils_ad_t *)); if (new_dcs == NULL) @@ -295,6 +302,7 @@ reload_dcs(void) } } +out: _idmapdstate.dcs = new_dcs; _idmapdstate.num_dcs = new_num_dcs; @@ -325,7 +333,7 @@ reload_ad(void) } void -print_idmapdstate() +print_idmapdstate(void) { int i, j; idmap_pg_config_t *pgcfg; diff --git a/usr/src/cmd/idmap/idmapd/nldaputils.c b/usr/src/cmd/idmap/idmapd/nldaputils.c index e14d47e2bb..2895789bd3 100644 --- a/usr/src/cmd/idmap/idmapd/nldaputils.c +++ b/usr/src/cmd/idmap/idmapd/nldaputils.c @@ -20,8 +20,7 @@ */ /* - * 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. */ /* @@ -721,7 +720,7 @@ nldap_lookup_batch(lookup_state_t *state, idmap_mapping_batch *batch, idmap_ids_res *result) { idmap_retcode retcode, rc1; - int i, add, is_wuser; + int i, add; idmap_mapping *req; idmap_id_res *res; idmap_nldap_query_state_t *qs = NULL; @@ -751,7 +750,7 @@ nldap_lookup_batch(lookup_state_t *state, idmap_mapping_batch *batch, if (!(req->direction & _IDMAP_F_LOOKUP_NLDAP)) continue; - if (IS_REQUEST_SID(*req, 1)) { + if (IS_ID_SID(req->id1)) { /* win2unix request: */ @@ -779,7 +778,7 @@ nldap_lookup_batch(lookup_state_t *state, idmap_mapping_batch *batch, /* Lookup nldap by winname to get pid and unixname */ add = 1; - idmap_info_free(&res->info); + idmap_how_clear(&res->info.how); res->info.src = IDMAP_MAP_SRC_NEW; how = &res->info.how; how->map_type = IDMAP_MAP_TYPE_DS_NLDAP; @@ -792,7 +791,7 @@ nldap_lookup_batch(lookup_state_t *state, idmap_mapping_batch *batch, &req->id2name, &res->id.idmap_id_u.uid, &res->retcode); - } else if (IS_REQUEST_UID(*req) || IS_REQUEST_GID(*req)) { + } else if (IS_ID_UID(req->id1) || IS_ID_GID(req->id1)) { /* unix2win request: */ @@ -807,7 +806,7 @@ nldap_lookup_batch(lookup_state_t *state, idmap_mapping_batch *batch, req->id2domain = NULL; /* Set how info */ - idmap_info_free(&res->info); + idmap_how_clear(&res->info.how); res->info.src = IDMAP_MAP_SRC_NEW; how = &res->info.how; how->map_type = IDMAP_MAP_TYPE_DS_NLDAP; @@ -887,18 +886,16 @@ out: if (res->retcode == IDMAP_SUCCESS && req->id2name != NULL && res->id.idmap_id_u.sid.prefix == NULL && - (IS_REQUEST_UID(*req) || IS_REQUEST_GID(*req))) { + (IS_ID_UID(req->id1) || IS_ID_GID(req->id1))) { - is_wuser = -1; rc1 = lookup_name2sid(state->cache, - req->id2name, req->id2domain, &is_wuser, + req->id2name, req->id2domain, -1, NULL, NULL, &res->id.idmap_id_u.sid.prefix, - &res->id.idmap_id_u.sid.rid, req, 1); - if (rc1 == IDMAP_SUCCESS) - res->id.idtype = - is_wuser ? IDMAP_USID : IDMAP_GSID; - else if (rc1 == IDMAP_ERR_NOTFOUND) { + &res->id.idmap_id_u.sid.rid, + &res->id.idtype, + req, 1); + if (rc1 == IDMAP_ERR_NOTFOUND) { req->direction |= _IDMAP_F_LOOKUP_AD; state->ad_nqueries++; } else @@ -913,7 +910,7 @@ out: if (res->retcode != IDMAP_SUCCESS && res->retcode != IDMAP_ERR_NS_LDAP_BAD_WINNAME && !(IDMAP_FATAL_ERROR(res->retcode))) { - idmap_info_free(&res->info); + idmap_how_clear(&res->info.how); res->retcode = IDMAP_SUCCESS; } } diff --git a/usr/src/cmd/idmap/idmapd/server.c b/usr/src/cmd/idmap/idmapd/server.c index db5e93c876..94a7cea12a 100644 --- a/usr/src/cmd/idmap/idmapd/server.c +++ b/usr/src/cmd/idmap/idmapd/server.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. */ @@ -123,10 +122,10 @@ validate_mapped_id_by_name_req(idmap_mapping *req) { int e; - if (IS_REQUEST_UID(*req) || IS_REQUEST_GID(*req)) + if (IS_ID_UID(req->id1) || IS_ID_GID(req->id1)) return (IDMAP_SUCCESS); - if (IS_REQUEST_SID(*req, 1)) { + if (IS_ID_SID(req->id1)) { if (!EMPTY_STRING(req->id1name) && u8_validate(req->id1name, strlen(req->id1name), NULL, U8_VALIDATE_ENTIRE, &e) < 0) @@ -186,6 +185,9 @@ idmap_get_mapped_ids_1_svc(idmap_mapping_batch batch, lookup_state_t state; idmap_retcode retcode; uint_t i; + idmap_mapping *req; + idmap_id_res *res; + boolean_t any_tracing; /* Init */ (void) memset(result, 0, sizeof (*result)); @@ -241,28 +243,34 @@ idmap_get_mapped_ids_1_svc(idmap_mapping_batch batch, /* Init our 'done' flags */ state.sid2pid_done = state.pid2sid_done = TRUE; + any_tracing = B_FALSE; + /* First stage */ for (i = 0; i < batch.idmap_mapping_batch_len; i++) { + req = &batch.idmap_mapping_batch_val[i]; + res = &result->ids.ids_val[i]; + if (TRACING(req)) + any_tracing = B_TRUE; state.curpos = i; - (void) sanitize_mapping_request( - &batch.idmap_mapping_batch_val[i]); - if (IS_BATCH_SID(batch, i)) { + (void) sanitize_mapping_request(req); + TRACE(req, res, "Start mapping"); + if (IS_ID_SID(req->id1)) { retcode = sid2pid_first_pass( &state, - &batch.idmap_mapping_batch_val[i], - &result->ids.ids_val[i]); - } else if (IS_BATCH_UID(batch, i)) { + req, + res); + } else if (IS_ID_UID(req->id1)) { retcode = pid2sid_first_pass( &state, - &batch.idmap_mapping_batch_val[i], - &result->ids.ids_val[i], 1); - } else if (IS_BATCH_GID(batch, i)) { + req, + res, 1); + } else if (IS_ID_GID(req->id1)) { retcode = pid2sid_first_pass( &state, - &batch.idmap_mapping_batch_val[i], - &result->ids.ids_val[i], 0); + req, + res, 0); } else { - result->ids.ids_val[i].retcode = IDMAP_ERR_IDTYPE; + res->retcode = IDMAP_ERR_IDTYPE; continue; } if (IDMAP_FATAL_ERROR(retcode)) { @@ -288,9 +296,23 @@ idmap_get_mapped_ids_1_svc(idmap_mapping_batch batch, if (state.nldap_nqueries) { retcode = nldap_lookup_batch(&state, &batch, result); if (IDMAP_FATAL_ERROR(retcode)) { + TRACE(req, res, "Native LDAP lookup error=%d", retcode); result->retcode = retcode; goto out; } + if (any_tracing) { + for (i = 0; i < batch.idmap_mapping_batch_len; i++) { + res = &result->ids.ids_val[i]; + req = &batch.idmap_mapping_batch_val[i]; + if (IDMAP_ERROR(res->retcode)) { + TRACE(req, res, + "Native LDAP lookup error=%d", + res->retcode); + } else { + TRACE(req, res, "Native LDAP lookup"); + } + } + } } /* @@ -310,9 +332,45 @@ idmap_get_mapped_ids_1_svc(idmap_mapping_batch batch, if (state.ad_nqueries) { retcode = ad_lookup_batch(&state, &batch, result); if (IDMAP_FATAL_ERROR(retcode)) { + TRACE(req, res, "AD lookup error=%d", retcode); result->retcode = retcode; goto out; } + for (i = 0; i < batch.idmap_mapping_batch_len; i++) { + res = &result->ids.ids_val[i]; + req = &batch.idmap_mapping_batch_val[i]; + if (res->retcode == IDMAP_ERR_DOMAIN_NOTFOUND && + req->id1.idmap_id_u.sid.prefix != NULL && + req->id1name != NULL) { + /* + * If AD lookup failed Domain Not Found but + * we have a winname and SID, it means that + * - LSA succeeded + * - it's a request a cross-forest trust + * and + * - we were looking for directory-based + * mapping information. + * In that case, we're OK, just go on. + * + * If this seems more convoluted than it + * should be, it is - really, we probably + * shouldn't even be attempting AD lookups + * in this situation, but that's a more + * intricate cleanup that will have to wait + * for later. + */ + res->retcode = IDMAP_SUCCESS; + TRACE(req, res, + "AD lookup - domain not found (ignored)"); + continue; + } + if (res->retcode == IDMAP_SUCCESS) + TRACE(req, res, "Found in AD"); + else if (res->retcode == IDMAP_ERR_NOTFOUND) + TRACE(req, res, "Not found in AD"); + else + TRACE(req, res, "AD lookup error"); + } } /* @@ -324,9 +382,17 @@ idmap_get_mapped_ids_1_svc(idmap_mapping_batch batch, if (state.nldap_nqueries) { retcode = nldap_lookup_batch(&state, &batch, result); if (IDMAP_FATAL_ERROR(retcode)) { + TRACE(req, res, "Native LDAP lookup error=%d", retcode); result->retcode = retcode; goto out; } + if (any_tracing) { + for (i = 0; i < batch.idmap_mapping_batch_len; i++) { + res = &result->ids.ids_val[i]; + req = &batch.idmap_mapping_batch_val[i]; + TRACE(req, res, "Native LDAP lookup"); + } + } } /* Reset 'done' flags */ @@ -334,22 +400,24 @@ idmap_get_mapped_ids_1_svc(idmap_mapping_batch batch, /* Second stage */ for (i = 0; i < batch.idmap_mapping_batch_len; i++) { + req = &batch.idmap_mapping_batch_val[i]; + res = &result->ids.ids_val[i]; state.curpos = i; - if (IS_BATCH_SID(batch, i)) { + if (IS_ID_SID(req->id1)) { retcode = sid2pid_second_pass( &state, - &batch.idmap_mapping_batch_val[i], - &result->ids.ids_val[i]); - } else if (IS_BATCH_UID(batch, i)) { + req, + res); + } else if (IS_ID_UID(req->id1)) { retcode = pid2sid_second_pass( &state, - &batch.idmap_mapping_batch_val[i], - &result->ids.ids_val[i], 1); - } else if (IS_BATCH_GID(batch, i)) { + req, + res, 1); + } else if (IS_ID_GID(req->id1)) { retcode = pid2sid_second_pass( &state, - &batch.idmap_mapping_batch_val[i], - &result->ids.ids_val[i], 0); + req, + res, 0); } else { /* First stage has already set the error */ continue; @@ -373,18 +441,20 @@ idmap_get_mapped_ids_1_svc(idmap_mapping_batch batch, goto out; for (i = 0; i < batch.idmap_mapping_batch_len; i++) { + req = &batch.idmap_mapping_batch_val[i]; + res = &result->ids.ids_val[i]; state.curpos = i; - if (IS_BATCH_SID(batch, i)) { + if (IS_ID_SID(req->id1)) { (void) update_cache_sid2pid( &state, - &batch.idmap_mapping_batch_val[i], - &result->ids.ids_val[i]); - } else if ((IS_BATCH_UID(batch, i)) || - (IS_BATCH_GID(batch, i))) { + req, + res); + } else if ((IS_ID_UID(req->id1)) || + (IS_ID_GID(req->id1))) { (void) update_cache_pid2sid( &state, - &batch.idmap_mapping_batch_val[i], - &result->ids.ids_val[i]); + req, + res); } } @@ -399,11 +469,36 @@ idmap_get_mapped_ids_1_svc(idmap_mapping_batch batch, out: cleanup_lookup_state(&state); if (IDMAP_ERROR(result->retcode)) { + if (any_tracing) { + for (i = 0; i < batch.idmap_mapping_batch_len; i++) { + req = &batch.idmap_mapping_batch_val[i]; + res = &result->ids.ids_val[i]; + TRACE(req, res, + "Failure code %d", result->retcode); + } + } xdr_free(xdr_idmap_ids_res, (caddr_t)result); result->ids.ids_len = 0; result->ids.ids_val = NULL; + } else { + if (any_tracing) { + for (i = 0; i < batch.idmap_mapping_batch_len; i++) { + req = &batch.idmap_mapping_batch_val[i]; + res = &result->ids.ids_val[i]; + TRACE(req, res, "Done"); + } + } } result->retcode = idmap_stat4prot(result->retcode); + + for (i = 0; i < result->ids.ids_len; i++) { + req = &batch.idmap_mapping_batch_val[i]; + res = &result->ids.ids_val[i]; + + if (!(req->flag & IDMAP_REQ_FLG_MAPPING_INFO) && + res->retcode == IDMAP_SUCCESS) + idmap_how_clear(&res->info.how); + } return (TRUE); } @@ -1087,11 +1182,7 @@ idmap_get_mapped_id_by_name_1_svc(idmap_mapping request, result->retcode = batch_result.ids.ids_val[0].retcode; - if (map->flag & IDMAP_REQ_FLG_MAPPING_INFO || - result->retcode != IDMAP_SUCCESS) { - (void) idmap_info_mov(&map->info, - &batch_result.ids.ids_val[0].info); - } + idmap_info_mov(&map->info, &batch_result.ids.ids_val[0].info); out: if (IDMAP_FATAL_ERROR(result->retcode)) { diff --git a/usr/src/cmd/idmap/idmapd/wksids.c b/usr/src/cmd/idmap/idmapd/wksids.c index 3e2c87eab1..90d749d336 100644 --- a/usr/src/cmd/idmap/idmapd/wksids.c +++ b/usr/src/cmd/idmap/idmapd/wksids.c @@ -20,8 +20,7 @@ */ /* - * 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. */ /* @@ -223,7 +222,7 @@ static wksids_table_t wksids[] = { */ const wksids_table_t * -find_wksid_by_name(const char *name, const char *domain, int type) +find_wksid_by_name(const char *name, const char *domain, idmap_id_type type) { int i; @@ -286,7 +285,7 @@ find_wksid_by_name(const char *name, const char *domain, int type) */ const wksids_table_t * -find_wksid_by_sid(const char *sid, int rid, int type) +find_wksid_by_sid(const char *sid, int rid, idmap_id_type type) { int i; diff --git a/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c b/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c index 49708383c9..58ebaa2945 100644 --- a/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c +++ b/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c @@ -19,11 +19,11 @@ * 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/mdb_modapi.h> +#include <mdb/mdb_modapi.h> +#include <mdb/mdb_ks.h> #include <sys/thread.h> #include <sys/taskq_impl.h> #include <smbsrv/smb_vops.h> @@ -35,16 +35,15 @@ #define ACE_TYPE_ENTRY(_v_) {_v_, #_v_} #define SMB_COM_ENTRY(_v_, _x_) {#_v_, _x_} -#define SMB_MDB_MAX_OPTS 10 +#define SMB_MDB_MAX_OPTS 9 #define SMB_OPT_SERVER 0x00000001 -#define SMB_OPT_VFS 0x00000002 -#define SMB_OPT_SESSION 0x00000004 -#define SMB_OPT_REQUEST 0x00000008 -#define SMB_OPT_USER 0x00000010 -#define SMB_OPT_TREE 0x00000020 -#define SMB_OPT_OFILE 0x00000040 -#define SMB_OPT_ODIR 0x00000080 +#define SMB_OPT_SESSION 0x00000002 +#define SMB_OPT_REQUEST 0x00000004 +#define SMB_OPT_USER 0x00000008 +#define SMB_OPT_TREE 0x00000010 +#define SMB_OPT_OFILE 0x00000020 +#define SMB_OPT_ODIR 0x00000040 #define SMB_OPT_WALK 0x00000100 #define SMB_OPT_VERBOSE 0x00000200 #define SMB_OPT_ALL_OBJ 0x000000FF @@ -78,9 +77,22 @@ typedef struct { /* * List of supported options. Ther order has the match the bits SMB_OPT_xxx. */ -static const char *smb_opts[SMB_MDB_MAX_OPTS] = +typedef struct smb_mdb_opts { + char *o_name; + uint32_t o_value; +} smb_mdb_opts_t; + +static smb_mdb_opts_t smb_opts[SMB_MDB_MAX_OPTS] = { - "-s", "-m", "-e", "-r", "-u", "-t", "-f", "-d", "-w", "-v" + { "-s", SMB_OPT_SERVER }, + { "-e", SMB_OPT_SESSION }, + { "-r", SMB_OPT_REQUEST }, + { "-u", SMB_OPT_USER }, + { "-t", SMB_OPT_TREE }, + { "-f", SMB_OPT_OFILE }, + { "-d", SMB_OPT_ODIR }, + { "-w", SMB_OPT_WALK }, + { "-v", SMB_OPT_VERBOSE } }; static smb_com_entry_t smb_com[256] = @@ -346,7 +358,6 @@ static smb_com_entry_t smb_com[256] = static int smb_dcmd_list(uintptr_t, uint_t, int, const mdb_arg_t *); static void smb_dcmd_list_help(void); static int smb_dcmd_server(uintptr_t, uint_t, int, const mdb_arg_t *); -static int smb_dcmd_vfs(uintptr_t, uint_t, int, const mdb_arg_t *); static void smb_dcmd_session_help(void); static int smb_dcmd_session(uintptr_t, uint_t, int, const mdb_arg_t *); static int smb_dcmd_request(uintptr_t, uint_t, int, const mdb_arg_t *); @@ -356,12 +367,14 @@ static void smb_dcmd_tree_help(void); static int smb_dcmd_tree(uintptr_t, uint_t, int, const mdb_arg_t *); static int smb_dcmd_odir(uintptr_t, uint_t, int, const mdb_arg_t *); static int smb_dcmd_ofile(uintptr_t, uint_t, int, const mdb_arg_t *); +static int smb_vfs(uintptr_t, uint_t, int, const mdb_arg_t *); +static int smb_vfs_walk_init(mdb_walk_state_t *); +static int smb_vfs_walk_step(mdb_walk_state_t *); static void smb_node_help(void); static int smb_node(uintptr_t, uint_t, int, const mdb_arg_t *); static int smb_node_walk_init(mdb_walk_state_t *); static int smb_node_walk_step(mdb_walk_state_t *); static int smb_lock(uintptr_t, uint_t, int, const mdb_arg_t *); -static int smb_stats(uintptr_t, uint_t, int, const mdb_arg_t *); static int smb_ace(uintptr_t, uint_t, int, const mdb_arg_t *); static int smb_ace_walk_init(mdb_walk_state_t *); static int smb_ace_walk_step(mdb_walk_state_t *); @@ -375,6 +388,7 @@ static int smb_dcmd_setopt(uint_t, int, mdb_arg_t *); static int smb_obj_expand(uintptr_t, uint_t, const smb_exp_t *, ulong_t); static int smb_obj_list(const char *, uint_t, uint_t); static int smb_worker_findstack(uintptr_t); +static int smb_stats(uintptr_t, uint_t, int, const mdb_arg_t *); /* * MDB module linkage information: @@ -396,7 +410,7 @@ static const mdb_dcmd_t dcmds[] = { { "smbvfs", "[-v]", "print smb_vfs information", - smb_dcmd_vfs }, + smb_vfs }, { "smbnode", "?[-vps]", "print smb_node_t information", @@ -431,8 +445,9 @@ static const mdb_dcmd_t dcmds[] = { "[-v]", "print smb_odir_t information", smb_dcmd_ofile }, - { "smbstats", NULL, - "print all smb dispatched requests statistics", smb_stats }, + { "smbstat", NULL, + "print all smb dispatched requests statistics", + smb_stats }, { "smbace", "[-v]", "print smb_ace_t information", smb_ace }, { "smbacl", "[-v]", @@ -453,6 +468,12 @@ static const mdb_walker_t walkers[] = { smb_node_walk_step, NULL, NULL }, + { "smbvfs_walker", + "walk list of smb_vfs_t structures", + smb_vfs_walk_init, + smb_vfs_walk_step, + NULL, + NULL }, { "smbace_walker", "walk list of smb_ace_t structures", smb_ace_walk_init, @@ -490,7 +511,6 @@ smb_dcmd_list_help(void) mdb_printf( "-v\tDisplay verbose information\n" "-s\tDisplay the list of servers\n" - "-m\tDisplay the list of shared file systems\n" "-e\tDisplay the list of sessions\n" "-r\tDisplay the list of smb requests\n" "-u\tDisplay the list of users\n" @@ -569,9 +589,6 @@ static const smb_exp_t smb_server_exp[] = { SMB_OPT_ALL_OBJ, offsetof(smb_server_t, sv_tcp_daemon.ld_session_list.se_act.lst), "smbsess", "smb_session"}, - { SMB_OPT_ALL_OBJ, - offsetof(smb_server_t, sv_vfs_list.ll_list), - "smbvfs", "smb_vfs"}, { 0, 0, NULL, NULL } }; @@ -620,20 +637,16 @@ smb_dcmd_server(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) "%<b>%<u>%-?s% " "%-4s% " "%-32s% " - "%-6s% " - "%-6s% " - "%-6s%</u>%</b>\n", - "SERVER", "ZONE", "STATE", "USERS", - "TREES", "FILES"); + "%</u>%</b>\n", + "SERVER", "ZONE", "STATE"); if (sv->sv_state >= SMB_SERVER_STATE_SENTINEL) state = "UNKNOWN"; else state = smb_server_state[sv->sv_state]; - mdb_printf("%-?p %-4d %-32s %-6d %-6d %-6d \n", - addr, sv->sv_zid, state, sv->sv_open_users, - sv->sv_open_trees, sv->sv_open_files); + mdb_printf("%-?p %-4d %-32s \n", + addr, sv->sv_zid, state); } } if (smb_obj_expand(addr, opts, smb_server_exp, indent)) @@ -643,68 +656,6 @@ smb_dcmd_server(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) /* * ***************************************************************************** - * ******************************** smb_vfs_t ********************************** - * ***************************************************************************** - */ - -/* - * ::smbvfs - * - * smbvfs dcmd - Prints out smb_vfs structures. - */ -/*ARGSUSED*/ -static int -smb_dcmd_vfs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) -{ - - uint_t opts; - - if (smb_dcmd_getopt(&opts, argc, argv)) - return (DCMD_USAGE); - - if (!(flags & DCMD_ADDRSPEC)) { - return (smb_obj_list("smb_vfs", SMB_OPT_VFS, flags)); - } - - if (((opts & SMB_OPT_WALK) && (opts & SMB_OPT_VFS)) || - !(opts & SMB_OPT_WALK)) { - smb_vfs_t *sf; - vnode_t *vn; - char *path; - - sf = mdb_alloc(sizeof (*sf), UM_SLEEP | UM_GC); - if (mdb_vread(sf, sizeof (*sf), addr) == -1) { - mdb_warn("failed to read smb_vfs at %p", addr); - return (DCMD_ERR); - } - vn = mdb_alloc(sizeof (*vn), UM_SLEEP | UM_GC); - if (mdb_vread(vn, sizeof (*vn), - (uintptr_t)sf->sv_rootvp) == -1) { - mdb_warn("failed to read vnode at %p", sf->sv_rootvp); - return (DCMD_ERR); - } - path = mdb_zalloc(MAXPATHLEN, UM_SLEEP | UM_GC); - (void) mdb_vread(path, MAXPATHLEN, (uintptr_t)vn->v_path); - - if (DCMD_HDRSPEC(flags)) - mdb_printf( - "%<b>%<u>" - "%-?s " - "%-10s " - "%-16s " - "%-16s" - "%-s" - "%</u>%</b>\n", - "SMB_VFS", "REFCNT", "VFS", "VNODE", "ROOT"); - mdb_printf( - "%-?p %-10d %-?p %-?p %-s\n", addr, sf->sv_refcnt, - sf->sv_vfsp, sf->sv_rootvp, path); - } - return (DCMD_OK); -} - -/* - * ***************************************************************************** * ***************************** smb_session_t ********************************* * ***************************************************************************** */ @@ -784,7 +735,6 @@ smb_dcmd_session(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) mdb_warn("failed to read smb_session at %p", addr); return (DCMD_ERR); } - if (se->s_state >= SMB_SESSION_STATE_SENTINEL) state = "INVALID"; else @@ -812,13 +762,13 @@ smb_dcmd_session(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) mdb_printf( "%<b>%<u>%-?s " "%-16s " - "%-16s%</u>%</b>\n", + "%-16s %-16s%</u>%</b>\n", "SESSION", "CLIENT_IP_ADDR", - "LOCAL_IP_ADDR"); + "LOCAL_IP_ADDR", "STATE"); mdb_printf( - "%-?p %-16I %-16I\n", addr, se->ipaddr.a_ipv4, - se->local_ipaddr.a_ipv4); + "%-?p %-16I %-16I %s\n", addr, se->ipaddr.a_ipv4, + se->local_ipaddr.a_ipv4, state); } } if (smb_obj_expand(addr, opts, smb_session_exp, indent)) @@ -846,6 +796,11 @@ static const char *smb_request_state[SMB_REQ_STATE_SENTINEL] = "CLEANED_UP" }; +#define SMB_REQUEST_BANNER \ + "%<b>%<u>%-?s %-?s %-14s %-14s %-16s %-32s%</u>%</b>\n" +#define SMB_REQUEST_FORMAT \ + "%-?p %-?p %e %e %-16s %s\n" + static int smb_dcmd_request(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { @@ -864,12 +819,33 @@ smb_dcmd_request(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) !(opts & SMB_OPT_WALK)) { smb_request_t *sr; const char *state; + uint64_t waiting; + uint64_t running; sr = mdb_alloc(sizeof (*sr), UM_SLEEP | UM_GC); if (mdb_vread(sr, sizeof (*sr), addr) == -1) { mdb_warn("failed to read smb_request at %p", addr); return (DCMD_ERR); } + if (sr->sr_magic != SMB_REQ_MAGIC) { + mdb_warn("not an smb_request_t (%p)>", addr); + return (DCMD_ERR); + } + waiting = 0; + running = 0; + if (sr->sr_time_submitted != 0) { + if (sr->sr_time_active != 0) { + waiting = sr->sr_time_active - + sr->sr_time_submitted; + running = mdb_gethrtime() - + sr->sr_time_active; + } else { + waiting = mdb_gethrtime() - + sr->sr_time_submitted; + } + } + waiting /= NANOSEC; + running /= NANOSEC; if (sr->sr_state >= SMB_REQ_STATE_SENTINEL) state = "INVALID"; @@ -880,27 +856,48 @@ smb_dcmd_request(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) mdb_printf( "%</b>%</u>SMB request information (%p):" "%</u>%</b>\n\n", addr); - mdb_printf("First SMB COM: %u (%s)\n", - sr->first_smb_com, - smb_com[sr->first_smb_com]); - mdb_printf("State: %u (%s)\n", sr->sr_state, state); - mdb_printf("Tree: %u (%p)\n", sr->smb_tid, - sr->tid_tree); - mdb_printf("User: %u (%p)\n", sr->smb_uid, - sr->uid_user); - mdb_printf("File: %u (%p)\n", - sr->smb_fid, sr->fid_ofile); - mdb_printf("PID: %u\n", sr->smb_pid); - mdb_printf("MID: %u\n\n", sr->smb_mid); + + mdb_printf( + "first SMB COM: %u (%s)\n" + "current SMB COM: %u (%s)\n" + "state: %u (%s)\n" + "TID(tree): %u (%p)\n" + "UID(user): %u (%p)\n" + "FID(file): %u (%p)\n" + "PID: %u\n" + "MID: %u\n\n" + "waiting time: %1.3e\n" + "running time: %1.3e", + sr->first_smb_com, smb_com[sr->first_smb_com], + sr->smb_com, smb_com[sr->smb_com], + sr->sr_state, state, + sr->smb_tid, sr->tid_tree, + sr->smb_uid, sr->uid_user, + sr->smb_fid, sr->fid_ofile, + sr->smb_pid, + sr->smb_mid, + waiting, + running); + smb_worker_findstack((uintptr_t)sr->sr_worker); } else { if (DCMD_HDRSPEC(flags)) mdb_printf( - "%<b>%<u>%-?s %-?s %-16s %s%</u>%</b>\n", - "ADDR", "Worker", "STATE", "COM"); - - mdb_printf("%-?p %-?p %-16s %s\n", addr, sr->sr_worker, - state, smb_com[sr->first_smb_com]); + SMB_REQUEST_BANNER, + "ADDR", + "WORKER", + "WAITING(s)", + "RUNNING(s)", + "STATE", + "COMMAND"); + + mdb_printf(SMB_REQUEST_FORMAT, + addr, + sr->sr_worker, + waiting, + running, + state, + smb_com[sr->smb_com]); } } return (DCMD_OK); @@ -972,7 +969,6 @@ smb_dcmd_user(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) mdb_warn("failed to read smb_user at %p", addr); return (DCMD_ERR); } - account = mdb_zalloc(user->u_domain_len + user->u_name_len + 2, UM_SLEEP | UM_GC); @@ -1088,7 +1084,6 @@ smb_dcmd_tree(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) mdb_warn("failed to read smb_tree at %p", addr); return (DCMD_ERR); } - if (opts & SMB_OPT_VERBOSE) { const char *state; @@ -1162,7 +1157,6 @@ smb_dcmd_odir(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) mdb_warn("failed to read smb_odir at %p", addr); return (DCMD_ERR); } - if (opts & SMB_OPT_VERBOSE) { const char *state; @@ -1232,7 +1226,6 @@ smb_dcmd_ofile(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) mdb_warn("failed to read smb_ofile at %p", addr); return (DCMD_ERR); } - if (opts & SMB_OPT_VERBOSE) { const char *state; @@ -1271,6 +1264,117 @@ smb_dcmd_ofile(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) /* * ***************************************************************************** + * ******************************** smb_vfs_t ********************************** + * ***************************************************************************** + */ + +/* + * ::smbvfs + * + * smbvfs dcmd - Prints out smb_vfs structures. + */ +/*ARGSUSED*/ +static int +smb_vfs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + int verbose = FALSE; + smb_vfs_t *sf; + vnode_t *vn; + char *path; + + if (mdb_getopts(argc, argv, + 'v', MDB_OPT_SETBITS, TRUE, &verbose, + NULL) != argc) + return (DCMD_USAGE); + + /* + * If no smb_vfs address was specified on the command line, we can + * print out all smb_vfs by invoking the smb_vfs walker, using + * this dcmd itself as the callback. + */ + if (!(flags & DCMD_ADDRSPEC)) { + if (mdb_walk_dcmd("smbvfs_walker", "smbvfs", + argc, argv) == -1) { + mdb_warn("failed to walk 'smb_vfs'"); + return (DCMD_ERR); + } + return (DCMD_OK); + } + + if (DCMD_HDRSPEC(flags)) { + mdb_printf( + "%<b>%<u>" + "%-?s " + "%-10s " + "%-16s " + "%-16s" + "%-s" + "%</u>%</b>\n", + "SMB_VFS", "REFCNT", "VFS", "VNODE", "ROOT"); + } + + sf = mdb_alloc(sizeof (*sf), UM_SLEEP | UM_GC); + if (mdb_vread(sf, sizeof (*sf), addr) == -1) { + mdb_warn("failed to read smb_vfs at %p", addr); + return (DCMD_ERR); + } + + vn = mdb_alloc(sizeof (*vn), UM_SLEEP | UM_GC); + if (mdb_vread(vn, sizeof (*vn), + (uintptr_t)sf->sv_rootvp) == -1) { + mdb_warn("failed to read vnode at %p", sf->sv_rootvp); + return (DCMD_ERR); + } + + path = mdb_zalloc(MAXPATHLEN, UM_SLEEP | UM_GC); + (void) mdb_vread(path, MAXPATHLEN, (uintptr_t)vn->v_path); + + mdb_printf( + "%-?p %-10d %-?p %-?p %-s\n", addr, sf->sv_refcnt, + sf->sv_vfsp, sf->sv_rootvp, path); + + return (DCMD_OK); +} + +/* + * Initialize the smb_vfs_t walker by reading the value of smb_export + * in the kernel's symbol table. Only global walk supported. + */ +static int +smb_vfs_walk_init(mdb_walk_state_t *wsp) +{ + GElf_Sym sym; + + if (wsp->walk_addr != NULL) { + mdb_printf("smb_vfs walk only supports global walks\n"); + return (WALK_ERR); + } + + if (mdb_lookup_by_name("smb_export", &sym) == -1) { + mdb_warn("failed to find 'smb_export'"); + return (WALK_ERR); + } + + wsp->walk_addr = (uintptr_t)sym.st_value + + offsetof(smb_export_t, e_vfs_list) + offsetof(smb_llist_t, ll_list); + + if (mdb_layered_walk("list", wsp) == -1) { + mdb_warn("failed to walk list of VFS"); + return (WALK_ERR); + } + + return (WALK_NEXT); +} + +static int +smb_vfs_walk_step(mdb_walk_state_t *wsp) +{ + return (wsp->walk_callback(wsp->walk_addr, wsp->walk_layer, + wsp->walk_cbdata)); +} + +/* + * ***************************************************************************** * ******************************* smb_node_t ********************************** * ***************************************************************************** */ @@ -1609,41 +1713,38 @@ smb_lock(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) } /* - * ::smb_dispatch_stats + * ::smbstat * - * smb_dispatch_stats dcmd - Prints all dispatched SMB requests statistics. + * Prints SMB requests statistics. */ /*ARGSUSED*/ static int smb_stats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { - smb_disp_entry_t *disp; - GElf_Sym sym; - int nstats = 0, i; + smb_server_t *sv; - if ((flags & DCMD_ADDRSPEC) || argc != 0) + if (!(flags & DCMD_ADDRSPEC)) return (DCMD_USAGE); - if (mdb_lookup_by_obj(MDB_OBJ_EVERY, "dispatch", &sym)) { - mdb_warn("failed to find dispatch object"); + sv = mdb_alloc(sizeof (*sv), UM_SLEEP | UM_GC); + if (mdb_vread(sv, sizeof (*sv), addr) == -1) { + mdb_warn("failed to read server object at %p", addr); return (DCMD_ERR); } - - disp = mdb_alloc(sym.st_size, UM_SLEEP | UM_GC); - if (mdb_vread(disp, sym.st_size, sym.st_value) == -1) { - mdb_warn("failed to read from dispatch object"); + if (sv->sv_magic != SMB_SERVER_MAGIC) { + mdb_warn("not an smb_server_t (%p)>", addr); return (DCMD_ERR); } + mdb_printf( + "\n%<b> nbt tcp users trees files pipes%</b>\n" + "%5d %5d %5d %5d %5d %5d\n", + sv->sv_nbt_sess, + sv->sv_tcp_sess, + sv->sv_users, + sv->sv_trees, + sv->sv_files, + sv->sv_pipes); - nstats = sym.st_size / sizeof (smb_disp_entry_t); - - mdb_printf("All dispatched SMB requests statistics:\n\n"); - for (i = 0; i < nstats; i++) { - if (disp[i].sdt_function) - mdb_printf(" %40s\t: %lld\n", - disp[i].sdt_dispatch_stats.name, - disp[i].sdt_dispatch_stats.value.ui64); - } return (DCMD_OK); } @@ -2043,7 +2144,6 @@ smb_dcmd_getopt(uint_t *opts, int argc, const mdb_arg_t *argv) if (mdb_getopts(argc, argv, 's', MDB_OPT_SETBITS, SMB_OPT_SERVER, opts, - 'm', MDB_OPT_SETBITS, SMB_OPT_VFS, opts, 'e', MDB_OPT_SETBITS, SMB_OPT_SESSION, opts, 'r', MDB_OPT_SETBITS, SMB_OPT_REQUEST, opts, 'u', MDB_OPT_SETBITS, SMB_OPT_USER, opts, @@ -2071,17 +2171,15 @@ static int smb_dcmd_setopt(uint_t opts, int max_argc, mdb_arg_t *argv) { int i; - uint_t mask = 0x00000001; int argc = 0; for (i = 0; i < SMB_MDB_MAX_OPTS; i++) { - if ((opts & mask) && (argc < max_argc)) { + if ((opts & smb_opts[i].o_value) && (argc < max_argc)) { argv->a_type = MDB_TYPE_STRING; - argv->a_un.a_str = smb_opts[i]; + argv->a_un.a_str = smb_opts[i].o_name; argc++; argv++; } - mask = mask << 1; } return (argc); } diff --git a/usr/src/cmd/smbsrv/dtrace/cifs.d b/usr/src/cmd/smbsrv/dtrace/cifs.d index 0e902e7604..c9748b4b40 100644 --- a/usr/src/cmd/smbsrv/dtrace/cifs.d +++ b/usr/src/cmd/smbsrv/dtrace/cifs.d @@ -20,8 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -69,17 +68,62 @@ sdt:smbsrv::-smb_op*-done self->status = sr->smb_error.status; } +sdt:smbsrv::-smb_op-Negotiate-done +{ + sr = (struct smb_request *)arg0; + negprot = (smb_arg_negotiate_t *)arg1; + + printf("dialect=%s index=%u caps=0x%08x maxmpx=%u tz=%d time=%u", + stringof(negprot->ni_name), + negprot->ni_index, + negprot->ni_capabilities, + negprot->ni_maxmpxcount, + negprot->ni_tzcorrection, + negprot->ni_servertime.tv_sec); + + printf(" [status=0x%08x (class=%d code=%d)]", + sr->smb_error.status, + sr->smb_error.errcls, sr->smb_error.errcode); + + self->status = sr->smb_error.status; +} + sdt:smbsrv::-smb_op-SessionSetupX-start { sr = (struct smb_request *)arg0; + ssetup = (smb_arg_sessionsetup_t *)arg1; - printf("[%s] %s", + printf("[%s] %s %s %s", (sr->session->s_local_port == 139) ? "NBT" : "TCP", (sr->session->s_local_port == 139) ? - stringof(sr->session->workstation) : ""); + stringof(sr->session->workstation) : "", + stringof(ssetup->ssi_domain), + stringof(ssetup->ssi_user)); + + printf(" maxmpx=%u vc=%u maxbuf=%u", + ssetup->ssi_maxmpxcount, + sr->session->vcnumber, + sr->session->smb_msg_size); +} + +sdt:smbsrv::-smb_op-SessionSetupX-done +{ + sr = (struct smb_request *)arg0; + ssetup = (smb_arg_sessionsetup_t *)arg1; + + printf("%s/%s: smbuid=%d (%s)", + stringof(sr->uid_user->u_domain), + stringof(sr->uid_user->u_name), + sr->smb_uid, + (ssetup->ssi_guest == 0) ? "user" : "guest"); + + printf(" [status=0x%08x (class=%d code=%d)]", + sr->smb_error.status, + sr->smb_error.errcls, sr->smb_error.errcode); + + self->status = sr->smb_error.status; } -sdt:smbsrv::-smb_op-SessionSetupX-done, sdt:smbsrv::-smb_op-LogoffX-start { sr = (struct smb_request *)arg0; @@ -98,7 +142,19 @@ sdt:smbsrv::-smb_op-TreeConnectX-start stringof(tcon->path)); } -sdt:smbsrv::-smb_op-TreeConnectX-done, +sdt:smbsrv::-smb_op-TreeConnectX-done +{ + sr = (struct smb_request *)arg0; + + printf("tid %d: %s", sr->smb_tid, + (sr->smb_error.status == 0) ? + stringof(sr->tid_tree->t_sharename) : ""); + + printf(" [status=0x%08x (class=%d code=%d)]", + sr->smb_error.status, + sr->smb_error.errcls, sr->smb_error.errcode); +} + sdt:smbsrv::-smb_op-TreeDisconnect-start { sr = (struct smb_request *)arg0; @@ -172,8 +228,8 @@ sdt:smbsrv::-smb_op-Rename-start p = (struct dirop *)arg1; printf("%s to %s", - stringof(p->fqi.fq_path.pn_path), - stringof(p->dst_fqi.fq_path.pn_path)); + stringof(p->fqi.fq_path.pn_path), + stringof(p->dst_fqi.fq_path.pn_path)); } sdt:smbsrv::-smb_op-CheckDirectory-start, @@ -192,7 +248,7 @@ smb_dispatch_request:return, smb_pre_*:return, smb_com_*:return, smb_post_*:return, -smbsr_error:return, +smbsr_status:return, smbsr_errno:return { } @@ -207,7 +263,7 @@ smb_post_*:entry sr->smb_com, sr->smb_uid, sr->smb_tid); } -smbsr_error:entry +smbsr_status:entry { printf("status=0x%08x class=%d, code=%d\n", arg1, arg2, arg3); } diff --git a/usr/src/cmd/smbsrv/dtrace/msrpc.d b/usr/src/cmd/smbsrv/dtrace/msrpc.d index 4462934cd6..609140bff3 100644 --- a/usr/src/cmd/smbsrv/dtrace/msrpc.d +++ b/usr/src/cmd/smbsrv/dtrace/msrpc.d @@ -19,9 +19,9 @@ * * 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. */ /* @@ -150,7 +150,7 @@ smb_com_logoff_andx:return /* * Raise error functions (no return). */ -smbsr_error:entry +smbsr_status:entry { printf("status=0x%08x class=%d, code=%d", arg1, arg2, arg3); } @@ -160,7 +160,7 @@ smbsr_errno:entry printf("errno=%d", arg1); } -smbsr_error:return, +smbsr_status:return, smbsr_errno:return { } diff --git a/usr/src/cmd/smbsrv/dtrace/stype.d b/usr/src/cmd/smbsrv/dtrace/stype.d index bf0d143790..ce157e5877 100755..100644 --- a/usr/src/cmd/smbsrv/dtrace/stype.d +++ b/usr/src/cmd/smbsrv/dtrace/stype.d @@ -22,12 +22,9 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "@(#)stype.d 1.4 08/08/07 SMI" - #pragma D option flowindent /* @@ -53,14 +50,37 @@ END sdt:smbsrv::-smb_op-SessionSetupX-start { sr = (struct smb_request *)arg0; + ssetup = (smb_arg_sessionsetup_t *)arg1; - printf("[%s] %s", + printf("[%s] %s %s %s", (sr->session->s_local_port == 139) ? "NBT" : "TCP", (sr->session->s_local_port == 139) ? - stringof(sr->session->workstation) : ""); + stringof(sr->session->workstation) : "", + stringof(ssetup->ssi_domain), + stringof(ssetup->ssi_user)); + + printf(" maxmpx=%u vc=%u maxbuf=%u", + ssetup->ssi_maxmpxcount, + sr->session->vcnumber, + sr->session->smb_msg_size); +} + +sdt:smbsrv::-smb_op-SessionSetupX-done +{ + sr = (struct smb_request *)arg0; + ssetup = (smb_arg_sessionsetup_t *)arg1; + + printf("%s/%s: smbuid=%d (%s)", + stringof(sr->uid_user->u_domain), + stringof(sr->uid_user->u_name), + sr->smb_uid, + (ssetup->ssi_guest == 0) ? "user" : "guest"); + + printf(" [status=0x%08x (class=%d code=%d)]", + sr->smb_error.status, + sr->smb_error.errcls, sr->smb_error.errcode); } -sdt:smbsrv::-smb_op-SessionSetupX-done, sdt:smbsrv::-smb_op-LogoffX-start { sr = (struct smb_request *)arg0; @@ -79,8 +99,20 @@ sdt:smbsrv::-smb_op-TreeConnectX-start stringof(tcon->path)); } -sdt:smbsrv::-smb_op-TreeConnectX-done, -sdt:smbsrv::-smb_op-TreeDisconnect-done +sdt:smbsrv::-smb_op-TreeConnectX-done +{ + sr = (struct smb_request *)arg0; + + printf("tid %d: %s", sr->smb_tid, + (sr->smb_error.status == 0) ? + stringof(sr->tid_tree->t_sharename) : ""); + + printf(" [status=0x%08x (class=%d code=%d)]", + sr->smb_error.status, + sr->smb_error.errcls, sr->smb_error.errcode); +} + +sdt:smbsrv::-smb_op-TreeDisconnect-start { sr = (struct smb_request *)arg0; @@ -92,7 +124,7 @@ sdt:smbsrv::-smb_op-TreeDisconnect-done /* * Error functions */ -smbsr_error:entry +smbsr_status:entry { printf("status=0x%08x class=%d, code=%d", arg1, arg2, arg3); } @@ -102,7 +134,7 @@ smbsr_errno:entry printf("errno=%d", arg1); } -smbsr_error:return, +smbsr_status:return, smbsr_errno:return { } @@ -119,15 +151,16 @@ smb_tree_get_sharename:entry printf("uncpath=%s", stringof(arg0)); } -smb_tree_get_stype:entry +smb_tree_connect_disk:entry { - printf("sharename=%s service=%s", stringof(arg0), stringof(arg1)); + printf("sharename=%s", stringof(arg1)); + self->stype = 0; } -smb_tree_connect_disk:entry +smb_tree_connect_printq:entry { printf("sharename=%s", stringof(arg1)); - self->stype = 0; + self->stype = 1; } smb_tree_connect_ipc:entry @@ -138,7 +171,6 @@ smb_tree_connect_ipc:entry smb_tree_connect:return, smb_tree_get_sharename:return, -smb_tree_get_stype:return, smb_tree_connect_disk:return, smb_tree_connect_ipc:return { diff --git a/usr/src/cmd/smbsrv/smbadm/smbadm.c b/usr/src/cmd/smbsrv/smbadm/smbadm.c index ecf0f52615..df7f163599 100644 --- a/usr/src/cmd/smbsrv/smbadm/smbadm.c +++ b/usr/src/cmd/smbsrv/smbadm/smbadm.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. */ /* @@ -748,14 +747,6 @@ smbadm_group_create(int argc, char **argv) smbadm_usage(B_FALSE); } - if (getgrnam(gname) == NULL) { - (void) fprintf(stderr, - gettext("failed to get the Solaris group '%s'\n"), gname); - (void) fprintf(stderr, - gettext("use 'groupadd' to add '%s'\n"), gname); - return (1); - } - status = smb_lgrp_add(gname, desc); if (status != SMB_LGRP_SUCCESS) { (void) fprintf(stderr, @@ -994,14 +985,6 @@ smbadm_group_rename(int argc, char **argv) smbadm_usage(B_FALSE); } - if (getgrnam(ngname) == NULL) { - (void) fprintf(stderr, - gettext("failed to get the Solaris group '%s'\n"), ngname); - (void) fprintf(stderr, - gettext("use 'groupadd' to add '%s'\n"), ngname); - return (1); - } - status = smb_lgrp_rename(gname, ngname); if (status != SMB_LGRP_SUCCESS) { if (status == SMB_LGRP_EXISTS) diff --git a/usr/src/cmd/smbsrv/smbd/Makefile b/usr/src/cmd/smbsrv/smbd/Makefile index dff759c94f..2078b536ad 100644 --- a/usr/src/cmd/smbsrv/smbd/Makefile +++ b/usr/src/cmd/smbsrv/smbd/Makefile @@ -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. # @@ -30,6 +29,7 @@ SRCS= \ smbd_join.c \ smbd_logon.c \ smbd_main.c \ + smbd_nicmon.c \ smbd_opipe_doorsvc.c \ smbd_share_doorsvc.c \ smbd_vss.c @@ -51,7 +51,7 @@ $(ROOTVARSMBDLL):= FILEMODE = 0755 include ../Makefile.smbsrv.defs LDLIBS += -L$(ROOT)/usr/lib/smbsrv -lmlsvc -lmlrpc -lsmbns -lsmb \ - -lzfs -lbsm -lnsl -lumem + -lzfs -lbsm -lsocket -lnsl -lscf -lumem LDFLAGS += -R/usr/lib/smbsrv ROOTSMBDDIR = $(ROOTLIB)/smbsrv diff --git a/usr/src/cmd/smbsrv/smbd/server.xml b/usr/src/cmd/smbsrv/smbd/server.xml index 30bbedd595..e5c45813c6 100644 --- a/usr/src/cmd/smbsrv/smbd/server.xml +++ b/usr/src/cmd/smbsrv/smbd/server.xml @@ -21,8 +21,7 @@ information: Portions Copyright [yyyy] [name of copyright owner] 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. NOTE: This service manifest is not editable; its contents will be overwritten by package or patch operations, including @@ -207,6 +206,8 @@ file. value='false' override='true'/> <propval name='sv_version' type='astring' value='5.0' override='true'/> + <propval name='dfs_stdroot_num' type='integer' + value='0' override='true'/> </property_group> <!-- SMB service-specific shares exec configuration defaults --> diff --git a/usr/src/cmd/smbsrv/smbd/smbd.h b/usr/src/cmd/smbsrv/smbd/smbd.h index 23bba19cbb..00fa2f5ca7 100644 --- a/usr/src/cmd/smbsrv/smbd/smbd.h +++ b/usr/src/cmd/smbsrv/smbd/smbd.h @@ -20,8 +20,7 @@ */ /* - * 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. */ #ifndef _SMBD_H @@ -43,6 +42,9 @@ int smbd_opipe_start(void); void smbd_opipe_stop(void); int smbd_share_start(void); void smbd_share_stop(void); +int smbd_nicmon_start(const char *); +void smbd_nicmon_stop(void); +int smbd_nicmon_refresh(void); boolean_t smbd_set_netlogon_cred(void); int smbd_locate_dc_start(void); smb_token_t *smbd_user_auth_logon(smb_logon_t *); @@ -78,8 +80,12 @@ typedef struct smbd { pthread_t s_nbt_listener_id; pthread_t s_tcp_listener_id; boolean_t s_fatal_error; + smb_log_hdl_t s_loghd; } smbd_t; +#define SMBD_LOGNAME "smbd" +#define SMBD_LOGSIZE 1024 + #define SMBD_DOOR_NAMESZ 16 typedef struct smbd_door { diff --git a/usr/src/cmd/smbsrv/smbd/smbd_doorsvc.c b/usr/src/cmd/smbsrv/smbd/smbd_doorsvc.c index e936029edc..5fb3695a16 100644 --- a/usr/src/cmd/smbsrv/smbd/smbd_doorsvc.c +++ b/usr/src/cmd/smbsrv/smbd/smbd_doorsvc.c @@ -90,6 +90,8 @@ static int smbd_dop_ads_find_host(smbd_arg_t *); static int smbd_dop_quota_query(smbd_arg_t *); static int smbd_dop_quota_set(smbd_arg_t *); static int smbd_dop_dfs_get_referrals(smbd_arg_t *); +static int smbd_dop_shr_hostaccess(smbd_arg_t *); +static int smbd_dop_shr_exec(smbd_arg_t *); typedef int (*smbd_dop_t)(smbd_arg_t *); @@ -114,7 +116,9 @@ smbd_doorop_t smbd_doorops[] = { { SMB_DR_ADS_FIND_HOST, smbd_dop_ads_find_host }, { SMB_DR_QUOTA_QUERY, smbd_dop_quota_query }, { SMB_DR_QUOTA_SET, smbd_dop_quota_set }, - { SMB_DR_DFS_GET_REFERRALS, smbd_dop_dfs_get_referrals } + { SMB_DR_DFS_GET_REFERRALS, smbd_dop_dfs_get_referrals }, + { SMB_DR_SHR_HOSTACCESS, smbd_dop_shr_hostaccess }, + { SMB_DR_SHR_EXEC, smbd_dop_shr_exec } }; static int smbd_ndoorop = (sizeof (smbd_doorops) / sizeof (smbd_doorops[0])); @@ -952,3 +956,56 @@ smbd_dop_dfs_get_referrals(smbd_arg_t *arg) return (SMB_DOP_ENCODE_ERROR); return (SMB_DOP_SUCCESS); } + +static int +smbd_dop_shr_hostaccess(smbd_arg_t *arg) +{ + smb_shr_hostaccess_query_t request; + uint32_t reply; + + bzero(&request, sizeof (request)); + bzero(&reply, sizeof (reply)); + + if (smb_common_decode(arg->data, arg->datalen, + smb_shr_hostaccess_query_xdr, &request) != 0) + return (SMB_DOP_DECODE_ERROR); + + reply = smb_shr_hostaccess(&request.shq_ipaddr, request.shq_none, + request.shq_ro, request.shq_rw, request.shq_flag); + + arg->rbuf = smb_common_encode(&reply, xdr_uint32_t, &arg->rsize); + + xdr_free(smb_shr_hostaccess_query_xdr, (char *)&request); + + if (arg->rbuf == NULL) + return (SMB_DOP_ENCODE_ERROR); + return (SMB_DOP_SUCCESS); +} + +static int +smbd_dop_shr_exec(smbd_arg_t *arg) +{ + smb_shr_execinfo_t request; + int reply; + + bzero(&request, sizeof (request)); + bzero(&reply, sizeof (reply)); + + if (smb_common_decode(arg->data, arg->datalen, + smb_shr_execinfo_xdr, &request) != 0) + return (SMB_DOP_DECODE_ERROR); + + reply = smb_shr_exec(&request); + + if (reply != 0) + syslog(LOG_NOTICE, "Failed to execute %s command", + (request.e_type == SMB_EXEC_MAP) ? "map" : "unmap"); + + arg->rbuf = smb_common_encode(&reply, xdr_int, &arg->rsize); + + xdr_free(smb_shr_execinfo_xdr, (char *)&request); + + if (arg->rbuf == NULL) + return (SMB_DOP_ENCODE_ERROR); + return (SMB_DOP_SUCCESS); +} diff --git a/usr/src/cmd/smbsrv/smbd/smbd_join.c b/usr/src/cmd/smbsrv/smbd/smbd_join.c index a4b57bbeb5..f0bbf9b18c 100644 --- a/usr/src/cmd/smbsrv/smbd/smbd_join.c +++ b/usr/src/cmd/smbsrv/smbd/smbd_join.c @@ -18,9 +18,9 @@ * * 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. */ #include <syslog.h> @@ -35,7 +35,6 @@ #include <smbsrv/libsmbns.h> #include <smbsrv/libmlsvc.h> #include <smbsrv/smbinfo.h> -#include <smbsrv/ntstatus.h> #include "smbd.h" diff --git a/usr/src/cmd/smbsrv/smbd/smbd_main.c b/usr/src/cmd/smbsrv/smbd/smbd_main.c index 72c5b110b8..0d1ba63615 100644 --- a/usr/src/cmd/smbsrv/smbd/smbd_main.c +++ b/usr/src/cmd/smbsrv/smbd/smbd_main.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> @@ -172,11 +171,13 @@ main(int argc, char *argv[]) (void) sigaction(SIGHUP, &act, NULL); (void) sigaction(SIGINT, &act, NULL); (void) sigaction(SIGPIPE, &act, NULL); + (void) sigaction(SIGUSR1, &act, NULL); (void) sigdelset(&set, SIGTERM); (void) sigdelset(&set, SIGHUP); (void) sigdelset(&set, SIGINT); (void) sigdelset(&set, SIGPIPE); + (void) sigdelset(&set, SIGUSR1); if (smbd.s_fg) { (void) sigdelset(&set, SIGTSTP); @@ -223,6 +224,10 @@ main(int argc, char *argv[]) (void) pthread_cond_signal(&refresh_cond); break; + case SIGUSR1: + smb_log_dumpall(); + break; + default: /* * Typically SIGINT or SIGTERM. @@ -465,10 +470,11 @@ smbd_service_init(void) return (-1); } + smbd.s_loghd = smb_log_create(SMBD_LOGSIZE, SMBD_LOGNAME); smb_codepage_init(); - if (smb_nicmon_start(SMBD_DEFAULT_INSTANCE_FMRI) != 0) - smbd_report("NIC monitoring failed to start"); + if (smbd_nicmon_start(SMBD_DEFAULT_INSTANCE_FMRI) != 0) + smbd_report("NIC monitor failed to start"); (void) dyndns_start(); smb_ipc_init(); @@ -583,7 +589,7 @@ smbd_service_fini(void) smbd_share_stop(); smb_shr_stop(); dyndns_stop(); - smb_nicmon_stop(); + smbd_nicmon_stop(); smb_ccache_remove(SMB_CCACHE_PATH); smb_pwd_fini(); smb_domain_fini(); @@ -683,9 +689,8 @@ smbd_refresh_monitor(void *arg) (void) dyndns_start(); dyndns_clear_zones(); - /* re-initialize NIC table */ - if (smb_nic_init() != SMB_NIC_SUCCESS) - smbd_report("failed to get NIC information"); + if (smbd_nicmon_refresh() != 0) + smbd_report("NIC monitor refresh failed"); smb_netbios_name_reconfig(); smb_browser_reconfig(); smbd_refresh_dc(); @@ -742,8 +747,8 @@ smbd_refresh_dc(void) if (smb_getfqdomainname(fqdomain, MAXHOSTNAMELEN)) return; - if (smb_locate_dc(fqdomain, "", NULL)) - smbd_report("DC discovery failed"); + if (!smb_locate_dc(fqdomain, "", NULL)) + smbd_report("DC refresh failed"); } void diff --git a/usr/src/cmd/smbsrv/smbd/smbd_nicmon.c b/usr/src/cmd/smbsrv/smbd/smbd_nicmon.c new file mode 100644 index 0000000000..bc6739843c --- /dev/null +++ b/usr/src/cmd/smbsrv/smbd/smbd_nicmon.c @@ -0,0 +1,323 @@ +/* + * 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) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + */ + +/* + * smbd NIC monitor. + */ + +#include <sys/types.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <stdio.h> +#include <net/if.h> +#include <net/route.h> +#include <sys/sockio.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <fcntl.h> +#include <pthread.h> +#include <syslog.h> +#include <smbsrv/libsmb.h> +#include "smbd.h" + +#define SMBD_NICMON_ENABLE "nicmon_enable" +#define SMBD_NICMON_THROTTLE 100 +#define SMBD_NICMON_DEBOUNCE 2 + +extern smbd_t smbd; + +static boolean_t smbd_nicmon_enabled = B_TRUE; + +/* Use this to stop monitoring */ +static int eventpipe_write = -1; + +/* Use this to refresh service instance */ +static char *smbd_nicmon_caller_fmri = NULL; + +static void smbd_nicmon_run_check(void); +static int smbd_nicmon_setup_rtsock(int); +static int smbd_nicmon_needscan(int); +static int smbd_nicmon_setup_eventpipe(int *, int *); +static void *smbd_nicmon_daemon(void *); + +/* + * Start the nic monitor thread. + */ +int +smbd_nicmon_start(const char *svc_fmri) +{ + pthread_t smbd_nicmon_tid; + int rc; + + if (smb_nic_init() != SMB_NIC_SUCCESS) + return (-1); + + rc = pthread_create(&smbd_nicmon_tid, NULL, smbd_nicmon_daemon, NULL); + if (rc != 0) + return (-1); + + if (svc_fmri) + smbd_nicmon_caller_fmri = (char *)svc_fmri; + + smbd_nicmon_run_check(); + return (0); +} + +void +smbd_nicmon_stop(void) +{ + uchar_t buf = 1; + + if (eventpipe_write < 0) + return; + + (void) write(eventpipe_write, &buf, sizeof (buf)); + smbd_nicmon_caller_fmri = NULL; + smb_nic_fini(); +} + +int +smbd_nicmon_refresh(void) +{ + if (smb_nic_init() != SMB_NIC_SUCCESS) + return (-1); + + smbd_nicmon_run_check(); + return (0); +} + +/* + * The monitor is enabled unless it is explicitly + * disabled by setting smbd/nicmon_enable to false. + * smbd/nicmon_enable is not defined by default. + */ +static void +smbd_nicmon_run_check(void) +{ + smb_scfhandle_t *hd; + uint8_t status; + int rc; + + smbd_nicmon_enabled = B_TRUE; + + if ((hd = smb_smf_scf_init(SMBD_FMRI_PREFIX)) == NULL) { + smb_log(smbd.s_loghd, LOG_DEBUG, + "smbd_nicmon: smb_smf_scf_init failed"); + return; + } + + rc = smb_smf_create_service_pgroup(hd, SMBD_PG_NAME); + if (rc != SMBD_SMF_OK) { + smb_smf_scf_fini(hd); + smb_log(smbd.s_loghd, LOG_DEBUG, + "smbd_nicmon: smb_smf_create_service_pgroup failed"); + return; + } + + rc = smb_smf_get_boolean_property(hd, SMBD_NICMON_ENABLE, &status); + if (rc == SMBD_SMF_OK && status == 0) + smbd_nicmon_enabled = B_FALSE; + + smb_smf_scf_fini(hd); +} + +/* + * Setup routing socket for getting RTM messages. + */ +static int +smbd_nicmon_setup_rtsock(int af) +{ + int sd; + int flags; + + if ((sd = socket(PF_ROUTE, SOCK_RAW, af)) == -1) { + smb_log(smbd.s_loghd, LOG_ERR, + "smbd_nicmon: routing socket failed: %d", errno); + return (-1); + } + + if ((flags = fcntl(sd, F_GETFL, 0)) < 0) { + smb_log(smbd.s_loghd, LOG_ERR, + "smbd_nicmon: fcntl F_GETFL failed: %d", errno); + (void) close(sd); + return (-1); + } + + if ((fcntl(sd, F_SETFL, flags | O_NONBLOCK)) < 0) { + smb_log(smbd.s_loghd, LOG_ERR, + "smbd_nicmon: fcntl F_SETFL failed: %d", errno); + (void) close(sd); + return (-1); + } + + return (sd); +} + +static int +smbd_nicmon_needscan(int sock) +{ + static uint32_t throttle; + struct rt_msghdr *rtm; + int64_t msg[2048 / 8]; + int need_if_scan = 0; + int nbytes; + + /* Read as many messages as possible and try to empty the sockets */ + for (;;) { + nbytes = read(sock, msg, sizeof (msg)); + if (nbytes <= 0) + break; + + rtm = (struct rt_msghdr *)msg; + if (rtm->rtm_version != RTM_VERSION) + continue; + + if (nbytes < rtm->rtm_msglen) { + if ((throttle % SMBD_NICMON_THROTTLE) == 0) { + smb_log(smbd.s_loghd, LOG_DEBUG, + "smbd_nicmon: short read: %d of %d", + nbytes, rtm->rtm_msglen); + } + ++throttle; + continue; + } + + switch (rtm->rtm_type) { + case RTM_NEWADDR: + case RTM_DELADDR: + case RTM_IFINFO: + need_if_scan = 1; + break; + default: + break; + } + } + + return (need_if_scan); +} + +/* + * Create pipe for signal delivery and set up signal handlers. + */ +static int +smbd_nicmon_setup_eventpipe(int *read_pipe, int *write_pipe) +{ + int fds[2]; + + if ((pipe(fds)) < 0) { + smb_log(smbd.s_loghd, LOG_ERR, + "smbd_nicmon: event pipe failed: %d", errno); + return (-1); + } + + *read_pipe = fds[0]; + *write_pipe = fds[1]; + return (0); +} + +/* + * Create the global routing socket to monitor changes in NIC interfaces. + * We are only interested in new inerface addition/deletion and changes + * in UP/DOWN status. + * + * Note: only supports AF_INET routing socket. Need to add AF_INET6 to + * support IPv6. + */ +/*ARGSUSED*/ +static void * +smbd_nicmon_daemon(void *arg) +{ + static uint32_t throttle; + static int rtsock_v4; + static int eventpipe_read = -1; + struct pollfd pollfds[2]; + int pollfd_num = 2; + int i, nic_changed; + int rc; + + if ((rtsock_v4 = smbd_nicmon_setup_rtsock(AF_INET)) == -1) + return (NULL); + + rc = smbd_nicmon_setup_eventpipe(&eventpipe_read, &eventpipe_write); + if (rc != 0) + return (NULL); + + /* + * Listen for activity on any of the sockets. + * The delay before checking the rtsock will hopefully + * smooth things out when there is a lot of activity. + */ + for (;;) { + errno = 0; + nic_changed = 0; + pollfds[0].fd = rtsock_v4; + pollfds[0].events = POLLIN; + pollfds[1].fd = eventpipe_read; + pollfds[1].events = POLLIN; + + if (poll(pollfds, pollfd_num, -1) < 0) { + if (errno == EINTR) + continue; + if ((throttle % SMBD_NICMON_THROTTLE) == 0) + smb_log(smbd.s_loghd, LOG_DEBUG, + "smbd_nicmon: poll failed: %d", errno); + ++throttle; + break; + } + + for (i = 0; i < pollfd_num; i++) { + if ((pollfds[i].fd < 0) || + !(pollfds[i].revents & POLLIN)) + continue; + if (pollfds[i].fd == rtsock_v4) { + (void) sleep(SMBD_NICMON_DEBOUNCE); + nic_changed = smbd_nicmon_needscan(rtsock_v4); + } + if (pollfds[i].fd == eventpipe_read) + goto done; + } + + /* + * If the monitor is enabled and something has changed, + * refresh the registered SMF service. + */ + if (smbd_nicmon_enabled && nic_changed && + smbd_nicmon_caller_fmri) { + if (smf_refresh_instance(smbd_nicmon_caller_fmri) != 0) + smb_log(smbd.s_loghd, LOG_ERR, + "smbd_nicmon: %s refresh failed", + smbd_nicmon_caller_fmri); + } + } +done: + (void) close(rtsock_v4); + (void) close(eventpipe_read); + (void) close(eventpipe_write); + eventpipe_write = -1; + return (NULL); +} diff --git a/usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c b/usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c index 3792e23853..887e8c5b22 100644 --- a/usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c +++ b/usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c @@ -49,7 +49,6 @@ static pthread_mutex_t smb_share_dsrv_mtx = PTHREAD_MUTEX_INITIALIZER; static smbd_door_t smb_share_sdh; static void smbd_share_dispatch(void *, char *, size_t, door_desc_t *, uint_t); -static int smbd_share_enum(smb_enumshare_info_t *esi); /* * Start the LanMan share door service. @@ -145,11 +144,7 @@ smbd_share_dispatch(void *cookie, char *ptr, size_t size, door_desc_t *dp, char *sharename, *sharename2; smb_share_t lmshr_info; smb_shrlist_t lmshr_list; - smb_enumshare_info_t esi; int offset; - smb_inaddr_t ipaddr; - int exec_type; - smb_execsub_info_t subs; smbd_door_enter(&smb_share_sdh); @@ -203,23 +198,6 @@ smbd_share_dispatch(void *cookie, char *ptr, size_t size, door_desc_t *dp, smb_dr_free_string(sharename2); break; - case SMB_SHROP_GETINFO: - sharename = smb_dr_get_string(dec_ctx); - (void) smb_dr_get_buf(dec_ctx, (unsigned char *)&ipaddr, - sizeof (smb_inaddr_t)); - if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) { - smb_dr_free_string(sharename); - goto decode_error; - } - rc = smb_shr_get(sharename, &lmshr_info); - if (rc == NERR_Success) - smb_shr_hostaccess(&lmshr_info, &ipaddr); - smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS); - smb_dr_put_uint32(enc_ctx, rc); - smb_dr_put_share(enc_ctx, &lmshr_info); - smb_dr_free_string(sharename); - break; - case SMB_SHROP_ADD: smb_dr_get_share(dec_ctx, &lmshr_info); if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) @@ -254,59 +232,6 @@ smbd_share_dispatch(void *cookie, char *ptr, size_t size, door_desc_t *dp, sizeof (smb_shrlist_t)); break; - case SMB_SHROP_ENUM: - esi.es_bufsize = smb_dr_get_ushort(dec_ctx); - 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_put_int32(enc_ctx, SMB_SHARE_DSUCCESS); - smb_dr_put_uint32(enc_ctx, rc); - if (rc == NERR_Success) { - smb_dr_put_ushort(enc_ctx, esi.es_ntotal); - smb_dr_put_ushort(enc_ctx, esi.es_nsent); - smb_dr_put_ushort(enc_ctx, esi.es_datasize); - smb_dr_put_buf(enc_ctx, - (unsigned char *)esi.es_buf, esi.es_bufsize); - free(esi.es_buf); - } - break; - - case SMB_SHROP_EXEC: - sharename = smb_dr_get_string(dec_ctx); - subs.e_winname = smb_dr_get_string(dec_ctx); - subs.e_userdom = smb_dr_get_string(dec_ctx); - (void) smb_dr_get_buf(dec_ctx, - (unsigned char *)&subs.e_srv_ipaddr, sizeof (smb_inaddr_t)); - (void) smb_dr_get_buf(dec_ctx, - (unsigned char *)&subs.e_cli_ipaddr, sizeof (smb_inaddr_t)); - subs.e_cli_netbiosname = smb_dr_get_string(dec_ctx); - subs.e_uid = smb_dr_get_int32(dec_ctx); - exec_type = smb_dr_get_int32(dec_ctx); - if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) { - smb_dr_free_string(sharename); - smb_dr_free_string(subs.e_winname); - smb_dr_free_string(subs.e_userdom); - smb_dr_free_string(subs.e_cli_netbiosname); - goto decode_error; - } - - rc = smb_shr_exec(sharename, &subs, exec_type); - - if (rc != 0) - syslog(LOG_NOTICE, "Failed to execute %s command", - (exec_type == SMB_SHR_UNMAP) ? "unmap" : "map"); - - smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS); - smb_dr_put_uint32(enc_ctx, rc); - smb_dr_free_string(sharename); - smb_dr_free_string(subs.e_winname); - smb_dr_free_string(subs.e_userdom); - smb_dr_free_string(subs.e_cli_netbiosname); - break; - default: dec_status = smb_dr_decode_finish(dec_ctx); goto decode_error; @@ -328,109 +253,3 @@ decode_error: (void) smb_dr_encode_finish(enc_ctx, &used); smbd_door_return(&smb_share_sdh, buf, used, NULL, 0); } - -/* - * This function builds a response for a NetShareEnum RAP request which - * originates from smbsrv kernel module. A response buffer is allocated - * with the specified size in esi->es_bufsize. List of shares is scanned - * twice. In the first round the total number of shares which their OEM - * name is shorter than 13 chars (esi->es_ntotal) and also the number of - * shares that fit in the given buffer are calculated. In the second - * round the shares data are encoded in the buffer. - * - * The data associated with each share has two parts, a fixed size part and - * a variable size part which is share's comment. The outline of the response - * buffer is so that fixed part for all the shares will appear first and follows - * with the comments for all those shares and that's why the data cannot be - * encoded in one round without unnecessarily complicating the code. - */ -static int -smbd_share_enum(smb_enumshare_info_t *esi) -{ - smb_shriter_t shi; - smb_share_t *si; - int remained; - uint16_t infolen = 0; - uint16_t cmntlen = 0; - uint16_t sharelen; - uint16_t clen; - uint32_t cmnt_offs; - smb_msgbuf_t info_mb; - smb_msgbuf_t cmnt_mb; - boolean_t autohome_added = B_FALSE; - - esi->es_ntotal = esi->es_nsent = 0; - - if ((esi->es_buf = malloc(esi->es_bufsize)) == NULL) - return (NERR_InternalError); - - bzero(esi->es_buf, esi->es_bufsize); - remained = esi->es_bufsize; - - /* Do the necessary calculations in the first round */ - smb_shr_iterinit(&shi); - - while ((si = smb_shr_iterate(&shi)) != NULL) { - if (si->shr_flags & SMB_SHRF_LONGNAME) - continue; - - if ((si->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) { - if (esi->es_posix_uid == si->shr_uid) - autohome_added = B_TRUE; - else - continue; - } - - esi->es_ntotal++; - - if (remained <= 0) - continue; - - clen = strlen(si->shr_cmnt) + 1; - sharelen = SHARE_INFO_1_SIZE + clen; - - if (sharelen <= remained) { - infolen += SHARE_INFO_1_SIZE; - cmntlen += clen; - } - - remained -= sharelen; - } - - esi->es_datasize = infolen + cmntlen; - - smb_msgbuf_init(&info_mb, (uint8_t *)esi->es_buf, infolen, 0); - smb_msgbuf_init(&cmnt_mb, (uint8_t *)esi->es_buf + infolen, cmntlen, 0); - cmnt_offs = infolen; - - /* Encode the data in the second round */ - smb_shr_iterinit(&shi); - autohome_added = B_FALSE; - - while ((si = smb_shr_iterate(&shi)) != NULL) { - if (si->shr_flags & SMB_SHRF_LONGNAME) - continue; - - if ((si->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) { - if (esi->es_posix_uid == si->shr_uid) - autohome_added = B_TRUE; - else - continue; - } - - if (smb_msgbuf_encode(&info_mb, "13c.wl", - si->shr_oemname, si->shr_type, cmnt_offs) < 0) - break; - - if (smb_msgbuf_encode(&cmnt_mb, "s", si->shr_cmnt) < 0) - break; - - cmnt_offs += strlen(si->shr_cmnt) + 1; - esi->es_nsent++; - } - - smb_msgbuf_term(&info_mb); - smb_msgbuf_term(&cmnt_mb); - - return (NERR_Success); -} diff --git a/usr/src/cmd/smbsrv/smbd/smbd_vss.c b/usr/src/cmd/smbsrv/smbd/smbd_vss.c index c49c541a74..411037b8e6 100644 --- a/usr/src/cmd/smbsrv/smbd/smbd_vss.c +++ b/usr/src/cmd/smbsrv/smbd/smbd_vss.c @@ -18,9 +18,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <synch.h> @@ -35,7 +35,6 @@ #include <smbsrv/libsmbns.h> #include <smbsrv/libmlsvc.h> #include <smbsrv/smbinfo.h> -#include <smbsrv/ntstatus.h> #include "smbd.h" /* diff --git a/usr/src/cmd/smbsrv/smbstat/Makefile b/usr/src/cmd/smbsrv/smbstat/Makefile index c44c076464..64268ccf70 100644 --- a/usr/src/cmd/smbsrv/smbstat/Makefile +++ b/usr/src/cmd/smbsrv/smbstat/Makefile @@ -19,10 +19,7 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" +# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. # PROG= smbstat @@ -34,6 +31,6 @@ OBJS= $(SRCS:%.c=%.o) include ../Makefile.smbsrv.defs -LDLIBS += -lkstat +LDLIBS += -lkstat -lm -lumem include ../Makefile.smbsrv.targ include ../../Makefile.targ diff --git a/usr/src/cmd/smbsrv/smbstat/smbstat.c b/usr/src/cmd/smbsrv/smbstat/smbstat.c index aad8655318..de3773d247 100644 --- a/usr/src/cmd/smbsrv/smbstat/smbstat.c +++ b/usr/src/cmd/smbsrv/smbstat/smbstat.c @@ -20,17 +20,74 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * smbstat: Server Message Block File System statistics + * + * The statistics this CLI displays come from two sources: + * + * 1) The kernel module 'smbsrv'. + * 2) The SMB workers task queue statistics the task queue manager of Solaris + * maintains. + * + * The flow of the code is the following: + * + * + * +----------------+ + * | Initialization | + * +----------------+ + * | + * | + * v + * +--------------------------* + * | Take a snapshot the data | <--------+ + * +--------------------------+ | + * | | + * | | + * v | + * +----------------------+ | + * | Process the snapshot | | + * +----------------------+ | + * | | + * | | + * v | + * +------------------------------------+ | + * | Print the result of the processing | | + * +------------------------------------+ | + * | | + * | | + * v | + * Yes --------------- | + * +------------ < interval == 0 ? > | + * | --------------- | + * | | | + * | | No | + * | v | + * | +------------------------+ | + * | | Sleep for the duration | ----------+ + * | | of the interval. | + * | +------------------------+ + * | + * +---------------------+ + * | + * v + * + * Exit + * + * There are two sets of snapshots. One set for the smbsrv module and the other + * for the task queue (SMB workers). Each set contains 2 snapshots. One is + * labeled 'current' the other one 'previous'. Their role changes after each + * snapshot. The 'current' becomes 'previous' and vice versa. + * The first snapshot taken is compared against the data gathered since the + * smbsrv module was loaded. Subsequent snapshots will be compared against the + * previous snapshot. */ + #include <stdio.h> #include <stdlib.h> +#include <unistd.h> #include <kstat.h> #include <stdarg.h> #include <errno.h> @@ -39,32 +96,216 @@ #include <utility.h> #include <libintl.h> #include <zone.h> +#include <termios.h> +#include <stropts.h> +#include <math.h> +#include <umem.h> +#include <locale.h> #include <smbsrv/smb_kstat.h> -static kstat_ctl_t *kc; /* libkstat cookie */ -static kstat_t *smb_server; -static kstat_t *smb_cmds; +#if !defined(TEXT_DOMAIN) +#define TEXT_DOMAIN "SYS_TEST" +#endif /* TEXT_DOMAIN */ + +#define SMBSTAT_ID_NO_CPU -1 +#define SMBSTAT_SNAPSHOT_COUNT 2 /* Must be a power of 2 */ +#define SMBSTAT_SNAPSHOT_MASK (SMBSTAT_SNAPSHOT_COUNT - 1) + +#define SMBSTAT_HELP \ + "Usage: smbstat [-acnrtuz] [interval]\n" \ + " -c: display counters\n" \ + " -t: display throughput\n" \ + " -u: display utilization\n" \ + " -r: display requests\n" \ + " -a: all the requests (supported and unsupported)\n" \ + " -z: skip the requests not received\n" \ + " -n: display in alphabetic order\n" \ + " interval: refresh cycle in seconds\n" + +#define SMBSRV_COUNTERS_BANNER "\n nbt tcp users trees files pipes\n" +#define SMBSRV_COUNTERS_FORMAT "%5d %5d %5d %5d %5d %5d\n" + +#define SMBSRV_THROUGHPUT_BANNER \ + "\nrbytes/s tbytes/s reqs/s reads/s writes/s\n" +#define SMBSRV_THROUGHPUT_FORMAT \ + "%1.3e %1.3e %1.3e %1.3e %1.3e\n" + +#define SMBSRV_UTILIZATION_BANNER \ + "\n wcnt rcnt wtime rtime" \ + " w%% r%% u%% sat usr%% sys%% idle%%\n" +#define SMBSRV_UTILIZATION_FORMAT \ + "%1.3e %1.3e %1.3e %1.3e %3.0f %3.0f %3.0f %s " \ + "%3.0f %3.0f %3.0f\n" + +#define SMBSRV_REQUESTS_BANNER \ + "\n%30s code %% rbytes/s tbytes/s req/s rt-mean" \ + " rt-stddev\n" +#define SMBSRV_REQUESTS_FORMAT \ + "%30s %02X %3.0f %1.3e %1.3e %1.3e %1.3e %1.3e\n" + +typedef enum { + CPU_TICKS_IDLE = 0, + CPU_TICKS_USER, + CPU_TICKS_KERNEL, + CPU_TICKS_SENTINEL +} cpu_state_idx_t; + +typedef struct smbstat_cpu_snapshot { + processorid_t cs_id; + int cs_state; + uint64_t cs_ticks[CPU_TICKS_SENTINEL]; +} smbstat_cpu_snapshot_t; + +typedef struct smbstat_srv_snapshot { + hrtime_t ss_snaptime; + smbsrv_kstats_t ss_data; +} smbstat_srv_snapshot_t; + +typedef struct smbstat_wrk_snapshot { + uint64_t ws_maxthreads; + uint64_t ws_bnalloc; +} smbstat_wrk_snapshot_t; + +typedef struct smbstat_req_info { + char ri_name[KSTAT_STRLEN]; + int ri_opcode; + double ri_pct; + double ri_tbs; + double ri_rbs; + double ri_rqs; + double ri_stddev; + double ri_mean; +} smbstat_req_info_t; + +typedef struct smbstat_srv_info { + double si_hretime; + double si_etime; + double si_total_nreqs; + /* + * Counters + */ + uint32_t si_nbt_sess; /* NBT sessions */ + uint32_t si_tcp_sess; /* TCP sessions */ + uint32_t si_users; /* Users logged in */ + uint32_t si_trees; /* Trees connected */ + uint32_t si_files; /* Open files */ + uint32_t si_pipes; /* Open pipes */ + /* + * Throughput of the server + */ + double si_tbs; /* Bytes transmitted / second */ + double si_rbs; /* Bytes received / second */ + double si_rqs; /* Requests treated / second */ + double si_rds; /* Reads treated / second */ + double si_wrs; /* Writes treated / second */ + /* + * Utilization of the server + */ + double si_wpct; /* */ + double si_rpct; /* */ + double si_upct; /* Utilization in % */ + double si_avw; /* Average number of requests waiting */ + double si_avr; /* Average number of requests running */ + double si_wserv; /* Average waiting time */ + double si_rserv; /* Average running time */ + boolean_t si_sat; + double si_ticks[CPU_TICKS_SENTINEL]; + /* + * Latency & Throughput per request + */ + smbstat_req_info_t si_reqs[SMB_COM_NUM]; +} smbstat_srv_info_t; -static int get_smbinfo_stat(void); -static int get_smbdispatch_stat(void); static void smbstat_init(void); static void smbstat_fini(void); -static void smbstat_smb_server_print(); -static void smbstat_smb_cmds_print(); -static void smbstat_print(const char *, kstat_t *, int); -static int smbstat_width(kstat_t *, int); +static void smbstat_kstat_snapshot(void); +static void smbstat_kstat_process(void); +static void smbstat_kstat_print(void); + +static void smbstat_print_counters(void); +static void smbstat_print_throughput(void); +static void smbstat_print_utilization(void); +static void smbstat_print_requests(void); + +static void smbstat_cpu_init(void); +static void smbstat_cpu_fini(void); +static smbstat_cpu_snapshot_t *smbstat_cpu_current_snapshot(void); +static smbstat_cpu_snapshot_t *smbstat_cpu_previous_snapshot(void); +static void smbstat_cpu_snapshot(void); +static void smbstat_cpu_process(void); + +static void smbstat_wrk_init(void); +static void smbstat_wrk_fini(void); +static void smbstat_wrk_snapshot(void); +static void smbstat_wrk_process(void); +static smbstat_wrk_snapshot_t *smbstat_wrk_current_snapshot(void); + +static void smbstat_srv_init(void); +static void smbstat_srv_fini(void); +static void smbstat_srv_snapshot(void); +static void smbstat_srv_process(void); +static void smbstat_srv_process_counters(smbstat_srv_snapshot_t *); +static void smbstat_srv_process_throughput(smbstat_srv_snapshot_t *, + smbstat_srv_snapshot_t *); +static void smbstat_srv_process_utilization(smbstat_srv_snapshot_t *, + smbstat_srv_snapshot_t *); +static void smbstat_srv_process_requests(smbstat_srv_snapshot_t *, + smbstat_srv_snapshot_t *); +static smbstat_srv_snapshot_t *smbstat_srv_current_snapshot(void); +static smbstat_srv_snapshot_t *smbstat_srv_previous_snapshot(void); + +static void *smbstat_zalloc(size_t); +static void smbstat_free(void *, size_t); static void smbstat_fail(int, char *, ...); -static kid_t smbstat_kstat_read(kstat_ctl_t *, kstat_t *, void *); -static void smbstat_usage(void); +static void smbstat_snapshot_inc_idx(void); +static void smbstat_usage(FILE *, int); +static uint_t smbstat_strtoi(char const *, char *); +static double smbstat_hrtime_delta(hrtime_t, hrtime_t); +static double smbstat_sub_64(uint64_t, uint64_t); +static void smbstat_req_order(void); +static double smbstat_zero(double); +static void smbstat_termio_init(void); + +#pragma does_not_return(smbstat_fail, smbstat_usage) + +static char *smbstat_cpu_states[CPU_TICKS_SENTINEL] = { + "cpu_ticks_idle", + "cpu_ticks_user", + "cpu_ticks_kernel" +}; -#define MAX_COLUMNS 80 +static boolean_t smbstat_opt_a = B_FALSE; /* all */ +static boolean_t smbstat_opt_c = B_FALSE; /* counters */ +static boolean_t smbstat_opt_n = B_FALSE; /* by name */ +static boolean_t smbstat_opt_u = B_FALSE; /* utilization */ +static boolean_t smbstat_opt_t = B_FALSE; /* throughput */ +static boolean_t smbstat_opt_r = B_FALSE; /* requests */ +static boolean_t smbstat_opt_z = B_FALSE; /* non-zero requests */ +static uint_t smbstat_interval = 0; +static long smbstat_nrcpus = 0; +static kstat_ctl_t *smbstat_ksc = NULL; +static kstat_t *smbstat_srv_ksp = NULL; +static kstat_t *smbstat_wrk_ksp = NULL; +static struct winsize smbstat_ws; +static uint16_t smbstat_rows = 0; + +static int smbstat_snapshot_idx = 0; +static smbstat_cpu_snapshot_t *smbstat_cpu_snapshots[SMBSTAT_SNAPSHOT_COUNT]; +static smbstat_srv_snapshot_t smbstat_srv_snapshots[SMBSTAT_SNAPSHOT_COUNT]; +static smbstat_wrk_snapshot_t smbstat_wrk_snapshots[SMBSTAT_SNAPSHOT_COUNT]; +static smbstat_srv_info_t smbstat_srv_info; + +/* + * main + */ int main(int argc, char *argv[]) { - int c; - int iflag = 0; /* smb_server stats */ - int dflag = 0; /* smb_cmds_all stats */ + int c; + + (void) setlocale(LC_ALL, ""); + (void) textdomain(TEXT_DOMAIN); if (getzoneid() != GLOBAL_ZONEID) { (void) fprintf(stderr, @@ -80,192 +321,781 @@ main(int argc, char *argv[]) return (0); } - while ((c = getopt(argc, argv, "id")) != EOF) { + while ((c = getopt(argc, argv, "achnrtuz")) != EOF) { switch (c) { - case 'i': - iflag++; + case 'a': + smbstat_opt_a = B_TRUE; break; - case 'd': - dflag++; + case 'n': + smbstat_opt_n = B_TRUE; break; - case '?': + case 'u': + smbstat_opt_u = B_TRUE; + break; + case 'c': + smbstat_opt_c = B_TRUE; + break; + case 'r': + smbstat_opt_r = B_TRUE; + break; + case 't': + smbstat_opt_t = B_TRUE; + break; + case 'z': + smbstat_opt_z = B_TRUE; + break; + case 'h': + smbstat_usage(stdout, 0); default: - smbstat_usage(); + smbstat_usage(stderr, 1); } } - if ((argc - optind) > 0) { - smbstat_usage(); + if (!smbstat_opt_u && + !smbstat_opt_c && + !smbstat_opt_r && + !smbstat_opt_t) { + /* Default options when none is specified. */ + smbstat_opt_u = B_TRUE; + smbstat_opt_t = B_TRUE; } - smbstat_init(); - - if (iflag) { - smbstat_smb_server_print(); - } else if (dflag) { - smbstat_smb_cmds_print(); - } else { - smbstat_smb_server_print(); - smbstat_smb_cmds_print(); + if (optind < argc) { + smbstat_interval = + smbstat_strtoi(argv[optind], "invalid count"); + optind++; } - smbstat_fini(); + if ((argc - optind) > 1) + smbstat_usage(stderr, 1); + + (void) atexit(smbstat_fini); + smbstat_init(); + for (;;) { + smbstat_kstat_snapshot(); + smbstat_kstat_process(); + smbstat_kstat_print(); + if (smbstat_interval == 0) + break; + (void) sleep(smbstat_interval); + smbstat_snapshot_inc_idx(); + } return (0); } +/* + * smbstat_init + * + * Global initialization. + */ +static void +smbstat_init(void) +{ + if ((smbstat_ksc = kstat_open()) == NULL) + smbstat_fail(1, gettext("kstat_open(): can't open /dev/kstat")); -static int -get_smbinfo_stat(void) + smbstat_cpu_init(); + smbstat_srv_init(); + smbstat_wrk_init(); + smbstat_req_order(); +} + +/* + * smbstat_fini + * + * Releases the resources smbstat_init() allocated. + */ +static void +smbstat_fini(void) { - (void) smbstat_kstat_read(kc, smb_server, NULL); - return (smbstat_width(smb_server, 0)); + smbstat_wrk_fini(); + smbstat_srv_fini(); + smbstat_cpu_fini(); + (void) kstat_close(smbstat_ksc); } -static int -get_smbdispatch_stat(void) +/* + * smbstat_kstat_snapshot + * + * Takes a snapshot of the data. + */ +static void +smbstat_kstat_snapshot(void) +{ + smbstat_cpu_snapshot(); + smbstat_srv_snapshot(); + smbstat_wrk_snapshot(); +} + +/* + * smbstat_kstat_process + */ +static void +smbstat_kstat_process(void) +{ + smbstat_cpu_process(); + smbstat_srv_process(); + smbstat_wrk_process(); +} + +/* + * smbstat_kstat_print + * + * Print the data processed. + */ +static void +smbstat_kstat_print(void) +{ + smbstat_termio_init(); + smbstat_print_counters(); + smbstat_print_throughput(); + smbstat_print_utilization(); + smbstat_print_requests(); +} + +/* + * smbstat_print_counters + * + * Displays the SMB server counters (session, users...). + */ +static void +smbstat_print_counters(void) +{ + if (!smbstat_opt_c) + return; + + if (smbstat_opt_u || smbstat_opt_r || smbstat_opt_t || + (smbstat_rows == 0) || (smbstat_rows >= smbstat_ws.ws_row)) { + (void) printf(SMBSRV_COUNTERS_BANNER); + smbstat_rows = 1; + } + + (void) printf(SMBSRV_COUNTERS_FORMAT, + smbstat_srv_info.si_nbt_sess, + smbstat_srv_info.si_tcp_sess, + smbstat_srv_info.si_users, + smbstat_srv_info.si_trees, + smbstat_srv_info.si_files, + smbstat_srv_info.si_pipes); + + ++smbstat_rows; +} +/* + * smbstat_print_throughput + * + * Formats the SMB server throughput output. + */ +static void +smbstat_print_throughput(void) +{ + if (!smbstat_opt_t) + return; + + if (smbstat_opt_u || smbstat_opt_r || smbstat_opt_c || + (smbstat_rows == 0) || (smbstat_rows >= smbstat_ws.ws_row)) { + (void) printf(SMBSRV_THROUGHPUT_BANNER); + smbstat_rows = 1; + } + (void) printf(SMBSRV_THROUGHPUT_FORMAT, + smbstat_zero(smbstat_srv_info.si_rbs), + smbstat_zero(smbstat_srv_info.si_tbs), + smbstat_zero(smbstat_srv_info.si_rqs), + smbstat_zero(smbstat_srv_info.si_rds), + smbstat_zero(smbstat_srv_info.si_wrs)); + + ++smbstat_rows; +} + +/* + * smbstat_print_utilization + */ +static void +smbstat_print_utilization(void) { - (void) smbstat_kstat_read(kc, smb_cmds, NULL); - return (smbstat_width(smb_cmds, 0)); + char *sat; + if (!smbstat_opt_u) + return; + + if (smbstat_opt_t || smbstat_opt_r || smbstat_opt_c || + (smbstat_rows == 0) || (smbstat_rows >= smbstat_ws.ws_row)) { + (void) printf(SMBSRV_UTILIZATION_BANNER); + smbstat_rows = 1; + } + + if (smbstat_srv_info.si_sat) + sat = "yes"; + else + sat = "no "; + + (void) printf(SMBSRV_UTILIZATION_FORMAT, + smbstat_srv_info.si_avw, + smbstat_srv_info.si_avr, + smbstat_srv_info.si_wserv, + smbstat_srv_info.si_rserv, + smbstat_zero(smbstat_srv_info.si_wpct), + smbstat_zero(smbstat_srv_info.si_rpct), + smbstat_zero(smbstat_srv_info.si_upct), + sat, + smbstat_srv_info.si_ticks[CPU_TICKS_USER], + smbstat_srv_info.si_ticks[CPU_TICKS_KERNEL], + smbstat_srv_info.si_ticks[CPU_TICKS_IDLE]); + + ++smbstat_rows; } +/* + * smbstat_print_requests + */ static void -smbstat_smb_server_print() +smbstat_print_requests(void) { - int field_width; - int i, j, nreq, ncolumns; - char fixlen[128]; - kstat_named_t *knp; + smbstat_req_info_t *prq; + int i; - field_width = get_smbinfo_stat(); - if (field_width == 0) + if (!smbstat_opt_r) return; - (void) printf("%s\n", "\nSMB Info:\n"); - ncolumns = (MAX_COLUMNS -1)/field_width; + prq = smbstat_srv_info.si_reqs; + + (void) printf(SMBSRV_REQUESTS_BANNER, " "); - knp = KSTAT_NAMED_PTR(smb_server); - nreq = smb_server->ks_ndata; + for (i = 0; i < SMB_COM_NUM; i++) { + if (!smbstat_opt_a && + strncmp(prq[i].ri_name, "Invalid", sizeof ("Invalid")) == 0) + continue; - for (i = 0; i < nreq; i += ncolumns) { - /* prints out the titles of the columns */ - for (j = i; j < MIN(i + ncolumns, nreq); j++) { - (void) printf("%-*s", field_width, knp[j].name); + if (!smbstat_opt_z || (prq[i].ri_pct != 0)) { + (void) printf(SMBSRV_REQUESTS_FORMAT, + prq[i].ri_name, + prq[i].ri_opcode, + smbstat_zero(prq[i].ri_pct), + smbstat_zero(prq[i].ri_rbs), + smbstat_zero(prq[i].ri_tbs), + smbstat_zero(prq[i].ri_rqs), + prq[i].ri_mean, + prq[i].ri_stddev); } - (void) printf("\n"); - /* prints out the stat numbers */ - for (j = i; j < MIN(i + ncolumns, nreq); j++) { - (void) sprintf(fixlen, "%" PRIu32 " ", - knp[j].value.ui32); - (void) printf("%-*s", field_width, fixlen); + } +} + +/* + * smbstat_cpu_init + */ +static void +smbstat_cpu_init(void) +{ + size_t size; + int i; + + smbstat_nrcpus = sysconf(_SC_CPUID_MAX) + 1; + size = smbstat_nrcpus * sizeof (smbstat_cpu_snapshot_t); + + for (i = 0; i < SMBSTAT_SNAPSHOT_COUNT; i++) + smbstat_cpu_snapshots[i] = smbstat_zalloc(size); +} + +/* + * smbstat_cpu_fini + */ +static void +smbstat_cpu_fini(void) +{ + size_t size; + int i; + + size = smbstat_nrcpus * sizeof (smbstat_cpu_snapshot_t); + + for (i = 0; i < SMBSTAT_SNAPSHOT_COUNT; i++) + smbstat_free(smbstat_cpu_snapshots[i], size); +} + +/* + * smbstat_cpu_current_snapshot + */ +static smbstat_cpu_snapshot_t * +smbstat_cpu_current_snapshot(void) +{ + return (smbstat_cpu_snapshots[smbstat_snapshot_idx]); +} + +/* + * smbstat_cpu_previous_snapshot + */ +static smbstat_cpu_snapshot_t * +smbstat_cpu_previous_snapshot(void) +{ + int idx; + + idx = (smbstat_snapshot_idx - 1) & SMBSTAT_SNAPSHOT_MASK; + return (smbstat_cpu_snapshots[idx]); +} + +/* + * smbstat_cpu_snapshot + */ +static void +smbstat_cpu_snapshot(void) +{ + kstat_t *ksp; + kstat_named_t *ksn; + smbstat_cpu_snapshot_t *curr; + long i; + int j; + + curr = smbstat_cpu_current_snapshot(); + + for (i = 0; i < smbstat_nrcpus; i++, curr++) { + curr->cs_id = SMBSTAT_ID_NO_CPU; + curr->cs_state = p_online(i, P_STATUS); + /* If no valid CPU is present, move on to the next one */ + if (curr->cs_state == -1) + continue; + + curr->cs_id = i; + + ksp = kstat_lookup(smbstat_ksc, "cpu", i, "sys"); + if (ksp == NULL) + smbstat_fail(1, + gettext("kstat_lookup('cpu sys %d') failed"), i); + + if (kstat_read(smbstat_ksc, ksp, NULL) == -1) + smbstat_fail(1, + gettext("kstat_read('cpu sys %d') failed"), i); + + for (j = 0; j < CPU_TICKS_SENTINEL; j++) { + ksn = kstat_data_lookup(ksp, smbstat_cpu_states[j]); + if (ksn == NULL) + smbstat_fail(1, + gettext("kstat_data_lookup('%s') failed"), + smbstat_cpu_states[j]); + curr->cs_ticks[j] = ksn->value.ui64; } - (void) printf("\n"); } } +/* + * smbstat_cpu_process + */ static void -smbstat_smb_cmds_print() +smbstat_cpu_process(void) { - int field_width; + smbstat_cpu_snapshot_t *curr, *prev; + double total_ticks; + double agg_ticks[CPU_TICKS_SENTINEL]; + int i, j; - field_width = get_smbdispatch_stat(); - if (field_width == 0) - return; + curr = smbstat_cpu_current_snapshot(); + prev = smbstat_cpu_previous_snapshot(); + bzero(agg_ticks, sizeof (agg_ticks)); + total_ticks = 0; - smbstat_print(gettext("\nAll dispatched SMB requests statistics:\n"), - smb_cmds, field_width); + for (i = 0; i < smbstat_nrcpus; i++, curr++, prev++) { + for (j = 0; j < CPU_TICKS_SENTINEL; j++) { + agg_ticks[j] += smbstat_sub_64(curr->cs_ticks[j], + prev->cs_ticks[j]); + total_ticks += smbstat_sub_64(curr->cs_ticks[j], + prev->cs_ticks[j]); + } + } + + for (j = 0; j < CPU_TICKS_SENTINEL; j++) + smbstat_srv_info.si_ticks[j] = + (agg_ticks[j] * 100.0) / total_ticks; } +/* + * smbstat_wrk_init + */ static void -smbstat_init(void) +smbstat_wrk_init(void) { - char smbsrv_name[KSTAT_STRLEN]; + smbstat_wrk_ksp = + kstat_lookup(smbstat_ksc, "unix", -1, SMBSRV_KSTAT_WORKERS); + if (smbstat_wrk_ksp == NULL) + smbstat_fail(1, + gettext("cannot retrieve smbsrv workers kstat\n")); +} - (void) snprintf(smbsrv_name, sizeof (smbsrv_name), "%s%d", - SMBSRV_KSTAT_NAME, getzoneid()); +static void +smbstat_wrk_fini(void) +{ + smbstat_wrk_ksp = NULL; +} - if ((kc = kstat_open()) == NULL) - smbstat_fail(1, gettext("kstat_open(): can't open /dev/kstat")); +/* + * smbstat_wrk_snapshot + */ +static void +smbstat_wrk_snapshot(void) +{ + smbstat_wrk_snapshot_t *curr; + kstat_named_t *kn; - smb_server = kstat_lookup(kc, SMBSRV_KSTAT_MODULE, 0, smbsrv_name); - smb_cmds = kstat_lookup(kc, SMBSRV_KSTAT_MODULE, 0, - SMBSRV_KSTAT_NAME_CMDS); + curr = smbstat_wrk_current_snapshot(); - if ((smb_server == NULL) || (smb_cmds == NULL)) - smbstat_fail(0, gettext("kstat lookups failed for smb. " - "Your kernel module may not be loaded\n")); + if (kstat_read(smbstat_ksc, smbstat_wrk_ksp, NULL) == -1) + smbstat_fail(1, gettext("kstat_read('%s') failed"), + smbstat_wrk_ksp->ks_name); + + kn = kstat_data_lookup(smbstat_wrk_ksp, "maxthreads"); + if ((kn == NULL) || (kn->data_type != KSTAT_DATA_UINT64)) + smbstat_fail(1, gettext("kstat_read('%s') failed"), + "maxthreads"); + curr->ws_maxthreads = kn->value.ui64; + + kn = kstat_data_lookup(smbstat_wrk_ksp, "bnalloc"); + if ((kn == NULL) || (kn->data_type != KSTAT_DATA_UINT64)) + smbstat_fail(1, gettext("kstat_read('%s') failed"), + "bnalloc"); + curr->ws_bnalloc = kn->value.ui64; } +/* + * smbstat_wrk_process + */ static void -smbstat_fini(void) +smbstat_wrk_process(void) { - (void) kstat_close(kc); + smbstat_wrk_snapshot_t *curr; + + curr = smbstat_wrk_current_snapshot(); + + if (curr->ws_maxthreads >= curr->ws_bnalloc) + smbstat_srv_info.si_sat = B_TRUE; + else + smbstat_srv_info.si_sat = B_FALSE; } -static int -smbstat_width(kstat_t *req, int field_width) -{ - int i, nreq, len; - char fixlen[128]; - kstat_named_t *knp; - - knp = KSTAT_NAMED_PTR(req); - nreq = req->ks_ndata; - - for (i = 0; i < nreq; i++) { - len = strlen(knp[i].name) + 1; - if (field_width < len) - field_width = len; - (void) sprintf(fixlen, "%" PRIu64, knp[i].value.ui64); - len = strlen(fixlen) + 1; - if (field_width < len) - field_width = len; +/* + * smbstat_wrk_current_snapshot + */ +static smbstat_wrk_snapshot_t * +smbstat_wrk_current_snapshot(void) +{ + return (&smbstat_wrk_snapshots[smbstat_snapshot_idx]); +} + +/* + * smbstat_srv_init + */ +static void +smbstat_srv_init(void) +{ + smbstat_srv_ksp = kstat_lookup(smbstat_ksc, SMBSRV_KSTAT_MODULE, + getzoneid(), SMBSRV_KSTAT_STATISTICS); + if (smbstat_srv_ksp == NULL) + smbstat_fail(1, gettext("cannot retrieve smbsrv kstat\n")); +} + +/* + * smbstat_srv_fini + */ +static void +smbstat_srv_fini(void) +{ + smbstat_srv_ksp = NULL; +} + +/* + * smbstat_srv_snapshot + * + * Take a snapshot of the smbsrv module statistics. + */ +static void +smbstat_srv_snapshot(void) +{ + smbstat_srv_snapshot_t *curr; + + curr = smbstat_srv_current_snapshot(); + + if ((kstat_read(smbstat_ksc, smbstat_srv_ksp, NULL) == -1) || + (smbstat_srv_ksp->ks_data_size != sizeof (curr->ss_data))) + smbstat_fail(1, gettext("kstat_read('%s') failed"), + smbstat_srv_ksp->ks_name); + + curr->ss_snaptime = smbstat_srv_ksp->ks_snaptime; + bcopy(smbstat_srv_ksp->ks_data, &curr->ss_data, sizeof (curr->ss_data)); +} + +/* + * smbstat_srv_process + * + * Processes the snapshot data. + */ +static void +smbstat_srv_process(void) +{ + smbstat_srv_snapshot_t *curr, *prev; + + curr = smbstat_srv_current_snapshot(); + prev = smbstat_srv_previous_snapshot(); + + if (prev->ss_snaptime == 0) + smbstat_srv_info.si_hretime = + smbstat_hrtime_delta(curr->ss_data.ks_start_time, + curr->ss_snaptime); + else + smbstat_srv_info.si_hretime = + smbstat_hrtime_delta(prev->ss_snaptime, curr->ss_snaptime); + + smbstat_srv_info.si_etime = smbstat_srv_info.si_hretime / NANOSEC; + smbstat_srv_info.si_total_nreqs = + smbstat_sub_64(curr->ss_data.ks_nreq, prev->ss_data.ks_nreq); + + if (smbstat_opt_c) + smbstat_srv_process_counters(curr); + if (smbstat_opt_t) + smbstat_srv_process_throughput(curr, prev); + if (smbstat_opt_u) + smbstat_srv_process_utilization(curr, prev); + if (smbstat_opt_r) + smbstat_srv_process_requests(curr, prev); +} + +/* + * smbstat_srv_process_counters + */ +static void +smbstat_srv_process_counters(smbstat_srv_snapshot_t *curr) +{ + smbstat_srv_info.si_nbt_sess = curr->ss_data.ks_nbt_sess; + smbstat_srv_info.si_tcp_sess = curr->ss_data.ks_tcp_sess; + smbstat_srv_info.si_users = curr->ss_data.ks_users; + smbstat_srv_info.si_trees = curr->ss_data.ks_trees; + smbstat_srv_info.si_files = curr->ss_data.ks_files; + smbstat_srv_info.si_pipes = curr->ss_data.ks_pipes; +} + +/* + * smbstat_srv_process_throughput + * + * Processes the data relative to the throughput of the smbsrv module and + * stores the results in the structure smbstat_srv_info. + */ +static void +smbstat_srv_process_throughput( + smbstat_srv_snapshot_t *curr, + smbstat_srv_snapshot_t *prev) +{ + smbstat_srv_info.si_tbs = + smbstat_sub_64(curr->ss_data.ks_txb, prev->ss_data.ks_txb); + smbstat_srv_info.si_tbs /= smbstat_srv_info.si_etime; + smbstat_srv_info.si_rbs = + smbstat_sub_64(curr->ss_data.ks_rxb, prev->ss_data.ks_rxb); + smbstat_srv_info.si_rbs /= smbstat_srv_info.si_etime; + smbstat_srv_info.si_rqs = smbstat_srv_info.si_total_nreqs; + smbstat_srv_info.si_rqs /= smbstat_srv_info.si_etime; + + smbstat_srv_info.si_rds = smbstat_sub_64( + curr->ss_data.ks_reqs[SMB_COM_READ].kr_nreq, + prev->ss_data.ks_reqs[SMB_COM_READ].kr_nreq); + smbstat_srv_info.si_rds += smbstat_sub_64( + curr->ss_data.ks_reqs[SMB_COM_LOCK_AND_READ].kr_nreq, + prev->ss_data.ks_reqs[SMB_COM_LOCK_AND_READ].kr_nreq); + smbstat_srv_info.si_rds += smbstat_sub_64( + curr->ss_data.ks_reqs[SMB_COM_READ_RAW].kr_nreq, + prev->ss_data.ks_reqs[SMB_COM_READ_RAW].kr_nreq); + smbstat_srv_info.si_rds += smbstat_sub_64( + curr->ss_data.ks_reqs[SMB_COM_READ_ANDX].kr_nreq, + prev->ss_data.ks_reqs[SMB_COM_READ_ANDX].kr_nreq); + smbstat_srv_info.si_rds /= smbstat_srv_info.si_etime; + + smbstat_srv_info.si_wrs = smbstat_sub_64( + curr->ss_data.ks_reqs[SMB_COM_WRITE].kr_nreq, + prev->ss_data.ks_reqs[SMB_COM_WRITE].kr_nreq); + smbstat_srv_info.si_wrs += smbstat_sub_64( + curr->ss_data.ks_reqs[SMB_COM_WRITE_AND_UNLOCK].kr_nreq, + prev->ss_data.ks_reqs[SMB_COM_WRITE_AND_UNLOCK].kr_nreq); + smbstat_srv_info.si_wrs += smbstat_sub_64( + curr->ss_data.ks_reqs[SMB_COM_WRITE_RAW].kr_nreq, + prev->ss_data.ks_reqs[SMB_COM_WRITE_RAW].kr_nreq); + smbstat_srv_info.si_wrs += smbstat_sub_64( + curr->ss_data.ks_reqs[SMB_COM_WRITE_AND_CLOSE].kr_nreq, + prev->ss_data.ks_reqs[SMB_COM_WRITE_AND_CLOSE].kr_nreq); + smbstat_srv_info.si_wrs += smbstat_sub_64( + curr->ss_data.ks_reqs[SMB_COM_WRITE_ANDX].kr_nreq, + prev->ss_data.ks_reqs[SMB_COM_WRITE_ANDX].kr_nreq); + smbstat_srv_info.si_wrs /= smbstat_srv_info.si_etime; +} + +/* + * smbstat_srv_process_utilization + * + * Processes the data relative to the utilization of the smbsrv module and + * stores the results in the structure smbstat_srv_info. + */ +static void +smbstat_srv_process_utilization( + smbstat_srv_snapshot_t *curr, + smbstat_srv_snapshot_t *prev) +{ + double tw_delta, tr_delta; + double w_delta, r_delta; + double tps, rqs; + + w_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_wlentime, + curr->ss_data.ks_utilization.ku_wlentime); + r_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_rlentime, + curr->ss_data.ks_utilization.ku_rlentime); + tw_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_wtime, + curr->ss_data.ks_utilization.ku_wtime); + tr_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_rtime, + curr->ss_data.ks_utilization.ku_rtime); + rqs = smbstat_srv_info.si_total_nreqs / smbstat_srv_info.si_etime; + + /* Average number of requests waiting */ + if (w_delta != 0) + smbstat_srv_info.si_avw = w_delta / smbstat_srv_info.si_hretime; + else + smbstat_srv_info.si_avw = 0.0; + + /* Average number of request running */ + if (r_delta != 0) + smbstat_srv_info.si_avr = r_delta / smbstat_srv_info.si_hretime; + else + smbstat_srv_info.si_avr = 0.0; + + /* Utilization */ + smbstat_srv_info.si_upct = + (smbstat_srv_info.si_avr / curr->ss_data.ks_maxreqs) * 100; + + /* Average wait service time in milliseconds */ + smbstat_srv_info.si_rserv = 0.0; + smbstat_srv_info.si_wserv = 0.0; + if (rqs > 0.0 && + (smbstat_srv_info.si_avw != 0.0 || + smbstat_srv_info.si_avr != 0.0)) { + tps = 1 / rqs; + if (smbstat_srv_info.si_avw != 0.0) + smbstat_srv_info.si_wserv = + smbstat_srv_info.si_avw * tps; + if (smbstat_srv_info.si_avr != 0.0) + smbstat_srv_info.si_rserv = + smbstat_srv_info.si_avr * tps; + } + + /* % of time there is a transaction waiting for service */ + if (tw_delta != 0) { + smbstat_srv_info.si_wpct = tw_delta; + smbstat_srv_info.si_wpct /= smbstat_srv_info.si_hretime; + smbstat_srv_info.si_wpct *= 100.0; + } else { + smbstat_srv_info.si_wpct = 0.0; + } + + /* % of time there is a transaction running */ + if (tr_delta != 0) { + smbstat_srv_info.si_rpct = tr_delta; + smbstat_srv_info.si_rpct /= smbstat_srv_info.si_hretime; + smbstat_srv_info.si_rpct *= 100.0; + } else { + smbstat_srv_info.si_rpct = 0.0; } - return (field_width); } +/* + * smbstat_srv_process_requests + * + * Processes the data relative to the SMB requests and stores the results in + * the structure smbstat_srv_info. + */ static void -smbstat_print(const char *title_string, kstat_t *req, int field_width) +smbstat_srv_process_requests( + smbstat_srv_snapshot_t *curr, + smbstat_srv_snapshot_t *prev) { - int i, j, nreq, ncolumns; - char fixlen[128]; - kstat_named_t *knp; + smbstat_req_info_t *info; + double nrqs; + int i, idx; - if (req == NULL) - return; + info = smbstat_srv_info.si_reqs; - if (field_width == 0) - return; + for (i = 0; i < SMB_COM_NUM; i++) { + idx = info[i].ri_opcode; + + nrqs = smbstat_sub_64(curr->ss_data.ks_reqs[idx].kr_nreq, + prev->ss_data.ks_reqs[idx].kr_nreq); + + info[i].ri_rqs = nrqs / smbstat_srv_info.si_etime; - (void) printf("%s\n", title_string); - ncolumns = (MAX_COLUMNS -1)/field_width; + info[i].ri_rbs = smbstat_sub_64( + curr->ss_data.ks_reqs[idx].kr_rxb, + prev->ss_data.ks_reqs[idx].kr_rxb) / + smbstat_srv_info.si_etime; - knp = KSTAT_NAMED_PTR(req); - nreq = req->ks_ndata; + info[i].ri_tbs = smbstat_sub_64( + curr->ss_data.ks_reqs[idx].kr_txb, + prev->ss_data.ks_reqs[idx].kr_txb) / + smbstat_srv_info.si_etime; - for (i = 0; i < nreq; i += ncolumns) { - /* prints out the titles of the columns */ - for (j = i; j < MIN(i + ncolumns, nreq); j++) { - (void) printf("%-*s", field_width, knp[j].name); + info[i].ri_pct = nrqs * 100; + if (smbstat_srv_info.si_total_nreqs > 0) + info[i].ri_pct /= smbstat_srv_info.si_total_nreqs; + + if (prev->ss_snaptime == 0) { + /* First time. Take the aggregate */ + info[i].ri_stddev = + curr->ss_data.ks_reqs[idx].kr_a_stddev; + info[i].ri_mean = curr->ss_data.ks_reqs[idx].kr_a_mean; + } else { + /* Take the differential */ + info[i].ri_stddev = + curr->ss_data.ks_reqs[idx].kr_d_stddev; + info[i].ri_mean = curr->ss_data.ks_reqs[idx].kr_d_mean; } - (void) printf("\n"); - /* prints out the stat numbers */ - for (j = i; j < MIN(i + ncolumns, nreq); j++) { - (void) sprintf(fixlen, "%" PRIu64 " ", - knp[j].value.ui64); - (void) printf("%-*s", field_width, fixlen); + if (nrqs > 0) { + info[i].ri_stddev /= nrqs; + info[i].ri_stddev = sqrt(info[i].ri_stddev); + } else { + info[i].ri_stddev = 0; } - (void) printf("\n"); - + info[i].ri_stddev /= NANOSEC; + info[i].ri_mean /= NANOSEC; } } +/* + * smbstat_srv_current_snapshot + * + * Returns the current snapshot. + */ +static smbstat_srv_snapshot_t * +smbstat_srv_current_snapshot(void) +{ + return (&smbstat_srv_snapshots[smbstat_snapshot_idx]); +} + +/* + * smbstat_srv_previous_snapshot + * + * Returns the previous snapshot. + */ +static smbstat_srv_snapshot_t * +smbstat_srv_previous_snapshot(void) +{ + int idx; + + idx = (smbstat_snapshot_idx - 1) & SMBSTAT_SNAPSHOT_MASK; + return (&smbstat_srv_snapshots[idx]); +} + +/* + * smbstat_usage + * + * Prints out a help message. + */ static void -smbstat_usage(void) +smbstat_usage(FILE *fd, int exit_code) { - (void) fprintf(stderr, gettext("Usage: smbstat [-id]\n")); - exit(1); + (void) fprintf(fd, gettext(SMBSTAT_HELP)); + exit(exit_code); } +/* + * smbstat_fail + * + * Prints out to stderr an error message and exits the process. + */ static void smbstat_fail(int do_perror, char *message, ...) { @@ -282,30 +1112,196 @@ smbstat_fail(int do_perror, char *message, ...) exit(1); } -static kid_t -smbstat_kstat_read(kstat_ctl_t *kc, kstat_t *ksp, void *data) +/* + * smbstat_sub_64 + * + * Substract 2 uint64_t and returns a double. + */ +static double +smbstat_sub_64(uint64_t a, uint64_t b) { - kid_t kstat_chain_id = kstat_read(kc, ksp, data); + return ((double)(a - b)); +} - if (kstat_chain_id == -1) - smbstat_fail(1, gettext("kstat_read('%s') failed"), - ksp->ks_name); - return (kstat_chain_id); +/* + * smbstat_zero + * + * Returns zero if the value passed in is less than 1. + */ +static double +smbstat_zero(double value) +{ + if (value < 1) + value = 0; + return (value); +} + +/* + * smbstat_strtoi + * + * Converts a string representing an integer value into its binary value. + * If the conversion fails this routine exits the process. + */ +static uint_t +smbstat_strtoi(char const *val, char *errmsg) +{ + char *end; + long tmp; + + errno = 0; + tmp = strtol(val, &end, 10); + if (*end != '\0' || errno) + smbstat_fail(1, "%s %s", errmsg, val); + return ((uint_t)tmp); +} + +/* + * smbstat_termio_init + * + * Determines the size of the terminal associated with the process. + */ +static void +smbstat_termio_init(void) +{ + char *envp; + + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &smbstat_ws) != -1) { + if (smbstat_ws.ws_row == 0) { + envp = getenv("LINES"); + if (envp != NULL) + smbstat_ws.ws_row = atoi(envp); + } + + if (smbstat_ws.ws_col == 0) { + envp = getenv("COLUMNS"); + if (envp != NULL) + smbstat_ws.ws_row = atoi(envp); + } + } + if (smbstat_ws.ws_col == 0) + smbstat_ws.ws_col = 80; + if (smbstat_ws.ws_row == 0) + smbstat_ws.ws_row = 25; +} + +/* + * smbstat_snapshot_idx_inc + * + * Increments the snapshot index. + */ +static void +smbstat_snapshot_inc_idx(void) +{ + smbstat_snapshot_idx++; + smbstat_snapshot_idx &= SMBSTAT_SNAPSHOT_MASK; } /* - * Enable libumem debugging by default on DEBUG builds. + * smbstat_req_cmp_name + * + * Call back function passed to qsort() when the list of requests must be sorted + * by name. */ -#ifdef DEBUG -const char * -_umem_debug_init(void) +static int +smbstat_req_cmp_name(const void *obj1, const void *obj2) { - return ("default,verbose"); /* $UMEM_DEBUG setting */ + return (strncasecmp( + ((smbstat_req_info_t *)obj1)->ri_name, + ((smbstat_req_info_t *)obj2)->ri_name, + sizeof (((smbstat_req_info_t *)obj2)->ri_name))); } -const char * -_umem_logging_init(void) +/* + * smbstat_req_order + * + * Snapshots the smbsrv module statistics once to get the name of the requests. + * The request list is smbstat_srv_info is then sorted by name or by code + * depending on the boolean smbstat_opt_a. + * The function should be called once during initialization. + */ +static void +smbstat_req_order(void) +{ + smbstat_req_info_t *info; + smb_kstat_req_t *reqs; + int i; + + smbstat_srv_snapshot(); + reqs = smbstat_srv_current_snapshot()->ss_data.ks_reqs; + info = smbstat_srv_info.si_reqs; + + for (i = 0; i < SMB_COM_NUM; i++) { + (void) strlcpy(info[i].ri_name, reqs[i].kr_name, + sizeof (reqs[i].kr_name)); + info[i].ri_opcode = i; + } + if (smbstat_opt_n) + qsort(info, SMB_COM_NUM, sizeof (smbstat_req_info_t), + smbstat_req_cmp_name); +} + +/* + * Return the number of ticks delta between two hrtime_t + * values. Attempt to cater for various kinds of overflow + * in hrtime_t - no matter how improbable. + */ +static double +smbstat_hrtime_delta(hrtime_t old, hrtime_t new) +{ + uint64_t del; + + if ((new >= old) && (old >= 0L)) + return ((double)(new - old)); + /* + * We've overflowed the positive portion of an hrtime_t. + */ + if (new < 0L) { + /* + * The new value is negative. Handle the case where the old + * value is positive or negative. + */ + uint64_t n1; + uint64_t o1; + + n1 = -new; + if (old > 0L) + return ((double)(n1 - old)); + + o1 = -old; + del = n1 - o1; + return ((double)del); + } + + /* + * Either we've just gone from being negative to positive *or* the last + * entry was positive and the new entry is also positive but *less* than + * the old entry. This implies we waited quite a few days on a very fast + * system between displays. + */ + if (old < 0L) { + uint64_t o2; + o2 = -old; + del = UINT64_MAX - o2; + } else { + del = UINT64_MAX - old; + } + del += new; + return ((double)del); +} + +static void * +smbstat_zalloc(size_t size) +{ + void *ptr; + + ptr = umem_zalloc(size, UMEM_DEFAULT); + if (ptr == NULL) + smbstat_fail(1, gettext("out of memory")); + return (ptr); +} + +static void +smbstat_free(void *ptr, size_t size) { - return ("fail,contents"); /* $UMEM_LOGGING setting */ + umem_free(ptr, size); } -#endif |