6582152 MMC remote service management support
6816841 name <-> SID interfaces
6843330 Create interposer library for SVCCTL and LOGR functionality.
6856791 Files dropped from large directory listing with long filenames
6859346 Query File Information errors when querying a named pipe
6860126 name<->SID interfaces use unacceptable style
--- a/usr/src/cmd/idmap/idmap/idmap.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/cmd/idmap/idmap/idmap.c Fri Jul 17 17:54:42 2009 -0700
@@ -34,7 +34,6 @@
#include <sys/varargs.h>
#include "idmap_engine.h"
#include "idmap_priv.h"
-#include "idmap_impl.h"
/* Initialization values for pids/rids: */
--- a/usr/src/cmd/idmap/idmapd/Makefile Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/cmd/idmap/idmapd/Makefile Fri Jul 17 17:54:42 2009 -0700
@@ -25,8 +25,21 @@
PROG = idmapd
MANIFEST = idmap.xml
-SERVEROBJS = idmapd.o init.o dbutils.o rpc_svc.o server.o adutils.o\
- idmap_config.o nldaputils.o
+SERVEROBJS = \
+ directory_provider_builtin.o \
+ directory_provider_nsswitch.o \
+ directory_provider_ad.o \
+ directory_server.o \
+ adutils.o \
+ dbutils.o \
+ idmap_config.o \
+ idmapd.o \
+ init.o \
+ nldaputils.o \
+ rpc_svc.o \
+ server.o \
+ wksids.o
+
SERVERSRCS = $(SERVEROBJS:%.o=%.c)
OBJS = $(SERVEROBJS)
SRCS = $(SERVERSRCS)
@@ -42,8 +55,17 @@
include ../../Makefile.cmd
+TEXT_DOMAIN = SUNW_OST_OSLIB
+XGETTEXT = $(GNUXGETTEXT)
+XGETFLAGS = --foreign-user --strict -n -E --width=72 \
+ --omit-header --keyword=directoryError:2 \
+ --language=C --force-po
+
+C99MODE = $(C99_ENABLE)
POFILE = $(PROG)_all.po
+RPC_MSGOUT_OPT = -DRPC_MSGOUT=idmap_rpc_msgout
+
ROOTMANIFESTDIR = $(ROOTSVCSYSTEM)
$(ROOTMANIFEST) := FILEMODE= 444
@@ -55,7 +77,18 @@
$(POFILE) := CPPFLAGS += $(INCS)
CFLAGS += -v
-LDLIBS += -lsecdb -lsocket -lnsl -lidmap -lscf -lsldap -lldap -luuid -ladutils
+LDLIBS += -lsecdb \
+ -lsocket \
+ -lnsl \
+ -lidmap \
+ -lscf \
+ -lsldap \
+ -lldap \
+ -luuid \
+ -ladutils \
+ -lumem
+
+rpc_svc.o := CFLAGS += $(RPC_MSGOUT_OPT)
$(PROG) := MAPFILES = $(MAPFILE.INT) $(MAPFILE.NGB)
$(PROG) := LDFLAGS += $(MAPFILES:%=-M%)
@@ -65,7 +98,7 @@
OWNER = root
GROUP = sys
-lint_SRCS := CPPFLAGS += $(INCS) -D_REENTRANT
+lint_SRCS := CPPFLAGS += $(INCS) -D_REENTRANT $(RPC_MSGOUT_OPT)
lint := LDLIBS += $(SQLITELINT)
.KEEP_STATE:
--- a/usr/src/cmd/idmap/idmapd/adutils.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/cmd/idmap/idmapd/adutils.c Fri Jul 17 17:54:42 2009 -0700
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -235,7 +235,7 @@
char *sid, rid_t rid, int sid_type, char *unixname)
{
char *domain;
- int err1, err2;
+ int err1;
assert(dn != NULL);
@@ -252,8 +252,7 @@
if (q->edomain != NULL) {
/* Check that this is the domain that we were looking for */
- if (u8_strcmp(q->edomain, domain, 0, U8_STRCMP_CI_LOWER,
- U8_UNICODE_LATEST, &err2) != 0 || err2 != 0)
+ if (!domain_eq(q->edomain, domain))
goto out;
}
--- a/usr/src/cmd/idmap/idmapd/dbutils.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/cmd/idmap/idmapd/dbutils.c Fri Jul 17 17:54:42 2009 -0700
@@ -74,8 +74,6 @@
#define IS_EPHEMERAL(pid) (pid > INT32_MAX && pid != SENTINEL_PID)
-#define LOCALRID_MIN 1000
-
typedef enum init_db_option {
FAIL_IF_CORRUPT = 0,
@@ -83,21 +81,6 @@
} init_db_option_t;
/*
- * Data structure to store well-known SIDs and
- * associated mappings (if any)
- */
-typedef struct wksids_table {
- const char *sidprefix;
- uint32_t rid;
- const char *domain;
- const char *winname;
- int is_wuser;
- uid_t pid;
- int is_user;
- int direction;
-} wksids_table_t;
-
-/*
* Thread specific data to hold the database handles so that the
* databases are not opened and closed for every request. It also
* contains the sqlite busy handler structure.
@@ -131,12 +114,6 @@
static pthread_key_t idmap_tsd_key;
-static const wksids_table_t *find_wksid_by_pid(uid_t pid, int is_user);
-static const wksids_table_t *find_wksid_by_sid(const char *sid, int rid,
- int type);
-static const wksids_table_t *find_wksid_by_name(const char *name,
- const char *domain, int type);
-
void
idmap_tsd_destroy(void *key)
{
@@ -1203,179 +1180,6 @@
rule->direction = direction;
}
-
-/*
- * Table for well-known SIDs.
- *
- * Background:
- *
- * Some of the well-known principals are stored under:
- * cn=WellKnown Security Principals, cn=Configuration, dc=<forestRootDomain>
- * They belong to objectClass "foreignSecurityPrincipal". They don't have
- * "samAccountName" nor "userPrincipalName" attributes. Their names are
- * available in "cn" and "name" attributes. Some of these principals have a
- * second entry under CN=ForeignSecurityPrincipals,dc=<forestRootDomain> and
- * these duplicate entries have the stringified SID in the "name" and "cn"
- * attributes instead of the actual name.
- *
- * Those of the form S-1-5-32-X are Builtin groups and are stored in the
- * cn=builtin container (except, Power Users which is not stored in AD)
- *
- * These principals are and will remain constant. Therefore doing AD lookups
- * provides no benefit. Also, using hard-coded table (and thus avoiding AD
- * lookup) improves performance and avoids additional complexity in the
- * adutils.c code. Moreover these SIDs can be used when no Active Directory
- * is available (such as the CIFS server's "workgroup" mode).
- *
- * Notes:
- * 1. Currently we don't support localization of well-known SID names,
- * unlike Windows.
- *
- * 2. Other well-known SIDs i.e. S-1-5-<domain>-<w-k RID> are not stored
- * here. AD does have normal user/group objects for these objects and
- * can be looked up using the existing AD lookup code.
- *
- * 3. See comments above lookup_wksids_sid2pid() for more information
- * on how we lookup the wksids table.
- *
- * 4. If this table contains two entries for a particular Windows name,
- * so as to offer both UID and GID mappings, the preferred mapping (the
- * one that matches Windows usage) must be listed first. That is the
- * entry that will be used when the caller specifies IDMAP_POSIXID
- * ("don't care") as the target.
- *
- * Entries here come from KB243330, MS-LSAT, and
- * http://technet.microsoft.com/en-us/library/cc755854.aspx
- * http://technet.microsoft.com/en-us/library/cc755925.aspx
- * http://msdn.microsoft.com/en-us/library/cc980032(PROT.10).aspx
- */
-static wksids_table_t wksids[] = {
- /* S-1-0 Null Authority */
- {"S-1-0", 0, "", "Nobody", 1, SENTINEL_PID, -1, 1},
-
- /* S-1-1 World Authority */
- {"S-1-1", 0, "", "Everyone", 0, SENTINEL_PID, -1, -1},
-
- /* S-1-2 Local Authority */
- {"S-1-2", 0, "", "Local", 0, SENTINEL_PID, -1, -1},
- {"S-1-2", 1, "", "Console Logon", 0, SENTINEL_PID, -1, -1},
-
- /* S-1-3 Creator Authority */
- {"S-1-3", 0, "", "Creator Owner", 1, IDMAP_WK_CREATOR_OWNER_UID, 1, 0},
- {"S-1-3", 1, "", "Creator Group", 0, IDMAP_WK_CREATOR_GROUP_GID, 0, 0},
- {"S-1-3", 2, "", "Creator Owner Server", 1, SENTINEL_PID, -1, -1},
- {"S-1-3", 3, "", "Creator Group Server", 0, SENTINEL_PID, -1, 1},
- {"S-1-3", 4, "", "Owner Rights", 0, SENTINEL_PID, -1, -1},
-
- /* S-1-4 Non-unique Authority */
-
- /* S-1-5 NT Authority */
- {"S-1-5", 1, "", "Dialup", 0, SENTINEL_PID, -1, -1},
- {"S-1-5", 2, "", "Network", 0, SENTINEL_PID, -1, -1},
- {"S-1-5", 3, "", "Batch", 0, SENTINEL_PID, -1, -1},
- {"S-1-5", 4, "", "Interactive", 0, SENTINEL_PID, -1, -1},
- /* S-1-5-5-X-Y Logon Session */
- {"S-1-5", 6, "", "Service", 0, SENTINEL_PID, -1, -1},
- {"S-1-5", 7, "", "Anonymous Logon", 0, GID_NOBODY, 0, 0},
- {"S-1-5", 7, "", "Anonymous Logon", 0, UID_NOBODY, 1, 0},
- {"S-1-5", 8, "", "Proxy", 0, SENTINEL_PID, -1, -1},
- {"S-1-5", 9, "", "Enterprise Domain Controllers", 0,
- SENTINEL_PID, -1, -1},
- {"S-1-5", 10, "", "Self", 0, SENTINEL_PID, -1, -1},
- {"S-1-5", 11, "", "Authenticated Users", 0, SENTINEL_PID, -1, -1},
- {"S-1-5", 12, "", "Restricted", 0, SENTINEL_PID, -1, -1},
- {"S-1-5", 13, "", "Terminal Server Users", 0, SENTINEL_PID, -1, -1},
- {"S-1-5", 14, "", "Remote Interactive Logon", 0, SENTINEL_PID, -1, -1},
- {"S-1-5", 15, "", "This Organization", 0, SENTINEL_PID, -1, -1},
- {"S-1-5", 17, "", "IUSR", 0, SENTINEL_PID, -1, -1},
- {"S-1-5", 18, "", "Local System", 0, IDMAP_WK_LOCAL_SYSTEM_GID, 0, 0},
- {"S-1-5", 19, "", "Local Service", 0, SENTINEL_PID, -1, -1},
- {"S-1-5", 20, "", "Network Service", 0, SENTINEL_PID, -1, -1},
-
- /* S-1-5-21-<domain> Machine-local definitions */
- {NULL, 498, NULL, "Enterprise Read-only Domain Controllers", 0,
- SENTINEL_PID, -1, -1},
- {NULL, 500, NULL, "Administrator", 1, SENTINEL_PID, 1, -1},
- {NULL, 501, NULL, "Guest", 1, SENTINEL_PID, 1, -1},
- {NULL, 502, NULL, "KRBTGT", 1, SENTINEL_PID, 1, -1},
- {NULL, 512, NULL, "Domain Admins", 0, SENTINEL_PID, -1, -1},
- {NULL, 513, NULL, "Domain Users", 0, SENTINEL_PID, -1, -1},
- {NULL, 514, NULL, "Domain Guests", 0, SENTINEL_PID, -1, -1},
- {NULL, 515, NULL, "Domain Computers", 0, SENTINEL_PID, -1, -1},
- {NULL, 516, NULL, "Domain Controllers", 0, SENTINEL_PID, -1, -1},
- {NULL, 517, NULL, "Cert Publishers", 0, SENTINEL_PID, -1, -1},
- {NULL, 518, NULL, "Schema Admins", 0, SENTINEL_PID, -1, -1},
- {NULL, 519, NULL, "Enterprise Admins", 0, SENTINEL_PID, -1, -1},
- {NULL, 520, NULL, "Global Policy Creator Owners", 0,
- SENTINEL_PID, -1, -1},
- {NULL, 533, NULL, "RAS and IAS Servers", 0, SENTINEL_PID, -1, -1},
-
- /* S-1-5-32 BUILTIN */
- {"S-1-5-32", 544, "BUILTIN", "Administrators", 0, SENTINEL_PID, -1, -1},
- {"S-1-5-32", 545, "BUILTIN", "Users", 0, SENTINEL_PID, -1, -1},
- {"S-1-5-32", 546, "BUILTIN", "Guests", 0, SENTINEL_PID, -1, -1},
- {"S-1-5-32", 547, "BUILTIN", "Power Users", 0, SENTINEL_PID, -1, -1},
- {"S-1-5-32", 548, "BUILTIN", "Account Operators", 0,
- SENTINEL_PID, -1, -1},
- {"S-1-5-32", 549, "BUILTIN", "Server Operators", 0,
- SENTINEL_PID, -1, -1},
- {"S-1-5-32", 550, "BUILTIN", "Print Operators", 0,
- SENTINEL_PID, -1, -1},
- {"S-1-5-32", 551, "BUILTIN", "Backup Operators", 0,
- SENTINEL_PID, -1, -1},
- {"S-1-5-32", 552, "BUILTIN", "Replicator", 0, SENTINEL_PID, -1, -1},
- {"S-1-5-32", 554, "BUILTIN", "Pre-Windows 2000 Compatible Access", 0,
- SENTINEL_PID, -1, -1},
- {"S-1-5-32", 555, "BUILTIN", "Remote Desktop Users", 0,
- SENTINEL_PID, -1, -1},
- {"S-1-5-32", 556, "BUILTIN", "Network Configuration Operators", 0,
- SENTINEL_PID, -1, -1},
- {"S-1-5-32", 557, "BUILTIN", "Incoming Forest Trust Builders", 0,
- SENTINEL_PID, -1, -1},
- {"S-1-5-32", 558, "BUILTIN", "Performance Monitor Users", 0,
- SENTINEL_PID, -1, -1},
- {"S-1-5-32", 559, "BUILTIN", "Performance Log Users", 0,
- SENTINEL_PID, -1, -1},
- {"S-1-5-32", 560, "BUILTIN", "Windows Authorization Access Group", 0,
- SENTINEL_PID, -1, -1},
- {"S-1-5-32", 561, "BUILTIN", "Terminal Server License Servers", 0,
- SENTINEL_PID, -1, -1},
- {"S-1-5-32", 562, "BUILTIN", "Distributed COM Users", 0,
- SENTINEL_PID, -1, -1},
- {"S-1-5-32", 568, "BUILTIN", "IIS_IUSRS", 0, SENTINEL_PID, -1, -1},
- {"S-1-5-32", 569, "BUILTIN", "Cryptographic Operators", 0,
- SENTINEL_PID, -1, -1},
- {"S-1-5-32", 573, "BUILTIN", "Event Log Readers", 0,
- SENTINEL_PID, -1, -1},
- {"S-1-5-32", 574, "BUILTIN", "Certificate Service DCOM Access", 0,
- SENTINEL_PID, -1, -1},
-
- {"S-1-5", 33, "", "Write Restricted", 0, SENTINEL_PID, -1, -1},
-
- /* S-1-5-64 NT Authority */
- {"S-1-5-64", 10, "", "NTLM Authentication", 0, SENTINEL_PID, -1, -1},
- {"S-1-5-64", 14, "", "SChannel Authentication", 0,
- SENTINEL_PID, -1, -1},
- {"S-1-5-64", 21, "", "Digest Authentication", 0, SENTINEL_PID, -1, -1},
-
- /* S-1-5-80-a-b-c-d NT Service */
-
- {"S-1-5", 1000, "", "Other Organization", 0, SENTINEL_PID, -1, -1},
-
- /* S-1-7 Internet$ */
-
- /*
- * S-1-16 Mandatory Label
- * S-1-16-0 Untrusted Mandatory Level
- * S-1-16-4096 Low Mandatory Level
- * S-1-16-8192 Medium Mandatory Level
- * S-1-16-8448 Medium Plus Mandatory Level
- * S-1-16-12288 High Mandatory Level
- * S-1-16-16384 System Mandatory Level
- * S-1-16-20480 Protected Process Mandatory Level
- */
-};
-
/*
* Lookup well-known SIDs table either by winname or by SID.
*
@@ -2634,8 +2438,8 @@
return (IDMAP_ERR_NOMAPPING);
/* Skip 1000 UIDs */
- if (is_user && req->id1.idmap_id_u.uid >
- (INT32_MAX - LOCALRID_MIN))
+ if (is_user &&
+ req->id1.idmap_id_u.uid + LOCALRID_UID_MIN > LOCALRID_UID_MAX)
return (IDMAP_ERR_NOMAPPING);
RDLOCK_CONFIG();
@@ -2652,8 +2456,8 @@
}
UNLOCK_CONFIG();
res->id.idmap_id_u.sid.rid =
- (is_user) ? req->id1.idmap_id_u.uid + LOCALRID_MIN :
- req->id1.idmap_id_u.gid + INT32_MAX + 1;
+ (is_user) ? req->id1.idmap_id_u.uid + LOCALRID_UID_MIN :
+ req->id1.idmap_id_u.gid + LOCALRID_GID_MIN;
res->direction = IDMAP_DIRECTION_BI;
if (res->id.idtype == IDMAP_SID)
res->id.idtype = is_user ? IDMAP_USID : IDMAP_GSID;
@@ -2702,24 +2506,24 @@
switch (res->id.idtype) {
case IDMAP_UID:
- if (rid > INT32_MAX || rid < LOCALRID_MIN)
+ if (rid < LOCALRID_UID_MIN || rid > LOCALRID_UID_MAX)
return (IDMAP_ERR_ARG);
- res->id.idmap_id_u.uid = rid - LOCALRID_MIN;
+ res->id.idmap_id_u.uid = rid - LOCALRID_UID_MIN;
break;
case IDMAP_GID:
- if (rid <= INT32_MAX)
+ if (rid < LOCALRID_GID_MIN)
return (IDMAP_ERR_ARG);
- res->id.idmap_id_u.gid = rid - INT32_MAX - 1;
+ res->id.idmap_id_u.gid = rid - LOCALRID_GID_MIN;
break;
case IDMAP_POSIXID:
- if (rid > INT32_MAX) {
- res->id.idmap_id_u.gid = rid - INT32_MAX - 1;
+ if (rid >= LOCALRID_GID_MIN) {
+ res->id.idmap_id_u.gid = rid - LOCALRID_GID_MIN;
res->id.idtype = IDMAP_GID;
- } else if (rid < LOCALRID_MIN) {
- return (IDMAP_ERR_ARG);
+ } else if (rid >= LOCALRID_UID_MIN) {
+ res->id.idmap_id_u.uid = rid - LOCALRID_UID_MIN;
+ res->id.idtype = IDMAP_UID;
} else {
- res->id.idmap_id_u.uid = rid - LOCALRID_MIN;
- res->id.idtype = IDMAP_UID;
+ return (IDMAP_ERR_ARG);
}
break;
default:
@@ -4851,161 +4655,3 @@
result.ids.ids_val = res;
return (ad_lookup_batch(state, &batch, &result));
}
-
-/*
- * Find a wksid entry for the specified Windows name and domain, of the
- * specified type.
- *
- * Ignore entries intended only for U2W use.
- */
-static
-const
-wksids_table_t *
-find_wksid_by_name(const char *name, const char *domain, int type)
-{
- int i;
- char *myhostname;
- int len;
-
- RDLOCK_CONFIG();
- len = strlen(_idmapdstate.hostname) + 1;
- myhostname = alloca(len);
- (void) memcpy(myhostname, _idmapdstate.hostname, len);
- UNLOCK_CONFIG();
-
- for (i = 0; i < NELEM(wksids); i++) {
- /* Check to see if this entry yields the desired type */
- switch (type) {
- case IDMAP_UID:
- if (wksids[i].is_user == 0)
- continue;
- break;
- case IDMAP_GID:
- if (wksids[i].is_user == 1)
- continue;
- break;
- case IDMAP_POSIXID:
- break;
- default:
- assert(FALSE);
- }
-
- if (strcasecmp(wksids[i].winname, name) != 0)
- continue;
-
- if (!EMPTY_STRING(domain)) {
- const char *dom;
-
- if (wksids[i].domain != NULL) {
- dom = wksids[i].domain;
- } else {
- dom = myhostname;
- }
- if (strcasecmp(dom, domain) != 0) {
- /* this is not our domain */
- continue;
- }
- }
-
- /*
- * We have a Windows name, so ignore entries that are only
- * usable for mapping UNIX->Windows. (Note: the current
- * table does not have any such entries.)
- */
- if (wksids[i].direction == IDMAP_DIRECTION_U2W)
- continue;
-
- return (&wksids[i]);
- }
-
- return (NULL);
-}
-
-/*
- * Find a wksid entry for the specified SID, of the specified type.
- *
- * Ignore entries intended only for U2W use.
- */
-static
-const
-wksids_table_t *
-find_wksid_by_sid(const char *sid, int rid, int type)
-{
- int i;
- char *mymachinesid;
- int len;
-
- RDLOCK_CONFIG();
- len = strlen(_idmapdstate.cfg->pgcfg.machine_sid) + 1;
- mymachinesid = alloca(len);
- (void) memcpy(mymachinesid, _idmapdstate.cfg->pgcfg.machine_sid, len);
- UNLOCK_CONFIG();
-
- for (i = 0; i < NELEM(wksids); i++) {
- int sidcmp;
-
- /* Check to see if this entry yields the desired type */
- switch (type) {
- case IDMAP_UID:
- if (wksids[i].is_user == 0)
- continue;
- break;
- case IDMAP_GID:
- if (wksids[i].is_user == 1)
- continue;
- break;
- case IDMAP_POSIXID:
- break;
- default:
- assert(FALSE);
- }
-
- if (wksids[i].sidprefix != NULL) {
- sidcmp = strcasecmp(wksids[i].sidprefix, sid);
- } else {
- sidcmp = strcasecmp(mymachinesid, sid);
- }
-
- if (sidcmp != 0)
- continue;
- if (wksids[i].rid != rid)
- continue;
-
- /*
- * We have a SID, so ignore entries that are only usable
- * for mapping UNIX->Windows. (Note: the current table
- * does not have any such entries.)
- */
- if (wksids[i].direction == IDMAP_DIRECTION_U2W)
- continue;
-
- return (&wksids[i]);
- }
-
- return (NULL);
-}
-
-/*
- * Find a wksid entry for the specified pid, of the specified type.
- * Ignore entries that do not specify U2W mappings.
- */
-static
-const
-wksids_table_t *
-find_wksid_by_pid(uid_t pid, int is_user)
-{
- int i;
-
- if (pid == SENTINEL_PID)
- return (NULL);
-
- for (i = 0; i < NELEM(wksids); i++) {
- if (wksids[i].pid == pid &&
- wksids[i].is_user == is_user &&
- (wksids[i].direction == IDMAP_DIRECTION_BI ||
- wksids[i].direction == IDMAP_DIRECTION_U2W)) {
- return (&wksids[i]);
- }
- }
- return (NULL);
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/idmap/idmapd/directory_provider_ad.c Fri Jul 17 17:54:42 2009 -0700
@@ -0,0 +1,590 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Retrieve directory information for Active Directory users.
+ */
+
+#include <ldap.h>
+#include <lber.h>
+#include <pwd.h>
+#include <malloc.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <libadutils.h>
+#include <note.h>
+#include <assert.h>
+#include "directory.h"
+#include "directory_private.h"
+#include "idmapd.h"
+#include <rpcsvc/idmap_prot.h>
+#include "directory_server_impl.h"
+#include "miscutils.h"
+
+/*
+ * Information required by the function that handles the callback from LDAP
+ * when responses are received.
+ */
+struct cbinfo {
+ const char * const *attrs;
+ int nattrs;
+ directory_entry_rpc *entry;
+ const char *domain;
+};
+
+static void directory_provider_ad_cb(LDAP *ld, LDAPMessage **ldapres, int rc,
+ int qid, void *argp);
+static void directory_provider_ad_cb1(LDAP *ld, LDAPMessage *msg,
+ struct cbinfo *cbinfo);
+static directory_error_t bv_list_dav(directory_values_rpc *lvals,
+ struct berval **bv);
+static directory_error_t directory_provider_ad_lookup(
+ directory_entry_rpc *pent, const char * const * attrs, int nattrs,
+ const char *domain, const char *filter);
+static directory_error_t get_domain(LDAP *ld, LDAPMessage *ldapres,
+ char **domain);
+static directory_error_t directory_provider_ad_utils_error(char *func, int rc);
+
+#if defined(DUMP_VALUES)
+static void dump_bv_list(const char *attr, struct berval **bv);
+#endif
+
+#define MAX_EXTRA_ATTRS 1 /* sAMAccountName */
+
+/*
+ * Add an entry to a NULL-terminated list, if it's not already there.
+ * Assumes that the list has been allocated large enough for all additions,
+ * and prefilled with NULL.
+ */
+static
+void
+maybe_add_to_list(const char **list, const char *s)
+{
+ for (; *list != NULL; list++) {
+ if (strcaseeq(*list, s))
+ return;
+ }
+ *list = s;
+}
+
+/*
+ * Copy a counted attribute list to a NULL-terminated one.
+ * In the process, examine the requested attributes and augment
+ * the list as required to support any synthesized attributes
+ * requested.
+ */
+static
+const char **
+copy_and_augment_attr_list(char **req_list, int req_list_len)
+{
+ const char **new_list;
+ int i;
+
+ new_list =
+ calloc(req_list_len + MAX_EXTRA_ATTRS + 1, sizeof (*new_list));
+ if (new_list == NULL)
+ return (NULL);
+
+ (void) memcpy(new_list, req_list, req_list_len * sizeof (char *));
+
+ for (i = 0; i < req_list_len; i++) {
+ const char *a = req_list[i];
+ /*
+ * Note that you must update MAX_EXTRA_ATTRS above if you
+ * add to this list.
+ */
+ if (strcaseeq(a, "x-sun-canonicalName")) {
+ maybe_add_to_list(new_list, "sAMAccountName");
+ continue;
+ }
+ /* None needed for x-sun-provider */
+ }
+
+ return (new_list);
+}
+
+/*
+ * Retrieve information by name.
+ * Called indirectly through the Directory_provider_static structure.
+ */
+static
+directory_error_t
+directory_provider_ad_get(
+ directory_entry_rpc *del,
+ idmap_utf8str_list *ids,
+ char *types,
+ idmap_utf8str_list *attrs)
+{
+ int i;
+ const char **attrs2;
+ directory_error_t de = NULL;
+
+ /*
+ * If we don't have any AD servers handy, we can't find anything.
+ */
+ if (_idmapdstate.num_ads < 1) {
+ return (NULL);
+ }
+
+ RDLOCK_CONFIG()
+
+ /* 6835280 spurious lint error if the strlen is in the declaration */
+ int len = strlen(_idmapdstate.cfg->pgcfg.default_domain);
+ char default_domain[len + 1];
+ (void) strcpy(default_domain, _idmapdstate.cfg->pgcfg.default_domain);
+
+ UNLOCK_CONFIG();
+
+ /*
+ * Turn our counted-array argument into a NULL-terminated array.
+ * At the same time, add in any attributes that we need to support
+ * any requested synthesized attributes.
+ */
+ attrs2 = copy_and_augment_attr_list(attrs->idmap_utf8str_list_val,
+ attrs->idmap_utf8str_list_len);
+ if (attrs2 == NULL)
+ goto nomem;
+
+ for (i = 0; i < ids->idmap_utf8str_list_len; i++) {
+ char *vw[3];
+ int type;
+
+ /*
+ * Extract the type for this particular ID.
+ * Advance to the next type, if it's there, else keep
+ * using this type until we run out of IDs.
+ */
+ type = *types;
+ if (*(types+1) != '\0')
+ types++;
+
+ /*
+ * If this entry has already been handled, one way or another,
+ * skip it.
+ */
+ if (del[i].status != DIRECTORY_NOT_FOUND)
+ continue;
+
+ char *id = ids->idmap_utf8str_list_val[i];
+
+ /*
+ * Allow for expanding every character to \xx, plus some
+ * space for the query syntax.
+ */
+ int id_len = strlen(id);
+ char filter[1000 + id_len*3];
+
+ if (type == DIRECTORY_ID_SID[0]) {
+ /*
+ * Mildly surprisingly, AD appears to allow searching
+ * based on text SIDs. Must be a special case on the
+ * server end.
+ */
+ ldap_build_filter(filter, sizeof (filter),
+ "(objectSid=%v)", NULL, NULL, NULL, id, NULL);
+
+ de = directory_provider_ad_lookup(&del[i], attrs2,
+ attrs->idmap_utf8str_list_len, NULL, filter);
+ if (de != NULL) {
+ directory_entry_set_error(&del[i], de);
+ de = NULL;
+ }
+ } else {
+ int id_len = strlen(id);
+ char name[id_len + 1];
+ char domain[id_len + 1];
+
+ split_name(name, domain, id);
+
+ vw[0] = name;
+
+ if (streq(domain, "")) {
+ vw[1] = default_domain;
+ } else {
+ vw[1] = domain;
+ }
+
+ if (type == DIRECTORY_ID_USER[0])
+ vw[2] = "user";
+ else if (type == DIRECTORY_ID_GROUP[0])
+ vw[2] = "group";
+ else
+ vw[2] = "*";
+
+ /*
+ * Try samAccountName.
+ * Note that here we rely on checking the returned
+ * distinguishedName to make sure that we found an
+ * entry from the right domain, because there's no
+ * attribute we can straightforwardly filter for to
+ * match domain.
+ *
+ * Eventually we should perhaps also try
+ * userPrincipalName.
+ */
+ ldap_build_filter(filter, sizeof (filter),
+ "(&(samAccountName=%v1)(objectClass=%v3))",
+ NULL, NULL, NULL, NULL, vw);
+
+ de = directory_provider_ad_lookup(&del[i], attrs2,
+ attrs->idmap_utf8str_list_len, vw[1], filter);
+ if (de != NULL) {
+ directory_entry_set_error(&del[i], de);
+ de = NULL;
+ }
+ }
+ }
+
+ de = NULL;
+
+ goto out;
+
+nomem:
+ de = directory_error("ENOMEM.AD",
+ "Out of memory during AD lookup", NULL);
+out:
+ free(attrs2);
+ return (de);
+}
+
+/*
+ * Note that attrs is NULL terminated, and that nattrs is the number
+ * of attributes requested by the user... which might be fewer than are
+ * in attrs because of attributes that we need for our own processing.
+ */
+static
+directory_error_t
+directory_provider_ad_lookup(
+ directory_entry_rpc *pent,
+ const char * const * attrs,
+ int nattrs,
+ const char *domain,
+ const char *filter)
+{
+ adutils_ad_t *ad;
+ adutils_rc batchrc;
+ struct cbinfo cbinfo;
+ adutils_query_state_t *qs;
+ int rc;
+
+ /*
+ * NEEDSWORK: Should eventually handle other forests.
+ * NEEDSWORK: Should eventually handle non-GC attributes.
+ */
+ ad = _idmapdstate.ads[0];
+
+ /* Stash away information for the callback function. */
+ cbinfo.attrs = attrs;
+ cbinfo.nattrs = nattrs;
+ cbinfo.entry = pent;
+ cbinfo.domain = domain;
+
+ rc = adutils_lookup_batch_start(ad, 1, directory_provider_ad_cb,
+ &cbinfo, &qs);
+ if (rc != ADUTILS_SUCCESS) {
+ return (directory_provider_ad_utils_error(
+ "adutils_lookup_batch_start", rc));
+ }
+
+ rc = adutils_lookup_batch_add(qs, filter, attrs, domain,
+ NULL, &batchrc);
+ if (rc != ADUTILS_SUCCESS) {
+ adutils_lookup_batch_release(&qs);
+ return (directory_provider_ad_utils_error(
+ "adutils_lookup_batch_add", rc));
+ }
+
+ rc = adutils_lookup_batch_end(&qs);
+ if (rc != ADUTILS_SUCCESS) {
+ return (directory_provider_ad_utils_error(
+ "adutils_lookup_batch_end", rc));
+ }
+
+ if (batchrc != ADUTILS_SUCCESS) {
+ /*
+ * NEEDSWORK: We're consistently getting -9997 here.
+ * What does it mean?
+ */
+ return (NULL);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Callback from the LDAP functions when they get responses.
+ * We don't really need (nor want) asynchronous handling, but it's
+ * what libadutils gives us.
+ */
+static
+void
+directory_provider_ad_cb(
+ LDAP *ld,
+ LDAPMessage **ldapres,
+ int rc,
+ int qid,
+ void *argp)
+{
+ NOTE(ARGUNUSED(rc, qid))
+ struct cbinfo *cbinfo = (struct cbinfo *)argp;
+ LDAPMessage *msg = *ldapres;
+
+ for (msg = ldap_first_entry(ld, msg);
+ msg != NULL;
+ msg = ldap_next_entry(ld, msg)) {
+ directory_provider_ad_cb1(ld, msg, cbinfo);
+ }
+}
+
+/*
+ * Process a single entry returned by an LDAP callback.
+ * Note that this performs a function roughly equivalent to the
+ * directory*Populate() functions in the other providers.
+ * Given an LDAP response, populate the directory entry for return to
+ * the caller. This one differs primarily in that we're working directly
+ * with LDAP, so we don't have to do any attribute translation.
+ */
+static
+void
+directory_provider_ad_cb1(
+ LDAP *ld,
+ LDAPMessage *msg,
+ struct cbinfo *cbinfo)
+{
+ int nattrs = cbinfo->nattrs;
+ const char * const *attrs = cbinfo->attrs;
+ directory_entry_rpc *pent = cbinfo->entry;
+
+ int i;
+ directory_values_rpc *llvals;
+ directory_error_t de;
+ char *domain = NULL;
+
+ /*
+ * We don't have a way to filter for entries from the right domain
+ * in the LDAP query, so we check for it here. Searches based on
+ * samAccountName might yield results from the wrong domain.
+ */
+ de = get_domain(ld, msg, &domain);
+ if (de != NULL)
+ goto err;
+
+ if (cbinfo->domain != NULL && !domain_eq(cbinfo->domain, domain))
+ goto out;
+
+ /*
+ * If we've already found a match, error.
+ */
+ if (pent->status != DIRECTORY_NOT_FOUND) {
+ de = directory_error("Duplicate.AD",
+ "Multiple matching entries found", NULL);
+ goto err;
+ }
+
+ llvals = calloc(nattrs, sizeof (directory_values_rpc));
+ if (llvals == NULL)
+ goto nomem;
+
+ pent->directory_entry_rpc_u.attrs.attrs_val = llvals;
+ pent->directory_entry_rpc_u.attrs.attrs_len = nattrs;
+ pent->status = DIRECTORY_FOUND;
+
+ for (i = 0; i < nattrs; i++) {
+ struct berval **bv;
+ const char *a = attrs[i];
+ directory_values_rpc *val = &llvals[i];
+
+ bv = ldap_get_values_len(ld, msg, a);
+#if defined(DUMP_VALUES)
+ dump_bv_list(attrs[i], bv);
+#endif
+ if (bv != NULL) {
+ de = bv_list_dav(val, bv);
+ ldap_value_free_len(bv);
+ if (de != NULL)
+ goto err;
+ } else if (strcaseeq(a, "x-sun-canonicalName")) {
+ bv = ldap_get_values_len(ld, msg, "sAMAccountName");
+ if (bv != NULL) {
+ int n = ldap_count_values_len(bv);
+ if (n > 0) {
+ char *tmp;
+ (void) asprintf(&tmp, "%.*s@%s",
+ bv[0]->bv_len, bv[0]->bv_val,
+ domain);
+ if (tmp == NULL)
+ goto nomem;
+ const char *ctmp = tmp;
+ de = str_list_dav(val, &ctmp, 1);
+ free(tmp);
+ if (de != NULL)
+ goto err;
+ }
+ }
+ } else if (strcaseeq(a, "x-sun-provider")) {
+ const char *provider = "LDAP-AD";
+ de = str_list_dav(val, &provider, 1);
+ }
+ }
+
+ goto out;
+
+nomem:
+ de = directory_error("ENOMEM.users",
+ "No memory allocating return value for user lookup", NULL);
+
+err:
+ directory_entry_set_error(pent, de);
+ de = NULL;
+
+out:
+ free(domain);
+}
+
+/*
+ * Given a struct berval, populate a directory attribute value (which is a
+ * list of values).
+ * Note that here we populate the DAV with the exact bytes that LDAP returns.
+ * Back over in the client it appends a \0 so that strings are null
+ * terminated.
+ */
+static
+directory_error_t
+bv_list_dav(directory_values_rpc *lvals, struct berval **bv)
+{
+ directory_value_rpc *dav;
+ int n;
+ int i;
+
+ n = ldap_count_values_len(bv);
+
+ dav = calloc(n, sizeof (directory_value_rpc));
+ if (dav == NULL)
+ goto nomem;
+
+ lvals->directory_values_rpc_u.values.values_val = dav;
+ lvals->directory_values_rpc_u.values.values_len = n;
+ lvals->found = TRUE;
+
+ for (i = 0; i < n; i++) {
+ dav[i].directory_value_rpc_val =
+ memdup(bv[i]->bv_val, bv[i]->bv_len);
+ if (dav[i].directory_value_rpc_val == NULL)
+ goto nomem;
+ dav[i].directory_value_rpc_len = bv[i]->bv_len;
+ }
+
+ return (NULL);
+
+nomem:
+ return (directory_error("ENOMEM.bv_list_dav",
+ "Insufficient memory copying values"));
+}
+
+#if defined(DUMP_VALUES)
+static
+void
+dump_bv_list(const char *attr, struct berval **bv)
+{
+ int i;
+
+ if (bv == NULL) {
+ (void) fprintf(stderr, "%s: (empty)\n", attr);
+ return;
+ }
+ for (i = 0; bv[i] != NULL; i++) {
+ (void) fprintf(stderr, "%s[%d] =\n", attr, i);
+ dump(stderr, " ", bv[i]->bv_val, bv[i]->bv_len);
+ }
+}
+#endif /* DUMP_VALUES */
+
+/*
+ * Return the domain associated with the specified entry.
+ */
+static
+directory_error_t
+get_domain(
+ LDAP *ld,
+ LDAPMessage *msg,
+ char **domain)
+{
+ *domain = NULL;
+
+ char *dn = ldap_get_dn(ld, msg);
+ if (dn == NULL) {
+ char buf[100]; /* big enough for any int */
+ char *m;
+ char *s;
+ int err = ldap_get_lderrno(ld, &m, &s);
+ (void) snprintf(buf, sizeof (buf), "%d", err);
+
+ return directory_error("AD.get_domain.ldap_get_dn",
+ "ldap_get_dn: %1 (%2)\n"
+ "matched: %3\n"
+ "error: %4",
+ ldap_err2string(err), buf,
+ m == NULL ? "(null)" : m,
+ s == NULL ? "(null)" : s,
+ NULL);
+ }
+
+ *domain = adutils_dn2dns(dn);
+ if (*domain == NULL) {
+ directory_error_t de;
+
+ de = directory_error("Unknown.get_domain.adutils_dn2dns",
+ "get_domain: Unexpected error from adutils_dn2dns(%1)",
+ dn, NULL);
+ free(dn);
+ return (de);
+ }
+ free(dn);
+
+ return (NULL);
+}
+
+/*
+ * Given an error report from libadutils, generate a directory_error_t.
+ */
+static
+directory_error_t
+directory_provider_ad_utils_error(char *func, int rc)
+{
+ char rcstr[100]; /* plenty for any int */
+ char code[100]; /* plenty for any int */
+ (void) snprintf(rcstr, sizeof (rcstr), "%d", rc);
+ (void) snprintf(code, sizeof (code), "ADUTILS.%d", rc);
+
+ return (directory_error(code,
+ "Error %2 from adutils function %1", func, rcstr, NULL));
+}
+
+struct directory_provider_static directory_provider_ad = {
+ "AD",
+ directory_provider_ad_get,
+};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/idmap/idmapd/directory_provider_builtin.c Fri Jul 17 17:54:42 2009 -0700
@@ -0,0 +1,319 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Retrieve directory information for built-in users and groups
+ */
+
+#include <stdio.h>
+#include <limits.h>
+#include <sys/idmap.h>
+#include <sys/param.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <note.h>
+#include "idmapd.h"
+#include "directory.h"
+#include "directory_private.h"
+#include <rpcsvc/idmap_prot.h>
+#include "directory_server_impl.h"
+#include "miscutils.h"
+#include "sidutil.h"
+
+static directory_error_t sid_dav(directory_values_rpc *lvals,
+ const wksids_table_t *wksid);
+static directory_error_t directory_provider_builtin_populate(
+ directory_entry_rpc *pent, const wksids_table_t *wksid,
+ idmap_utf8str_list *attrs);
+
+/*
+ * Retrieve information by name.
+ * Called indirectly through the directory_provider_static structure.
+ */
+static
+directory_error_t
+directory_provider_builtin_get(
+ directory_entry_rpc *del,
+ idmap_utf8str_list *ids,
+ idmap_utf8str types,
+ idmap_utf8str_list *attrs)
+{
+ int i;
+
+ for (i = 0; i < ids->idmap_utf8str_list_len; i++) {
+ const wksids_table_t *wksid;
+ directory_error_t de;
+ int type;
+
+ /*
+ * Extract the type for this particular ID.
+ * Advance to the next type, if it's there, else keep
+ * using this type until we run out of IDs.
+ */
+ type = *types;
+ if (*(types+1) != '\0')
+ types++;
+
+ /*
+ * If this entry has already been handled, one way or another,
+ * skip it.
+ */
+ if (del[i].status != DIRECTORY_NOT_FOUND)
+ continue;
+
+ char *id = ids->idmap_utf8str_list_val[i];
+
+ /*
+ * End-to-end error injection point.
+ * NEEDSWORK: should probably eliminate this for production
+ */
+ if (streq(id, " DEBUG BUILTIN ERROR ")) {
+ directory_entry_set_error(&del[i],
+ directory_error("Directory_provider_builtin.debug",
+ "Directory_provider_builtin: artificial error",
+ NULL));
+ continue;
+ }
+
+ if (type == DIRECTORY_ID_SID[0])
+ wksid = find_wk_by_sid(id);
+ else {
+ int idmap_id_type;
+ if (type == DIRECTORY_ID_NAME[0])
+ idmap_id_type = IDMAP_POSIXID;
+ else if (type == DIRECTORY_ID_USER[0])
+ idmap_id_type = IDMAP_UID;
+ else if (type == DIRECTORY_ID_GROUP[0])
+ idmap_id_type = IDMAP_GID;
+ else {
+ directory_entry_set_error(&del[i],
+ directory_error("invalid_arg.id_type",
+ "Invalid ID type \"%1\"",
+ types, NULL));
+ continue;
+ }
+
+ int id_len = strlen(id);
+ char name[id_len + 1];
+ char domain[id_len + 1];
+
+ split_name(name, domain, id);
+
+ wksid = find_wksid_by_name(name, domain, idmap_id_type);
+ }
+
+ if (wksid == NULL)
+ continue;
+
+ de = directory_provider_builtin_populate(&del[i], wksid, attrs);
+ if (de != NULL) {
+ directory_entry_set_error(&del[i], de);
+ de = NULL;
+ }
+ }
+
+ return (NULL);
+}
+
+/*
+ * Given a well-known name entry and a list of attributes that were
+ * requested, populate the structure to return to the caller.
+ */
+static
+directory_error_t
+directory_provider_builtin_populate(
+ directory_entry_rpc *pent,
+ const wksids_table_t *wksid,
+ idmap_utf8str_list *attrs)
+{
+ int j;
+ directory_values_rpc *llvals;
+ int nattrs;
+
+ nattrs = attrs->idmap_utf8str_list_len;
+
+ llvals = calloc(nattrs, sizeof (directory_values_rpc));
+ if (llvals == NULL)
+ goto nomem;
+
+ pent->status = DIRECTORY_FOUND;
+ pent->directory_entry_rpc_u.attrs.attrs_val = llvals;
+ pent->directory_entry_rpc_u.attrs.attrs_len = nattrs;
+
+ for (j = 0; j < nattrs; j++) {
+ directory_values_rpc *val;
+ char *a;
+ directory_error_t de;
+
+ /*
+ * We're going to refer to these a lot, so make a shorthand
+ * copy.
+ */
+ a = attrs->idmap_utf8str_list_val[j];
+ val = &llvals[j];
+
+ /*
+ * Start by assuming no errors and that we don't have
+ * the information.
+ */
+ val->found = FALSE;
+ de = NULL;
+
+ if (strcaseeq(a, "uid")) {
+ de = str_list_dav(val, &wksid->winname, 1);
+ } else if (strcaseeq(a, "uidNumber")) {
+ if (wksid->pid != SENTINEL_PID && wksid->is_user) {
+ de = uint_list_dav(val, &wksid->pid, 1);
+ }
+ } else if (strcaseeq(a, "gidNumber")) {
+ if (wksid->pid != SENTINEL_PID && !wksid->is_user) {
+ de = uint_list_dav(val, &wksid->pid, 1);
+ }
+ } else if (strcaseeq(a, "displayName") || strcaseeq(a, "cn")) {
+ de = str_list_dav(val, &wksid->winname, 1);
+ } else if (strcaseeq(a, "distinguishedName")) {
+ char *container;
+ if (wksid->domain == NULL) {
+ container = "Users";
+ } else {
+ container = "Builtin";
+ }
+ RDLOCK_CONFIG();
+ char *dn;
+ (void) asprintf(&dn,
+ "CN=%s,CN=%s,DC=%s",
+ wksid->winname, container, _idmapdstate.hostname);
+ UNLOCK_CONFIG();
+ const char *cdn = dn;
+ de = str_list_dav(val, &cdn, 1);
+ free(dn);
+ } else if (strcaseeq(a, "objectClass")) {
+ if (wksid->is_wuser) {
+ static const char *objectClasses[] = {
+ "top",
+ "person",
+ "organizationalPerson",
+ "user",
+ };
+ de = str_list_dav(val, objectClasses,
+ NELEM(objectClasses));
+ } else {
+ static const char *objectClasses[] = {
+ "top",
+ "group",
+ };
+ de = str_list_dav(val, objectClasses,
+ NELEM(objectClasses));
+ }
+ } else if (strcaseeq(a, "objectSid")) {
+ de = sid_dav(val, wksid);
+ } else if (strcaseeq(a, "x-sun-canonicalName")) {
+ char *canon;
+
+ if (wksid->domain == NULL) {
+ RDLOCK_CONFIG();
+ (void) asprintf(&canon, "%s@%s",
+ wksid->winname, _idmapdstate.hostname);
+ UNLOCK_CONFIG();
+ } else if (streq(wksid->domain, "")) {
+ canon = strdup(wksid->winname);
+ } else {
+ (void) asprintf(&canon, "%s@%s",
+ wksid->winname, wksid->domain);
+ }
+
+ if (canon == NULL)
+ goto nomem;
+ const char *ccanon = canon;
+ de = str_list_dav(val, &ccanon, 1);
+ free(canon);
+ } else if (strcaseeq(a, "x-sun-provider")) {
+ const char *provider = "Builtin";
+ de = str_list_dav(val, &provider, 1);
+ }
+ if (de != NULL)
+ return (de);
+ }
+
+ return (NULL);
+
+nomem:
+ return (directory_error("ENOMEM.users",
+ "No memory allocating return value for user lookup", NULL));
+}
+
+/*
+ * Given a well-known name structure, generate a binary-format SID.
+ * It's a bit perverse that we must take a text-format SID and turn it into
+ * a binary-format SID, only to have the caller probably turn it back into
+ * text format, but SIDs are carried across LDAP in binary format.
+ */
+static
+directory_error_t
+sid_dav(directory_values_rpc *lvals, const wksids_table_t *wksid)
+{
+ char *text_sid;
+ sid_t *sid;
+ directory_error_t de;
+
+ if (wksid->sidprefix == NULL) {
+ RDLOCK_CONFIG();
+ (void) asprintf(&text_sid, "%s-%d",
+ _idmapdstate.cfg->pgcfg.machine_sid,
+ wksid->rid);
+ UNLOCK_CONFIG();
+ } else {
+ (void) asprintf(&text_sid, "%s-%d",
+ wksid->sidprefix, wksid->rid);
+ }
+
+ if (text_sid == NULL)
+ goto nomem;
+
+ sid = sid_fromstr(text_sid);
+ free(text_sid);
+
+ if (sid == NULL)
+ goto nomem;
+
+ sid_to_le(sid);
+
+ de = bin_list_dav(lvals, sid, 1, sid_len(sid));
+
+ sid_free(sid);
+
+ return (de);
+
+nomem:
+ return (directory_error("ENOMEM.sid_dav",
+ "No memory allocating SID for user lookup", NULL));
+}
+
+struct directory_provider_static directory_provider_builtin = {
+ "builtin",
+ directory_provider_builtin_get,
+};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/idmap/idmapd/directory_provider_nsswitch.c Fri Jul 17 17:54:42 2009 -0700
@@ -0,0 +1,472 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Retrieve directory information for standard UNIX users/groups.
+ * (NB: not just from files, but all nsswitch sources.)
+ */
+
+#include <pwd.h>
+#include <grp.h>
+#include <malloc.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <note.h>
+#include <errno.h>
+#include "idmapd.h"
+#include "directory.h"
+#include "directory_private.h"
+#include <rpcsvc/idmap_prot.h>
+#include "directory_server_impl.h"
+#include "miscutils.h"
+#include "sidutil.h"
+
+static directory_error_t machine_sid_dav(directory_values_rpc *lvals,
+ unsigned int rid);
+static directory_error_t directory_provider_nsswitch_populate(
+ directory_entry_rpc *pent, struct passwd *pwd, struct group *grp,
+ idmap_utf8str_list *attrs);
+
+/*
+ * Retrieve information by name.
+ * Called indirectly through the directory_provider_static structure.
+ */
+static
+directory_error_t
+directory_provider_nsswitch_get(
+ directory_entry_rpc *del,
+ idmap_utf8str_list *ids,
+ idmap_utf8str types,
+ idmap_utf8str_list *attrs)
+{
+ int i;
+
+ RDLOCK_CONFIG();
+
+ /* 6835280 spurious lint error if the strlen is in the declaration */
+ int host_name_len = strlen(_idmapdstate.hostname);
+ char my_host_name[host_name_len + 1];
+ (void) strcpy(my_host_name, _idmapdstate.hostname);
+
+ /* We use len later, so this is not merely a workaround for 6835280 */
+ int machine_sid_len = strlen(_idmapdstate.cfg->pgcfg.machine_sid);
+ char my_machine_sid[machine_sid_len + 1];
+ (void) strcpy(my_machine_sid, _idmapdstate.cfg->pgcfg.machine_sid);
+
+ UNLOCK_CONFIG();
+
+ for (i = 0; i < ids->idmap_utf8str_list_len; i++) {
+ struct passwd *pwd = NULL;
+ struct group *grp = NULL;
+ directory_error_t de;
+ int type;
+
+ /*
+ * Extract the type for this particular ID.
+ * Advance to the next type, if it's there, else keep
+ * using this type until we run out of IDs.
+ */
+ type = *types;
+ if (*(types+1) != '\0')
+ types++;
+
+ /*
+ * If this entry has already been handled, one way or another,
+ * skip it.
+ */
+ if (del[i].status != DIRECTORY_NOT_FOUND)
+ continue;
+
+ char *id = ids->idmap_utf8str_list_val[i];
+
+ if (type == DIRECTORY_ID_SID[0]) {
+ /*
+ * Is it our SID?
+ * Check whether the first part matches, then a "-",
+ * then a single RID.
+ */
+ if (strncasecmp(id, my_machine_sid, machine_sid_len) !=
+ 0)
+ continue;
+ if (id[machine_sid_len] != '-')
+ continue;
+ char *p;
+ uint32_t rid =
+ strtoul(id + machine_sid_len + 1, &p, 10);
+ if (*p != '\0')
+ continue;
+
+ if (rid < LOCALRID_UID_MIN) {
+ /* Builtin, not handled here */
+ continue;
+ }
+
+ if (rid <= LOCALRID_UID_MAX) {
+ /* User */
+ errno = 0;
+ pwd = getpwuid(rid - LOCALRID_UID_MIN);
+ if (pwd == NULL) {
+ if (errno == 0) /* Not found */
+ continue;
+ char buf[40];
+ int err = errno;
+ (void) snprintf(buf, sizeof (buf),
+ "%d", err);
+ directory_entry_set_error(&del[i],
+ directory_error("errno.getpwuid",
+ "getpwuid: %2 (%1)",
+ buf, strerror(err), NULL));
+ continue;
+ }
+ } else if (rid >= LOCALRID_GID_MIN &&
+ rid <= LOCALRID_GID_MAX) {
+ /* Group */
+ errno = 0;
+ grp = getgrgid(rid - LOCALRID_GID_MIN);
+ if (grp == NULL) {
+ if (errno == 0) /* Not found */
+ continue;
+ char buf[40];
+ int err = errno;
+ (void) snprintf(buf, sizeof (buf),
+ "%d", err);
+ directory_entry_set_error(&del[i],
+ directory_error("errno.getgrgid",
+ "getgrgid: %2 (%1)",
+ buf, strerror(err), NULL));
+ continue;
+ }
+ } else
+ continue;
+
+ } else {
+ int id_len = strlen(id);
+ char name[id_len + 1];
+ char domain[id_len + 1];
+
+ split_name(name, domain, id);
+
+ if (domain[0] != '\0') {
+ if (!domain_eq(domain, my_host_name))
+ continue;
+ }
+
+ /*
+ * If the caller has requested user or group
+ * information specifically, we only set one of
+ * pwd or grp.
+ * If the caller has requested either type, we try
+ * both in the hopes of getting one.
+ * Note that directory_provider_nsswitch_populate
+ * considers it to be an error if both are set.
+ */
+ if (type != DIRECTORY_ID_GROUP[0]) {
+ /* prep for not found / error case */
+ errno = 0;
+
+ pwd = getpwnam(name);
+ if (pwd == NULL && errno != 0) {
+ char buf[40];
+ int err = errno;
+ (void) snprintf(buf, sizeof (buf),
+ "%d", err);
+ directory_entry_set_error(&del[i],
+ directory_error("errno.getpwnam",
+ "getpwnam: %2 (%1)",
+ buf, strerror(err), NULL));
+ continue;
+ }
+ }
+
+ if (type != DIRECTORY_ID_USER[0]) {
+ /* prep for not found / error case */
+ errno = 0;
+
+ grp = getgrnam(name);
+ if (grp == NULL && errno != 0) {
+ char buf[40];
+ int err = errno;
+ (void) snprintf(buf, sizeof (buf),
+ "%d", err);
+ directory_entry_set_error(&del[i],
+ directory_error("errno.getgrnam",
+ "getgrnam: %2 (%1)",
+ buf, strerror(err), NULL));
+ continue;
+ }
+ }
+ }
+
+ /*
+ * Didn't find it, don't populate the structure.
+ * Another provider might populate it.
+ */
+ if (pwd == NULL && grp == NULL)
+ continue;
+
+ de = directory_provider_nsswitch_populate(&del[i], pwd, grp,
+ attrs);
+ if (de != NULL) {
+ directory_entry_set_error(&del[i], de);
+ de = NULL;
+ continue;
+ }
+ }
+
+ return (NULL);
+}
+
+/*
+ * Given a pwd structure or a grp structure, and a list of attributes that
+ * were requested, populate the structure to return to the caller.
+ */
+static
+directory_error_t
+directory_provider_nsswitch_populate(
+ directory_entry_rpc *pent,
+ struct passwd *pwd,
+ struct group *grp,
+ idmap_utf8str_list *attrs)
+{
+ int j;
+ directory_values_rpc *llvals;
+ int nattrs;
+
+ /*
+ * If it wasn't for this case, everything would be a lot simpler.
+ * UNIX allows users and groups with the same name. Windows doesn't.
+ */
+ if (pwd != NULL && grp != NULL) {
+ return directory_error("Ambiguous.Name",
+ "Ambiguous name, is both a user and a group",
+ NULL);
+ }
+
+ nattrs = attrs->idmap_utf8str_list_len;
+
+ llvals = calloc(nattrs, sizeof (directory_values_rpc));
+ if (llvals == NULL)
+ goto nomem;
+
+ pent->directory_entry_rpc_u.attrs.attrs_val = llvals;
+ pent->directory_entry_rpc_u.attrs.attrs_len = nattrs;
+ pent->status = DIRECTORY_FOUND;
+
+ for (j = 0; j < nattrs; j++) {
+ directory_values_rpc *val;
+ char *a;
+ directory_error_t de;
+
+ /*
+ * We're going to refer to these a lot, so make a shorthand
+ * copy.
+ */
+ a = attrs->idmap_utf8str_list_val[j];
+ val = &llvals[j];
+
+ /*
+ * Start by assuming no errors and that we don't have
+ * the information
+ */
+ val->found = FALSE;
+ de = NULL;
+
+ if (pwd != NULL) {
+ /*
+ * Handle attributes for user entries.
+ */
+ if (strcaseeq(a, "cn")) {
+ const char *p = pwd->pw_name;
+ de = str_list_dav(val, &p, 1);
+ } else if (strcaseeq(a, "objectClass")) {
+ static const char *objectClasses[] = {
+ "top",
+ "posixAccount",
+ };
+ de = str_list_dav(val, objectClasses,
+ NELEM(objectClasses));
+ } else if (strcaseeq(a, "gidNumber")) {
+ de = uint_list_dav(val, &pwd->pw_gid, 1);
+ } else if (strcaseeq(a, "objectSid")) {
+ de = machine_sid_dav(val,
+ pwd->pw_uid + LOCALRID_UID_MIN);
+ } else if (strcaseeq(a, "displayName")) {
+ const char *p = pwd->pw_gecos;
+ de = str_list_dav(val, &p, 1);
+ } else if (strcaseeq(a, "distinguishedName")) {
+ char *dn;
+ RDLOCK_CONFIG();
+ (void) asprintf(&dn,
+ "uid=%s,ou=people,dc=%s",
+ pwd->pw_name, _idmapdstate.hostname);
+ UNLOCK_CONFIG();
+ if (dn == NULL)
+ goto nomem;
+ const char *cdn = dn;
+ de = str_list_dav(val, &cdn, 1);
+ free(dn);
+ } else if (strcaseeq(a, "uid")) {
+ const char *p = pwd->pw_name;
+ de = str_list_dav(val, &p, 1);
+ } else if (strcaseeq(a, "uidNumber")) {
+ de = uint_list_dav(val, &pwd->pw_uid, 1);
+ } else if (strcaseeq(a, "gecos")) {
+ const char *p = pwd->pw_gecos;
+ de = str_list_dav(val, &p, 1);
+ } else if (strcaseeq(a, "homeDirectory")) {
+ const char *p = pwd->pw_dir;
+ de = str_list_dav(val, &p, 1);
+ } else if (strcaseeq(a, "loginShell")) {
+ const char *p = pwd->pw_shell;
+ de = str_list_dav(val, &p, 1);
+ } else if (strcaseeq(a, "x-sun-canonicalName")) {
+ char *canon;
+ RDLOCK_CONFIG();
+ (void) asprintf(&canon, "%s@%s",
+ pwd->pw_name, _idmapdstate.hostname);
+ UNLOCK_CONFIG();
+ if (canon == NULL)
+ goto nomem;
+ const char *ccanon = canon;
+ de = str_list_dav(val, &ccanon, 1);
+ free(canon);
+ } else if (strcaseeq(a, "x-sun-provider")) {
+ const char *provider = "UNIX-passwd";
+ de = str_list_dav(val, &provider, 1);
+ }
+ } else if (grp != NULL) {
+ /*
+ * Handle attributes for group entries.
+ */
+ if (strcaseeq(a, "cn")) {
+ const char *p = grp->gr_name;
+ de = str_list_dav(val, &p, 1);
+ } else if (strcaseeq(a, "objectClass")) {
+ static const char *objectClasses[] = {
+ "top",
+ "posixGroup",
+ };
+ de = str_list_dav(val, objectClasses,
+ NELEM(objectClasses));
+ } else if (strcaseeq(a, "gidNumber")) {
+ de = uint_list_dav(val, &grp->gr_gid, 1);
+ } else if (strcaseeq(a, "objectSid")) {
+ de = machine_sid_dav(val,
+ grp->gr_gid + LOCALRID_GID_MIN);
+ } else if (strcaseeq(a, "displayName")) {
+ const char *p = grp->gr_name;
+ de = str_list_dav(val, &p, 1);
+ } else if (strcaseeq(a, "distinguishedName")) {
+ char *dn;
+ RDLOCK_CONFIG();
+ (void) asprintf(&dn,
+ "cn=%s,ou=group,dc=%s",
+ grp->gr_name, _idmapdstate.hostname);
+ UNLOCK_CONFIG();
+ if (dn == NULL)
+ goto nomem;
+ const char *cdn = dn;
+ de = str_list_dav(val, &cdn, 1);
+ free(dn);
+ } else if (strcaseeq(a, "memberUid")) {
+ /*
+ * NEEDSWORK: There is probably a non-cast
+ * way to do this, but I don't immediately
+ * see it.
+ */
+ const char * const *members =
+ (const char * const *)grp->gr_mem;
+ de = str_list_dav(val, members, 0);
+ } else if (strcaseeq(a, "x-sun-canonicalName")) {
+ char *canon;
+ RDLOCK_CONFIG();
+ (void) asprintf(&canon, "%s@%s",
+ grp->gr_name, _idmapdstate.hostname);
+ UNLOCK_CONFIG();
+ if (canon == NULL)
+ goto nomem;
+ const char *ccanon = canon;
+ de = str_list_dav(val, &ccanon, 1);
+ free(canon);
+ } else if (strcaseeq(a, "x-sun-provider")) {
+ const char *provider = "UNIX-group";
+ de = str_list_dav(val, &provider, 1);
+ }
+ }
+
+ if (de != NULL)
+ return (de);
+ }
+
+ return (NULL);
+
+nomem:
+ return (directory_error("ENOMEM.users",
+ "No memory allocating return value for user lookup", NULL));
+}
+
+/*
+ * Populate a directory attribute value with a SID based on our machine SID
+ * and the specified RID.
+ *
+ * It's a bit perverse that we must take a text-format SID and turn it into
+ * a binary-format SID, only to have the caller probably turn it back into
+ * text format, but SIDs are carried across LDAP in binary format.
+ */
+static
+directory_error_t
+machine_sid_dav(directory_values_rpc *lvals, unsigned int rid)
+{
+ sid_t *sid;
+ directory_error_t de;
+
+ RDLOCK_CONFIG();
+ int len = strlen(_idmapdstate.cfg->pgcfg.machine_sid);
+ char buf[len + 100]; /* 100 is enough space for any RID */
+ (void) snprintf(buf, sizeof (buf), "%s-%u",
+ _idmapdstate.cfg->pgcfg.machine_sid, rid);
+ UNLOCK_CONFIG();
+
+ sid = sid_fromstr(buf);
+ if (sid == NULL)
+ goto nomem;
+
+ sid_to_le(sid);
+
+ de = bin_list_dav(lvals, sid, 1, sid_len(sid));
+ sid_free(sid);
+ return (de);
+
+nomem:
+ return (directory_error("ENOMEM.machine_sid_dav",
+ "Out of memory allocating return value for lookup", NULL));
+}
+
+struct directory_provider_static directory_provider_nsswitch = {
+ "files",
+ directory_provider_nsswitch_get,
+};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/idmap/idmapd/directory_server.c Fri Jul 17 17:54:42 2009 -0700
@@ -0,0 +1,292 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Server-side support for directory information lookup functions.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <malloc.h>
+#include <sys/types.h>
+#include <netdb.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <string.h>
+#include <note.h>
+#include "idmapd.h"
+#include "directory.h"
+#include "directory_private.h"
+#include <rpcsvc/idmap_prot.h>
+#include "directory_library_impl.h"
+#include "directory_server_impl.h"
+#include "sized_array.h"
+#include "miscutils.h"
+
+/*
+ * Here's a list of all of the modules that provide directory
+ * information. In the fullness of time this should probably be
+ * a plugin-able switch mechanism.
+ * Note that the list is in precedence order.
+ */
+extern struct directory_provider_static directory_provider_builtin;
+extern struct directory_provider_static directory_provider_nsswitch;
+extern struct directory_provider_static directory_provider_ad;
+struct directory_provider_static *providers[] = {
+ &directory_provider_builtin,
+ &directory_provider_nsswitch,
+ &directory_provider_ad,
+};
+
+/*
+ * This is the entry point for all directory lookup service requests.
+ */
+bool_t
+directory_get_common_1_svc(
+ idmap_utf8str_list ids,
+ idmap_utf8str types,
+ idmap_utf8str_list attrs,
+ directory_results_rpc *result,
+ struct svc_req *req)
+{
+ NOTE(ARGUNUSED(req))
+ int nids;
+ directory_entry_rpc *entries;
+ directory_error_t de;
+ int i;
+
+ nids = ids.idmap_utf8str_list_len;
+
+ entries = (directory_entry_rpc *)
+ calloc(nids, sizeof (directory_entry_rpc));
+ if (entries == NULL)
+ goto nomem;
+ result->directory_results_rpc_u.entries.entries_val = entries;
+ result->directory_results_rpc_u.entries.entries_len = nids;
+ result->failed = FALSE;
+
+ for (i = 0; i < nids; i++) {
+ if (strlen(ids.idmap_utf8str_list_val[i]) >
+ IDMAP_MAX_NAME_LEN) {
+ directory_entry_set_error(&entries[i],
+ directory_error("invalid_arg.id.too_long",
+ "Identifier too long", NULL));
+ }
+ }
+
+ for (i = 0; i < NELEM(providers); i++) {
+ de = providers[i]->get(entries, &ids, types,
+ &attrs);
+ if (de != NULL)
+ goto err;
+ }
+
+ return (TRUE);
+
+nomem:
+ de = directory_error("ENOMEM.get_common",
+ "Insufficient memory retrieving directory data", NULL);
+
+err:
+ xdr_free(xdr_directory_results_rpc, (char *)result);
+ result->failed = TRUE;
+ return (
+ directory_error_to_rpc(&result->directory_results_rpc_u.err, de));
+}
+
+/*
+ * Split name into {domain, name}.
+ * Suggest allocating name and domain on the stack, same size as id,
+ * using variable length arrays.
+ */
+void
+split_name(char *name, char *domain, char *id)
+{
+ char *p;
+
+ if ((p = strchr(id, '@')) != NULL) {
+ (void) strlcpy(name, id, p - id + 1);
+ (void) strcpy(domain, p + 1);
+ } else if ((p = strchr(id, '\\')) != NULL) {
+ (void) strcpy(name, p + 1);
+ (void) strlcpy(domain, id, p - id + 1);
+ } else {
+ (void) strcpy(name, id);
+ (void) strcpy(domain, "");
+ }
+}
+
+/*
+ * Given a list of strings, return a set of directory attribute values.
+ *
+ * Mark that the attribute was found.
+ *
+ * Note that the terminating \0 is *not* included in the result, because
+ * that's the way that strings come from LDAP.
+ * (Note also that the client side stuff adds in a terminating \0.)
+ *
+ * Note that on error the array may have been partially populated and will
+ * need to be cleaned up by the caller. This is normally not a problem
+ * because the caller will need to clean up several such arrays.
+ */
+directory_error_t
+str_list_dav(directory_values_rpc *lvals, const char * const *str_list, int n)
+{
+ directory_value_rpc *dav;
+ int i;
+
+ if (n == 0) {
+ for (n = 0; str_list[n] != NULL; n++)
+ /* LOOP */;
+ }
+
+ dav = calloc(n, sizeof (directory_value_rpc));
+ if (dav == NULL)
+ goto nomem;
+
+ lvals->directory_values_rpc_u.values.values_val = dav;
+ lvals->directory_values_rpc_u.values.values_len = n;
+ lvals->found = TRUE;
+
+ for (i = 0; i < n; i++) {
+ int len;
+
+ len = strlen(str_list[i]);
+ dav[i].directory_value_rpc_val = memdup(str_list[i], len);
+ if (dav[i].directory_value_rpc_val == NULL)
+ goto nomem;
+ dav[i].directory_value_rpc_len = len;
+ }
+
+ return (NULL);
+
+nomem:
+ return (directory_error("ENOMEM.str_list_dav",
+ "Insufficient memory copying values"));
+}
+
+/*
+ * Given a list of unsigned integers, return a set of string directory
+ * attribute values.
+ *
+ * Mark that the attribute was found.
+ *
+ * Note that the terminating \0 is *not* included in the result, because
+ * that's the way that strings come from LDAP.
+ * (Note also that the client side stuff adds in a terminating \0.)
+ *
+ * Note that on error the array may have been partially populated and will
+ * need to be cleaned up by the caller. This is normally not a problem
+ * because the caller will need to clean up several such arrays.
+ */
+directory_error_t
+uint_list_dav(directory_values_rpc *lvals, const unsigned int *array, int n)
+{
+ directory_value_rpc *dav;
+ int i;
+
+ dav = calloc(n, sizeof (directory_value_rpc));
+ if (dav == NULL)
+ goto nomem;
+
+ lvals->directory_values_rpc_u.values.values_val = dav;
+ lvals->directory_values_rpc_u.values.values_len = n;
+ lvals->found = TRUE;
+
+ for (i = 0; i < n; i++) {
+ char buf[100]; /* larger than any integer */
+ int len;
+
+ (void) snprintf(buf, sizeof (buf), "%u", array[i]);
+
+ len = strlen(buf);
+ dav[i].directory_value_rpc_val = memdup(buf, len);
+ if (dav[i].directory_value_rpc_val == NULL)
+ goto nomem;
+ dav[i].directory_value_rpc_len = len;
+ }
+
+ return (NULL);
+
+nomem:
+ return (directory_error("ENOMEM.uint_list_dav",
+ "Insufficient memory copying values"));
+}
+
+/*
+ * Given a list of fixed-length binary chunks, return a set of binary
+ * directory attribute values.
+ *
+ * Mark that the attribute was found.
+ *
+ * Note that on error the array may have been partially populated and will
+ * need to be cleaned up by the caller. This is normally not a problem
+ * because the caller will need to clean up several such arrays.
+ */
+directory_error_t
+bin_list_dav(directory_values_rpc *lvals, const void *array, int n, size_t sz)
+{
+ directory_value_rpc *dav;
+ char *inbuf = (char *)array;
+ int i;
+
+ dav = calloc(n, sizeof (directory_value_rpc));
+ if (dav == NULL)
+ goto nomem;
+
+ lvals->directory_values_rpc_u.values.values_val = dav;
+ lvals->directory_values_rpc_u.values.values_len = n;
+ lvals->found = TRUE;
+
+ for (i = 0; i < n; i++) {
+ dav[i].directory_value_rpc_val = memdup(inbuf, sz);
+ if (dav[i].directory_value_rpc_val == NULL)
+ goto nomem;
+ dav[i].directory_value_rpc_len = sz;
+ inbuf += sz;
+ }
+
+ return (NULL);
+
+nomem:
+ return (directory_error("ENOMEM.bin_list_dav",
+ "Insufficient memory copying values"));
+}
+
+/*
+ * Set up to return an error on a particular directory entry.
+ * Note that the caller need not (and in fact must not) free
+ * the directory_error_t; it will be freed when the directory entry
+ * list is freed.
+ */
+void
+directory_entry_set_error(directory_entry_rpc *ent, directory_error_t de)
+{
+ xdr_free(xdr_directory_entry_rpc, (char *)&ent);
+ ent->status = DIRECTORY_ERROR;
+ (void) directory_error_to_rpc(&ent->directory_entry_rpc_u.err, de);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/idmap/idmapd/directory_server_impl.h Fri Jul 17 17:54:42 2009 -0700
@@ -0,0 +1,79 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DIRECTORY_SERVER_IMPL_H
+#define _DIRECTORY_SERVER_IMPL_H
+
+/*
+ * Internal implementation details for the server side of directory lookup.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Functions to populate Directory Attribute Value lists.
+ */
+directory_error_t str_list_dav(directory_values_rpc *lvals,
+ const char * const *str_list, int n);
+directory_error_t uint_list_dav(directory_values_rpc *lvals,
+ const unsigned int *uint_list, int n);
+directory_error_t bin_list_dav(directory_values_rpc *lvals,
+ const void *array, int n, size_t sz);
+
+/*
+ * Split a name@domain into name, domain. Recommend allocating the
+ * destination buffers the same size as the input, on the stack,
+ * using variable length arrays.
+ */
+void split_name(char *name, char *domain, char *id);
+
+/*
+ * Insert a directory_error_t into a directory entry to be returned.
+ * Caller MUST NOT free the directory_error_t.
+ */
+void directory_entry_set_error(directory_entry_rpc *ent,
+ directory_error_t de);
+
+/*
+ * This is the structure by which a provider supplies its entry points.
+ * The name is not currently used.
+ */
+struct directory_provider_static {
+ char *name;
+ directory_error_t (*get)(
+ directory_entry_rpc *ret,
+ idmap_utf8str_list *ids,
+ idmap_utf8str types,
+ idmap_utf8str_list *attrs);
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DIRECTORY_SERVER_IMPL_H */
--- a/usr/src/cmd/idmap/idmapd/idmap_config.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/cmd/idmap/idmapd/idmap_config.c Fri Jul 17 17:54:42 2009 -0700
@@ -696,7 +696,6 @@
int num_df1 = 0;
int num_df2 = 0;
boolean_t match;
- int err;
for (i = 0; df1[i].domain[0] != '\0'; i++)
if (df1[i].trusted)
@@ -714,10 +713,8 @@
match = B_FALSE;
for (j = 0; df2[j].domain[0] != '\0'; j++) {
if (df2[j].trusted &&
- u8_strcmp(df1[i].domain, df2[i].domain, 0,
- U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err)
- == 0 && err == 0 &&
- strcmp(df1[i].sid, df2[i].sid) == 0) {
+ domain_eq(df1[i].domain, df2[j].domain) &&
+ strcmp(df1[i].sid, df2[j].sid) == 0) {
match = B_TRUE;
break;
}
@@ -756,10 +753,10 @@
(*new)[j].forest_name) == 0 &&
ad_disc_compare_ds(
(*value)[i].global_catalog,
- (*new)[i].global_catalog) == 0 &&
+ (*new)[j].global_catalog) == 0 &&
compare_trusteddomainsinforest(
(*value)[i].domains_in_forest,
- (*new)[i].domains_in_forest) == 0) {
+ (*new)[j].domains_in_forest) == 0) {
match = B_TRUE;
break;
}
@@ -1274,7 +1271,6 @@
char *forestname;
int num_trusteddomains;
boolean_t new_forest;
- int err;
char *trusteddomain;
idmap_ad_disc_ds_t *globalcatalog;
idmap_trustedforest_t *trustedforests;
@@ -1368,11 +1364,8 @@
/* Mark the domain as trusted */
for (l = 0;
domainsinforest[l].domain[0] != '\0'; l++) {
- if (u8_strcmp(trusteddomain,
- domainsinforest[l].domain, 0,
- U8_STRCMP_CI_LOWER,
- U8_UNICODE_LATEST, &err) == 0 &&
- err == 0) {
+ if (domain_eq(trusteddomain,
+ domainsinforest[l].domain)) {
domainsinforest[l].trusted =
TRUE;
break;
@@ -1420,11 +1413,8 @@
/* Mark the domain as trusted */
for (l = 0; domainsinforest[l].domain[0] != '\0';
l++) {
- if (u8_strcmp(trusteddomain,
- domainsinforest[l].domain, 0,
- U8_STRCMP_CI_LOWER,
- U8_UNICODE_LATEST, &err) == 0 &&
- err == 0) {
+ if (domain_eq(trusteddomain,
+ domainsinforest[l].domain)) {
domainsinforest[l].trusted = TRUE;
break;
}
@@ -1434,6 +1424,8 @@
if (j > 0) {
pgcfg->num_trusted_forests = j;
pgcfg->trusted_forests = trustedforests;
+ } else {
+ free(trustedforests);
}
}
--- a/usr/src/cmd/idmap/idmapd/idmapd.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/cmd/idmap/idmapd/idmapd.c Fri Jul 17 17:54:42 2009 -0700
@@ -59,12 +59,6 @@
static void init_idmapd();
static void fini_idmapd();
-
-#define _RPCSVC_CLOSEDOWN 120
-
-int _rpcsvcstate = _IDLE; /* Set when a request is serviced */
-int _rpcsvccount = 0; /* Number of requests being serviced */
-mutex_t _svcstate_lock; /* lock for _rpcsvcstate, _rpcsvccount */
idmapd_state_t _idmapdstate;
SVCXPRT *xprt = NULL;
--- a/usr/src/cmd/idmap/idmapd/idmapd.h Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/cmd/idmap/idmapd/idmapd.h Fri Jul 17 17:54:42 2009 -0700
@@ -47,15 +47,9 @@
extern "C" {
#endif
-/* States a server can be in wrt request */
-#define _IDLE 0
-#define _SERVED 1
-
#define SENTINEL_PID UINT32_MAX
#define CHECK_NULL(s) (s != NULL ? s : "null")
-extern int _rpcsvcstate; /* set when a request is serviced */
-extern int _rpcsvccount; /* number of requests being serviced */
extern mutex_t _svcstate_lock; /* lock for _rpcsvcstate, _rpcsvccount */
typedef enum idmap_namemap_mode {
@@ -154,6 +148,21 @@
const char *msg;
} msg_table_t;
+/*
+ * Data structure to store well-known SIDs and
+ * associated mappings (if any)
+ */
+typedef struct wksids_table {
+ const char *sidprefix;
+ uint32_t rid;
+ const char *domain;
+ const char *winname;
+ int is_wuser;
+ uid_t pid;
+ int is_user;
+ int direction;
+} wksids_table_t;
+
#define IDMAPD_SEARCH_TIMEOUT 3 /* seconds */
#define IDMAPD_LDAP_OPEN_TIMEOUT 1 /* secs; initial, w/ exp backoff */
@@ -221,6 +230,14 @@
#define IS_REQUEST_GID(request) \
((request).id1.idtype == IDMAP_GID)
+/*
+ * Local RID ranges
+ */
+#define LOCALRID_UID_MIN 1000U
+#define LOCALRID_UID_MAX ((uint32_t)INT32_MAX)
+#define LOCALRID_GID_MIN (((uint32_t)INT32_MAX) + 1)
+#define LOCALRID_GID_MAX UINT32_MAX
+
typedef idmap_retcode (*update_list_res_cb)(void *, const char **, uint64_t);
typedef int (*list_svc_cb)(void *, int, char **, char **);
@@ -286,6 +303,13 @@
extern void idmap_log_syslog(boolean_t);
extern void idmap_log_degraded(boolean_t);
+extern const wksids_table_t *find_wksid_by_pid(uid_t pid, int is_user);
+extern const wksids_table_t *find_wksid_by_sid(const char *sid, int rid,
+ int type);
+extern const wksids_table_t *find_wksid_by_name(const char *name,
+ const char *domain, int type);
+extern const wksids_table_t *find_wk_by_sid(char *sid);
+
#ifdef __cplusplus
}
#endif
--- a/usr/src/cmd/idmap/idmapd/rpc_svc.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/cmd/idmap/idmapd/rpc_svc.c Fri Jul 17 17:54:42 2009 -0700
@@ -24,73 +24,152 @@
*/
/*
- * RPC service routines
- * It was initially generated using rpcgen.
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ * Edit idmap_prot.x and rebuild this file with
+ * rpcgen -CMNm -o idmap_prot_svc.c.new ../../../uts/common/rpcsvc/idmap_prot.x
+ * then merge as required. A recent version of rpcgen is needed to
+ * produce this exact file; when the revised rpcgen is available in the
+ * build environment this file can be built automatically.
*/
-#include "idmapd.h"
-#include <rpcsvc/idmap_prot.h>
-#include <stdlib.h>
+#include "../../../uts/common/rpcsvc/idmap_prot.h"
+#include <stdio.h>
+#include <stdlib.h> /* getenv, exit */
#include <signal.h>
-#include <rpc/xdr.h>
-#include <rpc/rpc.h>
-#include <string.h>
-#include <thread.h>
-#include <synch.h>
+#include <rpc/pmap_clnt.h> /* for pmap_unset */
+#include <string.h> /* strcmp */
+#include <unistd.h> /* setsid */
+#include <sys/types.h>
+#include <memory.h>
+#include <stropts.h>
+#include <sys/resource.h> /* rlimit */
+#include <syslog.h>
+
+#ifndef SIG_PF
+#define SIG_PF void(*)(int)
+#endif
+
+#ifdef DEBUG
+#define RPC_SVC_FG
+#endif
+
+#define _RPCSVC_CLOSEDOWN 120
+extern int _rpcpmstart; /* Started by a port monitor ? */
+
+/* States a server can be in wrt request */
+#define _IDLE 0
+#define _SERVED 1
+
+/* LINTED static unused if no main */
+static int _rpcsvcstate = _IDLE; /* Set when a request is serviced */
+static int _rpcsvccount = 0; /* Number of requests being serviced */
+mutex_t _svcstate_lock; /* lock for _rpcsvcstate, _rpcsvccount */
+
+#if defined(RPC_MSGOUT)
+extern void RPC_MSGOUT(const char *, ...);
+#else /* defined(RPC_MSGOUT) */
+static void
+RPC_MSGOUT(const char *fmt, char *msg)
+{
+#ifdef RPC_SVC_FG
+ if (_rpcpmstart)
+ syslog(LOG_ERR, fmt, msg);
+ else {
+ (void) fprintf(stderr, fmt, msg);
+ (void) putc('\n', stderr);
+ }
+#else
+ syslog(LOG_ERR, fmt, msg);
+#endif
+}
+#endif /* defined(RPC_MSGOUT) */
/* ARGSUSED */
int
-_idmap_null_1(void *argp, void *result, struct svc_req *rqstp)
+_idmap_null_1(
+ void *argp,
+ void *result,
+ struct svc_req *rqstp)
{
return (idmap_null_1_svc(result, rqstp));
}
int
-_idmap_get_mapped_ids_1(idmap_mapping_batch *argp, idmap_ids_res *result,
- struct svc_req *rqstp)
+_idmap_get_mapped_ids_1(
+ idmap_mapping_batch *argp,
+ idmap_ids_res *result,
+ struct svc_req *rqstp)
{
return (idmap_get_mapped_ids_1_svc(*argp, result, rqstp));
}
int
-_idmap_list_mappings_1(idmap_list_mappings_1_argument *argp,
- idmap_mappings_res *result, struct svc_req *rqstp)
+_idmap_list_mappings_1(
+ idmap_list_mappings_1_argument *argp,
+ idmap_mappings_res *result,
+ struct svc_req *rqstp)
{
- return (idmap_list_mappings_1_svc(argp->lastrowid,
- argp->limit, argp->flag, result, rqstp));
+ return (idmap_list_mappings_1_svc(
+ argp->lastrowid,
+ argp->limit,
+ argp->flag,
+ result, rqstp));
}
int
-_idmap_list_namerules_1(idmap_list_namerules_1_argument *argp,
- idmap_namerules_res *result, struct svc_req *rqstp)
+_idmap_list_namerules_1(
+ idmap_list_namerules_1_argument *argp,
+ idmap_namerules_res *result,
+ struct svc_req *rqstp)
{
- return (idmap_list_namerules_1_svc(argp->rule, argp->lastrowid,
- argp->limit, result, rqstp));
+ return (idmap_list_namerules_1_svc(
+ argp->rule,
+ argp->lastrowid,
+ argp->limit,
+ result, rqstp));
}
int
-_idmap_update_1(idmap_update_batch *argp, idmap_update_res *res,
- struct svc_req *rqstp)
+_idmap_update_1(
+ idmap_update_batch *argp,
+ idmap_update_res *result,
+ struct svc_req *rqstp)
{
- return (idmap_update_1_svc(*argp, res, rqstp));
+ return (idmap_update_1_svc(*argp, result, rqstp));
}
int
-_idmap_get_mapped_id_by_name_1(idmap_mapping *argp,
- idmap_mappings_res *result, struct svc_req *rqstp)
+_idmap_get_mapped_id_by_name_1(
+ idmap_mapping *argp,
+ idmap_mappings_res *result,
+ struct svc_req *rqstp)
{
return (idmap_get_mapped_id_by_name_1_svc(*argp, result, rqstp));
}
int
-_idmap_get_prop_1(idmap_prop_type *argp,
- idmap_prop_res *result, struct svc_req *rqstp)
+_idmap_get_prop_1(
+ idmap_prop_type *argp,
+ idmap_prop_res *result,
+ struct svc_req *rqstp)
{
return (idmap_get_prop_1_svc(*argp, result, rqstp));
}
-
+int
+_directory_get_common_1(
+ directory_get_common_1_argument *argp,
+ directory_results_rpc *result,
+ struct svc_req *rqstp)
+{
+ return (directory_get_common_1_svc(
+ argp->ids,
+ argp->types,
+ argp->attrs,
+ result, rqstp));
+}
void
idmap_prog_1(struct svc_req *rqstp, register SVCXPRT *transp)
@@ -102,6 +181,7 @@
idmap_update_batch idmap_update_1_arg;
idmap_mapping idmap_get_mapped_id_by_name_1_arg;
idmap_prop_type idmap_get_prop_1_arg;
+ directory_get_common_1_argument directory_get_common_1_arg;
} argument;
union {
idmap_ids_res idmap_get_mapped_ids_1_res;
@@ -110,6 +190,7 @@
idmap_update_res idmap_update_1_res;
idmap_mappings_res idmap_get_mapped_id_by_name_1_res;
idmap_prop_res idmap_get_prop_1_res;
+ directory_results_rpc directory_get_common_1_res;
} result;
bool_t retval;
xdrproc_t _xdr_argument, _xdr_result;
@@ -120,61 +201,84 @@
(void) mutex_unlock(&_svcstate_lock);
switch (rqstp->rq_proc) {
case IDMAP_NULL:
- _xdr_argument = (xdrproc_t)xdr_void;
- _xdr_result = (xdrproc_t)xdr_void;
+ _xdr_argument = (xdrproc_t)
+ xdr_void;
+ _xdr_result = (xdrproc_t)
+ xdr_void;
local = (bool_t (*) (char *, void *, struct svc_req *))
_idmap_null_1;
break;
case IDMAP_GET_MAPPED_IDS:
- _xdr_argument = (xdrproc_t)xdr_idmap_mapping_batch;
- _xdr_result = (xdrproc_t)xdr_idmap_ids_res;
+ _xdr_argument = (xdrproc_t)
+ xdr_idmap_mapping_batch;
+ _xdr_result = (xdrproc_t)
+ xdr_idmap_ids_res;
local = (bool_t (*) (char *, void *, struct svc_req *))
_idmap_get_mapped_ids_1;
break;
case IDMAP_LIST_MAPPINGS:
- _xdr_argument = (xdrproc_t)xdr_idmap_list_mappings_1_argument;
- _xdr_result = (xdrproc_t)xdr_idmap_mappings_res;
+ _xdr_argument = (xdrproc_t)
+ xdr_idmap_list_mappings_1_argument;
+ _xdr_result = (xdrproc_t)
+ xdr_idmap_mappings_res;
local = (bool_t (*) (char *, void *, struct svc_req *))
_idmap_list_mappings_1;
break;
case IDMAP_LIST_NAMERULES:
- _xdr_argument = (xdrproc_t)xdr_idmap_list_namerules_1_argument;
- _xdr_result = (xdrproc_t)xdr_idmap_namerules_res;
+ _xdr_argument = (xdrproc_t)
+ xdr_idmap_list_namerules_1_argument;
+ _xdr_result = (xdrproc_t)
+ xdr_idmap_namerules_res;
local = (bool_t (*) (char *, void *, struct svc_req *))
_idmap_list_namerules_1;
break;
case IDMAP_UPDATE:
- _xdr_argument = (xdrproc_t)xdr_idmap_update_batch;
- _xdr_result = (xdrproc_t)xdr_idmap_update_res;
+ _xdr_argument = (xdrproc_t)
+ xdr_idmap_update_batch;
+ _xdr_result = (xdrproc_t)
+ xdr_idmap_update_res;
local = (bool_t (*) (char *, void *, struct svc_req *))
_idmap_update_1;
break;
case IDMAP_GET_MAPPED_ID_BY_NAME:
- _xdr_argument = (xdrproc_t)xdr_idmap_mapping;
- _xdr_result = (xdrproc_t)xdr_idmap_mappings_res;
+ _xdr_argument = (xdrproc_t)
+ xdr_idmap_mapping;
+ _xdr_result = (xdrproc_t)
+ xdr_idmap_mappings_res;
local = (bool_t (*) (char *, void *, struct svc_req *))
_idmap_get_mapped_id_by_name_1;
break;
case IDMAP_GET_PROP:
- _xdr_argument = (xdrproc_t)xdr_idmap_prop_type;
- _xdr_result = (xdrproc_t)xdr_idmap_prop_res;
+ _xdr_argument = (xdrproc_t)
+ xdr_idmap_prop_type;
+ _xdr_result = (xdrproc_t)
+ xdr_idmap_prop_res;
local = (bool_t (*) (char *, void *, struct svc_req *))
_idmap_get_prop_1;
break;
+ case DIRECTORY_GET_COMMON:
+ _xdr_argument = (xdrproc_t)
+ xdr_directory_get_common_1_argument;
+ _xdr_result = (xdrproc_t)
+ xdr_directory_results_rpc;
+ local = (bool_t (*) (char *, void *, struct svc_req *))
+ _directory_get_common_1;
+ break;
+
default:
svcerr_noproc(transp);
(void) mutex_lock(&_svcstate_lock);
_rpcsvccount--;
_rpcsvcstate = _SERVED;
(void) mutex_unlock(&_svcstate_lock);
- return;
+ return; /* CSTYLED */
}
(void) memset((char *)&argument, 0, sizeof (argument));
if (!svc_getargs(transp, _xdr_argument, (caddr_t)&argument)) {
@@ -183,27 +287,28 @@
_rpcsvccount--;
_rpcsvcstate = _SERVED;
(void) mutex_unlock(&_svcstate_lock);
- return;
+ return; /* CSTYLED */
}
retval = (bool_t)(*local)((char *)&argument, (void *)&result, rqstp);
- if (_xdr_result && retval > 0 && !svc_sendreply(transp, _xdr_result,
- (char *)&result)) {
+ if (_xdr_result && retval > 0 &&
+ !svc_sendreply(transp, _xdr_result, (char *)&result)) {
svcerr_systemerr(transp);
}
if (!svc_freeargs(transp, _xdr_argument, (caddr_t)&argument)) {
- idmapdlog(LOG_ERR,
- "unable to free RPC arguments");
+ RPC_MSGOUT("%s",
+ "unable to free arguments");
exit(1);
}
if (_xdr_result != NULL) {
if (!idmap_prog_1_freeresult(transp, _xdr_result,
(caddr_t)&result))
- idmapdlog(LOG_ERR,
- "unable to free RPC results");
+ RPC_MSGOUT("%s",
+ "unable to free results");
}
(void) mutex_lock(&_svcstate_lock);
_rpcsvccount--;
_rpcsvcstate = _SERVED;
(void) mutex_unlock(&_svcstate_lock);
+ return; /* CSTYLED */
}
--- a/usr/src/cmd/idmap/idmapd/server.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/cmd/idmap/idmapd/server.c Fri Jul 17 17:54:42 2009 -0700
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -44,6 +44,7 @@
#include <auth_attr.h>
#include <secdb.h>
#include <sys/u8_textprep.h>
+#include <note.h>
#define _VALIDATE_LIST_CB_DATA(col, val, siz)\
retcode = validate_list_cb_data(cb_data, argc, argv, col,\
@@ -1097,3 +1098,20 @@
(void) xdr_free(xdr_result, result);
return (TRUE);
}
+
+/*
+ * This function is called by rpc_svc.c when it encounters an error.
+ */
+NOTE(PRINTFLIKE(1))
+void
+idmap_rpc_msgout(const char *fmt, ...)
+{
+ va_list va;
+ char buf[1000];
+
+ va_start(va, fmt);
+ (void) vsnprintf(buf, sizeof (buf), fmt, va);
+ va_end(va);
+
+ idmapdlog(LOG_ERR, "idmap RPC: %s", buf);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/idmap/idmapd/wksids.c Fri Jul 17 17:54:42 2009 -0700
@@ -0,0 +1,407 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Information about well-known (builtin) names, and functions to retrieve
+ * information about them.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include "idmapd.h"
+#include "miscutils.h"
+
+/*
+ * Table for well-known SIDs.
+ *
+ * Background:
+ *
+ * Some of the well-known principals are stored under:
+ * cn=WellKnown Security Principals, cn=Configuration, dc=<forestRootDomain>
+ * They belong to objectClass "foreignSecurityPrincipal". They don't have
+ * "samAccountName" nor "userPrincipalName" attributes. Their names are
+ * available in "cn" and "name" attributes. Some of these principals have a
+ * second entry under CN=ForeignSecurityPrincipals,dc=<forestRootDomain> and
+ * these duplicate entries have the stringified SID in the "name" and "cn"
+ * attributes instead of the actual name.
+ *
+ * Those of the form S-1-5-32-X are Builtin groups and are stored in the
+ * cn=builtin container (except, Power Users which is not stored in AD)
+ *
+ * These principals are and will remain constant. Therefore doing AD lookups
+ * provides no benefit. Also, using hard-coded table (and thus avoiding AD
+ * lookup) improves performance and avoids additional complexity in the
+ * adutils.c code. Moreover these SIDs can be used when no Active Directory
+ * is available (such as the CIFS server's "workgroup" mode).
+ *
+ * Notes:
+ * 1. Currently we don't support localization of well-known SID names,
+ * unlike Windows.
+ *
+ * 2. Other well-known SIDs i.e. S-1-5-<domain>-<w-k RID> are not stored
+ * here. AD does have normal user/group objects for these objects and
+ * can be looked up using the existing AD lookup code.
+ *
+ * 3. See comments above lookup_wksids_sid2pid() for more information
+ * on how we lookup the wksids table.
+ *
+ * 4. If this table contains two entries for a particular Windows name,
+ * so as to offer both UID and GID mappings, the preferred mapping (the
+ * one that matches Windows usage) must be listed first. That is the
+ * entry that will be used when the caller specifies IDMAP_POSIXID
+ * ("don't care") as the target.
+ *
+ * Entries here come from KB243330, MS-LSAT, and
+ * http://technet.microsoft.com/en-us/library/cc755854.aspx
+ * http://technet.microsoft.com/en-us/library/cc755925.aspx
+ * http://msdn.microsoft.com/en-us/library/cc980032(PROT.10).aspx
+ */
+static wksids_table_t wksids[] = {
+ /* S-1-0 Null Authority */
+ {"S-1-0", 0, "", "Nobody", 1, SENTINEL_PID, -1, 1},
+
+ /* S-1-1 World Authority */
+ {"S-1-1", 0, "", "Everyone", 0, SENTINEL_PID, -1, -1},
+
+ /* S-1-2 Local Authority */
+ {"S-1-2", 0, "", "Local", 0, SENTINEL_PID, -1, -1},
+ {"S-1-2", 1, "", "Console Logon", 0, SENTINEL_PID, -1, -1},
+
+ /* S-1-3 Creator Authority */
+ {"S-1-3", 0, "", "Creator Owner", 1, IDMAP_WK_CREATOR_OWNER_UID, 1, 0},
+ {"S-1-3", 1, "", "Creator Group", 0, IDMAP_WK_CREATOR_GROUP_GID, 0, 0},
+ {"S-1-3", 2, "", "Creator Owner Server", 1, SENTINEL_PID, -1, -1},
+ {"S-1-3", 3, "", "Creator Group Server", 0, SENTINEL_PID, -1, 1},
+ {"S-1-3", 4, "", "Owner Rights", 0, SENTINEL_PID, -1, -1},
+
+ /* S-1-4 Non-unique Authority */
+
+ /* S-1-5 NT Authority */
+ {"S-1-5", 1, "", "Dialup", 0, SENTINEL_PID, -1, -1},
+ {"S-1-5", 2, "", "Network", 0, SENTINEL_PID, -1, -1},
+ {"S-1-5", 3, "", "Batch", 0, SENTINEL_PID, -1, -1},
+ {"S-1-5", 4, "", "Interactive", 0, SENTINEL_PID, -1, -1},
+ /* S-1-5-5-X-Y Logon Session */
+ {"S-1-5", 6, "", "Service", 0, SENTINEL_PID, -1, -1},
+ {"S-1-5", 7, "", "Anonymous Logon", 0, GID_NOBODY, 0, 0},
+ {"S-1-5", 7, "", "Anonymous Logon", 0, UID_NOBODY, 1, 0},
+ {"S-1-5", 8, "", "Proxy", 0, SENTINEL_PID, -1, -1},
+ {"S-1-5", 9, "", "Enterprise Domain Controllers", 0,
+ SENTINEL_PID, -1, -1},
+ {"S-1-5", 10, "", "Self", 0, SENTINEL_PID, -1, -1},
+ {"S-1-5", 11, "", "Authenticated Users", 0, SENTINEL_PID, -1, -1},
+ {"S-1-5", 12, "", "Restricted", 0, SENTINEL_PID, -1, -1},
+ {"S-1-5", 13, "", "Terminal Server Users", 0, SENTINEL_PID, -1, -1},
+ {"S-1-5", 14, "", "Remote Interactive Logon", 0, SENTINEL_PID, -1, -1},
+ {"S-1-5", 15, "", "This Organization", 0, SENTINEL_PID, -1, -1},
+ {"S-1-5", 17, "", "IUSR", 0, SENTINEL_PID, -1, -1},
+ {"S-1-5", 18, "", "Local System", 0, IDMAP_WK_LOCAL_SYSTEM_GID, 0, 0},
+ {"S-1-5", 19, "", "Local Service", 0, SENTINEL_PID, -1, -1},
+ {"S-1-5", 20, "", "Network Service", 0, SENTINEL_PID, -1, -1},
+
+ /* S-1-5-21-<domain> Machine-local definitions */
+ {NULL, 498, NULL, "Enterprise Read-only Domain Controllers", 0,
+ SENTINEL_PID, -1, -1},
+ {NULL, 500, NULL, "Administrator", 1, SENTINEL_PID, 1, -1},
+ {NULL, 501, NULL, "Guest", 1, SENTINEL_PID, 1, -1},
+ {NULL, 502, NULL, "KRBTGT", 1, SENTINEL_PID, 1, -1},
+ {NULL, 512, NULL, "Domain Admins", 0, SENTINEL_PID, -1, -1},
+ {NULL, 513, NULL, "Domain Users", 0, SENTINEL_PID, -1, -1},
+ {NULL, 514, NULL, "Domain Guests", 0, SENTINEL_PID, -1, -1},
+ {NULL, 515, NULL, "Domain Computers", 0, SENTINEL_PID, -1, -1},
+ {NULL, 516, NULL, "Domain Controllers", 0, SENTINEL_PID, -1, -1},
+ {NULL, 517, NULL, "Cert Publishers", 0, SENTINEL_PID, -1, -1},
+ {NULL, 518, NULL, "Schema Admins", 0, SENTINEL_PID, -1, -1},
+ {NULL, 519, NULL, "Enterprise Admins", 0, SENTINEL_PID, -1, -1},
+ {NULL, 520, NULL, "Global Policy Creator Owners", 0,
+ SENTINEL_PID, -1, -1},
+ {NULL, 533, NULL, "RAS and IAS Servers", 0, SENTINEL_PID, -1, -1},
+
+ /* S-1-5-32 BUILTIN */
+ {"S-1-5-32", 544, "BUILTIN", "Administrators", 0, SENTINEL_PID, -1, -1},
+ {"S-1-5-32", 545, "BUILTIN", "Users", 0, SENTINEL_PID, -1, -1},
+ {"S-1-5-32", 546, "BUILTIN", "Guests", 0, SENTINEL_PID, -1, -1},
+ {"S-1-5-32", 547, "BUILTIN", "Power Users", 0, SENTINEL_PID, -1, -1},
+ {"S-1-5-32", 548, "BUILTIN", "Account Operators", 0,
+ SENTINEL_PID, -1, -1},
+ {"S-1-5-32", 549, "BUILTIN", "Server Operators", 0,
+ SENTINEL_PID, -1, -1},
+ {"S-1-5-32", 550, "BUILTIN", "Print Operators", 0,
+ SENTINEL_PID, -1, -1},
+ {"S-1-5-32", 551, "BUILTIN", "Backup Operators", 0,
+ SENTINEL_PID, -1, -1},
+ {"S-1-5-32", 552, "BUILTIN", "Replicator", 0, SENTINEL_PID, -1, -1},
+ {"S-1-5-32", 554, "BUILTIN", "Pre-Windows 2000 Compatible Access", 0,
+ SENTINEL_PID, -1, -1},
+ {"S-1-5-32", 555, "BUILTIN", "Remote Desktop Users", 0,
+ SENTINEL_PID, -1, -1},
+ {"S-1-5-32", 556, "BUILTIN", "Network Configuration Operators", 0,
+ SENTINEL_PID, -1, -1},
+ {"S-1-5-32", 557, "BUILTIN", "Incoming Forest Trust Builders", 0,
+ SENTINEL_PID, -1, -1},
+ {"S-1-5-32", 558, "BUILTIN", "Performance Monitor Users", 0,
+ SENTINEL_PID, -1, -1},
+ {"S-1-5-32", 559, "BUILTIN", "Performance Log Users", 0,
+ SENTINEL_PID, -1, -1},
+ {"S-1-5-32", 560, "BUILTIN", "Windows Authorization Access Group", 0,
+ SENTINEL_PID, -1, -1},
+ {"S-1-5-32", 561, "BUILTIN", "Terminal Server License Servers", 0,
+ SENTINEL_PID, -1, -1},
+ {"S-1-5-32", 562, "BUILTIN", "Distributed COM Users", 0,
+ SENTINEL_PID, -1, -1},
+ {"S-1-5-32", 568, "BUILTIN", "IIS_IUSRS", 0, SENTINEL_PID, -1, -1},
+ {"S-1-5-32", 569, "BUILTIN", "Cryptographic Operators", 0,
+ SENTINEL_PID, -1, -1},
+ {"S-1-5-32", 573, "BUILTIN", "Event Log Readers", 0,
+ SENTINEL_PID, -1, -1},
+ {"S-1-5-32", 574, "BUILTIN", "Certificate Service DCOM Access", 0,
+ SENTINEL_PID, -1, -1},
+
+ {"S-1-5", 33, "", "Write Restricted", 0, SENTINEL_PID, -1, -1},
+
+ /* S-1-5-64 NT Authority */
+ {"S-1-5-64", 10, "", "NTLM Authentication", 0, SENTINEL_PID, -1, -1},
+ {"S-1-5-64", 14, "", "SChannel Authentication", 0,
+ SENTINEL_PID, -1, -1},
+ {"S-1-5-64", 21, "", "Digest Authentication", 0, SENTINEL_PID, -1, -1},
+
+ /* S-1-5-80-a-b-c-d NT Service */
+
+ {"S-1-5", 1000, "", "Other Organization", 0, SENTINEL_PID, -1, -1},
+
+ /* S-1-7 Internet$ */
+
+ /*
+ * S-1-16 Mandatory Label
+ * S-1-16-0 Untrusted Mandatory Level
+ * S-1-16-4096 Low Mandatory Level
+ * S-1-16-8192 Medium Mandatory Level
+ * S-1-16-8448 Medium Plus Mandatory Level
+ * S-1-16-12288 High Mandatory Level
+ * S-1-16-16384 System Mandatory Level
+ * S-1-16-20480 Protected Process Mandatory Level
+ */
+};
+
+/*
+ * Find a wksid entry for the specified Windows name and domain, of the
+ * specified type.
+ *
+ * Ignore entries intended only for U2W use.
+ */
+const
+wksids_table_t *
+find_wksid_by_name(const char *name, const char *domain, int type)
+{
+ int i;
+
+ RDLOCK_CONFIG();
+ int len = strlen(_idmapdstate.hostname);
+ char my_host_name[len + 1];
+ (void) strcpy(my_host_name, _idmapdstate.hostname);
+ UNLOCK_CONFIG();
+
+ for (i = 0; i < NELEM(wksids); i++) {
+ /* Check to see if this entry yields the desired type */
+ switch (type) {
+ case IDMAP_UID:
+ if (wksids[i].is_user == 0)
+ continue;
+ break;
+ case IDMAP_GID:
+ if (wksids[i].is_user == 1)
+ continue;
+ break;
+ case IDMAP_POSIXID:
+ break;
+ default:
+ assert(FALSE);
+ }
+
+ if (strcasecmp(wksids[i].winname, name) != 0)
+ continue;
+
+ if (!EMPTY_STRING(domain)) {
+ const char *dom;
+
+ if (wksids[i].domain != NULL) {
+ dom = wksids[i].domain;
+ } else {
+ dom = my_host_name;
+ }
+ if (strcasecmp(dom, domain) != 0)
+ continue;
+ }
+
+ /*
+ * We have a Windows name, so ignore entries that are only
+ * usable for mapping UNIX->Windows. (Note: the current
+ * table does not have any such entries.)
+ */
+ if (wksids[i].direction == IDMAP_DIRECTION_U2W)
+ continue;
+
+ return (&wksids[i]);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Find a wksid entry for the specified SID, of the specified type.
+ *
+ * Ignore entries intended only for U2W use.
+ */
+const
+wksids_table_t *
+find_wksid_by_sid(const char *sid, int rid, int type)
+{
+ int i;
+
+ RDLOCK_CONFIG();
+ int len = strlen(_idmapdstate.cfg->pgcfg.machine_sid);
+ char my_machine_sid[len + 1];
+ (void) strcpy(my_machine_sid, _idmapdstate.cfg->pgcfg.machine_sid);
+ UNLOCK_CONFIG();
+
+ for (i = 0; i < NELEM(wksids); i++) {
+ int sidcmp;
+
+ /* Check to see if this entry yields the desired type */
+ switch (type) {
+ case IDMAP_UID:
+ if (wksids[i].is_user == 0)
+ continue;
+ break;
+ case IDMAP_GID:
+ if (wksids[i].is_user == 1)
+ continue;
+ break;
+ case IDMAP_POSIXID:
+ break;
+ default:
+ assert(FALSE);
+ }
+
+ if (wksids[i].sidprefix != NULL) {
+ sidcmp = strcasecmp(wksids[i].sidprefix, sid);
+ } else {
+ sidcmp = strcasecmp(my_machine_sid, sid);
+ }
+
+ if (sidcmp != 0)
+ continue;
+ if (wksids[i].rid != rid)
+ continue;
+
+ /*
+ * We have a SID, so ignore entries that are only usable
+ * for mapping UNIX->Windows. (Note: the current table
+ * does not have any such entries.)
+ */
+ if (wksids[i].direction == IDMAP_DIRECTION_U2W)
+ continue;
+
+ return (&wksids[i]);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Find a wksid entry for the specified pid, of the specified type.
+ * Ignore entries that do not specify U2W mappings.
+ */
+const
+wksids_table_t *
+find_wksid_by_pid(uid_t pid, int is_user)
+{
+ int i;
+
+ if (pid == SENTINEL_PID)
+ return (NULL);
+
+ for (i = 0; i < NELEM(wksids); i++) {
+ if (wksids[i].pid == pid &&
+ wksids[i].is_user == is_user &&
+ (wksids[i].direction == IDMAP_DIRECTION_BI ||
+ wksids[i].direction == IDMAP_DIRECTION_U2W)) {
+ return (&wksids[i]);
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * It is probably a bug that both this and find_wksid_by_sid exist,
+ * but for now the distinction is primarily that one takes {machinesid,rid}
+ * and the other takes a full SID.
+ */
+const
+wksids_table_t *
+find_wk_by_sid(char *sid)
+{
+ int i;
+
+ RDLOCK_CONFIG();
+ int len = strlen(_idmapdstate.cfg->pgcfg.machine_sid);
+ char my_machine_sid[len + 1];
+ (void) strcpy(my_machine_sid, _idmapdstate.cfg->pgcfg.machine_sid);
+ UNLOCK_CONFIG();
+
+ for (i = 0; i < NELEM(wksids); i++) {
+ int len;
+ const char *prefix;
+ char *p;
+ unsigned long rid;
+
+ if (wksids[i].sidprefix == NULL)
+ prefix = my_machine_sid;
+ else
+ prefix = wksids[i].sidprefix;
+
+ len = strlen(prefix);
+
+ /*
+ * Check to see whether the SID we're looking for starts
+ * with this prefix, then a -, then a single RID, and it's
+ * the right RID.
+ */
+ if (strncasecmp(sid, prefix, len) != 0)
+ continue;
+ if (sid[len] != '-')
+ continue;
+ rid = strtoul(sid + len + 1, &p, 10);
+ if (*p != '\0')
+ continue;
+
+ if (rid != wksids[i].rid)
+ continue;
+
+ return (&wksids[i]);
+ }
+ return (NULL);
+}
--- a/usr/src/common/smbsrv/smb_xdr_utils.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/common/smbsrv/smb_xdr_utils.c Fri Jul 17 17:54:42 2009 -0700
@@ -30,57 +30,6 @@
#endif /* _KERNEL */
#include <smbsrv/smb_xdr.h>
#include <sys/socket.h>
-#ifdef _KERNEL
-/*
- * xdr_vector():
- *
- * XDR a fixed length array. Unlike variable-length arrays,
- * the storage of fixed length arrays is static and unfreeable.
- * > basep: base of the array
- * > size: size of the array
- * > elemsize: size of each element
- * > xdr_elem: routine to XDR each element
- */
-#define LASTUNSIGNED ((uint_t)0-1)
-bool_t
-xdr_vector(XDR *xdrs, char *basep, uint_t nelem,
- uint_t elemsize, xdrproc_t xdr_elem)
-{
- uint_t i;
- char *elptr;
-
- elptr = basep;
- for (i = 0; i < nelem; i++) {
- if (!(*xdr_elem)(xdrs, elptr, LASTUNSIGNED))
- return (FALSE);
- elptr += elemsize;
- }
- return (TRUE);
-}
-
-/*
- * XDR an unsigned char
- */
-bool_t
-xdr_u_char(XDR *xdrs, uchar_t *cp)
-{
- int i;
-
- switch (xdrs->x_op) {
- case XDR_ENCODE:
- i = (*cp);
- return (XDR_PUTINT32(xdrs, &i));
- case XDR_DECODE:
- if (!XDR_GETINT32(xdrs, &i))
- return (FALSE);
- *cp = (uchar_t)i;
- return (TRUE);
- case XDR_FREE:
- return (TRUE);
- }
- return (FALSE);
-}
-#endif /* _KERNEL */
bool_t
xdr_smb_dr_string_t(xdrs, objp)
@@ -160,45 +109,44 @@
}
/*
- * Encode an opipe context structure into a buffer.
+ * Encode an smb_netuserinfo_t into a buffer.
*/
int
-smb_opipe_context_encode(smb_opipe_context_t *ctx, uint8_t *buf,
- uint32_t buflen, uint_t *pbytes_encoded)
+smb_netuserinfo_encode(smb_netuserinfo_t *info, uint8_t *buf,
+ uint32_t buflen, uint_t *nbytes)
{
XDR xdrs;
int rc = 0;
xdrmem_create(&xdrs, (const caddr_t)buf, buflen, XDR_ENCODE);
- if (!smb_opipe_context_xdr(&xdrs, ctx))
+ if (!smb_netuserinfo_xdr(&xdrs, info))
rc = -1;
- if (pbytes_encoded != NULL)
- *pbytes_encoded = xdr_getpos(&xdrs);
-
+ if (nbytes != NULL)
+ *nbytes = xdr_getpos(&xdrs);
xdr_destroy(&xdrs);
return (rc);
}
/*
- * Decode an XDR buffer into an opipe context structure.
+ * Decode an XDR buffer into an smb_netuserinfo_t.
*/
int
-smb_opipe_context_decode(smb_opipe_context_t *ctx, uint8_t *buf,
- uint32_t buflen, uint_t *pbytes_decoded)
+smb_netuserinfo_decode(smb_netuserinfo_t *info, uint8_t *buf,
+ uint32_t buflen, uint_t *nbytes)
{
XDR xdrs;
int rc = 0;
xdrmem_create(&xdrs, (const caddr_t)buf, buflen, XDR_DECODE);
- bzero(ctx, sizeof (smb_opipe_context_t));
- if (!smb_opipe_context_xdr(&xdrs, ctx))
+ bzero(info, sizeof (smb_netuserinfo_t));
+ if (!smb_netuserinfo_xdr(&xdrs, info))
rc = -1;
- if (pbytes_decoded != NULL)
- *pbytes_decoded = xdr_getpos(&xdrs);
+ if (nbytes != NULL)
+ *nbytes = xdr_getpos(&xdrs);
xdr_destroy(&xdrs);
return (rc);
}
@@ -219,32 +167,175 @@
return (TRUE);
}
+/*
+ * XDR encode/decode for smb_netuserinfo_t.
+ */
bool_t
-smb_opipe_context_xdr(XDR *xdrs, smb_opipe_context_t *objp)
+smb_netuserinfo_xdr(XDR *xdrs, smb_netuserinfo_t *objp)
{
- if (!xdr_uint64_t(xdrs, &objp->oc_session_id))
+ if (!xdr_uint64_t(xdrs, &objp->ui_session_id))
+ return (FALSE);
+ if (!xdr_uint16_t(xdrs, &objp->ui_uid))
+ return (FALSE);
+ if (!xdr_uint16_t(xdrs, &objp->ui_domain_len))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->ui_domain, ~0))
+ return (FALSE);
+ if (!xdr_uint16_t(xdrs, &objp->ui_account_len))
return (FALSE);
- if (!xdr_uint16_t(xdrs, &objp->oc_uid))
+ if (!xdr_string(xdrs, &objp->ui_account, ~0))
+ return (FALSE);
+ if (!xdr_uint16_t(xdrs, &objp->ui_workstation_len))
return (FALSE);
- if (!xdr_uint16_t(xdrs, &objp->oc_domain_len))
+ if (!xdr_string(xdrs, &objp->ui_workstation, ~0))
+ return (FALSE);
+ if (!xdr_smb_inaddr_t(xdrs, &objp->ui_ipaddr))
return (FALSE);
- if (!xdr_string(xdrs, &objp->oc_domain, ~0))
+ if (!xdr_int32_t(xdrs, &objp->ui_native_os))
+ return (FALSE);
+ if (!xdr_int64_t(xdrs, &objp->ui_logon_time))
return (FALSE);
- if (!xdr_uint16_t(xdrs, &objp->oc_account_len))
+ if (!xdr_uint32_t(xdrs, &objp->ui_numopens))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->ui_flags))
return (FALSE);
- if (!xdr_string(xdrs, &objp->oc_account, ~0))
+ return (TRUE);
+}
+
+/*
+ * Encode an smb_netconnectinfo_t into a buffer.
+ */
+int
+smb_netconnectinfo_encode(smb_netconnectinfo_t *info, uint8_t *buf,
+ uint32_t buflen, uint_t *nbytes)
+{
+ XDR xdrs;
+ int rc = 0;
+
+ xdrmem_create(&xdrs, (const caddr_t)buf, buflen, XDR_ENCODE);
+
+ if (!smb_netconnectinfo_xdr(&xdrs, info))
+ rc = -1;
+
+ if (nbytes != NULL)
+ *nbytes = xdr_getpos(&xdrs);
+ xdr_destroy(&xdrs);
+ return (rc);
+}
+
+/*
+ * Decode an XDR buffer into an smb_netconnectinfo_t.
+ */
+int
+smb_netconnectinfo_decode(smb_netconnectinfo_t *info, uint8_t *buf,
+ uint32_t buflen, uint_t *nbytes)
+{
+ XDR xdrs;
+ int rc = 0;
+
+ xdrmem_create(&xdrs, (const caddr_t)buf, buflen, XDR_DECODE);
+
+ bzero(info, sizeof (smb_netconnectinfo_t));
+ if (!smb_netconnectinfo_xdr(&xdrs, info))
+ rc = -1;
+
+ if (nbytes != NULL)
+ *nbytes = xdr_getpos(&xdrs);
+ xdr_destroy(&xdrs);
+ return (rc);
+}
+
+/*
+ * XDR encode/decode for smb_netconnectinfo_t.
+ */
+bool_t
+smb_netconnectinfo_xdr(XDR *xdrs, smb_netconnectinfo_t *objp)
+{
+ if (!xdr_uint32_t(xdrs, &objp->ci_id))
return (FALSE);
- if (!xdr_uint16_t(xdrs, &objp->oc_workstation_len))
+ if (!xdr_uint32_t(xdrs, &objp->ci_type))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->ci_numopens))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->ci_numusers))
return (FALSE);
- if (!xdr_string(xdrs, &objp->oc_workstation, ~0))
+ if (!xdr_uint32_t(xdrs, &objp->ci_time))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->ci_namelen))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->ci_sharelen))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->ci_username, MAXNAMELEN))
return (FALSE);
- if (!xdr_smb_inaddr_t(xdrs, &objp->oc_ipaddr))
- return (FALSE);
- if (!xdr_int32_t(xdrs, &objp->oc_native_os))
+ if (!xdr_string(xdrs, &objp->ci_share, MAXNAMELEN))
return (FALSE);
- if (!xdr_int64_t(xdrs, &objp->oc_logon_time))
+ return (TRUE);
+}
+
+/*
+ * Encode an smb_netfileinfo_t into a buffer.
+ */
+int
+smb_netfileinfo_encode(smb_netfileinfo_t *info, uint8_t *buf,
+ uint32_t buflen, uint_t *nbytes)
+{
+ XDR xdrs;
+ int rc = 0;
+
+ xdrmem_create(&xdrs, (const caddr_t)buf, buflen, XDR_ENCODE);
+
+ if (!smb_netfileinfo_xdr(&xdrs, info))
+ rc = -1;
+
+ if (nbytes != NULL)
+ *nbytes = xdr_getpos(&xdrs);
+ xdr_destroy(&xdrs);
+ return (rc);
+}
+
+/*
+ * Decode an XDR buffer into an smb_netfileinfo_t.
+ */
+int
+smb_netfileinfo_decode(smb_netfileinfo_t *info, uint8_t *buf,
+ uint32_t buflen, uint_t *nbytes)
+{
+ XDR xdrs;
+ int rc = 0;
+
+ xdrmem_create(&xdrs, (const caddr_t)buf, buflen, XDR_DECODE);
+
+ bzero(info, sizeof (smb_netfileinfo_t));
+ if (!smb_netfileinfo_xdr(&xdrs, info))
+ rc = -1;
+
+ if (nbytes != NULL)
+ *nbytes = xdr_getpos(&xdrs);
+ xdr_destroy(&xdrs);
+ return (rc);
+}
+
+/*
+ * XDR encode/decode for smb_netfileinfo_t.
+ */
+bool_t
+smb_netfileinfo_xdr(XDR *xdrs, smb_netfileinfo_t *objp)
+{
+ if (!xdr_uint16_t(xdrs, &objp->fi_fid))
return (FALSE);
- if (!xdr_uint32_t(xdrs, &objp->oc_flags))
+ if (!xdr_uint32_t(xdrs, &objp->fi_uniqid))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->fi_permissions))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->fi_numlocks))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->fi_pathlen))
+ return (FALSE);
+ if (!xdr_uint32_t(xdrs, &objp->fi_namelen))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->fi_path, MAXPATHLEN))
+ return (FALSE);
+ if (!xdr_string(xdrs, &objp->fi_username, MAXNAMELEN))
return (FALSE);
return (TRUE);
}
--- a/usr/src/lib/libadutils/common/addisc.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/libadutils/common/addisc.c Fri Jul 17 17:54:42 2009 -0700
@@ -314,7 +314,6 @@
int num_td1;
int num_td2;
boolean_t match;
- int err;
for (i = 0; td1[i].domain[0] != '\0'; i++)
continue;
@@ -330,9 +329,7 @@
for (i = 0; i < num_td1; i++) {
match = B_FALSE;
for (j = 0; j < num_td2; j++) {
- if (u8_strcmp(td1[i].domain, td2[j].domain, 0,
- U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err) == 0 &&
- err == 0) {
+ if (domain_eq(td1[i].domain, td2[j].domain)) {
match = B_TRUE;
break;
}
@@ -373,7 +370,6 @@
int num_df1;
int num_df2;
boolean_t match;
- int err;
for (i = 0; df1[i].domain[0] != '\0'; i++)
continue;
@@ -389,9 +385,7 @@
for (i = 0; i < num_df1; i++) {
match = B_FALSE;
for (j = 0; j < num_df2; j++) {
- if (u8_strcmp(df1[i].domain, df2[j].domain, 0,
- U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err) == 0 &&
- err == 0 &&
+ if (domain_eq(df1[i].domain, df2[j].domain) &&
strcmp(df1[i].sid, df2[j].sid) == 0) {
match = B_TRUE;
break;
@@ -1077,7 +1071,7 @@
if (ndomains < nresults) {
ad_disc_domainsinforest_t *tmp;
- tmp = realloc(domains, (ndomains+1) * sizeof (*domains));
+ tmp = realloc(domains, (ndomains + 1) * sizeof (*domains));
if (tmp == NULL)
goto err;
domains = tmp;
@@ -1241,8 +1235,8 @@
/* Eat any trailing dot */
len = strlen(dname);
- if (len > 0 && dname[len-1] == '.')
- dname[len-1] = '\0';
+ if (len > 0 && dname[len - 1] == '.')
+ dname[len - 1] = '\0';
update_item(&ctx->domain_name, dname, AD_STATE_AUTO, ttl);
--- a/usr/src/lib/libadutils/common/adutils.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/libadutils/common/adutils.c Fri Jul 17 17:54:42 2009 -0700
@@ -863,12 +863,10 @@
adutils_lookup_check_domain(adutils_query_state_t *qs, const char *domain)
{
adutils_ad_t *ad = qs->qadh->owner;
- int i, err;
+ int i;
for (i = 0; i < ad->num_known_domains; i++) {
- if (u8_strcmp(domain, ad->known_domains[i].name, 0,
- U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err) == 0 &&
- err == 0)
+ if (domain_eq(domain, ad->known_domains[i].name))
return (1);
}
@@ -1116,7 +1114,7 @@
char *attr = NULL, *dn = NULL, *domain = NULL;
adutils_entry_t *ep;
adutils_attr_t *ap;
- int i, j, b, err = 0, ret = -2;
+ int i, j, b, ret = -2;
*entry = NULL;
@@ -1128,8 +1126,7 @@
return (-2);
}
if (q->edomain != NULL) {
- if (u8_strcmp(q->edomain, domain, 0, U8_STRCMP_CI_LOWER,
- U8_UNICODE_LATEST, &err) != 0 || err != 0) {
+ if (!domain_eq(q->edomain, domain)) {
ldap_memfree(dn);
free(domain);
return (-1);
@@ -1560,7 +1557,7 @@
*/
adutils_rc
adutils_lookup_batch_add(adutils_query_state_t *state,
- const char *filter, const char **attrs, const char *edomain,
+ const char *filter, const char * const *attrs, const char *edomain,
adutils_result_t **result, adutils_rc *rc)
{
adutils_rc retcode = ADUTILS_SUCCESS;
@@ -1675,3 +1672,12 @@
return (rc);
return (brc);
}
+
+boolean_t
+domain_eq(const char *a, const char *b)
+{
+ int err;
+
+ return (u8_strcmp(a, b, 0, U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err)
+ == 0 && err == 0);
+}
--- a/usr/src/lib/libadutils/common/libadutils.h Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/libadutils/common/libadutils.h Fri Jul 17 17:54:42 2009 -0700
@@ -164,7 +164,7 @@
void *ldap_res_search_argp,
adutils_query_state_t **state);
extern adutils_rc adutils_lookup_batch_add(adutils_query_state_t *state,
- const char *filter, const char **attrs,
+ const char *filter, const char * const *attrs,
const char *edomain, adutils_result_t **result,
adutils_rc *rc);
extern adutils_rc adutils_lookup_batch_end(
@@ -181,6 +181,8 @@
const char *sid);
extern void adutils_set_logger(adutils_logger logger);
+extern boolean_t domain_eq(const char *a, const char *b);
+
#ifdef __cplusplus
}
#endif
--- a/usr/src/lib/libadutils/common/mapfile-vers Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/libadutils/common/mapfile-vers Fri Jul 17 17:54:42 2009 -0700
@@ -80,6 +80,7 @@
ad_disc_get_SiteName;
ad_disc_get_TrustedDomains;
ad_disc_get_DomainsInForest;
+ domain_eq;
local:
*;
};
--- a/usr/src/lib/libidmap/Makefile Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/libidmap/Makefile Fri Jul 17 17:54:42 2009 -0700
@@ -25,15 +25,18 @@
include $(SRC)/lib/Makefile.lib
-HDRS = idmap.h
+HDRS = idmap.h directory.h
HDRDIR = common
SUBDIRS = $(MACH)
$(BUILD64)SUBDIRS += $(MACH64)
POFILE = libidmap.po
-MSGFILES = `$(GREP) -l gettext common/*.[ch]`
-XGETFLAGS = -a
+MSGFILES:sh = echo common/*.[ch]
+XGETTEXT = $(GNUXGETTEXT)
+XGETFLAGS = --foreign-user --strict -n -E --width=72 \
+ --omit-header --keyword=directoryError:2 \
+ --language=C --force-po
all := TARGET = all
clean := TARGET = clean
@@ -49,7 +52,7 @@
check: $(CHECKHDRS)
-$(POFILE): pofile_MSGFILES
+$(POFILE): $(MSGFILES)
$(BUILDPO.msgfiles)
_msg: $(MSGDOMAINPOFILE)
--- a/usr/src/lib/libidmap/Makefile.com Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/libidmap/Makefile.com Fri Jul 17 17:54:42 2009 -0700
@@ -26,11 +26,24 @@
LIBRARY = libidmap.a
VERS = .1
-OBJECTS = idmap_xdr.o utils.o idmap_api.o namemaps.o idmap_cache.o
-LINT_OBJECTS = utils.o idmap_api.o namemaps.o idmap_cache.o
+LINT_OBJECTS = \
+ directory_client.o \
+ directory_error.o \
+ directory_helper.o \
+ directory_rpc_clnt.o \
+ sidutil.o \
+ sized_array.o \
+ idmap_api.o \
+ idmap_cache.o \
+ miscutils.o \
+ namemaps.o \
+ utils.o
+
+OBJECTS = $(LINT_OBJECTS) \
+ idmap_xdr.o
include ../../Makefile.lib
-
+C99MODE = $(C99_ENABLE)
LIBS = $(DYNLIB) $(LINTLIB)
LDLIBS += -lc -lldap -lsldap -lavl -ladutils -lnsl
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/directory.h Fri Jul 17 17:54:42 2009 -0700
@@ -0,0 +1,167 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DIRECTORY_H
+#define _DIRECTORY_H
+
+/*
+ * A suite of functions for retrieving information about objects
+ * in a directory service.
+ *
+ * Currently it is limited to retrieving SIDs from names, and vice
+ * versa.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+/*
+ * This bitmap is a distillation of the objectClass attribute,
+ * reporting those classes that Solaris finds "interesting".
+ *
+ * All undefined bits are reserved and must be ignored.
+ */
+#define DIRECTORY_CLASS_USER 0x0000000000000001
+#define DIRECTORY_CLASS_GROUP 0x0000000000000002
+
+/*
+ * Opaque pointer to a directory search context.
+ */
+typedef struct directory *directory_t;
+
+/*
+ * Opaque pointer to a structure that describes an error.
+ * Note that NULL means no error.
+ */
+typedef struct directory_error *directory_error_t;
+
+/*
+ * Initialize a directory query session, returning in *d a directory_t
+ * that should be used for query transactions.
+ */
+directory_error_t directory_open(directory_t *d);
+
+/*
+ * Tear down a directory query session.
+ * There is an argument that this should return a directory_error_t, but
+ * then what state would the directory_t be in, and what should you do
+ * if you were doing the directory_close as a result of encountering an error?
+ *
+ * Does nothing if d==NULL.
+ */
+void directory_close(directory_t d);
+
+/*
+ * All directory_t functions return NULL on success or a pointer to a
+ * directory_error_t structure on failure. The caller must call
+ * directory_error_free() on any non-NULL directory_error_t structures returned.
+ *
+ * Strings returned from the directory_error functions are are
+ * invalidated when the directory_error_t itself is freed.
+ */
+
+directory_error_t directory_error(const char *code, const char *fmt, ...);
+
+/*
+ * Determines whether this directory_error_t is an instance of the
+ * particular error, or a subclass of that error.
+ */
+boolean_t directory_error_is_instance_of(directory_error_t de,
+ char *error_string);
+
+/*
+ * Returns a printable version of this directory_error_t, suitable for
+ * human consumption.
+ *
+ * The string returned is valid as long as the directory_error_t itself is
+ * valid, and is freed when the directory_error_t is freed.
+ */
+const char *directory_error_printable(directory_error_t de);
+
+/*
+ * Returns the error code for the particular error, as a string.
+ * Note that this function should not normally be used to answer
+ * the question "did error X happen", since the value returned
+ * could be a subclass of X. directory_error_is_instance_of is intended
+ * to answer that question. This function is more appropriate for
+ * logging, where one would want to log the error code and the list
+ * of parameters so as to allow structured analysis of the error
+ * after the fact.
+ *
+ * The string returned is valid as long as the directory_error_t itself is
+ * valid, and is freed when the directory_error_t is freed.
+ */
+const char *directory_error_code(directory_error_t de);
+
+/*
+ * Returns one of the parameters of the directory_error_t, or NULL if
+ * the parameter does not exist.
+ *
+ * Note that by definition error subclasses have initial parameters
+ * the same as their superclasses.
+ *
+ * The string returned is valid as long as the directory_error_t itself is
+ * valid, and is freed when the directory_error_t is freed.
+ */
+const char *directory_error_param(directory_error_t de, int param);
+
+/*
+ * Frees the memory (if any) allocated for the directory_error_t.
+ * This frees all strings that might have been derived from this
+ * directory_error_t through directory_error_code, directory_error_printable,
+ * et cetera.
+ *
+ * Does nothing if de==NULL.
+ */
+void directory_error_free(directory_error_t de);
+
+/*
+ * Utility functions to look up a SID given a name, and vice versa.
+ * Caller must free() the result (sid or name, respectively).
+ */
+directory_error_t directory_sid_from_name(directory_t d, char *name, char **sid,
+ uint64_t *classes);
+directory_error_t directory_sid_from_user_name(directory_t d, char *name,
+ char **sid);
+directory_error_t directory_sid_from_group_name(directory_t d, char *name,
+ char **sid);
+directory_error_t directory_name_from_sid(directory_t d, char *sid, char **name,
+ uint64_t *classes);
+directory_error_t directory_canon_from_name(directory_t d, char *name,
+ char **canon, uint64_t *classes);
+directory_error_t directory_canon_from_user_name(directory_t d, char *name,
+ char **canon);
+directory_error_t directory_canon_from_group_name(directory_t d, char *name,
+ char **canon);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DIRECTORY_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/directory_client.c Fri Jul 17 17:54:42 2009 -0700
@@ -0,0 +1,366 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Directory lookup functions. These are shims that translate from the API
+ * into the RPC protocol.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <malloc.h>
+#include <sys/types.h>
+#include <netdb.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <string.h>
+#include "directory.h"
+#include "directory_private.h"
+#include <rpcsvc/idmap_prot.h>
+#include "directory_library_impl.h"
+#include "sized_array.h"
+
+static directory_error_t copy_directory_attribute_value(
+ directory_attribute_value_t *dav,
+ directory_values_rpc *dav_rpc);
+static directory_error_t copy_directory_entry(directory_entry_t *ent,
+ directory_entry_rpc *ent_rpc);
+static void directory_results_free(directory_results_rpc *dr);
+static directory_datum_t directory_datum(void *data, size_t len);
+static void directory_datum_free(directory_datum_t d);
+
+/*
+ * This is the actual implementation of the opaque directory_t structure.
+ */
+struct directory {
+ CLIENT *client;
+};
+
+/*
+ * Set up a directory search context.
+ */
+directory_error_t
+directory_open(directory_t *ret)
+{
+ directory_t d;
+ directory_error_t de;
+ char host[] = "localhost";
+
+ *ret = NULL;
+
+ d = calloc(1, sizeof (*d));
+ if (d == NULL)
+ goto nomem;
+
+ d->client = clnt_door_create(IDMAP_PROG, IDMAP_V1, 0);
+ if (d->client == NULL) {
+ de = directory_error("clnt_create.directory_open",
+ "Error: %1",
+ clnt_spcreateerror(host),
+ NULL);
+ goto err;
+ }
+
+ *ret = d;
+ return (NULL);
+
+nomem:
+ de = directory_error("ENOMEM.directory_open",
+ "Insufficient memory setting up directory access", NULL);
+err:
+ directory_close(d);
+ return (de);
+}
+
+/*
+ * Tear down a directory search context.
+ *
+ * Does nothing if d==NULL.
+ */
+void
+directory_close(directory_t d)
+{
+ if (d == NULL)
+ return;
+
+ if (d->client != NULL)
+ clnt_destroy(d->client);
+
+ free(d);
+}
+
+/*
+ * Given a list of identifiers, a list of their types, and a list of attributes,
+ * return the information.
+ */
+directory_error_t
+directory_get_v(
+ directory_t d,
+ directory_entry_list_t *ret,
+ char **ids,
+ int nids,
+ char *types,
+ char **attr_list)
+{
+ int nattrs;
+ directory_entry_list_t del;
+ directory_error_t de;
+ directory_results_rpc dr;
+ idmap_utf8str_list sl_ids;
+ idmap_utf8str_list sl_attrs;
+ directory_entry_rpc *users;
+ int i;
+ enum clnt_stat cs;
+
+ *ret = NULL;
+ del = NULL;
+
+ if (nids == 0) {
+ for (nids = 0; ids[nids] != NULL; nids++)
+ /* LOOP */;
+ }
+
+ for (nattrs = 0; attr_list[nattrs] != NULL; nattrs++)
+ /* LOOP */;
+
+ sl_ids.idmap_utf8str_list_len = nids;
+ sl_ids.idmap_utf8str_list_val = ids;
+ sl_attrs.idmap_utf8str_list_len = nattrs;
+ sl_attrs.idmap_utf8str_list_val = attr_list;
+
+ (void) memset(&dr, 0, sizeof (dr));
+ cs = directory_get_common_1(sl_ids, types, sl_attrs, &dr, d->client);
+ if (cs != RPC_SUCCESS) {
+ char errbuf[100]; /* well long enough for any integer */
+ (void) sprintf(errbuf, "%d", cs);
+ de = directory_error("RPC.Get_common",
+ "Get_common RPC (%1)%2", errbuf,
+ clnt_sperror(d->client, ""), NULL);
+ goto err;
+ }
+
+ if (dr.failed) {
+ de = directory_error_from_rpc(
+ &dr.directory_results_rpc_u.err);
+ goto err;
+ }
+
+ assert(dr.directory_results_rpc_u.entries.entries_len == nids);
+
+ users = dr.directory_results_rpc_u.entries.entries_val;
+
+ del = sized_array(nids, sizeof (directory_entry_t));
+
+ for (i = 0; i < nids; i++) {
+ de = copy_directory_entry(&del[i], &users[i]);
+ if (de != NULL)
+ goto err;
+ }
+
+ directory_results_free(&dr);
+
+ *ret = del;
+ return (NULL);
+
+err:
+ directory_results_free(&dr);
+ directory_free(del);
+ return (de);
+}
+
+/*
+ * Free the results from a directory_get_*() request.
+ */
+void
+directory_free(directory_entry_list_t del)
+{
+ directory_entry_t *ent;
+ directory_attribute_value_t dav;
+ int i;
+ int j;
+ int k;
+
+ if (del == NULL)
+ return;
+
+ /* For each directory entry returned */
+ for (i = 0; i < sized_array_n(del); i++) {
+ ent = &del[i];
+
+ if (ent->attrs != NULL) {
+ /* For each attribute */
+ for (j = 0; j < sized_array_n(ent->attrs); j++) {
+ dav = ent->attrs[j];
+ if (dav != NULL) {
+ for (k = 0; k < sized_array_n(dav); k++)
+ directory_datum_free(dav[k]);
+
+ sized_array_free(dav);
+ }
+ }
+ sized_array_free(ent->attrs);
+ }
+
+ directory_error_free(ent->err);
+ }
+
+ sized_array_free(del);
+}
+
+/*
+ * Create a directory datum. Note that we allocate an extra byte and
+ * zero it, so that strings get null-terminated. Return NULL on error.
+ */
+static
+directory_datum_t
+directory_datum(void *data, size_t len)
+{
+ void *p;
+
+ p = sized_array(len + 1, 1);
+ if (p == NULL)
+ return (NULL);
+ (void) memcpy(p, data, len);
+ *((char *)p + len) = '\0';
+ return (p);
+}
+
+/*
+ * Return the size of a directory_datum_t. Note that this does not include
+ * the terminating \0, so it represents the value as returned by LDAP.
+ */
+size_t
+directory_datum_len(directory_datum_t d)
+{
+ /*
+ * Deduct the terminal \0, so that binary data gets the
+ * expected length.
+ */
+ return (sized_array_n(d) - 1);
+}
+
+static
+void
+directory_datum_free(directory_datum_t d)
+{
+ sized_array_free(d);
+}
+
+/*
+ * Unmarshall an RPC directory entry into an API directory entry.
+ */
+static
+directory_error_t
+copy_directory_entry(
+ directory_entry_t *ent,
+ directory_entry_rpc *ent_rpc)
+{
+ int nattrs;
+ int i;
+ directory_error_t de;
+
+ /* If the entry wasn't found, leave the entry attrs and err NULL. */
+ if (ent_rpc->status == DIRECTORY_NOT_FOUND)
+ return (NULL);
+
+ if (ent_rpc->status == DIRECTORY_ERROR) {
+ ent->err = directory_error_from_rpc(
+ &ent_rpc->directory_entry_rpc_u.err);
+ return (NULL);
+ }
+
+ nattrs = ent_rpc->directory_entry_rpc_u.attrs.attrs_len;
+
+ ent->attrs = sized_array(nattrs, sizeof (directory_attribute_value_t));
+ if (ent->attrs == NULL) {
+ return (directory_error("ENOMEM.copy_directory_entry",
+ "Insufficient memory copying directory entry", NULL));
+ }
+ for (i = 0; i < nattrs; i++) {
+ de = copy_directory_attribute_value(&ent->attrs[i],
+ &ent_rpc->directory_entry_rpc_u.attrs.attrs_val[i]);
+ if (de != NULL)
+ return (de);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Unmarshall an RPC directory attribute value into the API equivalent.
+ *
+ * Note that on error some entries may have been copied, and so
+ * the caller needs to clean up dav. This is normally not a problem
+ * since the caller will have called this function several times and
+ * will need to clean up the results from the other calls too.
+ */
+static
+directory_error_t
+copy_directory_attribute_value(
+ directory_attribute_value_t *dav,
+ directory_values_rpc *dav_rpc)
+{
+ int i;
+ int nvals;
+ directory_value_rpc *vals;
+
+ /* If it wasn't found, leave the corresponding entry NULL */
+ if (!dav_rpc->found)
+ return (NULL);
+
+ nvals = dav_rpc->directory_values_rpc_u.values.values_len;
+ *dav = sized_array(nvals + 1, sizeof (directory_datum_t));
+ if (*dav == NULL) {
+ return (directory_error("ENOMEM.copy_directory_attribute_value",
+ "Insufficient memory copying directory entry", NULL));
+ }
+
+ vals = dav_rpc->directory_values_rpc_u.values.values_val;
+ for (i = 0; i < nvals; i++) {
+ (*dav)[i] = directory_datum(vals[i].directory_value_rpc_val,
+ vals[i].directory_value_rpc_len);
+ if ((*dav)[i] == NULL) {
+ return (directory_error(
+ "ENOMEM.copy_directory_attribute_value",
+ "Insufficient memory copying directory entry",
+ NULL));
+ }
+ }
+
+ return (NULL);
+}
+
+/*
+ * Free the results of a directory RPC request.
+ */
+static
+void
+directory_results_free(directory_results_rpc *dr)
+{
+ xdr_free(xdr_directory_results_rpc, (char *)&dr);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/directory_error.c Fri Jul 17 17:54:42 2009 -0700
@@ -0,0 +1,498 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Error handling support for directory lookup.
+ * Actually, this is intended to be a very generic and extensible error
+ * reporting mechanism.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <thread.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <malloc.h>
+#include <string.h>
+#include <ctype.h>
+#include <syslog.h>
+#include <idmap_impl.h>
+#include <rpcsvc/idmap_prot.h>
+#include <libintl.h>
+#include "directory.h"
+
+/*
+ * This is the actual implementation of the opaque directory_error_t structure.
+ */
+struct directory_error {
+ /*
+ * True if this directory_error_t is statically allocated. Used to
+ * handle out of memory errors during error reporting.
+ */
+ boolean_t is_static;
+
+ /*
+ * The error code. This is a locale-independent string that
+ * represents the precise error (to some level of granularity)
+ * that occurred. Internationalization processing could map it
+ * to an message. Errors may be subclassed by appending a dot
+ * and a name for the subclass.
+ *
+ * Note that this code plus the parameters allows for structured
+ * processing of error results.
+ */
+ char *code;
+
+ /*
+ * The default (in the absence of internationalization) format for
+ * the error message. %n interposes params[n - 1].
+ */
+ char *fmt;
+
+ /*
+ * Parameters to the error message. Note that subclasses are
+ * required to have the same initial parameters as their superclasses,
+ * so that code that processes the superclass can work on the subclass.
+ */
+ int nparams;
+ char **params;
+
+ /*
+ * Cached printable form (that is, with params[] interpolated into
+ * fmt) of the error message. Created when requested.
+ */
+ char *printable;
+};
+
+static directory_error_t directory_error_internal_error(int err);
+
+/*
+ * For debugging, reference count of directory_error instances still in
+ * existence. When the system is idle, this should be zero.
+ * Note that no attempt is made to make this MT safe, so it is not reliable
+ * in an MT environment.
+ */
+static int directory_errors_outstanding = 0;
+
+/*
+ * Free the specified directory_error_t. Note that this invalidates all strings
+ * returned based on it.
+ *
+ * Does nothing when de==NULL.
+ */
+void
+directory_error_free(directory_error_t de)
+{
+ int i;
+
+ if (de == NULL)
+ return;
+
+ /* Don't free our internal static directory_error_ts! */
+ if (de->is_static)
+ return;
+
+ free(de->code);
+ de->code = NULL;
+ free(de->fmt);
+ de->fmt = NULL;
+
+ /* Free parameters, if any */
+ if (de->params != NULL) {
+ for (i = 0; i < de->nparams; i++) {
+ free(de->params[i]);
+ de->params[i] = NULL;
+ }
+ free(de->params);
+ de->params = NULL;
+ }
+
+ /* Free cached printable */
+ free(de->printable);
+ de->printable = NULL;
+
+ free(de);
+
+ directory_errors_outstanding--;
+}
+
+/*
+ * de = directory_error(code, fmt [, arg1 ... ]);
+ * Code, fmt, and arguments must be strings and will be copied.
+ */
+directory_error_t
+directory_error(const char *code, const char *fmt, ...)
+{
+ directory_error_t de = NULL;
+ va_list va;
+ int i;
+
+ de = calloc(1, sizeof (*de));
+ if (de == NULL)
+ goto nomem;
+
+ directory_errors_outstanding++;
+
+ de->is_static = B_FALSE;
+
+ de->code = strdup(code);
+ if (de->code == NULL)
+ goto nomem;
+
+ de->fmt = strdup(fmt);
+ if (de->fmt == NULL)
+ goto nomem;
+
+ /* Count our parameters */
+ va_start(va, fmt);
+ for (i = 0; va_arg(va, char *) != NULL; i++)
+ /* LOOP */;
+ va_end(va);
+
+ de->nparams = i;
+
+ /*
+ * Note that we do not copy the terminating NULL because we have
+ * a count.
+ */
+ de->params = calloc(de->nparams, sizeof (char *));
+ if (de->params == NULL)
+ goto nomem;
+
+ va_start(va, fmt);
+ for (i = 0; i < de->nparams; i++) {
+ de->params[i] = strdup((char *)va_arg(va, char *));
+ if (de->params[i] == NULL) {
+ va_end(va);
+ goto nomem;
+ }
+ }
+ va_end(va);
+
+ return (de);
+
+nomem:;
+ int err = errno;
+ directory_error_free(de);
+ return (directory_error_internal_error(err));
+}
+
+/*
+ * Transform a directory_error returned by RPC into a directory_error_t.
+ */
+directory_error_t
+directory_error_from_rpc(directory_error_rpc *de_rpc)
+{
+ directory_error_t de;
+ int i;
+
+ de = calloc(1, sizeof (*de));
+ if (de == NULL)
+ goto nomem;
+
+ directory_errors_outstanding++;
+
+ de->is_static = B_FALSE;
+ de->code = strdup(de_rpc->code);
+ if (de->code == NULL)
+ goto nomem;
+ de->fmt = strdup(de_rpc->fmt);
+ if (de->fmt == NULL)
+ goto nomem;
+
+ de->nparams = de_rpc->params.params_len;
+
+ de->params = calloc(de->nparams, sizeof (char *));
+ if (de->params == NULL)
+ goto nomem;
+
+ for (i = 0; i < de->nparams; i++) {
+ de->params[i] = strdup(de_rpc->params.params_val[i]);
+ if (de->params[i] == NULL)
+ goto nomem;
+ }
+
+ return (de);
+
+nomem:;
+ int err = errno;
+ directory_error_free(de);
+ return (directory_error_internal_error(err));
+}
+
+/*
+ * Convert a directory_error_t into a directory_error to send over RPC.
+ *
+ * Returns TRUE on successful conversion, FALSE on failure.
+ *
+ * Frees the directory_error_t.
+ *
+ * Note that most functions in this suite return boolean_t, as defined
+ * by types.h. This function is intended to be used directly as the
+ * return value from an RPC service function, and so it returns bool_t.
+ */
+bool_t
+directory_error_to_rpc(directory_error_rpc *de_rpc, directory_error_t de)
+{
+ int i;
+ idmap_utf8str *params;
+
+ de_rpc->code = strdup(de->code);
+ if (de_rpc->code == NULL)
+ goto nomem;
+
+ de_rpc->fmt = strdup(de->fmt);
+ if (de_rpc->fmt == NULL)
+ goto nomem;
+
+ params = calloc(de->nparams, sizeof (idmap_utf8str));
+ if (params == NULL)
+ goto nomem;
+ de_rpc->params.params_val = params;
+ de_rpc->params.params_len = de->nparams;
+
+ for (i = 0; i < de->nparams; i++) {
+ params[i] = strdup(de->params[i]);
+ if (params[i] == NULL)
+ goto nomem;
+ }
+
+ directory_error_free(de);
+ return (TRUE);
+
+nomem:
+ logger(LOG_ERR, "Warning: failed to convert error for RPC\n"
+ "Original error: %s\n"
+ "Conversion error: %s\n",
+ strerror(errno),
+ directory_error_printable(de));
+ directory_error_free(de);
+ return (FALSE);
+}
+
+/*
+ * Determines whether this directory_error_t is an instance of the
+ * particular error, or a subclass of that error.
+ */
+boolean_t
+directory_error_is_instance_of(directory_error_t de, char *code)
+{
+ int len;
+
+ if (de == NULL || de->code == NULL)
+ return (B_FALSE);
+
+ len = strlen(code);
+
+ if (strncasecmp(de->code, code, len) != 0)
+ return (B_FALSE);
+
+ if (de->code[len] == '\0' || de->code[len] == '.')
+ return (B_TRUE);
+
+ return (B_FALSE);
+}
+
+/*
+ * Expand the directory_error_t in de into buf, returning the size of the
+ * resulting string including terminating \0. If buf is NULL, just
+ * return the size.
+ *
+ * Return -1 if there are no substitutions, so that the caller can
+ * avoid memory allocation.
+ */
+static
+int
+directory_error_expand(char *buf, directory_error_t de)
+{
+ int bufsiz;
+ boolean_t has_subst;
+ const char *p;
+ char c;
+ long n;
+ const char *s;
+ char *newp;
+
+ bufsiz = 0;
+ has_subst = B_FALSE;
+
+ for (p = dgettext(TEXT_DOMAIN, de->fmt); *p != '\0'; ) {
+ c = *p++;
+ if (c == '%') {
+ has_subst = B_TRUE;
+ if (isdigit(*p)) {
+ n = strtol(p, &newp, 10);
+ p = newp;
+ if (de->params == NULL ||
+ n < 1 ||
+ n > de->nparams)
+ s = dgettext(TEXT_DOMAIN, "(missing)");
+ else
+ s = de->params[n - 1];
+ if (buf != NULL)
+ (void) strcpy(buf + bufsiz, s);
+ bufsiz += strlen(s);
+ continue;
+ }
+ }
+ if (buf != NULL)
+ buf[bufsiz] = c;
+ bufsiz++;
+ }
+
+ if (buf != NULL)
+ buf[bufsiz] = '\0';
+ bufsiz++;
+
+ return (has_subst ? bufsiz : -1);
+}
+
+/*
+ * Returns a printable version of this directory_error_t, suitable for
+ * human consumption.
+ *
+ * The value returned is valid as long as the directory_error_t is valid,
+ * and is freed when the directory_error_t is freed.
+ */
+const char *
+directory_error_printable(directory_error_t de)
+{
+ char *s;
+ int bufsiz;
+
+ if (de->printable != NULL)
+ return (de->printable);
+
+ bufsiz = directory_error_expand(NULL, de);
+
+ /*
+ * Short circuit case to avoid memory allocation when there is
+ * no parameter substitution.
+ */
+ if (bufsiz < 0)
+ return (dgettext(TEXT_DOMAIN, de->fmt));
+
+ s = malloc(bufsiz);
+ if (s == NULL) {
+ return (dgettext(TEXT_DOMAIN,
+ "Out of memory while expanding directory_error_t"));
+ }
+
+ (void) directory_error_expand(s, de);
+
+ /*
+ * Stash the expansion away for later free, and to short-circuit
+ * repeated expansions.
+ */
+ de->printable = s;
+
+ return (de->printable);
+}
+
+/*
+ * Returns the error code for the particular error, as a string.
+ * Note that this function should not normally be used to answer
+ * the question "did error X happen", since the value returned
+ * could be a subclass of X. directory_error_is_instance_of is intended
+ * to answer that question.
+ *
+ * The value returned is valid as long as the directory_error_t is valid,
+ * and is freed when the directory_error_t is freed.
+ */
+const char *
+directory_error_code(directory_error_t de)
+{
+ return (de->code);
+}
+
+/*
+ * Returns one of the parameters of the directory_error_t, or NULL if
+ * the parameter does not exist.
+ *
+ * Note that it is required that error subclasses have initial parameters
+ * the same as their superclasses.
+ *
+ * The value returned is valid as long as the directory_error_t is valid,
+ * and is freed when the directory_error_t is freed.
+ */
+const char *
+directory_error_param(directory_error_t de, int param)
+{
+ if (param >= de->nparams)
+ return (NULL);
+ return (de->params[param]);
+}
+
+/*
+ * Here are some (almost) constant directory_error_t structures
+ * for use in reporting errors encountered while creating a
+ * directory_error_t structure. Unfortunately, the original error
+ * report is lost.
+ */
+#define gettext(x) x /* let xgettext see these messages */
+static struct directory_error directory_error_ENOMEM = {
+ B_TRUE,
+ "ENOMEM.directory_error_t",
+ gettext("Out of memory while creating a directory_error_t"),
+ 0, NULL,
+ NULL,
+};
+
+static struct directory_error directory_error_EAGAIN = {
+ B_TRUE,
+ "EAGAIN.directory_error_t",
+ gettext("Out of resources while creating a directory_error_t"),
+ 0, NULL,
+ NULL,
+};
+
+/* 40 is big enough for even 128 bits */
+static char directory_error_unknown_errno[40] = "0";
+static char *directory_error_unknown_params[] = {
+ directory_error_unknown_errno
+};
+static struct directory_error directory_error_unknown = {
+ B_TRUE,
+ "Unknown.directory_error_t",
+ gettext("Unknown error (%1) while creating a directory_error_t"),
+ 1, directory_error_unknown_params,
+ NULL,
+};
+#undef gettext
+
+static
+directory_error_t
+directory_error_internal_error(int err)
+{
+ switch (err) {
+ case ENOMEM: return (&directory_error_ENOMEM);
+ case EAGAIN: return (&directory_error_EAGAIN);
+ default:
+ /* Pray that we don't have a reentrancy problem ... */
+ (void) sprintf(directory_error_unknown_errno, "%u", err);
+ return (&directory_error_unknown);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/directory_helper.c Fri Jul 17 17:54:42 2009 -0700
@@ -0,0 +1,302 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Some helper routines for directory lookup. These offer functions that
+ * you could implement yourself on top of the generic routines, but since
+ * they're a common request we implement them here. (Well, OK, we cheat a bit
+ * and call an internal routine to do the dirty work to reduce code
+ * duplication, but you could still implement them using the generic routines.)
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <libadutils.h>
+#include <rpcsvc/idmap_prot.h>
+#include "directory.h"
+#include "directory_private.h"
+#include "directory_library_impl.h"
+#include "miscutils.h"
+#include "sidutil.h"
+
+/*
+ * Given a username, return a text-form SID.
+ *
+ * The SID must be free()ed by the caller.
+ *
+ * d, if non-NULL, specifies an existing directory-search context.
+ * If NULL, a temporary one will be created.
+ */
+directory_error_t
+directory_sid_from_name_common(
+ directory_t d,
+ char *name,
+ char *type,
+ char **sid,
+ uint64_t *classes)
+{
+ directory_t d1 = NULL;
+ static char *attrs[] = {
+ "objectSid",
+ "objectClass",
+ NULL,
+ };
+ directory_entry_t *ret_list = NULL;
+ directory_error_t de;
+ struct ret_sid {
+ sid_t **objectSid;
+ char **objectClass;
+ } *ret_sid;
+
+ /* Prep for error cases. */
+ *sid = NULL;
+ if (classes != NULL)
+ *classes = 0;
+
+ if (d == NULL) {
+ de = directory_open(&d1);
+ if (de != NULL)
+ goto out;
+ } else {
+ d1 = d;
+ }
+
+ de = directory_get_v(d1, &ret_list, &name, 1, type, attrs);
+ if (de != NULL)
+ goto out;
+ if (ret_list[0].err != NULL) {
+ de = ret_list[0].err;
+ ret_list[0].err = NULL;
+ goto out;
+ }
+
+ ret_sid = (struct ret_sid *)ret_list[0].attrs;
+ if (ret_sid == NULL)
+ goto out;
+
+ if (ret_sid->objectSid != NULL &&
+ ret_sid->objectSid[0] != NULL) {
+ char text_sid[SID_STRSZ+1];
+ sid_from_le(ret_sid->objectSid[0]);
+ sid_tostr(ret_sid->objectSid[0], text_sid);
+ *sid = strdup(text_sid);
+ if (*sid == NULL)
+ goto nomem;
+ }
+
+ if (ret_sid->objectClass != NULL &&
+ classes != NULL)
+ *classes = class_bitmap(ret_sid->objectClass);
+
+ goto out;
+
+nomem:
+ de = directory_error("ENOMEM.directory_sid_from_name_common",
+ "Insufficient memory retrieving data about SID", NULL);
+
+out:
+ directory_free(ret_list);
+ if (d == NULL)
+ directory_close(d1);
+ return (de);
+}
+
+directory_error_t
+directory_sid_from_name(
+ directory_t d,
+ char *name,
+ char **sid,
+ uint64_t *classes)
+{
+ return (directory_sid_from_name_common(d, name, DIRECTORY_ID_NAME, sid,
+ classes));
+}
+
+directory_error_t
+directory_sid_from_user_name(directory_t d, char *name, char **sid)
+{
+ return (directory_sid_from_name_common(d, name, DIRECTORY_ID_USER, sid,
+ NULL));
+}
+
+directory_error_t
+directory_sid_from_group_name(directory_t d, char *name, char **sid)
+{
+ return (directory_sid_from_name_common(d, name, DIRECTORY_ID_GROUP, sid,
+ NULL));
+}
+
+/*
+ * Given a name or text-format SID, return a user@domain.
+ *
+ * The user@domain returned must be free()ed by the caller.
+ *
+ * Returns NULL and sets *name to NULL if no error occurred but the specified
+ * entity does not exist.
+ *
+ * d, if non-NULL, specifies an existing directory-search context.
+ * If NULL, a temporary one will be created.
+ */
+static
+directory_error_t
+directory_canon_common(
+ directory_t d,
+ char *id,
+ char *id_type,
+ char **canon,
+ uint64_t *classes)
+{
+ directory_t d1 = NULL;
+ directory_entry_t *ret_list = NULL;
+ directory_error_t de;
+ /*
+ * Attributes required to generate a canonical name, in named-list and
+ * structure form.
+ */
+ static char *attrs[] = {
+ "x-sun-canonicalName",
+ "objectClass",
+ NULL,
+ };
+
+ struct canon_name_ret {
+ char **x_sun_canonicalName;
+ char **objectClass;
+ } *ret_name;
+
+ /* Prep for error cases. */
+ *canon = NULL;
+ if (classes != NULL)
+ *classes = 0;
+
+ if (d == NULL) {
+ de = directory_open(&d1);
+ if (de != NULL)
+ goto out;
+ } else {
+ d1 = d;
+ }
+
+ de = directory_get_v(d1, &ret_list, &id, 1, id_type, attrs);
+ if (de != NULL)
+ goto out;
+ if (ret_list[0].err != NULL) {
+ de = ret_list[0].err;
+ ret_list[0].err = NULL;
+ goto out;
+ }
+
+ ret_name = (struct canon_name_ret *)ret_list[0].attrs;
+ if (ret_name == NULL)
+ goto out;
+
+ if (ret_name->x_sun_canonicalName != NULL &&
+ ret_name->x_sun_canonicalName[0] != NULL) {
+ *canon = strdup(ret_name->x_sun_canonicalName[0]);
+ if (*canon == NULL)
+ goto nomem;
+ }
+
+ if (ret_name->objectClass != NULL &&
+ classes != NULL)
+ *classes = class_bitmap(ret_name->objectClass);
+
+ goto out;
+
+nomem:
+ de = directory_error("ENOMEM.directory_canon_common",
+ "Insufficient memory retrieving data about name", NULL);
+
+out:
+ directory_free(ret_list);
+ if (d == NULL)
+ directory_close(d1);
+ return (de);
+}
+
+directory_error_t
+directory_name_from_sid(
+ directory_t d,
+ char *sid,
+ char **canon,
+ uint64_t *classes)
+{
+ return (directory_canon_common(d, sid, DIRECTORY_ID_SID, canon,
+ classes));
+}
+
+directory_error_t
+directory_canon_from_name(
+ directory_t d,
+ char *name,
+ char **canon,
+ uint64_t *classes)
+{
+ return (directory_canon_common(d, name, DIRECTORY_ID_NAME, canon,
+ classes));
+}
+
+directory_error_t
+directory_canon_from_user_name(directory_t d, char *name, char **canon)
+{
+ return (
+ directory_canon_common(d, name, DIRECTORY_ID_USER, canon, NULL));
+}
+
+directory_error_t
+directory_canon_from_group_name(directory_t d, char *name, char **canon)
+{
+ return (
+ directory_canon_common(d, name, DIRECTORY_ID_GROUP, canon, NULL));
+}
+
+boolean_t
+is_in_list(char **list, char *val)
+{
+ for (; *list != NULL; list++) {
+ if (strcaseeq(*list, val))
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
+uint64_t
+class_bitmap(char **objectClass)
+{
+ uint64_t ret = 0;
+
+ for (; *objectClass != NULL; objectClass++) {
+ if (strcaseeq(*objectClass, "user") ||
+ strcaseeq(*objectClass, "posixAccount"))
+ ret |= DIRECTORY_CLASS_USER;
+
+ if (strcaseeq(*objectClass, "group") ||
+ strcaseeq(*objectClass, "posixGroup"))
+ ret |= DIRECTORY_CLASS_GROUP;
+ }
+
+ return (ret);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/directory_library_impl.h Fri Jul 17 17:54:42 2009 -0700
@@ -0,0 +1,50 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DIRECTORY_LIBRARY_IMPL_H
+#define _DIRECTORY_LIBRARY_IMPL_H
+
+/*
+ * Internal implementation of the client side of directory lookup.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+directory_error_t directory_error_from_rpc(directory_error_rpc *de_rpc);
+bool_t directory_error_to_rpc(directory_error_rpc *de_rpc,
+ directory_error_t de);
+
+
+directory_error_t directory_get_v(directory_t d, directory_entry_list_t *ret,
+ char **ids, int nids, char *types, char **attr_list);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DIRECTORY_LIBRARY_IMPL_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/directory_private.h Fri Jul 17 17:54:42 2009 -0700
@@ -0,0 +1,101 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _DIRECTORY_PRIVATE_H
+#define _DIRECTORY_PRIVATE_H
+
+/*
+ * A suite of functions for retrieving information about objects
+ * in a directory service.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+#define DIRECTORY_ID_NAME "n"
+#define DIRECTORY_ID_USER "u"
+#define DIRECTORY_ID_GROUP "g"
+#define DIRECTORY_ID_SID "s"
+
+/*
+ * Structure of the returned data.
+ * Note that this is constructed from the bottom up; what is returned is
+ * a directory_entry_list_t.
+ */
+typedef void *directory_datum_t;
+typedef directory_datum_t *directory_attribute_value_t;
+typedef struct {
+ directory_attribute_value_t *attrs;
+ directory_error_t err;
+} directory_entry_t;
+typedef directory_entry_t *directory_entry_list_t;
+
+/*
+ * Retrieve information about a user or group. By way of analogy to exec(2),
+ * the _v variants accept a list of attributes as an array, while
+ * the _l variants accept the attribute list as arguments.
+ * All variations accept a list of identifiers, and return a
+ * directory_entry_list_t in the same order. The length of the list of user
+ * identifiers can be specified either explicitly, or by a terminating
+ * NULL if the associated count is zero. Attributes are returned in the
+ * order they were requested, with missing attributes yielding NULL
+ * entries.
+ */
+directory_error_t directory_get_v(directory_t d, directory_entry_list_t *ret,
+ char **ids, int nids, char *types, char **attrlist);
+
+directory_error_t directory_get_l(directory_t d, directory_entry_list_t *ret,
+ char **ids, int nids, char *types, char *attr1, ...);
+
+/*
+ * Free the data structure returned by directory_get_by*().
+ *
+ * Does nothing if list==NULL.
+ */
+void directory_free(directory_entry_list_t list);
+
+/* Return the number of bytes in a directory_datum_t */
+size_t directory_datum_len(directory_datum_t d);
+
+/*
+ * Search a list, case-insensitively, for a string
+ */
+boolean_t is_in_list(char **list, char *value);
+
+/*
+ * Examine an objectClass list and distill it into a bitmap of "interesting"
+ * classes.
+ */
+uint64_t class_bitmap(char **objectClass);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DIRECTORY_PRIVATE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/directory_rpc_clnt.c Fri Jul 17 17:54:42 2009 -0700
@@ -0,0 +1,57 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * RPC shims for directory lookup. Originally generated using rpcgen.
+ */
+
+#include <memory.h> /* for memset */
+#include <rpcsvc/idmap_prot.h>
+#ifndef _KERNEL
+#include <stdio.h>
+#include <stdlib.h> /* getenv, exit */
+#endif /* !_KERNEL */
+
+/* Default timeout can be changed using clnt_control() */
+static struct timeval TIMEOUT = { 25, 0 };
+
+enum clnt_stat
+directory_get_common_1(
+ idmap_utf8str_list ids,
+ idmap_utf8str types,
+ idmap_utf8str_list attrs,
+ directory_results_rpc *clnt_res,
+ CLIENT *clnt)
+{
+ directory_get_common_1_argument arg;
+ arg.ids = ids;
+ arg.attrs = attrs;
+ arg.types = types;
+ return (clnt_call(clnt, DIRECTORY_GET_COMMON,
+ (xdrproc_t)xdr_directory_get_common_1_argument, (caddr_t)&arg,
+ (xdrproc_t)xdr_directory_results_rpc, (caddr_t)clnt_res,
+ TIMEOUT));
+}
--- a/usr/src/lib/libidmap/common/idmap_api.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/libidmap/common/idmap_api.c Fri Jul 17 17:54:42 2009 -0700
@@ -2072,9 +2072,9 @@
for (i = 0; stattable[i].msg; i++) {
if (stattable[i].retcode == status)
- return (gettext(stattable[i].msg));
+ return (dgettext(TEXT_DOMAIN, stattable[i].msg));
}
- return (gettext("Unknown error"));
+ return (dgettext(TEXT_DOMAIN, "Unknown error"));
}
--- a/usr/src/lib/libidmap/common/idmap_impl.h Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/libidmap/common/idmap_impl.h Fri Jul 17 17:54:42 2009 -0700
@@ -134,6 +134,7 @@
extern idmap_stat idmap_get_prop_str(idmap_handle_t *, idmap_prop_type,
char **);
+extern idmap_logger logger;
#ifdef __cplusplus
}
--- a/usr/src/lib/libidmap/common/llib-lidmap Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/libidmap/common/llib-lidmap Fri Jul 17 17:54:42 2009 -0700
@@ -19,13 +19,17 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/* LINTLIBRARY */
/* PROTOLIB1 */
#include "idmap_impl.h"
+#include "miscutils.h"
+#include "directory.h"
+#include "directory_private.h"
+#include "sized_array.h"
+#include "directory_library_impl.h"
+#include "sidutil.h"
--- a/usr/src/lib/libidmap/common/mapfile-vers Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/libidmap/common/mapfile-vers Fri Jul 17 17:54:42 2009 -0700
@@ -40,70 +40,105 @@
SUNWprivate {
global:
- xdr_idmap_retcode;
+ directory_canon_from_group_name;
+ directory_canon_from_name;
+ directory_canon_from_user_name;
+ directory_close;
+ directory_error;
+ directory_error_code;
+ directory_error_free;
+ directory_error_from_rpc;
+ directory_error_is_instance_of;
+ directory_error_param;
+ directory_error_printable;
+ directory_error_to_rpc;
+ directory_free;
+ directory_get_v;
+ directory_name_from_sid;
+ directory_open;
+ directory_sid_from_group_name;
+ directory_sid_from_name;
+ directory_sid_from_user_name;
+ idmap_cache_get_data;
+ idmap_fini;
+ idmap_fini_namemaps;
+ idmap_free;
+ idmap_getext_gidbysid;
+ idmap_getext_pidbysid;
+ idmap_getext_sidbygid;
+ idmap_getext_sidbyuid;
+ idmap_getext_uidbysid;
+ idmap_getgidbywinname;
+ idmap_getuidbywinname;
+ idmap_getwinnamebygid;
+ idmap_getwinnamebyuid;
+ idmap_get_create;
+ idmap_get_destroy;
+ idmap_get_gidbysid;
+ idmap_get_mappings;
+ idmap_get_namemap;
+ idmap_get_pidbysid;
+ idmap_get_sidbygid;
+ idmap_get_sidbyuid;
+ idmap_get_u2w_mapping;
+ idmap_get_uidbysid;
+ idmap_get_w2u_mapping;
+ idmap_info_cpy;
+ idmap_info_free;
+ idmap_info_mov;
+ idmap_init;
+ idmap_init_namemaps;
+ idmap_iter_destroy;
+ idmap_iter_mappings;
+ idmap_iter_namerules;
+ idmap_iter_next_mapping;
+ idmap_iter_next_namerule;
+ idmap_namerule_cpy;
+ idmap_set_logger;
+ idmap_set_namemap;
+ idmap_stat2string;
+ idmap_stat4prot;
+ idmap_string2stat;
+ idmap_udt_add_namerule;
+ idmap_udt_commit;
+ idmap_udt_create;
+ idmap_udt_destroy;
+ idmap_udt_flush_namerules;
+ idmap_udt_get_conflict_rule;
+ idmap_udt_get_error_index;
+ idmap_udt_get_error_rule;
+ idmap_udt_rm_namerule;
+ idmap_unset_namemap;
+ memdup;
+ sid_free;
+ sid_from_le;
+ sid_fromstr;
+ sid_len;
+ sid_to_le;
+ sid_tostr;
+ sized_array;
+ sized_array_free;
+ sized_array_n;
+ strcaseeq;
+ streq;
+ strndup;
+ xdr_directory_entry_rpc;
+ xdr_directory_get_common_1_argument;
+ xdr_directory_results_rpc;
+ xdr_idmap_ids_res;
+ xdr_idmap_id_res;
+ xdr_idmap_list_mappings_1_argument;
+ xdr_idmap_list_namerules_1_argument;
+ xdr_idmap_mapping;
+ xdr_idmap_mappings_res;
+ xdr_idmap_mapping_batch;
xdr_idmap_namerule;
xdr_idmap_namerules_res;
- xdr_idmap_ids_res;
- xdr_idmap_mapping_batch;
- xdr_idmap_list_mappings_1_argument;
- xdr_idmap_mappings_res;
- xdr_idmap_update_batch;
- xdr_idmap_list_namerules_1_argument;
- xdr_idmap_mapping;
- xdr_idmap_id_res;
- xdr_idmap_update_res;
xdr_idmap_prop_res;
xdr_idmap_prop_type;
- idmap_init;
- idmap_fini;
- idmap_free;
- idmap_stat2string;
- idmap_string2stat;
- idmap_stat4prot;
- idmap_iter_namerules;
- idmap_iter_next_namerule;
- idmap_iter_mappings;
- idmap_iter_next_mapping;
- idmap_iter_destroy;
- idmap_get_create;
- idmap_get_uidbysid;
- idmap_get_gidbysid;
- idmap_get_pidbysid;
- idmap_get_sidbyuid;
- idmap_get_sidbygid;
- idmap_get_mappings;
- idmap_get_destroy;
- idmap_get_w2u_mapping;
- idmap_get_u2w_mapping;
- idmap_udt_add_namerule;
- idmap_udt_rm_namerule;
- idmap_udt_destroy;
- idmap_udt_commit;
- idmap_udt_create;
- idmap_udt_get_error_index;
- idmap_udt_get_error_rule;
- idmap_udt_get_conflict_rule;
- idmap_udt_flush_namerules;
- idmap_getwinnamebyuid;
- idmap_getwinnamebygid;
- idmap_getuidbywinname;
- idmap_getgidbywinname;
- idmap_namerule_cpy;
- idmap_info_free;
- idmap_info_cpy;
- idmap_info_mov;
- idmap_getext_sidbygid;
- idmap_getext_uidbysid;
- idmap_getext_pidbysid;
- idmap_getext_gidbysid;
- idmap_getext_sidbyuid;
- idmap_set_namemap;
- idmap_unset_namemap;
- idmap_get_namemap;
- idmap_init_namemaps;
- idmap_fini_namemaps;
- idmap_cache_get_data;
- idmap_set_logger;
+ xdr_idmap_retcode;
+ xdr_idmap_update_batch;
+ xdr_idmap_update_res;
local:
*;
};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/miscutils.c Fri Jul 17 17:54:42 2009 -0700
@@ -0,0 +1,124 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Miscellaneous utility functions not specifically related to
+ * the application.
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <ctype.h>
+#include "miscutils.h"
+
+/* Return true if strings are equal */
+boolean_t
+streq(const char *a, const char *b)
+{
+ return (strcmp(a, b) == 0);
+}
+
+/* Return true if strings are equal, case-insensitively */
+boolean_t
+strcaseeq(const char *a, const char *b)
+{
+ return (strcasecmp(a, b) == 0);
+}
+
+/* Return true if string a Begins With string b */
+boolean_t
+strbw(const char *a, const char *b)
+{
+ return (strncmp(a, b, strlen(b)) == 0);
+}
+
+/*
+ * Duplicate up to n bytes of a string. Kind of sort of like
+ * strdup(strlcpy(s, n)).
+ */
+char *
+strndup(const char *s, int n)
+{
+ int len;
+ char *p;
+
+ len = strnlen(s, n);
+ p = malloc(len + 1);
+ if (p == NULL)
+ return (NULL);
+
+ if (len > 0)
+ (void) memcpy(p, s, len);
+ p[len] = '\0';
+
+ return (p);
+}
+
+/*
+ * Duplicate a block of memory. Combines malloc with memcpy, much as
+ * strdup combines malloc, strlen, and strcpy.
+ */
+void *
+memdup(const void *buf, size_t sz)
+{
+ void *p;
+
+ p = malloc(sz);
+ if (p == NULL)
+ return (NULL);
+ (void) memcpy(p, buf, sz);
+ return (p);
+}
+
+/*
+ * Dump a block of memory in hex+ascii, for debugging
+ */
+void
+dump(FILE *out, const char *prefix, const void *buf, size_t len)
+{
+ const unsigned char *p = buf;
+ int i;
+
+ for (i = 0; i < len; i += 16) {
+ int j;
+
+ (void) fprintf(out, "%s", prefix);
+ for (j = 0; j < 16 && i + j < len; j++) {
+ (void) fprintf(out, "%2.2x ", p[i + j]);
+ }
+ for (; j < 16; j++) {
+ (void) fprintf(out, " ");
+ }
+ for (j = 0; j < 16 && i + j < len; j++) {
+ (void) fprintf(out, "%c",
+ isprint(p[i + j]) ? p[i + j] : '.');
+ }
+ (void) fprintf(out, "\n");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/miscutils.h Fri Jul 17 17:54:42 2009 -0700
@@ -0,0 +1,51 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _MISCUTILS_H
+#define _MISCUTILS_H
+
+/*
+ * Miscellaneous functions and macros not directly related to the application.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define NELEM(a) (sizeof (a) / sizeof ((a)[0]))
+
+boolean_t strcaseeq(const char *a, const char *b);
+boolean_t streq(const char *a, const char *b);
+char *strndup(const char *s, int n);
+boolean_t strbw(const char *a, const char *b);
+void *memdup(const void *buf, size_t sz);
+void dump(FILE *out, const char *prefix, const void *buf, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MISCUTILS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/sidutil.c Fri Jul 17 17:54:42 2009 -0700
@@ -0,0 +1,189 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * This is an extract from usr/src/common/smbsrv/smb_sid.c,
+ * with functions renamed as part of a tentative plan for convergence.
+ */
+#ifndef _KERNEL
+#include <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <syslog.h>
+#else /* _KERNEL */
+#include <sys/types.h>
+#include <sys/sunddi.h>
+#endif /* _KERNEL */
+
+#include <sidutil.h>
+
+/*
+ * sid_len
+ *
+ * Returns the number of bytes required to hold the sid.
+ */
+int
+sid_len(sid_t *sid)
+{
+ if (sid == NULL)
+ return (0);
+
+ return (sizeof (sid_t) - sizeof (uint32_t)
+ + (sid->sid_subauthcnt * sizeof (uint32_t)));
+}
+
+/*
+ * sid_tostr
+ *
+ * Fill in the passed buffer with the string form of the given
+ * binary sid.
+ */
+void
+sid_tostr(sid_t *sid, char *strsid)
+{
+ char *p = strsid;
+ int i;
+
+ if (sid == NULL || strsid == NULL)
+ return;
+
+ (void) sprintf(p, "S-%d-", sid->sid_revision);
+ while (*p)
+ p++;
+
+ for (i = 0; i < NT_SID_AUTH_MAX; ++i) {
+ if (sid->sid_authority[i] != 0 || i == NT_SID_AUTH_MAX - 1) {
+ (void) sprintf(p, "%d", sid->sid_authority[i]);
+ while (*p)
+ p++;
+ }
+ }
+
+ for (i = 0; i < sid->sid_subauthcnt && i < NT_SID_SUBAUTH_MAX; ++i) {
+ (void) sprintf(p, "-%u", sid->sid_subauth[i]);
+ while (*p)
+ p++;
+ }
+}
+
+/*
+ * sid_fromstr
+ *
+ * Converts a SID in string form to a SID structure. There are lots of
+ * simplifying assumptions in here. The memory for the SID is allocated
+ * as if it was the largest possible SID; the caller is responsible for
+ * freeing the memory when it is no longer required. We assume that the
+ * string starts with "S-1-" and that the authority is held in the last
+ * byte, which should be okay for most situations. It also assumes the
+ * sub-authorities are in decimal format.
+ *
+ * On success, a pointer to a SID is returned. Otherwise a null pointer
+ * is returned.
+ */
+sid_t *
+sid_fromstr(char *sidstr)
+{
+ sid_t *sid;
+ char *p;
+ int size;
+ uint8_t i;
+
+ if (sidstr == NULL)
+ return (NULL);
+
+ if (strncmp(sidstr, "S-1-", 4) != 0)
+ return (NULL);
+
+ size = sizeof (sid_t) + (NT_SID_SUBAUTH_MAX * sizeof (uint32_t));
+
+ if ((sid = malloc(size)) == NULL)
+ return (NULL);
+
+ bzero(sid, size);
+ sid->sid_revision = NT_SID_REVISION;
+ sid->sid_authority[5] = atoi(&sidstr[4]);
+
+ for (i = 0, p = &sidstr[5]; i < NT_SID_SUBAUTH_MAX && *p; ++i) {
+ while (*p && *p == '-')
+ ++p;
+
+ if (*p < '0' || *p > '9') {
+ free(sid);
+ return (NULL);
+ }
+
+ sid->sid_subauth[i] = strtoul(p, NULL, 10);
+
+ while (*p && *p != '-')
+ ++p;
+ }
+
+ sid->sid_subauthcnt = i;
+ return (sid);
+}
+
+void
+sid_free(sid_t *sid)
+{
+#ifdef _KERNEL
+ if (sid == NULL)
+ return;
+
+ kmem_free(sid, sid_len(sid));
+#else
+ free(sid);
+#endif
+}
+
+void
+sid_to_le(sid_t *sid)
+{
+ int i;
+
+ for (i = 0; i < sid->sid_subauthcnt && i < NT_SID_SUBAUTH_MAX; ++i) {
+ uint32_t v = sid->sid_subauth[i];
+ uint8_t *p = (uint8_t *)&sid->sid_subauth[i];
+
+ p[0] = v & 0xff;
+ p[1] = (v >> 8) & 0xff;
+ p[2] = (v >> 16) & 0xff;
+ p[3] = (v >> 24) & 0xff;
+ }
+}
+
+void
+sid_from_le(sid_t *sid)
+{
+ int i;
+
+ for (i = 0; i < sid->sid_subauthcnt && i < NT_SID_SUBAUTH_MAX; ++i) {
+ uint32_t v;
+ uint8_t *p = (uint8_t *)&sid->sid_subauth[i];
+
+ v = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
+
+ sid->sid_subauth[i] = v;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/sidutil.h Fri Jul 17 17:54:42 2009 -0700
@@ -0,0 +1,123 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SIDUTIL_H
+#define _SIDUTIL_H
+
+/*
+ * Security Identifier (SID) interface definition.
+ *
+ * This is an extract from uts/common/smbsrv/smb_sid.h, with functions
+ * renamed as part of a tentative plan for convergence.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Common definition for a SID.
+ */
+#define NT_SID_REVISION 1
+#define NT_SID_AUTH_MAX 6
+#define NT_SID_SUBAUTH_MAX 15
+
+#if !defined(ANY_SIZE_ARRAY)
+#define ANY_SIZE_ARRAY 1
+#endif
+
+/*
+ * Security Identifier (SID)
+ *
+ * The security identifier (SID) uniquely identifies a user, group or
+ * a domain. It consists of a revision number, the identifier authority,
+ * and a list of sub-authorities. The revision number is currently 1.
+ * The identifier authority identifies which system issued the SID. The
+ * sub-authorities of a domain SID uniquely identify a domain. A user
+ * or group SID consists of a domain SID with the user or group id
+ * appended. The user or group id (also known as a relative id (RID)
+ * uniquely identifies a user within a domain. A user or group SID
+ * uniquely identifies a user or group across all domains. The SidType
+ * values identify the various types of SID.
+ *
+ * 1 1 1 1 1 1
+ * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ * +---------------------------------------------------------------+
+ * | SubAuthorityCount |Reserved1 (SBZ)| Revision |
+ * +---------------------------------------------------------------+
+ * | IdentifierAuthority[0] |
+ * +---------------------------------------------------------------+
+ * | IdentifierAuthority[1] |
+ * +---------------------------------------------------------------+
+ * | IdentifierAuthority[2] |
+ * +---------------------------------------------------------------+
+ * | |
+ * +- - - - - - - - SubAuthority[] - - - - - - - - -+
+ * | |
+ * +---------------------------------------------------------------+
+ *
+ */
+/*
+ * Note: NT defines the Identifier Authority as a separate
+ * structure (SID_IDENTIFIER_AUTHORITY) containing a literal
+ * definition of a 6 byte vector but the effect is the same
+ * as defining it as a member value.
+ */
+typedef struct sid {
+ uint8_t sid_revision;
+ uint8_t sid_subauthcnt;
+ uint8_t sid_authority[NT_SID_AUTH_MAX];
+ uint32_t sid_subauth[ANY_SIZE_ARRAY];
+} sid_t;
+
+/*
+ * The maximum size of a SID in string format
+ */
+#define SID_STRSZ 256
+
+/* Given a SID, return its length in bytes. */
+int sid_len(sid_t *);
+
+/* Given a dynamically allocated SID (e.g. from sid_fromstr), free it. */
+void sid_free(sid_t *);
+
+/* Translate a binary-format SID into the supplied SID_STRSZ buffer. */
+void sid_tostr(sid_t *, char *);
+
+/* Translate a text-format SID into an allocated binary-format SID. */
+sid_t *sid_fromstr(char *);
+
+/* In-place, translate a host-order SID into MS-native little endian. */
+void sid_to_le(sid_t *);
+
+/* In-place, translate a MS-native little endian SID into host order. */
+void sid_from_le(sid_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _SIDUTIL_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/sized_array.c Fri Jul 17 17:54:42 2009 -0700
@@ -0,0 +1,122 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Much like calloc, but with functions to report the size of the
+ * allocation given only the pointer.
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <malloc.h>
+#include "sized_array.h"
+
+/*
+ * Assumes that int is at least 32 bits and that nothing needs more than
+ * 8-byte alignment.
+ */
+
+/* COOKIE provides some bad-pointer protection. */
+#define COOKIE "SACOOKIE"
+
+struct sized_array {
+ int n;
+ int sz;
+#if defined(COOKIE)
+ char cookie[8];
+#endif
+};
+
+
+void *
+sized_array(size_t n, size_t sz)
+{
+ struct sized_array *sa;
+ size_t total;
+
+ total = sizeof (struct sized_array) + n*sz;
+
+ sa = malloc(total);
+
+ if (sa == NULL)
+ return (NULL);
+
+ (void) memset(sa, 0, total);
+
+ sa->n = n;
+ sa->sz = sz;
+
+#if defined(COOKIE)
+ (void) memcpy(sa->cookie, COOKIE, sizeof (sa->cookie));
+#endif
+
+ return ((void *)(sa + 1));
+}
+
+void
+sized_array_free(void *p)
+{
+ struct sized_array *sa;
+
+ if (p == NULL)
+ return;
+
+ sa = ((struct sized_array *)p)-1;
+
+#if defined(COOKIE)
+ assert(memcmp(sa->cookie, COOKIE, sizeof (sa->cookie)) == 0);
+#endif
+
+ free(sa);
+}
+
+size_t
+sized_array_n(void *p)
+{
+ struct sized_array *sa;
+
+ sa = ((struct sized_array *)p)-1;
+
+#if defined(COOKIE)
+ assert(memcmp(sa->cookie, COOKIE, sizeof (sa->cookie)) == 0);
+#endif
+
+ return (sa->n);
+}
+
+size_t
+sized_array_sz(void *p)
+{
+ struct sized_array *sa;
+
+ sa = ((struct sized_array *)p)-1;
+
+#if defined(COOKIE)
+ assert(memcmp(sa->cookie, COOKIE, sizeof (sa->cookie)) == 0);
+#endif
+
+ return (sa->sz);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libidmap/common/sized_array.h Fri Jul 17 17:54:42 2009 -0700
@@ -0,0 +1,48 @@
+/*
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SIZED_ARRAY_H
+#define _SIZED_ARRAY_H
+
+/*
+ * Like calloc, but with mechanisms to get the size of the allocated
+ * area given only the pointer.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *sized_array(size_t n, size_t sz);
+void sized_array_free(void *p);
+size_t sized_array_n(void *p);
+size_t sized_array_sz(void *p);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SIZED_ARRAY_H */
--- a/usr/src/lib/smbsrv/libmlrpc/common/libmlrpc.h Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/smbsrv/libmlrpc/common/libmlrpc.h Fri Jul 17 17:54:42 2009 -0700
@@ -245,7 +245,7 @@
typedef struct ndr_pipe {
int np_fid;
- smb_opipe_context_t np_ctx;
+ smb_netuserinfo_t np_user;
char *np_buf;
struct uio np_uio;
iovec_t np_iov;
@@ -516,7 +516,6 @@
int ndr_pipe_close(int);
int ndr_pipe_read(int, uint8_t *, uint32_t *, uint32_t *);
int ndr_pipe_write(int, uint8_t *, uint32_t);
-int ndr_pipe_getinfo(int, ndr_pipe_info_t *);
int ndr_generic_call_stub(ndr_xa_t *);
--- a/usr/src/lib/smbsrv/libmlrpc/common/mapfile-vers Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/smbsrv/libmlrpc/common/mapfile-vers Fri Jul 17 17:54:42 2009 -0700
@@ -67,7 +67,6 @@
ndr_mbtowc;
ndr_native_os;
ndr_params;
- ndr_pipe_getinfo;
ndr_pipe_open;
ndr_pipe_close;
ndr_pipe_read;
--- a/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c Fri Jul 17 17:54:42 2009 -0700
@@ -89,7 +89,7 @@
return (ENOMEM);
}
- if (smb_opipe_context_decode(&np->np_ctx, data, datalen, NULL) == -1) {
+ if (smb_netuserinfo_decode(&np->np_user, data, datalen, NULL) == -1) {
ndr_pipe_release(np);
(void) mutex_unlock(&ndr_pipe_lock);
return (EINVAL);
@@ -257,37 +257,6 @@
}
/*
- * Return information about the specified pipe.
- */
-int
-ndr_pipe_getinfo(int ndx, ndr_pipe_info_t *npi)
-{
- ndr_pipe_t *np;
-
- if ((ndx < 0) || (ndx >= NDR_PIPE_MAX) || (npi == NULL))
- return (-1);
-
- (void) mutex_lock(&ndr_pipe_lock);
- np = &ndr_pipe_table[ndx];
-
- if (np->np_fid == 0) {
- (void) mutex_unlock(&ndr_pipe_lock);
- return (-1);
- }
-
- npi->npi_fid = np->np_fid;
- npi->npi_permissions = FILE_READ_DATA | FILE_WRITE_DATA | FILE_EXECUTE;
- npi->npi_num_locks = 0;
- (void) snprintf(npi->npi_username, MAXNAMELEN, "%s\\%s",
- np->np_ctx.oc_domain, np->np_ctx.oc_account);
- (void) snprintf(npi->npi_pathname, MAXPATHLEN, "%s",
- np->np_binding->service->sec_addr_port);
-
- (void) mutex_unlock(&ndr_pipe_lock);
- return (0);
-}
-
-/*
* Must be called with ndr_pipe_lock held.
*/
static ndr_pipe_t *
@@ -365,9 +334,9 @@
ndr_pipe_rewind(np);
ndr_pipe_flush(np);
free(np->np_buf);
- free(np->np_ctx.oc_domain);
- free(np->np_ctx.oc_account);
- free(np->np_ctx.oc_workstation);
+ free(np->np_user.ui_domain);
+ free(np->np_user.ui_account);
+ free(np->np_user.ui_workstation);
bzero(np, sizeof (ndr_pipe_t));
}
}
@@ -412,9 +381,9 @@
boolean_t
ndr_is_admin(ndr_xa_t *xa)
{
- smb_opipe_context_t *ctx = &xa->pipe->np_ctx;
+ smb_netuserinfo_t *ctx = &xa->pipe->np_user;
- return (ctx->oc_flags & SMB_ATF_ADMIN);
+ return (ctx->ui_flags & SMB_ATF_ADMIN);
}
/*
@@ -426,18 +395,18 @@
boolean_t
ndr_is_poweruser(ndr_xa_t *xa)
{
- smb_opipe_context_t *ctx = &xa->pipe->np_ctx;
+ smb_netuserinfo_t *ctx = &xa->pipe->np_user;
- return ((ctx->oc_flags & SMB_ATF_ADMIN) ||
- (ctx->oc_flags & SMB_ATF_POWERUSER));
+ return ((ctx->ui_flags & SMB_ATF_ADMIN) ||
+ (ctx->ui_flags & SMB_ATF_POWERUSER));
}
int32_t
ndr_native_os(ndr_xa_t *xa)
{
- smb_opipe_context_t *ctx = &xa->pipe->np_ctx;
+ smb_netuserinfo_t *ctx = &xa->pipe->np_user;
- return (ctx->oc_native_os);
+ return (ctx->ui_native_os);
}
/*
--- a/usr/src/lib/smbsrv/libmlsvc/common/eventlog.h Fri Jul 17 16:57:52 2009 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-/*
- * 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 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef _eventlog_H
-#define _eventlog_H
-
-#include <netdb.h>
-#include <smbsrv/libsmb.h>
-#include <smbsrv/ndl/eventlog.ndl>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define LOGR_NMSGMASK 1023
-
-typedef struct logr_entry {
- struct timeval le_timestamp; /* Time of log entry */
- int le_pri; /* Message priority */
- char le_hostname[MAXHOSTNAMELEN]; /* Log hostname */
- char le_msg[LOGR_MAXENTRYLEN]; /* Log message text */
-} logr_entry_t;
-
-typedef struct logr_info {
- logr_entry_t li_entry[LOGR_NMSGMASK+1]; /* Array of log entry */
- int li_idx; /* Index */
-} logr_info_t;
-
-typedef struct logr_read_data {
- int rd_tot_recnum; /* Total no. of record read */
- int rd_last_sentrec; /* Last sentence read */
- char rd_first_read; /* First sentence read */
- logr_info_t *rd_log; /* Log information read */
-} logr_read_data_t;
-
-/* This structure provides the context for eventlog calls from clients. */
-typedef struct logr_context {
- logr_read_data_t *lc_cached_read_data;
- char *lc_source_name;
-} logr_context_t;
-
-int logr_syslog_snapshot(logr_info_t *);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _eventlog_H */
--- a/usr/src/lib/smbsrv/libmlsvc/common/eventlog_svc.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/smbsrv/libmlsvc/common/eventlog_svc.c Fri Jul 17 17:54:42 2009 -0700
@@ -29,15 +29,15 @@
#include <sys/utsname.h>
#include <unistd.h>
#include <strings.h>
-
#include <smbsrv/libsmb.h>
#include <smbsrv/libmlrpc.h>
#include <smbsrv/ntstatus.h>
#include <smbsrv/nmpipes.h>
#include <smbsrv/libmlsvc.h>
-#include "eventlog.h"
+#include <smbsrv/ndl/eventlog.ndl>
#include <smbsrv/nterror.h>
+
#define LOGR_FWD +1
#define LOGR_REW -1
#define LOGR_RECORD_SIGNATURE 0x654C664C
@@ -162,8 +162,6 @@
logr_stub_table /* stub_table */
};
-static int logr_get_snapshot(logr_context_t *);
-
/*
* logr_initialize
*
@@ -175,6 +173,13 @@
logr_initialize(void)
{
(void) ndr_svc_register(&logr_service);
+ logr_init();
+}
+
+void
+logr_finalize(void)
+{
+ logr_fini();
}
/*
@@ -222,12 +227,12 @@
}
/*
- * logr_mgr_hdalloc
+ * logr_hdalloc
*
* Handle allocation wrapper to setup the local manager context.
*/
static ndr_hdid_t *
-logr_hdalloc(ndr_xa_t *mxa)
+logr_hdalloc(ndr_xa_t *mxa, char *logname)
{
logr_context_t *ctx;
@@ -235,8 +240,13 @@
return (NULL);
bzero(ctx, sizeof (logr_context_t));
- ctx->lc_source_name = strdup("eventlog");
- if ((ctx->lc_source_name != NULL) && (logr_get_snapshot(ctx) < 0)) {
+ ctx->lc_source_name = strdup(logname);
+ if (ctx->lc_source_name == NULL) {
+ free(ctx);
+ return (NULL);
+ }
+
+ if (logr_get_snapshot(ctx) != 0) {
free(ctx->lc_source_name);
free(ctx);
return (NULL);
@@ -287,16 +297,22 @@
ndr_handle_t *hd;
char *log_name = NULL;
- if (param->log_name.length != 0)
- log_name = (char *)param->log_name.str;
-
- if ((log_name == NULL) || strcasecmp(log_name, "System") != 0) {
+ if (!ndr_is_admin(mxa)) {
bzero(¶m->handle, sizeof (logr_handle_t));
param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
return (NDR_DRC_OK);
}
- id = logr_hdalloc(mxa);
+ if (param->log_name.length != 0)
+ log_name = (char *)param->log_name.str;
+
+ if (!logr_is_supported(log_name)) {
+ bzero(¶m->handle, sizeof (logr_handle_t));
+ param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+ return (NDR_DRC_OK);
+ }
+
+ id = logr_hdalloc(mxa, log_name);
if (id && ((hd = logr_hdlookup(mxa, id)) != NULL)) {
hd->nh_data_free = logr_context_data_free;
bcopy(id, ¶m->handle, sizeof (logr_handle_t));
@@ -310,42 +326,6 @@
}
/*
- * logr_get_snapshot
- *
- * Allocate memory and make a copy, as a snapshot, from system log.
- */
-static int
-logr_get_snapshot(logr_context_t *ctx)
-{
- logr_read_data_t *data = NULL;
-
- ctx->lc_cached_read_data = malloc(sizeof (logr_read_data_t));
- if (ctx->lc_cached_read_data != NULL) {
- data = ctx->lc_cached_read_data;
-
- data->rd_log = (logr_info_t *)malloc(sizeof (logr_info_t));
- if (data->rd_log == NULL) {
- free(data);
- return (-1);
- }
- bzero(data->rd_log, sizeof (logr_info_t));
-
- data->rd_tot_recnum = logr_syslog_snapshot(data->rd_log);
- if (data->rd_tot_recnum < 0) {
- free(data->rd_log);
- free(data);
- return (-1);
- }
-
- data->rd_first_read = 1;
-
- return (0);
- }
-
- return (-1);
-}
-
-/*
* logr_s_EventLogQueryCount
*
* take a snapshot from system log, assign it to the given handle.
--- a/usr/src/lib/smbsrv/libmlsvc/common/eventlog_syslog.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/smbsrv/libmlsvc/common/eventlog_syslog.c Fri Jul 17 17:54:42 2009 -0700
@@ -32,11 +32,13 @@
#include <string.h>
#include <strings.h>
#include <stdarg.h>
+#include <dlfcn.h>
#include <sys/synch.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <ctype.h>
-#include "eventlog.h"
+#include <smbsrv/ndl/eventlog.ndl>
+#include <smbsrv/libmlsvc.h>
typedef enum {
LOGR_MONTH = 0,
@@ -77,6 +79,12 @@
char ln_logline[LOGR_MAXENTRYLEN];
} logr_syslog_node_t;
+static void *logr_interposer_hdl = NULL;
+static struct {
+ boolean_t (*logr_op_supported)(char *);
+ int (*logr_op_snapshot)(logr_context_t *);
+} logr_interposer_ops;
+
/*
* Set the syslog timestamp.
*
@@ -289,12 +297,12 @@
* provided by the caller. Returns the number of entries in
* the log.
*/
-int
-logr_syslog_snapshot(logr_info_t *loginfo)
+static int
+logr_syslog_snapshot(char *logname, logr_info_t *loginfo)
{
FILE *fp;
- if (loginfo == NULL)
+ if ((loginfo == NULL) || (!logr_is_supported(logname)))
return (-1);
if ((fp = fopen("/var/adm/messages", "r")) == 0)
@@ -311,3 +319,107 @@
return (LOGR_NMSGMASK+1);
}
+
+/*
+ * logr_is_supported
+ *
+ * Determines if a given log is supported or not.
+ * Returns B_TRUE on success, B_FALSE on failure.
+ */
+boolean_t
+logr_is_supported(char *log_name)
+{
+ if (log_name == NULL)
+ return (B_FALSE);
+
+ if (logr_interposer_ops.logr_op_supported != NULL)
+ return (logr_interposer_ops.logr_op_supported(log_name));
+
+ if (strcasecmp(log_name, LOGR_SYSTEM_LOG) != 0)
+ return (B_FALSE);
+
+ return (B_TRUE);
+}
+
+/*
+ * logr_get_snapshot
+ *
+ * Allocate memory and make a copy, as a snapshot, from system log.
+ * Returns 0 on success, -1 on failure.
+ */
+int
+logr_get_snapshot(logr_context_t *ctx)
+{
+ logr_read_data_t *data = NULL;
+
+ if (logr_interposer_ops.logr_op_snapshot != NULL)
+ return (logr_interposer_ops.logr_op_snapshot(ctx));
+
+ ctx->lc_cached_read_data = malloc(sizeof (logr_read_data_t));
+ if (ctx->lc_cached_read_data != NULL) {
+ data = ctx->lc_cached_read_data;
+
+ data->rd_log = (logr_info_t *)malloc(sizeof (logr_info_t));
+ if (data->rd_log == NULL) {
+ free(data);
+ return (-1);
+ }
+ bzero(data->rd_log, sizeof (logr_info_t));
+
+ data->rd_tot_recnum = logr_syslog_snapshot(ctx->lc_source_name,
+ data->rd_log);
+ if (data->rd_tot_recnum < 0) {
+ free(data->rd_log);
+ free(data);
+ return (-1);
+ }
+
+ data->rd_first_read = 1;
+
+ return (0);
+ }
+
+ return (-1);
+}
+
+/*
+ * logr_init
+ *
+ * Initializes the Eventlog service.
+ * Checks to see if a event log utility library
+ * is interposed. If yes then it'll initializes logr_interposer_ops
+ * structure with function pointers from this library.
+ */
+void
+logr_init(void)
+{
+ logr_interposer_hdl = smb_dlopen();
+ if (logr_interposer_hdl == NULL)
+ return;
+
+ bzero((void *)&logr_interposer_ops, sizeof (logr_interposer_ops));
+
+ logr_interposer_ops.logr_op_supported =
+ (boolean_t (*)())dlsym(logr_interposer_hdl, "logr_is_supported");
+
+ logr_interposer_ops.logr_op_snapshot =
+ (int (*)())dlsym(logr_interposer_hdl, "logr_get_snapshot");
+
+ if (logr_interposer_ops.logr_op_supported == NULL ||
+ logr_interposer_ops.logr_op_snapshot == NULL)
+ logr_fini();
+}
+
+/*
+ * logr_fini
+ *
+ * Finalizes the Eventlog service.
+ * Closes handle to interposed library.
+ */
+void
+logr_fini(void)
+{
+ smb_dlclose(logr_interposer_hdl);
+ logr_interposer_hdl = NULL;
+ bzero((void *)&logr_interposer_ops, sizeof (logr_interposer_ops));
+}
--- a/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h Fri Jul 17 17:54:42 2009 -0700
@@ -26,12 +26,15 @@
#ifndef _LIBMLSVC_H
#define _LIBMLSVC_H
+#include <uuid/uuid.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/ksynch.h>
#include <stdio.h>
#include <string.h>
+#include <netdb.h>
+#include <libuutil.h>
#include <smbsrv/wintypes.h>
#include <smbsrv/hash_table.h>
#include <smbsrv/smb_token.h>
@@ -59,12 +62,9 @@
extern boolean_t smb_domain_getinfo(smb_domain_t *);
-extern uint64_t mlsvc_get_num_users(void);
-extern int mlsvc_get_user_list(smb_ulist_t *);
extern void dssetup_clear_domain_info(void);
extern int mlsvc_init(void);
extern void mlsvc_fini(void);
-extern int mlsvc_set_share(int, char *, char *);
extern DWORD mlsvc_netlogon(char *, char *);
extern DWORD mlsvc_join(smb_domain_t *, char *, char *);
@@ -126,6 +126,21 @@
} ms_luid_t;
/*
+ * Information about a server as reported by NetServerGetInfo.
+ * The SV_PLATFORM and SV_TYPE definitions are in srvsvc.ndl.
+ */
+typedef struct srvsvc_server_info {
+ uint32_t sv_platform_id;
+ char *sv_name;
+ uint32_t sv_version_major;
+ uint32_t sv_version_minor;
+ uint32_t sv_type;
+ char *sv_comment;
+} srvsvc_server_info_t;
+
+int srvsvc_net_server_getinfo(char *, char *, srvsvc_server_info_t *);
+
+/*
* A client_t is created while binding a client connection to hold the
* context for calls made using that connection.
*
@@ -137,11 +152,14 @@
ndr_hdid_t handle;
ndr_client_t *clnt;
int remote_os;
+ srvsvc_server_info_t svinfo;
} mlsvc_handle_t;
int ndr_rpc_bind(mlsvc_handle_t *, char *, char *, char *, const char *);
void ndr_rpc_unbind(mlsvc_handle_t *);
int ndr_rpc_call(mlsvc_handle_t *, int, void *);
+void ndr_rpc_server_setinfo(mlsvc_handle_t *, const srvsvc_server_info_t *);
+void ndr_rpc_server_getinfo(mlsvc_handle_t *, srvsvc_server_info_t *);
int ndr_rpc_server_os(mlsvc_handle_t *);
void *ndr_rpc_malloc(mlsvc_handle_t *, size_t);
ndr_heap_t *ndr_rpc_get_heap(mlsvc_handle_t *);
@@ -151,6 +169,108 @@
void ndr_inherit_handle(mlsvc_handle_t *, mlsvc_handle_t *);
void ndr_rpc_status(mlsvc_handle_t *, int, uint32_t);
+/* SVCCTL service */
+/*
+ * Calculate the wide-char equivalent string length required to
+ * store a string - including the terminating null wide-char.
+ */
+#define SVCCTL_WNSTRLEN(S) ((strlen((S)) + 1) * sizeof (mts_wchar_t))
+
+/* An AVL-storable node representing each service in the SCM database. */
+typedef struct svcctl_svc_node {
+ uu_avl_node_t sn_node;
+ char *sn_name; /* Service Name (Key) */
+ char *sn_fmri; /* Display Name (FMRI) */
+ char *sn_desc; /* Description */
+ char *sn_state; /* State */
+} svcctl_svc_node_t;
+
+/* This structure provides context for each svcctl_s_OpenManager call. */
+typedef struct svcctl_manager_context {
+ scf_handle_t *mc_scf_hdl; /* SCF handle */
+ scf_propertygroup_t *mc_scf_gpg; /* Property group */
+ scf_property_t *mc_scf_gprop; /* Property */
+ scf_value_t *mc_scf_gval; /* Value */
+ uint32_t mc_scf_numsvcs; /* Number of SMF services */
+ ssize_t mc_scf_max_fmri_len; /* Max FMRI length */
+ ssize_t mc_scf_max_value_len; /* Max Value length */
+ uint32_t mc_bytes_needed; /* Number of bytes needed */
+ uu_avl_pool_t *mc_svcs_pool; /* AVL pool */
+ uu_avl_t *mc_svcs; /* AVL tree of SMF services */
+} svcctl_manager_context_t;
+
+/* This structure provides context for each svcctl_s_OpenService call. */
+typedef struct svcctl_service_context {
+ ndr_hdid_t *sc_mgrid; /* Manager ID */
+ char *sc_svcname; /* Service Name */
+} svcctl_service_context_t;
+
+typedef enum {
+ SVCCTL_MANAGER_CONTEXT = 0,
+ SVCCTL_SERVICE_CONTEXT
+} svcctl_context_type_t;
+
+/* This structure provides abstraction for service and manager context call. */
+typedef struct svcctl_context {
+ svcctl_context_type_t c_type;
+ union {
+ svcctl_manager_context_t *uc_mgr;
+ svcctl_service_context_t *uc_svc;
+ void *uc_cp;
+ } c_ctx;
+} svcctl_context_t;
+
+/* Service Control Manager (SCM) functions */
+void svcctl_init(void);
+void svcctl_fini(void);
+int svcctl_scm_init(svcctl_manager_context_t *);
+void svcctl_scm_fini(svcctl_manager_context_t *);
+int svcctl_scm_scf_handle_init(svcctl_manager_context_t *);
+void svcctl_scm_scf_handle_fini(svcctl_manager_context_t *);
+int svcctl_scm_refresh(svcctl_manager_context_t *);
+uint32_t svcctl_scm_enum_services(svcctl_manager_context_t *, uint8_t *,
+ size_t, uint32_t *, boolean_t);
+uint32_t svcctl_scm_validate_service(svcctl_manager_context_t *, char *);
+svcctl_svc_node_t *svcctl_scm_find_service(svcctl_manager_context_t *, char *);
+uint32_t svcctl_scm_map_status(const char *);
+
+/* LOGR service */
+#define LOGR_APPLICATION_LOG "Application"
+#define LOGR_SECURITY_LOG "Security"
+#define LOGR_SYSTEM_LOG "System"
+#define LOGR_NMSGMASK 1023
+#define LOGR_MAXMSGLEN 800
+
+typedef struct logr_entry {
+ struct timeval le_timestamp; /* Time of log entry */
+ int le_pri; /* Message priority */
+ char le_hostname[MAXHOSTNAMELEN]; /* Log hostname */
+ char le_msg[LOGR_MAXMSGLEN]; /* Log message text */
+} logr_entry_t;
+
+typedef struct logr_info {
+ logr_entry_t li_entry[LOGR_NMSGMASK+1]; /* Array of log entry */
+ int li_idx; /* Index */
+} logr_info_t;
+
+typedef struct logr_read_data {
+ int rd_tot_recnum; /* Total no. of record read */
+ int rd_last_sentrec; /* Last sentence read */
+ char rd_first_read; /* First sentence read */
+ logr_info_t *rd_log; /* Log information read */
+} logr_read_data_t;
+
+/* This structure provides the context for eventlog calls from clients. */
+typedef struct logr_context {
+ logr_read_data_t *lc_cached_read_data;
+ char *lc_source_name;
+} logr_context_t;
+
+void logr_init(void);
+void logr_fini(void);
+boolean_t logr_is_supported(char *);
+int logr_get_snapshot(logr_context_t *);
+
#ifdef __cplusplus
}
#endif
--- a/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers Fri Jul 17 17:54:42 2009 -0700
@@ -41,15 +41,12 @@
SUNWprivate {
global:
dssetup_clear_domain_info;
- mlsvc_get_num_users;
- mlsvc_get_user_list;
mlsvc_fini;
mlsvc_init;
mlsvc_join;
mlsvc_lookup_name;
mlsvc_lookup_sid;
mlsvc_netlogon;
- mlsvc_set_share;
smb_autohome_add;
smb_autohome_remove;
smb_domain_getinfo;
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h Fri Jul 17 17:54:42 2009 -0700
@@ -47,6 +47,9 @@
void msgsvcsend_initialize(void);
void spoolss_initialize(void);
+void logr_finalize(void);
+void svcctl_finalize(void);
+
int netr_open(char *, char *, mlsvc_handle_t *);
int netr_close(mlsvc_handle_t *);
DWORD netlogon_auth(char *, mlsvc_handle_t *, DWORD);
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c Fri Jul 17 17:54:42 2009 -0700
@@ -170,6 +170,36 @@
}
/*
+ * Set information about the remote RPC server in the handle.
+ */
+void
+ndr_rpc_server_setinfo(mlsvc_handle_t *handle,
+ const srvsvc_server_info_t *svinfo)
+{
+ bcopy(svinfo, &handle->svinfo, sizeof (srvsvc_server_info_t));
+ handle->svinfo.sv_name = NULL;
+ handle->svinfo.sv_comment = NULL;
+
+ if (svinfo->sv_version_major > 4)
+ handle->remote_os = NATIVE_OS_WIN2000;
+ else
+ handle->remote_os = NATIVE_OS_WINNT;
+
+ smb_tracef("NdrRpcServerSetInfo: %s (version %d.%d)",
+ svinfo->sv_name ? svinfo->sv_name : "<unknown>",
+ svinfo->sv_version_major, svinfo->sv_version_minor);
+}
+
+/*
+ * Get information about the remote RPC server from the handle.
+ */
+void
+ndr_rpc_server_getinfo(mlsvc_handle_t *handle, srvsvc_server_info_t *svinfo)
+{
+ bcopy(&handle->svinfo, svinfo, sizeof (srvsvc_server_info_t));
+}
+
+/*
* Returns the Native-OS of the RPC server.
*/
int
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c Fri Jul 17 17:54:42 2009 -0700
@@ -82,6 +82,8 @@
mlsvc_fini(void)
{
smb_logon_fini();
+ svcctl_finalize();
+ logr_finalize();
}
/*ARGSUSED*/
@@ -100,43 +102,3 @@
/*NOTREACHED*/
return (NULL);
}
-
-uint64_t
-mlsvc_get_num_users(void)
-{
- uint32_t n_users = 0;
-
- (void) smb_kmod_get_usernum(&n_users);
- return ((uint64_t)n_users);
-}
-
-/*
- * The calling function must free the output parameter 'users'.
- */
-int
-mlsvc_get_user_list(smb_ulist_t *ulist)
-{
- return (smb_kmod_get_userlist(ulist));
-}
-
-/*
- * Downcall to the kernel that is executed upon share enable and disable.
- */
-int
-mlsvc_set_share(int shrop, char *path, char *name)
-{
- int rc;
-
- switch (shrop) {
- case SMB_SHROP_ADD:
- rc = smb_kmod_share(path, name);
- break;
- case SMB_SHROP_DELETE:
- rc = smb_kmod_unshare(path, name);
- break;
- default:
- rc = EINVAL;
- break;
- }
- return (rc);
-}
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c Fri Jul 17 17:54:42 2009 -0700
@@ -518,7 +518,7 @@
lsarpc_s_GetConnectedUser(void *arg, ndr_xa_t *mxa)
{
struct mslsa_GetConnectedUser *param = arg;
- smb_opipe_context_t *ctx = &mxa->pipe->np_ctx;
+ smb_netuserinfo_t *user = &mxa->pipe->np_user;
DWORD status = NT_STATUS_SUCCESS;
smb_domain_t di;
int rc1;
@@ -546,8 +546,9 @@
return (NDR_DRC_OK);
}
- rc1 = NDR_MSTRING(mxa, ctx->oc_account, (ndr_mstring_t *)param->owner);
- rc2 = NDR_MSTRING(mxa, ctx->oc_domain,
+ rc1 = NDR_MSTRING(mxa, user->ui_account,
+ (ndr_mstring_t *)param->owner);
+ rc2 = NDR_MSTRING(mxa, user->ui_domain,
(ndr_mstring_t *)param->domain->name);
if (rc1 == -1 || rc2 == -1)
--- a/usr/src/lib/smbsrv/libmlsvc/common/netr_auth.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/smbsrv/libmlsvc/common/netr_auth.c Fri Jul 17 17:54:42 2009 -0700
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -118,19 +118,27 @@
/*
* netr_open
*
- * Open an anonymous session to the NETLOGON pipe on a domain
- * controller and bind to the NETR RPC interface. We store the
- * remote server's native OS type - we may need it due to
- * differences between versions of Windows.
+ * Open an anonymous session to the NETLOGON pipe on a domain controller
+ * and bind to the NETR RPC interface.
+ *
+ * We store the remote server information, which is used to drive Windows
+ * version specific behavior.
*/
int
netr_open(char *server, char *domain, mlsvc_handle_t *netr_handle)
{
+ srvsvc_server_info_t svinfo;
char *user = smbrdr_ipc_get_user();
+ if (srvsvc_net_server_getinfo(server, domain, &svinfo) < 0)
+ return (-1);
+
if (ndr_rpc_bind(netr_handle, server, domain, user, "NETR") < 0)
return (-1);
+ ndr_rpc_server_setinfo(netr_handle, &svinfo);
+ free(svinfo.sv_name);
+ free(svinfo.sv_comment);
return (0);
}
--- a/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c Fri Jul 17 17:54:42 2009 -0700
@@ -406,7 +406,7 @@
smb_shr_cache_unlock();
/* call kernel to take a hold on the shared file system */
- rc = mlsvc_set_share(SMB_SHROP_ADD, si->shr_path, si->shr_name);
+ rc = smb_kmod_share(si->shr_path, si->shr_name);
if (rc == 0) {
smb_shr_publish(si->shr_name, si->shr_container);
@@ -483,7 +483,7 @@
smb_shr_unpublish(sharename, container);
/* call kernel to release the hold on the shared file system */
- (void) mlsvc_set_share(SMB_SHROP_DELETE, path, sharename);
+ (void) smb_kmod_unshare(path, sharename);
return (NERR_Success);
}
--- a/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_clnt.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_clnt.c Fri Jul 17 17:54:42 2009 -0700
@@ -347,6 +347,52 @@
return (0);
}
+int
+srvsvc_net_server_getinfo(char *server, char *domain,
+ srvsvc_server_info_t *svinfo)
+{
+ mlsvc_handle_t handle;
+ struct mslm_NetServerGetInfo arg;
+ struct mslm_SERVER_INFO_101 *sv101;
+ int len, opnum, rc;
+ char *user = smbrdr_ipc_get_user();
+
+ if (srvsvc_open(server, domain, user, &handle) != 0)
+ return (-1);
+
+ opnum = SRVSVC_OPNUM_NetServerGetInfo;
+ bzero(&arg, sizeof (arg));
+
+ len = strlen(server) + 4;
+ arg.servername = ndr_rpc_malloc(&handle, len);
+ if (arg.servername == NULL)
+ return (-1);
+
+ (void) snprintf((char *)arg.servername, len, "\\\\%s", server);
+ arg.level = 101;
+
+ rc = ndr_rpc_call(&handle, opnum, &arg);
+ if ((rc != 0) || (arg.status != 0)) {
+ srvsvc_close(&handle);
+ return (-1);
+ }
+
+ sv101 = arg.result.bufptr.bufptr101;
+
+ bzero(svinfo, sizeof (srvsvc_server_info_t));
+ svinfo->sv_platform_id = sv101->sv101_platform_id;
+ svinfo->sv_version_major = sv101->sv101_version_major;
+ svinfo->sv_version_minor = sv101->sv101_version_minor;
+ svinfo->sv_type = sv101->sv101_type;
+ if (sv101->sv101_name)
+ svinfo->sv_name = strdup((char *)sv101->sv101_name);
+ if (sv101->sv101_comment)
+ svinfo->sv_comment = strdup((char *)sv101->sv101_comment);
+
+ srvsvc_close(&handle);
+ return (0);
+}
+
/*
* Synchronize the local system clock with the domain controller.
*/
@@ -490,6 +536,7 @@
srvsvc_net_test(char *server, char *domain, char *netname)
{
smb_domain_t di;
+ srvsvc_server_info_t svinfo;
(void) smb_tracef("%s %s %s", server, domain, netname);
@@ -498,6 +545,17 @@
domain = di.d_info.di_nbname;
}
+ if (srvsvc_net_server_getinfo(server, domain, &svinfo) == 0) {
+ smb_tracef("NetServerGetInfo: %s %s (%d.%d) id=%d type=0x%08x",
+ svinfo.sv_name ? svinfo.sv_name : "NULL",
+ svinfo.sv_comment ? svinfo.sv_comment : "NULL",
+ svinfo.sv_version_major, svinfo.sv_version_minor,
+ svinfo.sv_platform_id, svinfo.sv_type);
+
+ free(svinfo.sv_name);
+ free(svinfo.sv_comment);
+ }
+
(void) srvsvc_net_share_get_info(server, domain, netname);
#if 0
/*
--- a/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c Fri Jul 17 17:54:42 2009 -0700
@@ -65,26 +65,8 @@
#define SRVSVC_CONNECT_ENUM_SHARE 1
#define SRVSVC_CONNECT_ENUM_WKSTN 2
-#define SMB_SRVSVC_MAXBUFLEN (8 * 1024 * 1024)
-#define SMB_SRVSVC_MAXPREFLEN ((uint32_t)(-1))
-
-/*
- * prefmaxlen: Client specified response buffer limit.
- * resume_handle: Cookie used to track enumeration across multiple calls.
- * n_total: Total number of entries.
- * n_enum: Number of entries to enumerate (derived from prefmaxlen).
- * n_skip: Number of entries to skip (from incoming resume handle).
- * n_read: Number of objects returned for current enumeration request.
- */
-typedef struct srvsvc_enum {
- uint32_t se_level;
- uint32_t se_prefmaxlen;
- uint32_t se_resume_handle;
- uint32_t se_n_total;
- uint32_t se_n_enum;
- uint32_t se_n_skip;
- uint32_t se_n_read;
-} srvsvc_enum_t;
+#define SMB_SRVSVC_MAXBUFLEN (8 * 1024 * 1024)
+#define SMB_SRVSVC_MAXPREFLEN ((uint32_t)(-1))
typedef struct srvsvc_sd {
uint8_t *sd_buf;
@@ -112,46 +94,45 @@
struct mslm_NetShareInfo_1501 nsg_info1501;
} srvsvc_netshare_getinfo_t;
-static DWORD srvsvc_s_NetConnectEnumLevel0(ndr_xa_t *,
- srvsvc_NetConnectInfo0_t *);
-static DWORD srvsvc_s_NetConnectEnumLevel1(ndr_xa_t *,
- srvsvc_NetConnectInfo1_t *);
-
-static DWORD srvsvc_NetFileEnum2(ndr_xa_t *,
- struct mslm_NetFileEnum *);
-static DWORD srvsvc_NetFileEnum3(ndr_xa_t *,
- struct mslm_NetFileEnum *);
-
-static DWORD mlsvc_NetSessionEnumLevel0(struct mslm_infonres *, DWORD,
- ndr_xa_t *);
-static DWORD mlsvc_NetSessionEnumLevel1(struct mslm_infonres *, DWORD,
- ndr_xa_t *);
-static DWORD mlsvc_NetSessionEnumLevel2(struct mslm_infonres *, DWORD,
- ndr_xa_t *);
-static DWORD mlsvc_NetSessionEnumLevel10(struct mslm_infonres *, DWORD,
- ndr_xa_t *);
-static DWORD mlsvc_NetSessionEnumLevel502(struct mslm_infonres *, DWORD,
- ndr_xa_t *);
-
-static DWORD mlsvc_NetShareEnumLevel0(ndr_xa_t *,
- struct mslm_infonres *, srvsvc_enum_t *, int);
-static DWORD mlsvc_NetShareEnumLevel1(ndr_xa_t *,
- struct mslm_infonres *, srvsvc_enum_t *, int);
-static DWORD mlsvc_NetShareEnumLevel2(ndr_xa_t *,
- struct mslm_infonres *, srvsvc_enum_t *, int);
-static DWORD mlsvc_NetShareEnumLevel501(ndr_xa_t *,
- struct mslm_infonres *, srvsvc_enum_t *, int);
-static DWORD mlsvc_NetShareEnumLevel502(ndr_xa_t *,
- struct mslm_infonres *, srvsvc_enum_t *, int);
-static DWORD mlsvc_NetShareEnumCommon(ndr_xa_t *,
- srvsvc_enum_t *, smb_share_t *, void *);
-static boolean_t srvsvc_add_autohome(ndr_xa_t *, srvsvc_enum_t *,
- void *);
+typedef struct mslm_infonres srvsvc_infonres_t;
+typedef struct mslm_NetConnectEnum srvsvc_NetConnectEnum_t;
+
+static uint32_t srvsvc_netconnectenum_level0(ndr_xa_t *, smb_svcenum_t *,
+ srvsvc_NetConnectEnum_t *);
+static uint32_t srvsvc_netconnectenum_level1(ndr_xa_t *, smb_svcenum_t *,
+ srvsvc_NetConnectEnum_t *);
+static uint32_t srvsvc_netconnectenum_common(ndr_xa_t *,
+ srvsvc_NetConnectInfo_t *, smb_netsvc_t *, smb_svcenum_t *);
+
+static DWORD srvsvc_NetFileEnum2(ndr_xa_t *, struct mslm_NetFileEnum *,
+ smb_svcenum_t *se);
+static DWORD srvsvc_NetFileEnum3(ndr_xa_t *, struct mslm_NetFileEnum *,
+ smb_svcenum_t *se);
+
+static uint32_t srvsvc_NetSessionEnumCommon(ndr_xa_t *, srvsvc_infonres_t *,
+ smb_netsvc_t *, smb_svcenum_t *);
+
+static DWORD mlsvc_NetShareEnumLevel0(ndr_xa_t *, srvsvc_infonres_t *,
+ smb_svcenum_t *, int);
+static DWORD mlsvc_NetShareEnumLevel1(ndr_xa_t *, srvsvc_infonres_t *,
+ smb_svcenum_t *, int);
+static DWORD mlsvc_NetShareEnumLevel2(ndr_xa_t *, srvsvc_infonres_t *,
+ smb_svcenum_t *, int);
+static DWORD mlsvc_NetShareEnumLevel501(ndr_xa_t *, srvsvc_infonres_t *,
+ smb_svcenum_t *, int);
+static DWORD mlsvc_NetShareEnumLevel502(ndr_xa_t *, srvsvc_infonres_t *,
+ smb_svcenum_t *, int);
+static DWORD mlsvc_NetShareEnumCommon(ndr_xa_t *, smb_svcenum_t *,
+ smb_share_t *, void *);
+static boolean_t srvsvc_add_autohome(ndr_xa_t *, smb_svcenum_t *, void *);
static char *srvsvc_share_mkpath(ndr_xa_t *, char *);
static uint32_t srvsvc_share_getsd(ndr_xa_t *, smb_share_t *, srvsvc_sd_t *);
static int srvsvc_netconnect_qualifier(const char *);
-static uint32_t srvsvc_estimate_objcnt(uint32_t, uint32_t, uint32_t);
+static void srvsvc_estimate_limit(smb_svcenum_t *, uint32_t);
+static uint32_t srvsvc_open_sessions(void);
+static uint32_t srvsvc_open_connections(uint32_t, const char *);
+static uint32_t srvsvc_open_files(void);
static uint32_t srvsvc_modify_share(smb_share_t *,
srvsvc_netshare_setinfo_t *);
@@ -224,112 +205,222 @@
static int
srvsvc_s_NetConnectEnum(void *arg, ndr_xa_t *mxa)
{
- struct mslm_NetConnectEnum *param = arg;
- srvsvc_NetConnectInfo0_t *info0;
- srvsvc_NetConnectInfo1_t *info1;
- char *qualifier;
- int qualtype;
- DWORD status = ERROR_SUCCESS;
+ srvsvc_NetConnectEnum_t *param = arg;
+ smb_netsvc_t *ns;
+ smb_svcenum_t se;
+ char *qualifier;
+ int qualtype;
+ DWORD status = ERROR_SUCCESS;
if (!ndr_is_poweruser(mxa)) {
- bzero(param, sizeof (struct mslm_NetConnectEnum));
- param->status = ERROR_ACCESS_DENIED;
- return (NDR_DRC_OK);
+ status = ERROR_ACCESS_DENIED;
+ goto srvsvc_netconnectenum_error;
}
qualifier = (char *)param->qualifier;
qualtype = srvsvc_netconnect_qualifier(qualifier);
-
if (qualtype == SRVSVC_CONNECT_ENUM_NULL) {
- bzero(param, sizeof (struct mslm_NetConnectEnum));
- param->status = NERR_NetNameNotFound;
+ status = NERR_NetNameNotFound;
+ goto srvsvc_netconnectenum_error;
+ }
+
+ param->total_entries = srvsvc_open_connections(qualtype, qualifier);
+ if (param->total_entries == 0) {
+ bzero(param, sizeof (srvsvc_NetConnectEnum_t));
+ param->status = ERROR_SUCCESS;
return (NDR_DRC_OK);
}
+ bzero(&se, sizeof (smb_svcenum_t));
+ se.se_type = SMB_SVCENUM_TYPE_TREE;
+ se.se_level = param->info.level;
+ se.se_ntotal = param->total_entries;
+ se.se_nlimit = se.se_ntotal;
+
+ if (param->pref_max_len == SMB_SRVSVC_MAXPREFLEN ||
+ param->pref_max_len > SMB_SRVSVC_MAXBUFLEN)
+ se.se_prefmaxlen = SMB_SRVSVC_MAXBUFLEN;
+ else
+ se.se_prefmaxlen = param->pref_max_len;
+
+ if (param->resume_handle) {
+ se.se_resume = *param->resume_handle;
+ se.se_nskip = se.se_resume;
+ *param->resume_handle = 0;
+ }
+
switch (param->info.level) {
case 0:
- info0 = NDR_NEW(mxa, srvsvc_NetConnectInfo0_t);
- if (info0 == NULL) {
- status = ERROR_NOT_ENOUGH_MEMORY;
- break;
- }
-
- bzero(info0, sizeof (srvsvc_NetConnectInfo0_t));
- param->info.ru.info0 = info0;
-
- status = srvsvc_s_NetConnectEnumLevel0(mxa, info0);
-
- param->total_entries = info0->entries_read;
- param->resume_handle = NULL;
+ status = srvsvc_netconnectenum_level0(mxa, &se, param);
break;
-
case 1:
- info1 = NDR_NEW(mxa, srvsvc_NetConnectInfo1_t);
- if (info1 == NULL) {
- status = ERROR_NOT_ENOUGH_MEMORY;
- break;
- }
-
- bzero(info1, sizeof (srvsvc_NetConnectInfo1_t));
- param->info.ru.info1 = info1;
-
- status = srvsvc_s_NetConnectEnumLevel1(mxa, info1);
-
- param->total_entries = info1->entries_read;
- param->resume_handle = NULL;
+ status = srvsvc_netconnectenum_level1(mxa, &se, param);
break;
-
case 50:
status = ERROR_NOT_SUPPORTED;
break;
-
default:
status = ERROR_INVALID_LEVEL;
break;
}
if (status != ERROR_SUCCESS)
- bzero(param, sizeof (struct mslm_NetConnectEnum));
-
+ goto srvsvc_netconnectenum_error;
+
+ if ((ns = smb_kmod_enum_init(&se)) == NULL) {
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ goto srvsvc_netconnectenum_error;
+ }
+
+ status = srvsvc_netconnectenum_common(mxa, ¶m->info, ns, &se);
+ smb_kmod_enum_fini(ns);
+
+ if (status != ERROR_SUCCESS)
+ goto srvsvc_netconnectenum_error;
+
+ if (param->resume_handle &&
+ param->pref_max_len != SMB_SRVSVC_MAXPREFLEN) {
+ if (se.se_resume < param->total_entries) {
+ *param->resume_handle = se.se_resume;
+ status = ERROR_MORE_DATA;
+ }
+ }
+
+ param->status = status;
+ return (NDR_DRC_OK);
+
+srvsvc_netconnectenum_error:
+ bzero(param, sizeof (srvsvc_NetConnectEnum_t));
param->status = status;
return (NDR_DRC_OK);
}
-static DWORD
-srvsvc_s_NetConnectEnumLevel0(ndr_xa_t *mxa, srvsvc_NetConnectInfo0_t *info0)
+/*
+ * Allocate memory and estimate the number of objects that can
+ * be returned for NetConnectEnum level 0.
+ */
+static uint32_t
+srvsvc_netconnectenum_level0(ndr_xa_t *mxa, smb_svcenum_t *se,
+ srvsvc_NetConnectEnum_t *param)
{
- srvsvc_NetConnectInfoBuf0_t *ci0;
-
- ci0 = NDR_NEW(mxa, srvsvc_NetConnectInfoBuf0_t);
+ srvsvc_NetConnectInfo0_t *info0;
+ srvsvc_NetConnectInfoBuf0_t *ci0;
+
+ if ((info0 = NDR_NEW(mxa, srvsvc_NetConnectInfo0_t)) == NULL)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+
+ bzero(info0, sizeof (srvsvc_NetConnectInfo0_t));
+ param->info.ru.info0 = info0;
+
+ srvsvc_estimate_limit(se, sizeof (srvsvc_NetConnectInfoBuf0_t));
+ if (se->se_nlimit == 0)
+ return (NERR_BufTooSmall);
+
+ do {
+ ci0 = NDR_NEWN(mxa, srvsvc_NetConnectInfoBuf0_t, se->se_nlimit);
+ if (ci0 == NULL)
+ se->se_nlimit >>= 1;
+ } while ((se->se_nlimit > 0) && (ci0 == NULL));
+
if (ci0 == NULL)
return (ERROR_NOT_ENOUGH_MEMORY);
- ci0->coni0_id = 0x17;
-
info0->ci0 = ci0;
- info0->entries_read = 1;
+ info0->entries_read = 0;
return (ERROR_SUCCESS);
}
-static DWORD
-srvsvc_s_NetConnectEnumLevel1(ndr_xa_t *mxa, srvsvc_NetConnectInfo1_t *info1)
+/*
+ * Allocate memory and estimate the number of objects that can
+ * be returned for NetConnectEnum level 1.
+ */
+static uint32_t
+srvsvc_netconnectenum_level1(ndr_xa_t *mxa, smb_svcenum_t *se,
+ srvsvc_NetConnectEnum_t *param)
{
- srvsvc_NetConnectInfoBuf1_t *ci1;
-
- ci1 = NDR_NEW(mxa, srvsvc_NetConnectInfoBuf1_t);
+ srvsvc_NetConnectInfo1_t *info1;
+ srvsvc_NetConnectInfoBuf1_t *ci1;
+
+ if ((info1 = NDR_NEW(mxa, srvsvc_NetConnectInfo1_t)) == NULL)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+
+ bzero(info1, sizeof (srvsvc_NetConnectInfo1_t));
+ param->info.ru.info1 = info1;
+
+ srvsvc_estimate_limit(se,
+ sizeof (srvsvc_NetConnectInfoBuf1_t) + MAXNAMELEN);
+ if (se->se_nlimit == 0)
+ return (NERR_BufTooSmall);
+
+ do {
+ ci1 = NDR_NEWN(mxa, srvsvc_NetConnectInfoBuf1_t, se->se_nlimit);
+ if (ci1 == NULL)
+ se->se_nlimit >>= 1;
+ } while ((se->se_nlimit > 0) && (ci1 == NULL));
+
if (ci1 == NULL)
return (ERROR_NOT_ENOUGH_MEMORY);
- ci1->coni1_id = 0x17;
- ci1->coni1_type = STYPE_IPC;
- ci1->coni1_num_opens = 1;
- ci1->coni1_num_users = 1;
- ci1->coni1_time = 16;
- ci1->coni1_username = (uint8_t *)NDR_STRDUP(mxa, "Administrator");
- ci1->coni1_netname = (uint8_t *)NDR_STRDUP(mxa, "IPC$");
-
info1->ci1 = ci1;
- info1->entries_read = 1;
+ info1->entries_read = 0;
+ return (ERROR_SUCCESS);
+}
+
+/*
+ * Request a list of connections from the kernel and set up
+ * the connection information to be returned to the client.
+ */
+static uint32_t
+srvsvc_netconnectenum_common(ndr_xa_t *mxa, srvsvc_NetConnectInfo_t *info,
+ smb_netsvc_t *ns, smb_svcenum_t *se)
+{
+ srvsvc_NetConnectInfo0_t *info0;
+ srvsvc_NetConnectInfo1_t *info1;
+ srvsvc_NetConnectInfoBuf0_t *ci0;
+ srvsvc_NetConnectInfoBuf1_t *ci1;
+ smb_netsvcitem_t *item;
+ smb_netconnectinfo_t *tree;
+
+ if (smb_kmod_enum(ns) != 0)
+ return (ERROR_INTERNAL_ERROR);
+
+ info0 = info->ru.info0;
+ ci0 = info0->ci0;
+
+ info1 = info->ru.info1;
+ ci1 = info1->ci1;
+
+ item = list_head(&ns->ns_list);
+ while (item != NULL) {
+ tree = &item->nsi_un.nsi_tree;
+
+ switch (se->se_level) {
+ case 0:
+ ci0->coni0_id = tree->ci_id;
+ ++ci0;
+ ++info0->entries_read;
+ break;
+ case 1:
+ ci1->coni1_id = tree->ci_id;
+ ci1->coni1_type = tree->ci_type;
+ ci1->coni1_num_opens = tree->ci_numopens;
+ ci1->coni1_num_users = tree->ci_numusers;
+ ci1->coni1_time = tree->ci_time;
+ ci1->coni1_username = (uint8_t *)
+ NDR_STRDUP(mxa, tree->ci_username);
+ ci1->coni1_netname = (uint8_t *)
+ NDR_STRDUP(mxa, tree->ci_share);
+ ++ci1;
+ ++info1->entries_read;
+ break;
+ default:
+ return (ERROR_INVALID_LEVEL);
+ }
+
+ ++se->se_resume;
+ item = list_next(&ns->ns_list, item);
+ }
+
return (ERROR_SUCCESS);
}
@@ -361,6 +452,45 @@
}
}
+static uint32_t
+srvsvc_open_sessions(void)
+{
+ smb_opennum_t opennum;
+
+ bzero(&opennum, sizeof (smb_opennum_t));
+ if (smb_kmod_get_open_num(&opennum) != 0)
+ return (0);
+
+ return (opennum.open_users);
+}
+
+static uint32_t
+srvsvc_open_connections(uint32_t qualtype, const char *qualifier)
+{
+ smb_opennum_t opennum;
+
+ bzero(&opennum, sizeof (smb_opennum_t));
+ opennum.qualtype = qualtype;
+ (void) strlcpy(opennum.qualifier, qualifier, MAXNAMELEN);
+
+ if (smb_kmod_get_open_num(&opennum) != 0)
+ return (0);
+
+ return (opennum.open_trees);
+}
+
+static uint32_t
+srvsvc_open_files(void)
+{
+ smb_opennum_t opennum;
+
+ bzero(&opennum, sizeof (smb_opennum_t));
+ if (smb_kmod_get_open_num(&opennum) != 0)
+ return (0);
+
+ return (opennum.open_files);
+}
+
/*
* srvsvc_s_NetFileEnum
*
@@ -416,8 +546,9 @@
static int
srvsvc_s_NetFileEnum(void *arg, ndr_xa_t *mxa)
{
- struct mslm_NetFileEnum *param = arg;
- DWORD status;
+ struct mslm_NetFileEnum *param = arg;
+ smb_svcenum_t se;
+ DWORD status;
if (!ndr_is_admin(mxa)) {
bzero(param, sizeof (struct mslm_NetFileEnum));
@@ -425,13 +556,37 @@
return (NDR_DRC_OK);
}
+ if ((param->total_entries = srvsvc_open_files()) == 0) {
+ bzero(param, sizeof (struct mslm_NetFileEnum));
+ param->status = ERROR_SUCCESS;
+ return (NDR_DRC_OK);
+ }
+
+ bzero(&se, sizeof (smb_svcenum_t));
+ se.se_type = SMB_SVCENUM_TYPE_FILE;
+ se.se_level = param->info.switch_value;
+ se.se_ntotal = param->total_entries;
+ se.se_nlimit = se.se_ntotal;
+
+ if (param->pref_max_len == SMB_SRVSVC_MAXPREFLEN ||
+ param->pref_max_len > SMB_SRVSVC_MAXBUFLEN)
+ se.se_prefmaxlen = SMB_SRVSVC_MAXBUFLEN;
+ else
+ se.se_prefmaxlen = param->pref_max_len;
+
+ if (param->resume_handle) {
+ se.se_resume = *param->resume_handle;
+ se.se_nskip = se.se_resume;
+ *param->resume_handle = 0;
+ }
+
switch (param->info.switch_value) {
case 2:
- status = srvsvc_NetFileEnum2(mxa, param);
+ status = srvsvc_NetFileEnum2(mxa, param, &se);
break;
case 3:
- status = srvsvc_NetFileEnum3(mxa, param);
+ status = srvsvc_NetFileEnum3(mxa, param, &se);
break;
case 50:
@@ -449,92 +604,144 @@
return (NDR_DRC_OK);
}
- if (param->resume_handle)
- *param->resume_handle = 0;
-
- param->status = ERROR_SUCCESS;
+ if (param->resume_handle &&
+ param->pref_max_len != SMB_SRVSVC_MAXPREFLEN) {
+ if (se.se_resume < param->total_entries) {
+ *param->resume_handle = se.se_resume;
+ status = ERROR_MORE_DATA;
+ }
+ }
+
+ param->status = status;
return (NDR_DRC_OK);
}
/*
* Build level 2 file information.
*
+ * SMB fids are 16-bit values but this interface expects 32-bit file ids.
+ * So we use the uniqid here.
+ *
* On success, the caller expects that the info2, fi2 and entries_read
* fields have been set up.
*/
static DWORD
-srvsvc_NetFileEnum2(ndr_xa_t *mxa, struct mslm_NetFileEnum *param)
+srvsvc_NetFileEnum2(ndr_xa_t *mxa, struct mslm_NetFileEnum *param,
+ smb_svcenum_t *se)
{
- struct mslm_NetFileInfoBuf2 *fi2;
- ndr_pipe_info_t pi;
- uint32_t entries_read = 0;
- int i;
+ struct mslm_NetFileInfoBuf2 *fi2;
+ smb_netsvc_t *ns;
+ smb_netsvcitem_t *item;
+ smb_netfileinfo_t *ofile;
+ uint32_t entries_read = 0;
param->info.ru.info2 = NDR_NEW(mxa, struct mslm_NetFileInfo2);
if (param->info.ru.info2 == NULL)
return (ERROR_NOT_ENOUGH_MEMORY);
- fi2 = NDR_NEWN(mxa, struct mslm_NetFileInfoBuf2, 128);
+ srvsvc_estimate_limit(se, sizeof (struct mslm_NetFileInfoBuf2));
+ if (se->se_nlimit == 0)
+ return (NERR_BufTooSmall);
+
+ do {
+ fi2 = NDR_NEWN(mxa, struct mslm_NetFileInfoBuf2, se->se_nlimit);
+ if (fi2 == NULL)
+ se->se_nlimit >>= 1;
+ } while ((se->se_nlimit > 0) && (fi2 == NULL));
+
if (fi2 == NULL)
return (ERROR_NOT_ENOUGH_MEMORY);
param->info.ru.info2->fi2 = fi2;
- for (i = 0; i < 128; ++i) {
- if (ndr_pipe_getinfo(i, &pi) == -1)
- continue;
-
- fi2->fi2_id = pi.npi_fid;
+ if ((ns = smb_kmod_enum_init(se)) == NULL)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+
+ if (smb_kmod_enum(ns) != 0) {
+ smb_kmod_enum_fini(ns);
+ return (ERROR_INTERNAL_ERROR);
+ }
+
+ item = list_head(&ns->ns_list);
+ while (item != NULL) {
+ ofile = &item->nsi_un.nsi_ofile;
+ fi2->fi2_id = ofile->fi_uniqid;
++entries_read;
++fi2;
+ item = list_next(&ns->ns_list, item);
}
+ se->se_resume += entries_read;
param->info.ru.info2->entries_read = entries_read;
- param->total_entries = entries_read;
+ smb_kmod_enum_fini(ns);
return (ERROR_SUCCESS);
}
/*
* Build level 3 file information.
*
+ * SMB fids are 16-bit values but this interface expects 32-bit file ids.
+ * So we use the uniqid here.
+ *
* On success, the caller expects that the info3, fi3 and entries_read
* fields have been set up.
*/
static DWORD
-srvsvc_NetFileEnum3(ndr_xa_t *mxa, struct mslm_NetFileEnum *param)
+srvsvc_NetFileEnum3(ndr_xa_t *mxa, struct mslm_NetFileEnum *param,
+ smb_svcenum_t *se)
{
- struct mslm_NetFileInfoBuf3 *fi3;
- ndr_pipe_info_t pi;
- uint32_t entries_read = 0;
- int i;
+ struct mslm_NetFileInfoBuf3 *fi3;
+ smb_netsvc_t *ns;
+ smb_netsvcitem_t *item;
+ smb_netfileinfo_t *ofile;
+ uint32_t entries_read = 0;
param->info.ru.info3 = NDR_NEW(mxa, struct mslm_NetFileInfo3);
if (param->info.ru.info3 == NULL)
return (ERROR_NOT_ENOUGH_MEMORY);
- fi3 = NDR_NEWN(mxa, struct mslm_NetFileInfoBuf3, 128);
+ srvsvc_estimate_limit(se,
+ sizeof (struct mslm_NetFileInfoBuf3) + MAXNAMELEN);
+ if (se->se_nlimit == 0)
+ return (NERR_BufTooSmall);
+
+ do {
+ fi3 = NDR_NEWN(mxa, struct mslm_NetFileInfoBuf3, se->se_nlimit);
+ if (fi3 == NULL)
+ se->se_nlimit >>= 1;
+ } while ((se->se_nlimit > 0) && (fi3 == NULL));
+
if (fi3 == NULL)
return (ERROR_NOT_ENOUGH_MEMORY);
param->info.ru.info3->fi3 = fi3;
- for (i = 0; i < 128; ++i) {
- if (ndr_pipe_getinfo(i, &pi) == -1)
- continue;
-
- fi3->fi3_id = pi.npi_fid;
- fi3->fi3_permissions = pi.npi_permissions;
- fi3->fi3_num_locks = pi.npi_num_locks;
+ if ((ns = smb_kmod_enum_init(se)) == NULL)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+
+ if (smb_kmod_enum(ns) != 0) {
+ smb_kmod_enum_fini(ns);
+ return (ERROR_INTERNAL_ERROR);
+ }
+
+ item = list_head(&ns->ns_list);
+ while (item != NULL) {
+ ofile = &item->nsi_un.nsi_ofile;
+ fi3->fi3_id = ofile->fi_uniqid;
+ fi3->fi3_permissions = ofile->fi_permissions;
+ fi3->fi3_num_locks = ofile->fi_numlocks;
fi3->fi3_pathname = (uint8_t *)
- NDR_STRDUP(mxa, pi.npi_pathname);
+ NDR_STRDUP(mxa, ofile->fi_path);
fi3->fi3_username = (uint8_t *)
- NDR_STRDUP(mxa, pi.npi_username);
+ NDR_STRDUP(mxa, ofile->fi_username);
++entries_read;
++fi3;
+ item = list_next(&ns->ns_list, item);
}
+ se->se_resume += entries_read;
param->info.ru.info3->entries_read = entries_read;
param->total_entries = entries_read;
return (ERROR_SUCCESS);
@@ -544,32 +751,56 @@
* srvsvc_s_NetFileClose
*
* NetFileClose forces a file to close. This function can be used when
- * an error prevents closure by any other means. Use NetFileClose with
+ * an error prevents closure by other means. Use NetFileClose with
* caution because it does not flush data, cached on a client, to the
* file before closing the file.
*
+ * SMB fids are 16-bit values but this interface expects 32-bit file ids.
+ * So we use the uniqid here.
+ *
* Return Values
* ERROR_SUCCESS Operation succeeded.
* ERROR_ACCESS_DENIED Operation denied.
* NERR_FileIdNotFound No open file with the specified id.
*
- * Note: MSDN suggests that the error code should be ERROR_FILE_NOT_FOUND
- * but network captures using NT show NERR_FileIdNotFound.
- * The NetFileClose2 MSDN page has the right error code.
+ * Note: MSDN suggests ERROR_FILE_NOT_FOUND for NetFileClose but network
+ * captures using NT show NERR_FileIdNotFound, which is consistent with
+ * the NetFileClose2 page on MSDN.
*/
static int
srvsvc_s_NetFileClose(void *arg, ndr_xa_t *mxa)
{
+ static struct {
+ int errnum;
+ int nerr;
+ } errmap[] = {
+ 0, ERROR_SUCCESS,
+ EACCES, ERROR_ACCESS_DENIED,
+ EPERM, ERROR_ACCESS_DENIED,
+ EINVAL, ERROR_INVALID_PARAMETER,
+ ENOMEM, ERROR_NOT_ENOUGH_MEMORY,
+ ENOENT, NERR_FileIdNotFound
+ };
+
struct mslm_NetFileClose *param = arg;
+ int i;
+ int rc;
if (!ndr_is_admin(mxa)) {
- bzero(param, sizeof (struct mslm_NetFileClose));
param->status = ERROR_ACCESS_DENIED;
return (NDR_DRC_OK);
}
- bzero(param, sizeof (struct mslm_NetFileClose));
- param->status = ERROR_SUCCESS;
+ rc = smb_kmod_file_close(param->file_id);
+
+ for (i = 0; i < (sizeof (errmap) / sizeof (errmap[0])); ++i) {
+ if (rc == errmap[i].errnum) {
+ param->status = errmap[i].nerr;
+ return (NDR_DRC_OK);
+ }
+ }
+
+ param->status = ERROR_INTERNAL_ERROR;
return (NDR_DRC_OK);
}
@@ -1059,393 +1290,222 @@
static int
srvsvc_s_NetSessionEnum(void *arg, ndr_xa_t *mxa)
{
- struct mslm_NetSessionEnum *param = arg;
- struct mslm_infonres *infonres;
- DWORD status;
- DWORD n_sessions;
-
- infonres = NDR_NEW(mxa, struct mslm_infonres);
- if (infonres == NULL) {
- bzero(param, sizeof (struct mslm_NetSessionEnum));
- param->status = ERROR_NOT_ENOUGH_MEMORY;
+ struct mslm_NetSessionEnum *param = arg;
+ srvsvc_infonres_t *info;
+ smb_netsvc_t *ns;
+ smb_svcenum_t se;
+ DWORD status = ERROR_SUCCESS;
+
+ if (!ndr_is_admin(mxa)) {
+ status = ERROR_ACCESS_DENIED;
+ goto srvsvc_netsessionenum_error;
+ }
+
+ if ((info = NDR_NEW(mxa, srvsvc_infonres_t)) == NULL) {
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ goto srvsvc_netsessionenum_error;
+ }
+
+ info->entriesread = 0;
+ info->entries = NULL;
+ param->result.level = param->level;
+ param->result.bufptr.p = info;
+
+ if ((param->total_entries = srvsvc_open_sessions()) == 0) {
+ param->resume_handle = NULL;
+ param->status = ERROR_SUCCESS;
return (NDR_DRC_OK);
}
- infonres->entriesread = 0;
- infonres->entries = NULL;
- param->result.level = param->level;
- param->result.bufptr.p = infonres;
- param->total_entries = 0;
- param->resume_handle = NULL;
- param->status = ERROR_SUCCESS;
-
- if ((n_sessions = (DWORD) mlsvc_get_num_users()) == 0)
- return (NDR_DRC_OK);
+ bzero(&se, sizeof (smb_svcenum_t));
+ se.se_type = SMB_SVCENUM_TYPE_USER;
+ se.se_level = param->level;
+ se.se_ntotal = param->total_entries;
+ se.se_nlimit = se.se_ntotal;
+
+ if (param->resume_handle) {
+ se.se_resume = *param->resume_handle;
+ se.se_nskip = se.se_resume;
+ *param->resume_handle = 0;
+ }
switch (param->level) {
case 0:
- status = mlsvc_NetSessionEnumLevel0(infonres, n_sessions, mxa);
- break;
-
- case 1:
- status = mlsvc_NetSessionEnumLevel1(infonres, n_sessions, mxa);
+ info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_0,
+ se.se_nlimit);
break;
-
- case 2:
- status = mlsvc_NetSessionEnumLevel2(infonres, n_sessions, mxa);
+ case 1:
+ info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_1,
+ se.se_nlimit);
break;
-
- case 10:
- status = mlsvc_NetSessionEnumLevel10(infonres, n_sessions, mxa);
+ case 2:
+ info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_2,
+ se.se_nlimit);
break;
-
+ case 10:
+ info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_10,
+ se.se_nlimit);
+ break;
case 502:
- status = mlsvc_NetSessionEnumLevel502(infonres, n_sessions,
- mxa);
+ info->entries = NDR_NEWN(mxa, struct mslm_SESSION_INFO_502,
+ se.se_nlimit);
break;
-
default:
- status = ERROR_INVALID_LEVEL;
- break;
- }
-
- if (status != 0) {
bzero(param, sizeof (struct mslm_NetSessionEnum));
- param->status = status;
+ param->status = ERROR_INVALID_LEVEL;
return (NDR_DRC_OK);
}
- param->total_entries = infonres->entriesread;
+ if (info->entries == NULL) {
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ goto srvsvc_netsessionenum_error;
+ }
+
+ if ((ns = smb_kmod_enum_init(&se)) == NULL) {
+ status = ERROR_NOT_ENOUGH_MEMORY;
+ goto srvsvc_netsessionenum_error;
+ }
+
+ status = srvsvc_NetSessionEnumCommon(mxa, info, ns, &se);
+ smb_kmod_enum_fini(ns);
+
+ if (status != ERROR_SUCCESS)
+ goto srvsvc_netsessionenum_error;
+
+ if (param->resume_handle &&
+ param->pref_max_len != SMB_SRVSVC_MAXPREFLEN) {
+ if (se.se_resume < param->total_entries) {
+ *param->resume_handle = se.se_resume;
+ status = ERROR_MORE_DATA;
+ }
+ }
+
+ param->total_entries = info->entriesread;
+ param->status = status;
+ return (NDR_DRC_OK);
+
+srvsvc_netsessionenum_error:
+ bzero(param, sizeof (struct mslm_NetSessionEnum));
param->status = status;
return (NDR_DRC_OK);
}
-/*
- * mlsvc_NetSessionEnumLevel0
- *
- * Build the level 0 session information.
- */
-static DWORD
-mlsvc_NetSessionEnumLevel0(struct mslm_infonres *infonres, DWORD n_sessions,
- ndr_xa_t *mxa)
+static uint32_t
+srvsvc_NetSessionEnumCommon(ndr_xa_t *mxa, srvsvc_infonres_t *info,
+ smb_netsvc_t *ns, smb_svcenum_t *se)
{
- struct mslm_SESSION_INFO_0 *info0;
- smb_ulist_t *ulist;
- smb_opipe_context_t *user;
- char *workstation;
- char ipaddr_buf[INET6_ADDRSTRLEN];
- int i;
-
- ulist = smb_ulist_alloc();
- if (ulist == NULL)
- return (ERROR_NOT_ENOUGH_MEMORY);
-
- if (mlsvc_get_user_list(ulist) != 0) {
- smb_ulist_free(ulist);
- return (ERROR_NOT_ENOUGH_MEMORY);
- }
-
- if (ulist->ul_cnt < n_sessions)
- n_sessions = ulist->ul_cnt;
-
- info0 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_0, n_sessions);
- if (info0 == NULL) {
- smb_ulist_free(ulist);
- return (ERROR_NOT_ENOUGH_MEMORY);
- }
-
- user = ulist->ul_users;
- for (i = 0; i < n_sessions; ++i, user++) {
- workstation = user->oc_workstation;
+ struct mslm_SESSION_INFO_0 *info0 = info->entries;
+ struct mslm_SESSION_INFO_1 *info1 = info->entries;
+ struct mslm_SESSION_INFO_2 *info2 = info->entries;
+ struct mslm_SESSION_INFO_10 *info10 = info->entries;
+ struct mslm_SESSION_INFO_502 *info502 = info->entries;
+ smb_netsvcitem_t *item;
+ smb_netuserinfo_t *user;
+ char *workstation;
+ char account[MAXNAMELEN];
+ char ipaddr_buf[INET6_ADDRSTRLEN];
+ uint32_t logon_time;
+ uint32_t flags;
+ uint32_t entries_read = 0;
+
+ if (smb_kmod_enum(ns) != 0)
+ return (ERROR_INTERNAL_ERROR);
+
+ item = list_head(&ns->ns_list);
+ while (item != NULL) {
+ user = &item->nsi_un.nsi_user;
+
+ workstation = user->ui_workstation;
if (workstation == NULL || *workstation == '\0') {
- (void) smb_inet_ntop(&user->oc_ipaddr,
- ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family));
- workstation = ipaddr_buf;
- }
-
- info0[i].sesi0_cname = NDR_STRDUP(mxa, workstation);
- if (info0[i].sesi0_cname == NULL) {
- smb_ulist_free(ulist);
- return (ERROR_NOT_ENOUGH_MEMORY);
- }
- }
-
- smb_ulist_free(ulist);
- infonres->entriesread = n_sessions;
- infonres->entries = info0;
- return (ERROR_SUCCESS);
-}
-
-/*
- * mlsvc_NetSessionEnumLevel1
- *
- * Build the level 1 session information.
- */
-static DWORD
-mlsvc_NetSessionEnumLevel1(struct mslm_infonres *infonres, DWORD n_sessions,
- ndr_xa_t *mxa)
-{
- struct mslm_SESSION_INFO_1 *info1;
- smb_ulist_t *ulist;
- smb_opipe_context_t *user;
- char *workstation;
- char account[MAXNAMELEN];
- char ipaddr_buf[INET6_ADDRSTRLEN];
- int i;
-
- ulist = smb_ulist_alloc();
- if (ulist == NULL)
- return (ERROR_NOT_ENOUGH_MEMORY);
-
- if (mlsvc_get_user_list(ulist) != 0) {
- smb_ulist_free(ulist);
- return (ERROR_NOT_ENOUGH_MEMORY);
- }
-
- if (ulist->ul_cnt < n_sessions)
- n_sessions = ulist->ul_cnt;
-
- info1 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_1, n_sessions);
- if (info1 == NULL) {
- smb_ulist_free(ulist);
- return (ERROR_NOT_ENOUGH_MEMORY);
- }
-
- user = ulist->ul_users;
- for (i = 0; i < n_sessions; ++i, user++) {
- workstation = user->oc_workstation;
- if (workstation == NULL || *workstation == '\0') {
- (void) smb_inet_ntop(&user->oc_ipaddr,
- ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family));
+ (void) smb_inet_ntop(&user->ui_ipaddr, ipaddr_buf,
+ SMB_IPSTRLEN(user->ui_ipaddr.a_family));
workstation = ipaddr_buf;
}
(void) snprintf(account, MAXNAMELEN, "%s\\%s",
- user->oc_domain, user->oc_account);
-
- info1[i].sesi1_cname = NDR_STRDUP(mxa, workstation);
- info1[i].sesi1_uname = NDR_STRDUP(mxa, account);
-
- if (info1[i].sesi1_cname == NULL ||
- info1[i].sesi1_uname == NULL) {
- smb_ulist_free(ulist);
- return (ERROR_NOT_ENOUGH_MEMORY);
+ user->ui_domain, user->ui_account);
+
+ logon_time = time(0) - user->ui_logon_time;
+ flags = (user->ui_flags & SMB_ATF_GUEST) ? SESS_GUEST : 0;
+
+ switch (se->se_level) {
+ case 0:
+ info0->sesi0_cname = NDR_STRDUP(mxa, workstation);
+ if (info0->sesi0_cname == NULL)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+ ++info0;
+ break;
+
+ case 1:
+ info1->sesi1_cname = NDR_STRDUP(mxa, workstation);
+ info1->sesi1_uname = NDR_STRDUP(mxa, account);
+
+ if (info1->sesi1_cname == NULL ||
+ info1->sesi1_uname == NULL)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+
+ info1->sesi1_nopens = user->ui_numopens;
+ info1->sesi1_time = logon_time;
+ info1->sesi1_itime = 0;
+ info1->sesi1_uflags = flags;
+ ++info1;
+ break;
+
+ case 2:
+ info2->sesi2_cname = NDR_STRDUP(mxa, workstation);
+ info2->sesi2_uname = NDR_STRDUP(mxa, account);
+
+ if (info2->sesi2_cname == NULL ||
+ info2->sesi2_uname == NULL)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+
+ info2->sesi2_nopens = user->ui_numopens;
+ info2->sesi2_time = logon_time;
+ info2->sesi2_itime = 0;
+ info2->sesi2_uflags = flags;
+ info2->sesi2_cltype_name = (uint8_t *)"";
+ ++info2;
+ break;
+
+ case 10:
+ info10->sesi10_cname = NDR_STRDUP(mxa, workstation);
+ info10->sesi10_uname = NDR_STRDUP(mxa, account);
+
+ if (info10->sesi10_cname == NULL ||
+ info10->sesi10_uname == NULL)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+
+ info10->sesi10_time = logon_time;
+ info10->sesi10_itime = 0;
+ ++info10;
+ break;
+
+ case 502:
+ info502->sesi502_cname = NDR_STRDUP(mxa, workstation);
+ info502->sesi502_uname = NDR_STRDUP(mxa, account);
+
+ if (info502->sesi502_cname == NULL ||
+ info502->sesi502_uname == NULL)
+ return (ERROR_NOT_ENOUGH_MEMORY);
+
+ info502->sesi502_nopens = user->ui_numopens;
+ info502->sesi502_time = logon_time;
+ info502->sesi502_itime = 0;
+ info502->sesi502_uflags = flags;
+ info502->sesi502_cltype_name = (uint8_t *)"";
+ info502->sesi502_transport = (uint8_t *)"";
+ ++info502;
+ break;
+
+ default:
+ return (ERROR_INVALID_LEVEL);
}
- info1[i].sesi1_nopens = 1;
- info1[i].sesi1_time = time(0) - user->oc_logon_time;
- info1[i].sesi1_itime = 0;
- info1[i].sesi1_uflags =
- (user->oc_flags & SMB_ATF_GUEST) ? SESS_GUEST : 0;
- }
-
- smb_ulist_free(ulist);
- infonres->entriesread = n_sessions;
- infonres->entries = info1;
- return (ERROR_SUCCESS);
-}
-
-/*
- * mlsvc_NetSessionEnumLevel2
- *
- * Build the level 2 session information.
- */
-static DWORD
-mlsvc_NetSessionEnumLevel2(struct mslm_infonres *infonres, DWORD n_sessions,
- ndr_xa_t *mxa)
-{
- struct mslm_SESSION_INFO_2 *info2;
- smb_ulist_t *ulist;
- smb_opipe_context_t *user;
- char *workstation;
- char account[MAXNAMELEN];
- char ipaddr_buf[INET6_ADDRSTRLEN];
- int i;
-
- if ((ulist = smb_ulist_alloc()) == NULL)
- return (ERROR_NOT_ENOUGH_MEMORY);
-
- if (mlsvc_get_user_list(ulist) != 0) {
- smb_ulist_free(ulist);
- return (ERROR_NOT_ENOUGH_MEMORY);
- }
-
- if (ulist->ul_cnt < n_sessions)
- n_sessions = ulist->ul_cnt;
-
- info2 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_2, n_sessions);
- if (info2 == NULL) {
- smb_ulist_free(ulist);
- return (ERROR_NOT_ENOUGH_MEMORY);
- }
-
- user = ulist->ul_users;
- for (i = 0; i < n_sessions; ++i, user++) {
- workstation = user->oc_workstation;
- if (workstation == NULL || *workstation == '\0') {
- (void) smb_inet_ntop(&user->oc_ipaddr,
- ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family));
- workstation = ipaddr_buf;
- }
-
- (void) snprintf(account, MAXNAMELEN, "%s\\%s",
- user->oc_domain, user->oc_account);
-
- info2[i].sesi2_cname = NDR_STRDUP(mxa, workstation);
- info2[i].sesi2_uname = NDR_STRDUP(mxa, account);
-
- if (info2[i].sesi2_cname == NULL ||
- info2[i].sesi2_uname == NULL) {
- smb_ulist_free(ulist);
- return (ERROR_NOT_ENOUGH_MEMORY);
- }
-
- info2[i].sesi2_nopens = 1;
- info2[i].sesi2_time = time(0) - user->oc_logon_time;
- info2[i].sesi2_itime = 0;
- info2[i].sesi2_uflags =
- (user->oc_flags & SMB_ATF_GUEST) ? SESS_GUEST : 0;
- info2[i].sesi2_cltype_name = (uint8_t *)"";
+ ++entries_read;
+ item = list_next(&ns->ns_list, item);
}
- smb_ulist_free(ulist);
- infonres->entriesread = n_sessions;
- infonres->entries = info2;
- return (ERROR_SUCCESS);
-}
-
-/*
- * mlsvc_NetSessionEnumLevel10
- *
- * Build the level 10 session information.
- */
-static DWORD
-mlsvc_NetSessionEnumLevel10(struct mslm_infonres *infonres, DWORD n_sessions,
- ndr_xa_t *mxa)
-{
- struct mslm_SESSION_INFO_10 *info10;
- smb_ulist_t *ulist;
- smb_opipe_context_t *user;
- char *workstation;
- char account[MAXNAMELEN];
- char ipaddr_buf[INET6_ADDRSTRLEN];
- int i;
-
- if ((ulist = smb_ulist_alloc()) == NULL)
- return (ERROR_NOT_ENOUGH_MEMORY);
-
- if (mlsvc_get_user_list(ulist) != 0) {
- smb_ulist_free(ulist);
- return (ERROR_NOT_ENOUGH_MEMORY);
- }
-
- if (ulist->ul_cnt < n_sessions)
- n_sessions = ulist->ul_cnt;
-
- info10 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_10, n_sessions);
- if (info10 == NULL) {
- smb_ulist_free(ulist);
- return (ERROR_NOT_ENOUGH_MEMORY);
- }
-
- user = ulist->ul_users;
- for (i = 0; i < n_sessions; ++i, user++) {
- workstation = user->oc_workstation;
- if (workstation == NULL || *workstation == '\0') {
- (void) smb_inet_ntop(&user->oc_ipaddr,
- ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family));
- workstation = ipaddr_buf;
- }
-
- (void) snprintf(account, MAXNAMELEN, "%s\\%s",
- user->oc_domain, user->oc_account);
-
- info10[i].sesi10_cname = NDR_STRDUP(mxa, workstation);
- info10[i].sesi10_uname = NDR_STRDUP(mxa, account);
-
- if (info10[i].sesi10_cname == NULL ||
- info10[i].sesi10_uname == NULL) {
- smb_ulist_free(ulist);
- return (ERROR_NOT_ENOUGH_MEMORY);
- }
-
- info10[i].sesi10_time = time(0) - user->oc_logon_time;
- info10[i].sesi10_itime = 0;
- }
-
- smb_ulist_free(ulist);
- infonres->entriesread = n_sessions;
- infonres->entries = info10;
- return (ERROR_SUCCESS);
-}
-
-/*
- * mlsvc_NetSessionEnumLevel502
- *
- * Build the level 502 session information.
- */
-static DWORD
-mlsvc_NetSessionEnumLevel502(struct mslm_infonres *infonres, DWORD n_sessions,
- ndr_xa_t *mxa)
-{
- struct mslm_SESSION_INFO_502 *info502;
- smb_ulist_t *ulist;
- smb_opipe_context_t *user;
- char *workstation;
- char account[MAXNAMELEN];
- char ipaddr_buf[INET6_ADDRSTRLEN];
- int i;
-
- if ((ulist = smb_ulist_alloc()) == NULL)
- return (ERROR_NOT_ENOUGH_MEMORY);
-
- if (mlsvc_get_user_list(ulist) != 0) {
- smb_ulist_free(ulist);
- return (ERROR_NOT_ENOUGH_MEMORY);
- }
-
- if (ulist->ul_cnt < n_sessions)
- n_sessions = ulist->ul_cnt;
-
- info502 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_502, n_sessions);
- if (info502 == NULL) {
- smb_ulist_free(ulist);
- return (ERROR_NOT_ENOUGH_MEMORY);
- }
-
- user = ulist->ul_users;
- for (i = 0; i < n_sessions; ++i, user++) {
- workstation = user->oc_workstation;
- if (workstation == NULL || *workstation == '\0') {
- (void) smb_inet_ntop(&user->oc_ipaddr,
- ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family));
- workstation = ipaddr_buf;
- }
-
- (void) snprintf(account, MAXNAMELEN, "%s\\%s",
- user->oc_domain, user->oc_account);
-
- info502[i].sesi502_cname = NDR_STRDUP(mxa, workstation);
- info502[i].sesi502_uname = NDR_STRDUP(mxa, account);
-
- if (info502[i].sesi502_cname == NULL ||
- info502[i].sesi502_uname == NULL) {
- smb_ulist_free(ulist);
- return (ERROR_NOT_ENOUGH_MEMORY);
- }
-
- info502[i].sesi502_nopens = 1;
- info502[i].sesi502_time = time(0) - user->oc_logon_time;
- info502[i].sesi502_itime = 0;
- info502[i].sesi502_uflags =
- (user->oc_flags & SMB_ATF_GUEST) ? SESS_GUEST : 0;
- info502[i].sesi502_cltype_name = (uint8_t *)"";
- info502[i].sesi502_transport = (uint8_t *)"";
- }
-
- smb_ulist_free(ulist);
- infonres->entriesread = n_sessions;
- infonres->entries = info502;
+ info->entriesread = entries_read;
return (ERROR_SUCCESS);
}
@@ -1456,29 +1516,58 @@
* On NT only members of the Administrators or Account Operators
* local groups are permitted to use NetSessionDel.
*
+ * If unc_clientname is NULL, all sessions associated with the
+ * specified user will be disconnected.
+ *
+ * If username is NULL, all sessions from the specified client
+ * will be disconnected.
+ *
* Return Values
- * If the function succeeds, the return value is NERR_Success/
- * ERROR_SUCCESS. If the function fails, the return value can be
- * one of the following error codes:
+ * On success, the return value is NERR_Success/ERROR_SUCCESS.
+ * On failure, the return value can be one of the following errors:
*
* ERROR_ACCESS_DENIED The user does not have access to the
- * requested information.
+ * requested information.
* ERROR_INVALID_PARAMETER The specified parameter is invalid.
* ERROR_NOT_ENOUGH_MEMORY Insufficient memory is available.
* NERR_ClientNameNotFound A session does not exist with that
- * computer name.
+ * computer name.
*/
static int
srvsvc_s_NetSessionDel(void *arg, ndr_xa_t *mxa)
{
+ static struct {
+ int errnum;
+ int nerr;
+ } errmap[] = {
+ 0, ERROR_SUCCESS,
+ EACCES, ERROR_ACCESS_DENIED,
+ EPERM, ERROR_ACCESS_DENIED,
+ EINVAL, ERROR_INVALID_PARAMETER,
+ ENOMEM, ERROR_NOT_ENOUGH_MEMORY,
+ ENOENT, NERR_ClientNameNotFound
+ };
+
struct mslm_NetSessionDel *param = arg;
-
- if (!ndr_is_poweruser(mxa)) {
+ int i;
+ int rc;
+
+ if (!ndr_is_admin(mxa)) {
param->status = ERROR_ACCESS_DENIED;
return (NDR_DRC_OK);
}
- param->status = ERROR_ACCESS_DENIED;
+ rc = smb_kmod_session_close((char *)param->unc_clientname,
+ (char *)param->username);
+
+ for (i = 0; i < (sizeof (errmap) / sizeof (errmap[0])); ++i) {
+ if (rc == errmap[i].errnum) {
+ param->status = errmap[i].nerr;
+ return (NDR_DRC_OK);
+ }
+ }
+
+ param->status = ERROR_INTERNAL_ERROR;
return (NDR_DRC_OK);
}
@@ -1853,25 +1942,30 @@
}
/*
- * srvsvc_estimate_objcnt
+ * srvsvc_estimate_limit
*
* Estimate the number of objects that will fit in prefmaxlen.
+ * nlimit is adjusted here.
*/
-static uint32_t
-srvsvc_estimate_objcnt(uint32_t prefmaxlen, uint32_t n_obj, uint32_t obj_size)
+static void
+srvsvc_estimate_limit(smb_svcenum_t *se, uint32_t obj_size)
{
DWORD max_cnt;
- if (obj_size == 0)
- return (0);
-
- if ((max_cnt = (prefmaxlen / obj_size)) == 0)
- return (0);
-
- if (n_obj > max_cnt)
- n_obj = max_cnt;
-
- return (n_obj);
+ if (obj_size == 0) {
+ se->se_nlimit = 0;
+ return;
+ }
+
+ if ((max_cnt = (se->se_prefmaxlen / obj_size)) == 0) {
+ se->se_nlimit = 0;
+ return;
+ }
+
+ if (se->se_ntotal > max_cnt)
+ se->se_nlimit = max_cnt;
+ else
+ se->se_nlimit = se->se_ntotal;
}
/*
@@ -1890,11 +1984,11 @@
srvsvc_s_NetShareEnum(void *arg, ndr_xa_t *mxa)
{
struct mslm_NetShareEnum *param = arg;
- struct mslm_infonres *infonres;
- srvsvc_enum_t se;
+ srvsvc_infonres_t *infonres;
+ smb_svcenum_t se;
DWORD status;
- infonres = NDR_NEW(mxa, struct mslm_infonres);
+ infonres = NDR_NEW(mxa, srvsvc_infonres_t);
if (infonres == NULL) {
bzero(param, sizeof (struct mslm_NetShareEnum));
param->status = ERROR_NOT_ENOUGH_MEMORY;
@@ -1906,9 +2000,11 @@
param->result.level = param->level;
param->result.bufptr.p = infonres;
- bzero(&se, sizeof (srvsvc_enum_t));
+ bzero(&se, sizeof (smb_svcenum_t));
+ se.se_type = SMB_SVCENUM_TYPE_SHARE;
se.se_level = param->level;
- se.se_n_total = smb_shr_count();
+ se.se_ntotal = smb_shr_count();
+ se.se_nlimit = se.se_ntotal;
if (param->prefmaxlen == SMB_SRVSVC_MAXPREFLEN ||
param->prefmaxlen > SMB_SRVSVC_MAXBUFLEN)
@@ -1917,8 +2013,9 @@
se.se_prefmaxlen = param->prefmaxlen;
if (param->resume_handle) {
- se.se_resume_handle = *param->resume_handle;
- se.se_n_skip = se.se_resume_handle;
+ se.se_resume = *param->resume_handle;
+ se.se_nskip = se.se_resume;
+ *param->resume_handle = 0;
}
switch (param->level) {
@@ -1953,24 +2050,20 @@
return (NDR_DRC_OK);
}
- if (se.se_n_enum == 0) {
- if (param->resume_handle)
- *param->resume_handle = 0;
+ if (se.se_nlimit == 0) {
param->status = ERROR_SUCCESS;
return (NDR_DRC_OK);
}
if (param->resume_handle &&
param->prefmaxlen != SMB_SRVSVC_MAXPREFLEN) {
- if (se.se_resume_handle < se.se_n_total) {
- *param->resume_handle = se.se_resume_handle;
+ if (se.se_resume < se.se_ntotal) {
+ *param->resume_handle = se.se_resume;
status = ERROR_MORE_DATA;
- } else {
- *param->resume_handle = 0;
}
}
- param->totalentries = se.se_n_total;
+ param->totalentries = se.se_ntotal;
param->status = status;
return (NDR_DRC_OK);
}
@@ -1996,11 +2089,11 @@
srvsvc_s_NetShareEnumSticky(void *arg, ndr_xa_t *mxa)
{
struct mslm_NetShareEnum *param = arg;
- struct mslm_infonres *infonres;
- srvsvc_enum_t se;
+ srvsvc_infonres_t *infonres;
+ smb_svcenum_t se;
DWORD status;
- infonres = NDR_NEW(mxa, struct mslm_infonres);
+ infonres = NDR_NEW(mxa, srvsvc_infonres_t);
if (infonres == NULL) {
bzero(param, sizeof (struct mslm_NetShareEnum));
param->status = ERROR_NOT_ENOUGH_MEMORY;
@@ -2012,9 +2105,11 @@
param->result.level = param->level;
param->result.bufptr.p = infonres;
- bzero(&se, sizeof (srvsvc_enum_t));
+ bzero(&se, sizeof (smb_svcenum_t));
+ se.se_type = SMB_SVCENUM_TYPE_SHARE;
se.se_level = param->level;
- se.se_n_total = smb_shr_count();
+ se.se_ntotal = smb_shr_count();
+ se.se_nlimit = se.se_ntotal;
if (param->prefmaxlen == SMB_SRVSVC_MAXPREFLEN ||
param->prefmaxlen > SMB_SRVSVC_MAXBUFLEN)
@@ -2023,8 +2118,9 @@
se.se_prefmaxlen = param->prefmaxlen;
if (param->resume_handle) {
- se.se_resume_handle = *param->resume_handle;
- se.se_n_skip = se.se_resume_handle;
+ se.se_resume = *param->resume_handle;
+ se.se_nskip = se.se_resume;
+ *param->resume_handle = 0;
}
switch (param->level) {
@@ -2056,24 +2152,20 @@
return (NDR_DRC_OK);
}
- if (se.se_n_enum == 0) {
- if (param->resume_handle)
- *param->resume_handle = 0;
+ if (se.se_nlimit == 0) {
param->status = ERROR_SUCCESS;
return (NDR_DRC_OK);
}
if (param->resume_handle &&
param->prefmaxlen != SMB_SRVSVC_MAXPREFLEN) {
- if (se.se_resume_handle < se.se_n_total) {
- *param->resume_handle = se.se_resume_handle;
+ if (se.se_resume < se.se_ntotal) {
+ *param->resume_handle = se.se_resume;
status = ERROR_MORE_DATA;
- } else {
- *param->resume_handle = 0;
}
}
- param->totalentries = se.se_n_total;
+ param->totalentries = se.se_ntotal;
param->status = status;
return (NDR_DRC_OK);
}
@@ -2082,33 +2174,33 @@
* NetShareEnum Level 0
*/
static DWORD
-mlsvc_NetShareEnumLevel0(ndr_xa_t *mxa,
- struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky)
+mlsvc_NetShareEnumLevel0(ndr_xa_t *mxa, srvsvc_infonres_t *infonres,
+ smb_svcenum_t *se, int sticky)
{
struct mslm_NetShareInfo_0 *info0;
smb_shriter_t iterator;
smb_share_t *si;
DWORD status;
- se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen,
- se->se_n_total, sizeof (struct mslm_NetShareInfo_0) + MAXNAMELEN);
- if (se->se_n_enum == 0)
+ srvsvc_estimate_limit(se,
+ sizeof (struct mslm_NetShareInfo_0) + MAXNAMELEN);
+ if (se->se_nlimit == 0)
return (ERROR_SUCCESS);
- info0 = NDR_NEWN(mxa, struct mslm_NetShareInfo_0, se->se_n_enum);
+ info0 = NDR_NEWN(mxa, struct mslm_NetShareInfo_0, se->se_nlimit);
if (info0 == NULL)
return (ERROR_NOT_ENOUGH_MEMORY);
smb_shr_iterinit(&iterator);
- se->se_n_read = 0;
+ se->se_nitems = 0;
while ((si = smb_shr_iterate(&iterator)) != NULL) {
- if (se->se_n_skip > 0) {
- --se->se_n_skip;
+ if (se->se_nskip > 0) {
+ --se->se_nskip;
continue;
}
- ++se->se_resume_handle;
+ ++se->se_resume;
if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
continue;
@@ -2116,8 +2208,8 @@
if (si->shr_flags & SMB_SHRF_AUTOHOME)
continue;
- if (se->se_n_read >= se->se_n_enum) {
- se->se_n_read = se->se_n_enum;
+ if (se->se_nitems >= se->se_nlimit) {
+ se->se_nitems = se->se_nlimit;
break;
}
@@ -2125,15 +2217,15 @@
if (status != ERROR_SUCCESS)
break;
- ++se->se_n_read;
+ ++se->se_nitems;
}
- if (se->se_n_read < se->se_n_enum) {
+ if (se->se_nitems < se->se_nlimit) {
if (srvsvc_add_autohome(mxa, se, (void *)info0))
- ++se->se_n_read;
+ ++se->se_nitems;
}
- infonres->entriesread = se->se_n_read;
+ infonres->entriesread = se->se_nitems;
infonres->entries = info0;
return (ERROR_SUCCESS);
}
@@ -2142,33 +2234,33 @@
* NetShareEnum Level 1
*/
static DWORD
-mlsvc_NetShareEnumLevel1(ndr_xa_t *mxa,
- struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky)
+mlsvc_NetShareEnumLevel1(ndr_xa_t *mxa, srvsvc_infonres_t *infonres,
+ smb_svcenum_t *se, int sticky)
{
struct mslm_NetShareInfo_1 *info1;
smb_shriter_t iterator;
smb_share_t *si;
DWORD status;
- se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen,
- se->se_n_total, sizeof (struct mslm_NetShareInfo_1) + MAXNAMELEN);
- if (se->se_n_enum == 0)
+ srvsvc_estimate_limit(se,
+ sizeof (struct mslm_NetShareInfo_1) + MAXNAMELEN);
+ if (se->se_nlimit == 0)
return (ERROR_SUCCESS);
- info1 = NDR_NEWN(mxa, struct mslm_NetShareInfo_1, se->se_n_enum);
+ info1 = NDR_NEWN(mxa, struct mslm_NetShareInfo_1, se->se_nlimit);
if (info1 == NULL)
return (ERROR_NOT_ENOUGH_MEMORY);
smb_shr_iterinit(&iterator);
- se->se_n_read = 0;
+ se->se_nitems = 0;
while ((si = smb_shr_iterate(&iterator)) != 0) {
- if (se->se_n_skip > 0) {
- --se->se_n_skip;
+ if (se->se_nskip > 0) {
+ --se->se_nskip;
continue;
}
- ++se->se_resume_handle;
+ ++se->se_resume;
if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
continue;
@@ -2176,8 +2268,8 @@
if (si->shr_flags & SMB_SHRF_AUTOHOME)
continue;
- if (se->se_n_read >= se->se_n_enum) {
- se->se_n_read = se->se_n_enum;
+ if (se->se_nitems >= se->se_nlimit) {
+ se->se_nitems = se->se_nlimit;
break;
}
@@ -2185,15 +2277,15 @@
if (status != ERROR_SUCCESS)
break;
- ++se->se_n_read;
+ ++se->se_nitems;
}
- if (se->se_n_read < se->se_n_enum) {
+ if (se->se_nitems < se->se_nlimit) {
if (srvsvc_add_autohome(mxa, se, (void *)info1))
- ++se->se_n_read;
+ ++se->se_nitems;
}
- infonres->entriesread = se->se_n_read;
+ infonres->entriesread = se->se_nitems;
infonres->entries = info1;
return (ERROR_SUCCESS);
}
@@ -2202,33 +2294,33 @@
* NetShareEnum Level 2
*/
static DWORD
-mlsvc_NetShareEnumLevel2(ndr_xa_t *mxa,
- struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky)
+mlsvc_NetShareEnumLevel2(ndr_xa_t *mxa, srvsvc_infonres_t *infonres,
+ smb_svcenum_t *se, int sticky)
{
struct mslm_NetShareInfo_2 *info2;
smb_shriter_t iterator;
smb_share_t *si;
DWORD status;
- se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen,
- se->se_n_total, sizeof (struct mslm_NetShareInfo_2) + MAXNAMELEN);
- if (se->se_n_enum == 0)
+ srvsvc_estimate_limit(se,
+ sizeof (struct mslm_NetShareInfo_2) + MAXNAMELEN);
+ if (se->se_nlimit == 0)
return (ERROR_SUCCESS);
- info2 = NDR_NEWN(mxa, struct mslm_NetShareInfo_2, se->se_n_enum);
+ info2 = NDR_NEWN(mxa, struct mslm_NetShareInfo_2, se->se_nlimit);
if (info2 == NULL)
return (ERROR_NOT_ENOUGH_MEMORY);
smb_shr_iterinit(&iterator);
- se->se_n_read = 0;
+ se->se_nitems = 0;
while ((si = smb_shr_iterate(&iterator)) != 0) {
- if (se->se_n_skip > 0) {
- --se->se_n_skip;
+ if (se->se_nskip > 0) {
+ --se->se_nskip;
continue;
}
- ++se->se_resume_handle;
+ ++se->se_resume;
if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
continue;
@@ -2236,8 +2328,8 @@
if (si->shr_flags & SMB_SHRF_AUTOHOME)
continue;
- if (se->se_n_read >= se->se_n_enum) {
- se->se_n_read = se->se_n_enum;
+ if (se->se_nitems >= se->se_nlimit) {
+ se->se_nitems = se->se_nlimit;
break;
}
@@ -2245,15 +2337,15 @@
if (status != ERROR_SUCCESS)
break;
- ++se->se_n_read;
+ ++se->se_nitems;
}
- if (se->se_n_read < se->se_n_enum) {
+ if (se->se_nitems < se->se_nlimit) {
if (srvsvc_add_autohome(mxa, se, (void *)info2))
- ++se->se_n_read;
+ ++se->se_nitems;
}
- infonres->entriesread = se->se_n_read;
+ infonres->entriesread = se->se_nitems;
infonres->entries = info2;
return (ERROR_SUCCESS);
}
@@ -2262,34 +2354,34 @@
* NetShareEnum Level 501
*/
static DWORD
-mlsvc_NetShareEnumLevel501(ndr_xa_t *mxa,
- struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky)
+mlsvc_NetShareEnumLevel501(ndr_xa_t *mxa, srvsvc_infonres_t *infonres,
+ smb_svcenum_t *se, int sticky)
{
struct mslm_NetShareInfo_501 *info501;
smb_shriter_t iterator;
smb_share_t *si;
DWORD status;
- se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen,
- se->se_n_total, sizeof (struct mslm_NetShareInfo_501) + MAXNAMELEN);
- if (se->se_n_enum == 0)
+ srvsvc_estimate_limit(se,
+ sizeof (struct mslm_NetShareInfo_501) + MAXNAMELEN);
+ if (se->se_nlimit == 0)
return (ERROR_SUCCESS);
info501 = NDR_NEWN(mxa, struct mslm_NetShareInfo_501,
- se->se_n_enum);
+ se->se_nlimit);
if (info501 == NULL)
return (ERROR_NOT_ENOUGH_MEMORY);
smb_shr_iterinit(&iterator);
- se->se_n_read = 0;
+ se->se_nitems = 0;
while ((si = smb_shr_iterate(&iterator)) != 0) {
- if (se->se_n_skip > 0) {
- --se->se_n_skip;
+ if (se->se_nskip > 0) {
+ --se->se_nskip;
continue;
}
- ++se->se_resume_handle;
+ ++se->se_resume;
if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
continue;
@@ -2297,8 +2389,8 @@
if (si->shr_flags & SMB_SHRF_AUTOHOME)
continue;
- if (se->se_n_read >= se->se_n_enum) {
- se->se_n_read = se->se_n_enum;
+ if (se->se_nitems >= se->se_nlimit) {
+ se->se_nitems = se->se_nlimit;
break;
}
@@ -2306,15 +2398,15 @@
if (status != ERROR_SUCCESS)
break;
- ++se->se_n_read;
+ ++se->se_nitems;
}
- if (se->se_n_read < se->se_n_enum) {
+ if (se->se_nitems < se->se_nlimit) {
if (srvsvc_add_autohome(mxa, se, (void *)info501))
- ++se->se_n_read;
+ ++se->se_nitems;
}
- infonres->entriesread = se->se_n_read;
+ infonres->entriesread = se->se_nitems;
infonres->entries = info501;
return (ERROR_SUCCESS);
}
@@ -2323,34 +2415,34 @@
* NetShareEnum Level 502
*/
static DWORD
-mlsvc_NetShareEnumLevel502(ndr_xa_t *mxa,
- struct mslm_infonres *infonres, srvsvc_enum_t *se, int sticky)
+mlsvc_NetShareEnumLevel502(ndr_xa_t *mxa, srvsvc_infonres_t *infonres,
+ smb_svcenum_t *se, int sticky)
{
struct mslm_NetShareInfo_502 *info502;
smb_shriter_t iterator;
smb_share_t *si;
DWORD status;
- se->se_n_enum = srvsvc_estimate_objcnt(se->se_prefmaxlen,
- se->se_n_total, sizeof (struct mslm_NetShareInfo_502) + MAXNAMELEN);
- if (se->se_n_enum == 0)
+ srvsvc_estimate_limit(se,
+ sizeof (struct mslm_NetShareInfo_502) + MAXNAMELEN);
+ if (se->se_nlimit == 0)
return (ERROR_SUCCESS);
info502 = NDR_NEWN(mxa, struct mslm_NetShareInfo_502,
- se->se_n_enum);
+ se->se_nlimit);
if (info502 == NULL)
return (ERROR_NOT_ENOUGH_MEMORY);
smb_shr_iterinit(&iterator);
- se->se_n_read = 0;
+ se->se_nitems = 0;
while ((si = smb_shr_iterate(&iterator)) != NULL) {
- if (se->se_n_skip > 0) {
- --se->se_n_skip;
+ if (se->se_nskip > 0) {
+ --se->se_nskip;
continue;
}
- ++se->se_resume_handle;
+ ++se->se_resume;
if (sticky && (si->shr_flags & SMB_SHRF_TRANS))
continue;
@@ -2358,8 +2450,8 @@
if (si->shr_flags & SMB_SHRF_AUTOHOME)
continue;
- if (se->se_n_read >= se->se_n_enum) {
- se->se_n_read = se->se_n_enum;
+ if (se->se_nitems >= se->se_nlimit) {
+ se->se_nitems = se->se_nlimit;
break;
}
@@ -2367,15 +2459,15 @@
if (status != ERROR_SUCCESS)
break;
- ++se->se_n_read;
+ ++se->se_nitems;
}
- if (se->se_n_read < se->se_n_enum) {
+ if (se->se_nitems < se->se_nlimit) {
if (srvsvc_add_autohome(mxa, se, (void *)info502))
- ++se->se_n_read;
+ ++se->se_nitems;
}
- infonres->entriesread = se->se_n_read;
+ infonres->entriesread = se->se_nitems;
infonres->entries = info502;
return (ERROR_SUCCESS);
}
@@ -2396,7 +2488,7 @@
* ERROR_INVALID_LEVEL
*/
static DWORD
-mlsvc_NetShareEnumCommon(ndr_xa_t *mxa, srvsvc_enum_t *se,
+mlsvc_NetShareEnumCommon(ndr_xa_t *mxa, smb_svcenum_t *se,
smb_share_t *si, void *infop)
{
struct mslm_NetShareInfo_0 *info0;
@@ -2409,7 +2501,7 @@
uint8_t *comment;
uint8_t *passwd;
uint8_t *path;
- int i = se->se_n_read;
+ int i = se->se_nitems;
netname = (uint8_t *)NDR_STRDUP(mxa, si->shr_name);
comment = (uint8_t *)NDR_STRDUP(mxa, si->shr_cmnt);
@@ -2487,10 +2579,10 @@
* share to avoid duplicates.
*/
static boolean_t
-srvsvc_add_autohome(ndr_xa_t *mxa, srvsvc_enum_t *se, void *infop)
+srvsvc_add_autohome(ndr_xa_t *mxa, smb_svcenum_t *se, void *infop)
{
- smb_opipe_context_t *ctx = &mxa->pipe->np_ctx;
- char *username = ctx->oc_account;
+ smb_netuserinfo_t *user = &mxa->pipe->np_user;
+ char *username = user->ui_account;
smb_share_t si;
DWORD status;
@@ -2580,8 +2672,8 @@
/*
* srvsvc_s_NetShareDel
*
- * Delete a share. Only the administrator, or a member of the domain
- * administrators group, is allowed to delete shares.
+ * Delete a share. Only members of the Administrators, Server Operators
+ * or Power Users local groups are allowed to delete shares.
*
* This interface is used by the rmtshare command from the NT resource
* kit. Rmtshare allows a client to add or remove shares on a server
--- a/usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.c Fri Jul 17 17:54:42 2009 -0700
@@ -30,7 +30,6 @@
* of Solaris SMF service are displayed on the Server/Connection Manager
* Windows client.
*/
-
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
@@ -40,9 +39,12 @@
#include <libscf.h>
#include <libscf_priv.h>
#include <time.h>
+#include <dlfcn.h>
#include <sys/types.h>
-
-#include "svcctl_scm.h"
+#include <smbsrv/winsvc.h>
+#include <smbsrv/nterror.h>
+#include <smbsrv/ndl/svcctl.ndl>
+#include <smbsrv/libmlsvc.h>
#define LEGACY_UNKNOWN "unknown"
#define SVC_NAME_PROP "name"
@@ -51,6 +53,12 @@
#define EMPTY_OK 0x01
#define MULTI_OK 0x02
+static void *svcctl_scm_interposer_hdl = NULL;
+static struct {
+ int (*svcctl_op_scm_init)(svcctl_manager_context_t *);
+ int (*svcctl_op_scf_init)(svcctl_manager_context_t *);
+} svcctl_scm_ops;
+
/*
* svcctl_scm_avl_nodecmp
*
@@ -659,7 +667,7 @@
*
* Calculates bytes needed to enumerate SMF services.
*/
-void
+static void
svcctl_scm_bytes_needed(svcctl_manager_context_t *mgr_ctx)
{
int bytes_needed = 0, svc_enum_status_size = 0;
@@ -761,6 +769,10 @@
svcctl_scm_refresh(svcctl_manager_context_t *mgr_ctx)
{
svcctl_scm_fini(mgr_ctx);
+
+ if (svcctl_scm_ops.svcctl_op_scm_init != NULL)
+ return (svcctl_scm_ops.svcctl_op_scm_init(mgr_ctx));
+
return (svcctl_scm_init(mgr_ctx));
}
@@ -772,6 +784,10 @@
int
svcctl_scm_scf_handle_init(svcctl_manager_context_t *mgr_ctx)
{
+ if (svcctl_scm_ops.svcctl_op_scf_init != NULL)
+ return (svcctl_scm_ops.
+ svcctl_op_scf_init(mgr_ctx));
+
mgr_ctx->mc_scf_hdl = scf_handle_create(SCF_VERSION);
if (mgr_ctx->mc_scf_hdl == NULL)
return (-1);
@@ -810,8 +826,11 @@
scf_value_destroy(mgr_ctx->mc_scf_gval);
scf_property_destroy(mgr_ctx->mc_scf_gprop);
scf_pg_destroy(mgr_ctx->mc_scf_gpg);
- (void) scf_handle_unbind(mgr_ctx->mc_scf_hdl);
- scf_handle_destroy(mgr_ctx->mc_scf_hdl);
+
+ if (mgr_ctx->mc_scf_hdl != NULL) {
+ (void) scf_handle_unbind(mgr_ctx->mc_scf_hdl);
+ scf_handle_destroy(mgr_ctx->mc_scf_hdl);
+ }
}
/*
@@ -829,6 +848,9 @@
assert(mgr_ctx->mc_svcs_pool == NULL);
assert(mgr_ctx->mc_svcs == NULL);
+ if (svcctl_scm_ops.svcctl_op_scm_init != NULL)
+ return (svcctl_scm_ops.svcctl_op_scm_init(mgr_ctx));
+
mgr_ctx->mc_svcs_pool = uu_avl_pool_create("smf_svcs_pool",
sizeof (svcctl_svc_node_t), offsetof(svcctl_svc_node_t, sn_node),
svcctl_scm_avl_nodecmp, UU_AVL_DEBUG);
@@ -890,3 +912,47 @@
mgr_ctx->mc_svcs_pool = NULL;
mgr_ctx->mc_svcs = NULL;
}
+
+/*
+ * svcctl_init
+ *
+ * Initializes the SVCCTL service.
+ * Initializes handle and ops structure to interposed library.
+ */
+void
+svcctl_init(void)
+{
+ svcctl_scm_interposer_hdl = smb_dlopen();
+ if (svcctl_scm_interposer_hdl == NULL)
+ return;
+
+ bzero((void *)&svcctl_scm_ops,
+ sizeof (svcctl_scm_ops));
+
+ svcctl_scm_ops.svcctl_op_scm_init =
+ (int (*)())dlsym(svcctl_scm_interposer_hdl, "svcctl_scm_init");
+
+ svcctl_scm_ops.svcctl_op_scf_init =
+ (int (*)())dlsym(svcctl_scm_interposer_hdl,
+ "svcctl_scm_scf_handle_init");
+
+ if (svcctl_scm_ops.svcctl_op_scm_init == NULL ||
+ svcctl_scm_ops.svcctl_op_scf_init == NULL)
+ svcctl_fini();
+
+}
+
+/*
+ * svcctl_fini
+ *
+ * Finalizes the SVCCTL service.
+ * Closes handle to interposed library.
+ */
+void
+svcctl_fini(void)
+{
+ smb_dlclose(svcctl_scm_interposer_hdl);
+ svcctl_scm_interposer_hdl = NULL;
+ bzero((void *)&svcctl_scm_ops,
+ sizeof (svcctl_scm_ops));
+}
--- a/usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.h Fri Jul 17 16:57:52 2009 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,108 +0,0 @@
-/*
- * 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 2009 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef _SVCCTL_H
-#define _SVCCTL_H
-
-#include <libuutil.h>
-#include <smbsrv/libsmb.h>
-#include <smbsrv/libmlrpc.h>
-#include <smbsrv/libmlsvc.h>
-#include <smbsrv/nterror.h>
-#include <smbsrv/winsvc.h>
-#include <smbsrv/ndl/svcctl.ndl>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Calculate the wide-char equivalent string length required to
- * store a string - including the terminating null wide-char.
- */
-#define SVCCTL_WNSTRLEN(S) ((strlen((S)) + 1) * sizeof (mts_wchar_t))
-
-/* An AVL-storable node representing each service in the SCM database. */
-typedef struct svcctl_svc_node {
- uu_avl_node_t sn_node;
- char *sn_name; /* Service Name (Key) */
- char *sn_fmri; /* Display Name (FMRI) */
- char *sn_desc; /* Description */
- char *sn_state; /* State */
-} svcctl_svc_node_t;
-
-/* This structure provides context for each svcctl_s_OpenManager call. */
-typedef struct svcctl_manager_context {
- scf_handle_t *mc_scf_hdl; /* SCF handle */
- scf_propertygroup_t *mc_scf_gpg; /* Property group */
- scf_property_t *mc_scf_gprop; /* Property */
- scf_value_t *mc_scf_gval; /* Value */
- uint32_t mc_scf_numsvcs; /* Number of SMF services */
- ssize_t mc_scf_max_fmri_len; /* Max FMRI length */
- ssize_t mc_scf_max_value_len; /* Max Value length */
- uint32_t mc_bytes_needed; /* Number of bytes needed */
- uu_avl_pool_t *mc_svcs_pool; /* AVL pool */
- uu_avl_t *mc_svcs; /* AVL tree of SMF services */
-} svcctl_manager_context_t;
-
-/* This structure provides context for each svcctl_s_OpenService call. */
-typedef struct svcctl_service_context {
- ndr_hdid_t *sc_mgrid; /* Manager ID */
- char *sc_svcname; /* Service Name */
-} svcctl_service_context_t;
-
-typedef enum {
- SVCCTL_MANAGER_CONTEXT = 0,
- SVCCTL_SERVICE_CONTEXT
-} svcctl_context_type_t;
-
-/* This structure provides abstraction for service and manager context call. */
-typedef struct svcctl_context {
- svcctl_context_type_t c_type;
- union {
- svcctl_manager_context_t *uc_mgr;
- svcctl_service_context_t *uc_svc;
- void *uc_cp;
- } c_ctx;
-} svcctl_context_t;
-
-/* Service Control Manager (SCM) functions */
-int svcctl_scm_init(svcctl_manager_context_t *);
-void svcctl_scm_fini(svcctl_manager_context_t *);
-int svcctl_scm_scf_handle_init(svcctl_manager_context_t *);
-void svcctl_scm_scf_handle_fini(svcctl_manager_context_t *);
-int svcctl_scm_refresh(svcctl_manager_context_t *);
-void svcctl_scm_bytes_needed(svcctl_manager_context_t *);
-uint32_t svcctl_scm_enum_services(svcctl_manager_context_t *, uint8_t *,
- size_t, uint32_t *, boolean_t);
-uint32_t svcctl_scm_validate_service(svcctl_manager_context_t *, char *);
-svcctl_svc_node_t *svcctl_scm_find_service(svcctl_manager_context_t *, char *);
-uint32_t svcctl_scm_map_status(const char *);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _SVCCTL_H */
--- a/usr/src/lib/smbsrv/libmlsvc/common/svcctl_svc.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/smbsrv/libmlsvc/common/svcctl_svc.c Fri Jul 17 17:54:42 2009 -0700
@@ -37,7 +37,10 @@
#include <smbsrv/ntstatus.h>
#include <smbsrv/nmpipes.h>
#include <smbsrv/ntifs.h>
-#include "svcctl_scm.h"
+#include <smbsrv/winsvc.h>
+#include <smbsrv/nterror.h>
+#include <smbsrv/ndl/svcctl.ndl>
+#include <smbsrv/libmlsvc.h>
#define SVCCTL_SECURITY_BUFSIZE 256
#define SVCCTL_ENUMSERVICES_MINBUFSIZE 1024
@@ -120,6 +123,13 @@
svcctl_initialize(void)
{
(void) ndr_svc_register(&svcctl_service);
+ svcctl_init();
+}
+
+void
+svcctl_finalize(void)
+{
+ svcctl_fini();
}
/*
--- a/usr/src/lib/smbsrv/libsmb/Makefile.com Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/smbsrv/libsmb/Makefile.com Fri Jul 17 17:54:42 2009 -0700
@@ -79,7 +79,7 @@
INCS += -I$(SRC)/common/smbsrv
LDLIBS += $(MACH_LDLIBS)
-LDLIBS += -lscf -lmd -lnsl -lpkcs11 -lsec -lsocket -lresolv
+LDLIBS += -lscf -lmd -luuid -lnsl -lpkcs11 -lsec -lsocket -lresolv
LDLIBS += -lidmap -lavl -lc
CPPFLAGS += $(INCS) -D_REENTRANT
--- a/usr/src/lib/smbsrv/libsmb/common/libsmb.h Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/smbsrv/libsmb/common/libsmb.h Fri Jul 17 17:54:42 2009 -0700
@@ -41,6 +41,7 @@
#include <libscf.h>
#include <libshare.h>
#include <sqlite/sqlite.h>
+#include <uuid/uuid.h>
#include <smbsrv/string.h>
#include <smbsrv/smb_idmap.h>
@@ -65,7 +66,6 @@
#define SMB_CCACHE_PATH SMB_VARRUN_DIR "/" SMB_CCACHE_FILE
-
/* Max value length of all SMB properties */
#define MAX_VALUE_BUFLEN 512
@@ -272,9 +272,6 @@
extern int smb_chk_hostaccess(smb_inaddr_t *, char *);
extern int smb_getnameinfo(smb_inaddr_t *, char *, int, int);
-extern smb_ulist_t *smb_ulist_alloc(void);
-extern void smb_ulist_free(smb_ulist_t *);
-extern void smb_ulist_cleanup(smb_ulist_t *);
void smb_trace(const char *s);
void smb_tracef(const char *fmt, ...);
@@ -848,8 +845,24 @@
void smb_kmod_unbind(void);
int smb_kmod_share(char *, char *);
int smb_kmod_unshare(char *, char *);
-int smb_kmod_get_usernum(uint32_t *);
-int smb_kmod_get_userlist(smb_ulist_t *);
+int smb_kmod_get_open_num(smb_opennum_t *);
+int smb_kmod_enum(smb_netsvc_t *);
+smb_netsvc_t *smb_kmod_enum_init(smb_svcenum_t *);
+void smb_kmod_enum_fini(smb_netsvc_t *);
+int smb_kmod_session_close(const char *, const char *);
+int smb_kmod_file_close(uint32_t);
+
+/*
+ * Interposer library validation
+ */
+#define SMBEX_VERSION 1
+#define SMBEX_KEY "82273fdc-e32a-18c3-3f78-827929dc23ea"
+typedef struct smbex_version {
+ uint32_t v_version;
+ uuid_t v_uuid;
+} smbex_version_t;
+void *smb_dlopen(void);
+void smb_dlclose(void *);
#ifdef __cplusplus
}
--- a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers Fri Jul 17 17:54:42 2009 -0700
@@ -147,6 +147,8 @@
smb_ctxbuf_init;
smb_ctxbuf_len;
smb_ctxbuf_printf;
+ smb_dlclose;
+ smb_dlopen;
smb_dr_clnt_call;
smb_dr_clnt_cleanup;
smb_dr_clnt_setup;
@@ -219,10 +221,14 @@
smb_inet_iszero;
smb_inet_ntop;
smb_kmod_bind;
- smb_kmod_get_userlist;
- smb_kmod_get_usernum;
+ smb_kmod_enum;
+ smb_kmod_enum_init;
+ smb_kmod_enum_fini;
+ smb_kmod_file_close;
+ smb_kmod_get_open_num;
smb_kmod_nbtlisten;
smb_kmod_nbtreceive;
+ smb_kmod_session_close;
smb_kmod_setcfg;
smb_kmod_setgmtoff;
smb_kmod_share;
@@ -275,6 +281,12 @@
smb_msgbuf_term;
smb_msgbuf_used;
smb_msgbuf_word_align;
+ smb_netconnectinfo_decode;
+ smb_netconnectinfo_encode;
+ smb_netfileinfo_decode;
+ smb_netfileinfo_encode;
+ smb_netuserinfo_decode;
+ smb_netuserinfo_encode;
smb_nic_addhost;
smb_nic_delhost;
smb_nic_is_local;
@@ -289,9 +301,6 @@
smb_opipe_hdr_encode;
smb_opipe_hdr_decode;
smb_opipe_hdr_xdr;
- smb_opipe_context_encode;
- smb_opipe_context_decode;
- smb_opipe_context_xdr;
smb_priv_getbyname;
smb_priv_getbyvalue;
smb_priv_presentable_ids;
@@ -348,8 +357,6 @@
smb_tonetbiosname;
smb_trace;
smb_tracef;
- smb_ulist_alloc;
- smb_ulist_free;
smb_update_netlogon_seqnum;
smb_wka_fini;
smb_wka_get_domain;
--- a/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c Fri Jul 17 17:54:42 2009 -0700
@@ -181,83 +181,213 @@
}
int
-smb_kmod_get_usernum(uint32_t *punum)
+smb_kmod_get_open_num(smb_opennum_t *opennum)
{
- smb_ioc_usernum_t ioc;
+ smb_ioc_opennum_t ioc;
int rc;
- ioc.num = 0;
- rc = smb_kmod_ioctl(SMB_IOC_USER_NUMBER, &ioc.hdr, sizeof (ioc));
- if (rc == 0)
- *punum = ioc.num;
+ bzero(&ioc, sizeof (ioc));
+ ioc.qualtype = opennum->qualtype;
+ (void) strlcpy(ioc.qualifier, opennum->qualifier, MAXNAMELEN);
+
+ rc = smb_kmod_ioctl(SMB_IOC_NUMOPEN, &ioc.hdr, sizeof (ioc));
+ if (rc == 0) {
+ opennum->open_users = ioc.open_users;
+ opennum->open_trees = ioc.open_trees;
+ opennum->open_files = ioc.open_files;
+ }
+
+ return (rc);
+}
+
+/*
+ * Initialization for an smb_kmod_enum request. If this call succeeds,
+ * smb_kmod_enum_fini() must be called later to deallocate resources.
+ */
+smb_netsvc_t *
+smb_kmod_enum_init(smb_svcenum_t *request)
+{
+ smb_netsvc_t *ns;
+ smb_svcenum_t *svcenum;
+ smb_ioc_svcenum_t *ioc;
+ uint32_t ioclen;
+
+ if ((ns = calloc(1, sizeof (smb_netsvc_t))) == NULL)
+ return (NULL);
+
+ ioclen = sizeof (smb_ioc_svcenum_t) + SMB_IOC_DATA_SIZE;
+ if ((ioc = malloc(ioclen)) == NULL) {
+ free(ns);
+ return (NULL);
+ }
+
+ bzero(ioc, ioclen);
+ svcenum = &ioc->svcenum;
+ svcenum->se_type = request->se_type;
+ svcenum->se_level = request->se_level;
+ svcenum->se_bavail = SMB_IOC_DATA_SIZE;
+ svcenum->se_nlimit = request->se_nlimit;
+ svcenum->se_nskip = request->se_nskip;
+ svcenum->se_buflen = SMB_IOC_DATA_SIZE;
+
+ list_create(&ns->ns_list, sizeof (smb_netsvcitem_t),
+ offsetof(smb_netsvcitem_t, nsi_lnd));
+
+ ns->ns_ioc = ioc;
+ ns->ns_ioclen = ioclen;
+ return (ns);
+}
+
+/*
+ * Cleanup resources allocated via smb_kmod_enum_init and smb_kmod_enum.
+ */
+void
+smb_kmod_enum_fini(smb_netsvc_t *ns)
+{
+ list_t *lst;
+ smb_netsvcitem_t *item;
+ smb_netuserinfo_t *user;
+ smb_netconnectinfo_t *tree;
+ smb_netfileinfo_t *ofile;
+ uint32_t se_type;
+
+ if (ns == NULL)
+ return;
+
+ lst = &ns->ns_list;
+ se_type = ns->ns_ioc->svcenum.se_type;
+
+ while ((item = list_head(lst)) != NULL) {
+ list_remove(lst, item);
+ switch (se_type) {
+ case SMB_SVCENUM_TYPE_USER:
+ user = &item->nsi_un.nsi_user;
+ free(user->ui_domain);
+ free(user->ui_account);
+ free(user->ui_workstation);
+ break;
+ case SMB_SVCENUM_TYPE_TREE:
+ tree = &item->nsi_un.nsi_tree;
+ free(tree->ci_username);
+ free(tree->ci_share);
+ break;
+ case SMB_SVCENUM_TYPE_FILE:
+ ofile = &item->nsi_un.nsi_ofile;
+ free(ofile->fi_path);
+ free(ofile->fi_username);
+ break;
+ default:
+ break;
+ }
+ }
+
+ list_destroy(&ns->ns_list);
+ free(ns->ns_items);
+ free(ns->ns_ioc);
+ free(ns);
+}
+
+/*
+ * Enumerate users, connections or files.
+ */
+int
+smb_kmod_enum(smb_netsvc_t *ns)
+{
+ smb_ioc_svcenum_t *ioc;
+ uint32_t ioclen;
+ smb_svcenum_t *svcenum;
+ smb_netsvcitem_t *items;
+ smb_netuserinfo_t *user;
+ smb_netconnectinfo_t *tree;
+ smb_netfileinfo_t *ofile;
+ uint8_t *data;
+ uint32_t len;
+ uint32_t se_type;
+ uint_t nbytes;
+ int i;
+ int rc;
+
+ ioc = ns->ns_ioc;
+ ioclen = ns->ns_ioclen;
+ rc = smb_kmod_ioctl(SMB_IOC_SVCENUM, &ioc->hdr, ioclen);
+ if (rc != 0)
+ return (rc);
+
+ svcenum = &ioc->svcenum;
+ items = calloc(svcenum->se_nitems, sizeof (smb_netsvcitem_t));
+ if (items == NULL)
+ return (ENOMEM);
+
+ ns->ns_items = items;
+ se_type = ns->ns_ioc->svcenum.se_type;
+ data = svcenum->se_buf;
+ len = svcenum->se_bused;
+
+ for (i = 0; i < svcenum->se_nitems; ++i) {
+ switch (se_type) {
+ case SMB_SVCENUM_TYPE_USER:
+ user = &items->nsi_un.nsi_user;
+ rc = smb_netuserinfo_decode(user, data, len, &nbytes);
+ break;
+ case SMB_SVCENUM_TYPE_TREE:
+ tree = &items->nsi_un.nsi_tree;
+ rc = smb_netconnectinfo_decode(tree, data, len,
+ &nbytes);
+ break;
+ case SMB_SVCENUM_TYPE_FILE:
+ ofile = &items->nsi_un.nsi_ofile;
+ rc = smb_netfileinfo_decode(ofile, data, len, &nbytes);
+ break;
+ default:
+ rc = -1;
+ break;
+ }
+
+ if (rc != 0)
+ return (EINVAL);
+
+ list_insert_tail(&ns->ns_list, items);
+
+ ++items;
+ data += nbytes;
+ len -= nbytes;
+ }
+
+ return (0);
+}
+
+/*
+ * A NULL pointer is a wildcard indicator, which we pass on
+ * as an empty string (by virtue of the bzero).
+ */
+int
+smb_kmod_session_close(const char *client, const char *username)
+{
+ smb_ioc_session_t ioc;
+ int rc;
+
+ bzero(&ioc, sizeof (ioc));
+
+ if (client != NULL)
+ (void) strlcpy(ioc.client, client, MAXNAMELEN);
+ if (username != NULL)
+ (void) strlcpy(ioc.username, username, MAXNAMELEN);
+
+ rc = smb_kmod_ioctl(SMB_IOC_SESSION_CLOSE, &ioc.hdr, sizeof (ioc));
return (rc);
}
int
-smb_kmod_get_userlist(smb_ulist_t *ulist)
+smb_kmod_file_close(uint32_t uniqid)
{
- smb_opipe_context_t *ctx;
- smb_ioc_ulist_t *ioc;
- uint32_t ioc_len;
- uint8_t *data;
- uint32_t data_len;
- uint32_t unum;
- int rc;
-
- smb_ulist_cleanup(ulist);
-
- rc = smb_kmod_get_usernum(&unum);
- if ((rc != 0) || (unum == 0))
- return (rc);
-
- ioc_len = sizeof (smb_ioc_ulist_t) + SMB_IOC_DATA_SIZE;
- ioc = malloc(ioc_len);
- if (ioc == NULL)
- return (ENOMEM);
-
- ctx = malloc(sizeof (smb_opipe_context_t) * unum);
- if (ctx == NULL) {
- free(ioc);
- return (ENOMEM);
- }
- ulist->ul_users = ctx;
+ smb_ioc_fileid_t ioc;
+ int rc;
- while (ulist->ul_cnt < unum) {
- ioc->cookie = ulist->ul_cnt;
- ioc->data_len = SMB_IOC_DATA_SIZE;
- rc = smb_kmod_ioctl(SMB_IOC_USER_LIST, &ioc->hdr,
- ioc_len);
- if (rc != 0)
- break;
-
- if ((ulist->ul_cnt + ioc->num) > unum)
- ioc->num = unum - ulist->ul_cnt;
-
- if (ioc->num == 0)
- break;
+ bzero(&ioc, sizeof (ioc));
+ ioc.uniqid = uniqid;
- data = ioc->data;
- data_len = ioc->data_len;
- while (ioc->num > 0) {
- uint_t bd = 0;
-
- rc = smb_opipe_context_decode(ctx, data, data_len, &bd);
- if (rc != 0)
- break;
-
- ctx++;
- ioc->num--;
- ulist->ul_cnt++;
- data += bd;
- data_len -= bd;
- }
- }
-
- if (rc != 0)
- smb_ulist_cleanup(ulist);
-
- free(ioc);
+ rc = smb_kmod_ioctl(SMB_IOC_FILE_CLOSE, &ioc.hdr, sizeof (ioc));
return (rc);
}
--- a/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c Fri Jul 17 17:54:42 2009 -0700
@@ -45,8 +45,6 @@
#define SMB_PASSTEMP "/var/smb/ptmp"
#define SMB_PASSLCK "/var/smb/.pwd.lock"
-#define SMB_LIB_ALT "/usr/lib/smbsrv/libsmb_pwd.so"
-
#define SMB_PWD_DISABLE "*DIS*"
#define SMB_PWD_BUFSIZE 256
@@ -172,11 +170,9 @@
smb_lucache_update();
}
- smb_pwd_hdl = dlopen(SMB_LIB_ALT, RTLD_NOW | RTLD_LOCAL);
- if (smb_pwd_hdl == NULL) {
- /* No library is interposed */
+ smb_pwd_hdl = smb_dlopen();
+ if (smb_pwd_hdl == NULL)
return;
- }
bzero((void *)&smb_pwd_ops, sizeof (smb_pwd_ops));
@@ -212,7 +208,7 @@
smb_pwd_ops.pwop_iteropen == NULL ||
smb_pwd_ops.pwop_iterclose == NULL ||
smb_pwd_ops.pwop_iterate == NULL) {
- (void) dlclose(smb_pwd_hdl);
+ smb_dlclose(smb_pwd_hdl);
smb_pwd_hdl = NULL;
/* If error or function(s) are missing, use original lib */
@@ -230,11 +226,9 @@
smb_pwd_fini(void)
{
smb_lucache_destroy();
-
- if (smb_pwd_hdl) {
- (void) dlclose(smb_pwd_hdl);
- smb_pwd_hdl = NULL;
- }
+ smb_dlclose(smb_pwd_hdl);
+ smb_pwd_hdl = NULL;
+ bzero((void *)&smb_pwd_ops, sizeof (smb_pwd_ops));
}
/*
--- a/usr/src/lib/smbsrv/libsmb/common/smb_util.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_util.c Fri Jul 17 17:54:42 2009 -0700
@@ -26,6 +26,7 @@
#include <ctype.h>
#include <stdio.h>
#include <string.h>
+#include <strings.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/varargs.h>
@@ -37,9 +38,12 @@
#include <sys/systeminfo.h>
#include <sys/utsname.h>
#include <libzfs.h>
+#include <dlfcn.h>
#include <smbsrv/string.h>
#include <smbsrv/libsmb.h>
+#define SMB_LIB_ALT "/usr/lib/smbsrv/libsmbex.so"
+
static uint_t smb_make_mask(char *, uint_t);
static boolean_t smb_netmatch(struct netbuf *, char *);
static boolean_t smb_netgroup_match(struct nd_hostservlist *, char *, int);
@@ -755,6 +759,64 @@
}
/*
+ * smb_dlopen
+ *
+ * Check to see if an interposer library exists. If it exists
+ * and reports a valid version number and key (UUID), return
+ * a handle to the library. Otherwise, return NULL.
+ */
+void *
+smb_dlopen(void)
+{
+ uuid_t uuid;
+ void *interposer_hdl;
+ typedef int (*smbex_versionfn_t)(smbex_version_t *);
+ smbex_versionfn_t getversion;
+ smbex_version_t *version;
+
+ bzero(&uuid, sizeof (uuid_t));
+ if (uuid_parse(SMBEX_KEY, uuid) < 0)
+ return (NULL);
+
+ interposer_hdl = dlopen(SMB_LIB_ALT, RTLD_NOW | RTLD_LOCAL);
+ if (interposer_hdl == NULL)
+ return (NULL);
+
+ bzero(&getversion, sizeof (smbex_versionfn_t));
+ getversion = (smbex_versionfn_t)dlsym(interposer_hdl,
+ "smbex_get_version");
+ if ((getversion == NULL) ||
+ (version = malloc(sizeof (smbex_version_t))) == NULL) {
+ (void) dlclose(interposer_hdl);
+ return (NULL);
+ }
+ bzero(version, sizeof (smbex_version_t));
+
+ if ((getversion(version) != 0) ||
+ (version->v_version != SMBEX_VERSION) ||
+ (uuid_compare(version->v_uuid, uuid) != 0)) {
+ free(version);
+ (void) dlclose(interposer_hdl);
+ return (NULL);
+ }
+
+ free(version);
+ return (interposer_hdl);
+}
+
+/*
+ * smb_dlclose
+ *
+ * Closes handle to the interposed library.
+ */
+void
+smb_dlclose(void *handle)
+{
+ if (handle)
+ (void) dlclose(handle);
+}
+
+/*
* Returns the hostname given the IP address. Wrapper for getnameinfo.
*/
int
@@ -782,47 +844,3 @@
return (getnameinfo((struct sockaddr *)sp, salen,
hostname, hostlen, NULL, 0, flags));
}
-
-smb_ulist_t *
-smb_ulist_alloc(void)
-{
- smb_ulist_t *ulist;
-
- ulist = malloc(sizeof (smb_ulist_t));
- if (ulist != NULL) {
- ulist->ul_cnt = 0;
- ulist->ul_users = NULL;
- }
- return (ulist);
-}
-
-void
-smb_ulist_free(smb_ulist_t *ulist)
-{
- if (ulist != NULL) {
- smb_ulist_cleanup(ulist);
- free(ulist);
- }
-}
-
-void
-smb_ulist_cleanup(smb_ulist_t *ulist)
-{
- smb_opipe_context_t *ctx;
-
- if (ulist->ul_users != NULL) {
- ctx = ulist->ul_users;
- while (ulist->ul_cnt != 0) {
- free(ctx->oc_domain);
- free(ctx->oc_account);
- free(ctx->oc_workstation);
- ctx->oc_domain = NULL;
- ctx->oc_account = NULL;
- ctx->oc_workstation = NULL;
- ulist->ul_cnt--;
- ctx++;
- }
- free(ulist->ul_users);
- ulist->ul_users = NULL;
- }
-}
--- a/usr/src/pkgdefs/etc/exception_list_i386 Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/pkgdefs/etc/exception_list_i386 Fri Jul 17 17:54:42 2009 -0700
@@ -1256,3 +1256,6 @@
# Private idmap RPC protocol
usr/include/rpcsvc/idmap_prot.h i386
usr/include/rpcsvc/idmap_prot.x i386
+
+# Private idmap directory API
+usr/include/directory.h i386
--- a/usr/src/pkgdefs/etc/exception_list_sparc Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/pkgdefs/etc/exception_list_sparc Fri Jul 17 17:54:42 2009 -0700
@@ -1355,3 +1355,6 @@
# Private idmap RPC protocol
usr/include/rpcsvc/idmap_prot.h sparc
usr/include/rpcsvc/idmap_prot.x sparc
+
+# Private idmap directory API
+usr/include/directory.h sparc
--- a/usr/src/uts/common/fs/smbsrv/smb_common_open.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_open.c Fri Jul 17 17:54:42 2009 -0700
@@ -414,7 +414,7 @@
sizeof (op->fqi.fq_last_comp),
"%s%s", cur_node->od_name, pn->pn_sname);
- op->fqi.fq_dnode = cur_node->dir_snode;
+ op->fqi.fq_dnode = cur_node->n_dnode;
smb_node_ref(op->fqi.fq_dnode);
} else {
if (rc = smb_pathname_reduce(sr, sr->user_cr, pn->pn_path,
--- a/usr/src/uts/common/fs/smbsrv/smb_delete.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/fs/smbsrv/smb_delete.c Fri Jul 17 17:54:42 2009 -0700
@@ -519,7 +519,7 @@
if (SMB_TREE_SUPPORTS_CATIA(sr))
flags |= SMB_CATIA;
- rc = smb_fsop_remove(sr, sr->user_cr, node->dir_snode,
+ rc = smb_fsop_remove(sr, sr->user_cr, node->n_dnode,
node->od_name, flags);
if (rc != 0) {
if (rc == ENOENT)
--- a/usr/src/uts/common/fs/smbsrv/smb_fsops.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/fs/smbsrv/smb_fsops.c Fri Jul 17 17:54:42 2009 -0700
@@ -694,7 +694,7 @@
sname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
if (dnode->flags & NODE_XATTR_DIR) {
- rc = smb_vop_stream_remove(dnode->dir_snode->vp,
+ rc = smb_vop_stream_remove(dnode->n_dnode->vp,
name, flags, cr);
} else if (smb_is_stream_name(name)) {
smb_stream_parse_name(name, fname, sname);
@@ -1453,7 +1453,7 @@
faccess &= sr->tid_tree->t_access;
if (acl_check) {
- dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL;
+ dir_vp = (snode->n_dnode) ? snode->n_dnode->vp : NULL;
error = smb_vop_access(snode->vp, faccess, V_ACE_MASK, dir_vp,
cr);
} else {
@@ -2297,7 +2297,7 @@
}
if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_ACEMASKONACCESS)) {
- dir_vp = (snode->dir_snode) ? snode->dir_snode->vp : NULL;
+ dir_vp = (snode->n_dnode) ? snode->n_dnode->vp : NULL;
smb_vop_eaccess(snode->vp, (int *)eaccess, V_ACE_MASK, dir_vp,
cr);
return;
--- a/usr/src/uts/common/fs/smbsrv/smb_init.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/fs/smbsrv/smb_init.c Fri Jul 17 17:54:42 2009 -0700
@@ -245,14 +245,20 @@
case SMB_IOC_UNSHARE:
rc = smb_server_share_unexport(&ioc->ioc_share);
break;
- case SMB_IOC_USER_NUMBER:
- rc = smb_server_user_number(&ioc->ioc_unum);
+ case SMB_IOC_NUMOPEN:
+ rc = smb_server_numopen(&ioc->ioc_opennum);
copyout = B_TRUE;
break;
- case SMB_IOC_USER_LIST:
- rc = smb_server_user_list(&ioc->ioc_ulist);
+ case SMB_IOC_SVCENUM:
+ rc = smb_server_enum(&ioc->ioc_svcenum);
copyout = B_TRUE;
break;
+ case SMB_IOC_SESSION_CLOSE:
+ rc = smb_server_session_close(&ioc->ioc_session);
+ break;
+ case SMB_IOC_FILE_CLOSE:
+ rc = smb_server_file_close(&ioc->ioc_fileid);
+ break;
default:
rc = ENOTTY;
break;
--- a/usr/src/uts/common/fs/smbsrv/smb_lock.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/fs/smbsrv/smb_lock.c Fri Jul 17 17:54:42 2009 -0700
@@ -52,7 +52,22 @@
static void smb_lock_destroy(smb_lock_t *);
static void smb_lock_free(smb_lock_t *);
+/*
+ * Return the number of range locks on the specified node.
+ */
+uint32_t
+smb_lock_get_lock_count(smb_node_t *node)
+{
+ uint32_t count;
+ SMB_NODE_VALID(node);
+
+ smb_llist_enter(&node->n_lock_list, RW_READER);
+ count = smb_llist_get_count(&node->n_ofile_list);
+ smb_llist_exit(&node->n_lock_list);
+
+ return (count);
+}
/*
* smb_unlock_range
--- a/usr/src/uts/common/fs/smbsrv/smb_node.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/fs/smbsrv/smb_node.c Fri Jul 17 17:54:42 2009 -0700
@@ -153,7 +153,7 @@
#define VALIDATE_DIR_NODE(_dir_, _node_) \
ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \
ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \
- ASSERT((_dir_)->dir_snode != (_node_));
+ ASSERT((_dir_)->n_dnode != (_node_));
static kmem_cache_t *smb_node_cache = NULL;
static boolean_t smb_node_initialized = B_FALSE;
@@ -246,7 +246,7 @@
* or newly created.
*
* If an smb_node needs to be created, a reference is also taken on the
- * dir_snode (if passed in).
+ * dnode (if passed in).
*
* See smb_node_release() for details on the release of these references.
*/
@@ -259,8 +259,8 @@
cred_t *cred,
vnode_t *vp,
char *od_name,
- smb_node_t *dir_snode,
- smb_node_t *unnamed_node)
+ smb_node_t *dnode,
+ smb_node_t *unode)
{
smb_llist_t *node_hdr;
smb_node_t *node;
@@ -277,8 +277,8 @@
* it with the list lock held.
*/
- if (unnamed_node)
- unnamed_vp = unnamed_node->vp;
+ if (unode)
+ unnamed_vp = unode->vp;
/*
* This getattr is performed on behalf of the server
@@ -323,14 +323,13 @@
case SMB_NODE_STATE_AVAILABLE:
/* The node was found. */
node->n_refcnt++;
- if ((node->dir_snode == NULL) &&
- (dir_snode != NULL) &&
+ if ((node->n_dnode == NULL) &&
+ (dnode != NULL) &&
(strcmp(od_name, "..") != 0) &&
(strcmp(od_name, ".") != 0)) {
- VALIDATE_DIR_NODE(dir_snode,
- node);
- node->dir_snode = dir_snode;
- smb_node_ref(dir_snode);
+ VALIDATE_DIR_NODE(dnode, node);
+ node->n_dnode = dnode;
+ smb_node_ref(dnode);
}
smb_node_audit(node);
@@ -371,17 +370,17 @@
if (op)
node->flags |= smb_is_executable(op->fqi.fq_last_comp);
- if (dir_snode) {
- smb_node_ref(dir_snode);
- node->dir_snode = dir_snode;
- ASSERT(dir_snode->dir_snode != node);
- ASSERT((dir_snode->vp->v_xattrdir) ||
- (dir_snode->vp->v_type == VDIR));
+ if (dnode) {
+ smb_node_ref(dnode);
+ node->n_dnode = dnode;
+ ASSERT(dnode->n_dnode != node);
+ ASSERT((dnode->vp->v_xattrdir) ||
+ (dnode->vp->v_type == VDIR));
}
- if (unnamed_node) {
- smb_node_ref(unnamed_node);
- node->unnamed_stream_node = unnamed_node;
+ if (unode) {
+ smb_node_ref(unode);
+ node->n_unode = unode;
}
DTRACE_PROBE1(smb_node_lookup_miss, smb_node_t *, node);
@@ -472,8 +471,8 @@
* then the caller with the local variable should call smb_node_release()
* directly.
*
- * smb_node_release() itself will call smb_node_release() on a node's dir_snode,
- * as smb_node_lookup() takes a hold on dir_snode.
+ * smb_node_release() itself will call smb_node_release() on a node's n_dnode,
+ * as smb_node_lookup() takes a hold on dnode.
*/
void
smb_node_release(smb_node_t *node)
@@ -499,16 +498,16 @@
*/
smb_node_delete_on_close(node);
- if (node->dir_snode) {
- ASSERT(node->dir_snode->n_magic ==
+ if (node->n_dnode) {
+ ASSERT(node->n_dnode->n_magic ==
SMB_NODE_MAGIC);
- smb_node_release(node->dir_snode);
+ smb_node_release(node->n_dnode);
}
- if (node->unnamed_stream_node) {
- ASSERT(node->unnamed_stream_node->n_magic ==
+ if (node->n_unode) {
+ ASSERT(node->n_unode->n_magic ==
SMB_NODE_MAGIC);
- smb_node_release(node->unnamed_stream_node);
+ smb_node_release(node->n_unode);
}
smb_node_free(node);
@@ -529,7 +528,7 @@
int rc = 0;
uint32_t flags = 0;
- d_snode = node->dir_snode;
+ d_snode = node->n_dnode;
if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
node->flags &= ~NODE_FLAGS_DELETE_ON_CLOSE;
flags = node->n_delete_on_close_flags;
@@ -570,9 +569,9 @@
case SMB_NODE_STATE_AVAILABLE:
case SMB_NODE_STATE_OPLOCK_GRANTED:
case SMB_NODE_STATE_OPLOCK_BREAKING:
- ret_node->dir_snode = to_dnode;
+ ret_node->n_dnode = to_dnode;
mutex_exit(&ret_node->n_mutex);
- ASSERT(to_dnode->dir_snode != ret_node);
+ ASSERT(to_dnode->n_dnode != ret_node);
ASSERT((to_dnode->vp->v_xattrdir) ||
(to_dnode->vp->v_type == VDIR));
smb_node_release(from_dnode);
@@ -956,10 +955,9 @@
node->n_orig_uid = 0;
node->readonly_creator = NULL;
node->waiting_event = 0;
- node->what = 0;
node->n_open_count = 0;
- node->dir_snode = NULL;
- node->unnamed_stream_node = NULL;
+ node->n_dnode = NULL;
+ node->n_unode = NULL;
node->delete_on_close_cred = NULL;
node->n_delete_on_close_flags = 0;
--- a/usr/src/uts/common/fs/smbsrv/smb_ofile.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/fs/smbsrv/smb_ofile.c Fri Jul 17 17:54:42 2009 -0700
@@ -164,10 +164,14 @@
#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_fsops.h>
-/* Static functions defined further down this file. */
-static void smb_ofile_delete(smb_ofile_t *of);
-static smb_ofile_t *smb_ofile_close_and_next(smb_ofile_t *of);
+static boolean_t smb_ofile_is_open_locked(smb_ofile_t *);
+static void smb_ofile_delete(smb_ofile_t *);
+static smb_ofile_t *smb_ofile_close_and_next(smb_ofile_t *);
static void smb_ofile_set_close_attrs(smb_ofile_t *, uint32_t);
+static int smb_ofile_netinfo_encode(smb_ofile_t *, uint8_t *, size_t,
+ uint32_t *);
+static int smb_ofile_netinfo_init(smb_ofile_t *, smb_netfileinfo_t *);
+static void smb_ofile_netinfo_fini(smb_netfileinfo_t *);
/*
* smb_ofile_open
@@ -277,6 +281,7 @@
smb_llist_enter(&tree->t_ofile_list, RW_WRITER);
smb_llist_insert_tail(&tree->t_ofile_list, of);
smb_llist_exit(&tree->t_ofile_list);
+ atomic_inc_32(&tree->t_open_files);
atomic_inc_32(&tree->t_server->sv_open_files);
atomic_inc_32(&of->f_session->s_file_cnt);
@@ -328,6 +333,7 @@
if (of->f_node->flags & NODE_FLAGS_NOTIFY_CHANGE)
smb_process_file_notify_change_queue(of);
}
+ atomic_dec_32(&of->f_tree->t_open_files);
atomic_dec_32(&of->f_tree->t_server->sv_open_files);
mutex_enter(&of->f_mutex);
@@ -409,6 +415,70 @@
}
/*
+ * If the enumeration request is for ofile data, handle it here.
+ * Otherwise, return.
+ *
+ * This function should be called with a hold on the ofile.
+ */
+int
+smb_ofile_enum(smb_ofile_t *of, smb_svcenum_t *svcenum)
+{
+ uint8_t *pb;
+ uint_t nbytes;
+ int rc;
+
+ ASSERT(of);
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+ ASSERT(of->f_refcnt);
+
+ if (svcenum->se_type != SMB_SVCENUM_TYPE_FILE)
+ return (0);
+
+ if (svcenum->se_nskip > 0) {
+ svcenum->se_nskip--;
+ return (0);
+ }
+
+ if (svcenum->se_nitems >= svcenum->se_nlimit) {
+ svcenum->se_nitems = svcenum->se_nlimit;
+ return (0);
+ }
+
+ pb = &svcenum->se_buf[svcenum->se_bused];
+
+ rc = smb_ofile_netinfo_encode(of, pb, svcenum->se_bavail,
+ &nbytes);
+ if (rc == 0) {
+ svcenum->se_bavail -= nbytes;
+ svcenum->se_bused += nbytes;
+ svcenum->se_nitems++;
+ }
+
+ return (rc);
+}
+
+/*
+ * Take a reference on an open file.
+ */
+boolean_t
+smb_ofile_hold(smb_ofile_t *of)
+{
+ ASSERT(of);
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+
+ mutex_enter(&of->f_mutex);
+
+ if (smb_ofile_is_open_locked(of)) {
+ of->f_refcnt++;
+ mutex_exit(&of->f_mutex);
+ return (B_TRUE);
+ }
+
+ mutex_exit(&of->f_mutex);
+ return (B_FALSE);
+}
+
+/*
* smb_ofile_release
*
*/
@@ -487,6 +557,71 @@
}
/*
+ * smb_ofile_lookup_by_uniqid
+ *
+ * Find the open file whose uniqid matches the one specified in the request.
+ */
+smb_ofile_t *
+smb_ofile_lookup_by_uniqid(smb_tree_t *tree, uint32_t uniqid)
+{
+ smb_llist_t *of_list;
+ smb_ofile_t *of;
+
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+ of_list = &tree->t_ofile_list;
+ smb_llist_enter(of_list, RW_READER);
+ of = smb_llist_head(of_list);
+
+ while (of) {
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+ ASSERT(of->f_tree == tree);
+
+ if (of->f_uniqid == uniqid) {
+ if (smb_ofile_hold(of)) {
+ smb_llist_exit(of_list);
+ return (of);
+ }
+ }
+
+ of = smb_llist_next(of_list, of);
+ }
+
+ smb_llist_exit(of_list);
+ return (NULL);
+}
+
+/*
+ * Disallow NetFileClose on certain ofiles to avoid side-effects.
+ * Closing a tree root is not allowed: use NetSessionDel or NetShareDel.
+ * Closing SRVSVC connections is not allowed because this NetFileClose
+ * request may depend on this ofile.
+ */
+boolean_t
+smb_ofile_disallow_fclose(smb_ofile_t *of)
+{
+ ASSERT(of);
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+ ASSERT(of->f_refcnt);
+
+ switch (of->f_ftype) {
+ case SMB_FTYPE_DISK:
+ ASSERT(of->f_tree);
+ return (of->f_node == of->f_tree->t_snode);
+
+ case SMB_FTYPE_MESG_PIPE:
+ ASSERT(of->f_pipe);
+ if (utf8_strcasecmp(of->f_pipe->p_name, "SRVSVC") == 0)
+ return (B_TRUE);
+ break;
+ default:
+ break;
+ }
+
+ return (B_FALSE);
+}
+
+/*
* smb_ofile_set_flags
*
* Return value:
@@ -588,14 +723,12 @@
boolean_t
smb_ofile_is_open(smb_ofile_t *of)
{
- boolean_t rc = B_FALSE;
+ boolean_t rc;
SMB_OFILE_VALID(of);
mutex_enter(&of->f_mutex);
- if (of->f_state == SMB_OFILE_STATE_OPEN) {
- rc = B_TRUE;
- }
+ rc = smb_ofile_is_open_locked(of);
mutex_exit(&of->f_mutex);
return (rc);
}
@@ -674,6 +807,27 @@
/* *************************** Static Functions ***************************** */
/*
+ * Determine whether or not an ofile is open.
+ * This function must be called with the mutex held.
+ */
+static boolean_t
+smb_ofile_is_open_locked(smb_ofile_t *of)
+{
+ switch (of->f_state) {
+ case SMB_OFILE_STATE_OPEN:
+ return (B_TRUE);
+
+ case SMB_OFILE_STATE_CLOSING:
+ case SMB_OFILE_STATE_CLOSED:
+ return (B_FALSE);
+
+ default:
+ ASSERT(0);
+ return (B_FALSE);
+ }
+}
+
+/*
* smb_ofile_set_close_attrs
*
* Updates timestamps, size and readonly bit.
@@ -1038,3 +1192,107 @@
of->f_flags |= SMB_OFLAGS_SET_DELETE_ON_CLOSE;
mutex_exit(&of->f_mutex);
}
+
+/*
+ * Encode open file information into a buffer; needed in user space to
+ * support RPC requests.
+ */
+static int
+smb_ofile_netinfo_encode(smb_ofile_t *of, uint8_t *buf, size_t buflen,
+ uint32_t *nbytes)
+{
+ smb_netfileinfo_t fi;
+ int rc;
+
+ rc = smb_ofile_netinfo_init(of, &fi);
+ if (rc == 0) {
+ rc = smb_netfileinfo_encode(&fi, buf, buflen, nbytes);
+ smb_ofile_netinfo_fini(&fi);
+ }
+
+ return (rc);
+}
+
+static int
+smb_ofile_netinfo_init(smb_ofile_t *of, smb_netfileinfo_t *fi)
+{
+ smb_user_t *user;
+ smb_tree_t *tree;
+ smb_node_t *node;
+ char *path;
+ char *buf;
+ int rc;
+
+ ASSERT(of);
+ user = of->f_user;
+ tree = of->f_tree;
+ ASSERT(user);
+ ASSERT(tree);
+
+ buf = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+
+ switch (of->f_ftype) {
+ case SMB_FTYPE_DISK:
+ node = of->f_node;
+ ASSERT(node);
+
+ fi->fi_permissions = of->f_granted_access;
+ fi->fi_numlocks = smb_lock_get_lock_count(node);
+
+ path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
+
+ if (node != tree->t_snode) {
+ rc = vnodetopath(tree->t_snode->vp, node->vp, path,
+ MAXPATHLEN, kcred);
+ if (rc == 0)
+ (void) strsubst(path, '/', '\\');
+ else
+ (void) strlcpy(path, node->od_name, MAXPATHLEN);
+ }
+
+ (void) snprintf(buf, MAXPATHLEN, "%s:%s", tree->t_sharename,
+ path);
+ kmem_free(path, MAXPATHLEN);
+ break;
+
+ case SMB_FTYPE_MESG_PIPE:
+ ASSERT(of->f_pipe);
+
+ fi->fi_permissions = FILE_READ_DATA | FILE_WRITE_DATA |
+ FILE_EXECUTE;
+ fi->fi_numlocks = 0;
+ (void) snprintf(buf, MAXPATHLEN, "\\PIPE\\%s",
+ of->f_pipe->p_name);
+ break;
+
+ default:
+ kmem_free(buf, MAXPATHLEN);
+ return (-1);
+ }
+
+ fi->fi_fid = of->f_fid;
+ fi->fi_uniqid = of->f_uniqid;
+ fi->fi_pathlen = strlen(buf) + 1;
+ fi->fi_path = smb_kstrdup(buf, fi->fi_pathlen);
+ kmem_free(buf, MAXPATHLEN);
+
+ fi->fi_namelen = user->u_domain_len + user->u_name_len + 2;
+ fi->fi_username = kmem_alloc(fi->fi_namelen, KM_SLEEP);
+ (void) snprintf(fi->fi_username, fi->fi_namelen, "%s\\%s",
+ user->u_domain, user->u_name);
+ return (0);
+}
+
+static void
+smb_ofile_netinfo_fini(smb_netfileinfo_t *fi)
+{
+ if (fi == NULL)
+ return;
+
+ if (fi->fi_path)
+ kmem_free(fi->fi_path, fi->fi_pathlen);
+ if (fi->fi_username)
+ kmem_free(fi->fi_username, fi->fi_namelen);
+
+ bzero(fi, sizeof (smb_netfileinfo_t));
+}
--- a/usr/src/uts/common/fs/smbsrv/smb_opipe.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/fs/smbsrv/smb_opipe.c Fri Jul 17 17:54:42 2009 -0700
@@ -143,13 +143,14 @@
* The full pipe path will be in the form \\PIPE\\SERVICE. The first part
* can be assumed, so all we need here are the service names.
*
- * Returns a pointer to the pipe name (without any leading \'s) on sucess.
+ * Returns a pointer to the pipe name (without any leading \'s) on success.
* Otherwise returns a null pointer.
*/
static char *
smb_opipe_lookup(const char *path)
{
static char *named_pipes[] = {
+ "lsass",
"LSARPC",
"NETLOGON",
"SAMR",
@@ -188,14 +189,14 @@
static int
smb_opipe_do_open(smb_request_t *sr, smb_opipe_t *opipe)
{
- smb_opipe_context_t *ctx = &opipe->p_context;
+ smb_netuserinfo_t *userinfo = &opipe->p_user;
smb_user_t *user = sr->uid_user;
uint8_t *buf = opipe->p_doorbuf;
uint32_t buflen = SMB_OPIPE_DOOR_BUFSIZE;
uint32_t len;
- smb_user_context_init(user, ctx);
- len = xdr_sizeof(smb_opipe_context_xdr, ctx);
+ smb_user_netinfo_init(user, userinfo);
+ len = xdr_sizeof(smb_netuserinfo_xdr, userinfo);
bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t));
opipe->p_hdr.oh_magic = SMB_OPIPE_HDR_MAGIC;
@@ -208,7 +209,7 @@
buf += len;
buflen -= len;
- if (smb_opipe_context_encode(ctx, buf, buflen, NULL) == -1)
+ if (smb_netuserinfo_encode(userinfo, buf, buflen, NULL) == -1)
return (-1);
return (smb_opipe_door_call(opipe));
@@ -266,7 +267,7 @@
kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE);
}
- smb_user_context_fini(&opipe->p_context);
+ smb_user_netinfo_fini(&opipe->p_user);
smb_opipe_exit(opipe);
cv_destroy(&opipe->p_cv);
mutex_destroy(&opipe->p_mutex);
@@ -620,48 +621,3 @@
opipe->p_hdr.oh_resid = hdr.oh_resid;
return (0);
}
-
-void
-smb_user_context_init(smb_user_t *user, smb_opipe_context_t *ctx)
-{
- smb_session_t *session;
-
- ASSERT(user);
- ASSERT(user->u_domain);
- ASSERT(user->u_name);
-
- session = user->u_session;
- ASSERT(session);
- ASSERT(session->workstation);
-
- ctx->oc_session_id = session->s_kid;
- ctx->oc_native_os = session->native_os;
- ctx->oc_ipaddr = session->ipaddr;
- ctx->oc_uid = user->u_uid;
- ctx->oc_logon_time = user->u_logon_time;
- ctx->oc_flags = user->u_flags;
-
- ctx->oc_domain_len = user->u_domain_len;
- ctx->oc_domain = smb_kstrdup(user->u_domain, ctx->oc_domain_len);
-
- ctx->oc_account_len = user->u_name_len;
- ctx->oc_account = smb_kstrdup(user->u_name, ctx->oc_account_len);
-
- ctx->oc_workstation_len = strlen(session->workstation) + 1;
- ctx->oc_workstation = smb_kstrdup(session->workstation,
- ctx->oc_workstation_len);
-}
-
-void
-smb_user_context_fini(smb_opipe_context_t *ctx)
-{
- if (ctx) {
- if (ctx->oc_domain)
- kmem_free(ctx->oc_domain, ctx->oc_domain_len);
- if (ctx->oc_account)
- kmem_free(ctx->oc_account, ctx->oc_account_len);
- if (ctx->oc_workstation)
- kmem_free(ctx->oc_workstation, ctx->oc_workstation_len);
- bzero(ctx, sizeof (smb_opipe_context_t));
- }
-}
--- a/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c Fri Jul 17 17:54:42 2009 -0700
@@ -367,7 +367,7 @@
* ENOENT will be returned.
*
* Path components are processed one at a time so that smb_nodes can be
- * created for each component. This allows the dir_snode field in the
+ * created for each component. This allows the n_dnode field in the
* smb_node to be properly populated.
*
* Because of the above, links are also processed in this routine
--- a/usr/src/uts/common/fs/smbsrv/smb_query_information.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/fs/smbsrv/smb_query_information.c Fri Jul 17 17:54:42 2009 -0700
@@ -102,9 +102,9 @@
timestruc_t *mtime;
if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
- rc = smbsr_encode_result(sr, 10, 0, "bwll10.w",
- 10, FILE_ATTRIBUTE_NORMAL, 0, 0, 0);
- return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
+ smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
+ ERROR_ACCESS_DENIED);
+ return (SDRC_ERROR);
}
if ((rc = smb_pathname_reduce(sr, sr->user_cr, path,
--- a/usr/src/uts/common/fs/smbsrv/smb_query_information2.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/fs/smbsrv/smb_query_information2.c Fri Jul 17 17:54:42 2009 -0700
@@ -93,8 +93,9 @@
}
if (sr->fid_ofile->f_ftype != SMB_FTYPE_DISK) {
- smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
- return (SDRC_ERROR);
+ rc = smbsr_encode_result(sr, 11, 0, "blllllww",
+ 11, 0, 0, 0, 0, 0, 0, 0);
+ return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
node = sr->fid_ofile->f_node;
--- a/usr/src/uts/common/fs/smbsrv/smb_server.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/fs/smbsrv/smb_server.c Fri Jul 17 17:54:42 2009 -0700
@@ -236,8 +236,6 @@
in_port_t, int, int);
static int smb_server_lookup(smb_server_t **);
static void smb_server_release(smb_server_t *);
-static int smb_server_ulist_geti(smb_session_list_t *, uint32_t,
- uint8_t *, uint32_t, uint_t *);
static void smb_server_store_cfg(smb_server_t *, smb_ioc_cfg_t *);
static void smb_server_stop(smb_server_t *);
static int smb_server_fsop_start(smb_server_t *);
@@ -246,6 +244,11 @@
static void smb_server_disconnect_share(char *, smb_server_t *);
static void smb_server_thread_unexport(smb_thread_t *, void *);
+static void smb_server_enum_private(smb_session_list_t *, smb_svcenum_t *);
+static int smb_server_sesion_disconnect(smb_session_list_t *, const char *,
+ const char *);
+static int smb_server_fclose(smb_session_list_t *, uint32_t);
+
static smb_llist_t smb_servers;
/*
@@ -253,7 +256,8 @@
* **************** Functions called from the device interface *****************
* *****************************************************************************
*
- * These functions determine the relevant smb server to which the call apply.
+ * These functions typically have to determine the relevant smb server
+ * to which the call applies.
*/
/*
@@ -759,75 +763,117 @@
}
int
-smb_server_user_number(smb_ioc_usernum_t *ioc)
+smb_server_numopen(smb_ioc_opennum_t *ioc)
{
smb_server_t *sv;
int rc;
if ((rc = smb_server_lookup(&sv)) == 0) {
- ioc->num = sv->sv_open_users;
- smb_server_release(sv);
- }
- return (rc);
-}
-
-int
-smb_server_user_list(smb_ioc_ulist_t *ioc)
-{
- smb_server_t *sv;
- uint8_t *data;
- uint32_t data_len;
- uint_t bytes_encoded;
- int rc;
-
- if ((rc = smb_server_lookup(&sv)) == 0) {
-
- bytes_encoded = 0;
- data = ioc->data;
- data_len = ioc->data_len;
- ioc->num =
- smb_server_ulist_geti(&sv->sv_nbt_daemon.ld_session_list,
- ioc->cookie, data, data_len, &bytes_encoded);
-
- data += bytes_encoded;
- data_len -= bytes_encoded;
- ioc->data_len = bytes_encoded;
- ioc->cookie += ioc->num;
-
- ioc->num +=
- smb_server_ulist_geti(&sv->sv_tcp_daemon.ld_session_list,
- ioc->cookie, data, data_len, &bytes_encoded);
-
- ioc->data_len += bytes_encoded;
-
+ ioc->open_users = sv->sv_open_users;
+ ioc->open_trees = sv->sv_open_trees;
+ ioc->open_files = sv->sv_open_files;
smb_server_release(sv);
}
return (rc);
}
/*
- * *****************************************************************************
- * ****************** Functions called from the door interface *****************
- * *****************************************************************************
- *
+ * Enumerate objects within the server. The svcenum provides the
+ * enumeration context, i.e. what the caller want to get back.
+ */
+int
+smb_server_enum(smb_ioc_svcenum_t *ioc)
+{
+ smb_svcenum_t *svcenum = &ioc->svcenum;
+ smb_server_t *sv;
+ smb_session_list_t *se;
+ int rc;
+
+ switch (svcenum->se_type) {
+ case SMB_SVCENUM_TYPE_USER:
+ case SMB_SVCENUM_TYPE_TREE:
+ case SMB_SVCENUM_TYPE_FILE:
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ if ((rc = smb_server_lookup(&sv)) != 0)
+ return (rc);
+
+ svcenum->se_bavail = svcenum->se_buflen;
+ svcenum->se_bused = 0;
+ svcenum->se_nitems = 0;
+
+ se = &sv->sv_nbt_daemon.ld_session_list;
+ smb_server_enum_private(se, svcenum);
+
+ se = &sv->sv_tcp_daemon.ld_session_list;
+ smb_server_enum_private(se, svcenum);
+
+ smb_server_release(sv);
+ return (0);
+}
+
+/*
+ * Look for sessions to disconnect by client and user name.
+ */
+int
+smb_server_session_close(smb_ioc_session_t *ioc)
+{
+ smb_session_list_t *se;
+ smb_server_t *sv;
+ int nbt_cnt;
+ int tcp_cnt;
+ int rc;
+
+ if ((rc = smb_server_lookup(&sv)) != 0)
+ return (rc);
+
+ se = &sv->sv_nbt_daemon.ld_session_list;
+ nbt_cnt = smb_server_sesion_disconnect(se, ioc->client, ioc->username);
+
+ se = &sv->sv_tcp_daemon.ld_session_list;
+ tcp_cnt = smb_server_sesion_disconnect(se, ioc->client, ioc->username);
+
+ smb_server_release(sv);
+
+ if ((nbt_cnt == 0) && (tcp_cnt == 0))
+ return (ENOENT);
+ return (0);
+}
+
+/*
+ * Close a file by uniqid.
+ */
+int
+smb_server_file_close(smb_ioc_fileid_t *ioc)
+{
+ uint32_t uniqid = ioc->uniqid;
+ smb_session_list_t *se;
+ smb_server_t *sv;
+ int rc;
+
+ if ((rc = smb_server_lookup(&sv)) != 0)
+ return (rc);
+
+ se = &sv->sv_nbt_daemon.ld_session_list;
+ rc = smb_server_fclose(se, uniqid);
+
+ if (rc == ENOENT) {
+ se = &sv->sv_tcp_daemon.ld_session_list;
+ rc = smb_server_fclose(se, uniqid);
+ }
+
+ smb_server_release(sv);
+ return (rc);
+}
+
+/*
* These functions determine the relevant smb server to which the call apply.
*/
uint32_t
-smb_server_get_user_count(void)
-{
- smb_server_t *sv;
- uint32_t counter = 0;
-
- if (smb_server_lookup(&sv) == 0) {
- counter = (uint32_t)sv->sv_open_users;
- smb_server_release(sv);
- }
-
- return (counter);
-}
-
-uint32_t
smb_server_get_session_count(void)
{
smb_server_t *sv;
@@ -1422,51 +1468,140 @@
mutex_exit(&sv->sv_mutex);
}
-static int
-smb_server_ulist_geti(smb_session_list_t *se, uint32_t cookie,
- uint8_t *buf, uint32_t buf_len, uint_t *pbe)
+/*
+ * Enumerate the users associated with a session list.
+ */
+static void
+smb_server_enum_private(smb_session_list_t *se, smb_svcenum_t *svcenum)
{
- smb_session_t *sn = NULL;
- smb_user_t *user;
- smb_llist_t *ulist;
- smb_opipe_context_t ctx;
- uint_t bytes_encoded;
- int rc = 0;
- int cnt = 0;
+ smb_session_t *sn;
+ smb_llist_t *ulist;
+ smb_user_t *user;
+ int rc = 0;
rw_enter(&se->se_lock, RW_READER);
sn = list_head(&se->se_act.lst);
- while ((sn != NULL) && (rc == 0)) {
+
+ while (sn != NULL) {
ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
ulist = &sn->s_user_list;
smb_llist_enter(ulist, RW_READER);
user = smb_llist_head(ulist);
- while ((user != NULL) && (rc == 0)) {
- ASSERT(user->u_magic == SMB_USER_MAGIC);
- mutex_enter(&user->u_mutex);
- if ((user->u_state == SMB_USER_STATE_LOGGED_IN) &&
- (cookie == 0)) {
- smb_user_context_init(user, &ctx);
- rc = smb_opipe_context_encode(&ctx, buf,
- buf_len, &bytes_encoded);
- smb_user_context_fini(&ctx);
- if (rc == 0) {
- *pbe += bytes_encoded;
- buf += bytes_encoded;
- buf_len -= bytes_encoded;
- cnt++;
+
+ while (user != NULL) {
+ if (smb_user_hold(user)) {
+ rc = smb_user_enum(user, svcenum);
+ smb_user_release(user);
+ }
+
+ user = smb_llist_next(ulist, user);
+ }
+
+ smb_llist_exit(ulist);
+
+ if (rc != 0)
+ break;
+
+ sn = list_next(&se->se_act.lst, sn);
+ }
+
+ rw_exit(&se->se_lock);
+}
+
+/*
+ * Disconnect sessions associated with the specified client and username.
+ * Empty strings are treated as wildcards.
+ */
+static int
+smb_server_sesion_disconnect(smb_session_list_t *se,
+ const char *client, const char *name)
+{
+ smb_session_t *sn;
+ smb_llist_t *ulist;
+ smb_user_t *user;
+ boolean_t match;
+ int count = 0;
+
+ rw_enter(&se->se_lock, RW_READER);
+ sn = list_head(&se->se_act.lst);
+
+ while (sn != NULL) {
+ ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
+
+ if ((*client != '\0') && (!smb_session_isclient(sn, client))) {
+ sn = list_next(&se->se_act.lst, sn);
+ continue;
+ }
+
+ ulist = &sn->s_user_list;
+ smb_llist_enter(ulist, RW_READER);
+ user = smb_llist_head(ulist);
+
+ while (user != NULL) {
+ if (smb_user_hold(user)) {
+ match = (*name == '\0');
+ if (!match)
+ match = smb_user_namecmp(user, name);
+
+ if (match) {
+ smb_llist_exit(ulist);
+ smb_user_logoff(user);
+ ++count;
+ smb_user_release(user);
+ smb_llist_enter(ulist, RW_READER);
+ user = smb_llist_head(ulist);
+ continue;
}
+
+ smb_user_release(user);
}
- mutex_exit(&user->u_mutex);
+
user = smb_llist_next(ulist, user);
- if (cookie > 0)
- cookie--;
}
+
smb_llist_exit(ulist);
sn = list_next(&se->se_act.lst, sn);
}
+
rw_exit(&se->se_lock);
- return (cnt);
+ return (count);
+}
+
+/*
+ * Close a file by its unique id.
+ */
+static int
+smb_server_fclose(smb_session_list_t *se, uint32_t uniqid)
+{
+ smb_session_t *sn;
+ smb_llist_t *ulist;
+ smb_user_t *user;
+ int rc = ENOENT;
+
+ rw_enter(&se->se_lock, RW_READER);
+ sn = list_head(&se->se_act.lst);
+
+ while ((sn != NULL) && (rc == ENOENT)) {
+ ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
+ ulist = &sn->s_user_list;
+ smb_llist_enter(ulist, RW_READER);
+ user = smb_llist_head(ulist);
+
+ while ((user != NULL) && (rc == ENOENT)) {
+ if (smb_user_hold(user)) {
+ rc = smb_user_fclose(user, uniqid);
+ smb_user_release(user);
+ }
+
+ user = smb_llist_next(ulist, user);
+ }
+
+ smb_llist_exit(ulist);
+ sn = list_next(&se->se_act.lst, sn);
+ }
+
+ rw_exit(&se->se_lock);
+ return (rc);
}
static void
--- a/usr/src/uts/common/fs/smbsrv/smb_session.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/fs/smbsrv/smb_session.c Fri Jul 17 17:54:42 2009 -0700
@@ -1041,13 +1041,8 @@
ASSERT(user->u_magic == SMB_USER_MAGIC);
if (!utf8_strcasecmp(user->u_name, name) &&
!utf8_strcasecmp(user->u_domain, domain)) {
- mutex_enter(&user->u_mutex);
- if (user->u_state == SMB_USER_STATE_LOGGED_IN) {
- user->u_refcnt++;
- mutex_exit(&user->u_mutex);
+ if (smb_user_hold(user))
break;
- }
- mutex_exit(&user->u_mutex);
}
user = smb_llist_next(ulist, user);
}
@@ -1084,6 +1079,64 @@
}
/*
+ * Copy the session workstation/client name to buf. If the workstation
+ * is an empty string (which it will be on TCP connections), use the
+ * client IP address.
+ */
+void
+smb_session_getclient(smb_session_t *sn, char *buf, size_t buflen)
+{
+ char ipbuf[INET6_ADDRSTRLEN];
+ smb_inaddr_t *ipaddr;
+
+ ASSERT(sn);
+ ASSERT(buf);
+ ASSERT(buflen);
+
+ *buf = '\0';
+
+ if (sn->workstation[0] != '\0') {
+ (void) strlcpy(buf, sn->workstation, buflen);
+ return;
+ }
+
+ ipaddr = &sn->ipaddr;
+ if (smb_inet_ntop(ipaddr, ipbuf, SMB_IPSTRLEN(ipaddr->a_family)))
+ (void) strlcpy(buf, ipbuf, buflen);
+}
+
+/*
+ * Check whether or not the specified client name is the client of this
+ * session. The name may be in UNC format (\\CLIENT).
+ *
+ * A workstation/client name is setup on NBT connections as part of the
+ * NetBIOS session request but that isn't available on TCP connections.
+ * If the session doesn't have a client name we typically return the
+ * client IP address as the workstation name on MSRPC requests. So we
+ * check for the IP address here in addition to the workstation name.
+ */
+boolean_t
+smb_session_isclient(smb_session_t *sn, const char *client)
+{
+ char buf[INET6_ADDRSTRLEN];
+ smb_inaddr_t *ipaddr;
+
+ client += strspn(client, "\\");
+
+ if (utf8_strcasecmp(client, sn->workstation) == 0)
+ return (B_TRUE);
+
+ ipaddr = &sn->ipaddr;
+ if (smb_inet_ntop(ipaddr, buf, SMB_IPSTRLEN(ipaddr->a_family)) == NULL)
+ return (B_FALSE);
+
+ if (utf8_strcasecmp(client, buf) == 0)
+ return (B_TRUE);
+
+ return (B_FALSE);
+}
+
+/*
* smb_request_alloc
*
* Allocate an smb_request_t structure from the kmem_cache. Partially
@@ -1171,7 +1224,7 @@
void
dump_smb_inaddr(smb_inaddr_t *ipaddr)
{
-char ipstr[INET6_ADDRSTRLEN];
+ char ipstr[INET6_ADDRSTRLEN];
if (smb_inet_ntop(ipaddr, ipstr, SMB_IPSTRLEN(ipaddr->a_family)))
cmn_err(CE_WARN, "error ipstr=%s", ipstr);
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c Fri Jul 17 17:54:42 2009 -0700
@@ -519,8 +519,12 @@
if (count != 0)
smb_odir_save_cookie(od, 0, cookie);
- /* if eos not already detected, check if more entries */
- if (!*eos)
+ /*
+ * If all retrieved entries have been successfully encoded
+ * and eos has not already been detected, check if there are
+ * any more entries. eos will be set if there are no more.
+ */
+ if ((rc == 0) && (!*eos))
(void) smb_odir_read_fileinfo(sr, od, &fileinfo, eos);
return (count);
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c Fri Jul 17 17:54:42 2009 -0700
@@ -52,6 +52,8 @@
#include <smbsrv/smb_fsops.h>
uint32_t smb_pad_align(uint32_t offset, uint32_t align);
+void smb_encode_smb_datetimes(smb_request_t *, smb_xa_t *, smb_attr_t *);
+void smb_encode_nt_times(smb_request_t *, smb_xa_t *, smb_attr_t *);
extern int smb_query_all_info_filename(smb_tree_t *, smb_node_t *,
char *, size_t);
@@ -80,11 +82,10 @@
u_offset_t datasz = 0, allocsz = 0;
smb_attr_t *ap = NULL;
char *namep = NULL;
- char *filename = NULL, *alt_nm_ptr = NULL;
+ char *filename = NULL;
int filename_len = 0;
smb_node_t *node = NULL; /* only set for SMB_FTYPE_DISK files */
- smb_node_t *dir_snode = NULL;
- timestruc_t *creation_time = NULL;
+ smb_node_t *dnode = NULL;
unsigned char delete_on_close = 0;
unsigned char is_dir = 0;
char *filebuf = NULL;
@@ -133,7 +134,6 @@
}
dattr = ap->sa_dosattr;
- creation_time = &ap->sa_crtime;
if (smb_node_is_dir(node)) {
is_dir = 1;
@@ -144,31 +144,55 @@
allocsz = ap->sa_vattr.va_nblocks * DEV_BSIZE;
}
- dir_snode = node->dir_snode;
+ dnode = node->n_dnode;
delete_on_close =
(node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0;
+
+ /*
+ * The number of links reported should be the number of
+ * non-deleted links. Thus if delete_on_close is set,
+ * decrement the link count.
+ */
+ if (delete_on_close && ap->sa_vattr.va_nlink > 0)
+ --(ap->sa_vattr.va_nlink);
+
}
break;
case SMB_FTYPE_MESG_PIPE:
{
- /*
- * The pipe is only valid for SMB_FTYPE_MESG_PIPE files.
- */
+ /* The pipe is only valid for SMB_FTYPE_MESG_PIPE files */
namep = sr->fid_ofile->f_pipe->p_name;
filename = namep;
filename_len = smb_ascii_or_unicode_strlen(sr, filename);
ap = &pipe_attr;
- creation_time = (timestruc_t *)&ap->sa_vattr.va_ctime;
+ ap->sa_vattr.va_nlink = 1;
dattr = FILE_ATTRIBUTE_NORMAL;
datasz = allocsz = 0;
- delete_on_close = 0;
+ delete_on_close = 1;
is_dir = 0;
+
+ /* some levels are not valid for pipes */
+ switch (infolev) {
+ case SMB_QUERY_FILE_ALT_NAME_INFO:
+ case SMB_FILE_ALT_NAME_INFORMATION:
+ case SMB_QUERY_FILE_STREAM_INFO:
+ case SMB_FILE_STREAM_INFORMATION:
+ case SMB_QUERY_FILE_COMPRESSION_INFO:
+ case SMB_FILE_COMPRESSION_INFORMATION:
+ case SMB_FILE_ATTR_TAG_INFORMATION:
+ smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ return (SDRC_ERROR);
+ case SMB_INFO_QUERY_ALL_EAS:
+ smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ return (SDRC_ERROR);
+ }
}
break;
-
default:
smbsr_error(sr, 0, ERRDOS, ERRbadfile);
return (SDRC_ERROR);
@@ -188,16 +212,14 @@
if (allocsz > UINT_MAX)
allocsz = UINT_MAX;
+ /* unlike other levels attributes should be 0 here for pipes */
+ if (sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE)
+ dattr = 0;
+
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb,
- ((sr->session->native_os == NATIVE_OS_WIN95)
- ? "YYYllw" : "yyyllw"),
- smb_gmt2local(sr, creation_time->tv_sec),
- smb_gmt2local(sr, ap->sa_vattr.va_atime.tv_sec),
- smb_gmt2local(sr, ap->sa_vattr.va_mtime.tv_sec),
- (uint32_t)datasz,
- (uint32_t)allocsz,
- dattr);
+ smb_encode_smb_datetimes(sr, xa, ap);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "llw",
+ (uint32_t)datasz, (uint32_t)allocsz, dattr);
break;
case SMB_INFO_QUERY_EA_SIZE:
@@ -206,20 +228,18 @@
if (allocsz > UINT_MAX)
allocsz = UINT_MAX;
+ /* unlike other levels attributes should be 0 here for pipes */
+ if (sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE)
+ dattr = 0;
+
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb,
- ((sr->session->native_os == NATIVE_OS_WIN95)
- ? "YYYllwl" : "yyyllwl"),
- smb_gmt2local(sr, creation_time->tv_sec),
- smb_gmt2local(sr, ap->sa_vattr.va_atime.tv_sec),
- smb_gmt2local(sr, ap->sa_vattr.va_mtime.tv_sec),
- (uint32_t)datasz,
- (uint32_t)allocsz,
- dattr, 0);
+ smb_encode_smb_datetimes(sr, xa, ap);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "llwl",
+ (uint32_t)datasz, (uint32_t)allocsz, dattr, 0);
break;
+ case SMB_INFO_QUERY_ALL_EAS:
case SMB_INFO_QUERY_EAS_FROM_LIST:
- case SMB_INFO_QUERY_ALL_EAS:
case SMB_FILE_EA_INFORMATION:
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
(void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
@@ -236,12 +256,8 @@
* Similar change in smb_trans2_query_path_information.c.
*/
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.",
- creation_time,
- &ap->sa_vattr.va_atime,
- &ap->sa_vattr.va_mtime,
- &ap->sa_vattr.va_ctime,
- dattr);
+ smb_encode_nt_times(sr, xa, ap);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "w6.", dattr);
break;
case SMB_QUERY_FILE_STANDARD_INFO:
@@ -294,19 +310,28 @@
case SMB_QUERY_FILE_ALL_INFO:
case SMB_FILE_ALL_INFORMATION:
+ if (sr->fid_ofile->f_ftype == SMB_FTYPE_DISK) {
+ rc = smb_query_all_info_filename(sr->tid_tree, node,
+ filebuf, MAXPATHLEN);
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ kmem_free(filebuf, MAXPATHLEN+1);
+ return (SDRC_ERROR);
+ }
+ filename = filebuf;
+ } else {
+ /* If the leading \ is missing, add it. */
+ if (*namep != '\\') {
+ (void) snprintf(filebuf, MAXNAMELEN,
+ "\\%s", namep);
+ filename = filebuf;
+ }
+ }
+ filename_len = smb_ascii_or_unicode_strlen(sr, filename);
+
/*
- * The reply of this information level on the
- * wire doesn't match with protocol specification.
- * This is what spec. needs: "TTTTwqqlbbqllqqll"
- * But this is actually is sent on the wire:
- * "TTTTw6.qqlbb2.l"
- * So, there is a 6-byte pad between Attributes and
- * AllocationSize. Also there is a 2-byte pad After
- * Directory field. Between Directory and FileNameLength
- * there is just 4 bytes that it seems is AlignmentRequirement.
- * There are 6 other fields between Directory and
- * AlignmentRequirement in spec. that aren't sent
- * on the wire.
+ * There is a 6-byte pad between Attributes and AllocationSize,
+ * and a 2-byte pad after the Directory field.
*/
if (node) {
rc = smb_query_all_info_filename(sr->tid_tree, node,
@@ -322,11 +347,8 @@
}
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.qqlbb2.l",
- creation_time,
- &ap->sa_vattr.va_atime,
- &ap->sa_vattr.va_mtime,
- &ap->sa_vattr.va_ctime,
+ smb_encode_nt_times(sr, xa, ap);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "w6.qqlbb2.l",
dattr,
(uint64_t)allocsz,
(uint64_t)datasz,
@@ -342,43 +364,41 @@
case SMB_QUERY_FILE_ALT_NAME_INFO:
case SMB_FILE_ALT_NAME_INFORMATION:
/*
- * Conform to the rule used by Windows NT/2003 servers.
- * Shortname is created only if either the filename or
- * extension portion of a file is made up of mixed case.
- *
- * If the shortname is generated, it will be returned as
- * the alternative name. Otherwise, convert the original
- * name to all upper-case and return it as the alternative
- * name.
+ * If the shortname is generated by smb_mangle_name()
+ * it will be returned as the alternative name.
+ * Otherwise, convert the original name to upper-case
+ * and return it as the alternative name.
*/
(void) smb_mangle_name(ap->sa_vattr.va_nodeid,
filename, short_name, name83, 0);
- alt_nm_ptr = (*short_name == 0) ?
- utf8_strupr(filename) : short_name;
+ if (*short_name == 0) {
+ (void) strlcpy(short_name, filename, SMB_SHORTNAMELEN);
+ (void) utf8_strupr(short_name);
+ }
+
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
(void) smb_mbc_encodef(&xa->rep_data_mb, "%lU", sr,
- mts_wcequiv_strlen(alt_nm_ptr), alt_nm_ptr);
+ mts_wcequiv_strlen(short_name), short_name);
break;
case SMB_QUERY_FILE_STREAM_INFO:
case SMB_FILE_STREAM_INFORMATION:
{
struct smb_node *node = sr->fid_ofile->f_node;
- if (dir_snode == NULL) {
+ if (dnode == NULL) {
kmem_free(filebuf, MAXPATHLEN+1);
smbsr_error(sr, 0, ERRDOS, ERRbadfile);
return (SDRC_ERROR);
}
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
if (SMB_IS_STREAM(node)) {
- ASSERT(node->unnamed_stream_node);
- ASSERT(node->unnamed_stream_node->n_magic ==
- SMB_NODE_MAGIC);
- ASSERT(node->unnamed_stream_node->n_state !=
+ ASSERT(node->n_unode);
+ ASSERT(node->n_unode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(node->n_unode->n_state !=
SMB_NODE_STATE_DESTROYING);
(void) smb_encode_stream_info(sr, xa,
- node->unnamed_stream_node, ap);
+ node->n_unode, ap);
} else {
(void) smb_encode_stream_info(sr, xa, node, ap);
}
@@ -572,3 +592,45 @@
return (pad);
}
+
+/*
+ * smb_encode_smb_datetimes
+ *
+ * Encode timestamps in the SMB_DATE / SMB_TIME format.
+ */
+void
+smb_encode_smb_datetimes(smb_request_t *sr, smb_xa_t *xa, smb_attr_t *attr)
+{
+ if ((sr->fid_ofile) &&
+ (sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE)) {
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "lll", 0, 0, 0);
+ return;
+ }
+
+ (void) smb_mbc_encodef(&xa->rep_data_mb,
+ ((sr->session->native_os == NATIVE_OS_WIN95) ? "YYY" : "yyy"),
+ smb_gmt2local(sr, attr->sa_crtime.tv_sec),
+ smb_gmt2local(sr, attr->sa_vattr.va_atime.tv_sec),
+ smb_gmt2local(sr, attr->sa_vattr.va_mtime.tv_sec));
+}
+
+/*
+ * smb_encode_nt_times
+ *
+ * Encode timestamps in LARGE INTEGER format NT Times.
+ */
+void
+smb_encode_nt_times(smb_request_t *sr, smb_xa_t *xa, smb_attr_t *attr)
+{
+ if ((sr->fid_ofile) &&
+ (sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE)) {
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "qqqq", 0, 0, 0, 0);
+ return;
+ }
+
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTT",
+ &attr->sa_crtime,
+ &attr->sa_vattr.va_atime,
+ &attr->sa_vattr.va_mtime,
+ &attr->sa_vattr.va_ctime);
+}
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c Fri Jul 17 17:54:42 2009 -0700
@@ -322,6 +322,8 @@
#include <smbsrv/smb_fsops.h>
int smb_query_all_info_filename(smb_tree_t *, smb_node_t *, char *, size_t);
+extern void smb_encode_smb_datetimes(smb_request_t *, smb_xa_t *, smb_attr_t *);
+extern void smb_encode_nt_times(smb_request_t *, smb_xa_t *, smb_attr_t *);
/*
* Function: int smb_com_trans2_query_path_information(struct smb_request *)
@@ -340,11 +342,12 @@
char short_name[SMB_SHORTNAMELEN];
char name83[SMB_SHORTNAMELEN];
unsigned char is_dir;
+ unsigned char delete_on_close;
int len;
if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
- smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
- ERROR_ACCESS_DENIED);
+ smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST, ERRDOS,
+ ERROR_INVALID_FUNCTION);
return (SDRC_ERROR);
}
@@ -422,6 +425,18 @@
allocsz = ap->sa_vattr.va_nblocks * DEV_BSIZE;
}
+ delete_on_close =
+ (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0;
+
+ /*
+ * The number of links reported should be the number of
+ * non-deleted links. Thus if delete_on_close is set,
+ * decrement the link count.
+ */
+ if (delete_on_close && ap->sa_vattr.va_nlink > 0)
+ --(ap->sa_vattr.va_nlink);
+
+
switch (infolev) {
case SMB_INFO_STANDARD:
@@ -431,15 +446,9 @@
allocsz = UINT_MAX;
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb,
- ((sr->session->native_os == NATIVE_OS_WIN95)
- ? "YYYllw" : "yyyllw"),
- smb_gmt2local(sr, ap->sa_crtime.tv_sec),
- smb_gmt2local(sr, ap->sa_vattr.va_atime.tv_sec),
- smb_gmt2local(sr, ap->sa_vattr.va_mtime.tv_sec),
- (uint32_t)datasz,
- (uint32_t)allocsz,
- dattr);
+ smb_encode_smb_datetimes(sr, xa, ap);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "llw",
+ (uint32_t)datasz, (uint32_t)allocsz, dattr);
break;
case SMB_INFO_QUERY_EA_SIZE:
@@ -449,15 +458,9 @@
allocsz = UINT_MAX;
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb,
- ((sr->session->native_os == NATIVE_OS_WIN95)
- ? "YYYllwl" : "yyyllwl"),
- smb_gmt2local(sr, ap->sa_crtime.tv_sec),
- smb_gmt2local(sr, ap->sa_vattr.va_atime.tv_sec),
- smb_gmt2local(sr, ap->sa_vattr.va_mtime.tv_sec),
- (uint32_t)datasz,
- (uint32_t)allocsz,
- dattr, 0);
+ smb_encode_smb_datetimes(sr, xa, ap);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "llwl",
+ (uint32_t)datasz, (uint32_t)allocsz, dattr, 0);
break;
case SMB_INFO_QUERY_EAS_FROM_LIST:
@@ -477,12 +480,8 @@
* Similar change in smb_trans2_query_file_information.c.
*/
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.",
- &ap->sa_crtime,
- &ap->sa_vattr.va_atime,
- &ap->sa_vattr.va_mtime,
- &ap->sa_vattr.va_ctime,
- dattr);
+ smb_encode_nt_times(sr, xa, ap);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "w6.", dattr);
break;
case SMB_QUERY_FILE_STANDARD_INFO:
@@ -496,7 +495,7 @@
(uint64_t)allocsz,
(uint64_t)datasz,
ap->sa_vattr.va_nlink,
- (node && (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0),
+ delete_on_close,
(char)(ap->sa_vattr.va_type == VDIR));
break;
@@ -520,19 +519,18 @@
case SMB_QUERY_FILE_ALL_INFO:
case SMB_FILE_ALL_INFORMATION:
+ rc = smb_query_all_info_filename(sr->tid_tree, node,
+ name, MAXPATHLEN);
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ smb_node_release(node);
+ kmem_free(name, MAXPATHLEN);
+ return (SDRC_ERROR);
+ }
+
/*
- * The reply of this information level on the
- * wire doesn't match with protocol specification.
- * This is what spec. needs: "TTTTwqqlbbqllqqll"
- * But this is actually is sent on the wire:
- * "TTTTw6.qqlbb2.l"
- * So, there is a 6-byte pad between Attributes and
- * AllocationSize. Also there is a 2-byte pad After
- * Directory field. Between Directory and FileNameLength
- * there is just 4 bytes that it seems is AlignmentRequirement.
- * There are 6 other fields between Directory and
- * AlignmentRequirement in spec. that aren't sent
- * on the wire.
+ * There is a 6-byte pad between Attributes and AllocationSize,
+ * and a 2-byte pad after the Directory field.
*/
rc = smb_query_all_info_filename(sr->tid_tree, node,
name, MAXPATHLEN);
@@ -544,11 +542,8 @@
}
(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.qqlbb2.l",
- &ap->sa_crtime,
- &ap->sa_vattr.va_atime,
- &ap->sa_vattr.va_mtime,
- &ap->sa_vattr.va_ctime,
+ smb_encode_nt_times(sr, xa, ap);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "w6.qqlbb2.l",
dattr,
(uint64_t)allocsz,
(uint64_t)datasz,
@@ -564,14 +559,10 @@
case SMB_QUERY_FILE_ALT_NAME_INFO:
case SMB_FILE_ALT_NAME_INFORMATION:
/*
- * Conform to the rule used by Windows NT/2003 servers.
- * Shortname is created only if either the filename or
- * extension portion of a file is made up of mixed case.
- *
- * If the shortname is generated, it will be returned as
- * the alternative name. Otherwise, convert the original
- * name to all upper-case and return it as the alternative
- * name.
+ * If the shortname is generated by smb_mangle_name()
+ * it will be returned as the alternative name.
+ * Otherwise, convert the original name to upper-case
+ * and return it as the alternative name.
*/
(void) smb_mangle_name(ap->sa_vattr.va_nodeid,
name, short_name, name83, 0);
@@ -656,7 +647,7 @@
buflen -= len;
if (SMB_IS_STREAM(node))
- vp = node->unnamed_stream_node->vp;
+ vp = node->n_unode->vp;
else
vp = node->vp;
--- a/usr/src/uts/common/fs/smbsrv/smb_tree.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree.c Fri Jul 17 17:54:42 2009 -0700
@@ -193,8 +193,13 @@
static void smb_tree_get_flags(const smb_share_t *, vfs_t *, smb_tree_t *);
static void smb_tree_log(smb_request_t *, const char *, const char *, ...);
static void smb_tree_close_odirs(smb_tree_t *, uint16_t);
+static smb_ofile_t *smb_tree_get_ofile(smb_tree_t *, smb_ofile_t *);
static smb_odir_t *smb_tree_get_odir(smb_tree_t *, smb_odir_t *);
static void smb_tree_set_execsub_info(smb_tree_t *, smb_execsub_info_t *);
+static int smb_tree_enum_private(smb_tree_t *, smb_svcenum_t *);
+static int smb_tree_netinfo_encode(smb_tree_t *, uint8_t *, size_t, uint32_t *);
+static void smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *);
+static void smb_tree_netinfo_fini(smb_netconnectinfo_t *);
/*
* Extract the share name and share type and connect as appropriate.
@@ -362,8 +367,69 @@
return ((tree->t_flags & flags) == flags);
}
+/*
+ * If the enumeration request is for tree data, handle the request
+ * here. Otherwise, pass it on to the ofiles.
+ *
+ * This function should be called with a hold on the tree.
+ */
+int
+smb_tree_enum(smb_tree_t *tree, smb_svcenum_t *svcenum)
+{
+ smb_ofile_t *of;
+ smb_ofile_t *next;
+ int rc;
+
+ ASSERT(tree);
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+ if (svcenum->se_type == SMB_SVCENUM_TYPE_TREE)
+ return (smb_tree_enum_private(tree, svcenum));
+
+ of = smb_tree_get_ofile(tree, NULL);
+ while (of) {
+ ASSERT(of->f_tree == tree);
+
+ rc = smb_ofile_enum(of, svcenum);
+ if (rc != 0) {
+ smb_ofile_release(of);
+ break;
+ }
+
+ next = smb_tree_get_ofile(tree, of);
+ smb_ofile_release(of);
+ of = next;
+ }
+
+ return (rc);
+}
+
+/*
+ * Close a file by its unique id.
+ */
+int
+smb_tree_fclose(smb_tree_t *tree, uint32_t uniqid)
+{
+ smb_ofile_t *of;
+
+ ASSERT(tree);
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+ if ((of = smb_ofile_lookup_by_uniqid(tree, uniqid)) == NULL)
+ return (ENOENT);
+
+ if (smb_ofile_disallow_fclose(of)) {
+ smb_ofile_release(of);
+ return (EACCES);
+ }
+
+ smb_ofile_close(of, 0);
+ smb_ofile_release(of);
+ return (0);
+}
/* *************************** Static Functions ***************************** */
+
#define SHARES_DIR ".zfs/shares/"
static void
smb_tree_acl_access(cred_t *cred, const char *sharename, vnode_t *pathvp,
@@ -434,7 +500,7 @@
smb_tree_connect_disk(smb_request_t *sr, const char *sharename)
{
smb_user_t *user = sr->uid_user;
- smb_node_t *dir_snode = NULL;
+ smb_node_t *dnode = NULL;
smb_node_t *snode = NULL;
char last_component[MAXNAMELEN];
smb_tree_t *tree;
@@ -529,15 +595,15 @@
/*
* Check that the shared directory exists.
*/
- rc = smb_pathname_reduce(sr, u_cred, si->shr_path, 0, 0, &dir_snode,
+ rc = smb_pathname_reduce(sr, u_cred, si->shr_path, 0, 0, &dnode,
last_component);
if (rc == 0) {
rc = smb_fsop_lookup(sr, u_cred, SMB_FOLLOW_LINKS,
- sr->sr_server->si_root_smb_node, dir_snode, last_component,
+ sr->sr_server->si_root_smb_node, dnode, last_component,
&snode);
- smb_node_release(dir_snode);
+ smb_node_release(dnode);
}
if (rc) {
@@ -704,6 +770,7 @@
tree->t_state = SMB_TREE_STATE_CONNECTED;
tree->t_magic = SMB_TREE_MAGIC;
tree->t_access = access;
+ tree->t_connect_time = gethrestime_sec();
/* if FS is readonly, enforce that here */
if (tree->t_flags & SMB_TREE_READONLY)
@@ -1080,6 +1147,44 @@
}
/*
+ * Get the next open ofile in the list. A reference is taken on
+ * the ofile, which can be released later with smb_ofile_release().
+ *
+ * If the specified ofile is NULL, search from the beginning of the
+ * list. Otherwise, the search starts just after that ofile.
+ *
+ * Returns NULL if there are no open files in the list.
+ */
+static smb_ofile_t *
+smb_tree_get_ofile(smb_tree_t *tree, smb_ofile_t *of)
+{
+ smb_llist_t *ofile_list;
+
+ ASSERT(tree);
+ ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+ ofile_list = &tree->t_ofile_list;
+ smb_llist_enter(ofile_list, RW_READER);
+
+ if (of) {
+ ASSERT(of->f_magic == SMB_OFILE_MAGIC);
+ of = smb_llist_next(ofile_list, of);
+ } else {
+ of = smb_llist_head(ofile_list);
+ }
+
+ while (of) {
+ if (smb_ofile_hold(of))
+ break;
+
+ of = smb_llist_next(ofile_list, of);
+ }
+
+ smb_llist_exit(ofile_list);
+ return (of);
+}
+
+/*
* smb_tree_get_odir
*
* Find the next odir in the tree's list of odirs, and obtain a
@@ -1157,3 +1262,96 @@
subs->e_cli_netbiosname = tree->t_session->workstation;
subs->e_uid = tree->t_user->u_cred->cr_uid;
}
+
+/*
+ * Private function to support smb_tree_enum.
+ */
+static int
+smb_tree_enum_private(smb_tree_t *tree, smb_svcenum_t *svcenum)
+{
+ uint8_t *pb;
+ uint_t nbytes;
+ int rc;
+
+ if (svcenum->se_nskip > 0) {
+ svcenum->se_nskip--;
+ return (0);
+ }
+
+ if (svcenum->se_nitems >= svcenum->se_nlimit) {
+ svcenum->se_nitems = svcenum->se_nlimit;
+ return (0);
+ }
+
+ pb = &svcenum->se_buf[svcenum->se_bused];
+ rc = smb_tree_netinfo_encode(tree, pb, svcenum->se_bavail, &nbytes);
+ if (rc == 0) {
+ svcenum->se_bavail -= nbytes;
+ svcenum->se_bused += nbytes;
+ svcenum->se_nitems++;
+ }
+
+ return (rc);
+}
+
+/*
+ * Encode connection information into a buffer: connection information
+ * needed in user space to support RPC requests.
+ */
+static int
+smb_tree_netinfo_encode(smb_tree_t *tree, uint8_t *buf, size_t buflen,
+ uint32_t *nbytes)
+{
+ smb_netconnectinfo_t info;
+ int rc;
+
+ smb_tree_netinfo_init(tree, &info);
+ rc = smb_netconnectinfo_encode(&info, buf, buflen, nbytes);
+ smb_tree_netinfo_fini(&info);
+
+ return (rc);
+}
+
+/*
+ * Note: ci_numusers should be the number of users connected to
+ * the share rather than the number of references on the tree but
+ * we don't have a mechanism to track users/share in smbsrv yet.
+ */
+static void
+smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *info)
+{
+ smb_user_t *user;
+
+ ASSERT(tree);
+
+ info->ci_id = tree->t_tid;
+ info->ci_type = tree->t_res_type;
+ info->ci_numopens = tree->t_open_files;
+ info->ci_numusers = tree->t_refcnt;
+ info->ci_time = gethrestime_sec() - tree->t_connect_time;
+
+ info->ci_sharelen = strlen(tree->t_sharename) + 1;
+ info->ci_share = smb_kstrdup(tree->t_sharename, info->ci_sharelen);
+
+ user = tree->t_user;
+ ASSERT(user);
+
+ info->ci_namelen = user->u_domain_len + user->u_name_len + 2;
+ info->ci_username = kmem_alloc(info->ci_namelen, KM_SLEEP);
+ (void) snprintf(info->ci_username, info->ci_namelen, "%s\\%s",
+ user->u_domain, user->u_name);
+}
+
+static void
+smb_tree_netinfo_fini(smb_netconnectinfo_t *info)
+{
+ if (info == NULL)
+ return;
+
+ if (info->ci_username)
+ kmem_free(info->ci_username, info->ci_namelen);
+ if (info->ci_share)
+ kmem_free(info->ci_share, info->ci_sharelen);
+
+ bzero(info, sizeof (smb_netconnectinfo_t));
+}
--- a/usr/src/uts/common/fs/smbsrv/smb_user.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/fs/smbsrv/smb_user.c Fri Jul 17 17:54:42 2009 -0700
@@ -171,6 +171,8 @@
static smb_sid_t *smb_admins_sid = NULL;
+static boolean_t smb_user_is_logged_in(smb_user_t *);
+static int smb_user_enum_private(smb_user_t *, smb_svcenum_t *);
static void smb_user_delete(smb_user_t *user);
static smb_tree_t *smb_user_get_tree(smb_llist_t *, smb_tree_t *);
@@ -287,7 +289,8 @@
/*
* smb_user_logoff
*
- *
+ * Change the user state and disconnect trees.
+ * The user list must not be entered or modified here.
*/
void
smb_user_logoff(
@@ -376,6 +379,27 @@
}
/*
+ * Take a reference on a user.
+ */
+boolean_t
+smb_user_hold(smb_user_t *user)
+{
+ ASSERT(user);
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+
+ mutex_enter(&user->u_mutex);
+
+ if (smb_user_is_logged_in(user)) {
+ user->u_refcnt++;
+ mutex_exit(&user->u_mutex);
+ return (B_TRUE);
+ }
+
+ mutex_exit(&user->u_mutex);
+ return (B_FALSE);
+}
+
+/*
* smb_user_release
*
*
@@ -434,29 +458,10 @@
ASSERT(user->u_magic == SMB_USER_MAGIC);
ASSERT(user->u_session == session);
if (user->u_uid == uid) {
- mutex_enter(&user->u_mutex);
- switch (user->u_state) {
-
- case SMB_USER_STATE_LOGGED_IN:
- /* The user exists and is still logged in. */
- user->u_refcnt++;
- mutex_exit(&user->u_mutex);
+ if (smb_user_hold(user)) {
smb_llist_exit(&session->s_user_list);
return (user);
-
- case SMB_USER_STATE_LOGGING_OFF:
- case SMB_USER_STATE_LOGGED_OFF:
- /*
- * The user exists but has logged off or is in
- * the process of logging off.
- */
- mutex_exit(&user->u_mutex);
- smb_llist_exit(&session->s_user_list);
- return (NULL);
-
- default:
- ASSERT(0);
- mutex_exit(&user->u_mutex);
+ } else {
smb_llist_exit(&session->s_user_list);
return (NULL);
}
@@ -499,17 +504,11 @@
while (next) {
ASSERT(next->u_magic == SMB_USER_MAGIC);
ASSERT(next->u_session == session);
- mutex_enter(&next->u_mutex);
- if (next->u_state == SMB_USER_STATE_LOGGED_IN) {
- next->u_refcnt++;
- mutex_exit(&next->u_mutex);
+
+ if (smb_user_hold(next))
break;
- } else {
- ASSERT((next->u_state == SMB_USER_STATE_LOGGING_OFF) ||
- (next->u_state == SMB_USER_STATE_LOGGED_OFF));
- mutex_exit(&next->u_mutex);
- next = smb_llist_next(lst, next);
- }
+
+ next = smb_llist_next(lst, next);
}
smb_llist_exit(lst);
@@ -712,6 +711,40 @@
}
/*
+ * Close a file by its unique id.
+ */
+int
+smb_user_fclose(smb_user_t *user, uint32_t uniqid)
+{
+ smb_llist_t *tree_list;
+ smb_tree_t *tree;
+ int rc = ENOENT;
+
+ ASSERT(user);
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+
+ tree_list = &user->u_tree_list;
+ ASSERT(tree_list);
+
+ smb_llist_enter(tree_list, RW_READER);
+ tree = smb_llist_head(tree_list);
+
+ while ((tree != NULL) && (rc == ENOENT)) {
+ ASSERT(tree->t_user == user);
+
+ if (smb_tree_hold(tree)) {
+ rc = smb_tree_fclose(tree, uniqid);
+ smb_tree_release(tree);
+ }
+
+ tree = smb_llist_next(tree_list, tree);
+ }
+
+ smb_llist_exit(tree_list);
+ return (rc);
+}
+
+/*
* Determine whether or not the user is an administrator.
* Members of the administrators group have administrative rights.
*/
@@ -734,9 +767,99 @@
return (B_FALSE);
}
+/*
+ * This function should be called with a hold on the user.
+ */
+boolean_t
+smb_user_namecmp(smb_user_t *user, const char *name)
+{
+ char *fq_name;
+ boolean_t match;
+
+ if (utf8_strcasecmp(name, user->u_name) == 0)
+ return (B_TRUE);
+
+ fq_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+
+ (void) snprintf(fq_name, MAXNAMELEN, "%s\\%s",
+ user->u_domain, user->u_name);
+
+ match = (utf8_strcasecmp(name, fq_name) == 0);
+ if (!match) {
+ (void) snprintf(fq_name, MAXNAMELEN, "%s@%s",
+ user->u_name, user->u_domain);
+
+ match = (utf8_strcasecmp(name, fq_name) == 0);
+ }
+
+ kmem_free(fq_name, MAXNAMELEN);
+ return (match);
+}
+
+/*
+ * If the enumeration request is for user data, handle the request
+ * here. Otherwise, pass it on to the trees.
+ *
+ * This function should be called with a hold on the user.
+ */
+int
+smb_user_enum(smb_user_t *user, smb_svcenum_t *svcenum)
+{
+ smb_tree_t *tree;
+ smb_tree_t *next;
+ int rc;
+
+ ASSERT(user);
+ ASSERT(user->u_magic == SMB_USER_MAGIC);
+
+ if (svcenum->se_type == SMB_SVCENUM_TYPE_USER)
+ return (smb_user_enum_private(user, svcenum));
+
+ tree = smb_user_get_tree(&user->u_tree_list, NULL);
+ while (tree) {
+ ASSERT(tree->t_user == user);
+
+ rc = smb_tree_enum(tree, svcenum);
+ if (rc != 0) {
+ smb_tree_release(tree);
+ break;
+ }
+
+ next = smb_user_get_tree(&user->u_tree_list, tree);
+ smb_tree_release(tree);
+ tree = next;
+ }
+
+ return (rc);
+}
+
/* *************************** Static Functions ***************************** */
/*
+ * Determine whether or not a user is logged in.
+ * Typically, a reference can only be taken on a logged-in user.
+ *
+ * This is a private function and must be called with the user
+ * mutex held.
+ */
+static boolean_t
+smb_user_is_logged_in(smb_user_t *user)
+{
+ switch (user->u_state) {
+ case SMB_USER_STATE_LOGGED_IN:
+ return (B_TRUE);
+
+ case SMB_USER_STATE_LOGGING_OFF:
+ case SMB_USER_STATE_LOGGED_OFF:
+ return (B_FALSE);
+
+ default:
+ ASSERT(0);
+ return (B_FALSE);
+ }
+}
+
+/*
* smb_user_delete
*/
static void
@@ -821,3 +944,104 @@
{
return ((user->u_privcred)? user->u_privcred : user->u_cred);
}
+
+/*
+ * Private function to support smb_user_enum.
+ */
+static int
+smb_user_enum_private(smb_user_t *user, smb_svcenum_t *svcenum)
+{
+ uint8_t *pb;
+ uint_t nbytes;
+ int rc;
+
+ if (svcenum->se_nskip > 0) {
+ svcenum->se_nskip--;
+ return (0);
+ }
+
+ if (svcenum->se_nitems >= svcenum->se_nlimit) {
+ svcenum->se_nitems = svcenum->se_nlimit;
+ return (0);
+ }
+
+ pb = &svcenum->se_buf[svcenum->se_bused];
+ rc = smb_user_netinfo_encode(user, pb, svcenum->se_bavail, &nbytes);
+ if (rc == 0) {
+ svcenum->se_bavail -= nbytes;
+ svcenum->se_bused += nbytes;
+ svcenum->se_nitems++;
+ }
+
+ return (rc);
+}
+
+/*
+ * Encode the NetInfo for a user into a buffer. NetInfo contains
+ * information that is often needed in user space to support RPC
+ * requests.
+ */
+int
+smb_user_netinfo_encode(smb_user_t *user, uint8_t *buf, size_t buflen,
+ uint32_t *nbytes)
+{
+ smb_netuserinfo_t info;
+ int rc;
+
+ smb_user_netinfo_init(user, &info);
+ rc = smb_netuserinfo_encode(&info, buf, buflen, nbytes);
+ smb_user_netinfo_fini(&info);
+
+ return (rc);
+}
+
+void
+smb_user_netinfo_init(smb_user_t *user, smb_netuserinfo_t *info)
+{
+ smb_session_t *session;
+ char *buf;
+
+ ASSERT(user);
+ ASSERT(user->u_domain);
+ ASSERT(user->u_name);
+
+ session = user->u_session;
+ ASSERT(session);
+ ASSERT(session->workstation);
+
+ info->ui_session_id = session->s_kid;
+ info->ui_native_os = session->native_os;
+ info->ui_ipaddr = session->ipaddr;
+ info->ui_numopens = session->s_file_cnt;
+ info->ui_uid = user->u_uid;
+ info->ui_logon_time = user->u_logon_time;
+ info->ui_flags = user->u_flags;
+
+ info->ui_domain_len = user->u_domain_len;
+ info->ui_domain = smb_kstrdup(user->u_domain, info->ui_domain_len);
+
+ info->ui_account_len = user->u_name_len;
+ info->ui_account = smb_kstrdup(user->u_name, info->ui_account_len);
+
+ buf = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ smb_session_getclient(session, buf, MAXNAMELEN);
+ info->ui_workstation_len = strlen(buf) + 1;
+ info->ui_workstation = smb_kstrdup(buf, info->ui_workstation_len);
+ kmem_free(buf, MAXNAMELEN);
+}
+
+void
+smb_user_netinfo_fini(smb_netuserinfo_t *info)
+{
+ if (info == NULL)
+ return;
+
+ if (info->ui_domain)
+ kmem_free(info->ui_domain, info->ui_domain_len);
+ if (info->ui_account)
+ kmem_free(info->ui_account, info->ui_account_len);
+ if (info->ui_workstation)
+ kmem_free(info->ui_workstation, info->ui_workstation_len);
+
+ bzero(info, sizeof (smb_netuserinfo_t));
+}
--- a/usr/src/uts/common/rpc/xdr.c Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/rpc/xdr.c Fri Jul 17 17:54:42 2009 -0700
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -307,6 +307,29 @@
}
/*
+ * XDR an unsigned char
+ */
+bool_t
+xdr_u_char(XDR *xdrs, uchar_t *cp)
+{
+ int i;
+
+ switch (xdrs->x_op) {
+ case XDR_ENCODE:
+ i = (*cp);
+ return (XDR_PUTINT32(xdrs, &i));
+ case XDR_DECODE:
+ if (!XDR_GETINT32(xdrs, &i))
+ return (FALSE);
+ *cp = (uchar_t)i;
+ return (TRUE);
+ case XDR_FREE:
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+/*
* XDR booleans
*
* PSARC 2003/523 Contract Private Interface
@@ -608,6 +631,32 @@
}
/*
+ * xdr_vector():
+ *
+ * XDR a fixed length array. Unlike variable-length arrays, the storage
+ * of fixed length arrays is static and unfreeable.
+ * > basep: base of the array
+ * > size: size of the array
+ * > elemsize: size of each element
+ * > xdr_elem: routine to XDR each element
+ */
+bool_t
+xdr_vector(XDR *xdrs, char *basep, const uint_t nelem,
+ const uint_t elemsize, const xdrproc_t xdr_elem)
+{
+ uint_t i;
+ char *elptr;
+
+ elptr = basep;
+ for (i = 0; i < nelem; i++) {
+ if (!(*xdr_elem)(xdrs, elptr, LASTUNSIGNED))
+ return (FALSE);
+ elptr += elemsize;
+ }
+ return (TRUE);
+}
+
+/*
* Wrapper for xdr_string that can be called directly from
* routines like clnt_call
*/
--- a/usr/src/uts/common/rpc/xdr.h Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/rpc/xdr.h Fri Jul 17 17:54:42 2009 -0700
@@ -18,7 +18,7 @@
*
* CDDL HEADER END
*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
@@ -420,6 +420,8 @@
extern bool_t xdr_string(XDR *, char **, const uint_t);
extern bool_t xdr_union(XDR *, enum_t *, char *,
const struct xdr_discrim *, const xdrproc_t);
+extern bool_t xdr_vector(XDR *, char *, const uint_t, const uint_t,
+ const xdrproc_t);
extern unsigned int xdr_sizeof(xdrproc_t, void *);
extern bool_t xdr_hyper(XDR *, longlong_t *);
@@ -428,6 +430,7 @@
extern bool_t xdr_u_longlong_t(XDR *, u_longlong_t *);
extern bool_t xdr_char(XDR *, char *);
+extern bool_t xdr_u_char(XDR *, uchar_t *);
extern bool_t xdr_wrapstring(XDR *, char **);
extern bool_t xdr_reference(XDR *, caddr_t *, uint_t, const xdrproc_t);
extern bool_t xdr_pointer(XDR *, char **, uint_t, const xdrproc_t);
@@ -446,9 +449,6 @@
#endif
#ifndef _KERNEL
-extern bool_t xdr_u_char(XDR *, uchar_t *);
-extern bool_t xdr_vector(XDR *, char *, const uint_t, const uint_t, const
-xdrproc_t);
extern bool_t xdr_float(XDR *, float *);
extern bool_t xdr_double(XDR *, double *);
extern bool_t xdr_quadruple(XDR *, long double *);
@@ -468,12 +468,14 @@
extern bool_t xdr_opaque();
extern bool_t xdr_string();
extern bool_t xdr_union();
+extern bool_t xdr_vector();
extern bool_t xdr_hyper();
extern bool_t xdr_longlong_t();
extern bool_t xdr_u_hyper();
extern bool_t xdr_u_longlong_t();
extern bool_t xdr_char();
+extern bool_t xdr_u_char();
extern bool_t xdr_reference();
extern bool_t xdr_pointer();
extern void xdr_free();
@@ -492,8 +494,6 @@
#endif
#ifndef _KERNEL
-extern bool_t xdr_u_char();
-extern bool_t xdr_vector();
extern bool_t xdr_float();
extern bool_t xdr_double();
extern bool_t xdr_quadruple();
--- a/usr/src/uts/common/rpcsvc/idmap_prot.x Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/rpcsvc/idmap_prot.x Fri Jul 17 17:54:42 2009 -0700
@@ -19,13 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-
/* opaque type to support non-ASCII strings */
typedef string idmap_utf8str<>;
+typedef idmap_utf8str idmap_utf8str_list<>;
/* Return status */
typedef int idmap_retcode;
@@ -270,6 +270,76 @@
};
#endif
+/*
+ * Represents an error from the directory lookup service.
+ *
+ * code is an ASCII string that is a key for the error. It is not
+ * localized.
+ *
+ * fmt is a format string with %n markers for where to include
+ * params[n-1]. It should be, but NEEDSWORK is not localized to
+ * the caller's locale.
+ *
+ * params is a list of parameters for the error - e.g. the name that
+ * encountered a failure, the server that reported the failure, et cetera.
+ * The values are to be used both as marked in fmt and for machine
+ * interpretation of the error.
+ */
+struct directory_error_rpc {
+ idmap_utf8str code;
+ idmap_utf8str fmt;
+ idmap_utf8str params<>;
+};
+
+/*
+ * One value of a multivalued attribute.
+ */
+typedef opaque directory_value_rpc<>;
+
+/*
+ * The value of an attribute, if found. Note that this is a list
+ * of directory_value_rpc objects, to support multivalued attributes.
+ */
+union directory_values_rpc switch (bool found) {
+ case TRUE:
+ directory_value_rpc values<>;
+ case FALSE:
+ void;
+};
+
+/*
+ * The status of the lookup for any particular identifier.
+ */
+enum directory_lookup_status_rpc {
+ DIRECTORY_NOT_FOUND = 0,
+ DIRECTORY_FOUND = 1,
+ DIRECTORY_ERROR = 2
+};
+
+/*
+ * This is the data returned for a particular identifier, either a
+ * list of attribute values or an error.
+ */
+union directory_entry_rpc switch (directory_lookup_status_rpc status) {
+ case DIRECTORY_NOT_FOUND:
+ void;
+ case DIRECTORY_FOUND:
+ directory_values_rpc attrs<>;
+ case DIRECTORY_ERROR:
+ directory_error_rpc err;
+};
+
+/*
+ * This is the result from a request, either a list of the entries for
+ * the identifiers specified, or an error.
+ */
+union directory_results_rpc switch (bool failed) {
+ case TRUE:
+ directory_error_rpc err;
+ case FALSE:
+ directory_entry_rpc entries<>;
+};
+
program IDMAP_PROG {
version IDMAP_V1 {
void
@@ -302,6 +372,27 @@
idmap_prop_res
IDMAP_GET_PROP(idmap_prop_type) = 6;
#endif
+ /*
+ * Retrieve directory information about a list of users
+ * or groups by name or SID.
+ *
+ * ids is a list of user names, group names, or SIDs.
+ *
+ * types is a list of types of the ids in the id list.
+ * If the type list is shorter than the id list, the last
+ * type listed applies to all of the ids from that point.
+ * The defined types are:
+ * 'n' - name (could be user or group)
+ * 'u' - user
+ * 'g' - group
+ * 's' - SID
+ *
+ * attrs is a list of attribute names to retrieve.
+ */
+ directory_results_rpc DIRECTORY_GET_COMMON(
+ idmap_utf8str_list ids,
+ idmap_utf8str types,
+ idmap_utf8str_list attrs) = 7;
} = 1;
} = 100172;
--- a/usr/src/uts/common/smbsrv/ndl/srvsvc.ndl Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/smbsrv/ndl/srvsvc.ndl Fri Jul 17 17:54:42 2009 -0700
@@ -403,6 +403,7 @@
SWITCH(switch_value)
union mslm_NetConnectInfoResUnion ru;
};
+typedef struct mslm_NetConnectInfo srvsvc_NetConnectInfo_t;
OPERATION(SRVSVC_OPNUM_NetConnectEnum)
struct mslm_NetConnectEnum {
@@ -993,22 +994,19 @@
*
* servername
* [in] Pointer to a string that specifies the DNS or NetBIOS name
- * of the remote server on which the function is to execute. If this
- * parameter is NULL, the local computer is used.
- * Windows NT 4.0 and earlier: This string must begin with \\.
+ * of the server. Servers should not validate this parameter.
+ * This parameter may be NULL and on Windows NT 4.0 and earlier it
+ * should begin with \\.
*
* UncClientName
- * [in] Pointer to a string that specifies the computer name of the
- * client to disconnect. If UncClientName is NULL, then all the sessions
- * of the user identified by the username parameter will be deleted on
- * the server specified by servername. For more information, see
- * NetSessionEnum.
+ * [in] Pointer to a string that specifies the name of the client
+ * to disconnect. If UncClientName is NULL, all sessions associated
+ * with the specified user will be disconnected.
*
* username
* [in] Pointer to a string that specifies the name of the user whose
- * session is to be terminated. If this parameter is NULL, all users'
- * sessions from the client specified by the UncClientName parameter
- * are to be terminated.
+ * session is to be terminated. If username is NULL, all sessions
+ * from the specified client will be disconnected.
*
* Remarks
* Windows 95/98/Me: You must specify the session key in the sReserved
@@ -1041,8 +1039,11 @@
*/
/* for svX_platform */
-#define SV_PLATFORM_ID_OS2 400
-#define SV_PLATFORM_ID_NT 500
+#define SV_PLATFORM_ID_DOS 300
+#define SV_PLATFORM_ID_OS2 400
+#define SV_PLATFORM_ID_NT 500
+#define SV_PLATFORM_ID_OSF 600
+#define SV_PLATFORM_ID_VMS 700
/* Bit-mapped values for svX_type fields */
#define SV_TYPE_WORKSTATION 0x00000001
--- a/usr/src/uts/common/smbsrv/smb_ioctl.h Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/smbsrv/smb_ioctl.h Fri Jul 17 17:54:42 2009 -0700
@@ -47,8 +47,10 @@
#define SMB_IOC_GMTOFF _IOW(SMB_IOC_BASE, 7, int)
#define SMB_IOC_SHARE _IOW(SMB_IOC_BASE, 8, int)
#define SMB_IOC_UNSHARE _IOW(SMB_IOC_BASE, 9, int)
-#define SMB_IOC_USER_NUMBER _IOW(SMB_IOC_BASE, 10, int)
-#define SMB_IOC_USER_LIST _IOW(SMB_IOC_BASE, 11, int)
+#define SMB_IOC_NUMOPEN _IOW(SMB_IOC_BASE, 10, int)
+#define SMB_IOC_SVCENUM _IOW(SMB_IOC_BASE, 11, int)
+#define SMB_IOC_FILE_CLOSE _IOW(SMB_IOC_BASE, 12, int)
+#define SMB_IOC_SESSION_CLOSE _IOW(SMB_IOC_BASE, 13, int)
typedef struct smb_ioc_header {
uint32_t version;
@@ -80,18 +82,55 @@
int udoor;
} smb_ioc_start_t;
-typedef struct smb_ioc_usernum {
+typedef struct smb_ioc_opennum {
smb_ioc_header_t hdr;
- uint32_t num;
-} smb_ioc_usernum_t;
+ uint32_t open_users;
+ uint32_t open_trees;
+ uint32_t open_files;
+ uint32_t qualtype;
+ char qualifier[MAXNAMELEN];
+} smb_ioc_opennum_t;
+
+/*
+ * For enumeration, user and session are synonymous, as are
+ * connection and tree.
+ */
+#define SMB_SVCENUM_TYPE_USER 0x55534552 /* 'USER' */
+#define SMB_SVCENUM_TYPE_TREE 0x54524545 /* 'TREE' */
+#define SMB_SVCENUM_TYPE_FILE 0x46494C45 /* 'FILE' */
+#define SMB_SVCENUM_TYPE_SHARE 0x53484152 /* 'SHAR' */
-typedef struct smb_ioc_ulist {
+typedef struct smb_svcenum {
+ uint32_t se_type; /* object type to enumerate */
+ uint32_t se_level; /* level of detail being requested */
+ uint32_t se_prefmaxlen; /* client max size buffer preference */
+ uint32_t se_resume; /* client resume handle */
+ uint32_t se_bavail; /* remaining buffer space in bytes */
+ uint32_t se_bused; /* consumed buffer space in bytes */
+ uint32_t se_ntotal; /* total number of objects */
+ uint32_t se_nlimit; /* max number of objects to return */
+ uint32_t se_nitems; /* number of objects in buf */
+ uint32_t se_nskip; /* number of objects to skip */
+ uint32_t se_status; /* enumeration status */
+ uint32_t se_buflen; /* length of the buffer in bytes */
+ uint8_t se_buf[1]; /* buffer to hold enumeration data */
+} smb_svcenum_t;
+
+typedef struct smb_ioc_svcenum {
smb_ioc_header_t hdr;
- uint32_t cookie;
- uint32_t num;
- uint32_t data_len;
- uint8_t data[1];
-} smb_ioc_ulist_t;
+ smb_svcenum_t svcenum;
+} smb_ioc_svcenum_t;
+
+typedef struct smb_ioc_session {
+ smb_ioc_header_t hdr;
+ char client[MAXNAMELEN];
+ char username[MAXNAMELEN];
+} smb_ioc_session_t;
+
+typedef struct smb_ioc_fileid {
+ smb_ioc_header_t hdr;
+ uint32_t uniqid;
+} smb_ioc_fileid_t;
typedef struct smb_ioc_cfg {
smb_ioc_header_t hdr;
@@ -117,8 +156,10 @@
smb_ioc_cfg_t ioc_cfg;
smb_ioc_start_t ioc_start;
smb_ioc_listen_t ioc_listen;
- smb_ioc_usernum_t ioc_unum;
- smb_ioc_ulist_t ioc_ulist;
+ smb_ioc_opennum_t ioc_opennum;
+ smb_ioc_svcenum_t ioc_svcenum;
+ smb_ioc_session_t ioc_session;
+ smb_ioc_fileid_t ioc_fileid;
smb_ioc_share_t ioc_share;
} smb_ioc_t;
--- a/usr/src/uts/common/smbsrv/smb_kproto.h Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/smbsrv/smb_kproto.h Fri Jul 17 17:54:42 2009 -0700
@@ -198,6 +198,7 @@
((op)->create_disposition != FILE_SUPERSEDE) && \
((op)->create_disposition != FILE_OVERWRITE)) \
+uint32_t smb_lock_get_lock_count(smb_node_t *);
uint32_t smb_unlock_range(smb_request_t *, smb_node_t *,
uint64_t, uint64_t);
uint32_t smb_lock_range(smb_request_t *, uint64_t, uint64_t, uint32_t,
@@ -313,8 +314,6 @@
void smb_opipe_door_fini(void);
int smb_opipe_door_open(int);
void smb_opipe_door_close(void);
-void smb_user_context_init(smb_user_t *, smb_opipe_context_t *);
-void smb_user_context_fini(smb_opipe_context_t *);
/*
* SMB server functions (file smb_server.c)
@@ -329,13 +328,14 @@
int smb_server_tcp_listen(smb_ioc_listen_t *);
int smb_server_nbt_receive(void);
int smb_server_tcp_receive(void);
-uint32_t smb_server_get_user_count(void);
uint32_t smb_server_get_session_count(void);
int smb_server_share_export(smb_ioc_share_t *);
int smb_server_share_unexport(smb_ioc_share_t *);
int smb_server_set_gmtoff(smb_ioc_gmt_t *);
-int smb_server_user_number(smb_ioc_usernum_t *);
-int smb_server_user_list(smb_ioc_ulist_t *);
+int smb_server_numopen(smb_ioc_opennum_t *);
+int smb_server_enum(smb_ioc_svcenum_t *);
+int smb_server_session_close(smb_ioc_session_t *);
+int smb_server_file_close(smb_ioc_fileid_t *);
void smb_server_reconnection_check(smb_server_t *, smb_session_t *);
void smb_server_get_cfg(smb_server_t *, smb_kmod_cfg_t *);
@@ -474,6 +474,8 @@
void smb_session_list_terminate(smb_session_list_t *, smb_session_t *);
void smb_session_list_signal(smb_session_list_t *);
smb_user_t *smb_session_dup_user(smb_session_t *, char *, char *);
+void smb_session_getclient(smb_session_t *, char *, size_t);
+boolean_t smb_session_isclient(smb_session_t *, const char *);
void smb_session_correct_keep_alive_values(smb_session_list_t *, uint32_t);
void smb_session_oplock_break(smb_session_t *, smb_ofile_t *);
int smb_session_send(smb_session_t *, uint8_t type, mbuf_chain_t *);
@@ -489,16 +491,20 @@
* ofile functions (file smb_ofile.c)
*/
smb_ofile_t *smb_ofile_lookup_by_fid(smb_tree_t *, uint16_t);
+smb_ofile_t *smb_ofile_lookup_by_uniqid(smb_tree_t *, uint32_t);
+boolean_t smb_ofile_disallow_fclose(smb_ofile_t *);
smb_ofile_t *smb_ofile_open(smb_tree_t *, smb_node_t *, uint16_t,
open_param_t *, uint16_t, uint32_t, smb_error_t *);
void smb_ofile_close(smb_ofile_t *, uint32_t);
uint32_t smb_ofile_access(smb_ofile_t *, cred_t *, uint32_t);
int smb_ofile_seek(smb_ofile_t *, ushort_t, int32_t, uint32_t *);
+boolean_t smb_ofile_hold(smb_ofile_t *);
void smb_ofile_release(smb_ofile_t *);
void smb_ofile_close_all(smb_tree_t *);
void smb_ofile_close_all_by_pid(smb_tree_t *, uint16_t);
void smb_ofile_set_flags(smb_ofile_t *, uint32_t);
boolean_t smb_ofile_is_open(smb_ofile_t *);
+int smb_ofile_enum(smb_ofile_t *, smb_svcenum_t *);
uint32_t smb_ofile_open_check(smb_ofile_t *, cred_t *, uint32_t, uint32_t);
uint32_t smb_ofile_rename_check(smb_ofile_t *);
uint32_t smb_ofile_delete_check(smb_ofile_t *);
@@ -554,12 +560,19 @@
smb_tree_t *smb_user_lookup_share(smb_user_t *, const char *, smb_tree_t *);
smb_tree_t *smb_user_lookup_volume(smb_user_t *, const char *, smb_tree_t *);
boolean_t smb_user_is_admin(smb_user_t *);
+boolean_t smb_user_namecmp(smb_user_t *, const char *);
+int smb_user_enum(smb_user_t *, smb_svcenum_t *);
void smb_user_close_pid(smb_user_t *, uint16_t);
void smb_user_disconnect_trees(smb_user_t *user);
void smb_user_disconnect_share(smb_user_t *, const char *);
+int smb_user_fclose(smb_user_t *, uint32_t);
+boolean_t smb_user_hold(smb_user_t *);
void smb_user_release(smb_user_t *);
cred_t *smb_user_getcred(smb_user_t *);
cred_t *smb_user_getprivcred(smb_user_t *);
+void smb_user_netinfo_init(smb_user_t *, smb_netuserinfo_t *);
+void smb_user_netinfo_fini(smb_netuserinfo_t *);
+int smb_user_netinfo_encode(smb_user_t *, uint8_t *, size_t, uint32_t *);
/*
* SMB tree functions (file smb_tree.c)
@@ -568,6 +581,8 @@
void smb_tree_disconnect(smb_tree_t *, boolean_t);
void smb_tree_close_pid(smb_tree_t *, uint16_t);
boolean_t smb_tree_has_feature(smb_tree_t *, uint_t);
+int smb_tree_enum(smb_tree_t *, smb_svcenum_t *);
+int smb_tree_fclose(smb_tree_t *, uint32_t);
boolean_t smb_tree_hold(smb_tree_t *);
void smb_tree_release(smb_tree_t *);
smb_odir_t *smb_tree_lookup_odir(smb_tree_t *, uint16_t);
--- a/usr/src/uts/common/smbsrv/smb_ktypes.h Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/smbsrv/smb_ktypes.h Fri Jul 17 17:54:42 2009 -0700
@@ -507,10 +507,9 @@
volatile int flags; /* FILE_NOTIFY_CHANGE_* */
volatile int waiting_event; /* # of clients requesting FCN */
smb_times_t n_timestamps; /* cached timestamps */
- unsigned int what;
smb_oplock_t n_oplock;
- struct smb_node *dir_snode; /* Directory of node */
- struct smb_node *unnamed_stream_node; /* set in stream nodes */
+ struct smb_node *n_dnode; /* directory node */
+ struct smb_node *n_unode; /* unnamed stream node */
/* Credentials for delayed delete */
cred_t *delete_on_close_cred;
uint32_t n_delete_on_close_flags;
@@ -873,6 +872,8 @@
acl_type_t t_acltype;
uint32_t t_access;
uint32_t t_shr_flags;
+ time_t t_connect_time;
+ volatile uint32_t t_open_files;
} smb_tree_t;
#define SMB_TREE_VFS(tree) ((tree)->t_snode->vp->v_vfsp)
@@ -942,7 +943,7 @@
char *p_name;
uint32_t p_busy;
smb_opipe_hdr_t p_hdr;
- smb_opipe_context_t p_context;
+ smb_netuserinfo_t p_user;
uint8_t *p_doorbuf;
uint8_t *p_data;
} smb_opipe_t;
@@ -1656,7 +1657,7 @@
char name[MAXNAMELEN];
} smb_trans2_setinfo_t;
-#define SMB_IS_STREAM(node) ((node)->unnamed_stream_node)
+#define SMB_IS_STREAM(node) ((node)->n_unode)
typedef struct smb_tsd {
void (*proc)();
--- a/usr/src/uts/common/smbsrv/smb_xdr.h Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/smbsrv/smb_xdr.h Fri Jul 17 17:54:42 2009 -0700
@@ -33,6 +33,7 @@
#include <rpc/xdr.h>
#include <sys/param.h>
#include <smbsrv/smbinfo.h>
+#include <smbsrv/smb_ioctl.h>
typedef struct smb_dr_kshare {
int32_t k_op;
@@ -46,10 +47,6 @@
#define xdr_int16_t xdr_short
#define xdr_uint16_t xdr_u_short
-extern bool_t xdr_u_char(XDR *xdrs, uchar_t *cp);
-extern bool_t xdr_vector(XDR *xdrs, char *basep, uint_t nelem,
- uint_t elemsize, xdrproc_t xdr_elem);
-
smb_dr_kshare_t *smb_share_mkabsolute(uint8_t *buf, uint32_t len);
#else
uint8_t *smb_kshare_mkselfrel(smb_dr_kshare_t *kshare, uint32_t *len);
@@ -91,25 +88,68 @@
uint32_t oh_status;
} smb_opipe_hdr_t;
-typedef struct smb_opipe_context {
- uint64_t oc_session_id;
- uint16_t oc_uid;
- uint16_t oc_domain_len;
- char *oc_domain;
- uint16_t oc_account_len;
- char *oc_account;
- uint16_t oc_workstation_len;
- char *oc_workstation;
- smb_inaddr_t oc_ipaddr;
- int32_t oc_native_os;
- int64_t oc_logon_time;
- uint32_t oc_flags;
-} smb_opipe_context_t;
+typedef struct smb_netuserinfo {
+ uint64_t ui_session_id;
+ uint16_t ui_uid;
+ uint16_t ui_domain_len;
+ char *ui_domain;
+ uint16_t ui_account_len;
+ char *ui_account;
+ uint16_t ui_workstation_len;
+ char *ui_workstation;
+ smb_inaddr_t ui_ipaddr;
+ int32_t ui_native_os;
+ int64_t ui_logon_time;
+ uint32_t ui_numopens;
+ uint32_t ui_flags;
+} smb_netuserinfo_t;
+
+typedef struct smb_opennum {
+ uint32_t open_users;
+ uint32_t open_trees;
+ uint32_t open_files;
+ uint32_t qualtype;
+ char qualifier[MAXNAMELEN];
+} smb_opennum_t;
-typedef struct smb_ulist {
- uint32_t ul_cnt;
- smb_opipe_context_t *ul_users;
-} smb_ulist_t;
+typedef struct smb_netconnectinfo {
+ uint32_t ci_id;
+ uint32_t ci_type;
+ uint32_t ci_numopens;
+ uint32_t ci_numusers;
+ uint32_t ci_time;
+ uint32_t ci_namelen;
+ uint32_t ci_sharelen;
+ char *ci_username;
+ char *ci_share;
+} smb_netconnectinfo_t;
+
+typedef struct smb_netfileinfo {
+ uint16_t fi_fid;
+ uint32_t fi_uniqid;
+ uint32_t fi_permissions;
+ uint32_t fi_numlocks;
+ uint32_t fi_pathlen;
+ uint32_t fi_namelen;
+ char *fi_path;
+ char *fi_username;
+} smb_netfileinfo_t;
+
+typedef struct smb_netsvcitem {
+ list_node_t nsi_lnd;
+ union {
+ smb_netuserinfo_t nsi_user;
+ smb_netconnectinfo_t nsi_tree;
+ smb_netfileinfo_t nsi_ofile;
+ } nsi_un;
+} smb_netsvcitem_t;
+
+typedef struct smb_netsvc {
+ list_t ns_list;
+ smb_netsvcitem_t *ns_items;
+ smb_ioc_svcenum_t *ns_ioc;
+ uint32_t ns_ioclen;
+} smb_netsvc_t;
/* xdr routines for common door arguments/results */
extern bool_t xdr_smb_dr_string_t(XDR *, smb_dr_string_t *);
@@ -120,11 +160,18 @@
int smb_opipe_hdr_encode(smb_opipe_hdr_t *, uint8_t *, uint32_t);
int smb_opipe_hdr_decode(smb_opipe_hdr_t *, uint8_t *, uint32_t);
bool_t smb_opipe_hdr_xdr(XDR *xdrs, smb_opipe_hdr_t *objp);
-int smb_opipe_context_encode(smb_opipe_context_t *, uint8_t *, uint32_t,
+int smb_netuserinfo_encode(smb_netuserinfo_t *, uint8_t *, uint32_t, uint_t *);
+int smb_netuserinfo_decode(smb_netuserinfo_t *, uint8_t *, uint32_t, uint_t *);
+bool_t smb_netuserinfo_xdr(XDR *, smb_netuserinfo_t *);
+int smb_netconnectinfo_encode(smb_netconnectinfo_t *, uint8_t *, uint32_t,
uint_t *);
-int smb_opipe_context_decode(smb_opipe_context_t *, uint8_t *, uint32_t,
+int smb_netconnectinfo_decode(smb_netconnectinfo_t *, uint8_t *, uint32_t,
uint_t *);
-bool_t smb_opipe_context_xdr(XDR *, smb_opipe_context_t *);
+bool_t smb_netconnectinfo_xdr(XDR *, smb_netconnectinfo_t *);
+int smb_netfileinfo_encode(smb_netfileinfo_t *, uint8_t *, uint32_t, uint_t *);
+int smb_netfileinfo_decode(smb_netfileinfo_t *, uint8_t *, uint32_t, uint_t *);
+bool_t smb_netfileinfo_xdr(XDR *, smb_netfileinfo_t *);
+
/*
* VSS Door Structures
*/
--- a/usr/src/uts/common/sys/lvm/meta_basic.x Fri Jul 17 16:57:52 2009 -0600
+++ b/usr/src/uts/common/sys/lvm/meta_basic.x Fri Jul 17 17:54:42 2009 -0700
@@ -20,7 +20,7 @@
% */
%
%/*
-% * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+% * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
% * Use is subject to license terms.
% */
%
@@ -177,42 +177,6 @@
% return (FALSE);
% return (TRUE);
%}
-%
-#ifdef _KERNEL
-%
-%#define LASTUNSIGNED ((u_int)0-1)
-%
-%/*
-% * xdr_vector():
-% *
-% * XDR a fixed length array. Unlike variable-length arrays,
-% * the storage of fixed length arrays is static and unfreeable.
-% * > basep: base of the array
-% * > size: size of the array
-% * > elemsize: size of each element
-% * > xdr_elem: routine to XDR each element
-% */
-%bool_t
-%xdr_vector(xdrs, basep, nelem, elemsize, xdr_elem)
-% XDR *xdrs;
-% char *basep;
-% u_int nelem;
-% u_int elemsize;
-% xdrproc_t xdr_elem;
-%{
-% u_int i;
-% char *elptr;
-%
-% elptr = basep;
-% for (i = 0; i < nelem; i++) {
-% if (! (*xdr_elem)(xdrs, elptr, LASTUNSIGNED)) {
-% return (FALSE);
-% }
-% elptr += elemsize;
-% }
-% return (TRUE);
-%}
-#endif /* _KERNEL */
#endif /* RPC_XDR */
#ifdef RPC_HDR
@@ -351,11 +315,6 @@
%extern bool_t xdr_minor_t(XDR *xdrs, minor_t *objp);
%extern bool_t xdr_timeval(XDR *xdrs, struct timeval *objp);
%extern bool_t xdr_clnt_stat(XDR *xdrs, enum clnt_stat *objp);
-#ifdef _KERNEL
-%extern bool_t xdr_vector(XDR *xdrs, char *basep,
-% u_int nelem, u_int elemsize,
-% xdrproc_t xdr_elem);
-#endif /* _KERNEL */
%#else /* K&R C */
#ifndef _KERNEL
%extern bool_t xdr_uint_t();
@@ -374,9 +333,5 @@
%extern bool_t xdr_minor_t();
%extern bool_t xdr_timeval();
%extern bool_t xdr_clnt_stat();
-%
-#ifdef _KERNEL
-%extern bool_t xdr_vector();
-#endif /* _KERNEL */
%#endif /* K&R C */
#endif /* RPC_HDR */