Mercurial > illumos > illumos-gate
changeset 12902:16985853e3aa
6957935 Only one standalone DFS namespace should be cached
6958322 Should allow setting and returning target priority info for DFS root target
6955030 assertion failed in thread_join() from smb_server_delete()
6950891 No "no matching rule" trace point for pid->sid
6957520 Sparc - System panics when running smbstat
6950103 Failed to open group database due to too many open files
6961197 SAMR requests failed due to context mismatch
6960835 Need to pass the share type to smbsrv
6952831 SMB level II oplocks
6955337 "Found in AD" tracepoint bogus for U->W with directory-based mapping
6960038 CIFS file ownership problem
6915527 libidmap should not export memdup()
6960283 Windows client dir /R option not listing NTFS named stream
6808472 SMB name space caching on clients
6966183 SMB/CIFS print service CUPS support
6966490 Validation support for NetrDfsSetInfo method, level 105
6962887 Restore kstats for SMB commands
6969600 ::smblist -r[v] crashed mdb
6968451 panic: smbsrv:smb_odir_open
6957572 Cifs server panics at ffffff000c895ad0 smbsrv:smb_user_delete+82 () with smbtorture test.
line wrap: on
line diff
--- a/usr/src/cmd/idmap/idmapd/Makefile Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/cmd/idmap/idmapd/Makefile Thu Jul 22 14:53:56 2010 -0700 @@ -34,7 +34,7 @@ idmap_config.o \ idmapd.o \ init.o \ - idmap_lsa.o \ + idmap_lsa.o \ nldaputils.o \ rpc_svc.o \ server.o \ @@ -89,6 +89,7 @@ -ladutils \ -lumem \ -lnvpair \ + -luutil \ -L $(ROOT)/usr/lib/smbsrv \ -lsmb
--- a/usr/src/cmd/idmap/idmapd/dbutils.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/cmd/idmap/idmapd/dbutils.c Thu Jul 22 14:53:56 2010 -0700 @@ -41,6 +41,7 @@ #include <assert.h> #include <sys/u8_textprep.h> #include <alloca.h> +#include <libuutil.h> #include <note.h> #include "idmapd.h" @@ -50,7 +51,6 @@ #include "schema.h" #include "nldaputils.h" #include "idmap_lsa.h" -#include "miscutils.h" static idmap_retcode sql_compile_n_step_once(sqlite *, char *, @@ -59,8 +59,6 @@ static idmap_retcode lookup_cache_name2sid(sqlite *, const char *, const char *, char **, char **, idmap_rid_t *, idmap_id_type *); -#define NELEM(a) (sizeof (a) / sizeof ((a)[0])) - #define EMPTY_NAME(name) (*name == 0 || strcmp(name, "\"\"") == 0) #define DO_NOT_ALLOC_NEW_ID_MAPPING(req)\ @@ -2256,8 +2254,15 @@ } if (IS_ID_SID(req->id1)) { - if (res->retcode != IDMAP_SUCCESS) + if (res->retcode == IDMAP_ERR_NOTFOUND) { + TRACE(req, res, "Not found in AD"); continue; + } + if (res->retcode != IDMAP_SUCCESS) { + TRACE(req, res, "AD lookup error=%d", + res->retcode); + continue; + } /* Evaluate result type */ switch (type) { case IDMAP_USID: @@ -2302,6 +2307,7 @@ res->retcode = IDMAP_ERR_SID; break; } + TRACE(req, res, "Found in AD"); if (res->retcode == IDMAP_SUCCESS && req->id1name != NULL && (req->id2name == NULL || @@ -2314,7 +2320,7 @@ if (res->retcode != IDMAP_SUCCESS) { if ((!(IDMAP_FATAL_ERROR(res->retcode))) && res->id.idmap_id_u.sid.prefix == NULL && - req->id2name == NULL) /* no winname */ + req->id2name == NULL) { /* * If AD lookup by unixname or pid * failed with non fatal error @@ -2324,7 +2330,20 @@ * process other mapping * mechanisms for this request. */ - res->retcode = IDMAP_SUCCESS; + if (res->retcode == + IDMAP_ERR_NOTFOUND) { + /* This is not an error */ + res->retcode = IDMAP_SUCCESS; + TRACE(req, res, + "Not found in AD"); + } else { + TRACE(req, res, + "AD lookup error (ignored)"); + res->retcode = IDMAP_SUCCESS; + } + } else { + TRACE(req, res, "AD lookup error"); + } continue; } /* Evaluate result type */ @@ -2339,6 +2358,7 @@ res->retcode = IDMAP_ERR_SID; break; } + TRACE(req, res, "Found in AD"); } } @@ -2535,7 +2555,7 @@ if (p != NULL) { char *q; q = req->id1name; - req->id1name = strndup(q, p - req->id1name); + req->id1name = uu_strndup(q, p - req->id1name); req->id1domain = strdup(p+1); free(q); if (req->id1name == NULL || @@ -3126,6 +3146,7 @@ } goto out; } else if (r == SQLITE_DONE) { + TRACE(req, res, "No matching rule"); retcode = IDMAP_ERR_NOTFOUND; goto out; } else { @@ -3523,7 +3544,6 @@ TRACE(req, res, "Rule-based mapping error=%d", retcode); goto out; } - TRACE(req, res, "No matching rule"); do_eph: /* If not found, do ephemeral mapping */ @@ -4390,7 +4410,6 @@ int ncol, r; int want_wuser; const char *me = "name_based_mapping_pid2sid"; - int non_wild_match = FALSE; idmap_namerule *rule = &res->info.how.idmap_how_u.rule; int direction; @@ -4459,28 +4478,10 @@ if (values[0][0] == '*') { winname = unixname; - if (non_wild_match) { - /* - * There were non-wildcard rules - * where the Windows identity doesn't - * exist. Return no mapping. - */ - retcode = IDMAP_ERR_NOMAPPING; - goto out; - } } else { - /* Save first non-wild match rule */ - if (!non_wild_match) { - idmap_namerule_set(rule, values[1], - values[0], values[4], - is_user, - strtol(values[3], &end, 10), - strtol(values[5], &end, 10), - direction); - non_wild_match = TRUE; - } winname = values[0]; } + want_wuser = res->id.idtype == IDMAP_USID ? 1 : res->id.idtype == IDMAP_GSID ? 0 : -1; @@ -4509,28 +4510,34 @@ if (retcode == IDMAP_SUCCESS) { break; } else if (retcode == IDMAP_ERR_NOTFOUND) { - TRACE(req, res, - "%s@%s not found, continuing", - winname, windomain); - continue; + if (values[0][0] == '*') { + TRACE(req, res, + "%s@%s not found, continuing", + winname, windomain); + continue; + } else { + TRACE(req, res, + "%s@%s not found", + winname, windomain); + retcode = IDMAP_ERR_NOMAPPING; + } } else { TRACE(req, res, "Looking up %s@%s error=%d", winname, windomain, retcode); } + idmap_namerule_set(rule, values[1], + values[0], values[4], is_user, + strtol(values[3], &end, 10), + strtol(values[5], &end, 10), + direction); + goto out; } else if (r == SQLITE_DONE) { - /* - * If there were non-wildcard rules where - * Windows identity doesn't exist - * return no mapping. - */ - if (non_wild_match) - retcode = IDMAP_ERR_NOMAPPING; - else - retcode = IDMAP_ERR_NOTFOUND; + TRACE(req, res, "No matching rule"); + retcode = IDMAP_ERR_NOTFOUND; goto out; } else { (void) sqlite_finalize(vm, &errmsg);
--- a/usr/src/cmd/idmap/idmapd/directory_provider_ad.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/cmd/idmap/idmapd/directory_provider_ad.c Thu Jul 22 14:53:56 2010 -0700 @@ -20,8 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -36,6 +35,7 @@ #include <stdlib.h> #include <netdb.h> #include <libadutils.h> +#include <libuutil.h> #include <note.h> #include <assert.h> #include "directory.h" @@ -43,7 +43,6 @@ #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 @@ -85,7 +84,7 @@ maybe_add_to_list(const char **list, const char *s) { for (; *list != NULL; list++) { - if (strcaseeq(*list, s)) + if (uu_strcaseeq(*list, s)) return; } *list = s; @@ -117,7 +116,7 @@ * Note that you must update MAX_EXTRA_ATTRS above if you * add to this list. */ - if (strcaseeq(a, "x-sun-canonicalName")) { + if (uu_strcaseeq(a, "x-sun-canonicalName")) { maybe_add_to_list(new_list, "sAMAccountName"); continue; } @@ -222,7 +221,7 @@ vw[0] = name; - if (streq(domain, "")) { + if (uu_streq(domain, "")) { vw[1] = default_domain; } else { vw[1] = domain; @@ -427,7 +426,7 @@ ldap_value_free_len(bv); if (de != NULL) goto err; - } else if (strcaseeq(a, "x-sun-canonicalName")) { + } else if (uu_strcaseeq(a, "x-sun-canonicalName")) { bv = ldap_get_values_len(ld, msg, "sAMAccountName"); if (bv != NULL) { int n = ldap_count_values_len(bv); @@ -445,7 +444,7 @@ goto err; } } - } else if (strcaseeq(a, "x-sun-provider")) { + } else if (uu_strcaseeq(a, "x-sun-provider")) { const char *provider = "LDAP-AD"; de = str_list_dav(val, &provider, 1); } @@ -492,7 +491,7 @@ for (i = 0; i < n; i++) { dav[i].directory_value_rpc_val = - memdup(bv[i]->bv_val, bv[i]->bv_len); + uu_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;
--- a/usr/src/cmd/idmap/idmapd/directory_provider_builtin.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/cmd/idmap/idmapd/directory_provider_builtin.c Thu Jul 22 14:53:56 2010 -0700 @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -35,13 +34,13 @@ #include <string.h> #include <stdlib.h> #include <netdb.h> +#include <libuutil.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, @@ -91,7 +90,7 @@ * End-to-end error injection point. * NEEDSWORK: should probably eliminate this for production */ - if (streq(id, " DEBUG BUILTIN ERROR ")) { + if (uu_streq(id, " DEBUG BUILTIN ERROR ")) { directory_entry_set_error(&del[i], directory_error("Directory_provider_builtin.debug", "Directory_provider_builtin: artificial error", @@ -183,21 +182,22 @@ val->found = FALSE; de = NULL; - if (strcaseeq(a, "uid")) { + if (uu_strcaseeq(a, "uid")) { de = str_list_dav(val, &wksid->winname, 1); - } else if (strcaseeq(a, "uidNumber")) { + } else if (uu_strcaseeq(a, "uidNumber")) { if (wksid->pid != IDMAP_SENTINEL_PID && wksid->is_user) { de = uint_list_dav(val, &wksid->pid, 1); } - } else if (strcaseeq(a, "gidNumber")) { + } else if (uu_strcaseeq(a, "gidNumber")) { if (wksid->pid != IDMAP_SENTINEL_PID && !wksid->is_user) { de = uint_list_dav(val, &wksid->pid, 1); } - } else if (strcaseeq(a, "displayName") || strcaseeq(a, "cn")) { + } else if (uu_strcaseeq(a, "displayName") || + uu_strcaseeq(a, "cn")) { de = str_list_dav(val, &wksid->winname, 1); - } else if (strcaseeq(a, "distinguishedName")) { + } else if (uu_strcaseeq(a, "distinguishedName")) { char *container; if (wksid->domain == NULL) { container = "Users"; @@ -213,7 +213,7 @@ const char *cdn = dn; de = str_list_dav(val, &cdn, 1); free(dn); - } else if (strcaseeq(a, "objectClass")) { + } else if (uu_strcaseeq(a, "objectClass")) { if (wksid->is_wuser) { static const char *objectClasses[] = { "top", @@ -222,18 +222,18 @@ "user", }; de = str_list_dav(val, objectClasses, - NELEM(objectClasses)); + UU_NELEM(objectClasses)); } else { static const char *objectClasses[] = { "top", "group", }; de = str_list_dav(val, objectClasses, - NELEM(objectClasses)); + UU_NELEM(objectClasses)); } - } else if (strcaseeq(a, "objectSid")) { + } else if (uu_strcaseeq(a, "objectSid")) { de = sid_dav(val, wksid); - } else if (strcaseeq(a, "x-sun-canonicalName")) { + } else if (uu_strcaseeq(a, "x-sun-canonicalName")) { char *canon; if (wksid->domain == NULL) { @@ -241,7 +241,7 @@ (void) asprintf(&canon, "%s@%s", wksid->winname, _idmapdstate.hostname); UNLOCK_CONFIG(); - } else if (streq(wksid->domain, "")) { + } else if (uu_streq(wksid->domain, "")) { canon = strdup(wksid->winname); } else { (void) asprintf(&canon, "%s@%s", @@ -253,7 +253,7 @@ const char *ccanon = canon; de = str_list_dav(val, &ccanon, 1); free(canon); - } else if (strcaseeq(a, "x-sun-provider")) { + } else if (uu_strcaseeq(a, "x-sun-provider")) { const char *provider = "Builtin"; de = str_list_dav(val, &provider, 1); }
--- a/usr/src/cmd/idmap/idmapd/directory_provider_nsswitch.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/cmd/idmap/idmapd/directory_provider_nsswitch.c Thu Jul 22 14:53:56 2010 -0700 @@ -20,8 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -35,6 +34,7 @@ #include <string.h> #include <stdlib.h> #include <netdb.h> +#include <libuutil.h> #include <note.h> #include <errno.h> #include "idmapd.h" @@ -42,7 +42,6 @@ #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, @@ -299,25 +298,25 @@ /* * Handle attributes for user entries. */ - if (strcaseeq(a, "cn")) { + if (uu_strcaseeq(a, "cn")) { const char *p = pwd->pw_name; de = str_list_dav(val, &p, 1); - } else if (strcaseeq(a, "objectClass")) { + } else if (uu_strcaseeq(a, "objectClass")) { static const char *objectClasses[] = { "top", "posixAccount", }; de = str_list_dav(val, objectClasses, - NELEM(objectClasses)); - } else if (strcaseeq(a, "gidNumber")) { + UU_NELEM(objectClasses)); + } else if (uu_strcaseeq(a, "gidNumber")) { de = uint_list_dav(val, &pwd->pw_gid, 1); - } else if (strcaseeq(a, "objectSid")) { + } else if (uu_strcaseeq(a, "objectSid")) { de = machine_sid_dav(val, pwd->pw_uid + LOCALRID_UID_MIN); - } else if (strcaseeq(a, "displayName")) { + } else if (uu_strcaseeq(a, "displayName")) { const char *p = pwd->pw_gecos; de = str_list_dav(val, &p, 1); - } else if (strcaseeq(a, "distinguishedName")) { + } else if (uu_strcaseeq(a, "distinguishedName")) { char *dn; RDLOCK_CONFIG(); (void) asprintf(&dn, @@ -329,21 +328,21 @@ const char *cdn = dn; de = str_list_dav(val, &cdn, 1); free(dn); - } else if (strcaseeq(a, "uid")) { + } else if (uu_strcaseeq(a, "uid")) { const char *p = pwd->pw_name; de = str_list_dav(val, &p, 1); - } else if (strcaseeq(a, "uidNumber")) { + } else if (uu_strcaseeq(a, "uidNumber")) { de = uint_list_dav(val, &pwd->pw_uid, 1); - } else if (strcaseeq(a, "gecos")) { + } else if (uu_strcaseeq(a, "gecos")) { const char *p = pwd->pw_gecos; de = str_list_dav(val, &p, 1); - } else if (strcaseeq(a, "homeDirectory")) { + } else if (uu_strcaseeq(a, "homeDirectory")) { const char *p = pwd->pw_dir; de = str_list_dav(val, &p, 1); - } else if (strcaseeq(a, "loginShell")) { + } else if (uu_strcaseeq(a, "loginShell")) { const char *p = pwd->pw_shell; de = str_list_dav(val, &p, 1); - } else if (strcaseeq(a, "x-sun-canonicalName")) { + } else if (uu_strcaseeq(a, "x-sun-canonicalName")) { char *canon; RDLOCK_CONFIG(); (void) asprintf(&canon, "%s@%s", @@ -354,7 +353,7 @@ const char *ccanon = canon; de = str_list_dav(val, &ccanon, 1); free(canon); - } else if (strcaseeq(a, "x-sun-provider")) { + } else if (uu_strcaseeq(a, "x-sun-provider")) { const char *provider = "UNIX-passwd"; de = str_list_dav(val, &provider, 1); } @@ -362,25 +361,25 @@ /* * Handle attributes for group entries. */ - if (strcaseeq(a, "cn")) { + if (uu_strcaseeq(a, "cn")) { const char *p = grp->gr_name; de = str_list_dav(val, &p, 1); - } else if (strcaseeq(a, "objectClass")) { + } else if (uu_strcaseeq(a, "objectClass")) { static const char *objectClasses[] = { "top", "posixGroup", }; de = str_list_dav(val, objectClasses, - NELEM(objectClasses)); - } else if (strcaseeq(a, "gidNumber")) { + UU_NELEM(objectClasses)); + } else if (uu_strcaseeq(a, "gidNumber")) { de = uint_list_dav(val, &grp->gr_gid, 1); - } else if (strcaseeq(a, "objectSid")) { + } else if (uu_strcaseeq(a, "objectSid")) { de = machine_sid_dav(val, grp->gr_gid + LOCALRID_GID_MIN); - } else if (strcaseeq(a, "displayName")) { + } else if (uu_strcaseeq(a, "displayName")) { const char *p = grp->gr_name; de = str_list_dav(val, &p, 1); - } else if (strcaseeq(a, "distinguishedName")) { + } else if (uu_strcaseeq(a, "distinguishedName")) { char *dn; RDLOCK_CONFIG(); (void) asprintf(&dn, @@ -392,7 +391,7 @@ const char *cdn = dn; de = str_list_dav(val, &cdn, 1); free(dn); - } else if (strcaseeq(a, "memberUid")) { + } else if (uu_strcaseeq(a, "memberUid")) { /* * NEEDSWORK: There is probably a non-cast * way to do this, but I don't immediately @@ -401,7 +400,7 @@ const char * const *members = (const char * const *)grp->gr_mem; de = str_list_dav(val, members, 0); - } else if (strcaseeq(a, "x-sun-canonicalName")) { + } else if (uu_strcaseeq(a, "x-sun-canonicalName")) { char *canon; RDLOCK_CONFIG(); (void) asprintf(&canon, "%s@%s", @@ -412,7 +411,7 @@ const char *ccanon = canon; de = str_list_dav(val, &ccanon, 1); free(canon); - } else if (strcaseeq(a, "x-sun-provider")) { + } else if (uu_strcaseeq(a, "x-sun-provider")) { const char *provider = "UNIX-group"; de = str_list_dav(val, &provider, 1); }
--- a/usr/src/cmd/idmap/idmapd/directory_server.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/cmd/idmap/idmapd/directory_server.c Thu Jul 22 14:53:56 2010 -0700 @@ -20,8 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -37,6 +36,7 @@ #include <pthread.h> #include <unistd.h> #include <string.h> +#include <libuutil.h> #include <note.h> #include "idmapd.h" #include "directory.h" @@ -45,7 +45,6 @@ #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 @@ -98,7 +97,7 @@ } } - for (i = 0; i < NELEM(providers); i++) { + for (i = 0; i < UU_NELEM(providers); i++) { de = providers[i]->get(entries, &ids, types, &attrs); if (de != NULL) @@ -176,7 +175,7 @@ int len; len = strlen(str_list[i]); - dav[i].directory_value_rpc_val = memdup(str_list[i], len); + dav[i].directory_value_rpc_val = uu_memdup(str_list[i], len); if (dav[i].directory_value_rpc_val == NULL) goto nomem; dav[i].directory_value_rpc_len = len; @@ -224,7 +223,7 @@ (void) snprintf(buf, sizeof (buf), "%u", array[i]); len = strlen(buf); - dav[i].directory_value_rpc_val = memdup(buf, len); + dav[i].directory_value_rpc_val = uu_memdup(buf, len); if (dav[i].directory_value_rpc_val == NULL) goto nomem; dav[i].directory_value_rpc_len = len; @@ -263,7 +262,7 @@ lvals->found = TRUE; for (i = 0; i < n; i++) { - dav[i].directory_value_rpc_val = memdup(inbuf, sz); + dav[i].directory_value_rpc_val = uu_memdup(inbuf, sz); if (dav[i].directory_value_rpc_val == NULL) goto nomem; dav[i].directory_value_rpc_len = sz;
--- a/usr/src/cmd/idmap/idmapd/server.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/cmd/idmap/idmapd/server.c Thu Jul 22 14:53:56 2010 -0700 @@ -364,12 +364,6 @@ "AD lookup - domain not found (ignored)"); continue; } - if (res->retcode == IDMAP_SUCCESS) - TRACE(req, res, "Found in AD"); - else if (res->retcode == IDMAP_ERR_NOTFOUND) - TRACE(req, res, "Not found in AD"); - else - TRACE(req, res, "AD lookup error"); } }
--- a/usr/src/cmd/idmap/idmapd/wksids.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/cmd/idmap/idmapd/wksids.c Thu Jul 22 14:53:56 2010 -0700 @@ -30,8 +30,8 @@ #include <assert.h> #include <string.h> +#include <libuutil.h> #include "idmapd.h" -#include "miscutils.h" /* * Table for well-known SIDs. @@ -232,7 +232,7 @@ (void) strcpy(my_host_name, _idmapdstate.hostname); UNLOCK_CONFIG(); - for (i = 0; i < NELEM(wksids); i++) { + for (i = 0; i < UU_NELEM(wksids); i++) { /* Check to see if this entry yields the desired type */ switch (type) { case IDMAP_UID: @@ -295,7 +295,7 @@ (void) strcpy(my_machine_sid, _idmapdstate.cfg->pgcfg.machine_sid); UNLOCK_CONFIG(); - for (i = 0; i < NELEM(wksids); i++) { + for (i = 0; i < UU_NELEM(wksids); i++) { int sidcmp; /* Check to see if this entry yields the desired type */ @@ -352,7 +352,7 @@ if (pid == IDMAP_SENTINEL_PID) return (NULL); - for (i = 0; i < NELEM(wksids); i++) { + for (i = 0; i < UU_NELEM(wksids); i++) { if (wksids[i].pid == pid && wksids[i].is_user == is_user && (wksids[i].direction == IDMAP_DIRECTION_BI || @@ -380,7 +380,7 @@ (void) strcpy(my_machine_sid, _idmapdstate.cfg->pgcfg.machine_sid); UNLOCK_CONFIG(); - for (i = 0; i < NELEM(wksids); i++) { + for (i = 0; i < UU_NELEM(wksids); i++) { int len; const char *prefix; char *p;
--- a/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c Thu Jul 22 14:53:56 2010 -0700 @@ -375,6 +375,8 @@ static int smb_node_walk_init(mdb_walk_state_t *); static int smb_node_walk_step(mdb_walk_state_t *); static int smb_lock(uintptr_t, uint_t, int, const mdb_arg_t *); +static int smb_oplock(uintptr_t, uint_t, int, const mdb_arg_t *); +static int smb_oplock_grant(uintptr_t, uint_t, int, const mdb_arg_t *); static int smb_ace(uintptr_t, uint_t, int, const mdb_arg_t *); static int smb_ace_walk_init(mdb_walk_state_t *); static int smb_ace_walk_step(mdb_walk_state_t *); @@ -443,8 +445,12 @@ smb_dcmd_odir }, { "smbofile", "[-v]", - "print smb_odir_t information", + "print smb_file_t information", smb_dcmd_ofile }, + { "smboplock", NULL, + "print smb_oplock_t information", smb_oplock }, + { "smboplockgrant", NULL, + "print smb_oplock_grant_t information", smb_oplock_grant }, { "smbstat", NULL, "print all smb dispatched requests statistics", smb_stats }, @@ -799,7 +805,7 @@ #define SMB_REQUEST_BANNER \ "%<b>%<u>%-?s %-?s %-14s %-14s %-16s %-32s%</u>%</b>\n" #define SMB_REQUEST_FORMAT \ - "%-?p %-?p %e %e %-16s %s\n" + "%-?p %-?p %-14lld %-14lld %-16s %s\n" static int smb_dcmd_request(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) @@ -866,10 +872,12 @@ "FID(file): %u (%p)\n" "PID: %u\n" "MID: %u\n\n" - "waiting time: %1.3e\n" - "running time: %1.3e", - sr->first_smb_com, smb_com[sr->first_smb_com], - sr->smb_com, smb_com[sr->smb_com], + "waiting time: %lld\n" + "running time: %lld\n", + sr->first_smb_com, + smb_com[sr->first_smb_com].smb_com, + sr->smb_com, + smb_com[sr->smb_com].smb_com, sr->sr_state, state, sr->smb_tid, sr->tid_tree, sr->smb_uid, sr->uid_user, @@ -897,7 +905,7 @@ waiting, running, state, - smb_com[sr->smb_com]); + smb_com[sr->smb_com].smb_com); } } return (DCMD_OK); @@ -1403,13 +1411,14 @@ smb_node(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { smb_node_t node; + int rc; int verbose = FALSE; int print_full_path = FALSE; int stack_trace = FALSE; vnode_t vnode; char od_name[MAXNAMELEN]; char path_name[1024]; - uintptr_t list_addr; + uintptr_t list_addr, oplock_addr; if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &verbose, @@ -1446,9 +1455,10 @@ "%-18s " "%-6s " "%-6s " + "%-8s " "%-6s%</u>%</b>\n", "ADDR", "VP", "NODE-NAME", "OFILES", "LOCKS", - "REF"); + "OPLOCK", "REF"); } } @@ -1489,11 +1499,25 @@ } (void) mdb_dec_indent(SMB_DCMD_INDENT); } + if (node.n_oplock.ol_count == 0) { + mdb_printf("Opportunistic Locks: 0\n"); + } else { + oplock_addr = + addr + offsetof(smb_node_t, n_oplock); + mdb_printf("Opportunistic Lock: %p\n", + oplock_addr); + rc = mdb_call_dcmd("smboplock", oplock_addr, + flags, argc, argv); + if (rc != DCMD_OK) + return (rc); + } mdb_printf("Reference Count: %u\n\n", node.n_refcnt); } else { - mdb_printf("%-?p %-?p %-18s %-6d %-6d %-6d\n", + mdb_printf("%-?p %-?p %-18s %-6d %-6d %-8d %-6d ", addr, node.vp, od_name, node.n_ofile_list.ll_count, - node.n_lock_list.ll_count, node.n_refcnt); + node.n_lock_list.ll_count, + node.n_oplock.ol_count, node.n_refcnt); + if (print_full_path) mdb_printf("\t%s\n", path_name); } @@ -1713,6 +1737,99 @@ } /* + * ***************************************************************************** + * ************************** smb_oplock_grant_t ******************************* + * ***************************************************************************** + */ +/*ARGSUSED*/ +static int +smb_oplock_grant(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + smb_oplock_grant_t grant; + char *level; + + if (!(flags & DCMD_ADDRSPEC)) + return (DCMD_USAGE); + + /* + * If this is the first invocation of the command, print a nice + * header line for the output that will follow. + */ + if (DCMD_HDRSPEC(flags)) { + mdb_printf("%<u>%-16s %-10s %-16s%</u>\n", + "Grants:", "LEVEL", "OFILE"); + } + + if (mdb_vread(&grant, sizeof (grant), addr) == sizeof (grant)) { + switch (grant.og_level) { + case SMB_OPLOCK_EXCLUSIVE: + level = "EXCLUSIVE"; + break; + case SMB_OPLOCK_BATCH: + level = "BATCH"; + break; + case SMB_OPLOCK_LEVEL_II: + level = "LEVEL_II"; + break; + default: + level = "UNKNOWN"; + break; + } + + mdb_printf("%-16p %-10s %-16p", addr, level, grant.og_ofile); + } + return (DCMD_OK); +} + +/* + * ***************************************************************************** + * ***************************** smb_oplock_t ********************************** + * ***************************************************************************** + */ +/*ARGSUSED*/ +static int +smb_oplock(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +{ + smb_oplock_t oplock; + uintptr_t list_addr; + + if (!(flags & DCMD_ADDRSPEC)) + return (DCMD_USAGE); + + if (mdb_vread(&oplock, sizeof (oplock), addr) != sizeof (oplock)) { + mdb_warn("failed to read struct smb_oplock at %p", addr); + return (DCMD_ERR); + } + + if (oplock.ol_count == 0) + return (DCMD_OK); + + (void) mdb_inc_indent(SMB_DCMD_INDENT); + switch (oplock.ol_break) { + case SMB_OPLOCK_BREAK_TO_NONE: + mdb_printf("Break Pending: BREAK_TO_NONE\n"); + break; + case SMB_OPLOCK_BREAK_TO_LEVEL_II: + mdb_printf( + "Break Pending: BREAK_TO_LEVEL_II\n"); + break; + default: + break; + } + + list_addr = addr + offsetof(smb_oplock_t, ol_grants); + + if (mdb_pwalk_dcmd("list", "smboplockgrant", + argc, argv, list_addr)) { + mdb_warn("failed to walk oplock grants"); + } + + (void) mdb_dec_indent(SMB_DCMD_INDENT); + + return (DCMD_OK); +} + +/* * ::smbstat * * Prints SMB requests statistics.
--- a/usr/src/cmd/smbsrv/dtrace/msrpc.d Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/cmd/smbsrv/dtrace/msrpc.d Thu Jul 22 14:53:56 2010 -0700 @@ -262,7 +262,7 @@ /* * SAMR */ -pid$target::samr_s_ConnectAnon:entry, +pid$target::samr_s_Connect:entry, pid$target::samr_s_CloseHandle:entry, pid$target::samr_s_LookupDomain:entry, pid$target::samr_s_EnumLocalDomains:entry, @@ -275,14 +275,14 @@ pid$target::samr_s_QueryUserInfo:entry, pid$target::samr_s_QueryUserGroups:entry, pid$target::samr_s_OpenGroup:entry, -pid$target::samr_s_Connect:entry, +pid$target::samr_s_Connect2:entry, pid$target::samr_s_GetUserPwInfo:entry, pid$target::samr_s_CreateUser:entry, pid$target::samr_s_ChangeUserPasswd:entry, pid$target::samr_s_GetDomainPwInfo:entry, pid$target::samr_s_SetUserInfo:entry, -pid$target::samr_s_Connect3:entry, pid$target::samr_s_Connect4:entry, +pid$target::samr_s_Connect5:entry, pid$target::samr_s_QueryDispInfo:entry, pid$target::samr_s_OpenAlias:entry, pid$target::samr_s_CreateDomainAlias:entry, @@ -294,7 +294,7 @@ { } -pid$target::samr_s_ConnectAnon:return, +pid$target::samr_s_Connect:return, pid$target::samr_s_CloseHandle:return, pid$target::samr_s_LookupDomain:return, pid$target::samr_s_EnumLocalDomains:return, @@ -307,14 +307,14 @@ pid$target::samr_s_QueryUserInfo:return, pid$target::samr_s_QueryUserGroups:return, pid$target::samr_s_OpenGroup:return, -pid$target::samr_s_Connect:return, +pid$target::samr_s_Connect2:return, pid$target::samr_s_GetUserPwInfo:return, pid$target::samr_s_CreateUser:return, pid$target::samr_s_ChangeUserPasswd:return, pid$target::samr_s_GetDomainPwInfo:return, pid$target::samr_s_SetUserInfo:return, -pid$target::samr_s_Connect3:return, pid$target::samr_s_Connect4:return, +pid$target::samr_s_Connect5:return, pid$target::samr_s_QueryDispInfo:return, pid$target::samr_s_OpenAlias:return, pid$target::samr_s_CreateDomainAlias:return,
--- a/usr/src/cmd/smbsrv/smbd/smbd_main.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/cmd/smbsrv/smbd/smbd_main.c Thu Jul 22 14:53:56 2010 -0700 @@ -48,6 +48,7 @@ #include <libgen.h> #include <pwd.h> #include <grp.h> +#include <cups/cups.h> #include <smbsrv/smb_door.h> #include <smbsrv/smb_ioctl.h> @@ -57,8 +58,10 @@ #include <smbsrv/libmlsvc.h> #include "smbd.h" +#define SMB_CUPS_DOCNAME "generic_doc" #define DRV_DEVICE_PATH "/devices/pseudo/smbsrv@0:smbsrv" #define SMB_DBDIR "/var/smb" +#define SMB_SPOOL_WAIT 2 static void *smbd_nbt_listener(void *); static void *smbd_tcp_listener(void *); @@ -88,6 +91,10 @@ static pthread_t localtime_thr; +static int smbd_spool_init(void); +static void *smbd_spool_monitor(void *arg); +static pthread_t smbd_spool_thr; + static int smbd_refresh_init(void); static void smbd_refresh_fini(void); static void *smbd_refresh_monitor(void *); @@ -134,6 +141,8 @@ uid_t uid; int pfd = -1; uint_t sigval; + struct rlimit rl; + int orig_limit; smbd.s_pname = basename(argv[0]); openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON); @@ -159,6 +168,19 @@ if (smbd_already_running()) return (SMF_EXIT_OK); + /* + * Raise the file descriptor limit to accommodate simultaneous user + * authentications/file access. + */ + if ((getrlimit(RLIMIT_NOFILE, &rl) == 0) && + (rl.rlim_cur < rl.rlim_max)) { + orig_limit = rl.rlim_cur; + rl.rlim_cur = rl.rlim_max; + if (setrlimit(RLIMIT_NOFILE, &rl) != 0) + smbd_report("Failed to raise file descriptor limit" + " from %d to %d", orig_limit, rl.rlim_cur); + } + (void) sigfillset(&set); (void) sigdelset(&set, SIGABRT); @@ -545,6 +567,13 @@ return (-1); } + if (smbd_spool_init() != 0) { + smbd_report("failed to start print monitor: %s", + strerror(errno)); + (void) mutex_unlock(&smbd_service_mutex); + return (-1); + } + smbd.s_initialized = B_TRUE; smbd_report("service initialized"); (void) cond_signal(&smbd_service_cv); @@ -870,6 +899,63 @@ } /* + * Initialization of the spool thread. + * Returns 0 on success, an error number if thread creation fails. + */ + +static int +smbd_spool_init(void) +{ + pthread_attr_t tattr; + int rc; + + (void) pthread_attr_init(&tattr); + (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); + rc = pthread_create(&smbd_spool_thr, &tattr, smbd_spool_monitor, 0); + (void) pthread_attr_destroy(&tattr); + + return (rc); +} + +/* + * This user thread blocks waiting for close print file + * in the kernel. It then uses the data returned from the ioctl + * to copy the spool file into the cups spooler. + * This function is really only used by Vista and Win7 clients, + * other versions of windows create only a zero size file and this + * be removed by spoolss_copy_spool_file function. + */ + +/*ARGSUSED*/ +static void * +smbd_spool_monitor(void *arg) +{ + uint32_t spool_num; + char username[MAXNAMELEN]; + char path[MAXPATHLEN]; + smb_inaddr_t ipaddr; + int error_retry_cnt = 5; + + while (!smbd.s_shutting_down && (error_retry_cnt > 0)) { + errno = 0; + + if (smb_kmod_get_spool_doc(&spool_num, username, + path, &ipaddr) == 0) { + spoolss_copy_spool_file(&ipaddr, + username, path, SMB_CUPS_DOCNAME); + error_retry_cnt = 5; + } else { + if (errno == ECANCELED) + break; + + (void) sleep(SMB_SPOOL_WAIT); + error_retry_cnt--; + } + } + return (NULL); +} + +/* * Initialization of the localtime thread. * Returns 0 on success, an error number if thread creation fails. */
--- a/usr/src/lib/Makefile Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/Makefile Thu Jul 22 14:53:56 2010 -0700 @@ -589,7 +589,7 @@ libefi: libuuid libfstyp: libnvpair libelfsign: libcryptoutil libkmf -libidmap: libadutils libldap5 libavl libsldap +libidmap: libadutils libldap5 libavl libsldap libuutil libipadm: libnsl libinetutil libsocket libdlpi libnvpair libdhcpagent \ libdladm libsecdb libiscsit: libc libnvpair libstmf libuuid libnsl
--- a/usr/src/lib/libidmap/Makefile.com Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/libidmap/Makefile.com Thu Jul 22 14:53:56 2010 -0700 @@ -34,7 +34,6 @@ sized_array.o \ idmap_api.o \ idmap_cache.o \ - miscutils.o \ utils.o OBJECTS = $(LINT_OBJECTS) \ @@ -44,7 +43,7 @@ C99MODE = $(C99_ENABLE) LIBS = $(DYNLIB) $(LINTLIB) -LDLIBS += -lc -lavl -lnsl -lnvpair +LDLIBS += -lc -lavl -lnsl -lnvpair -luutil SRCDIR = ../common $(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC)
--- a/usr/src/lib/libidmap/common/directory_helper.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/libidmap/common/directory_helper.c Thu Jul 22 14:53:56 2010 -0700 @@ -33,11 +33,11 @@ #include <stdio.h> #include <string.h> +#include <libuutil.h> #include <rpcsvc/idmap_prot.h> #include "directory.h" #include "directory_private.h" #include "directory_library_impl.h" -#include "miscutils.h" #include "sidutil.h" /* @@ -275,7 +275,7 @@ is_in_list(char **list, char *val) { for (; *list != NULL; list++) { - if (strcaseeq(*list, val)) + if (uu_strcaseeq(*list, val)) return (B_TRUE); } return (B_FALSE); @@ -287,12 +287,12 @@ uint64_t ret = 0; for (; *objectClass != NULL; objectClass++) { - if (strcaseeq(*objectClass, "user") || - strcaseeq(*objectClass, "posixAccount")) + if (uu_strcaseeq(*objectClass, "user") || + uu_strcaseeq(*objectClass, "posixAccount")) ret |= DIRECTORY_CLASS_USER; - if (strcaseeq(*objectClass, "group") || - strcaseeq(*objectClass, "posixGroup")) + if (uu_strcaseeq(*objectClass, "group") || + uu_strcaseeq(*objectClass, "posixGroup")) ret |= DIRECTORY_CLASS_GROUP; }
--- a/usr/src/lib/libidmap/common/directory_library_impl.h Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/libidmap/common/directory_library_impl.h Thu Jul 22 14:53:56 2010 -0700 @@ -20,8 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _DIRECTORY_LIBRARY_IMPL_H @@ -31,6 +30,8 @@ * Internal implementation of the client side of directory lookup. */ +#include <rpcsvc/idmap_prot.h> + #ifdef __cplusplus extern "C" { #endif
--- a/usr/src/lib/libidmap/common/llib-lidmap Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/libidmap/common/llib-lidmap Thu Jul 22 14:53:56 2010 -0700 @@ -19,15 +19,14 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ /* LINTLIBRARY */ /* PROTOLIB1 */ -#include "idmap_impl.h" -#include "miscutils.h" +#include "idmap.h" +#include "idmap_priv.h" #include "directory.h" #include "directory_private.h" #include "sized_array.h"
--- a/usr/src/lib/libidmap/common/mapfile-vers Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/libidmap/common/mapfile-vers Thu Jul 22 14:53:56 2010 -0700 @@ -60,7 +60,6 @@ directory_sid_from_group_name; directory_sid_from_name; directory_sid_from_user_name; - idmap_cache_get_data; idmap_fini; idmap_flush; idmap_free; @@ -110,7 +109,6 @@ idmap_udt_get_error_index; idmap_udt_get_error_rule; idmap_udt_rm_namerule; - memdup; sid_free; sid_from_le; sid_fromstr; @@ -120,9 +118,6 @@ 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;
--- a/usr/src/lib/libidmap/common/miscutils.c Thu Jul 22 12:31:36 2010 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +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. - */ - -/* - * 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"); - } -}
--- a/usr/src/lib/libidmap/common/miscutils.h Thu Jul 22 12:31:36 2010 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +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 _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 */
--- a/usr/src/lib/libshare/smb/libshare_smb.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/libshare/smb/libshare_smb.c Thu Jul 22 14:53:56 2010 -0700 @@ -912,6 +912,8 @@ { SMB_CI_AUTOHOME_MAP, 0, MAX_VALUE_BUFLEN, path_validator, 0 }, { SMB_CI_IPV6_ENABLE, 0, 0, true_false_validator, SMB_REFRESH_REFRESH }, + { SMB_CI_PRINT_ENABLE, 0, 0, true_false_validator, + SMB_REFRESH_REFRESH }, { SMB_CI_MAP, 0, MAX_VALUE_BUFLEN, cmd_validator, SMB_REFRESH_REFRESH }, { SMB_CI_UNMAP, 0, MAX_VALUE_BUFLEN, cmd_validator, SMB_REFRESH_REFRESH },
--- a/usr/src/lib/libuutil/Makefile.com Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/libuutil/Makefile.com Thu Jul 22 14:53:56 2010 -0700 @@ -19,10 +19,7 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. -# Use is subject to license terms. -# -# ident "%Z%%M% %I% %E% SMI" +# Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. # LIBRARY = libuutil.a @@ -38,6 +35,7 @@ uu_misc.o \ uu_open.o \ uu_pname.o \ + uu_string.o \ uu_strtoint.o include ../../Makefile.lib
--- a/usr/src/lib/libuutil/common/libuutil.h Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/libuutil/common/libuutil.h Thu Jul 22 14:53:56 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _LIBUUTIL_H @@ -28,6 +27,7 @@ #include <sys/types.h> #include <stdarg.h> +#include <stdio.h> #ifdef __cplusplus extern "C" { @@ -142,12 +142,21 @@ /* * Convenience functions. */ +#define UU_NELEM(a) (sizeof (a) / sizeof ((a)[0])) + /*PRINTFLIKE1*/ extern char *uu_msprintf(const char *format, ...); extern void *uu_zalloc(size_t); extern char *uu_strdup(const char *); extern void uu_free(void *); +extern boolean_t uu_strcaseeq(const char *a, const char *b); +extern boolean_t uu_streq(const char *a, const char *b); +extern char *uu_strndup(const char *s, size_t n); +extern boolean_t uu_strbw(const char *a, const char *b); +extern void *uu_memdup(const void *buf, size_t sz); +extern void uu_dump(FILE *out, const char *prefix, const void *buf, size_t len); + /* * Comparison function type definition. * Developers should be careful in their use of the _private argument. If you
--- a/usr/src/lib/libuutil/common/mapfile-vers Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/libuutil/common/mapfile-vers Thu Jul 22 14:53:56 2010 -0700 @@ -68,6 +68,7 @@ uu_dprintf_create; uu_dprintf_destroy; uu_dprintf_getname; + uu_dump; uu_error; uu_exit_fatal; uu_exit_ok; @@ -97,11 +98,16 @@ uu_list_walk_end; uu_list_walk_next; uu_list_walk_start; + uu_memdup; uu_msprintf; uu_open_tmp; uu_setpname; + uu_strbw; + uu_strcaseeq; uu_strdup; + uu_streq; uu_strerror; + uu_strndup; uu_strtoint; uu_strtouint; uu_vdie;
--- a/usr/src/lib/libuutil/common/uu_alloc.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/libuutil/common/uu_alloc.c Thu Jul 22 14:53:56 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #include "libuutil_common.h" @@ -67,6 +66,44 @@ return (buf); } +/* + * Duplicate up to n bytes of a string. Kind of sort of like + * strdup(strlcpy(s, n)). + */ +char * +uu_strndup(const char *s, size_t n) +{ + size_t len; + char *p; + + len = strnlen(s, n); + p = uu_zalloc(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 * +uu_memdup(const void *buf, size_t sz) +{ + void *p; + + p = uu_zalloc(sz); + if (p == NULL) + return (NULL); + (void) memcpy(p, buf, sz); + return (p); +} + char * uu_msprintf(const char *format, ...) {
--- a/usr/src/lib/libuutil/common/uu_misc.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/libuutil/common/uu_misc.c Thu Jul 22 14:53:56 2010 -0700 @@ -20,12 +20,9 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include "libuutil_common.h" #include <assert.h> @@ -39,6 +36,7 @@ #include <sys/debug.h> #include <thread.h> #include <unistd.h> +#include <ctype.h> #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" @@ -253,3 +251,30 @@ { (void) pthread_atfork(uu_lockup, uu_release, uu_release_child); } + +/* + * Dump a block of memory in hex+ascii, for debugging + */ +void +uu_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/libuutil/common/uu_string.c Thu Jul 22 14:53:56 2010 -0700 @@ -0,0 +1,56 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + */ + +/* + * String helper functions + */ + +#include <string.h> +#include <sys/types.h> +#include <stdio.h> +#include <malloc.h> +#include <ctype.h> +#include "libuutil.h" + +/* Return true if strings are equal */ +boolean_t +uu_streq(const char *a, const char *b) +{ + return (strcmp(a, b) == 0); +} + +/* Return true if strings are equal, case-insensitively */ +boolean_t +uu_strcaseeq(const char *a, const char *b) +{ + return (strcasecmp(a, b) == 0); +} + +/* Return true if string a Begins With string b */ +boolean_t +uu_strbw(const char *a, const char *b) +{ + return (strncmp(a, b, strlen(b)) == 0); +}
--- a/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c Thu Jul 22 14:53:56 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -405,6 +404,7 @@ } np->np_buf = newbuf; + np->np_iov.iov_base = np->np_buf + np->np_uio.uio_offset; np->np_uio.uio_resid += desired; np->np_iov.iov_len += desired; smb_tracef("ndr_pipe_grow: %d bytes", required);
--- a/usr/src/lib/smbsrv/libmlsvc/common/dfs.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/smbsrv/libmlsvc/common/dfs.c Thu Jul 22 14:53:56 2010 -0700 @@ -75,6 +75,14 @@ static char dfs_nbname[NETBIOS_NAME_SZ]; /* + * The name of cached namespace. This will be the only + * exported namespace until hosting multiple namespaces + * is supported + */ +static char dfs_cached_ns[MAXNAMELEN]; +static mutex_t dfs_nsmtx; + +/* * Lock for accessing root information (extended attribute) */ static rwlock_t dfs_root_rwl; @@ -86,6 +94,7 @@ */ static boolean_t dfs_namespace_findlink(const char *, char *, char *, size_t); static void *dfs_namespace_cache(void *); +static boolean_t dfs_namespace_iscached(const char *); /* * Root functions @@ -124,6 +133,8 @@ static uint32_t dfs_cache_add_byunc(const char *, const char *, uint32_t); static void dfs_cache_populate(const char *, const char *); static int dfs_cache_cmp(const void *, const void *); +static void dfs_cache_flush(const char *); +static uint32_t dfs_cache_nscount(void); /* * Utility functions @@ -234,7 +245,7 @@ void /*ARGSUSED*/ dfs_namespace_unload(const char *name) { - smb_cache_flush(&dfs_nscache); + dfs_cache_flush(name); } /* @@ -254,6 +265,9 @@ if ((si.shr_flags & SMB_SHRF_DFSROOT) == 0) return (ERROR_NOT_FOUND); + if (!dfs_namespace_iscached(name)) + return (ERROR_NOT_FOUND); + if (path != NULL) (void) strlcpy(path, si.shr_path, pathsz); @@ -267,8 +281,6 @@ uint32_t dfs_namespace_count(void) { - smb_shriter_t shi; - smb_share_t *si; uint32_t nroot = 0; int rc; @@ -285,11 +297,7 @@ "assuming one namespace exists", rc); } - smb_shr_iterinit(&shi); - while ((si = smb_shr_iterate(&shi)) != NULL) { - if ((si->shr_flags & SMB_SHRF_DFSROOT) != 0) - nroot++; - } + nroot += dfs_cache_nscount(); return (nroot); } @@ -317,11 +325,22 @@ if (smb_shr_get((char *)rootshr, &si) != NERR_Success) return (NERR_NetNameNotFound); - if (si.shr_flags & SMB_SHRF_DFSROOT) { - /* Share is already a DFS root */ + (void) mutex_lock(&dfs_nsmtx); + if (smb_strcasecmp(dfs_cached_ns, rootshr, 0) == 0) { + /* This DFS root is already exported */ + (void) mutex_unlock(&dfs_nsmtx); return (ERROR_FILE_EXISTS); } + if (*dfs_cached_ns != '\0') { + syslog(LOG_WARNING, "dfs: trying to add %s namespace." + " Only one standalone namespace is supported." + " A namespace is already exported for %s", + rootshr, dfs_cached_ns); + (void) mutex_unlock(&dfs_nsmtx); + return (ERROR_NOT_SUPPORTED); + } + bzero(&info, sizeof (info)); if (cmnt) (void) strlcpy(info.i_comment, cmnt, sizeof (info.i_comment)); @@ -337,12 +356,18 @@ info.i_ntargets = 1; info.i_targets = &t; - if ((status = dfs_root_add(si.shr_path, &info)) != ERROR_SUCCESS) + if ((status = dfs_root_add(si.shr_path, &info)) != ERROR_SUCCESS) { + (void) mutex_unlock(&dfs_nsmtx); return (status); + } status = srvsvc_shr_setdfsroot(&si, B_TRUE); - if (status == ERROR_SUCCESS) + if (status == ERROR_SUCCESS) { (void) dfs_cache_add_byname(rootshr, NULL, DFS_OBJECT_ROOT); + (void) strlcpy(dfs_cached_ns, rootshr, sizeof (dfs_cached_ns)); + (void) smb_config_setnum(SMB_CI_DFS_STDROOT_NUM, 1); + } + (void) mutex_unlock(&dfs_nsmtx); return (status); } @@ -372,6 +397,9 @@ syslog(LOG_WARNING, "dfs: failed to disable root share %s (%d)", name, status); + if (!dfs_namespace_iscached(name)) + return (ERROR_SUCCESS); + smb_cache_iterinit(&dfs_nscache, &cursor); while (smb_cache_iterate(&dfs_nscache, &cursor, &nscnode)) { @@ -383,13 +411,32 @@ nscnode.nsc_fspath, status); } - smb_cache_flush(&dfs_nscache); + dfs_cache_flush(name); /* TODO: remove empty dirs */ return (ERROR_SUCCESS); } /* + * Determines the DFS namespace flavor. + */ +uint32_t +dfs_namespace_getflavor(const char *name) +{ + char rootdir[DFS_PATH_MAX]; + dfs_info_t info; + + if (dfs_namespace_path(name, rootdir, DFS_PATH_MAX) != ERROR_SUCCESS) + return (0); + + /* get flavor info from state info (info level 2) */ + if (dfs_root_getinfo(rootdir, &info, 2) != ERROR_SUCCESS) + return (0); + + return (info.i_state & DFS_VOLUME_FLAVORS); +} + +/* * ================== * Root API (public) * ================== @@ -1050,6 +1097,24 @@ return (NULL); } + /* + * This check should be removed when multiple standalone + * namespaces are supported. + */ + (void) mutex_lock(&dfs_nsmtx); + if (*dfs_cached_ns != '\0') { + syslog(LOG_WARNING, "dfs: trying to load %s namespace." + " Only one standalone namespace is supported." + " A namespace is already exported for %s", + share, dfs_cached_ns); + (void) mutex_unlock(&dfs_nsmtx); + free(share); + return (NULL); + } + (void) strlcpy(dfs_cached_ns, share, sizeof (dfs_cached_ns)); + (void) smb_config_setnum(SMB_CI_DFS_STDROOT_NUM, 1); + (void) mutex_unlock(&dfs_nsmtx); + (void) snprintf(uncpath, DFS_PATH_MAX, "\\\\%s\\%s", dfs_nbname, share); (void) dfs_cache_add_byunc(uncpath, si.shr_path, DFS_OBJECT_ROOT); @@ -1059,6 +1124,22 @@ return (NULL); } +/* + * Checks whether the given name matches the name of + * the cached namespace. + */ +static boolean_t +dfs_namespace_iscached(const char *name) +{ + boolean_t iscached; + + (void) mutex_lock(&dfs_nsmtx); + iscached = (smb_strcasecmp(name, dfs_cached_ns, 0) == 0); + (void) mutex_unlock(&dfs_nsmtx); + + return (iscached); +} + static int dfs_root_add(const char *rootdir, dfs_info_t *info) { @@ -1216,6 +1297,10 @@ rc |= nvlist_add_string(nvl, "t_server", t->t_server); rc |= nvlist_add_string(nvl, "t_share", t->t_share); rc |= nvlist_add_uint32(nvl, "t_state", t->t_state); + rc |= nvlist_add_uint32(nvl, "t_priority_class", + t->t_priority.p_class); + rc |= nvlist_add_uint16(nvl, "t_priority_rank", + t->t_priority.p_rank); if (rc == 0) rc = nvlist_pack(nvl, buf, bufsz, NV_ENCODE_NATIVE, 0); @@ -1236,6 +1321,9 @@ char *cmnt, *guid; char *t_server, *t_share; uint32_t t_state; + uint32_t t_priority_class; + uint16_t t_priority_rank; + boolean_t decode_priority = B_FALSE; int rc; if (nvlist_unpack(buf, bufsz, &nvl, 0) != 0) @@ -1263,9 +1351,12 @@ case DFS_INFO_ALL: case 3: case 4: + /* need target information */ + break; case 6: case 9: - /* need target information */ + /* need target and priority information */ + decode_priority = B_TRUE; break; default: nvlist_free(nvl); @@ -1288,6 +1379,23 @@ } dfs_target_init(info->i_targets, t_server, t_share, t_state); + if (decode_priority) { + rc = nvlist_lookup_uint32(nvl, "t_priority_class", + &t_priority_class); + if (rc == 0) + rc = nvlist_lookup_uint16(nvl, "t_priority_rank", + &t_priority_rank); + + if (rc != 0 && rc != ENOENT) { + nvlist_free(nvl); + free(info->i_targets); + return (ERROR_INTERNAL_ERROR); + } else if (rc == 0) { + info->i_targets->t_priority.p_class = t_priority_class; + info->i_targets->t_priority.p_rank = t_priority_rank; + } + } + nvlist_free(nvl); return (ERROR_SUCCESS); } @@ -1625,6 +1733,41 @@ } /* + * If this namespace hasn't been cached then return + * without flushing the cache; otherwise clear the + * name and flush the cache. + */ +static void +dfs_cache_flush(const char *name) +{ + (void) mutex_lock(&dfs_nsmtx); + if (smb_strcasecmp(name, dfs_cached_ns, 0) != 0) { + (void) mutex_unlock(&dfs_nsmtx); + return; + } + *dfs_cached_ns = '\0'; + (void) smb_config_setnum(SMB_CI_DFS_STDROOT_NUM, 0); + (void) mutex_unlock(&dfs_nsmtx); + + smb_cache_flush(&dfs_nscache); +} + +/* + * Returns the number of cached namespaces + */ +static uint32_t +dfs_cache_nscount(void) +{ + uint32_t nscount; + + (void) mutex_lock(&dfs_nsmtx); + nscount = (*dfs_cached_ns == '\0') ? 0 : 1; + (void) mutex_unlock(&dfs_nsmtx); + + return (nscount); +} + +/* * Determines whether the given path is a directory. */ static boolean_t @@ -1639,36 +1782,103 @@ } /* - * Validates the given state based on the object type (root/link) - * and whether it is the object's state or its target's state + * Validates the given state based on the object type (root/link), info + * level, and whether it is the object's state or its target's state */ static uint32_t -dfs_isvalidstate(uint32_t state, uint32_t type, boolean_t target) +dfs_isvalidstate(uint32_t state, uint32_t type, boolean_t target, + uint32_t infolvl) { uint32_t status = ERROR_SUCCESS; - if (type == DFS_OBJECT_ROOT) { - if (!target) - return (dfs_root_isvalidstate(state)); + switch (infolvl) { + case 101: + if (type == DFS_OBJECT_ROOT) { + if (!target) + return (dfs_root_isvalidstate(state)); - if (!dfs_target_isvalidstate(state)) - status = ERROR_INVALID_PARAMETER; - else if (state == DFS_STORAGE_STATE_OFFLINE) - status = ERROR_NOT_SUPPORTED; - } else { - if (!target) { - if (!dfs_link_isvalidstate(state)) - status = ERROR_INVALID_PARAMETER; - } else { if (!dfs_target_isvalidstate(state)) status = ERROR_INVALID_PARAMETER; + else if (state == DFS_STORAGE_STATE_OFFLINE) + status = ERROR_NOT_SUPPORTED; + } else { + if (!target) { + if (!dfs_link_isvalidstate(state)) + status = ERROR_INVALID_PARAMETER; + } else { + if (!dfs_target_isvalidstate(state)) + status = ERROR_INVALID_PARAMETER; + } } + break; + + case 105: + if (state == 0) + return (ERROR_SUCCESS); + + if (type == DFS_OBJECT_ROOT) { + switch (state) { + case DFS_VOLUME_STATE_OK: + case DFS_VOLUME_STATE_OFFLINE: + case DFS_VOLUME_STATE_ONLINE: + case DFS_VOLUME_STATE_RESYNCHRONIZE: + case DFS_VOLUME_STATE_STANDBY: + status = ERROR_NOT_SUPPORTED; + break; + + default: + status = ERROR_INVALID_PARAMETER; + } + } else { + switch (state) { + case DFS_VOLUME_STATE_OK: + case DFS_VOLUME_STATE_OFFLINE: + case DFS_VOLUME_STATE_ONLINE: + break; + + case DFS_VOLUME_STATE_RESYNCHRONIZE: + case DFS_VOLUME_STATE_STANDBY: + status = ERROR_NOT_SUPPORTED; + break; + + default: + status = ERROR_INVALID_PARAMETER; + } + } + break; + + default: + status = ERROR_INVALID_LEVEL; } return (status); } /* + * Validates the given property flag mask based on the object + * type (root/link) and namespace flavor. + */ +static uint32_t +dfs_isvalidpropflagmask(uint32_t propflag_mask, uint32_t type, + uint32_t flavor) +{ + uint32_t flgs_not_supported; + + flgs_not_supported = DFS_PROPERTY_FLAG_ROOT_SCALABILITY + | DFS_PROPERTY_FLAG_CLUSTER_ENABLED + | DFS_PROPERTY_FLAG_ABDE; + + if (flavor == DFS_VOLUME_FLAVOR_STANDALONE) { + if (type == DFS_OBJECT_LINK) + flgs_not_supported |= DFS_PROPERTY_FLAG_SITE_COSTING; + if (propflag_mask & flgs_not_supported) + return (ERROR_NOT_SUPPORTED); + } + + return (ERROR_SUCCESS); +} + +/* * Based on the specified information level (infolvl) copy parts of the * information provided through newinfo into the existing information * (info) for the given object. @@ -1699,7 +1909,7 @@ case 101: state = (target_op) ? newinfo->i_targets->t_state : newinfo->i_state; - status = dfs_isvalidstate(state, type, target_op); + status = dfs_isvalidstate(state, type, target_op, 101); if (status != ERROR_SUCCESS) return (status); @@ -1730,9 +1940,19 @@ break; case 105: + status = dfs_isvalidstate(newinfo->i_state, type, B_FALSE, 105); + if (status != ERROR_SUCCESS) + return (status); + + status = dfs_isvalidpropflagmask(newinfo->i_propflag_mask, type, + newinfo->i_flavor); + if (status != ERROR_SUCCESS) + return (status); + (void) strlcpy(info->i_comment, newinfo->i_comment, sizeof (newinfo->i_comment)); - info->i_state = newinfo->i_state; + if (newinfo->i_state != 0) + info->i_state = newinfo->i_state; info->i_timeout = newinfo->i_timeout; info->i_propflags = newinfo->i_propflags; break;
--- a/usr/src/lib/smbsrv/libmlsvc/common/dfs.h Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/smbsrv/libmlsvc/common/dfs.h Thu Jul 22 14:53:56 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _DFS_H @@ -61,6 +60,7 @@ uint32_t dfs_namespace_remove(const char *); void dfs_namespace_load(const char *); void dfs_namespace_unload(const char *); +uint32_t dfs_namespace_getflavor(const char *); uint32_t dfs_root_getinfo(const char *, dfs_info_t *, uint32_t); uint32_t dfs_root_setinfo(const char *, dfs_info_t *, uint32_t);
--- a/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h Thu Jul 22 14:53:56 2010 -0700 @@ -277,6 +277,10 @@ uint32_t dfs_get_referrals(const char *, dfs_reftype_t, dfs_info_t *); void dfs_info_free(dfs_info_t *); +/* spool functions */ +void spoolss_copy_spool_file(smb_inaddr_t *, char *, char *, char *); + + #ifdef __cplusplus } #endif
--- a/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers Thu Jul 22 14:53:56 2010 -0700 @@ -21,7 +21,6 @@ # # Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. # -# # # MAPFILE HEADER START @@ -76,6 +75,7 @@ smb_shr_stop; smb_token_destroy; smb_token_log; + spoolss_copy_spool_file; local: *; };
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h Thu Jul 22 14:53:56 2010 -0700 @@ -19,13 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SMBSRV_MLSVC_H #define _SMBSRV_MLSVC_H +#include <cups/cups.h> #include <smbsrv/smb_share.h> #include <smbsrv/ndl/netlogon.ndl> @@ -50,6 +50,7 @@ void logr_finalize(void); void svcctl_finalize(void); +void spoolss_finalize(void); void netdfs_finalize(void); int netr_open(char *, char *, mlsvc_handle_t *); @@ -79,6 +80,26 @@ void smb_quota_add_fs(const char *); void smb_quota_remove_fs(const char *); +typedef struct smb_cups_ops { + void *cups_hdl; + cups_lang_t *(*cupsLangDefault)(); + const char *(*cupsLangEncoding)(cups_lang_t *); + void (*cupsLangFree)(cups_lang_t *); + ipp_status_t (*cupsLastError)(); + int (*cupsGetDests)(cups_dest_t **); + void (*cupsFreeDests)(int, cups_dest_t *); + ipp_t *(*cupsDoFileRequest)(http_t *, ipp_t *, const char *, + const char *); + ipp_t *(*ippNew)(); + void (*ippDelete)(); + char *(*ippErrorString)(); + ipp_attribute_t *(*ippAddString)(); + void (*httpClose)(http_t *); + http_t *(*httpConnect)(const char *, int); +} smb_cups_ops_t; + +smb_cups_ops_t *spoolss_cups_ops(void); + #ifdef __cplusplus } #endif
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c Thu Jul 22 14:53:56 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <sys/errno.h> @@ -85,6 +84,7 @@ mlsvc_fini(void) { smb_logon_fini(); + spoolss_finalize(); svcctl_finalize(); logr_finalize(); netdfs_finalize();
--- a/usr/src/lib/smbsrv/libmlsvc/common/netdfs.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/smbsrv/libmlsvc/common/netdfs.c Thu Jul 22 14:53:56 2010 -0700 @@ -708,17 +708,13 @@ } dfs_setpriv(PRIV_ON); - /* For now only allow a single standalone namespace */ - if (dfs_namespace_count() == 0) { + if (dfs_namespace_count() == 0) param->status = dfs_namespace_add(share, comment); - if (param->status == ERROR_SUCCESS) - (void) smb_config_setnum(SMB_CI_DFS_STDROOT_NUM, 1); - } else { + else param->status = ERROR_NOT_SUPPORTED; - } + dfs_setpriv(PRIV_OFF); - dfs_setpriv(PRIV_OFF); return (NDR_DRC_OK); } @@ -737,13 +733,10 @@ dfs_setpriv(PRIV_ON); - if (ndr_is_admin(mxa)) { + if (ndr_is_admin(mxa)) param->status = dfs_namespace_remove(share); - if (param->status == ERROR_SUCCESS) - (void) smb_config_setnum(SMB_CI_DFS_STDROOT_NUM, 0); - } else { + else param->status = ERROR_ACCESS_DENIED; - } dfs_setpriv(PRIV_OFF); return (NDR_DRC_OK); @@ -879,6 +872,12 @@ if ((t_server == NULL) || (t_share == NULL)) return (ERROR_INVALID_PARAMETER); + if (netinfo->priority_class > DfsGlobalLowPriorityClass) + return (ERROR_INVALID_PARAMETER); + + if (netinfo->priority_rank > DFS_PRIORITY_RANK_MAX) + return (ERROR_INVALID_PARAMETER); + bzero(&info, sizeof (dfs_info_t)); bzero(&target, sizeof (dfs_target_t)); @@ -905,15 +904,21 @@ netdfs_setinfo_105(dfs_path_t *path, netdfs_info105_t *netinfo) { dfs_info_t info; - uint32_t status; + uint32_t status, flavor; char *cmnt = (char *)netinfo->comment; bzero(&info, sizeof (dfs_info_t)); + flavor = dfs_namespace_getflavor(path->p_unc.unc_share); + if (flavor == 0) + return (ERROR_INTERNAL_ERROR); + info.i_flavor = flavor; + if (cmnt != NULL) (void) strlcpy(info.i_comment, cmnt, sizeof (info.i_comment)); info.i_state = netinfo->state; info.i_timeout = netinfo->timeout; + info.i_propflag_mask = netinfo->property_flag_mask; info.i_propflags = netinfo->property_flags & netinfo->property_flag_mask;
--- a/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c Thu Jul 22 14:53:56 2010 -0700 @@ -54,8 +54,8 @@ /*LINTED E_STATIC_UNUSED*/ static DWORD samr_connect1(char *, char *, char *, DWORD, mlsvc_handle_t *); static DWORD samr_connect2(char *, char *, char *, DWORD, mlsvc_handle_t *); -static DWORD samr_connect3(char *, char *, char *, DWORD, mlsvc_handle_t *); static DWORD samr_connect4(char *, char *, char *, DWORD, mlsvc_handle_t *); +static DWORD samr_connect5(char *, char *, char *, DWORD, mlsvc_handle_t *); typedef DWORD (*samr_connop_t)(char *, char *, char *, DWORD, mlsvc_handle_t *); @@ -109,8 +109,8 @@ * * Windows NT3.x: SamrConnect * Windows NT4.0: SamrConnect2 - * Windows 2000: SamrConnect3 - * Windows XP: SamrConnect4 + * Windows 2000: SamrConnect4 + * Windows XP: SamrConnect5 * * Try the calls from most recent to oldest until the server responds with * something other than an RPC protocol error. We don't use the original @@ -121,8 +121,8 @@ mlsvc_handle_t *samr_handle) { static samr_connop_t samr_connop[] = { + samr_connect5, samr_connect4, - samr_connect3, samr_connect2 }; @@ -137,16 +137,12 @@ status = (*samr_connop[i])(server, domain, username, access_mask, samr_handle); - if (status != NT_STATUS_UNSUCCESSFUL) - break; + if (status == NT_STATUS_SUCCESS) + return (0); } - if (status != NT_STATUS_SUCCESS) { - ndr_rpc_unbind(samr_handle); - return (-1); - } - - return (0); + ndr_rpc_unbind(samr_handle); + return (-1); } /* @@ -163,12 +159,12 @@ samr_connect1(char *server, char *domain, char *username, DWORD access_mask, mlsvc_handle_t *samr_handle) { - struct samr_ConnectAnon arg; + struct samr_Connect arg; int opnum; DWORD status; - bzero(&arg, sizeof (struct samr_ConnectAnon)); - opnum = SAMR_OPNUM_ConnectAnon; + bzero(&arg, sizeof (struct samr_Connect)); + opnum = SAMR_OPNUM_Connect; status = NT_STATUS_SUCCESS; arg.servername = ndr_rpc_malloc(samr_handle, sizeof (DWORD)); @@ -206,13 +202,13 @@ samr_connect2(char *server, char *domain, char *username, DWORD access_mask, mlsvc_handle_t *samr_handle) { - struct samr_Connect arg; + struct samr_Connect2 arg; int opnum; DWORD status; int len; - bzero(&arg, sizeof (struct samr_Connect)); - opnum = SAMR_OPNUM_Connect; + bzero(&arg, sizeof (struct samr_Connect2)); + opnum = SAMR_OPNUM_Connect2; status = NT_STATUS_SUCCESS; len = strlen(server) + 4; @@ -237,22 +233,22 @@ } /* - * samr_connect3 + * samr_connect4 * * Connect to the SAM on a Windows 2000 domain controller. */ /*ARGSUSED*/ static DWORD -samr_connect3(char *server, char *domain, char *username, DWORD access_mask, +samr_connect4(char *server, char *domain, char *username, DWORD access_mask, mlsvc_handle_t *samr_handle) { - struct samr_Connect3 arg; + struct samr_Connect4 arg; int opnum; DWORD status; int len; - bzero(&arg, sizeof (struct samr_Connect3)); - opnum = SAMR_OPNUM_Connect3; + bzero(&arg, sizeof (struct samr_Connect4)); + opnum = SAMR_OPNUM_Connect4; status = NT_STATUS_SUCCESS; len = strlen(server) + 4; @@ -278,7 +274,7 @@ } /* - * samr_connect4 + * samr_connect5 * * Connect to the SAM on a Windows XP domain controller. On Windows * XP, the server should be the fully qualified DNS domain name with @@ -290,17 +286,17 @@ */ /*ARGSUSED*/ static DWORD -samr_connect4(char *server, char *domain, char *username, DWORD access_mask, +samr_connect5(char *server, char *domain, char *username, DWORD access_mask, mlsvc_handle_t *samr_handle) { - struct samr_Connect4 arg; + struct samr_Connect5 arg; int len; int opnum; DWORD status; smb_domainex_t dinfo; - bzero(&arg, sizeof (struct samr_Connect4)); - opnum = SAMR_OPNUM_Connect; + bzero(&arg, sizeof (struct samr_Connect5)); + opnum = SAMR_OPNUM_Connect5; status = NT_STATUS_SUCCESS; if (!smb_domain_getinfo(&dinfo))
--- a/usr/src/lib/smbsrv/libmlsvc/common/samr_svc.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/smbsrv/libmlsvc/common/samr_svc.c Thu Jul 22 14:53:56 2010 -0700 @@ -213,7 +213,7 @@ } /* - * samr_s_ConnectAnon + * samr_s_Connect * * This is a request to connect to the local SAM database. We don't * support any form of update request and our database doesn't @@ -223,9 +223,9 @@ * Return a handle for use with subsequent SAM requests. */ static int -samr_s_ConnectAnon(void *arg, ndr_xa_t *mxa) +samr_s_Connect(void *arg, ndr_xa_t *mxa) { - struct samr_ConnectAnon *param = arg; + struct samr_Connect *param = arg; ndr_hdid_t *id; id = samr_hdalloc(mxa, SAMR_KEY_CONNECT, SMB_DOMAIN_NULL, 0); @@ -1082,7 +1082,7 @@ } /* - * samr_s_Connect + * samr_s_Connect2 * * This is a request to connect to the local SAM database. * We don't support any form of update request and our database doesn't @@ -1092,9 +1092,9 @@ * Return a handle for use with subsequent SAM requests. */ static int -samr_s_Connect(void *arg, ndr_xa_t *mxa) +samr_s_Connect2(void *arg, ndr_xa_t *mxa) { - struct samr_Connect *param = arg; + struct samr_Connect2 *param = arg; ndr_hdid_t *id; id = samr_hdalloc(mxa, SAMR_KEY_CONNECT, SMB_DOMAIN_NULL, 0); @@ -1807,12 +1807,12 @@ } /* - * samr_s_Connect3 + * samr_s_Connect4 */ static int -samr_s_Connect3(void *arg, ndr_xa_t *mxa) +samr_s_Connect4(void *arg, ndr_xa_t *mxa) { - struct samr_Connect3 *param = arg; + struct samr_Connect4 *param = arg; ndr_hdid_t *id; id = samr_hdalloc(mxa, SAMR_KEY_CONNECT, SMB_DOMAIN_NULL, 0); @@ -1828,23 +1828,23 @@ } /* - * samr_s_Connect4 + * samr_s_Connect5 * - * This is the connect4 form of the connect request used by Windows XP. + * This is the connect5 form of the connect request used by Windows XP. * Returns an RPC fault for now. */ /*ARGSUSED*/ static int -samr_s_Connect4(void *arg, ndr_xa_t *mxa) +samr_s_Connect5(void *arg, ndr_xa_t *mxa) { - struct samr_Connect4 *param = arg; + struct samr_Connect5 *param = arg; - bzero(param, sizeof (struct samr_Connect4)); + bzero(param, sizeof (struct samr_Connect5)); return (NDR_DRC_FAULT_REQUEST_OPNUM_INVALID); } static ndr_stub_table_t samr_stub_table[] = { - { samr_s_ConnectAnon, SAMR_OPNUM_ConnectAnon }, + { samr_s_Connect, SAMR_OPNUM_Connect }, { samr_s_CloseHandle, SAMR_OPNUM_CloseHandle }, { samr_s_LookupDomain, SAMR_OPNUM_LookupDomain }, { samr_s_EnumLocalDomains, SAMR_OPNUM_EnumLocalDomains }, @@ -1857,14 +1857,14 @@ { samr_s_QueryUserInfo, SAMR_OPNUM_QueryUserInfo }, { samr_s_QueryUserGroups, SAMR_OPNUM_QueryUserGroups }, { samr_s_OpenGroup, SAMR_OPNUM_OpenGroup }, - { samr_s_Connect, SAMR_OPNUM_Connect }, + { samr_s_Connect2, SAMR_OPNUM_Connect2 }, { samr_s_GetUserPwInfo, SAMR_OPNUM_GetUserPwInfo }, { samr_s_CreateUser, SAMR_OPNUM_CreateUser }, { samr_s_ChangeUserPasswd, SAMR_OPNUM_ChangeUserPasswd }, { samr_s_GetDomainPwInfo, SAMR_OPNUM_GetDomainPwInfo }, { samr_s_SetUserInfo, SAMR_OPNUM_SetUserInfo }, - { samr_s_Connect3, SAMR_OPNUM_Connect3 }, { samr_s_Connect4, SAMR_OPNUM_Connect4 }, + { samr_s_Connect5, SAMR_OPNUM_Connect5 }, { samr_s_QueryDispInfo, SAMR_OPNUM_QueryDispInfo }, { samr_s_OpenAlias, SAMR_OPNUM_OpenAlias }, { samr_s_CreateDomainAlias, SAMR_OPNUM_CreateDomainAlias },
--- a/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c Thu Jul 22 14:53:56 2010 -0700 @@ -43,6 +43,7 @@ #include <pwd.h> #include <signal.h> #include <dirent.h> +#include <dlfcn.h> #include <smbsrv/libsmb.h> #include <smbsrv/libsmbns.h> @@ -51,6 +52,7 @@ #include <smbsrv/smb.h> #include <mlsvc.h> #include <dfs.h> +#include <cups/cups.h> #define SMB_SHR_ERROR_THRESHOLD 3 #define SMB_SHR_CSC_BUFSZ 64 @@ -142,6 +144,7 @@ static uint32_t smb_shr_sa_load(sa_share_t, sa_resource_t); static uint32_t smb_shr_sa_loadbyname(char *); static uint32_t smb_shr_sa_get(sa_share_t, sa_resource_t, smb_share_t *); +static void smb_shr_load_cups_printers(); /* * .ZFS management functions @@ -448,6 +451,9 @@ /* If path is ZFS, add the .zfs/shares/<share> entry. */ smb_shr_zfs_add(si); + if ((si->shr_flags & SMB_SHRF_DFSROOT) != 0) + dfs_namespace_load(si->shr_name); + return (NERR_Success); } } @@ -572,6 +578,7 @@ bcopy(from_si, &to_si, sizeof (smb_share_t)); (void) strlcpy(to_si.shr_name, to_name, sizeof (to_si.shr_name)); + /* If path is ZFS, rename the .zfs/shares/<share> entry. */ smb_shr_zfs_rename(from_si, &to_si); @@ -1394,8 +1401,10 @@ (void) smb_strlwr(si->shr_name); - if ((si->shr_type & STYPE_IPC) == 0) + if (((si->shr_type & STYPE_PRINTQ) == 0) && + (si->shr_type & STYPE_IPC) == 0) si->shr_type = STYPE_DISKTREE; + si->shr_type |= smb_shr_is_special(cache_ent->shr_name); if (smb_shr_is_admin(cache_ent->shr_name)) @@ -1456,9 +1465,12 @@ sa_group_t group, subgroup; char *gstate; boolean_t gdisabled; - - if ((handle = smb_shr_sa_enter()) == NULL) + boolean_t printing_enabled; + + if ((handle = smb_shr_sa_enter()) == NULL) { + syslog(LOG_ERR, "smb_shr_sa_loadall: ret NULL"); return (NULL); + } for (group = sa_get_group(handle, NULL); group != NULL; group = sa_get_next_group(group)) { @@ -1480,12 +1492,54 @@ } } - smb_shr_sa_exit(); + printing_enabled = smb_config_getbool(SMB_CI_PRINT_ENABLE); + if (printing_enabled) + smb_shr_load_cups_printers(); return (NULL); } /* + * Load print shares from cups + */ +static void +smb_shr_load_cups_printers() +{ + uint32_t nerr; + int i; + cups_dest_t *dests; + int num_dests; + cups_dest_t *dest; + smb_share_t si; + smb_cups_ops_t *cups; + + if ((cups = spoolss_cups_ops()) == NULL) + return; + + if (smb_shr_get(SMB_SHARE_PRINT, &si) != NERR_Success) { + syslog(LOG_DEBUG, "error getting print$"); + return; + } + + num_dests = cups->cupsGetDests(&dests); + for (i = num_dests, dest = dests; i > 0; i--, dest++) { + if (dest->instance == NULL) { + /* + * Use the path from print$ + */ + (void) strlcpy(si.shr_name, dest->name, MAXPATHLEN); + (void) strlcpy(si.shr_cmnt, + SMB_SHARE_PRINT, SMB_SHARE_PRINT_LEN + 1); + si.shr_type = STYPE_PRINTQ; + nerr = smb_shr_add(&si); + if (nerr != NERR_Success) + break; + } + } + cups->cupsFreeDests(num_dests, dests); +} + +/* * Load the shares contained in the specified group. * * Don't process groups on which the smb protocol is disabled. @@ -1562,9 +1616,6 @@ return (status); } - if ((si.shr_flags & SMB_SHRF_DFSROOT) != 0) - dfs_namespace_load(si.shr_name); - return (NERR_Success); } @@ -2432,6 +2483,8 @@ if ((csc = smb_shr_sa_csc_name(si)) != NULL) rc |= nvlist_add_string(smb, SHOPT_CSC, csc); + rc |= nvlist_add_uint32(smb, "type", si->shr_type); + rc |= nvlist_add_nvlist(share, "smb", smb); rc |= nvlist_add_nvlist(list, si->shr_name, share);
--- a/usr/src/lib/smbsrv/libmlsvc/common/spoolss_svc.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/smbsrv/libmlsvc/common/spoolss_svc.c Thu Jul 22 14:53:56 2010 -0700 @@ -18,70 +18,138 @@ * * CDDL HEADER END */ - /* - * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * Printing and Spooling RPC service. */ - +#include <unistd.h> #include <stdlib.h> #include <strings.h> +#include <pthread.h> +#include <synch.h> #include <smbsrv/libsmb.h> #include <smbsrv/libmlrpc.h> #include <smbsrv/libmlsvc.h> +#include <smbsrv/ndl/ndrtypes.ndl> #include <smbsrv/ndl/spoolss.ndl> +#include <smb/nterror.h> #include <smbsrv/smbinfo.h> #include <smbsrv/nmpipes.h> +#include <wchar.h> +#include <cups/cups.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <dlfcn.h> +#include <mlsvc.h> -int spoolss_s_OpenPrinter(void *, ndr_xa_t *); -int spoolss_s_stub(void *, ndr_xa_t *); +typedef struct smb_spool { + list_t sp_list; + int sp_cnt; + rwlock_t sp_rwl; + int sp_initialized; +} smb_spool_t; + +static uint32_t spoolss_cnt; +static uint32_t spoolss_jobnum = 1; +static smb_spool_t spoolss_splist; +static smb_cups_ops_t smb_cups; +static mutex_t spoolss_cups_mutex; + +#define SPOOLSS_PJOBLEN 256 +#define SPOOLSS_JOB_NOT_ISSUED 3004 +#define SPOOLSS_PRINTER "Postscript" +#define SPOOLSS_FN_PREFIX "cifsprintjob-" +#define SPOOLSS_CUPS_SPOOL_DIR "//var//spool//cups" + +struct spoolss_printjob { + pid_t pj_pid; + int pj_sysjob; + int pj_fd; + time_t pj_start_time; + int pj_status; + size_t pj_size; + int pj_page_count; + boolean_t pj_isspooled; + boolean_t pj_jobnum; + char pj_filename[SPOOLSS_PJOBLEN]; + char pj_jobname[SPOOLSS_PJOBLEN]; + char pj_username[SPOOLSS_PJOBLEN]; + char pj_queuename[SPOOLSS_PJOBLEN]; +}; + +DECL_FIXUP_STRUCT(spoolss_GetPrinter_result_u); +DECL_FIXUP_STRUCT(spoolss_GetPrinter_result); +DECL_FIXUP_STRUCT(spoolss_GetPrinter); + +DECL_FIXUP_STRUCT(spoolss_RPC_V2_NOTIFY_INFO_DATA_DATA); +DECL_FIXUP_STRUCT(spoolss_RPC_V2_NOTIFY_INFO_DATA); +DECL_FIXUP_STRUCT(spoolss_RPC_V2_NOTIFY_INFO); +DECL_FIXUP_STRUCT(spoolss_RFNPCNEX); + +uint32_t srvsvc_sd_set_relative(smb_sd_t *, uint8_t *); +static int spoolss_s_make_sd(uint8_t *); +static uint32_t spoolss_sd_format(smb_sd_t *); +static int spoolss_find_fd(ndr_hdid_t *); +static void spoolss_find_doc_and_print(ndr_hdid_t *); +static void spoolss_add_spool_doc(smb_spooldoc_t *); +static int spoolss_cups_init(void); +static void spoolss_cups_fini(void); + +static int spoolss_s_OpenPrinter(void *, ndr_xa_t *); +static int spoolss_s_ClosePrinter(void *, ndr_xa_t *); +static int spoolss_s_AbortPrinter(void *, ndr_xa_t *); +static int spoolss_s_ResetPrinter(void *, ndr_xa_t *); +static int spoolss_s_GetPrinter(void *, ndr_xa_t *); +static int spoolss_s_GetPrinterData(void *, ndr_xa_t *); +static int spoolss_s_AddJob(void *, ndr_xa_t *); +static int spoolss_s_GetJob(void *, ndr_xa_t *); +static int spoolss_s_EnumJobs(void *, ndr_xa_t *); +static int spoolss_s_ScheduleJob(void *, ndr_xa_t *); +static int spoolss_s_StartDocPrinter(void *, ndr_xa_t *); +static int spoolss_s_EndDocPrinter(void *, ndr_xa_t *); +static int spoolss_s_StartPagePrinter(void *, ndr_xa_t *); +static int spoolss_s_EndPagePrinter(void *, ndr_xa_t *); +static int spoolss_s_rfnpcnex(void *, ndr_xa_t *); +static int spoolss_s_WritePrinter(void *, ndr_xa_t *); +static int spoolss_s_EnumForms(void *, ndr_xa_t *); +static int spoolss_s_stub(void *, ndr_xa_t *); static ndr_stub_table_t spoolss_stub_table[] = { + { spoolss_s_GetJob, SPOOLSS_OPNUM_GetJob }, + { spoolss_s_EnumJobs, SPOOLSS_OPNUM_EnumJobs }, + { spoolss_s_stub, SPOOLSS_OPNUM_DeletePrinter }, + { spoolss_s_GetPrinter, SPOOLSS_OPNUM_GetPrinter }, + { spoolss_s_stub, SPOOLSS_OPNUM_GetPrinterDriver }, + { spoolss_s_stub, SPOOLSS_OPNUM_DeletePrinterDriver }, { spoolss_s_OpenPrinter, SPOOLSS_OPNUM_OpenPrinter }, - { spoolss_s_stub, SPOOLSS_OPNUM_GetJob }, - { spoolss_s_stub, SPOOLSS_OPNUM_DeletePrinter }, - { spoolss_s_stub, SPOOLSS_OPNUM_GetPrinterDriver }, - { spoolss_s_stub, SPOOLSS_OPNUM_DeletePrinterDriver }, - { spoolss_s_stub, SPOOLSS_OPNUM_AddPrintProcessor }, - { spoolss_s_stub, SPOOLSS_OPNUM_GetPrintProcessorDirectory }, - { spoolss_s_stub, SPOOLSS_OPNUM_AbortPrinter }, - { spoolss_s_stub, SPOOLSS_OPNUM_ReadPrinter }, - { spoolss_s_stub, SPOOLSS_OPNUM_WaitForPrinterChange }, - { spoolss_s_stub, SPOOLSS_OPNUM_AddForm }, - { spoolss_s_stub, SPOOLSS_OPNUM_DeleteForm }, - { spoolss_s_stub, SPOOLSS_OPNUM_GetForm }, - { spoolss_s_stub, SPOOLSS_OPNUM_SetForm }, - { spoolss_s_stub, SPOOLSS_OPNUM_EnumMonitors }, - { spoolss_s_stub, SPOOLSS_OPNUM_AddPort }, - { spoolss_s_stub, SPOOLSS_OPNUM_ConfigurePort }, - { spoolss_s_stub, SPOOLSS_OPNUM_DeletePort }, - { spoolss_s_stub, SPOOLSS_OPNUM_CreatePrinterIc }, - { spoolss_s_stub, SPOOLSS_OPNUM_PlayDescriptionPrinterIc }, - { spoolss_s_stub, SPOOLSS_OPNUM_DeletePrinterIc }, - { spoolss_s_stub, SPOOLSS_OPNUM_AddPrinterConnection }, - { spoolss_s_stub, SPOOLSS_OPNUM_DeletePrinterConnection }, - { spoolss_s_stub, SPOOLSS_OPNUM_PrinterMessageBox }, - { spoolss_s_stub, SPOOLSS_OPNUM_AddMonitor }, - { spoolss_s_stub, SPOOLSS_OPNUM_DeleteMonitor }, - { spoolss_s_stub, SPOOLSS_OPNUM_DeletePrintProcessor }, - { spoolss_s_stub, SPOOLSS_OPNUM_AddPrintProvider }, - { spoolss_s_stub, SPOOLSS_OPNUM_DeletePrintProvider }, - { spoolss_s_stub, SPOOLSS_OPNUM_ResetPrinter }, - { spoolss_s_stub, SPOOLSS_OPNUM_FindFirstChangeNotify }, - { spoolss_s_stub, SPOOLSS_OPNUM_FindNextChangeNotify }, - { spoolss_s_stub, SPOOLSS_OPNUM_RouterFindFirstNotify }, - { spoolss_s_stub, SPOOLSS_OPNUM_ReplyOpenPrinter }, - { spoolss_s_stub, SPOOLSS_OPNUM_RouterReplyPrinter }, - { spoolss_s_stub, SPOOLSS_OPNUM_ReplyClosePrinter }, - { spoolss_s_stub, SPOOLSS_OPNUM_AddPortEx }, - { spoolss_s_stub, SPOOLSS_OPNUM_RemoteFindFirstChangeNotify }, - { spoolss_s_stub, SPOOLSS_OPNUM_SpoolerInitialize }, - { spoolss_s_stub, SPOOLSS_OPNUM_ResetPrinterEx }, - { spoolss_s_stub, SPOOLSS_OPNUM_RouterRefreshChangeNotify }, - { spoolss_s_OpenPrinter, SPOOLSS_OPNUM_OpenPrinter2 }, + { spoolss_s_StartDocPrinter, SPOOLSS_OPNUM_StartDocPrinter }, + { spoolss_s_WritePrinter, SPOOLSS_OPNUM_WritePrinter }, + { spoolss_s_EndDocPrinter, SPOOLSS_OPNUM_EndDocPrinter }, + { spoolss_s_StartPagePrinter, SPOOLSS_OPNUM_StartPagePrinter }, + { spoolss_s_EndPagePrinter, SPOOLSS_OPNUM_EndPagePrinter }, + { spoolss_s_AbortPrinter, SPOOLSS_OPNUM_AbortPrinter }, + { spoolss_s_ResetPrinter, SPOOLSS_OPNUM_ResetPrinter }, + { spoolss_s_AddJob, SPOOLSS_OPNUM_AddJob }, + { spoolss_s_ScheduleJob, SPOOLSS_OPNUM_ScheduleJob }, + { spoolss_s_GetPrinterData, SPOOLSS_OPNUM_GetPrinterData }, + { spoolss_s_ClosePrinter, SPOOLSS_OPNUM_ClosePrinter }, + { spoolss_s_EnumForms, SPOOLSS_OPNUM_EnumForms }, + { spoolss_s_stub, SPOOLSS_OPNUM_GetPrinterDriver2 }, + { spoolss_s_stub, SPOOLSS_OPNUM_FCPN }, + { spoolss_s_stub, SPOOLSS_OPNUM_ReplyOpenPrinter }, + { spoolss_s_stub, SPOOLSS_OPNUM_ReplyClosePrinter }, + { spoolss_s_stub, SPOOLSS_OPNUM_RFFPCNEX }, + { spoolss_s_rfnpcnex, SPOOLSS_OPNUM_RFNPCNEX }, + { spoolss_s_stub, SPOOLSS_OPNUM_RRPCN }, + { spoolss_s_OpenPrinter, SPOOLSS_OPNUM_OpenPrinterEx }, + { spoolss_s_stub, SPOOLSS_OPNUM_EnumPrinterData }, + { spoolss_s_stub, SPOOLSS_OPNUM_EnumPrinterDataEx }, + { spoolss_s_stub, SPOOLSS_OPNUM_EnumPrinterKey }, {0} }; @@ -90,7 +158,7 @@ "Print Spool Service", /* desc */ "\\spoolss", /* endpoint */ PIPE_SPOOLSS, /* sec_addr_port */ - "12345678-1234-abcd-ef000123456789ab", 1, /* abstract */ + "12345678-1234-abcd-ef00-0123456789ab", 1, /* abstract */ NDR_TRANSFER_SYNTAX_UUID, 2, /* transfer */ 0, /* no bind_instance_size */ 0, /* no bind_req() */ @@ -104,26 +172,980 @@ spoolss_initialize(void) { (void) ndr_svc_register(&spoolss_service); + (void) spoolss_cups_init(); } -int +void +spoolss_finalize(void) +{ + spoolss_cups_fini(); +} + +static int spoolss_s_OpenPrinter(void *arg, ndr_xa_t *mxa) { struct spoolss_OpenPrinter *param = arg; + ndr_hdid_t *id; - bzero(param, sizeof (struct spoolss_OpenPrinter)); + if ((id = ndr_hdalloc(mxa, 0)) == NULL) { + bzero(¶m->handle, sizeof (spoolss_handle_t)); + param->status = ERROR_NOT_ENOUGH_MEMORY; + return (NDR_DRC_OK); + } + + bcopy(id, ¶m->handle, sizeof (spoolss_handle_t)); + param->status = 0; - if (mxa == NULL) - param->status = NT_SC_ERROR(NT_STATUS_INVALID_PARAMETER); - else - param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); + return (NDR_DRC_OK); +} + +/*ARGSUSED*/ +static int +spoolss_s_StartPagePrinter(void *arg, ndr_xa_t *mxa) +{ + struct spoolss_StartPagePrinter *param = arg; + + param->status = ERROR_SUCCESS; return (NDR_DRC_OK); } /*ARGSUSED*/ +static int +spoolss_s_EndPagePrinter(void *arg, ndr_xa_t *mxa) +{ + struct spoolss_EndPagePrinter *param = arg; + + param->status = ERROR_SUCCESS; + + return (NDR_DRC_OK); +} + +/* + * + * adds new spool doc to the tail. used by windows + * XP and 2000 only + * + * Return values + * smb_spooldoc_t - NULL if not found + */ + +static void +spoolss_add_spool_doc(smb_spooldoc_t *sp) +{ + (void) rw_wrlock(&spoolss_splist.sp_rwl); + if (!spoolss_splist.sp_initialized) { + list_create(&spoolss_splist.sp_list, + sizeof (smb_spooldoc_t), + offsetof(smb_spooldoc_t, sd_lnd)); + spoolss_splist.sp_initialized = 1; + } + list_insert_tail(&spoolss_splist.sp_list, sp); + spoolss_splist.sp_cnt++; + (void) rw_unlock(&spoolss_splist.sp_rwl); +} + +/* + * + * finds a completed spool doc using the RPC handle + * as the key, then prints the doc + * + * XP and 2000 only + * + */ + +static void +spoolss_find_doc_and_print(ndr_hdid_t *handle) +{ + smb_spooldoc_t *sp; + + if (!spoolss_splist.sp_initialized) { + syslog(LOG_ERR, "spoolss_find_doc_and_print: not initialized"); + return; + } + (void) rw_wrlock(&spoolss_splist.sp_rwl); + sp = list_head(&spoolss_splist.sp_list); + while (sp != NULL) { + /* + * search the spooldoc list for a matching RPC handle + * and use the info to pass to cups for printing + */ + if (!memcmp(handle, &(sp->sd_handle), sizeof (ndr_hdid_t))) { + spoolss_copy_spool_file(&sp->sd_ipaddr, + sp->sd_username, sp->sd_path, sp->sd_doc_name); + (void) close(sp->sd_fd); + list_remove(&spoolss_splist.sp_list, sp); + free(sp); + (void) rw_unlock(&spoolss_splist.sp_rwl); + return; + } + sp = list_next(&spoolss_splist.sp_list, sp); + } + syslog(LOG_ERR, "spoolss_find_doc_and_print: handle not found"); + (void) rw_unlock(&spoolss_splist.sp_rwl); +} + +static int +spoolss_find_fd(ndr_hdid_t *handle) +{ + smb_spooldoc_t *sp; + + if (!spoolss_splist.sp_initialized) { + syslog(LOG_ERR, "spoolss_find_fd: not initialized"); + return (-1); + } + (void) rw_rdlock(&spoolss_splist.sp_rwl); + sp = list_head(&spoolss_splist.sp_list); + while (sp != NULL) { + /* + * check for a matching rpc handle in the + * spooldoc list + */ + if (!memcmp(handle, &(sp->sd_handle), sizeof (ndr_hdid_t))) { + (void) rw_unlock(&spoolss_splist.sp_rwl); + return (sp->sd_fd); + } + sp = list_next(&spoolss_splist.sp_list, sp); + } + syslog(LOG_ERR, "spoolss_find_fd: handle not found"); + (void) rw_unlock(&spoolss_splist.sp_rwl); + return (-1); +} + +/* + * Windows XP and 2000 use this mechanism to write spool files. + * Creates a spool file fd to be used by spoolss_s_WritePrinter. + */ +static int +spoolss_s_StartDocPrinter(void *arg, ndr_xa_t *mxa) +{ + struct spoolss_StartDocPrinter *param = arg; + ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; + smb_spooldoc_t *spfile; + spoolss_DocInfo_t *docinfo; + char g_path[MAXPATHLEN]; + smb_share_t si; + int rc; + int fd; + + if (ndr_hdlookup(mxa, id) == NULL) { + syslog(LOG_ERR, "spoolss_s_StartDocPrinter: invalid handle"); + param->status = ERROR_INVALID_HANDLE; + return (NDR_DRC_OK); + } + + if ((docinfo = param->dinfo.DocInfoContainer) == NULL) { + param->status = ERROR_INVALID_PARAMETER; + return (NDR_DRC_OK); + } + + if ((rc = smb_shr_get(SMB_SHARE_PRINT, &si)) != NERR_Success) { + syslog(LOG_INFO, "spoolss_s_StartDocPrinter: %s error=%d", + SMB_SHARE_PRINT, rc); + param->status = rc; + return (NDR_DRC_OK); + } + + if ((spfile = calloc(1, sizeof (smb_spooldoc_t))) == NULL) { + param->status = ERROR_NOT_ENOUGH_MEMORY; + return (NDR_DRC_OK); + } + + if (docinfo->doc_name != NULL) + (void) strlcpy(spfile->sd_doc_name, + (char *)docinfo->doc_name, MAXNAMELEN); + else + (void) strlcpy(spfile->sd_doc_name, "document", MAXNAMELEN); + + if (docinfo->printer_name != NULL) + (void) strlcpy(spfile->sd_printer_name, + (char *)docinfo->printer_name, MAXPATHLEN); + else + (void) strlcpy(spfile->sd_printer_name, "printer", MAXPATHLEN); + + spfile->sd_ipaddr = mxa->pipe->np_user.ui_ipaddr; + (void) strlcpy((char *)spfile->sd_username, + mxa->pipe->np_user.ui_account, MAXNAMELEN); + (void) memcpy(&spfile->sd_handle, ¶m->handle, + sizeof (rpc_handle_t)); + /* + * write temporary spool file to print$ + */ + (void) snprintf(g_path, MAXPATHLEN, "%s/%s%d", si.shr_path, + spfile->sd_username, spoolss_cnt); + atomic_inc_32(&spoolss_cnt); + + fd = open(g_path, O_CREAT | O_RDWR, 0600); + if (fd == -1) { + syslog(LOG_INFO, "spoolss_s_StartDocPrinter: %s: %s", + g_path, strerror(errno)); + param->status = ERROR_OPEN_FAILED; + free(spfile); + } else { + (void) strlcpy((char *)spfile->sd_path, g_path, MAXPATHLEN); + spfile->sd_fd = (uint16_t)fd; + spoolss_add_spool_doc(spfile); + /* + * JobId isn't used now, but if printQ management is added + * this will have to be incremented per job submitted. + */ + param->JobId = 46; + param->status = ERROR_SUCCESS; + } + return (NDR_DRC_OK); +} + +/* + * Windows XP and 2000 use this mechanism to write spool files + */ + +/*ARGSUSED*/ +static int +spoolss_s_EndDocPrinter(void *arg, ndr_xa_t *mxa) +{ + struct spoolss_EndDocPrinter *param = arg; + + spoolss_find_doc_and_print((ndr_hdid_t *)¶m->handle); + param->status = ERROR_SUCCESS; + return (NDR_DRC_OK); +} + +/*ARGSUSED*/ +static int +spoolss_s_AbortPrinter(void *arg, ndr_xa_t *mxa) +{ + struct spoolss_AbortPrinter *param = arg; + + param->status = ERROR_SUCCESS; + return (NDR_DRC_OK); +} + +/*ARGSUSED*/ +static int +spoolss_s_ResetPrinter(void *arg, ndr_xa_t *mxa) +{ + struct spoolss_AbortPrinter *param = arg; + + param->status = ERROR_SUCCESS; + return (NDR_DRC_OK); +} + +static int +spoolss_s_ClosePrinter(void *arg, ndr_xa_t *mxa) +{ + struct spoolss_ClosePrinter *param = arg; + ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; + ndr_handle_t *hd; + + if ((hd = ndr_hdlookup(mxa, id)) != NULL) { + free(hd->nh_data); + hd->nh_data = NULL; + } + + ndr_hdfree(mxa, id); + bzero(¶m->result_handle, sizeof (spoolss_handle_t)); + param->status = ERROR_SUCCESS; + return (NDR_DRC_OK); +} + +/*ARGSUSED*/ int +spoolss_s_EnumForms(void *arg, ndr_xa_t *mxa) +{ + struct spoolss_EnumForms *param = arg; + DWORD status = ERROR_SUCCESS; + + param->status = status; + param->needed = 0; + return (NDR_DRC_OK); +} + +/*ARGSUSED*/ +int +spoolss_s_EnumJobs(void *arg, ndr_xa_t *mxa) +{ + struct spoolss_EnumJobs *param = arg; + DWORD status = ERROR_SUCCESS; + + switch (param->level) { + case 1: + case 2: + case 3: + case 4: + default: + break; + } + + param->status = status; + param->needed = 0; + param->needed2 = 0; + return (NDR_DRC_OK); +} + + +/*ARGSUSED*/ +static int +spoolss_s_GetJob(void *arg, ndr_xa_t *mxa) +{ + struct spoolss_GetJob *param = arg; + DWORD status = ERROR_SUCCESS; + + if (param->BufCount == 0) + param->status = ERROR_INSUFFICIENT_BUFFER; + else + param->status = status; + param->needed = 0; + return (NDR_DRC_OK); +} + + +/*ARGSUSED*/ +static int +spoolss_s_ScheduleJob(void *arg, ndr_xa_t *mxa) +{ + struct spoolss_ScheduleJob *param = arg; + DWORD status = SPOOLSS_JOB_NOT_ISSUED; + + param->status = status; + return (NDR_DRC_OK); +} + +/*ARGSUSED*/ +static int +spoolss_s_AddJob(void *arg, ndr_xa_t *mxa) +{ + struct spoolss_AddJob *param = arg; + + param->status = ERROR_SUCCESS; + param->needed = 0; + return (NDR_DRC_OK); +} + +/*ARGSUSED*/ +static int +spoolss_s_rfnpcnex(void *arg, ndr_xa_t *mxa) +{ + struct spoolss_RFNPCNEX *param = arg; + + param->ppinfo = 0; + param->status = ERROR_SUCCESS; + return (NDR_DRC_OK); +} + +/* + * Use the RPC context handle to find the fd and write the document content. + */ +static int +spoolss_s_WritePrinter(void *arg, ndr_xa_t *mxa) +{ + struct spoolss_WritePrinter *param = arg; + int written = 0; + ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; + int spfd; + + if (ndr_hdlookup(mxa, id) == NULL) { + param->written = 0; + param->status = ERROR_INVALID_HANDLE; + syslog(LOG_ERR, "spoolss_s_WritePrinter: invalid handle"); + return (NDR_DRC_OK); + } + + if ((spfd = spoolss_find_fd(id)) < 0) { + param->written = 0; + param->status = ERROR_INVALID_HANDLE; + syslog(LOG_ERR, "spoolss_s_WritePrinter: cannot find fd"); + return (NDR_DRC_OK); + } + + written = write(spfd, param->pBuf, param->BufCount); + if (written < param->BufCount) { + syslog(LOG_ERR, "spoolss_s_WritePrinter: write failed"); + param->written = 0; + param->status = ERROR_CANTWRITE; + return (NDR_DRC_OK); + } + + param->written = written; + param->status = ERROR_SUCCESS; + return (NDR_DRC_OK); +} + +/* + * All versions of windows use this function to print + * spool files via the cups interface + */ + +void +spoolss_copy_spool_file(smb_inaddr_t *ipaddr, char *username, + char *path, char *doc_name) +{ + smb_cups_ops_t *cups; + int ret = 1; /* Return value */ + http_t *http = NULL; /* HTTP connection to server */ + ipp_t *request = NULL; /* IPP Request */ + ipp_t *response = NULL; /* IPP Response */ + cups_lang_t *language = NULL; /* Default language */ + char uri[HTTP_MAX_URI]; /* printer-uri attribute */ + char new_jobname[SPOOLSS_PJOBLEN]; + struct spoolss_printjob pjob; + char clientname[INET6_ADDRSTRLEN]; + struct stat sbuf; + + if (stat(path, &sbuf)) { + syslog(LOG_INFO, "spoolss_copy_spool_file: %s: %s", + path, strerror(errno)); + return; + } + + /* + * Remove zero size files and return; these were inadvertantly + * created by XP or 2000. + */ + if (sbuf.st_blocks == 0) { + if (remove(path)) + syslog(LOG_INFO, + "spoolss_copy_spool_file: cannot remove %s", path); + return; + } + + if ((cups = spoolss_cups_ops()) == NULL) + return; + + if ((http = cups->httpConnect("localhost", 631)) == NULL) { + syslog(LOG_INFO, "spoolss_copy_spool_file: cupsd not running"); + return; + } + + if ((request = cups->ippNew()) == NULL) { + syslog(LOG_INFO, "spoolss_copy_spool_file: ipp not running"); + return; + } + request->request.op.operation_id = IPP_PRINT_JOB; + request->request.op.request_id = 1; + language = cups->cupsLangDefault(); + + cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cups->cupsLangEncoding(language)); + + cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + (void) snprintf(uri, sizeof (uri), "ipp://localhost/printers/%s", + SPOOLSS_PRINTER); + pjob.pj_pid = pthread_self(); + pjob.pj_sysjob = 10; + (void) strlcpy(pjob.pj_filename, path, SPOOLSS_PJOBLEN); + pjob.pj_start_time = time(NULL); + pjob.pj_status = 2; + pjob.pj_size = sbuf.st_blocks * 512; + pjob.pj_page_count = 1; + pjob.pj_isspooled = B_TRUE; + pjob.pj_jobnum = spoolss_jobnum; + + (void) strlcpy(pjob.pj_jobname, doc_name, SPOOLSS_PJOBLEN); + (void) strlcpy(pjob.pj_username, username, SPOOLSS_PJOBLEN); + (void) strlcpy(pjob.pj_queuename, SPOOLSS_CUPS_SPOOL_DIR, + SPOOLSS_PJOBLEN); + cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, uri); + + cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requesting-user-name", NULL, pjob.pj_username); + + if (smb_inet_ntop(ipaddr, clientname, + SMB_IPSTRLEN(ipaddr->a_family)) == NULL) { + syslog(LOG_INFO, "spoolss_copy_spool_file: %s: unknown client", + clientname); + goto out; + } + cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "job-originating-host-name", NULL, clientname); + + (void) snprintf(new_jobname, SPOOLSS_PJOBLEN, "%s%d", + SPOOLSS_FN_PREFIX, pjob.pj_jobnum); + cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "job-name", NULL, new_jobname); + + (void) snprintf(uri, sizeof (uri) - 1, "/printers/%s", SPOOLSS_PRINTER); + + response = cups->cupsDoFileRequest(http, request, uri, + pjob.pj_filename); + if (response != NULL) { + if (response->request.status.status_code >= IPP_OK_CONFLICT) { + syslog(LOG_ERR, + "spoolss_copy_spool_file: file print %s: %s", + SPOOLSS_PRINTER, + cups->ippErrorString(cups->cupsLastError())); + } else { + atomic_inc_32(&spoolss_jobnum); + ret = 0; + } + } else { + syslog(LOG_ERR, + "spoolss_copy_spool_file: unable to print file to %s", + cups->ippErrorString(cups->cupsLastError())); + } + + if (ret == 0) + (void) unlink(pjob.pj_filename); + +out: + if (response) + cups->ippDelete(response); + + if (language) + cups->cupsLangFree(language); + + if (http) + cups->httpClose(http); +} + +static int +spoolss_s_GetPrinterData(void *arg, ndr_xa_t *mxa) +{ + struct spoolss_GetPrinterData *param = arg; + DWORD status = ERROR_SUCCESS; + + if (param->Size > 0) { + param->Buf = NDR_NEWN(mxa, char, param->Size); + bzero(param->Buf, param->Size); + } else { + param->Buf = NDR_NEWN(mxa, uint32_t, 1); + param->Buf[0] = 1; + param->Buf[1] = 1; + param->Buf[2] = 2; + param->Buf[3] = 2; + } + + /* + * Increment pType if the Printer Data changes + * as specified by Microsoft documentation + */ + param->pType = 1; + if (strcasecmp((char *)param->pValueName, "ChangeId") == 0) { + param->pType = 4; + param->Buf[3] = 0x00; + param->Buf[2] = 0x50; + param->Buf[1] = 0xac; + param->Buf[0] = 0xf2; + } else if (strcasecmp((char *)param->pValueName, + "UISingleJobStatusString") == 0) { + status = ERROR_FILE_NOT_FOUND; + } else if (strcasecmp((char *)param->pValueName, + "W3SvcInstalled") == 0) { + status = ERROR_FILE_NOT_FOUND; + } else if (strcasecmp((char *)param->pValueName, + "PrintProcCaps_NT EMF 1.008") == 0) { + status = ERROR_FILE_NOT_FOUND; + } else if (strcasecmp((char *)param->pValueName, "OSVersion") == 0) { + param->Buf = NDR_NEWN(mxa, char, param->Size); + bzero(param->Buf, param->Size); + param->Buf[0] = 0x14; + param->Buf[1] = 0x01; + param->Buf[4] = 0x05; + param->Buf[12] = 0x93; + param->Buf[13] = 0x08; + } + param->status = status; + param->Needed = param->Size; + return (NDR_DRC_OK); +} + +smb_cups_ops_t * +spoolss_cups_ops(void) +{ + if (spoolss_cups_init() != 0) + return (NULL); + + return (&smb_cups); +} + +static int +spoolss_cups_init(void) +{ + (void) mutex_lock(&spoolss_cups_mutex); + + if (smb_cups.cups_hdl != NULL) { + (void) mutex_unlock(&spoolss_cups_mutex); + return (0); + } + + if ((smb_cups.cups_hdl = dlopen("libcups.so.2", RTLD_NOW)) == NULL) { + (void) mutex_unlock(&spoolss_cups_mutex); + syslog(LOG_DEBUG, "spoolss_cups_init: cannot open libcups"); + return (ENOENT); + } + + smb_cups.cupsLangDefault = + (cups_lang_t *(*)())dlsym(smb_cups.cups_hdl, "cupsLangDefault"); + smb_cups.cupsLangEncoding = (const char *(*)(cups_lang_t *)) + dlsym(smb_cups.cups_hdl, "cupsLangEncoding"); + smb_cups.cupsDoFileRequest = + (ipp_t *(*)(http_t *, ipp_t *, const char *, const char *)) + dlsym(smb_cups.cups_hdl, "cupsDoFileRequest"); + smb_cups.cupsLastError = (ipp_status_t (*)()) + dlsym(smb_cups.cups_hdl, "cupsLastError"); + smb_cups.cupsLangFree = (void (*)(cups_lang_t *)) + dlsym(smb_cups.cups_hdl, "cupsLangFree"); + smb_cups.cupsGetDests = (int (*)(cups_dest_t **)) + dlsym(smb_cups.cups_hdl, "cupsGetDests"); + smb_cups.cupsFreeDests = (void (*)(int, cups_dest_t *)) + dlsym(smb_cups.cups_hdl, "cupsFreeDests"); + + smb_cups.httpClose = (void (*)(http_t *)) + dlsym(smb_cups.cups_hdl, "httpClose"); + smb_cups.httpConnect = (http_t *(*)(const char *, int)) + dlsym(smb_cups.cups_hdl, "httpConnect"); + + smb_cups.ippNew = (ipp_t *(*)())dlsym(smb_cups.cups_hdl, "ippNew"); + smb_cups.ippDelete = (void (*)())dlsym(smb_cups.cups_hdl, "ippDelete"); + smb_cups.ippErrorString = (char *(*)()) + dlsym(smb_cups.cups_hdl, "ippErrorString"); + smb_cups.ippAddString = (ipp_attribute_t *(*)()) + dlsym(smb_cups.cups_hdl, "ippAddString"); + + if (smb_cups.cupsLangDefault == NULL || + smb_cups.cupsLangEncoding == NULL || + smb_cups.cupsDoFileRequest == NULL || + smb_cups.cupsLastError == NULL || + smb_cups.cupsLangFree == NULL || + smb_cups.cupsGetDests == NULL || + smb_cups.cupsFreeDests == NULL || + smb_cups.ippNew == NULL || + smb_cups.httpClose == NULL || + smb_cups.httpConnect == NULL || + smb_cups.ippDelete == NULL || + smb_cups.ippErrorString == NULL || + smb_cups.ippAddString == NULL) { + smb_dlclose(smb_cups.cups_hdl); + smb_cups.cups_hdl = NULL; + (void) mutex_unlock(&spoolss_cups_mutex); + syslog(LOG_DEBUG, "spoolss_cups_init: cannot load libcups"); + return (ENOENT); + } + + (void) mutex_unlock(&spoolss_cups_mutex); + return (0); +} + +static void +spoolss_cups_fini(void) +{ + (void) mutex_lock(&spoolss_cups_mutex); + + if (smb_cups.cups_hdl != NULL) { + smb_dlclose(smb_cups.cups_hdl); + smb_cups.cups_hdl = NULL; + } + + (void) mutex_unlock(&spoolss_cups_mutex); +} + +void +smb_rpc_off(char *dst, char *src, uint32_t *offset, uint32_t *outoffset) +{ + int nwchars; + int bytes; + + bytes = smb_wcequiv_strlen(src) + 2; + nwchars = strlen(src) + 1; + *offset -= bytes; + *outoffset = *offset; + /*LINTED E_BAD_PTR_CAST_ALIGN*/ + (void) smb_mbstowcs(((smb_wchar_t *)(dst + *offset)), src, nwchars); +} + +int +spoolss_s_GetPrinter(void *arg, ndr_xa_t *mxa) +{ + struct spoolss_GetPrinter *param = arg; + struct spoolss_GetPrinter0 *pinfo0; + struct spoolss_GetPrinter1 *pinfo1; + struct spoolss_GetPrinter2 *pinfo2; + struct spoolss_DeviceMode *devmode2; + DWORD status = ERROR_SUCCESS; + char *wname; + uint32_t offset; + smb_inaddr_t ipaddr; + struct hostent *h; + char hname[MAXHOSTNAMELEN]; + char soutbuf[MAXNAMELEN]; + char poutbuf[MAXNAMELEN]; + char ipstr[INET6_ADDRSTRLEN]; + int error; + uint8_t *tmpbuf; + + if (param->BufCount == 0) { + status = ERROR_INSUFFICIENT_BUFFER; + goto error_out; + } + param->Buf = NDR_NEWN(mxa, char, param->BufCount); + bzero(param->Buf, param->BufCount); + switch (param->switch_value) { + case 0: + /*LINTED E_BAD_PTR_CAST_ALIGN*/ + pinfo0 = (struct spoolss_GetPrinter0 *)param->Buf; + break; + case 1: + /*LINTED E_BAD_PTR_CAST_ALIGN*/ + pinfo1 = (struct spoolss_GetPrinter1 *)param->Buf; + break; + case 2: + /*LINTED E_BAD_PTR_CAST_ALIGN*/ + pinfo2 = (struct spoolss_GetPrinter2 *)param->Buf; + break; + } + wname = (char *)param->Buf; + + status = ERROR_INVALID_PARAMETER; + if (smb_gethostname(hname, MAXHOSTNAMELEN, 0) != 0) { + syslog(LOG_NOTICE, "spoolss_s_GetPrinter: gethostname failed"); + goto error_out; + } + if ((h = smb_gethostbyname(hname, &error)) == NULL) { + syslog(LOG_NOTICE, + "spoolss_s_GetPrinter: gethostbyname failed"); + goto error_out; + } + bcopy(h->h_addr, &ipaddr, h->h_length); + ipaddr.a_family = h->h_addrtype; + freehostent(h); + if (smb_inet_ntop(&ipaddr, ipstr, SMB_IPSTRLEN(ipaddr.a_family)) + == NULL) { + syslog(LOG_NOTICE, "spoolss_s_GetPrinter: inet_ntop failed"); + goto error_out; + } + status = ERROR_SUCCESS; + (void) snprintf(poutbuf, MAXNAMELEN, "\\\\%s\\%s", + ipstr, SPOOLSS_PRINTER); + (void) snprintf(soutbuf, MAXNAMELEN, "\\\\%s", ipstr); + param->needed = 0; + switch (param->switch_value) { + case 0: + offset = 460; + smb_rpc_off(wname, "", &offset, &pinfo0->servername); + smb_rpc_off(wname, poutbuf, &offset, &pinfo0->printername); + pinfo0->cjobs = 0; + pinfo0->total_jobs = 6; + pinfo0->total_bytes = 1040771; + pinfo0->time0 = 0; + pinfo0->time1 = 0; + pinfo0->time2 = 3; + pinfo0->time3 = 0; + pinfo0->global_counter = 2162710; + pinfo0->total_pages = 21495865; + pinfo0->version = 10; + pinfo0->session_counter = 1; + pinfo0->job_error = 0x6; + pinfo0->change_id = 0x1; + pinfo0->status = 0; + pinfo0->c_setprinter = 0; + break; + case 1: + pinfo1->flags = PRINTER_ENUM_ICON8; + offset = 460; + smb_rpc_off(wname, poutbuf, &offset, &pinfo1->flags); + smb_rpc_off(wname, poutbuf, &offset, &pinfo1->description); + smb_rpc_off(wname, poutbuf, &offset, &pinfo1->comment); + break; + case 2: + offset = param->BufCount; + smb_rpc_off(wname, soutbuf, &offset, &pinfo2->servername); + smb_rpc_off(wname, poutbuf, &offset, &pinfo2->printername); + smb_rpc_off(wname, SPOOLSS_PRINTER, &offset, + &pinfo2->sharename); + smb_rpc_off(wname, "CIFS Printer Port", &offset, + &pinfo2->portname); + smb_rpc_off(wname, "", &offset, &pinfo2->drivername); + smb_rpc_off(wname, SPOOLSS_PRINTER, &offset, + &pinfo2->comment); + smb_rpc_off(wname, "farside", &offset, &pinfo2->location); + smb_rpc_off(wname, "farside", &offset, &pinfo2->sepfile); + smb_rpc_off(wname, "winprint", &offset, + &pinfo2->printprocessor); + smb_rpc_off(wname, "RAW", &offset, &pinfo2->datatype); + smb_rpc_off(wname, "", &offset, &pinfo2->datatype); + pinfo2->attributes = 0x00001048; + pinfo2->status = 0x00000000; + pinfo2->starttime = 0; + pinfo2->untiltime = 0; + pinfo2->cjobs = 0; + pinfo2->averageppm = 0; + pinfo2->defaultpriority = 0; + pinfo2->devmode = 568; // offset + /*LINTED E_BAD_PTR_CAST_ALIGN*/ + devmode2 = (struct spoolss_DeviceMode *)(param->Buf + + pinfo2->devmode); + /*LINTED E_BAD_PTR_CAST_ALIGN*/ + (void) smb_mbstowcs(((smb_wchar_t *) + (devmode2->devicename)), (const char *)poutbuf, 25); + devmode2->specversion = 0x0401; + devmode2->driverversion = 1024; + devmode2->size = 220; + devmode2->driverextra_length = 0; + devmode2->fields = 0x00014713; + devmode2->orientation = 1; + devmode2->papersize = 1; + devmode2->paperlength = 0; + devmode2->paperwidth = 0; + devmode2->scale = 100; + devmode2->copies = 1; + devmode2->defaultsource = 15; + devmode2->printquality = 65532; + devmode2->color = 1; + devmode2->duplex = 1; + devmode2->yresolution = 1; + devmode2->ttoption = 1; + devmode2->collate = 0; + /*LINTED E_BAD_PTR_CAST_ALIGN*/ + (void) smb_mbstowcs(((smb_wchar_t *) + (devmode2->formname)), (const char *)"Letter", 6); + devmode2->logpixels = 0; + devmode2->bitsperpel = 0; + devmode2->pelswidth = 0; + devmode2->pelsheight = 0; + devmode2->displayflags = 0; + devmode2->displayfrequency = 0; + devmode2->icmmethod = 0; + devmode2->icmintent = 0; + devmode2->mediatype = 0; + devmode2->dithertype = 0; + devmode2->reserved1 = 0; + devmode2->reserved2 = 0; + devmode2->panningwidth = 0; + devmode2->panningheight = 0; + + pinfo2->secdesc = 84; + tmpbuf = (uint8_t *)(pinfo2->secdesc + (uint8_t *)param->Buf); + error = spoolss_s_make_sd(tmpbuf); + param->needed = 712; + break; + + default: + syslog(LOG_NOTICE, "spoolss_s_GetPrinter: INVALID_LEVEL"); + status = ERROR_INVALID_LEVEL; + break; + + } +error_out: + param->status = status; + return (NDR_DRC_OK); +} + +int +spoolss_s_make_sd(uint8_t *sd_buf) +{ + smb_sd_t sd; + uint32_t status; + + bzero(&sd, sizeof (smb_sd_t)); + + if ((status = spoolss_sd_format(&sd)) == ERROR_SUCCESS) { + status = srvsvc_sd_set_relative(&sd, sd_buf); + smb_sd_term(&sd); + return (NDR_DRC_OK); + } + syslog(LOG_NOTICE, "spoolss_s_make_sd: error status=%d", status); + smb_sd_term(&sd); + return (NDR_DRC_OK); +} + +static uint32_t +spoolss_sd_format(smb_sd_t *sd) +{ + smb_fssd_t fs_sd; + acl_t *acl; + uint32_t status = ERROR_SUCCESS; + + if (acl_fromtext("everyone@:full_set::allow", &acl) != 0) { + syslog(LOG_ERR, "spoolss_sd_format: NOT_ENOUGH_MEMORY"); + return (ERROR_NOT_ENOUGH_MEMORY); + } + smb_fssd_init(&fs_sd, SMB_ALL_SECINFO, SMB_FSSD_FLAGS_DIR); + fs_sd.sd_uid = 0; + fs_sd.sd_gid = 0; + fs_sd.sd_zdacl = acl; + fs_sd.sd_zsacl = NULL; + + if (smb_sd_fromfs(&fs_sd, sd) != NT_STATUS_SUCCESS) { + syslog(LOG_NOTICE, "spoolss_sd_format: ACCESS_DENIED"); + status = ERROR_ACCESS_DENIED; + } + smb_fssd_term(&fs_sd); + return (status); +} + +/*ARGSUSED*/ +static int spoolss_s_stub(void *arg, ndr_xa_t *mxa) { return (NDR_DRC_FAULT_PARAM_0_UNIMPLEMENTED); } + +/*ARGSUSED*/ +void +fixup_spoolss_RFNPCNEX(struct spoolss_RFNPCNEX *val) +{ + unsigned short size1 = 0; + unsigned short size2 = 0; + unsigned short size3 = 0; + struct spoolss_RPC_V2_NOTIFY_INFO *pinfo; + + pinfo = val->ppinfo->pinfo; + switch (pinfo->aData->Reserved) { + case TABLE_STRING: + size1 = sizeof (struct STRING_CONTAINER); + break; + case TABLE_DWORD: + size1 = sizeof (DWORD) * 2; + break; + case TABLE_TIME: + size1 = sizeof (struct SYSTEMTIME_CONTAINER); + break; + case TABLE_DEVMODE: + size1 = sizeof (struct spoolssDevmodeContainer); + break; + case TABLE_SECURITY_DESCRIPTOR: + size1 = sizeof (struct SECURITY_CONTAINER); + break; + default: + return; + } + size2 = size1 + (2 * sizeof (DWORD)); + size3 = size2 + sizeof (ndr_request_hdr_t) + sizeof (DWORD); + + FIXUP_PDU_SIZE(spoolss_RPC_V2_NOTIFY_INFO_DATA_DATA, size1); + FIXUP_PDU_SIZE(spoolss_RPC_V2_NOTIFY_INFO_DATA, size2); + FIXUP_PDU_SIZE(spoolss_RPC_V2_NOTIFY_INFO, size3); + FIXUP_PDU_SIZE(spoolss_RFNPCNEX, size3); +} + +void +fixup_spoolss_GetPrinter(struct spoolss_GetPrinter *val) +{ + unsigned short size1 = 0; + unsigned short size2 = 0; + unsigned short size3 = 0; + + switch (val->switch_value) { + CASE_INFO_ENT(spoolss_GetPrinter, 0); + CASE_INFO_ENT(spoolss_GetPrinter, 1); + CASE_INFO_ENT(spoolss_GetPrinter, 2); + CASE_INFO_ENT(spoolss_GetPrinter, 3); + CASE_INFO_ENT(spoolss_GetPrinter, 4); + CASE_INFO_ENT(spoolss_GetPrinter, 5); + CASE_INFO_ENT(spoolss_GetPrinter, 6); + CASE_INFO_ENT(spoolss_GetPrinter, 7); + CASE_INFO_ENT(spoolss_GetPrinter, 8); + + default: + return; + }; + + size2 = size1 + (2 * sizeof (DWORD)); + size3 = size2 + sizeof (ndr_request_hdr_t) + sizeof (DWORD); + + FIXUP_PDU_SIZE(spoolss_GetPrinter_result_u, size1); + FIXUP_PDU_SIZE(spoolss_GetPrinter_result, size2); + FIXUP_PDU_SIZE(spoolss_GetPrinter, size3); +}
--- a/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c Thu Jul 22 14:53:56 2010 -0700 @@ -1330,6 +1330,7 @@ srvsvc_get_share_flags(smb_share_t *si) { uint32_t flags = 0; + boolean_t shortnames = B_TRUE; switch (si->shr_flags & SMB_SHRF_CSC_MASK) { case SMB_SHRF_CSC_DISABLED: @@ -1352,6 +1353,12 @@ if (si->shr_flags & SMB_SHRF_ABE) flags |= SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM; + /* if 'smb' zfs property: shortnames=disabled */ + if ((smb_kmod_shareinfo(si->shr_name, &shortnames) == 0) && + (shortnames == B_FALSE)) { + flags |= SHI1005_FLAGS_ALLOW_NAMESPACE_CACHING; + } + return (flags); }
--- a/usr/src/lib/smbsrv/libsmb/common/libsmb.h Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/smbsrv/libsmb/common/libsmb.h Thu Jul 22 14:53:56 2010 -0700 @@ -144,6 +144,7 @@ SMB_CI_KPASSWD_SEQNUM, SMB_CI_NETLOGON_SEQNUM, SMB_CI_IPV6_ENABLE, + SMB_CI_PRINT_ENABLE, SMB_CI_MAP, SMB_CI_UNMAP, SMB_CI_DISPOSITION, @@ -226,6 +227,23 @@ extern void smb_config_setdomaininfo(char *, char *, char *, char *, char *); extern uint32_t smb_get_dcinfo(char *, uint32_t, smb_inaddr_t *); +CONTEXT_HANDLE(rpc_handle) rpc_handle_t; + +typedef struct smb_spooldoc { + uint32_t sd_magic; + list_node_t sd_lnd; + smb_inaddr_t sd_ipaddr; + int sd_spool_num; + char sd_username[MAXNAMELEN]; + char sd_path[MAXPATHLEN]; + char sd_doc_name[MAXNAMELEN]; + char sd_printer_name[MAXPATHLEN]; + int32_t sd_fd; + rpc_handle_t sd_handle; +} smb_spooldoc_t; + +int smb_kmod_get_spool_doc(uint32_t *, char *, char *, smb_inaddr_t *); + /* * buffer context structure. This is used to keep track of the buffer * context. @@ -889,6 +907,7 @@ void smb_kmod_unbind(void); int smb_kmod_share(nvlist_t *); int smb_kmod_unshare(nvlist_t *); +int smb_kmod_shareinfo(char *, boolean_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 *);
--- a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers Thu Jul 22 14:53:56 2010 -0700 @@ -220,12 +220,14 @@ smb_kmod_event_notify; smb_kmod_file_close; smb_kmod_get_open_num; + smb_kmod_get_spool_doc; smb_kmod_nbtlisten; smb_kmod_nbtreceive; smb_kmod_session_close; smb_kmod_setcfg; smb_kmod_setgmtoff; smb_kmod_share; + smb_kmod_shareinfo; smb_kmod_start; smb_kmod_stop; smb_kmod_tcplisten;
--- a/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c Thu Jul 22 14:53:56 2010 -0700 @@ -128,6 +128,7 @@ {SMB_CI_NETLOGON_SEQNUM, "netlogon_seqnum", SCF_TYPE_INTEGER, 0}, {SMB_CI_IPV6_ENABLE, "ipv6_enable", SCF_TYPE_BOOLEAN, 0}, + {SMB_CI_PRINT_ENABLE, "print_enable", SCF_TYPE_BOOLEAN, 0}, {SMB_CI_MAP, "map", SCF_TYPE_ASTRING, SMB_CF_EXEC}, {SMB_CI_UNMAP, "unmap", SCF_TYPE_ASTRING, SMB_CF_EXEC}, {SMB_CI_DISPOSITION, "disposition", SCF_TYPE_ASTRING, SMB_CF_EXEC},
--- a/usr/src/lib/smbsrv/libsmb/common/smb_info.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/smbsrv/libsmb/common/smb_info.c Thu Jul 22 14:53:56 2010 -0700 @@ -89,6 +89,7 @@ kcfg->skc_signing_enable = smb_config_getbool(SMB_CI_SIGNING_ENABLE); kcfg->skc_signing_required = smb_config_getbool(SMB_CI_SIGNING_REQD); kcfg->skc_ipv6_enable = smb_config_getbool(SMB_CI_IPV6_ENABLE); + kcfg->skc_print_enable = smb_config_getbool(SMB_CI_PRINT_ENABLE); kcfg->skc_oplock_enable = smb_config_getbool(SMB_CI_OPLOCK_ENABLE); kcfg->skc_sync_enable = smb_config_getbool(SMB_CI_SYNC_ENABLE); kcfg->skc_secmode = smb_config_get_secmode();
--- a/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c Thu Jul 22 14:53:56 2010 -0700 @@ -78,6 +78,7 @@ ioc.sync_enable = cfg->skc_sync_enable; ioc.secmode = cfg->skc_secmode; ioc.ipv6_enable = cfg->skc_ipv6_enable; + ioc.print_enable = cfg->skc_print_enable; ioc.exec_flags = cfg->skc_execflags; ioc.version = cfg->skc_version; @@ -213,6 +214,24 @@ } int +smb_kmod_shareinfo(char *shrname, boolean_t *shortnames) +{ + smb_ioc_shareinfo_t ioc; + int rc; + + bzero(&ioc, sizeof (ioc)); + (void) strlcpy(ioc.shrname, shrname, MAXNAMELEN); + + rc = smb_kmod_ioctl(SMB_IOC_SHAREINFO, &ioc.hdr, sizeof (ioc)); + if (rc == 0) + *shortnames = ioc.shortnames; + else + *shortnames = B_TRUE; + + return (rc); +} + +int smb_kmod_get_open_num(smb_opennum_t *opennum) { smb_ioc_opennum_t ioc; @@ -232,6 +251,24 @@ return (rc); } +int +smb_kmod_get_spool_doc(uint32_t *spool_num, char *username, + char *path, smb_inaddr_t *ipaddr) +{ + smb_ioc_spooldoc_t ioc; + int rc; + + bzero(&ioc, sizeof (ioc)); + rc = smb_kmod_ioctl(SMB_IOC_SPOOLDOC, &ioc.hdr, sizeof (ioc)); + if (rc == 0) { + *spool_num = ioc.spool_num; + (void) strlcpy(username, ioc.username, MAXNAMELEN); + (void) strlcpy(path, ioc.path, MAXPATHLEN); + *ipaddr = ioc.ipaddr; + } + return (rc); +} + /* * Initialization for an smb_kmod_enum request. If this call succeeds, * smb_kmod_enum_fini() must be called later to deallocate resources.
--- a/usr/src/uts/common/fs/smbsrv/smb_common_open.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_common_open.c Thu Jul 22 14:53:56 2010 -0700 @@ -43,6 +43,9 @@ extern uint32_t smb_is_executable(char *); static void smb_delete_new_object(smb_request_t *); static int smb_set_open_timestamps(smb_request_t *, smb_ofile_t *, boolean_t); +static void smb_open_oplock_break(smb_request_t *, smb_node_t *); +static boolean_t smb_open_attr_only(smb_arg_open_t *); +static boolean_t smb_open_overwrite(smb_arg_open_t *); /* * smb_access_generic_to_file @@ -204,7 +207,6 @@ } kmem_free(parg, sizeof (*parg)); - return (status); } @@ -232,10 +234,9 @@ * * The following rules apply when processing a file open request: * - * - Oplocks must be broken prior to share checking to prevent open - * starvation due to batch oplocks. Checking share reservations first - * could potentially result in unnecessary open failures due to - * open/close batching on the client. + * - Oplocks must be broken prior to share checking as the break may + * cause other clients to close the file, which would affect sharing + * checks. * * - Share checks must take place prior to access checks for correct * Windows semantics and to prevent unnecessary NFS delegation recalls. @@ -243,7 +244,6 @@ * - Oplocks must be acquired after open to ensure the correct * synchronization with NFS delegation and FEM installation. * - * * DOS readonly bit rules * * 1. The creator of a readonly file can write to/modify the size of the file @@ -315,6 +315,7 @@ int lookup_flags = SMB_FOLLOW_LINKS; uint32_t uniq_fid; smb_pathname_t *pn = &op->fqi.fq_path; + smb_server_t *sv = sr->sr_server; is_dir = (op->create_options & FILE_DIRECTORY_FILE) ? 1 : 0; @@ -341,7 +342,7 @@ if (sr->session->s_file_cnt >= SMB_SESSION_OFILE_MAX) { ASSERT(sr->uid_user); - cmn_err(CE_NOTE, "smbd[%s\\%s]: TOO_MANY_OPENED_FILES", + cmn_err(CE_NOTE, "smbsrv[%s\\%s]: TOO_MANY_OPENED_FILES", sr->uid_user->u_domain, sr->uid_user->u_name); smbsr_error(sr, NT_STATUS_TOO_MANY_OPENED_FILES, @@ -360,12 +361,21 @@ break; case STYPE_IPC: + + if ((rc = smb_threshold_enter(&sv->sv_opipe_ct)) != 0) { + status = RPC_NT_SERVER_TOO_BUSY; + smbsr_error(sr, status, 0, 0); + return (status); + } + /* * No further processing for IPC, we need to either * raise an exception or return success here. */ if ((status = smb_opipe_open(sr)) != NT_STATUS_SUCCESS) smbsr_error(sr, status, 0, 0); + + smb_threshold_exit(&sv->sv_opipe_ct, sv); return (status); default: @@ -558,8 +568,13 @@ } } - if (smb_oplock_conflict(node, sr->session, op)) - (void) smb_oplock_break(node, sr->session, B_FALSE); + /* + * Oplock break is done prior to sharing checks as the break + * may cause other clients to close the file which would + * affect the sharing checks. + */ + smb_node_inc_opening_count(node); + smb_open_oplock_break(sr, node); smb_node_wrlock(node); @@ -573,6 +588,7 @@ (!smb_sattr_check(op->fqi.fq_fattr.sa_dosattr, op->dattr))) { smb_node_unlock(node); + smb_node_dec_opening_count(node); smb_node_release(node); smb_node_release(dnode); smbsr_error(sr, NT_STATUS_ACCESS_DENIED, @@ -586,6 +602,7 @@ if (status == NT_STATUS_SHARING_VIOLATION) { smb_node_unlock(node); + smb_node_dec_opening_count(node); smb_node_release(node); smb_node_release(dnode); return (status); @@ -598,6 +615,7 @@ smb_fsop_unshrlock(sr->user_cr, node, uniq_fid); smb_node_unlock(node); + smb_node_dec_opening_count(node); smb_node_release(node); smb_node_release(dnode); @@ -619,6 +637,7 @@ if (smb_node_is_dir(node)) { smb_fsop_unshrlock(sr->user_cr, node, uniq_fid); smb_node_unlock(node); + smb_node_dec_opening_count(node); smb_node_release(node); smb_node_release(dnode); smbsr_error(sr, NT_STATUS_ACCESS_DENIED, @@ -641,6 +660,7 @@ if (rc != 0) { smb_fsop_unshrlock(sr->user_cr, node, uniq_fid); smb_node_unlock(node); + smb_node_dec_opening_count(node); smb_node_release(node); smb_node_release(dnode); smbsr_errno(sr, rc); @@ -657,6 +677,7 @@ smb_fsop_unshrlock(sr->user_cr, node, uniq_fid); smb_node_unlock(node); + smb_node_dec_opening_count(node); smb_node_release(node); smb_node_release(dnode); return (sr->smb_error.status); @@ -741,6 +762,7 @@ } node = op->fqi.fq_fnode; + smb_node_inc_opening_count(node); smb_node_wrlock(node); status = smb_fsop_shrlock(sr->user_cr, node, uniq_fid, @@ -748,6 +770,7 @@ if (status == NT_STATUS_SHARING_VIOLATION) { smb_node_unlock(node); + smb_node_dec_opening_count(node); smb_delete_new_object(sr); smb_node_release(node); smb_node_unlock(dnode); @@ -772,6 +795,7 @@ } node = op->fqi.fq_fnode; + smb_node_inc_opening_count(node); smb_node_wrlock(node); } @@ -833,6 +857,7 @@ if (created) smb_delete_new_object(sr); smb_node_unlock(node); + smb_node_dec_opening_count(node); smb_node_release(node); if (created) smb_node_unlock(dnode); @@ -861,12 +886,8 @@ sr->smb_fid = of->f_fid; sr->fid_ofile = of; - smb_node_unlock(node); - if (created) - smb_node_unlock(dnode); - if (smb_node_is_file(node)) { - smb_oplock_acquire(node, of, op); + smb_oplock_acquire(sr, node, of); op->dsize = op->fqi.fq_fattr.sa_vattr.va_size; } else { /* directory or symlink */ @@ -874,6 +895,12 @@ op->dsize = 0; } + smb_node_dec_opening_count(node); + + smb_node_unlock(node); + if (created) + smb_node_unlock(dnode); + smb_node_release(node); smb_node_release(dnode); @@ -881,6 +908,63 @@ } /* + * smb_open_oplock_break + * + * If the node has an ofile opened with share access none, + * (smb_node_share_check = FALSE) only break BATCH oplock. + * Otherwise: + * If overwriting, break to SMB_OPLOCK_NONE, else + * If opening for anything other than attribute access, + * break oplock to LEVEL_II. + */ +static void +smb_open_oplock_break(smb_request_t *sr, smb_node_t *node) +{ + smb_arg_open_t *op = &sr->sr_open; + uint32_t flags = 0; + + if (!smb_node_share_check(node)) + flags |= SMB_OPLOCK_BREAK_BATCH; + + if (smb_open_overwrite(op)) { + flags |= SMB_OPLOCK_BREAK_TO_NONE; + (void) smb_oplock_break(sr, node, flags); + } else if (!smb_open_attr_only(op)) { + flags |= SMB_OPLOCK_BREAK_TO_LEVEL_II; + (void) smb_oplock_break(sr, node, flags); + } +} + +/* + * smb_open_attr_only + * + * Determine if file is being opened for attribute access only. + * This is used to determine whether it is necessary to break + * existing oplocks on the file. + */ +static boolean_t +smb_open_attr_only(smb_arg_open_t *op) +{ + if (((op->desired_access & ~(FILE_READ_ATTRIBUTES | + FILE_WRITE_ATTRIBUTES | SYNCHRONIZE)) == 0) && + (op->create_disposition != FILE_SUPERSEDE) && + (op->create_disposition != FILE_OVERWRITE)) { + return (B_TRUE); + } + return (B_FALSE); +} + +static boolean_t +smb_open_overwrite(smb_arg_open_t *op) +{ + if ((op->create_disposition == FILE_SUPERSEDE) || + (op->create_disposition == FILE_OVERWRITE_IF) || + (op->create_disposition == FILE_OVERWRITE)) { + return (B_TRUE); + } + return (B_FALSE); +} +/* * smb_set_open_timestamps * * Last write time:
--- a/usr/src/uts/common/fs/smbsrv/smb_create.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_create.c Thu Jul 22 14:53:56 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <smbsrv/smb_kproto.h> @@ -199,6 +198,7 @@ } else { op->op_oplock_level = SMB_OPLOCK_NONE; } + op->op_oplock_levelII = B_FALSE; status = smb_common_open(sr);
--- a/usr/src/uts/common/fs/smbsrv/smb_delete.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_delete.c Thu Jul 22 14:53:56 2010 -0700 @@ -478,7 +478,8 @@ fqi = &sr->arg.dirop.fqi; node = fqi->fq_fnode; - (void) smb_oplock_break(node, sr->session, B_FALSE); + (void) smb_oplock_break(sr, node, + SMB_OPLOCK_BREAK_TO_LEVEL_II | SMB_OPLOCK_BREAK_BATCH); smb_node_start_crit(node, RW_READER);
--- a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c Thu Jul 22 14:53:56 2010 -0700 @@ -140,9 +140,13 @@ #include <sys/sdt.h> #include <sys/spl.h> +static int smb_legacy_dispatch_stats_update(kstat_t *, int); static int is_andx_com(unsigned char); static int smbsr_check_result(struct smb_request *, int, int); +static kstat_t *smb_legacy_dispatch_ksp = NULL; +static kmutex_t smb_legacy_dispatch_ksmtx; + static smb_disp_entry_t smb_disp_table[SMB_COM_NUM] = { { "SmbCreateDirectory", SMB_SDT_OPS(create_directory), /* 0x00 000 */ 0x00, PC_NETWORK_PROGRAM_1_0 }, @@ -1180,13 +1184,44 @@ void smb_dispatch_stats_init(smb_kstat_req_t *ksr) { - int i; + kstat_named_t *ksn; + int ks_ndata; + int i; for (i = 0; i < SMB_COM_NUM; i++, ksr++) { smb_latency_init(&smb_disp_table[i].sdt_lat); (void) strlcpy(ksr->kr_name, smb_disp_table[i].sdt_name, sizeof (ksr->kr_name)); } + /* Legacy Statistics */ + for (i = 0, ks_ndata = 0; i < SMB_COM_NUM; i++) { + if (smb_disp_table[i].sdt_function != smb_com_invalid) + ks_ndata++; + } + + smb_legacy_dispatch_ksp = kstat_create(SMBSRV_KSTAT_MODULE, 0, + SMBSRV_KSTAT_NAME_CMDS, SMBSRV_KSTAT_CLASS, + KSTAT_TYPE_NAMED, ks_ndata, 0); + + if (smb_legacy_dispatch_ksp != NULL) { + ksn = smb_legacy_dispatch_ksp->ks_data; + + for (i = 0, ks_ndata = 0; i < SMB_COM_NUM; i++) { + if (smb_disp_table[i].sdt_function != smb_com_invalid) { + (void) strlcpy(ksn->name, + smb_disp_table[i].sdt_name, + sizeof (ksn->name)); + ksn->data_type = KSTAT_DATA_UINT64; + ++ksn; + } + } + mutex_init(&smb_legacy_dispatch_ksmtx, NULL, + MUTEX_DEFAULT, NULL); + smb_legacy_dispatch_ksp->ks_update = + smb_legacy_dispatch_stats_update; + smb_legacy_dispatch_ksp->ks_lock = &smb_legacy_dispatch_ksmtx; + kstat_install(smb_legacy_dispatch_ksp); + } } /* @@ -1199,6 +1234,12 @@ { int i; + if (smb_legacy_dispatch_ksp != NULL) { + kstat_delete(smb_legacy_dispatch_ksp); + mutex_destroy(&smb_legacy_dispatch_ksmtx); + smb_legacy_dispatch_ksp = NULL; + } + for (i = 0; i < SMB_COM_NUM; i++) smb_latency_destroy(&smb_disp_table[i].sdt_lat); } @@ -1232,3 +1273,37 @@ } } } + +/* + * smb_legacy_dispatch_stats_update + * + * This callback function updates the smb_legacy_dispatch_kstat_data when kstat + * command is invoked. + */ +static int +smb_legacy_dispatch_stats_update(kstat_t *ksp, int rw) +{ + kstat_named_t *ksn; + int i; + + ASSERT(MUTEX_HELD(ksp->ks_lock)); + + switch (rw) { + case KSTAT_WRITE: + return (EACCES); + + case KSTAT_READ: + ksn = ksp->ks_data; + for (i = 0; i < SMB_COM_NUM; i++) { + if (smb_disp_table[i].sdt_function != smb_com_invalid) { + ksn->value.ui64 = + smb_disp_table[i].sdt_lat.ly_a_nreq; + ++ksn; + } + } + return (0); + + default: + return (EIO); + } +}
--- a/usr/src/uts/common/fs/smbsrv/smb_fem.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_fem.c Thu Jul 22 14:53:56 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <smbsrv/smb_kproto.h> @@ -76,7 +75,7 @@ */ int smb_fem_oplock_install(smb_node_t *); -void smb_fem_oplock_uninstall(smb_node_t *); +int smb_fem_oplock_uninstall(smb_node_t *); static int smb_fem_oplock_open(femarg_t *, int, cred_t *, struct caller_context *); @@ -89,8 +88,6 @@ static int smb_fem_oplock_rwlock(femarg_t *, int, caller_context_t *); static int smb_fem_oplock_space(femarg_t *, int, flock64_t *, int, offset_t, cred_t *, caller_context_t *); -static int smb_fem_oplock_setsecattr(femarg_t *, vsecattr_t *, int, cred_t *, - caller_context_t *); static int smb_fem_oplock_vnevent(femarg_t *, vnevent_t, vnode_t *, char *, caller_context_t *); @@ -101,12 +98,11 @@ VOPNAME_SETATTR, { .femop_setattr = smb_fem_oplock_setattr }, VOPNAME_RWLOCK, { .femop_rwlock = smb_fem_oplock_rwlock }, VOPNAME_SPACE, { .femop_space = smb_fem_oplock_space }, - VOPNAME_SETSECATTR, { .femop_setsecattr = smb_fem_oplock_setsecattr }, VOPNAME_VNEVENT, { .femop_vnevent = smb_fem_oplock_vnevent }, NULL, NULL }; -static int smb_fem_oplock_break(femarg_t *, caller_context_t *); +static int smb_fem_oplock_break(femarg_t *, caller_context_t *, uint32_t); /* * smb_fem_init @@ -179,10 +175,10 @@ (fem_func_t)smb_node_ref, (fem_func_t)smb_node_release)); } -void +int smb_fem_oplock_uninstall(smb_node_t *node) { - (void) fem_uninstall(node->vp, smb_oplock_ops, (void *)node); + return (fem_uninstall(node->vp, smb_oplock_ops, (void *)node)); } /* @@ -404,9 +400,15 @@ cred_t *cr, caller_context_t *ct) { - int rc; + int rc; + uint32_t flags; - rc = smb_fem_oplock_break(arg, ct); + if (mode & (FWRITE|FTRUNC)) + flags = SMB_OPLOCK_BREAK_TO_NONE; + else + flags = SMB_OPLOCK_BREAK_TO_LEVEL_II; + + rc = smb_fem_oplock_break(arg, ct, flags); if (rc == 0) rc = vnext_open(arg, mode, cr, ct); return (rc); @@ -427,7 +429,7 @@ { int rc; - rc = smb_fem_oplock_break(arg, ct); + rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_LEVEL_II); if (rc == 0) rc = vnext_read(arg, uiop, ioflag, cr, ct); return (rc); @@ -448,7 +450,7 @@ { int rc; - rc = smb_fem_oplock_break(arg, ct); + rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE); if (rc == 0) rc = vnext_write(arg, uiop, ioflag, cr, ct); return (rc); @@ -462,9 +464,10 @@ cred_t *cr, caller_context_t *ct) { - int rc; + int rc = 0; - rc = smb_fem_oplock_break(arg, ct); + if (vap->va_mask & AT_SIZE) + rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE); if (rc == 0) rc = vnext_setattr(arg, vap, flags, cr, ct); return (rc); @@ -476,14 +479,19 @@ int write_lock, caller_context_t *ct) { - if (write_lock) { - int rc; + int rc; + uint32_t flags; - rc = smb_fem_oplock_break(arg, ct); - if (rc != 0) - return (rc); - } - return (vnext_rwlock(arg, write_lock, ct)); + if (write_lock) + flags = SMB_OPLOCK_BREAK_TO_NONE; + else + flags = SMB_OPLOCK_BREAK_TO_LEVEL_II; + + rc = smb_fem_oplock_break(arg, ct, flags); + if (rc == 0) + rc = vnext_rwlock(arg, write_lock, ct); + + return (rc); } static int @@ -498,28 +506,12 @@ { int rc; - rc = smb_fem_oplock_break(arg, ct); + rc = smb_fem_oplock_break(arg, ct, SMB_OPLOCK_BREAK_TO_NONE); if (rc == 0) rc = vnext_space(arg, cmd, bfp, flag, offset, cr, ct); return (rc); } -static int -smb_fem_oplock_setsecattr( - femarg_t *arg, - vsecattr_t *vsap, - int flag, - cred_t *cr, - caller_context_t *ct) -{ - int rc; - - rc = smb_fem_oplock_break(arg, ct); - if (rc == 0) - rc = vnext_setsecattr(arg, vsap, flag, cr, ct); - return (rc); -} - /* * smb_fem_oplock_vnevent() * @@ -542,25 +534,32 @@ char *name, caller_context_t *ct) { - int rc; + int rc; + uint32_t flags; switch (vnevent) { case VE_REMOVE: case VE_RENAME_DEST: + flags = SMB_OPLOCK_BREAK_TO_NONE | SMB_OPLOCK_BREAK_BATCH; + rc = smb_fem_oplock_break(arg, ct, flags); + break; case VE_RENAME_SRC: - rc = smb_fem_oplock_break(arg, ct); - if (rc != 0) - return (rc); + flags = SMB_OPLOCK_BREAK_TO_LEVEL_II | SMB_OPLOCK_BREAK_BATCH; + rc = smb_fem_oplock_break(arg, ct, flags); break; - default: + rc = 0; break; } + + if (rc != 0) + return (rc); + return (vnext_vnevent(arg, vnevent, dvp, name, ct)); } static int -smb_fem_oplock_break(femarg_t *arg, caller_context_t *ct) +smb_fem_oplock_break(femarg_t *arg, caller_context_t *ct, uint32_t flags) { smb_node_t *node; int rc; @@ -568,22 +567,17 @@ node = (smb_node_t *)((arg)->fa_fnode->fn_available); SMB_NODE_VALID(node); - if (ct == NULL) { - (void) smb_oplock_break(node, NULL, B_FALSE); - return (0); - } - - if (ct->cc_caller_id == smb_ct.cc_caller_id) + if (ct && (ct->cc_caller_id == smb_ct.cc_caller_id)) return (0); - if (ct->cc_flags & CC_DONTBLOCK) { - if (smb_oplock_break(node, NULL, B_TRUE)) - return (0); - ct->cc_flags |= CC_WOULDBLOCK; - rc = EAGAIN; + if (ct && (ct->cc_flags & CC_DONTBLOCK)) { + flags |= SMB_OPLOCK_BREAK_NOWAIT; + rc = smb_oplock_break(NULL, node, flags); + if (rc == EAGAIN) + ct->cc_flags |= CC_WOULDBLOCK; } else { - (void) smb_oplock_break(node, NULL, B_FALSE); - rc = 0; + rc = smb_oplock_break(NULL, node, flags); } + return (rc); }
--- a/usr/src/uts/common/fs/smbsrv/smb_find.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_find.c Thu Jul 22 14:53:56 2010 -0700 @@ -332,6 +332,8 @@ break; if (*fileinfo.fi_shortname == '\0') { + if (smb_needs_mangled(fileinfo.fi_name)) + continue; (void) strlcpy(fileinfo.fi_shortname, fileinfo.fi_name, SMB_SHORTNAMELEN - 1); if (to_upper) @@ -476,6 +478,8 @@ break; if (*fileinfo.fi_shortname == '\0') { + if (smb_needs_mangled(fileinfo.fi_name)) + continue; (void) strlcpy(fileinfo.fi_shortname, fileinfo.fi_name, SMB_SHORTNAMELEN - 1); } @@ -660,6 +664,8 @@ break; if (*fileinfo.fi_shortname == '\0') { + if (smb_needs_mangled(fileinfo.fi_name)) + continue; (void) strlcpy(fileinfo.fi_shortname, fileinfo.fi_name, SMB_SHORTNAMELEN - 1); }
--- a/usr/src/uts/common/fs/smbsrv/smb_fsops.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_fsops.c Thu Jul 22 14:53:56 2010 -0700 @@ -33,11 +33,6 @@ extern caller_context_t smb_ct; -extern int smb_fem_oplock_install(smb_node_t *); -extern void smb_fem_oplock_uninstall(smb_node_t *); - -extern int smb_vop_other_opens(vnode_t *, int); - static int smb_fsop_create_stream(smb_request_t *, cred_t *, smb_node_t *, char *, char *, int, smb_attr_t *, smb_node_t **); @@ -120,31 +115,6 @@ smb_vop_close(node->vp, mode, cred); } -int -smb_fsop_oplock_install(smb_node_t *node, int mode) -{ - int rc; - - if (smb_vop_other_opens(node->vp, mode)) - return (EMFILE); - - if ((rc = smb_fem_oplock_install(node))) - return (rc); - - if (smb_vop_other_opens(node->vp, mode)) { - (void) smb_fem_oplock_uninstall(node); - return (EMFILE); - } - - return (0); -} - -void -smb_fsop_oplock_uninstall(smb_node_t *node) -{ - smb_fem_oplock_uninstall(node); -} - static int smb_fsop_create_with_sd(smb_request_t *sr, cred_t *cr, smb_node_t *dnode, char *name, @@ -354,7 +324,7 @@ /* Not a named stream */ - if (smb_maybe_mangled(name)) { + if (SMB_TREE_SUPPORTS_SHORTNAMES(sr) && smb_maybe_mangled(name)) { longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); rc = smb_unmangle(dnode, name, longname, MAXNAMELEN, flags); kmem_free(longname, MAXNAMELEN); @@ -584,7 +554,7 @@ if (SMB_TREE_SUPPORTS_ABE(sr)) flags |= SMB_ABE; - if (smb_maybe_mangled(name)) { + if (SMB_TREE_SUPPORTS_SHORTNAMES(sr) && smb_maybe_mangled(name)) { longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); rc = smb_unmangle(dnode, name, longname, MAXNAMELEN, flags); kmem_free(longname, MAXNAMELEN); @@ -746,7 +716,8 @@ rc = smb_vop_remove(dnode->vp, name, flags, cr); if (rc == ENOENT) { - if (!smb_maybe_mangled(name)) { + if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) || + !smb_maybe_mangled(name)) { kmem_free(fname, MAXNAMELEN); kmem_free(sname, MAXNAMELEN); return (rc); @@ -889,8 +860,10 @@ rc = smb_vop_rmdir(dnode->vp, name, flags, cr); if (rc == ENOENT) { - if (!smb_maybe_mangled(name)) + if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) || + !smb_maybe_mangled(name)) { return (rc); + } longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); @@ -1031,7 +1004,7 @@ if (SMB_TREE_SUPPORTS_ABE(sr)) flags |= SMB_ABE; - if (smb_maybe_mangled(to_name)) { + if (SMB_TREE_SUPPORTS_SHORTNAMES(sr) && smb_maybe_mangled(to_name)) { longname = kmem_alloc(MAXNAMELEN, KM_SLEEP); rc = smb_unmangle(to_dnode, to_name, longname, MAXNAMELEN, flags); @@ -1492,8 +1465,9 @@ ASSERT(snode->n_magic == SMB_NODE_MAGIC); ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); + /* Requests for no access should be denied. */ if (faccess == 0) - return (NT_STATUS_SUCCESS); + return (NT_STATUS_ACCESS_DENIED); if (SMB_TREE_IS_READONLY(sr)) { if (faccess & (FILE_WRITE_DATA|FILE_APPEND_DATA| @@ -1550,13 +1524,10 @@ smb_node_is_symlink(snode)) acl_check = B_FALSE; - /* - * Use the most restrictive parts of both faccess and the - * share access. An AND of the two value masks gives us that - * since we've already converted to a mask of what we "can" - * do. - */ - faccess &= sr->tid_tree->t_access; + /* Deny access based on the share access mask */ + + if ((faccess & ~sr->tid_tree->t_access) != 0) + return (NT_STATUS_ACCESS_DENIED); if (acl_check) { dir_vp = (snode->n_dnode) ? snode->n_dnode->vp : NULL; @@ -1779,7 +1750,8 @@ &ret_flags, root_node ? root_node->vp : NULL, &attr, cr); if (rc != 0) { - if (!smb_maybe_mangled(name)) { + if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) || + !smb_maybe_mangled(name)) { kmem_free(od_name, MAXNAMELEN); return (rc); }
--- a/usr/src/uts/common/fs/smbsrv/smb_init.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_init.c Thu Jul 22 14:53:56 2010 -0700 @@ -54,12 +54,18 @@ * with Windows NT4.0. Previous experiments with NT4.0 resulted in directory * listing problems so this buffer size is configurable based on the end-user * environment. When in doubt use 37KB. + * + * smb_raw_mode: read_raw and write_raw supported (1) or NOT supported (0). */ int smb_maxbufsize = SMB_NT_MAXBUF; +int smb_oplock_levelII = 1; int smb_oplock_timeout = OPLOCK_STD_TIMEOUT; +int smb_oplock_min_timeout = OPLOCK_MIN_TIMEOUT; int smb_flush_required = 1; int smb_dirsymlink_enable = 1; int smb_sign_debug = 0; +int smb_raw_mode = 1; +int smb_shortnames = 1; uint_t smb_audit_flags = #ifdef DEBUG SMB_AUDIT_NODE; @@ -68,6 +74,25 @@ #endif /* + * Maximum number of simultaneous authentication, share mapping, pipe open + * requests to be processed. + */ +int smb_ssetup_threshold = 256; +int smb_tcon_threshold = 1024; +int smb_opipe_threshold = 1024; + +/* + * Number of milliseconds that a request will be stalled if it comes in after + * the maximum number of inflight operations are being proccessed. + */ +int smb_ssetup_timeout = (30 * 1000); +int smb_tcon_timeout = (30 * 1000); +int smb_opipe_timeout = (30 * 1000); + +int smb_threshold_debug = 0; + + +/* * ***************************************************************************** * ********************** Static Variables / Module Linkage ******************** * ***************************************************************************** @@ -257,6 +282,10 @@ case SMB_IOC_UNSHARE: rc = smb_kshare_unexport_list(&ioc->ioc_share); break; + case SMB_IOC_SHAREINFO: + rc = smb_kshare_info(&ioc->ioc_shareinfo); + copyout = B_TRUE; + break; case SMB_IOC_NUMOPEN: rc = smb_server_numopen(&ioc->ioc_opennum); copyout = B_TRUE; @@ -271,6 +300,10 @@ case SMB_IOC_FILE_CLOSE: rc = smb_server_file_close(&ioc->ioc_fileid); break; + case SMB_IOC_SPOOLDOC: + rc = smb_server_spooldoc(&ioc->ioc_spooldoc); + copyout = B_TRUE; + break; default: rc = ENOTTY; break;
--- a/usr/src/uts/common/fs/smbsrv/smb_kdoor.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_kdoor.c Thu Jul 22 14:53:56 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <sys/types.h> @@ -133,7 +132,7 @@ if (rsp_data != NULL && rsp_xdr != NULL) da.da_flags = SMB_DF_ASYNC; - if ((da.da_event = smb_event_create()) == NULL) + if ((da.da_event = smb_event_create(SMB_EVENT_TIMEOUT)) == NULL) return (-1); mutex_enter(&smb_kdoor_mutex);
--- a/usr/src/uts/common/fs/smbsrv/smb_kshare.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_kshare.c Thu Jul 22 14:53:56 2010 -0700 @@ -388,7 +388,6 @@ } nvlist_free(shrlist); - return (0); } @@ -448,6 +447,17 @@ } /* + * Get properties (currently only shortname enablement) + * of specified share. + */ +int +smb_kshare_info(smb_ioc_shareinfo_t *ioc) +{ + ioc->shortnames = smb_shortnames; + return (0); +} + +/* * This function builds a response for a NetShareEnum RAP request. * List of shares is scanned twice. In the first round the total number * of shares which their OEM name is shorter than 13 chars (esi->es_ntotal) @@ -589,7 +599,6 @@ key.shr_name = (char *)shrname; shr = smb_avl_lookup(&smb_export.e_share_avl, &key); - return (shr); } @@ -605,7 +614,6 @@ smb_avl_release(&smb_export.e_share_avl, shr); } - /* * Add the given share in the specified server. * If the share is a disk share, smb_vfs_hold() is @@ -795,6 +803,13 @@ return (NULL); } + rc = nvlist_lookup_uint32(smb, "type", &tmp.shr_type); + if (rc != 0) { + cmn_err(CE_WARN, "kshare[%s]: failed getting the share type" + " (%d)", tmp.shr_name, rc); + return (NULL); + } + (void) nvlist_lookup_string(smb, SHOPT_AD_CONTAINER, &tmp.shr_container); (void) nvlist_lookup_string(smb, SHOPT_NONE, &tmp.shr_access_none); @@ -815,7 +830,7 @@ rc = nvlist_lookup_uint32(smb, "uid", &tmp.shr_uid); rc |= nvlist_lookup_uint32(smb, "gid", &tmp.shr_gid); if (rc != 0) { - cmn_err(CE_WARN, "kshare: failed looking up UID/GID" + cmn_err(CE_WARN, "kshare: failed looking up uid/gid" " (%d)", rc); return (NULL); } @@ -846,7 +861,7 @@ shr->shr_oemname = smb_kshare_oemname(shr->shr_name); shr->shr_flags = tmp.shr_flags | smb_kshare_is_admin(shr->shr_name); - shr->shr_type = STYPE_DISKTREE | smb_kshare_is_special(shr->shr_name); + shr->shr_type = tmp.shr_type | smb_kshare_is_special(shr->shr_name); shr->shr_uid = tmp.shr_uid; shr->shr_gid = tmp.shr_gid;
--- a/usr/src/uts/common/fs/smbsrv/smb_kutil.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_kutil.c Thu Jul 22 14:53:56 2010 -0700 @@ -501,6 +501,7 @@ ll->ll_count = 0; ll->ll_wrop = 0; ll->ll_deleteq_count = 0; + ll->ll_flushing = B_FALSE; } /* @@ -567,6 +568,11 @@ smb_dtor_t *dtor; mutex_enter(&ll->ll_mutex); + if (ll->ll_flushing) { + mutex_exit(&ll->ll_mutex); + return; + } + ll->ll_flushing = B_TRUE; dtor = list_head(&ll->ll_deleteq); while (dtor != NULL) { @@ -583,6 +589,7 @@ mutex_enter(&ll->ll_mutex); dtor = list_head(&ll->ll_deleteq); } + ll->ll_flushing = B_FALSE; mutex_exit(&ll->ll_mutex); } @@ -2347,3 +2354,111 @@ scalehrtime(&kd->ku_wlentime); scalehrtime(&kd->ku_wtime); } + +void +smb_threshold_init(smb_cmd_threshold_t *ct, char *cmd, int threshold, + int timeout) +{ + bzero(ct, sizeof (smb_cmd_threshold_t)); + mutex_init(&ct->ct_mutex, NULL, MUTEX_DEFAULT, NULL); + ct->ct_cmd = cmd; + ct->ct_threshold = threshold; + ct->ct_event = smb_event_create(timeout); + ct->ct_event_id = smb_event_txid(ct->ct_event); + + if (smb_threshold_debug) { + cmn_err(CE_NOTE, "smb_threshold_init[%s]: threshold (%d), " + "timeout (%d)", cmd, threshold, timeout); + } +} + +/* + * This function must be called prior to SMB_SERVER_STATE_STOPPING state + * so that ct_event can be successfully removed from the event list. + * It should not be called when the server mutex is held or when the + * server is removed from the server list. + */ +void +smb_threshold_fini(smb_cmd_threshold_t *ct) +{ + smb_event_destroy(ct->ct_event); + mutex_destroy(&ct->ct_mutex); + bzero(ct, sizeof (smb_cmd_threshold_t)); +} + +/* + * This threshold mechanism can be used to limit the number of simultaneous + * requests, which serves to limit the stress that can be applied to the + * service and also allows the service to respond to requests before the + * client times out and reports that the server is not responding, + * + * If the number of requests exceeds the threshold, new requests will be + * stalled until the number drops back to the threshold. Stalled requests + * will be notified as appropriate, in which case 0 will be returned. + * If the timeout expires before the request is notified, a non-zero errno + * value will be returned. + * + * To avoid a flood of messages, the message rate is throttled as well. + */ +int +smb_threshold_enter(smb_cmd_threshold_t *ct) +{ + int rc; + + mutex_enter(&ct->ct_mutex); + if (ct->ct_active_cnt >= ct->ct_threshold && ct->ct_event != NULL) { + atomic_inc_32(&ct->ct_blocked_cnt); + + if (smb_threshold_debug) { + cmn_err(CE_NOTE, "smb_threshold_enter[%s]: blocked " + "(blocked ops: %u, inflight ops: %u)", + ct->ct_cmd, ct->ct_blocked_cnt, ct->ct_active_cnt); + } + + mutex_exit(&ct->ct_mutex); + + if ((rc = smb_event_wait(ct->ct_event)) != 0) { + if (rc == ECANCELED) + return (rc); + + mutex_enter(&ct->ct_mutex); + if (ct->ct_active_cnt >= ct->ct_threshold) { + + if ((ct->ct_error_cnt % + SMB_THRESHOLD_REPORT_THROTTLE) == 0) { + cmn_err(CE_NOTE, "%s: server busy: " + "threshold %d exceeded)", + ct->ct_cmd, ct->ct_threshold); + } + + atomic_inc_32(&ct->ct_error_cnt); + mutex_exit(&ct->ct_mutex); + return (rc); + } + + mutex_exit(&ct->ct_mutex); + + } + + mutex_enter(&ct->ct_mutex); + atomic_dec_32(&ct->ct_blocked_cnt); + if (smb_threshold_debug) { + cmn_err(CE_NOTE, "smb_threshold_enter[%s]: resumed " + "(blocked ops: %u, inflight ops: %u)", ct->ct_cmd, + ct->ct_blocked_cnt, ct->ct_active_cnt); + } + } + + atomic_inc_32(&ct->ct_active_cnt); + mutex_exit(&ct->ct_mutex); + return (0); +} + +void +smb_threshold_exit(smb_cmd_threshold_t *ct, smb_server_t *sv) +{ + mutex_enter(&ct->ct_mutex); + atomic_dec_32(&ct->ct_active_cnt); + mutex_exit(&ct->ct_mutex); + smb_event_notify(sv, ct->ct_event_id); +}
--- a/usr/src/uts/common/fs/smbsrv/smb_lock.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_lock.c Thu Jul 22 14:53:56 2010 -0700 @@ -120,10 +120,13 @@ /* * smb_lock_range * - * checks for integrity of file lock operation for the given range of file data. + * Checks for integrity of file lock operation for the given range of file data. * This is performed by applying lock rules with all the elements of the node * lock list. * + * Break shared (levelII) oplocks. If there is an exclusive oplock, it is + * owned by this ofile and therefore should not be broken. + * * The function returns with new lock added if lock request is non-conflicting * with existing range lock for the file. Otherwise smb request is filed * without returning. @@ -241,6 +244,9 @@ } smb_llist_exit(&node->n_lock_list); + if (result == NT_STATUS_SUCCESS) + smb_oplock_break_levelII(node); + return (result); }
--- a/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_locking_andx.c Thu Jul 22 14:53:56 2010 -0700 @@ -240,6 +240,8 @@ DWORD result; int rc; uint32_t ltype; + smb_ofile_t *ofile; + uint8_t brk; rc = smbsr_decode_vwv(sr, "4.wbblww", &sr->smb_fid, &lock_type, &oplock_level, &timeout, &unlock_num, &lock_num); @@ -251,6 +253,7 @@ smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); return (SDRC_ERROR); } + ofile = sr->fid_ofile; if (lock_type & LOCKING_ANDX_SHARED_LOCK) ltype = SMB_LOCK_TYPE_READONLY; @@ -260,19 +263,11 @@ pid = sr->smb_pid; /* Save the original pid */ if (lock_type & LOCKING_ANDX_OPLOCK_RELEASE) { - smb_oplock_release(sr->fid_ofile->f_node, sr->fid_ofile); - /* - * According to the protocol: - * - * If the client sends an SMB_LOCKING_ANDX request with the - * LOCKING_ANDX_OPLOCK_RELEASE flag set - * and NumberOfLocks is zero, - * the server does not send a response. - * - * I'm not sure if it's going to break anything if I change - * it according to the protocol. So, I leave it unchanged - * for now. - */ + if (oplock_level == 0) + brk = SMB_OPLOCK_BREAK_TO_NONE; + else + brk = SMB_OPLOCK_BREAK_TO_LEVEL_II; + smb_oplock_ack(ofile->f_node, ofile, brk); if (unlock_num == 0 && lock_num == 0) return (SDRC_NO_REPLY); }
--- a/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c Thu Jul 22 14:53:56 2010 -0700 @@ -55,41 +55,10 @@ #define isinvalid(c) (strchr(invalid_dos_chars, c) || (c & 0x80)) -static boolean_t smb_is_reserved_dos_name(const char *name); static int smb_generate_mangle(uint64_t, char *, size_t); static char smb_mangle_char(char); /* - * smb_match_name - * - * Don't match reserved dos filenames. - * Check name to see if it matches pattern. - * Generate the shortname (even if !smb_needs_mangled()) since names may - * be mangled to address case conflicts) and check if shortname matches - * pattern. - * - * Returns: B_TRUE - if there is a match - * B_FALSE - otherwise - */ -boolean_t -smb_match_name(ino64_t fid, char *name, char *pattern) -{ - char shortname[SMB_SHORTNAMELEN]; - - if (smb_is_reserved_dos_name(name)) - return (B_FALSE); - - if (smb_match_ci(pattern, name)) - return (B_TRUE); - - smb_mangle(name, fid, shortname, SMB_SHORTNAMELEN); - if (smb_match_ci(pattern, shortname)) - return (B_TRUE); - - return (B_FALSE); -} - -/* * Return true if name contains characters that are invalid in a file * name or it is a reserved DOS device name. Otherwise, returns false. * @@ -117,7 +86,7 @@ * The device name should not be followed immediately by an extension, * for example, NUL.txt. */ -static boolean_t +boolean_t smb_is_reserved_dos_name(const char *name) { static char *cnames[] = { "CLOCK$", "COM1", "COM2", "COM3", "COM4",
--- a/usr/src/uts/common/fs/smbsrv/smb_negotiate.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_negotiate.c Thu Jul 22 14:53:56 2010 -0700 @@ -285,6 +285,7 @@ { smb_arg_negotiate_t *negprot = sr->sr_negprot; uint16_t secmode; + uint16_t rawmode = 0; uint32_t sesskey; char ipaddr_buf[INET6_ADDRSTRLEN]; char *nbdomain; @@ -320,7 +321,6 @@ | CAP_NT_SMBS | CAP_STATUS32 | CAP_NT_FIND - | CAP_RAW_MODE | CAP_LEVEL_II_OPLOCKS | CAP_LOCK_AND_READ | CAP_RPC_REMOTE_APIS @@ -328,6 +328,11 @@ | CAP_LARGE_WRITEX | CAP_DFS; + if (smb_raw_mode) { + negprot->ni_capabilities |= CAP_RAW_MODE; + rawmode = 3; + } + if (smb_cap_passthru) negprot->ni_capabilities |= CAP_INFOLEVEL_PASSTHRU; else @@ -366,7 +371,7 @@ SMB_DOS_MAXBUF, /* max buffer size */ 1, /* max MPX */ 1, /* max VCs */ - 3, /* raw mode (s/b 3) */ + rawmode, /* read/write raw (s/b 3) */ sesskey, /* session key */ negprot->ni_servertime.tv_sec, /* server date/time */ negprot->ni_tzcorrection, @@ -391,7 +396,7 @@ SMB_DOS_MAXBUF, /* max buffer size */ 1, /* max MPX */ 1, /* max VCs */ - 3, /* raw mode (s/b 3) */ + rawmode, /* read/write raw (s/b 3) */ sesskey, /* session key */ negprot->ni_servertime.tv_sec, /* server date/time */ negprot->ni_tzcorrection,
--- a/usr/src/uts/common/fs/smbsrv/smb_node.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_node.c Thu Jul 22 14:53:56 2010 -0700 @@ -31,20 +31,11 @@ * | T0 * | * v - * +----------------------------+ T1 - * | SMB_NODE_STATE_AVAILABLE |--------------------+ - * +----------------------------+ | - * | ^ | - * | | v - * | | T2 +-------------------------------+ - * | |<---------| SMB_NODE_STATE_OPLOCK_GRANTED | - * | | +-------------------------------+ - * | T5 | | - * | | | T3 - * | | v - * | | T4 +--------------------------------+ - * | +----------| SMB_NODE_STATE_OPLOCK_BREAKING | - * | +--------------------------------+ + * +----------------------------+ + * | SMB_NODE_STATE_AVAILABLE | + * +----------------------------+ + * | + * | T1 * | * v * +-----------------------------+ @@ -52,7 +43,7 @@ * +-----------------------------+ * | * | - * | T6 + * | T2 * | * +----------> Deletion/Free * @@ -64,42 +55,11 @@ * * Transition T1 * - * This transition occurs smb_oplock_acquire() during an OPEN. - * - * Transition T2 - * - * This transition occurs in smb_oplock_release(). The events triggering - * it are: - * - * - LockingAndX sent by the client that was granted the oplock. - * - Closing of the file. - * - * Transition T3 - * - * This transition occurs in smb_oplock_break(). The events triggering - * it are: - * - * - Another client wants to open the file. - * - A client is trying to delete the file. - * - A client is trying to rename the file. - * - A client is trying to set/modify the file attributes. - * - * Transition T4 - * - * This transition occurs in smb_oplock_release or smb_oplock_break(). The - * events triggering it are: - * - * - The client that was granting the oplock releases it (close or - * LockingAndx). - * - The time alloted to release the oplock expired. - * - * Transition T5 - * * This transition occurs in smb_node_release(). If the reference count * drops to zero the state is moved to SMB_NODE_STATE_DESTROYING and no more * reference count will be given out for that node. * - * Transition T6 + * Transition T2 * * This transition occurs in smb_node_release(). The structure is deleted. * @@ -332,8 +292,6 @@ DTRACE_PROBE1(smb_node_lookup_hit, smb_node_t *, node); switch (node->n_state) { - case SMB_NODE_STATE_OPLOCK_GRANTED: - case SMB_NODE_STATE_OPLOCK_BREAKING: case SMB_NODE_STATE_AVAILABLE: /* The node was found. */ node->n_refcnt++; @@ -457,8 +415,6 @@ mutex_enter(&node->n_mutex); switch (node->n_state) { case SMB_NODE_STATE_AVAILABLE: - case SMB_NODE_STATE_OPLOCK_GRANTED: - case SMB_NODE_STATE_OPLOCK_BREAKING: node->n_refcnt++; ASSERT(node->n_refcnt); DTRACE_PROBE1(smb_node_ref_exit, smb_node_t *, node); @@ -584,8 +540,6 @@ mutex_enter(&ret_node->n_mutex); switch (ret_node->n_state) { case SMB_NODE_STATE_AVAILABLE: - case SMB_NODE_STATE_OPLOCK_GRANTED: - case SMB_NODE_STATE_OPLOCK_BREAKING: ret_node->n_dnode = to_dnode; mutex_exit(&ret_node->n_mutex); ASSERT(to_dnode->n_dnode != ret_node); @@ -807,6 +761,29 @@ return (NT_STATUS_SUCCESS); } +/* + * smb_node_share_check + * + * Returns: TRUE - ofiles have non-zero share access + * B_FALSE - ofile with share access NONE. + */ +boolean_t +smb_node_share_check(smb_node_t *node) +{ + smb_ofile_t *of; + boolean_t status = B_TRUE; + + SMB_NODE_VALID(node); + + smb_llist_enter(&node->n_ofile_list, RW_READER); + of = smb_llist_head(&node->n_ofile_list); + if (of) + status = smb_ofile_share_check(of); + smb_llist_exit(&node->n_ofile_list); + + return (status); +} + void smb_node_notify_change(smb_node_t *node) { @@ -894,19 +871,6 @@ rw_exit(&node->n_lock); } -uint32_t -smb_node_get_ofile_count(smb_node_t *node) -{ - uint32_t cntr; - - SMB_NODE_VALID(node); - - smb_llist_enter(&node->n_ofile_list, RW_READER); - cntr = smb_llist_get_count(&node->n_ofile_list); - smb_llist_exit(&node->n_ofile_list); - return (cntr); -} - void smb_node_add_ofile(smb_node_t *node, smb_ofile_t *of) { @@ -957,17 +921,29 @@ smb_node_clear_cached_data(node); } -uint32_t -smb_node_get_open_ofiles(smb_node_t *node) +/* + * smb_node_inc_opening_count + */ +void +smb_node_inc_opening_count(smb_node_t *node) { - uint32_t cnt; - SMB_NODE_VALID(node); - mutex_enter(&node->n_mutex); - cnt = node->n_open_count; + node->n_opening_count++; mutex_exit(&node->n_mutex); - return (cnt); +} + +/* + * smb_node_dec_opening_count + */ +void +smb_node_dec_opening_count(smb_node_t *node) +{ + SMB_NODE_VALID(node); + mutex_enter(&node->n_mutex); + ASSERT(node->n_opening_count > 0); + node->n_opening_count--; + mutex_exit(&node->n_mutex); } /* @@ -1106,6 +1082,10 @@ node->n_unode = NULL; node->delete_on_close_cred = NULL; node->n_delete_on_close_flags = 0; + node->n_oplock.ol_fem = B_FALSE; + node->n_oplock.ol_xthread = NULL; + node->n_oplock.ol_count = 0; + node->n_oplock.ol_break = SMB_OPLOCK_NO_BREAK; (void) strlcpy(node->od_name, od_name, sizeof (node->od_name)); if (strcmp(od_name, XATTR_DIR) == 0) @@ -1135,7 +1115,9 @@ VERIFY(!list_link_active(&node->n_lnd)); VERIFY(node->n_lock_list.ll_count == 0); VERIFY(node->n_ofile_list.ll_count == 0); + VERIFY(node->n_oplock.ol_count == 0); VERIFY(node->n_oplock.ol_xthread == NULL); + VERIFY(node->n_oplock.ol_fem == B_FALSE); VERIFY(mutex_owner(&node->n_mutex) == NULL); VERIFY(!RW_LOCK_HELD(&node->n_lock)); VN_RELE(node->vp); @@ -1159,6 +1141,9 @@ smb_llist_constructor(&node->n_lock_list, sizeof (smb_lock_t), offsetof(smb_lock_t, l_lnd)); cv_init(&node->n_oplock.ol_cv, NULL, CV_DEFAULT, NULL); + mutex_init(&node->n_oplock.ol_mutex, NULL, MUTEX_DEFAULT, NULL); + list_create(&node->n_oplock.ol_grants, sizeof (smb_oplock_grant_t), + offsetof(smb_oplock_grant_t, og_lnd)); rw_init(&node->n_lock, NULL, RW_DEFAULT, NULL); mutex_init(&node->n_mutex, NULL, MUTEX_DEFAULT, NULL); smb_node_create_audit_buf(node, kmflags); @@ -1179,8 +1164,10 @@ mutex_destroy(&node->n_mutex); rw_destroy(&node->n_lock); cv_destroy(&node->n_oplock.ol_cv); + mutex_destroy(&node->n_oplock.ol_mutex); smb_llist_destructor(&node->n_lock_list); smb_llist_destructor(&node->n_ofile_list); + list_destroy(&node->n_oplock.ol_grants); } /* @@ -1608,7 +1595,7 @@ * request in smb_node_getattr and smb_node_setattr above.) * Timestamps remain cached while there are open ofiles for the node. * This includes open ofiles for named streams. - * n_open_ofiles cannot be used as this doesn't include ofiles opened + * n_ofile_list cannot be used as this doesn't include ofiles opened * for the node's named streams. Thus n_timestamps contains a count * of open ofiles (t_open_ofiles), including named streams' ofiles, * to be used to control timestamp caching.
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c Thu Jul 22 14:53:56 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -231,7 +230,6 @@ smb_com_nt_create_andx(struct smb_request *sr) { struct open_param *op = &sr->arg.open; - unsigned char OplockLevel; unsigned char DirFlag; smb_attr_t attr; smb_node_t *node; @@ -275,28 +273,14 @@ op->fqi.fq_dnode = op->dir->f_node; } + op->op_oplock_levelII = B_TRUE; + if (smb_common_open(sr) != NT_STATUS_SUCCESS) return (SDRC_ERROR); switch (sr->tid_tree->t_res_type & STYPE_MASK) { case STYPE_DISKTREE: case STYPE_PRINTQ: - switch (op->op_oplock_level) { - case SMB_OPLOCK_EXCLUSIVE: - OplockLevel = 1; - break; - case SMB_OPLOCK_BATCH: - OplockLevel = 2; - break; - case SMB_OPLOCK_LEVEL_II: - OplockLevel = 3; - break; - case SMB_OPLOCK_NONE: - default: - OplockLevel = 0; - break; - } - if (op->create_options & FILE_DELETE_ON_CLOSE) smb_ofile_set_delete_on_close(sr->fid_ofile); @@ -312,7 +296,7 @@ 34, sr->andx_com, 0x67, - OplockLevel, + op->op_oplock_level, sr->smb_fid, op->action_taken, &attr.sa_crtime, @@ -329,12 +313,11 @@ break; case STYPE_IPC: - OplockLevel = 0; rc = smbsr_encode_result(sr, 34, 0, "bb.wbwlqqqqlqqwwbw", 34, sr->andx_com, 0x67, - OplockLevel, + 0, sr->smb_fid, op->action_taken, 0LL,
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c Thu Jul 22 14:53:56 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -140,7 +139,6 @@ smb_nt_transact_create(smb_request_t *sr, smb_xa_t *xa) { struct open_param *op = &sr->arg.open; - uint8_t OplockLevel; uint8_t DirFlag; smb_attr_t attr; smb_node_t *node; @@ -184,6 +182,8 @@ op->fqi.fq_dnode = op->dir->f_node; } + op->op_oplock_levelII = B_TRUE; + status = smb_common_open(sr); if (status != NT_STATUS_SUCCESS) @@ -192,22 +192,6 @@ switch (sr->tid_tree->t_res_type & STYPE_MASK) { case STYPE_DISKTREE: case STYPE_PRINTQ: - switch (op->op_oplock_level) { - case SMB_OPLOCK_EXCLUSIVE: - OplockLevel = 1; - break; - case SMB_OPLOCK_BATCH: - OplockLevel = 2; - break; - case SMB_OPLOCK_LEVEL_II: - OplockLevel = 3; - break; - case SMB_OPLOCK_NONE: - default: - OplockLevel = 0; - break; - } - if (op->create_options & FILE_DELETE_ON_CLOSE) smb_ofile_set_delete_on_close(sr->fid_ofile); @@ -220,7 +204,7 @@ } (void) smb_mbc_encodef(&xa->rep_param_mb, "b.wllTTTTlqqwwb", - OplockLevel, + op->op_oplock_level, sr->smb_fid, op->action_taken, 0, /* EaErrorOffset */
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c Thu Jul 22 14:53:56 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <smbsrv/smb_kproto.h> @@ -34,6 +33,10 @@ /* * This table defines the list of FSCTL values for which we'll * call a funtion to perform specific processing. + * + * Note: If support is added for FSCTL_SET_ZERO_DATA, it must break + * any oplocks on the file to none: + * smb_oplock_break(sr, node, SMB_OPLOCK_BREAK_TO_NONE); */ static struct { uint32_t fcode;
--- a/usr/src/uts/common/fs/smbsrv/smb_odir.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_odir.c Thu Jul 22 14:53:56 2010 -0700 @@ -248,7 +248,7 @@ #include <sys/extdirent.h> /* static functions */ -static smb_odir_t *smb_odir_create(smb_request_t *, smb_node_t *, +static uint16_t smb_odir_create(smb_request_t *, smb_node_t *, char *, uint16_t, cred_t *); static int smb_odir_single_fileinfo(smb_request_t *, smb_odir_t *, smb_fileinfo_t *); @@ -257,6 +257,7 @@ static int smb_odir_next_odirent(smb_odir_t *, smb_odirent_t *); static boolean_t smb_odir_lookup_link(smb_request_t *, smb_odir_t *, char *, smb_node_t **); +static boolean_t smb_odir_match_name(smb_odir_t *, smb_odirent_t *); /* @@ -275,7 +276,7 @@ smb_tree_t *tree; smb_node_t *dnode; char pattern[MAXNAMELEN]; - smb_odir_t *od; + uint16_t odid; cred_t *cr; ASSERT(sr); @@ -313,9 +314,9 @@ else cr = tree->t_user->u_cred; - od = smb_odir_create(sr, dnode, pattern, sattr, cr); + odid = smb_odir_create(sr, dnode, pattern, sattr, cr); smb_node_release(dnode); - return (od ? od->d_odid : 0); + return (odid); } /* @@ -333,7 +334,7 @@ { int rc; vnode_t *xattr_dvp; - smb_odir_t *od; + uint16_t odid; cred_t *cr; char pattern[SMB_STREAM_PREFIX_LEN + 2]; @@ -370,14 +371,10 @@ } (void) snprintf(pattern, sizeof (pattern), "%s*", SMB_STREAM_PREFIX); - od = smb_odir_create(sr, xattr_dnode, pattern, SMB_SEARCH_ATTRIBUTES, + odid = smb_odir_create(sr, xattr_dnode, pattern, SMB_SEARCH_ATTRIBUTES, cr); smb_node_release(xattr_dnode); - if (od == NULL) - return (0); - - od->d_flags |= SMB_ODIR_FLAG_XATTR; - return (od->d_odid); + return (odid); } /* @@ -516,8 +513,7 @@ for (;;) { if ((rc = smb_odir_next_odirent(od, odirent)) != 0) break; - if (smb_match_name(odirent->od_ino, odirent->od_name, - od->d_pattern)) + if (smb_odir_match_name(od, odirent)) break; } @@ -605,8 +601,7 @@ U8_VALIDATE_ENTIRE, &errnum) < 0) continue; - if (!smb_match_name(odirent->od_ino, odirent->od_name, - od->d_pattern)) + if (!smb_odir_match_name(od, odirent)) continue; rc = smb_odir_wildcard_fileinfo(sr, od, odirent, @@ -811,7 +806,7 @@ * smb_odir_create * Allocate and populate an odir obect and add it to the tree's list. */ -static smb_odir_t * +static uint16_t smb_odir_create(smb_request_t *sr, smb_node_t *dnode, char *pattern, uint16_t sattr, cred_t *cr) { @@ -831,7 +826,7 @@ if (smb_idpool_alloc(&tree->t_odid_pool, &odid)) { smbsr_error(sr, NT_STATUS_TOO_MANY_OPENED_FILES, ERRDOS, ERROR_TOO_MANY_OPEN_FILES); - return (NULL); + return (0); } od = kmem_cache_alloc(tree->t_server->si_cache_odir, KM_SLEEP); @@ -857,10 +852,14 @@ od->d_flags |= SMB_ODIR_FLAG_EDIRENT; if (smb_tree_has_feature(tree, SMB_TREE_CASEINSENSITIVE)) od->d_flags |= SMB_ODIR_FLAG_IGNORE_CASE; + if (smb_tree_has_feature(tree, SMB_TREE_SHORTNAMES)) + od->d_flags |= SMB_ODIR_FLAG_SHORTNAMES; if (SMB_TREE_SUPPORTS_CATIA(sr)) od->d_flags |= SMB_ODIR_FLAG_CATIA; if (SMB_TREE_SUPPORTS_ABE(sr)) od->d_flags |= SMB_ODIR_FLAG_ABE; + if (dnode->flags & NODE_XATTR_DIR) + od->d_flags |= SMB_ODIR_FLAG_XATTR; od->d_eof = B_FALSE; smb_llist_enter(&tree->t_odir_list, RW_WRITER); @@ -868,7 +867,7 @@ smb_llist_exit(&tree->t_odir_list); atomic_inc_32(&tree->t_session->s_dir_cnt); - return (od); + return (odid); } /* @@ -1038,7 +1037,7 @@ int rc; smb_node_t *fnode, *tgt_node; smb_attr_t attr; - ino64_t ino; + ino64_t fid; char *name; boolean_t case_conflict = B_FALSE; int lookup_flags, flags = 0; @@ -1101,11 +1100,15 @@ } name = fnode->od_name; - ino = attr.sa_vattr.va_nodeid; - if (case_conflict || smb_needs_mangled(name)) - smb_mangle(name, ino, fileinfo->fi_shortname, SMB_SHORTNAMELEN); - if (case_conflict) - name = fileinfo->fi_shortname; + if (od->d_flags & SMB_ODIR_FLAG_SHORTNAMES) { + fid = attr.sa_vattr.va_nodeid; + if (case_conflict || smb_needs_mangled(name)) { + smb_mangle(name, fid, fileinfo->fi_shortname, + SMB_SHORTNAMELEN); + } + if (case_conflict) + name = fileinfo->fi_shortname; + } (void) strlcpy(fileinfo->fi_name, name, sizeof (fileinfo->fi_name)); @@ -1194,14 +1197,18 @@ return (ENOENT); } - case_conflict = ((od->d_flags & SMB_ODIR_FLAG_IGNORE_CASE) && - (odirent->od_eflags & ED_CASE_CONFLICT)); - if (case_conflict || smb_needs_mangled(odirent->od_name)) { - smb_mangle(odirent->od_name, odirent->od_ino, - fileinfo->fi_shortname, SMB_SHORTNAMELEN); + name = odirent->od_name; + if (od->d_flags & SMB_ODIR_FLAG_SHORTNAMES) { + case_conflict = ((od->d_flags & SMB_ODIR_FLAG_IGNORE_CASE) && + (odirent->od_eflags & ED_CASE_CONFLICT)); + if (case_conflict || smb_needs_mangled(name)) { + smb_mangle(name, odirent->od_ino, + fileinfo->fi_shortname, SMB_SHORTNAMELEN); + } + if (case_conflict) + name = fileinfo->fi_shortname; } - name = (case_conflict) ? fileinfo->fi_shortname : odirent->od_name; (void) strlcpy(fileinfo->fi_name, name, sizeof (fileinfo->fi_name)); fileinfo->fi_cookie = (uint32_t)od->d_offset; @@ -1261,3 +1268,34 @@ return (B_TRUE); } + +/* + * smb_odir_match_name + * + * Check if the directory entry name matches the search pattern: + * - Don't match reserved dos filenames. + * - Check if odirent->od_name matches od->d_pattern. + * - If shortnames are supported, generate the shortname from + * odirent->od_name and check if it matches od->d_pattern. + */ +boolean_t +smb_odir_match_name(smb_odir_t *od, smb_odirent_t *odirent) +{ + char *name = odirent->od_name; + char shortname[SMB_SHORTNAMELEN]; + ino64_t ino = odirent->od_ino; + + if (smb_is_reserved_dos_name(name)) + return (B_FALSE); + + if (smb_match_ci(od->d_pattern, name)) + return (B_TRUE); + + if (od->d_flags & SMB_ODIR_FLAG_SHORTNAMES) { + smb_mangle(name, ino, shortname, SMB_SHORTNAMELEN); + if (smb_match_ci(od->d_pattern, shortname)) + return (B_TRUE); + } + + return (B_FALSE); +}
--- a/usr/src/uts/common/fs/smbsrv/smb_ofile.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_ofile.c Thu Jul 22 14:53:56 2010 -0700 @@ -217,7 +217,6 @@ mutex_init(&of->f_mutex, NULL, MUTEX_DEFAULT, NULL); of->f_state = SMB_OFILE_STATE_OPEN; - if (ftype == SMB_FTYPE_MESG_PIPE) { of->f_pipe = smb_opipe_alloc(tree->t_server); smb_server_inc_pipes(of->f_server); @@ -338,15 +337,11 @@ ASSERT(of->f_refcnt); ASSERT(of->f_state == SMB_OFILE_STATE_CLOSING); of->f_state = SMB_OFILE_STATE_CLOSED; - mutex_exit(&of->f_mutex); if (of->f_node != NULL) { smb_node_dec_open_ofiles(of->f_node); - if (of->f_oplock_granted) { - smb_oplock_release(of->f_node, of); - of->f_oplock_granted = B_FALSE; - } + smb_oplock_release(of->f_node, of); } - return; + break; } case SMB_OFILE_STATE_CLOSED: case SMB_OFILE_STATE_CLOSING: @@ -483,20 +478,11 @@ * iteration may be in progress. */ void -smb_ofile_release(smb_ofile_t *of) +smb_ofile_release(smb_ofile_t *of) { - boolean_t rb; - SMB_OFILE_VALID(of); mutex_enter(&of->f_mutex); - if (of->f_oplock_exit) { - mutex_exit(&of->f_mutex); - rb = smb_oplock_broadcast(of->f_node); - mutex_enter(&of->f_mutex); - if (rb) - of->f_oplock_exit = B_FALSE; - } ASSERT(of->f_refcnt); of->f_refcnt--; switch (of->f_state) { @@ -517,6 +503,35 @@ } /* + * smb_ofile_request_complete + * + * During oplock acquisition, all other oplock requests on the node + * are blocked until the acquire request completes and the response + * is on the wire. + * Call smb_oplock_broadcast to notify the node that the request + * has completed. + * + * THIS MECHANISM RELIES ON THE FACT THAT THE OFILE IS NOT REMOVED + * FROM THE SR UNTIL REQUEST COMPLETION (when the sr is destroyed) + */ +void +smb_ofile_request_complete(smb_ofile_t *of) +{ + SMB_OFILE_VALID(of); + + switch (of->f_ftype) { + case SMB_FTYPE_DISK: + ASSERT(of->f_node); + smb_oplock_broadcast(of->f_node); + break; + case SMB_FTYPE_MESG_PIPE: + break; + default: + break; + } +} + +/* * smb_ofile_lookup_by_fid * * Find the open file whose fid matches the one specified in the request. @@ -735,17 +750,6 @@ return (rc); } -void -smb_ofile_set_oplock_granted(smb_ofile_t *of) -{ - SMB_OFILE_VALID(of); - mutex_enter(&of->f_mutex); - ASSERT(!of->f_oplock_granted); - of->f_oplock_granted = B_TRUE; - of->f_oplock_exit = B_TRUE; - mutex_exit(&of->f_mutex); -} - /* * smb_ofile_pending_write_time * @@ -994,6 +998,18 @@ return (NT_STATUS_SUCCESS); } +/* + * smb_ofile_share_check + * + * Check if ofile was opened with share access NONE (0). + * Returns: B_TRUE - share access non-zero + * B_FALSE - share access NONE + */ +boolean_t +smb_ofile_share_check(smb_ofile_t *of) +{ + return (!SMB_DENY_ALL(of->f_share_access)); +} /* * check file sharing rules for current open request
--- a/usr/src/uts/common/fs/smbsrv/smb_open_andx.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_open_andx.c Thu Jul 22 14:53:56 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <smbsrv/smb_kproto.h> @@ -264,6 +263,7 @@ } else { op->op_oplock_level = SMB_OPLOCK_NONE; } + op->op_oplock_levelII = B_FALSE; if (smb_common_open(sr) != NT_STATUS_SUCCESS) return (SDRC_ERROR); @@ -372,6 +372,8 @@ if (op->omode & SMB_DA_WRITE_THROUGH) op->create_options |= FILE_WRITE_THROUGH; + op->op_oplock_levelII = B_FALSE; + if (smb_common_open(sr) != NT_STATUS_SUCCESS) return (SDRC_ERROR); @@ -480,6 +482,7 @@ } else { op->op_oplock_level = SMB_OPLOCK_NONE; } + op->op_oplock_levelII = B_FALSE; if (smb_common_open(sr) != NT_STATUS_SUCCESS) return (SDRC_ERROR);
--- a/usr/src/uts/common/fs/smbsrv/smb_opipe.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_opipe.c Thu Jul 22 14:53:56 2010 -0700 @@ -235,7 +235,7 @@ uint32_t buflen = SMB_OPIPE_DOOR_BUFSIZE; uint32_t len; - if ((opipe->p_event = smb_event_create()) == NULL) + if ((opipe->p_event = smb_event_create(SMB_EVENT_TIMEOUT)) == NULL) return (-1); smb_user_netinfo_init(user, userinfo);
--- a/usr/src/uts/common/fs/smbsrv/smb_oplock.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_oplock.c Thu Jul 22 14:53:56 2010 -0700 @@ -21,441 +21,809 @@ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ + /* - * SMB Locking library functions. + * smb_oplock_wait / smb_oplock_broadcast + * When an oplock is being acquired, we must ensure that the acquisition + * response is submitted to the network stack before any other operation + * is permitted on the oplock. + * In smb_oplock_acquire, oplock.ol_xthread is set to point to the worker + * thread processing the command that is granting the oplock. + * Other threads accessing the oplock will be suspended in smb_oplock_wait(). + * They will be awakened when the worker thread referenced in 'ol_xthread' + * calls smb_oplock_broadcast(). * - * You will notice that the functions in this file exit the lock of the session - * and reenter it before returning. They even assume that the lock has been - * entered in READER mode. The reason for that is a potential deadlock that may - * occur when an oplock needs to be broken and the function - * smb_session_break_oplock() is called. It should be noticed that the mutex of - * the smb node, the oplock of which needs to be broken, is also exited before - * calling smb_session_break_oplock(). The reason for that is the same: avoiding - * a deadlock. That complexity is due to the fact that the lock of the session - * is held during the treatment of a request. That complexity will go away when - * that is not the case anymore. + * The purpose of this mechanism is to prevent another thread from + * triggering an oplock break before the response conveying the grant + * has been sent. */ #include <smbsrv/smb_kproto.h> -#include <smbsrv/smb_fsops.h> +#include <sys/nbmlock.h> #include <inet/tcp.h> +#define SMB_OPLOCK_IS_EXCLUSIVE(level) \ + (((level) == SMB_OPLOCK_EXCLUSIVE) || \ + ((level) == SMB_OPLOCK_BATCH)) + +extern int smb_fem_oplock_install(smb_node_t *); +extern int smb_fem_oplock_uninstall(smb_node_t *); + +static int smb_oplock_install_fem(smb_node_t *); +static void smb_oplock_uninstall_fem(smb_node_t *); + static void smb_oplock_wait(smb_node_t *); +static void smb_oplock_wait_ack(smb_node_t *, uint32_t); +static void smb_oplock_timedout(smb_node_t *); + +static smb_oplock_grant_t *smb_oplock_create_grant(smb_ofile_t *, uint8_t); +void smb_oplock_delete_grant(smb_oplock_grant_t *); +static int smb_oplock_insert_grant(smb_node_t *, smb_oplock_grant_t *); +static void smb_oplock_remove_grant(smb_node_t *, smb_oplock_grant_t *); +static smb_oplock_grant_t *smb_oplock_exclusive_grant(list_t *); +static smb_oplock_grant_t *smb_oplock_find_grant(list_t *, smb_ofile_t *); + +static smb_oplock_break_t *smb_oplock_create_break(smb_node_t *); +static smb_oplock_break_t *smb_oplock_get_break(void); +static void smb_oplock_delete_break(smb_oplock_break_t *); +static void smb_oplock_process_levelII_break(smb_node_t *); + +static void smb_oplock_break_thread(); + +/* levelII oplock break requests (smb_oplock_break_t) */ +static boolean_t smb_oplock_initialized = B_FALSE; +static kmem_cache_t *smb_oplock_break_cache = NULL; +static kmem_cache_t *smb_oplock_grant_cache = NULL; +static smb_llist_t smb_oplock_breaks; +static smb_thread_t smb_oplock_thread; + /* - * Magic 0xFF 'S' 'M' 'B' - * smb_com a byte, the "first" command - * Error a 4-byte union, ignored in a request - * smb_flg a one byte set of eight flags - * smb_flg2 a two byte set of 16 flags - * . twelve reserved bytes, have a role - * in connectionless transports (IPX, UDP?) - * smb_tid a 16-bit tree ID, a mount point sorta, - * 0xFFFF is this command does not have - * or require a tree context - * smb_pid a 16-bit process ID - * smb_uid a 16-bit user ID, specific to this "session" - * and mapped to a system (bona-fide) UID - * smb_mid a 16-bit multiplex ID, used to differentiate - * multiple simultaneous requests from the same - * process (pid) (ref RPC "xid") - * - * SMB_COM_LOCKING_ANDX allows both locking and/or unlocking of file range(s). - * - * Client Request Description - * ================================== ================================= - * - * UCHAR WordCount; Count of parameter words = 8 - * UCHAR AndXCommand; Secondary (X) command; 0xFF = none - * UCHAR AndXReserved; Reserved (must be 0) - * USHORT AndXOffset; Offset to next command WordCount - * USHORT Fid; File handle - * UCHAR LockType; See LockType table below - * UCHAR OplockLevel; The new oplock level - * ULONG Timeout; Milliseconds to wait for unlock - * USHORT NumberOfUnlocks; Num. unlock range structs following - * USHORT NumberOfLocks; Num. lock range structs following - * USHORT ByteCount; Count of data bytes - * LOCKING_ANDX_RANGE Unlocks[]; Unlock ranges - * LOCKING_ANDX_RANGE Locks[]; Lock ranges + * smb_oplock_init * - * LockType Flag Name Value Description - * ============================ ===== ================================ - * - * LOCKING_ANDX_SHARED_LOCK 0x01 Read-only lock - * LOCKING_ANDX_OPLOCK_RELEASE 0x02 Oplock break notification - * LOCKING_ANDX_CHANGE_LOCKTYPE 0x04 Change lock type - * LOCKING_ANDX_CANCEL_LOCK 0x08 Cancel outstanding request - * LOCKING_ANDX_LARGE_FILES 0x10 Large file locking format - * - * LOCKING_ANDX_RANGE Format - * ===================================================================== - * - * USHORT Pid; PID of process "owning" lock - * ULONG Offset; Offset to bytes to [un]lock - * ULONG Length; Number of bytes to [un]lock - * - * Large File LOCKING_ANDX_RANGE Format - * ===================================================================== - * - * USHORT Pid; PID of process "owning" lock - * USHORT Pad; Pad to DWORD align (mbz) - * ULONG OffsetHigh; Offset to bytes to [un]lock - * (high) - * ULONG OffsetLow; Offset to bytes to [un]lock (low) - * ULONG LengthHigh; Number of bytes to [un]lock - * (high) - * ULONG LengthLow; Number of bytes to [un]lock (low) - * - * Server Response Description - * ================================== ================================= - * - * UCHAR WordCount; Count of parameter words = 2 - * UCHAR AndXCommand; Secondary (X) command; 0xFF = - * none - * UCHAR AndXReserved; Reserved (must be 0) - * USHORT AndXOffset; Offset to next command WordCount - * USHORT ByteCount; Count of data bytes = 0 - * + * This function is not multi-thread safe. The caller must make sure only one + * thread makes the call. + */ +int +smb_oplock_init(void) +{ + int rc; + + if (smb_oplock_initialized) + return (0); + + smb_oplock_break_cache = kmem_cache_create("smb_oplock_break_cache", + sizeof (smb_oplock_break_t), 8, NULL, NULL, NULL, NULL, NULL, 0); + + smb_oplock_grant_cache = kmem_cache_create("smb_oplock_grant_cache", + sizeof (smb_oplock_grant_t), 8, NULL, NULL, NULL, NULL, NULL, 0); + + smb_llist_constructor(&smb_oplock_breaks, sizeof (smb_oplock_break_t), + offsetof(smb_oplock_break_t, ob_lnd)); + + smb_thread_init(&smb_oplock_thread, "smb_thread_oplock_break", + smb_oplock_break_thread, NULL, NULL, NULL); + + rc = smb_thread_start(&smb_oplock_thread); + if (rc != 0) { + smb_thread_destroy(&smb_oplock_thread); + smb_llist_destructor(&smb_oplock_breaks); + kmem_cache_destroy(smb_oplock_break_cache); + kmem_cache_destroy(smb_oplock_grant_cache); + return (rc); + } + + smb_oplock_initialized = B_TRUE; + return (0); +} + +/* + * smb_oplock_fini + * This function is not multi-thread safe. The caller must make sure only one + * thread makes the call. */ +void +smb_oplock_fini(void) +{ + smb_oplock_break_t *ob; + + if (!smb_oplock_initialized) + return; + + smb_thread_stop(&smb_oplock_thread); + smb_thread_destroy(&smb_oplock_thread); + + while ((ob = smb_llist_head(&smb_oplock_breaks)) != NULL) { + SMB_OPLOCK_BREAK_VALID(ob); + smb_llist_remove(&smb_oplock_breaks, ob); + smb_oplock_delete_break(ob); + } + smb_llist_destructor(&smb_oplock_breaks); + + kmem_cache_destroy(smb_oplock_break_cache); + kmem_cache_destroy(smb_oplock_grant_cache); +} + +/* + * smb_oplock_install_fem + * Install fem monitor for cross protocol oplock breaking. + */ +static int +smb_oplock_install_fem(smb_node_t *node) +{ + ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex)); + + if (node->n_oplock.ol_fem == B_FALSE) { + if (smb_fem_oplock_install(node) != 0) { + cmn_err(CE_NOTE, "No oplock granted: " + "failed to install fem monitor %s", + node->vp->v_path); + return (-1); + } + node->n_oplock.ol_fem = B_TRUE; + } + return (0); +} + +/* + * smb_oplock_uninstall_fem + * Uninstall fem monitor for cross protocol oplock breaking. + */ +static void +smb_oplock_uninstall_fem(smb_node_t *node) +{ + ASSERT(MUTEX_HELD(&node->n_oplock.ol_mutex)); + + if (node->n_oplock.ol_fem) { + if (smb_fem_oplock_uninstall(node) == 0) { + node->n_oplock.ol_fem = B_FALSE; + } else { + cmn_err(CE_NOTE, + "failed to uninstall fem monitor %s", + node->vp->v_path); + } + } +} /* * smb_oplock_acquire * - * Attempt to acquire an oplock. Note that the oplock granted may be - * none, i.e. the oplock was not granted. The result of the acquisition is - * provided in ol->ol_level. - * - * Grant an oplock to the requestor if this session is the only one - * that has the file open, regardless of the number of instances of - * the file opened by this session. + * Attempt to acquire an oplock. Clients will request EXCLUSIVE or BATCH, + * but might only be granted LEVEL_II or NONE. * - * However, if there is no oplock on this file and there is already - * at least one open, we will not grant an oplock, even if the only - * existing opens are from the same client. This is "server discretion." + * If oplocks are not supported on the tree, or node, grant NONE. + * If nobody else has the file open, grant the requested level. + * If any of the following are true, grant NONE: + * - there is an exclusive oplock on the node + * - op->op_oplock_levelII is B_FALSE (LEVEL_II not supported by open cmd. + * - LEVEL_II oplocks are not supported for the session + * - a BATCH oplock is requested on a named stream + * - there are any range locks on the node + * Otherwise, grant LEVEL_II. * - * An oplock may need to be broken in order for one to be granted, and - * depending on what action is taken by the other client (unlock or close), - * an oplock may or may not be granted. (The breaking of an oplock is - * done earlier in the calling path.) + * ol->ol_xthread is set to the current thread to lock the oplock against + * other operations until the acquire response is on the wire. When the + * acquire response is on the wire, smb_oplock_broadcast() is called to + * reset ol->ol_xthread and wake any waiting threads. */ void -smb_oplock_acquire(smb_node_t *node, smb_ofile_t *of, smb_arg_open_t *op) +smb_oplock_acquire(smb_request_t *sr, smb_node_t *node, smb_ofile_t *ofile) { - smb_session_t *session; - smb_oplock_t *ol; - clock_t time; + smb_oplock_t *ol; + smb_oplock_grant_t *og; + list_t *grants; + smb_arg_open_t *op; + smb_tree_t *tree; + smb_session_t *session; SMB_NODE_VALID(node); - SMB_OFILE_VALID(of); + SMB_OFILE_VALID(ofile); - ASSERT(node == SMB_OFILE_GET_NODE(of)); + ASSERT(node == SMB_OFILE_GET_NODE(ofile)); - session = SMB_OFILE_GET_SESSION(of); + op = &sr->sr_open; + tree = SMB_OFILE_GET_TREE(ofile); + session = SMB_OFILE_GET_SESSION(ofile); - if (!smb_session_oplocks_enable(session) || - smb_tree_has_feature(SMB_OFILE_GET_TREE(of), SMB_TREE_NO_OPLOCKS)) { + if (!smb_tree_has_feature(tree, SMB_TREE_OPLOCKS) || + (op->op_oplock_level == SMB_OPLOCK_NONE) || + ((op->op_oplock_level == SMB_OPLOCK_BATCH) && + SMB_IS_STREAM(node))) { op->op_oplock_level = SMB_OPLOCK_NONE; return; } ol = &node->n_oplock; - time = MSEC_TO_TICK(smb_oplock_timeout) + ddi_get_lbolt(); + grants = &ol->ol_grants; - mutex_enter(&node->n_mutex); + mutex_enter(&ol->ol_mutex); + smb_oplock_wait(node); + + nbl_start_crit(node->vp, RW_READER); - switch (node->n_state) { - case SMB_NODE_STATE_OPLOCK_GRANTED: - if (SMB_SESSION_GET_ID(session) == ol->ol_sess_id) { - mutex_exit(&node->n_mutex); + if ((node->n_open_count > 1) || + (node->n_opening_count > 1) || + smb_vop_other_opens(node->vp, ofile->f_mode)) { + if ((!op->op_oplock_levelII) || + (!smb_session_levelII_oplocks(session)) || + (smb_oplock_exclusive_grant(grants) != NULL) || + (smb_range_check(sr, node, 0, UINT64_MAX, B_TRUE) != 0)) { + op->op_oplock_level = SMB_OPLOCK_NONE; + nbl_end_crit(node->vp); + mutex_exit(&ol->ol_mutex); return; } + + op->op_oplock_level = SMB_OPLOCK_LEVEL_II; + } + + nbl_end_crit(node->vp); + + og = smb_oplock_create_grant(ofile, op->op_oplock_level); + if (smb_oplock_insert_grant(node, og) != 0) { + smb_oplock_delete_grant(og); + op->op_oplock_level = SMB_OPLOCK_NONE; + mutex_exit(&ol->ol_mutex); + return; + } + + ol->ol_xthread = curthread; + mutex_exit(&ol->ol_mutex); +} + +/* + * smb_oplock_break + * + * Break granted oplocks according to the following rules: + * + * If there's an exclusive oplock granted on the node + * - if the BREAK_BATCH flags is specified and the oplock is not + * a batch oplock, no break is required. + * - if the session doesn't support LEVEL II oplocks, and 'brk' is + * BREAK_TO_LEVEL_II, do a BREAK_TO_NONE. + * - if the oplock is already breaking update the break level (if + * the requested break is to a lesser level), otherwise send an + * oplock break. + * Wait for acknowledgement of the break (unless NOWAIT flag is set) + * + * Otherwise: + * If there are level II oplocks granted on the node, and the flags + * indicate that they should be broken (BREAK_TO_NONE specified, + * BREAK_EXCLUSIVE, BREAK_BATCH not specified) queue the levelII + * break request for asynchronous processing. + * + * Returns: + * 0 - oplock broken (or no break required) + * EAGAIN - oplock break request sent and would block + * awaiting the reponse but NOWAIT was specified + */ +int +smb_oplock_break(smb_request_t *sr, smb_node_t *node, uint32_t flags) +{ + smb_oplock_t *ol; + smb_oplock_grant_t *og; + list_t *grants; + uint32_t timeout; + uint8_t brk; + + SMB_NODE_VALID(node); + ol = &node->n_oplock; + grants = &ol->ol_grants; + + mutex_enter(&ol->ol_mutex); + smb_oplock_wait(node); + + og = list_head(grants); + if (og == NULL) { + mutex_exit(&ol->ol_mutex); + return (0); + } + + SMB_OPLOCK_GRANT_VALID(og); + + /* break levelII oplocks */ + if (og->og_level == SMB_OPLOCK_LEVEL_II) { + mutex_exit(&ol->ol_mutex); + + if ((flags & SMB_OPLOCK_BREAK_TO_NONE) && + !(flags & SMB_OPLOCK_BREAK_EXCLUSIVE) && + !(flags & SMB_OPLOCK_BREAK_BATCH)) { + smb_oplock_break_levelII(node); + } + return (0); + } + + /* break exclusive oplock */ + if ((flags & SMB_OPLOCK_BREAK_BATCH) && + (og->og_level != SMB_OPLOCK_BATCH)) { + mutex_exit(&ol->ol_mutex); + return (0); + } + + if ((flags & SMB_OPLOCK_BREAK_TO_LEVEL_II) && + smb_session_levelII_oplocks(og->og_session)) { + brk = SMB_OPLOCK_BREAK_TO_LEVEL_II; + } else { + brk = SMB_OPLOCK_BREAK_TO_NONE; + } + + switch (ol->ol_break) { + case SMB_OPLOCK_NO_BREAK: + ol->ol_break = brk; + smb_session_oplock_break(og->og_session, + og->og_tid, og->og_fid, brk); break; - case SMB_NODE_STATE_AVAILABLE: - case SMB_NODE_STATE_OPLOCK_BREAKING: + case SMB_OPLOCK_BREAK_TO_LEVEL_II: + if (brk == SMB_OPLOCK_BREAK_TO_NONE) + ol->ol_break = SMB_OPLOCK_BREAK_TO_NONE; + break; + case SMB_OPLOCK_BREAK_TO_NONE: + default: + break; + } + + if (flags & SMB_OPLOCK_BREAK_NOWAIT) { + mutex_exit(&ol->ol_mutex); + return (EAGAIN); + } + + if (sr && (sr->session == og->og_session) && + (sr->smb_uid == og->og_uid)) { + timeout = smb_oplock_min_timeout; + } else { + timeout = smb_oplock_timeout; + } + + mutex_exit(&ol->ol_mutex); + smb_oplock_wait_ack(node, timeout); + return (0); +} + +/* + * smb_oplock_break_levelII + * + * LevelII (shared) oplock breaks are processed asynchronously. + * Unlike exclusive oplock breaks, the thread initiating the break + * is NOT blocked while the request is processed. + * + * Create an oplock_break_request and add it to the list for async + * processing. + */ +void +smb_oplock_break_levelII(smb_node_t *node) +{ + smb_oplock_break_t *ob; + + ob = smb_oplock_create_break(node); + + smb_llist_enter(&smb_oplock_breaks, RW_WRITER); + smb_llist_insert_tail(&smb_oplock_breaks, ob); + smb_llist_exit(&smb_oplock_breaks); + + smb_thread_signal(&smb_oplock_thread); +} + +/* + * smb_oplock_break_thread + * + * The smb_oplock_thread is woken when an oplock break request is + * added to the list of pending levelII oplock break requests. + * Gets the oplock break request from the list, processes it and + * deletes it. + */ +/*ARGSUSED*/ +static void +smb_oplock_break_thread(smb_thread_t *thread, void *arg) +{ + smb_oplock_break_t *ob; + + while (smb_thread_continue(thread)) { + while ((ob = smb_oplock_get_break()) != NULL) { + smb_oplock_process_levelII_break(ob->ob_node); + smb_oplock_delete_break(ob); + } + } +} + +/* + * smb_oplock_get_break + * + * Remove and return the next oplock break request from the list + */ +static smb_oplock_break_t * +smb_oplock_get_break(void) +{ + smb_oplock_break_t *ob; + + smb_llist_enter(&smb_oplock_breaks, RW_WRITER); + if ((ob = smb_llist_head(&smb_oplock_breaks)) != NULL) { + SMB_OPLOCK_BREAK_VALID(ob); + smb_llist_remove(&smb_oplock_breaks, ob); + } + smb_llist_exit(&smb_oplock_breaks); + return (ob); +} + +/* + * smb_oplock_process_levelII_break + */ +void +smb_oplock_process_levelII_break(smb_node_t *node) +{ + smb_oplock_t *ol; + smb_oplock_grant_t *og; + list_t *grants; + + if (!smb_oplock_levelII) + return; + + ol = &node->n_oplock; + mutex_enter(&ol->ol_mutex); + smb_oplock_wait(node); + grants = &node->n_oplock.ol_grants; + + while ((og = list_head(grants)) != NULL) { + SMB_OPLOCK_GRANT_VALID(og); + + if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level)) + break; + + smb_session_oplock_break(og->og_session, + og->og_tid, og->og_fid, SMB_OPLOCK_BREAK_TO_NONE); + smb_oplock_remove_grant(node, og); + smb_oplock_delete_grant(og); + } + + mutex_exit(&ol->ol_mutex); +} + +/* + * smb_oplock_wait_ack + * + * Timed wait for an oplock break acknowledgement (or oplock release). + */ +static void +smb_oplock_wait_ack(smb_node_t *node, uint32_t timeout) +{ + smb_oplock_t *ol; + clock_t time; + + ol = &node->n_oplock; + mutex_enter(&ol->ol_mutex); + time = MSEC_TO_TICK(timeout) + ddi_get_lbolt(); + + while (ol->ol_break != SMB_OPLOCK_NO_BREAK) { + if (cv_timedwait(&ol->ol_cv, &ol->ol_mutex, time) < 0) { + smb_oplock_timedout(node); + cv_broadcast(&ol->ol_cv); + break; + } + } + mutex_exit(&ol->ol_mutex); +} + +/* + * smb_oplock_timedout + * + * An oplock break has not been acknowledged within timeout + * 'smb_oplock_timeout'. + * Set oplock grant to the desired break level. + */ +static void +smb_oplock_timedout(smb_node_t *node) +{ + smb_oplock_t *ol; + smb_oplock_grant_t *og; + list_t *grants; + + ol = &node->n_oplock; + grants = &ol->ol_grants; + + ASSERT(MUTEX_HELD(&ol->ol_mutex)); + + og = smb_oplock_exclusive_grant(grants); + if (og) { + switch (ol->ol_break) { + case SMB_OPLOCK_BREAK_TO_NONE: + og->og_level = SMB_OPLOCK_NONE; + smb_oplock_remove_grant(node, og); + smb_oplock_delete_grant(og); + break; + case SMB_OPLOCK_BREAK_TO_LEVEL_II: + og->og_level = SMB_OPLOCK_LEVEL_II; + break; + default: + SMB_PANIC(); + } + } + ol->ol_break = SMB_OPLOCK_NO_BREAK; +} + +/* + * smb_oplock_release + * + * Release the oplock granted on ofile 'of'. + * Wake any threads waiting for an oplock break acknowledgement for + * this oplock. + * This is called when the ofile is being closed. + */ +void +smb_oplock_release(smb_node_t *node, smb_ofile_t *of) +{ + smb_oplock_t *ol; + smb_oplock_grant_t *og; + list_t *grants; + + ol = &node->n_oplock; + grants = &ol->ol_grants; + + mutex_enter(&ol->ol_mutex); + smb_oplock_wait(node); + + og = smb_oplock_find_grant(grants, of); + if (og) { + smb_oplock_remove_grant(node, og); + smb_oplock_delete_grant(og); + + if (ol->ol_break != SMB_OPLOCK_NO_BREAK) { + ol->ol_break = SMB_OPLOCK_NO_BREAK; + cv_broadcast(&ol->ol_cv); + } + } + + mutex_exit(&ol->ol_mutex); +} + +/* + * smb_oplock_ack + * + * Process oplock acknowledgement received for ofile 'of'. + * - oplock.ol_break is the break level that was requested. + * - brk is the break level being acknowledged by the client. + * + * Update the oplock grant level to the lesser of ol_break and brk. + * If the grant is now SMB_OPLOCK_NONE, remove the grant from the + * oplock's grant list and delete it. + * If the requested break level (ol_break) was NONE and the brk is + * LEVEL_II, send another oplock break (NONE). Do not wait for an + * acknowledgement. + * Wake any threads waiting for the oplock break acknowledgement. + */ +void +smb_oplock_ack(smb_node_t *node, smb_ofile_t *of, uint8_t brk) +{ + smb_oplock_t *ol; + smb_oplock_grant_t *og; + list_t *grants; + boolean_t brk_to_none = B_FALSE; + + ol = &node->n_oplock; + grants = &ol->ol_grants; + + mutex_enter(&ol->ol_mutex); + smb_oplock_wait(node); + + if ((ol->ol_break == SMB_OPLOCK_NO_BREAK) || + ((og = smb_oplock_find_grant(grants, of)) == NULL)) { + mutex_exit(&ol->ol_mutex); + return; + } + + switch (brk) { + case SMB_OPLOCK_BREAK_TO_NONE: + og->og_level = SMB_OPLOCK_NONE; + break; + case SMB_OPLOCK_BREAK_TO_LEVEL_II: + if (ol->ol_break == SMB_OPLOCK_BREAK_TO_LEVEL_II) { + og->og_level = SMB_OPLOCK_LEVEL_II; + } else { + /* SMB_OPLOCK_BREAK_TO_NONE */ + og->og_level = SMB_OPLOCK_NONE; + brk_to_none = B_TRUE; + } break; default: SMB_PANIC(); } - for (;;) { - int rc; - - smb_oplock_wait(node); + if (og->og_level == SMB_OPLOCK_NONE) { + smb_oplock_remove_grant(node, og); + smb_oplock_delete_grant(og); + } - if (node->n_state == SMB_NODE_STATE_AVAILABLE) { - if ((op->op_oplock_level == SMB_OPLOCK_LEVEL_II) || - (op->op_oplock_level == SMB_OPLOCK_NONE) || - (node->n_open_count > 1)) { - mutex_exit(&node->n_mutex); - op->op_oplock_level = SMB_OPLOCK_NONE; - return; - } - ol->ol_ofile = of; - ol->ol_sess_id = SMB_SESSION_GET_ID(session); - ol->ol_level = op->op_oplock_level; - ol->ol_xthread = curthread; - node->n_state = SMB_NODE_STATE_OPLOCK_GRANTED; - mutex_exit(&node->n_mutex); - if (smb_fsop_oplock_install(node, of->f_mode) == 0) { - smb_ofile_set_oplock_granted(of); - return; - } - mutex_enter(&node->n_mutex); - ASSERT(node->n_state == SMB_NODE_STATE_OPLOCK_GRANTED); - node->n_state = SMB_NODE_STATE_AVAILABLE; - ol->ol_xthread = NULL; - op->op_oplock_level = SMB_OPLOCK_NONE; - cv_broadcast(&ol->ol_cv); - break; - } + ol->ol_break = SMB_OPLOCK_NO_BREAK; + cv_broadcast(&ol->ol_cv); - if (node->n_state == SMB_NODE_STATE_OPLOCK_GRANTED) { - if (SMB_SESSION_GET_ID(session) == ol->ol_sess_id) - break; - node->n_state = SMB_NODE_STATE_OPLOCK_BREAKING; - mutex_exit(&node->n_mutex); - smb_session_oplock_break( - SMB_OFILE_GET_SESSION(ol->ol_ofile), ol->ol_ofile); - mutex_enter(&node->n_mutex); - continue; - } - - ASSERT(node->n_state == SMB_NODE_STATE_OPLOCK_BREAKING); - - rc = cv_timedwait(&ol->ol_cv, &node->n_mutex, time); + if (brk_to_none) { + smb_session_oplock_break(of->f_session, + of->f_tree->t_tid, of->f_fid, + SMB_OPLOCK_BREAK_TO_NONE); + } - if (rc == -1) { - /* - * Oplock release timed out. - */ - if (node->n_state == SMB_NODE_STATE_OPLOCK_BREAKING) { - node->n_state = SMB_NODE_STATE_AVAILABLE; - ol->ol_xthread = curthread; - mutex_exit(&node->n_mutex); - smb_fsop_oplock_uninstall(node); - mutex_enter(&node->n_mutex); - ol->ol_xthread = NULL; - cv_broadcast(&ol->ol_cv); - } - } - } - mutex_exit(&node->n_mutex); + mutex_exit(&ol->ol_mutex); } /* - * smb_oplock_break - * - * The oplock break may succeed for multiple reasons: file close, oplock - * release, holder connection dropped, requesting client disconnect etc. - * - * Returns: + * smb_oplock_broadcast * - * B_TRUE The oplock is broken. - * B_FALSE The oplock is being broken. This is returned if nowait is set - * to B_TRUE; - */ -boolean_t -smb_oplock_break(smb_node_t *node, smb_session_t *session, boolean_t nowait) -{ - smb_oplock_t *ol; - clock_t time; - - SMB_NODE_VALID(node); - ol = &node->n_oplock; - time = MSEC_TO_TICK(smb_oplock_timeout) + ddi_get_lbolt(); - - if (session != NULL) { - mutex_enter(&node->n_mutex); - if (SMB_SESSION_GET_ID(session) == ol->ol_sess_id) { - mutex_exit(&node->n_mutex); - return (B_TRUE); - } - } else { - mutex_enter(&node->n_mutex); - } - - for (;;) { - int rc; - - smb_oplock_wait(node); - - if (node->n_state == SMB_NODE_STATE_AVAILABLE) { - mutex_exit(&node->n_mutex); - return (B_TRUE); - } - - if (node->n_state == SMB_NODE_STATE_OPLOCK_GRANTED) { - node->n_state = SMB_NODE_STATE_OPLOCK_BREAKING; - mutex_exit(&node->n_mutex); - smb_session_oplock_break( - SMB_OFILE_GET_SESSION(ol->ol_ofile), ol->ol_ofile); - mutex_enter(&node->n_mutex); - continue; - } - - ASSERT(node->n_state == SMB_NODE_STATE_OPLOCK_BREAKING); - if (nowait) { - mutex_exit(&node->n_mutex); - return (B_FALSE); - } - rc = cv_timedwait(&ol->ol_cv, &node->n_mutex, time); - if (rc == -1) { - /* - * Oplock release timed out. - */ - if (node->n_state == SMB_NODE_STATE_OPLOCK_BREAKING) { - node->n_state = SMB_NODE_STATE_AVAILABLE; - ol->ol_xthread = curthread; - mutex_exit(&node->n_mutex); - smb_fsop_oplock_uninstall(node); - mutex_enter(&node->n_mutex); - ol->ol_xthread = NULL; - cv_broadcast(&ol->ol_cv); - break; - } - } - } - mutex_exit(&node->n_mutex); - return (B_TRUE); -} - -/* - * smb_oplock_release - * - * This function releases the oplock on the node passed in. If other threads - * were waiting for the oplock to be released they are signaled. + * ol->ol_xthread identifies the thread that was performing an oplock + * acquire. Other threads may be blocked awaiting completion of the + * acquire. + * If the calling thread is ol_ol_xthread, wake any waiting threads. */ void -smb_oplock_release(smb_node_t *node, smb_ofile_t *of) +smb_oplock_broadcast(smb_node_t *node) { smb_oplock_t *ol; SMB_NODE_VALID(node); ol = &node->n_oplock; - mutex_enter(&node->n_mutex); - smb_oplock_wait(node); - switch (node->n_state) { - case SMB_NODE_STATE_AVAILABLE: - break; - - case SMB_NODE_STATE_OPLOCK_GRANTED: - case SMB_NODE_STATE_OPLOCK_BREAKING: - if (ol->ol_ofile == of) { - node->n_state = SMB_NODE_STATE_AVAILABLE; - ol->ol_xthread = curthread; - mutex_exit(&node->n_mutex); - smb_fsop_oplock_uninstall(node); - mutex_enter(&node->n_mutex); - ol->ol_xthread = NULL; - cv_broadcast(&ol->ol_cv); - } - break; - - default: - SMB_PANIC(); - } - mutex_exit(&node->n_mutex); -} - -/* - * smb_oplock_conflict - * - * The two checks on "session" and "op" are primarily for the open path. - * Other SMB functions may call smb_oplock_conflict() with a session - * pointer so as to do the session check. - */ -boolean_t -smb_oplock_conflict(smb_node_t *node, smb_session_t *session, - smb_arg_open_t *op) -{ - boolean_t rb; - - SMB_NODE_VALID(node); - SMB_SESSION_VALID(session); - - mutex_enter(&node->n_mutex); - smb_oplock_wait(node); - switch (node->n_state) { - case SMB_NODE_STATE_AVAILABLE: - rb = B_FALSE; - break; - - case SMB_NODE_STATE_OPLOCK_GRANTED: - case SMB_NODE_STATE_OPLOCK_BREAKING: - if (SMB_SESSION_GET_ID(session) == node->n_oplock.ol_sess_id) { - rb = B_FALSE; - break; - } - - if (op != NULL) { - if (((op->desired_access & ~(FILE_READ_ATTRIBUTES | - FILE_WRITE_ATTRIBUTES | SYNCHRONIZE)) == 0) && - (op->create_disposition != FILE_SUPERSEDE) && - (op->create_disposition != FILE_OVERWRITE)) { - /* Attributs only */ - rb = B_FALSE; - break; - } - } - rb = B_TRUE; - break; - - default: - SMB_PANIC(); - } - mutex_exit(&node->n_mutex); - return (rb); -} - -/* - * smb_oplock_broadcast - * - * The the calling thread has the pointer to its context stored in ol_thread - * it resets that field. If any other thread is waiting for that field to - * turn to NULL it is signaled. - * - * Returns: - * B_TRUE Oplock unlocked - * B_FALSE Oplock still locked - */ -boolean_t -smb_oplock_broadcast(smb_node_t *node) -{ - smb_oplock_t *ol; - boolean_t rb; - - SMB_NODE_VALID(node); - ol = &node->n_oplock; - rb = B_FALSE; - - mutex_enter(&node->n_mutex); + mutex_enter(&ol->ol_mutex); if ((ol->ol_xthread != NULL) && (ol->ol_xthread == curthread)) { ol->ol_xthread = NULL; cv_broadcast(&ol->ol_cv); - rb = B_TRUE; } - mutex_exit(&node->n_mutex); - return (rb); + mutex_exit(&ol->ol_mutex); } /* * smb_oplock_wait * - * The mutex of the node must have been entered before calling this function. - * If the field ol_xthread is not NULL and doesn't contain the pointer to the - * context of the calling thread, the caller will sleep until that field is - * reset (set to NULL). + * Wait for the completion of an oplock acquire. + * If ol_xthread is not NULL and doesn't contain the pointer to the + * context of the calling thread, the caller will sleep until the + * ol_xthread is reset to NULL (via smb_oplock_broadcast()). */ static void smb_oplock_wait(smb_node_t *node) { - smb_oplock_t *ol = &node->n_oplock; + smb_oplock_t *ol; + + ol = &node->n_oplock; + ASSERT(MUTEX_HELD(&ol->ol_mutex)); if ((ol->ol_xthread != NULL) && (ol->ol_xthread != curthread)) { - ASSERT(!MUTEX_HELD(&ol->ol_ofile->f_mutex)); while (ol->ol_xthread != NULL) - cv_wait(&ol->ol_cv, &node->n_mutex); + cv_wait(&ol->ol_cv, &ol->ol_mutex); } } + +/* + * smb_oplock_create_grant + */ +static smb_oplock_grant_t * +smb_oplock_create_grant(smb_ofile_t *of, uint8_t level) +{ + smb_oplock_grant_t *og; + + og = kmem_cache_alloc(smb_oplock_grant_cache, KM_SLEEP); + og->og_magic = SMB_OPLOCK_GRANT_MAGIC; + og->og_level = level; + og->og_ofile = of; + og->og_fid = of->f_fid; + og->og_tid = of->f_tree->t_tid; + og->og_uid = of->f_user->u_uid; + og->og_session = of->f_session; + return (og); +} + +/* + * smb_oplock_delete_grant + */ +void +smb_oplock_delete_grant(smb_oplock_grant_t *og) +{ + kmem_cache_free(smb_oplock_grant_cache, og); +} + +/* + * smb_oplock_insert_grant + * + * If there are no grants in the oplock's list install the fem + * monitor. + * Insert the grant into the list and increment the grant count. + */ +static int +smb_oplock_insert_grant(smb_node_t *node, smb_oplock_grant_t *og) +{ + smb_oplock_t *ol = &node->n_oplock; + + ASSERT(MUTEX_HELD(&ol->ol_mutex)); + + if (ol->ol_count == 0) { + if (smb_oplock_install_fem(node) != 0) + return (-1); + } + + list_insert_tail(&ol->ol_grants, og); + ++ol->ol_count; + return (0); +} + +/* + * smb_oplock_remove_grant + * + * Remove the oplock grant from the list, decrement the grant count + * and, if there are no other grants in the list, uninstall the fem + * monitor. + */ +static void +smb_oplock_remove_grant(smb_node_t *node, smb_oplock_grant_t *og) +{ + smb_oplock_t *ol = &node->n_oplock; + + ASSERT(MUTEX_HELD(&ol->ol_mutex)); + ASSERT(ol->ol_count > 0); + + list_remove(&ol->ol_grants, og); + if (--ol->ol_count == 0) + smb_oplock_uninstall_fem(node); +} + +/* + * smb_oplock_exclusive_grant + * + * If an exclusive (EXCLUSIVE or BATCH) oplock grant exists, + * return it. Otherwise return NULL. + */ +static smb_oplock_grant_t * +smb_oplock_exclusive_grant(list_t *grants) +{ + smb_oplock_grant_t *og; + + og = list_head(grants); + if (og) { + SMB_OPLOCK_GRANT_VALID(og); + if (SMB_OPLOCK_IS_EXCLUSIVE(og->og_level)) + return (og); + } + return (NULL); +} + +/* + * smb_oplock_find_grant + * + * Find oplock grant corresponding to the specified ofile. + */ +static smb_oplock_grant_t * +smb_oplock_find_grant(list_t *grants, smb_ofile_t *ofile) +{ + smb_oplock_grant_t *og = NULL; + + for (og = list_head(grants); + og != NULL; + og = list_next(grants, og)) { + SMB_OPLOCK_GRANT_VALID(og); + if (og->og_ofile == ofile) + break; + } + return (og); +} + +/* + * smb_oplock_create_break + */ +static smb_oplock_break_t * +smb_oplock_create_break(smb_node_t *node) +{ + smb_oplock_break_t *ob; + + ob = kmem_cache_alloc(smb_oplock_break_cache, KM_SLEEP); + + smb_node_ref(node); + ob->ob_magic = SMB_OPLOCK_BREAK_MAGIC; + ob->ob_node = node; + + return (ob); +} + +/* + * smb_oplock_delete_break + */ +static void +smb_oplock_delete_break(smb_oplock_break_t *ob) +{ + smb_node_release(ob->ob_node); + kmem_cache_free(smb_oplock_break_cache, ob); +}
--- a/usr/src/uts/common/fs/smbsrv/smb_pathname.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_pathname.c Thu Jul 22 14:53:56 2010 -0700 @@ -402,7 +402,8 @@ &vp, rootvp, dnode->vp, &attr, cred); if (err) { - if (!smb_maybe_mangled(component)) + if (!SMB_TREE_SUPPORTS_SHORTNAMES(sr) || + !smb_maybe_mangled(component)) break; if ((err = smb_unmangle(dnode, component,
--- a/usr/src/uts/common/fs/smbsrv/smb_print.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_print.c Thu Jul 22 14:53:56 2010 -0700 @@ -27,10 +27,15 @@ */ #include <smbsrv/smb_kproto.h> +#include <sys/unistd.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/fcntl.h> +#include <smbsrv/smb_share.h> /* - * Create a new printer file, which should be deleted automatically once - * it has been closed and printed. + * Starts the creation of a new printer file, which will be deleted + * automatically once it has been closed and printed. * * SetupLength is the number of bytes in the first part of the resulting * print spool file which contains printer-specific control strings. @@ -49,7 +54,6 @@ smb_sdrc_t smb_pre_open_print_file(smb_request_t *sr) { - static uint32_t tmp_id = 10000; struct open_param *op = &sr->arg.open; char *path; char *identifier; @@ -57,9 +61,9 @@ uint16_t setup; uint16_t mode; int rc; + static uint32_t tmp_id = 10000; bzero(op, sizeof (sr->arg.open)); - rc = smbsr_decode_vwv(sr, "ww", &setup, &mode); if (rc == 0) rc = smbsr_decode_data(sr, "%S", sr, &identifier); @@ -73,7 +77,6 @@ op->create_disposition = FILE_OVERWRITE_IF; op->create_options = FILE_NON_DIRECTORY_FILE; - DTRACE_SMB_2(op__OpenPrintFile__start, smb_request_t *, sr, struct open_param *, op); @@ -86,21 +89,53 @@ DTRACE_SMB_1(op__OpenPrintFile__done, smb_request_t *, sr); } +/* + * Creates a new spool file which will be later copied and + * deleted by cupsd. After the file is created, information + * related to the file will be placed in a spooldoc list + * to be later used by cupsd + * + * Return values + * rc 0 SDRC_SUCCESS + * rc non-zero SDRC_ERROR + */ + smb_sdrc_t smb_com_open_print_file(smb_request_t *sr) { - int rc; + int rc; + smb_kspooldoc_t *sp; + smb_kshare_t *si; + struct open_param *op = &sr->arg.open; if (!STYPE_ISPRN(sr->tid_tree->t_res_type)) { + cmn_err(CE_WARN, "smb_com_open_print_file: bad device"); smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE, ERRDOS, ERROR_BAD_DEV_TYPE); return (SDRC_ERROR); } - - if (smb_common_create(sr) != NT_STATUS_SUCCESS) + if ((rc = smb_common_create(sr)) != NT_STATUS_SUCCESS) { + cmn_err(CE_WARN, "smb_com_open_print_file: error rc=%d", rc); return (SDRC_ERROR); - - rc = smbsr_encode_result(sr, 1, 0, "bww", 1, sr->smb_fid, 0); + } + if ((rc = smbsr_encode_result(sr, 1, 0, + "bww", 1, sr->smb_fid, 0)) == 0) { + if ((si = smb_kshare_lookup(SMB_SHARE_PRINT)) == NULL) { + cmn_err(CE_NOTE, "smb_com_open_print_file: SDRC_ERROR"); + return (SDRC_ERROR); + } + sp = kmem_zalloc(sizeof (smb_kspooldoc_t), KM_SLEEP); + (void) snprintf(sp->sd_path, MAXPATHLEN, "%s/%s", si->shr_path, + op->fqi.fq_path.pn_path); + sp->sd_spool_num = sr->sr_server->sp_info.sp_cnt; + sp->sd_ipaddr = sr->session->ipaddr; + (void) strlcpy(sp->sd_username, sr->uid_user->u_name, + MAXNAMELEN); + sp->sd_fid = sr->smb_fid; + if (smb_spool_add_doc(sp)) + kmem_free(sp, sizeof (smb_kspooldoc_t)); + smb_kshare_release(si); + } return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); } @@ -130,16 +165,34 @@ DTRACE_SMB_1(op__ClosePrintFile__done, smb_request_t *, sr); } +/* + * + * Adds the print file fid to a list to be used as a search + * key in the spooldoc list. It then wakes up the smbd + * spool monitor thread to copy the spool file. + * + * Return values + * rc - 0 success + * + */ + smb_sdrc_t smb_com_close_print_file(smb_request_t *sr) { + smb_sdrc_t rc; + if (!STYPE_ISPRN(sr->tid_tree->t_res_type)) { smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE, ERRDOS, ERROR_BAD_DEV_TYPE); + cmn_err(CE_WARN, "smb_com_close_print_file: SDRC_ERROR"); return (SDRC_ERROR); } + rc = smb_com_close(sr); - return (smb_com_close(sr)); + (void) smb_spool_add_fid(sr->smb_fid); + cv_broadcast(&sr->sr_server->sp_info.sp_cv); + + return (rc); } /*
--- a/usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.c Thu Jul 22 14:53:56 2010 -0700 @@ -50,7 +50,7 @@ * SMB_FILE_STANDARD_INFORMATION * SMB_FILE_INTERNAL_INFORMATION * SMB_FILE_EA_INFORMATION - * SMB_FILE_ACCESS_INFORMATION - not yet supported quen query by path + * SMB_FILE_ACCESS_INFORMATION - not yet supported when query by path * SMB_FILE_NAME_INFORMATION * SMB_FILE_ALL_INFORMATION * SMB_FILE_ALT_NAME_INFORMATION - not valid for pipes @@ -64,6 +64,12 @@ * SMB_QUERY_INFORMATION2 */ +/* + * SMB_STREAM_ENCODE_FIXED_SIZE: + * 2 dwords + 2 quadwords => 4 + 4 + 8 + 8 => 24 + */ +#define SMB_STREAM_ENCODE_FIXED_SZ 24 + typedef struct smb_queryinfo { smb_node_t *qi_node; /* NULL for pipes */ smb_attr_t qi_attr; @@ -90,6 +96,7 @@ uint16_t, smb_queryinfo_t *); static void smb_encode_stream_info(smb_request_t *, smb_xa_t *, smb_queryinfo_t *); +static boolean_t smb_stream_fits(smb_request_t *, smb_xa_t *, char *, uint32_t); static int smb_query_pathname(smb_request_t *, smb_node_t *, boolean_t, smb_queryinfo_t *); static void smb_query_shortname(smb_node_t *, smb_queryinfo_t *); @@ -598,8 +605,10 @@ * entries. The entries that have been read so far are returned and * no error is reported. * - * Offset calculation: - * 2 dwords + 2 quadwords => 4 + 4 + 8 + 8 => 24 + * If the response buffer is not large enough to return all of the + * named stream entries, the entries that do fit are returned and + * a warning code is set (NT_STATUS_BUFFER_OVERFLOW). The next_offset + * value in the last returned entry must be 0. */ static void smb_encode_stream_info(smb_request_t *sr, smb_xa_t *xa, smb_queryinfo_t *qinfo) @@ -647,20 +656,36 @@ if (!is_dir) { stream_name = "::$DATA"; stream_nlen = smb_ascii_or_unicode_strlen(sr, stream_name); + next_offset = SMB_STREAM_ENCODE_FIXED_SZ + stream_nlen + + smb_ascii_or_unicode_null_len(sr); - if (done) - next_offset = 0; - else - next_offset = 24 + stream_nlen + - smb_ascii_or_unicode_null_len(sr); + /* Can unnamed stream fit in response buffer? */ + if (MBC_ROOM_FOR(&xa->rep_data_mb, next_offset) == 0) { + done = B_TRUE; + smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW, + ERRDOS, ERROR_MORE_DATA); + } else { + /* Can first named stream fit in rsp buffer? */ + if (!done && !smb_stream_fits(sr, xa, sinfo->si_name, + next_offset)) { + done = B_TRUE; + smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW, + ERRDOS, ERROR_MORE_DATA); + } - (void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu", sr, - next_offset, stream_nlen, datasz, allocsz, stream_name); + if (done) + next_offset = 0; + + (void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu", sr, + next_offset, stream_nlen, datasz, allocsz, + stream_name); + } } /* - * Since last packet does not have a pad we need to check - * for the next stream before we encode the current one + * If there is no next entry, or there is not enough space in + * the response buffer for the next entry, the next_offset and + * padding are 0. */ while (!done) { stream_nlen = smb_ascii_or_unicode_strlen(sr, sinfo->si_name); @@ -669,15 +694,28 @@ rc = smb_odir_read_streaminfo(sr, od, sinfo_next, &eos); if ((rc != 0) || (eos)) { done = B_TRUE; - next_offset = 0; - pad = 0; } else { - next_offset = 24 + stream_nlen + + next_offset = SMB_STREAM_ENCODE_FIXED_SZ + + stream_nlen + smb_ascii_or_unicode_null_len(sr); pad = smb_pad_align(next_offset, 8); next_offset += pad; + + /* Can next named stream fit in response buffer? */ + if (!smb_stream_fits(sr, xa, sinfo_next->si_name, + next_offset)) { + done = B_TRUE; + smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW, + ERRDOS, ERROR_MORE_DATA); + } } - (void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu#.", + + if (done) { + next_offset = 0; + pad = 0; + } + + rc = smb_mbc_encodef(&xa->rep_data_mb, "%llqqu#.", sr, next_offset, stream_nlen, sinfo->si_size, sinfo->si_alloc_size, sinfo->si_name, pad); @@ -694,6 +732,32 @@ } /* + * smb_stream_fits + * + * Check if the named stream entry can fit in the response buffer. + * + * Required space = + * offset (size of current entry) + * + SMB_STREAM_ENCODE_FIXED_SIZE + * + length of encoded stream name + * + length of null terminator + * + alignment padding + */ +static boolean_t +smb_stream_fits(smb_request_t *sr, smb_xa_t *xa, char *name, uint32_t offset) +{ + uint32_t len, pad; + + len = SMB_STREAM_ENCODE_FIXED_SZ + + smb_ascii_or_unicode_strlen(sr, name) + + smb_ascii_or_unicode_null_len(sr); + pad = smb_pad_align(len, 8); + len += pad; + + return (MBC_ROOM_FOR(&xa->rep_data_mb, offset + len) != 0); +} + +/* * smb_query_fileinfo * * Populate smb_queryinfo_t structure for SMB_FTYPE_DISK @@ -705,6 +769,16 @@ { int rc = 0; + /* If shortname required but not supported -> OBJECT_NAME_NOT_FOUND */ + if ((infolev == SMB_QUERY_FILE_ALT_NAME_INFO) || + (infolev == SMB_FILE_ALT_NAME_INFORMATION)) { + if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_SHORTNAMES)) { + smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, + ERRDOS, ERROR_FILE_NOT_FOUND); + return (-1); + } + } + (void) bzero(qinfo, sizeof (smb_queryinfo_t)); if (smb_node_getattr(sr, node, &qinfo->qi_attr) != 0) { @@ -830,8 +904,7 @@ smb_mangle(namep, qinfo->qi_attr.sa_vattr.va_nodeid, qinfo->qi_shortname, SMB_SHORTNAMELEN); } else { - (void) strlcpy(qinfo->qi_shortname, namep, - SMB_SHORTNAMELEN); + (void) strlcpy(qinfo->qi_shortname, namep, SMB_SHORTNAMELEN); (void) smb_strupr(qinfo->qi_shortname); } }
--- a/usr/src/uts/common/fs/smbsrv/smb_read.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_read.c Thu Jul 22 14:53:56 2010 -0700 @@ -19,13 +19,18 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <smbsrv/smb_kproto.h> #include <smbsrv/smb_fsops.h> +/* + * There may be oplock break requests waiting to be sent after + * a read raw request completes. + */ +#define SMB_OPLOCK_BREAKS_PENDING(sr) \ + !list_is_empty(&(sr)->session->s_oplock_brkreqs) /* * The maximum number of bytes to return from SMB Core @@ -283,7 +288,12 @@ mbuf_chain_t *mbc; if (sr->session->s_state == SMB_SESSION_STATE_READ_RAW_ACTIVE) { - sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED; + if (SMB_OPLOCK_BREAKS_PENDING(sr)) { + sr->session->s_state = + SMB_SESSION_STATE_OPLOCK_BREAKING; + } else { + sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED; + } while ((mbc = list_head(&sr->session->s_oplock_brkreqs)) != NULL) { @@ -306,6 +316,9 @@ { smb_rw_param_t *param = sr->arg.rw; + if (!smb_raw_mode) + return (SDRC_DROP_VC); + switch (sr->session->s_state) { case SMB_SESSION_STATE_NEGOTIATED: sr->session->s_state = SMB_SESSION_STATE_READ_RAW_ACTIVE; @@ -341,7 +354,8 @@ if (param->rw_mincnt > param->rw_count) param->rw_mincnt = 0; - if (smb_common_read(sr, param) != 0) { + if ((smb_common_read(sr, param) != 0) || + (SMB_OPLOCK_BREAKS_PENDING(sr))) { (void) smb_session_send(sr->session, 0, NULL); m_freem(sr->raw_data.chain); sr->raw_data.chain = NULL; @@ -492,6 +506,12 @@ * function. We can't move the fid lookup here because lock-and-read * requires the fid to do locking before attempting the read. * + * Reading from a file should break oplocks on the file to LEVEL_II. + * A call to smb_oplock_break(SMB_OPLOCK_BREAK_TO_LEVEL_II) is not + * required as it is a no-op. If there's anything greater than a + * LEVEL_II oplock on the file, the oplock MUST be owned by the ofile + * on which the read is occuring and therefore would not be broken. + * * Returns errno values. */ int
--- a/usr/src/uts/common/fs/smbsrv/smb_rename.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_rename.c Thu Jul 22 14:53:56 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <sys/synch.h> @@ -446,7 +445,8 @@ return (EEXIST); } - (void) smb_oplock_break(dst_fnode, sr->session, B_FALSE); + (void) smb_oplock_break(sr, dst_fnode, + SMB_OPLOCK_BREAK_TO_NONE | SMB_OPLOCK_BREAK_BATCH); for (count = 0; count <= 3; count++) { if (count) { @@ -628,7 +628,7 @@ * smb_rename_lookup_src * * Lookup the src node, checking for sharing violations and - * breaking any existing oplock. + * breaking any existing BATCH oplock. * Populate sr->arg.dirop.fqi * * Upon success, the dnode and fnode will have holds and the @@ -685,11 +685,12 @@ } /* - * Break the oplock before access checks. If a client + * Break BATCH oplock before access checks. If a client * has a file open, this will force a flush or close, * which may affect the outcome of any share checking. */ - (void) smb_oplock_break(src_node, sr->session, B_FALSE); + (void) smb_oplock_break(sr, src_node, + SMB_OPLOCK_BREAK_TO_LEVEL_II | SMB_OPLOCK_BREAK_BATCH); for (count = 0; count <= 3; count++) { if (count) {
--- a/usr/src/uts/common/fs/smbsrv/smb_server.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_server.c Thu Jul 22 14:53:56 2010 -0700 @@ -229,8 +229,6 @@ #include <smbsrv/smb_door.h> #include <smbsrv/smb_kstat.h> -#define SMB_EVENT_TIMEOUT 45 /* seconds */ - extern void smb_reply_notify_change_request(smb_request_t *); static void smb_server_kstat_init(smb_server_t *); @@ -248,7 +246,6 @@ static void smb_server_fsop_stop(smb_server_t *); static void smb_server_signal_listeners(smb_server_t *); static void smb_event_cancel(smb_server_t *, uint32_t); -static void smb_event_notify(smb_server_t *, uint32_t); static uint32_t smb_event_alloc_txid(void); static void smb_server_disconnect_share(smb_session_list_t *, const char *); @@ -257,6 +254,7 @@ const char *); static int smb_server_fclose(smb_session_list_t *, uint32_t); static int smb_server_kstat_update(kstat_t *, int); +static int smb_server_legacy_kstat_update(kstat_t *, int); int smb_event_debug = 0; @@ -288,6 +286,8 @@ continue; if (rc = smb_node_init()) continue; + if (rc = smb_oplock_init()) + continue; if (rc = smb_fem_init()) continue; if (rc = smb_notify_init()) @@ -327,6 +327,7 @@ smb_notify_fini(); smb_fem_fini(); smb_node_fini(); + smb_oplock_fini(); smb_vop_fini(); smb_mbc_fini(); smb_llist_destructor(&smb_servers); @@ -372,6 +373,12 @@ smb_llist_constructor(&sv->sv_event_list, sizeof (smb_event_t), offsetof(smb_event_t, se_lnd)); + smb_llist_constructor(&sv->sp_info.sp_list, sizeof (smb_kspooldoc_t), + offsetof(smb_kspooldoc_t, sd_lnd)); + + smb_llist_constructor(&sv->sp_info.sp_fidlist, + sizeof (smb_spoolfid_t), offsetof(smb_spoolfid_t, sf_lnd)); + smb_session_list_constructor(&sv->sv_nbt_daemon.ld_session_list); smb_session_list_constructor(&sv->sv_tcp_daemon.ld_session_list); @@ -404,13 +411,24 @@ smb_server_kstat_init(sv); mutex_init(&sv->sv_mutex, NULL, MUTEX_DEFAULT, NULL); + mutex_init(&sv->sp_info.sp_mutex, NULL, MUTEX_DEFAULT, NULL); cv_init(&sv->sv_cv, NULL, CV_DEFAULT, NULL); + cv_init(&sv->sp_info.sp_cv, NULL, CV_DEFAULT, NULL); + sv->sv_state = SMB_SERVER_STATE_CREATED; sv->sv_magic = SMB_SERVER_MAGIC; sv->sv_zid = zid; smb_llist_insert_tail(&smb_servers, sv); smb_llist_exit(&smb_servers); + + smb_threshold_init(&sv->sv_ssetup_ct, SMB_SSETUP_CMD, + smb_ssetup_threshold, smb_ssetup_timeout); + smb_threshold_init(&sv->sv_tcon_ct, SMB_TCON_CMD, smb_tcon_threshold, + smb_tcon_timeout); + smb_threshold_init(&sv->sv_opipe_ct, SMB_OPIPE_CMD, smb_opipe_threshold, + smb_opipe_timeout); + return (0); } @@ -432,6 +450,10 @@ if (rc != 0) return (rc); + smb_threshold_fini(&sv->sv_ssetup_ct); + smb_threshold_fini(&sv->sv_tcon_ct); + smb_threshold_fini(&sv->sv_opipe_ct); + mutex_enter(&sv->sv_mutex); switch (sv->sv_state) { case SMB_SERVER_STATE_RUNNING: @@ -440,6 +462,7 @@ smb_server_signal_listeners(sv); nbt_tid = smb_server_listener_tid(&sv->sv_nbt_daemon); tcp_tid = smb_server_listener_tid(&sv->sv_tcp_daemon); + cv_broadcast(&sv->sp_info.sp_cv); sv->sv_state = SMB_SERVER_STATE_DELETING; mutex_exit(&sv->sv_mutex); @@ -630,6 +653,7 @@ case SMB_SERVER_STATE_RUNNING: sv->sv_state = SMB_SERVER_STATE_STOPPING; smb_server_signal_listeners(sv); + cv_broadcast(&sv->sp_info.sp_cv); break; default: SMB_SERVER_STATE_VALID(sv->sv_state); @@ -839,6 +863,54 @@ return (rc); } +/* + * smb_server_spooldoc + * + * Waits for print file close broadcast. + * Gets the head of the fid list, + * then searches the spooldoc list and returns + * this info via the ioctl to user land. + * + * rc - 0 success + */ + +int +smb_server_spooldoc(smb_ioc_spooldoc_t *ioc) +{ + smb_server_t *sv; + int rc; + smb_kspooldoc_t *spdoc; + uint16_t fid; + + if ((rc = smb_server_lookup(&sv)) == 0) { + if (sv->sv_state != SMB_SERVER_STATE_RUNNING) { + smb_server_release(sv); + return (ECANCELED); + } + mutex_enter(&sv->sp_info.sp_mutex); + spdoc = kmem_zalloc(sizeof (smb_kspooldoc_t), KM_SLEEP); + cv_wait(&sv->sp_info.sp_cv, &sv->sp_info.sp_mutex); + if (sv->sv_state != SMB_SERVER_STATE_RUNNING) + rc = ECANCELED; + else { + fid = smb_spool_get_fid(); + atomic_inc_32(&sv->sp_info.sp_cnt); + if (smb_spool_lookup_doc_byfid(fid, spdoc)) { + ioc->spool_num = spdoc->sd_spool_num; + ioc->ipaddr = spdoc->sd_ipaddr; + (void) strlcpy(ioc->path, spdoc->sd_path, + MAXPATHLEN); + (void) strlcpy(ioc->username, + spdoc->sd_username, MAXNAMELEN); + } + } + kmem_free(spdoc, sizeof (smb_kspooldoc_t)); + mutex_exit(&sv->sp_info.sp_mutex); + smb_server_release(sv); + } + return (rc); +} + int smb_server_set_gmtoff(smb_ioc_gmt_t *ioc) { @@ -1303,6 +1375,8 @@ static void smb_server_kstat_init(smb_server_t *sv) { + char name[KSTAT_STRLEN]; + sv->sv_ksp = kstat_create_zone(SMBSRV_KSTAT_MODULE, sv->sv_zid, SMBSRV_KSTAT_STATISTICS, SMBSRV_KSTAT_CLASS, KSTAT_TYPE_RAW, sizeof (smbsrv_kstats_t), 0, sv->sv_zid); @@ -1318,6 +1392,36 @@ } else { cmn_err(CE_WARN, "SMB Server: Statistics unavailable"); } + + (void) snprintf(name, sizeof (name), "%s%d", + SMBSRV_KSTAT_NAME, sv->sv_zid); + + sv->sv_legacy_ksp = kstat_create(SMBSRV_KSTAT_MODULE, sv->sv_zid, + name, SMBSRV_KSTAT_CLASS, KSTAT_TYPE_NAMED, + sizeof (smb_server_legacy_kstat_t) / sizeof (kstat_named_t), 0); + + if (sv->sv_legacy_ksp != NULL) { + smb_server_legacy_kstat_t *ksd; + + ksd = sv->sv_legacy_ksp->ks_data; + + (void) strlcpy(ksd->ls_files.name, "open_files", + sizeof (ksd->ls_files.name)); + ksd->ls_files.data_type = KSTAT_DATA_UINT32; + + (void) strlcpy(ksd->ls_trees.name, "connections", + sizeof (ksd->ls_trees.name)); + ksd->ls_trees.data_type = KSTAT_DATA_UINT32; + + (void) strlcpy(ksd->ls_users.name, "connections", + sizeof (ksd->ls_users.name)); + ksd->ls_users.data_type = KSTAT_DATA_UINT32; + + mutex_init(&sv->sv_legacy_ksmtx, NULL, MUTEX_DEFAULT, NULL); + sv->sv_legacy_ksp->ks_lock = &sv->sv_legacy_ksmtx; + sv->sv_legacy_ksp->ks_update = smb_server_legacy_kstat_update; + kstat_install(sv->sv_legacy_ksp); + } } /* @@ -1326,6 +1430,12 @@ static void smb_server_kstat_fini(smb_server_t *sv) { + if (sv->sv_legacy_ksp != NULL) { + kstat_delete(sv->sv_legacy_ksp); + mutex_destroy(&sv->sv_legacy_ksmtx); + sv->sv_legacy_ksp = NULL; + } + if (sv->sv_ksp != NULL) { kstat_delete(sv->sv_ksp); sv->sv_ksp = NULL; @@ -1379,6 +1489,38 @@ return (EIO); } +static int +smb_server_legacy_kstat_update(kstat_t *ksp, int rw) +{ + smb_server_t *sv; + smb_server_legacy_kstat_t *ksd; + int rc; + + switch (rw) { + case KSTAT_WRITE: + rc = EACCES; + break; + case KSTAT_READ: + if (!smb_server_lookup(&sv)) { + ASSERT(MUTEX_HELD(ksp->ks_lock)); + ASSERT(sv->sv_legacy_ksp == ksp); + ksd = (smb_server_legacy_kstat_t *)ksp->ks_data; + ksd->ls_files.value.ui32 = sv->sv_files + sv->sv_pipes; + ksd->ls_trees.value.ui32 = sv->sv_trees; + ksd->ls_users.value.ui32 = sv->sv_users; + smb_server_release(sv); + rc = 0; + break; + } + _NOTE(FALLTHRU) + default: + rc = EIO; + break; + } + return (rc); + +} + /* * The mutex of the server must have been entered before calling this function. */ @@ -1547,7 +1689,7 @@ static kt_did_t smb_server_listener_tid(smb_listener_daemon_t *ld) { - kt_did_t tid; + kt_did_t tid = 0; if (ld->ld_ktdid != 0) { tid = ld->ld_ktdid; @@ -1769,6 +1911,7 @@ sv->sv_cfg.skc_sync_enable = ioc->sync_enable; sv->sv_cfg.skc_secmode = ioc->secmode; sv->sv_cfg.skc_ipv6_enable = ioc->ipv6_enable; + sv->sv_cfg.skc_print_enable = ioc->print_enable; sv->sv_cfg.skc_execflags = ioc->exec_flags; sv->sv_cfg.skc_version = ioc->version; (void) strlcpy(sv->sv_cfg.skc_nbdomain, ioc->nbdomain, @@ -1823,7 +1966,7 @@ } smb_event_t * -smb_event_create(void) +smb_event_create(int timeout) { smb_server_t *sv; smb_event_t *event; @@ -1844,6 +1987,7 @@ event->se_magic = SMB_EVENT_MAGIC; event->se_txid = smb_event_alloc_txid(); event->se_server = sv; + event->se_timeout = timeout; smb_llist_enter(&sv->sv_event_list, RW_WRITER); smb_llist_insert_tail(&sv->sv_event_list, event); @@ -1920,7 +2064,7 @@ if (event->se_errno != 0) break; - if (event->se_waittime > SMB_EVENT_TIMEOUT) { + if (event->se_waittime > event->se_timeout) { event->se_errno = ETIME; break; } @@ -1978,7 +2122,7 @@ * If txid is non-zero, notify the specified event. * Otherwise, notify all events. */ -static void +void smb_event_notify(smb_server_t *sv, uint32_t txid) { smb_event_t *event; @@ -2036,3 +2180,146 @@ return (txid_ret); } + +/* + * Called by the ioctl to find the corresponding + * spooldoc node. removes node on success + * + * Return values + * rc + * B_FALSE - not found + * B_TRUE - found + * + */ + +boolean_t +smb_spool_lookup_doc_byfid(uint16_t fid, smb_kspooldoc_t *spdoc) +{ + smb_kspooldoc_t *sp; + smb_llist_t *splist; + smb_server_t *sv; + int rc; + + rc = smb_server_lookup(&sv); + if (rc) + return (B_FALSE); + + splist = &sv->sp_info.sp_list; + smb_llist_enter(splist, RW_WRITER); + sp = smb_llist_head(splist); + while (sp != NULL) { + /* + * check for a matching fid + */ + if (sp->sd_fid == fid) { + *spdoc = *sp; + smb_llist_remove(splist, sp); + smb_llist_exit(splist); + kmem_free(sp, sizeof (smb_kspooldoc_t)); + smb_server_release(sv); + return (B_TRUE); + } + sp = smb_llist_next(splist, sp); + } + cmn_err(CE_WARN, "smb_spool_lookup_user_byfid: no fid:%d", fid); + smb_llist_exit(splist); + smb_server_release(sv); + return (B_FALSE); +} + +/* + * Adds the spool fid to a linked list to be used + * as a search key in the spooldoc queue + * + * Return values + * rc non-zero error + * rc zero success + * + */ + +int +smb_spool_add_fid(uint16_t fid) +{ + smb_llist_t *fidlist; + smb_server_t *sv; + smb_spoolfid_t *sf; + int rc = 0; + + rc = smb_server_lookup(&sv); + if (rc) + return (rc); + + sf = kmem_zalloc(sizeof (smb_spoolfid_t), KM_SLEEP); + fidlist = &sv->sp_info.sp_fidlist; + smb_llist_enter(fidlist, RW_WRITER); + sf->sf_fid = fid; + smb_llist_insert_tail(fidlist, sf); + smb_llist_exit(fidlist); + smb_server_release(sv); + return (rc); +} + +/* + * Called by the ioctl to get and remove the head of the fid list + * + * Return values + * int fd + * greater than 0 success + * 0 - error + * + */ + +uint16_t +smb_spool_get_fid() +{ + smb_spoolfid_t *spfid; + smb_llist_t *splist; + smb_server_t *sv; + int rc = 0; + uint16_t fid; + + rc = smb_server_lookup(&sv); + if (rc) + return (0); + + splist = &sv->sp_info.sp_fidlist; + smb_llist_enter(splist, RW_WRITER); + spfid = smb_llist_head(splist); + if (spfid != NULL) { + fid = spfid->sf_fid; + smb_llist_remove(&sv->sp_info.sp_fidlist, spfid); + kmem_free(spfid, sizeof (smb_spoolfid_t)); + } else { + fid = 0; + } + smb_llist_exit(splist); + smb_server_release(sv); + return (fid); +} + +/* + * Adds the spooldoc to the tail of the spooldoc list + * + * Return values + * rc non-zero error + * rc zero success + */ +int +smb_spool_add_doc(smb_kspooldoc_t *sp) +{ + smb_llist_t *splist; + smb_server_t *sv; + int rc = 0; + + rc = smb_server_lookup(&sv); + if (rc) + return (rc); + + splist = &sv->sp_info.sp_list; + smb_llist_enter(splist, RW_WRITER); + sp->sd_spool_num = sv->sp_info.sp_cnt; + smb_llist_insert_tail(splist, sp); + smb_llist_exit(splist); + smb_server_release(sv); + return (rc); +}
--- a/usr/src/uts/common/fs/smbsrv/smb_session.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_session.c Thu Jul 22 14:53:56 2010 -0700 @@ -1284,8 +1284,10 @@ ASSERT(sr->session); ASSERT(sr->r_xa == NULL); - if (sr->fid_ofile != NULL) + if (sr->fid_ofile != NULL) { + smb_ofile_request_complete(sr->fid_ofile); smb_ofile_release(sr->fid_ofile); + } if (sr->tid_tree != NULL) smb_tree_release(sr->tid_tree); @@ -1334,17 +1336,22 @@ return (B_TRUE); } +boolean_t +smb_session_levelII_oplocks(smb_session_t *session) +{ + SMB_SESSION_VALID(session); + return (session->capabilities & CAP_LEVEL_II_OPLOCKS); +} + /* - * smb_session_breaking_oplock + * smb_session_oplock_break * - * This MUST be a cross-session call, i.e. the caller must be in a different - * context than the one passed. The mutex of the SMB node requiring an oplock - * break MUST be dropped before calling this function. This last requirement is - * due to a potential deadlock that can occur when trying to enter the lock of - * the session passed in. + * The session lock must NOT be held by the caller of this thread; + * as this would cause a deadlock. */ void -smb_session_oplock_break(smb_session_t *session, smb_ofile_t *of) +smb_session_oplock_break(smb_session_t *session, + uint16_t tid, uint16_t fid, uint8_t brk) { mbuf_chain_t *mbc; @@ -1352,17 +1359,19 @@ mbc = smb_mbc_alloc(MLEN); - (void) smb_mbc_encodef(mbc, "Mb19.wwwwbb3.ww10.", + (void) smb_mbc_encodef(mbc, "Mb19.wwwwbb3.wbb10.", SMB_COM_LOCKING_ANDX, - SMB_TREE_GET_TID(SMB_OFILE_GET_TREE(of)), + tid, 0xFFFF, 0, 0xFFFF, 8, 0xFF, - SMB_OFILE_GET_FID(of), - LOCKING_ANDX_OPLOCK_RELEASE); + fid, + LOCKING_ANDX_OPLOCK_RELEASE, + (brk == SMB_OPLOCK_BREAK_TO_LEVEL_II) ? 1 : 0); smb_rwx_rwenter(&session->s_lock, RW_WRITER); switch (session->s_state) { case SMB_SESSION_STATE_NEGOTIATED: case SMB_SESSION_STATE_OPLOCK_BREAKING: + case SMB_SESSION_STATE_WRITE_RAW_ACTIVE: session->s_state = SMB_SESSION_STATE_OPLOCK_BREAKING; (void) smb_session_send(session, 0, mbc); smb_mbc_free(mbc);
--- a/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c Thu Jul 22 14:53:56 2010 -0700 @@ -33,6 +33,8 @@ static int smb_authenticate(smb_request_t *, smb_arg_sessionsetup_t *, smb_session_key_t **); +static int smb_authenticate_core(smb_request_t *, smb_arg_sessionsetup_t *, + smb_session_key_t **); static cred_t *smb_cred_create(smb_token_t *); static void smb_cred_set_sid(smb_id_t *id, ksid_t *ksid); static ksidlist_t *smb_cred_set_sidlist(smb_ids_t *token_grps); @@ -188,6 +190,9 @@ sinfo->ssi_capabilities |= CAP_LARGE_FILES | CAP_LARGE_READX | CAP_LARGE_WRITEX; + if (!smb_oplock_levelII) + sr->session->capabilities &= ~CAP_LEVEL_II_OPLOCKS; + sr->session->capabilities = sinfo->ssi_capabilities; if (!(sr->session->signing.flags & SMB_SIGNING_ENABLED) && @@ -223,6 +228,23 @@ return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); } +static int +smb_authenticate(smb_request_t *sr, smb_arg_sessionsetup_t *sinfo, + smb_session_key_t **session_key) +{ + int rc; + smb_server_t *sv = sr->sr_server; + + if (smb_threshold_enter(&sv->sv_ssetup_ct) != 0) { + smbsr_error(sr, RPC_NT_SERVER_TOO_BUSY, 0, 0); + return (-1); + } + + rc = smb_authenticate_core(sr, sinfo, session_key); + smb_threshold_exit(&sv->sv_ssetup_ct, sv); + return (rc); +} + /* * Authenticate a user. If the user has already been authenticated on * this session, we can simply dup the user and return. @@ -232,7 +254,7 @@ * generate a cred and new user based on the token. */ static int -smb_authenticate(smb_request_t *sr, smb_arg_sessionsetup_t *sinfo, +smb_authenticate_core(smb_request_t *sr, smb_arg_sessionsetup_t *sinfo, smb_session_key_t **session_key) { char *hostname = sr->sr_cfg->skc_hostname;
--- a/usr/src/uts/common/fs/smbsrv/smb_set_fileinfo.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_set_fileinfo.c Thu Jul 22 14:53:56 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ /* @@ -305,11 +304,6 @@ return (-1); } - /* Break any conflicting oplock for subsequent attribute setting */ - if (smb_oplock_conflict(node, sr->session, NULL)) { - (void) smb_oplock_break(node, sr->session, B_FALSE); - } - sinfo.si_xa = xa; sinfo.si_infolev = infolev; sinfo.si_node = node; @@ -599,6 +593,11 @@ return (-1); } + /* If opened by path, break exclusive oplock */ + if (sr->fid_ofile == NULL) + (void) smb_oplock_break(sr, node, + SMB_OPLOCK_BREAK_EXCLUSIVE | SMB_OPLOCK_BREAK_TO_NONE); + bzero(&attr, sizeof (smb_attr_t)); attr.sa_mask = SMB_AT_SIZE; attr.sa_vattr.va_size = (u_offset_t)eof; @@ -608,6 +607,7 @@ return (-1); } + smb_oplock_break_levelII(node); return (0); } @@ -631,6 +631,11 @@ return (-1); } + /* If opened by path, break exclusive oplock */ + if (sr->fid_ofile == NULL) + (void) smb_oplock_break(sr, node, + SMB_OPLOCK_BREAK_EXCLUSIVE | SMB_OPLOCK_BREAK_TO_NONE); + bzero(&attr, sizeof (smb_attr_t)); attr.sa_mask = SMB_AT_ALLOCSZ; attr.sa_allocsz = (u_offset_t)allocsz; @@ -640,6 +645,7 @@ return (-1); } + smb_oplock_break_levelII(node); return (0); } @@ -711,10 +717,14 @@ /* * smb_set_rename_info * - * Explicity specified parameter validation rules: + * Explicitly specified parameter validation rules: * - If rootdir is not NULL respond with NT_STATUS_INVALID_PARAMETER. * - If the filename contains a separator character respond with * NT_STATUS_INVALID_PARAMETER. + * + * Oplock break: + * Some Windows servers break BATCH oplocks prior to the rename. + * W2K3 does not. We behave as W2K3; we do not send an oplock break. */ static int smb_set_rename_info(smb_request_t *sr, smb_setinfo_t *sinfo)
--- a/usr/src/uts/common/fs/smbsrv/smb_tree.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_tree.c Thu Jul 22 14:53:56 2010 -0700 @@ -166,9 +166,11 @@ #include <smbsrv/smb_kproto.h> #include <smbsrv/smb_ktypes.h> #include <smbsrv/smb_fsops.h> +#include <smbsrv/smb_share.h> int smb_tcon_mute = 0; +static smb_tree_t *smb_tree_connect_core(smb_request_t *); static smb_tree_t *smb_tree_connect_disk(smb_request_t *, const char *); static smb_tree_t *smb_tree_connect_printq(smb_request_t *, const char *); static smb_tree_t *smb_tree_connect_ipc(smb_request_t *, const char *); @@ -190,6 +192,22 @@ static void smb_tree_netinfo_init(smb_tree_t *tree, smb_netconnectinfo_t *); static void smb_tree_netinfo_fini(smb_netconnectinfo_t *); +smb_tree_t * +smb_tree_connect(smb_request_t *sr) +{ + smb_tree_t *tree; + smb_server_t *sv = sr->sr_server; + + if (smb_threshold_enter(&sv->sv_tcon_ct) != 0) { + smbsr_error(sr, RPC_NT_SERVER_TOO_BUSY, 0, 0); + return (NULL); + } + + tree = smb_tree_connect_core(sr); + smb_threshold_exit(&sv->sv_tcon_ct, sv); + return (tree); +} + /* * Lookup the share name dispatch the appropriate stype handler. * Share names are case insensitive so we map the share name to @@ -202,8 +220,8 @@ * COMM Communications device * ????? Any type of device (wildcard) */ -smb_tree_t * -smb_tree_connect(smb_request_t *sr) +static smb_tree_t * +smb_tree_connect_core(smb_request_t *sr) { char *unc_path = sr->sr_tcon.path; smb_tree_t *tree = NULL; @@ -223,6 +241,14 @@ smbsr_error(sr, 0, ERRSRV, ERRinvnetname); return (NULL); } + + if (!strcasecmp(SMB_SHARE_PRINT, name)) { + smb_kshare_release(si); + smb_tree_log(sr, name, "access not permitted"); + smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess); + return (NULL); + } + sr->sr_tcon.si = si; switch (si->shr_type & STYPE_MASK) { @@ -681,6 +707,10 @@ if (si->shr_flags & SMB_SHRF_DFSROOT) sr->sr_tcon.optional_support |= SMB_SHARE_IS_IN_DFS; + /* if 'smb' zfs property: shortnames=disabled */ + if (!smb_shortnames) + sr->arg.tcon.optional_support |= SMB_UNIQUE_FILE_NAME; + tree = smb_tree_alloc(user, si, snode, access, sr->sr_cfg->skc_execflags); @@ -835,6 +865,10 @@ tree = kmem_cache_alloc(user->u_server->si_cache_tree, KM_SLEEP); bzero(tree, sizeof (smb_tree_t)); + tree->t_user = user; + tree->t_session = user->u_session; + tree->t_server = user->u_server; + if (STYPE_ISDSK(stype) || STYPE_ISPRN(stype)) { if (smb_tree_getattr(si, snode, tree) != 0) { smb_idpool_free(&user->u_tid_pool, tid); @@ -869,9 +903,6 @@ mutex_init(&tree->t_mutex, NULL, MUTEX_DEFAULT, NULL); - tree->t_user = user; - tree->t_session = user->u_session; - tree->t_server = user->u_server; tree->t_refcnt = 1; tree->t_tid = tid; tree->t_res_type = stype; @@ -1095,15 +1126,21 @@ if (si->shr_flags & SMB_SHRF_ABE) flags |= SMB_TREE_ABE; + if (smb_session_oplocks_enable(tree->t_session)) { + /* if 'smb' zfs property: oplocks=enabled */ + flags |= SMB_TREE_OPLOCKS; + } + + /* if 'smb' zfs property: shortnames=enabled */ + if (smb_shortnames) + flags |= SMB_TREE_SHORTNAMES; + if (vfsp->vfs_flag & VFS_RDONLY) flags |= SMB_TREE_READONLY; if (vfsp->vfs_flag & VFS_XATTR) flags |= SMB_TREE_STREAMS; - if (vfs_optionisset(vfsp, MNTOPT_NOATIME, NULL)) - flags |= SMB_TREE_NO_ATIME; - name = vfssw[vfsp->vfs_fstype].vsw_name; for (i = 0; i < sizeof (smb_mtype) / sizeof (smb_mtype[0]); ++i) {
--- a/usr/src/uts/common/fs/smbsrv/smb_tree_connect.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_tree_connect.c Thu Jul 22 14:53:56 2010 -0700 @@ -23,7 +23,7 @@ */ #include <smbsrv/smb_kproto.h> - +#include <smbsrv/smb_share.h> /* * SmbTreeConnect: Map a share to a tree and obtain a tree-id (TID).
--- a/usr/src/uts/common/fs/smbsrv/smb_write.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_write.c Thu Jul 22 14:53:56 2010 -0700 @@ -490,6 +490,9 @@ smb_ofile_set_write_time_pending(ofile); + if (!smb_node_is_dir(node)) + smb_oplock_break_levelII(node); + param->rw_count = lcount; break;
--- a/usr/src/uts/common/fs/smbsrv/smb_write_raw.c Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/fs/smbsrv/smb_write_raw.c Thu Jul 22 14:53:56 2010 -0700 @@ -255,6 +255,12 @@ if (sr->session->s_state != SMB_SESSION_STATE_WRITE_RAW_ACTIVE) return (SDRC_DROP_VC); + if (!smb_raw_mode) { + smbsr_error(sr, NT_STATUS_NOT_SUPPORTED, ERRDOS, + ERROR_NOT_SUPPORTED); + return (SDRC_ERROR); + } + smbsr_lookup_file(sr); if (sr->fid_ofile == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
--- a/usr/src/uts/common/smbsrv/Makefile Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/smbsrv/Makefile Thu Jul 22 14:53:56 2010 -0700 @@ -72,6 +72,7 @@ netlogon.ndl \ rpcpdu.ndl \ samrpc.ndl \ + security.ndl \ spoolss.ndl \ srvsvc.ndl \ svcctl.ndl \
--- a/usr/src/uts/common/smbsrv/ndl/samrpc.ndl Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/smbsrv/ndl/samrpc.ndl Thu Jul 22 14:53:56 2010 -0700 @@ -32,7 +32,7 @@ #include "ndrtypes.ndl" /* Windows NT */ -#define SAMR_OPNUM_ConnectAnon 0x00 /* SamrConnect */ +#define SAMR_OPNUM_Connect 0x00 /* SamrConnect */ #define SAMR_OPNUM_CloseHandle 0x01 #define SAMR_OPNUM_SetSecObject 0x02 #define SAMR_OPNUM_QuerySecObject 0x03 @@ -91,16 +91,16 @@ #define SAMR_OPNUM_ChangeUserOemPassword 0x36 #define SAMR_OPNUM_ChangeUserPasswd 0x37 /* UnicodePasswd */ #define SAMR_OPNUM_GetDomainPwInfo 0x38 -#define SAMR_OPNUM_Connect 0x39 /* SamrConnect2 */ +#define SAMR_OPNUM_Connect2 0x39 /* SamrConnect2 */ #define SAMR_OPNUM_SetUserInfo 0x3a #define SAMR_OPNUM_SetBootKeyInformation 0x3b #define SAMR_OPNUM_GetBootKeyInformation 0x3c -#define SAMR_OPNUM_Connect2 0x3d /* SamrConnect3 */ -#define SAMR_OPNUM_Connect3 0x3e /* SamrConnect4 */ +#define SAMR_OPNUM_Connect3 0x3d /* NotUsedOnWire */ +#define SAMR_OPNUM_Connect4 0x3e /* SamrConnect4 */ #define SAMR_OPNUM_ChangeUserUnicodePassword3 0x3f /* Windows XP and Windows Server 2003 */ -#define SAMR_OPNUM_Connect4 0x40 /* SamrConnect5 */ +#define SAMR_OPNUM_Connect5 0x40 /* SamrConnect5 */ #define SAMR_OPNUM_RidToSid 0x41 #define SAMR_OPNUM_SetDSRMPassword 0x42 #define SAMR_OPNUM_ValidatePassword 0x43 @@ -362,12 +362,11 @@ /* *********************************************************************** - * ConnectAnon. It looks like the SAM handle is identical to an LSA - * handle. See Connect. + * SamrConnect. *********************************************************************** */ -OPERATION(SAMR_OPNUM_ConnectAnon) -struct samr_ConnectAnon { +OPERATION(SAMR_OPNUM_Connect) +struct samr_Connect { IN DWORD *servername; IN DWORD access_mask; OUT samr_handle_t handle; @@ -377,12 +376,11 @@ /* *********************************************************************** - * Connect. I'm not sure what the difference is between Connect and - * ConnectAnon but this call seems to work better than ConnectAnon. + * SamrConnect2. *********************************************************************** */ -OPERATION(SAMR_OPNUM_Connect) -struct samr_Connect { +OPERATION(SAMR_OPNUM_Connect2) +struct samr_Connect2 { IN LPTSTR servername; IN DWORD access_mask; OUT samr_handle_t handle; @@ -392,14 +390,12 @@ /* *********************************************************************** - * SamrConnect3. A new form of connect first seen with Windows 2000. + * SamrConnect4. A new form of connect first seen with Windows 2000. * A new field has been added to the input request. Value: 0x00000002. - * I haven't looked at the Win2K response yet to see if it differs - * from SAMR_OPNUM_Connect. *********************************************************************** */ -OPERATION(SAMR_OPNUM_Connect3) -struct samr_Connect3 { +OPERATION(SAMR_OPNUM_Connect4) +struct samr_Connect4 { IN LPTSTR servername; IN DWORD revision; IN DWORD access_mask; @@ -410,7 +406,7 @@ /* *********************************************************************** - * SamrConnect4. A new form of connect first seen with Windows XP. + * SamrConnect5. A new form of connect first seen with Windows XP. * The server name is the fully qualified domain name, i.e. * \\server.sun.com. * @@ -437,8 +433,8 @@ DEFAULT char *nullptr; }; -OPERATION(SAMR_OPNUM_Connect4) -struct samr_Connect4 { +OPERATION(SAMR_OPNUM_Connect5) +struct samr_Connect5 { IN LPTSTR servername; IN DWORD access_mask; INOUT DWORD unknown2_00000001; @@ -1426,8 +1422,8 @@ */ INTERFACE(0) union samr_interface { - CASE(SAMR_OPNUM_ConnectAnon) - struct samr_ConnectAnon ConnectAnon; + CASE(SAMR_OPNUM_Connect) + struct samr_Connect Connect; CASE(SAMR_OPNUM_CloseHandle) struct samr_CloseHandle CloseHandle; CASE(SAMR_OPNUM_LookupDomain) @@ -1466,14 +1462,14 @@ struct samr_ChangeUserPasswd ChangeUserPasswd; CASE(SAMR_OPNUM_GetDomainPwInfo) struct samr_GetDomainPwInfo GetDomainPwInfo; - CASE(SAMR_OPNUM_Connect) - struct samr_Connect Connect; + CASE(SAMR_OPNUM_Connect2) + struct samr_Connect2 Connect2; CASE(SAMR_OPNUM_SetUserInfo) struct samr_SetUserInfo SetUserInfo; - CASE(SAMR_OPNUM_Connect3) - struct samr_Connect3 Connect3; CASE(SAMR_OPNUM_Connect4) struct samr_Connect4 Connect4; + CASE(SAMR_OPNUM_Connect5) + struct samr_Connect5 Connect5; CASE(SAMR_OPNUM_QueryDispInfo) struct samr_QueryDispInfo QueryDispInfo; CASE(SAMR_OPNUM_OpenAlias)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/uts/common/smbsrv/ndl/security.ndl Thu Jul 22 14:53:56 2010 -0700 @@ -0,0 +1,347 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + */ + +#ifndef _SECURITY_NDL_ +#define _SECURITY_NDL_ + +#define USE_UINT_ENUMS 1 + +struct GUID { + DWORD time_low; + WORD time_mid; + WORD time_hi_and_version; + BYTE clock_seq[2]; + BYTE node[6]; +}; + +#define SEC_MASK_GENERIC 0xF0000000 +#define SEC_MASK_FLAGS 0x0F000000 +#define SEC_MASK_STANDARD 0x00FF0000 +#define SEC_MASK_SPECIFIC 0x0000FFFF +#define SEC_GENERIC_ALL 0x10000000 +#define SEC_GENERIC_EXECUTE 0x20000000 +#define SEC_GENERIC_WRITE 0x40000000 +#define SEC_GENERIC_READ 0x80000000 +#define SEC_FLAG_SYSTEM_SECURITY 0x01000000 +#define SEC_FLAG_MAXIMUM_ALLOWED 0x02000000 +#define SEC_STD_DELETE 0x00010000 +#define SEC_STD_READ_CONTROL 0x00020000 +#define SEC_STD_WRITE_DAC 0x00040000 +#define SEC_STD_WRITE_OWNER 0x00080000 +#define SEC_STD_SYNCHRONIZE 0x00100000 +#define SEC_STD_REQUIRED 0x000F0000 +#define SEC_STD_ALL 0x001F0000 +#define SEC_FILE_READ_DATA 0x00000001 +#define SEC_FILE_WRITE_DATA 0x00000002 +#define SEC_FILE_APPEND_DATA 0x00000004 +#define SEC_FILE_READ_EA 0x00000008 +#define SEC_FILE_WRITE_EA 0x00000010 +#define SEC_FILE_EXECUTE 0x00000020 +#define SEC_FILE_READ_ATTRIBUTE 0x00000080 +#define SEC_FILE_WRITE_ATTRIBUTE 0x00000100 +#define SEC_FILE_ALL 0x000001ff +#define SEC_DIR_LIST 0x00000001 +#define SEC_DIR_ADD_FILE 0x00000002 +#define SEC_DIR_ADD_SUBDIR 0x00000004 +#define SEC_DIR_READ_EA 0x00000008 +#define SEC_DIR_WRITE_EA 0x00000010 +#define SEC_DIR_TRAVERSE 0x00000020 +#define SEC_DIR_DELETE_CHILD 0x00000040 +#define SEC_DIR_READ_ATTRIBUTE 0x00000080 +#define SEC_DIR_WRITE_ATTRIBUTE 0x00000100 +#define SEC_REG_QUERY_VALUE 0x00000001 +#define SEC_REG_SET_VALUE 0x00000002 +#define SEC_REG_CREATE_SUBKEY 0x00000004 +#define SEC_REG_ENUM_SUBKEYS 0x00000008 +#define SEC_REG_NOTIFY 0x00000010 +#define SEC_REG_CREATE_LINK 0x00000020 +#define SEC_ADS_CREATE_CHILD 0x00000001 +#define SEC_ADS_DELETE_CHILD 0x00000002 +#define SEC_ADS_LIST 0x00000004 +#define SEC_ADS_SELF_WRITE 0x00000008 +#define SEC_ADS_READ_PROP 0x00000010 +#define SEC_ADS_WRITE_PROP 0x00000020 +#define SEC_ADS_DELETE_TREE 0x00000040 +#define SEC_ADS_LIST_OBJECT 0x00000080 +#define SEC_ADS_CONTROL_ACCESS 0x00000100 +#define SEC_RIGHTS_FILE_READ SEC_STD_READ_CONTROL|SEC_STD_SYNCHRONIZE|SEC_FILE_READ_DATA|SEC_FILE_READ_ATTRIBUTE|SEC_FILE_READ_EA +#define SEC_RIGHTS_FILE_WRITE SEC_STD_READ_CONTROL|SEC_STD_SYNCHRONIZE|SEC_FILE_WRITE_DATA|SEC_FILE_WRITE_ATTRIBUTE|SEC_FILE_WRITE_EA|SEC_FILE_APPEND_DATA +#define SEC_RIGHTS_FILE_EXECUTE SEC_STD_SYNCHRONIZE|SEC_STD_READ_CONTROL|SEC_FILE_READ_ATTRIBUTE|SEC_FILE_EXECUTE +#define SEC_RIGHTS_FILE_ALL SEC_STD_ALL|SEC_FILE_ALL +#define SEC_RIGHTS_DIR_READ SEC_RIGHTS_FILE_READ +#define SEC_RIGHTS_DIR_WRITE SEC_RIGHTS_FILE_WRITE +#define SEC_RIGHTS_DIR_EXECUTE SEC_RIGHTS_FILE_EXECUTE +#define SEC_RIGHTS_DIR_ALL SEC_RIGHTS_FILE_ALL +#define SID_NULL "S-1-0-0" +#define SID_WORLD_DOMAIN "S-1-1" +#define SID_WORLD "S-1-1-0" +#define SID_CREATOR_OWNER_DOMAIN "S-1-3" +#define SID_CREATOR_OWNER "S-1-3-0" +#define SID_CREATOR_GROUP "S-1-3-1" +#define SID_NT_AUTHORITY "S-1-5" +#define SID_NT_DIALUP "S-1-5-1" +#define SID_NT_NETWORK "S-1-5-2" +#define SID_NT_BATCH "S-1-5-3" +#define SID_NT_INTERACTIVE "S-1-5-4" +#define SID_NT_SERVICE "S-1-5-6" +#define SID_NT_ANONYMOUS "S-1-5-7" +#define SID_NT_PROXY "S-1-5-8" +#define SID_NT_ENTERPRISE_DCS "S-1-5-9" +#define SID_NT_SELF "S-1-5-10" +#define SID_NT_AUTHENTICATED_USERS "S-1-5-11" +#define SID_NT_RESTRICTED "S-1-5-12" +#define SID_NT_TERMINAL_SERVER_USERS "S-1-5-13" +#define SID_NT_REMOTE_INTERACTIVE "S-1-5-14" +#define SID_NT_THIS_ORGANISATION "S-1-5-15" +#define SID_NT_SYSTEM "S-1-5-18" +#define SID_NT_LOCAL_SERVICE "S-1-5-19" +#define SID_NT_NETWORK_SERVICE "S-1-5-20" +#define SID_BUILTIN "S-1-5-32" +#define SID_BUILTIN_ADMINISTRATORS "S-1-5-32-544" +#define SID_BUILTIN_USERS "S-1-5-32-545" +#define SID_BUILTIN_GUESTS "S-1-5-32-546" +#define SID_BUILTIN_POWER_USERS "S-1-5-32-547" +#define SID_BUILTIN_ACCOUNT_OPERATORS "S-1-5-32-548" +#define SID_BUILTIN_SERVER_OPERATORS "S-1-5-32-549" +#define SID_BUILTIN_PRINT_OPERATORS "S-1-5-32-550" +#define SID_BUILTIN_BACKUP_OPERATORS "S-1-5-32-551" +#define SID_BUILTIN_REPLICATOR "S-1-5-32-552" +#define SID_BUILTIN_RAS_SERVERS "S-1-5-32-553" +#define SID_BUILTIN_PREW2K "S-1-5-32-554" +#define DOMAIN_RID_LOGON 9 +#define DOMAIN_RID_ADMINISTRATOR 500 +#define DOMAIN_RID_GUEST 501 +#define DOMAIN_RID_ADMINS 512 +#define DOMAIN_RID_USERS 513 +#define DOMAIN_RID_DCS 516 +#define DOMAIN_RID_CERT_ADMINS 517 +#define DOMAIN_RID_SCHEMA_ADMINS 518 +#define DOMAIN_RID_ENTERPRISE_ADMINS 519 +#define NT4_ACL_REVISION SECURITY_ACL_REVISION_NT4 +#define SD_REVISION SECURITY_DESCRIPTOR_REVISION_1 + +#ifndef USE_UINT_ENUMS + enum sec_privilege { + SEC_PRIV_SECURITY=1, + SEC_PRIV_BACKUP=2, + SEC_PRIV_RESTORE=3, + SEC_PRIV_SYSTEMTIME=4, + SEC_PRIV_SHUTDOWN=5, + SEC_PRIV_REMOTE_SHUTDOWN=6, + SEC_PRIV_TAKE_OWNERSHIP=7, + SEC_PRIV_DEBUG=8, + SEC_PRIV_SYSTEM_ENVIRONMENT=9, + SEC_PRIV_SYSTEM_PROFILE=10, + SEC_PRIV_PROFILE_SINGLE_PROCESS=11, + SEC_PRIV_INCREASE_BASE_PRIORITY=12, + SEC_PRIV_LOAD_DRIVER=13, + SEC_PRIV_CREATE_PAGEFILE=14, + SEC_PRIV_INCREASE_QUOTA=15, + SEC_PRIV_CHANGE_NOTIFY=16, + SEC_PRIV_UNDOCK=17, + SEC_PRIV_MANAGE_VOLUME=18, + SEC_PRIV_IMPERSONATE=19, + SEC_PRIV_CREATE_GLOBAL=20, + SEC_PRIV_ENABLE_DELEGATION=21, + SEC_PRIV_INTERACTIVE_LOGON=22, + SEC_PRIV_NETWORK_LOGON=23, + SEC_PRIV_REMOTE_INTERACTIVE_LOGON=24 +}; +#else + +#define SEC_PRIV_SECURITY 1 +#define SEC_PRIV_BACKUP 2 +#define SEC_PRIV_RESTORE 3 +#define SEC_PRIV_SYSTEMTIME 4 +#define SEC_PRIV_SHUTDOWN 5 +#define SEC_PRIV_REMOTE_SHUTDOWN 6 +#define SEC_PRIV_TAKE_OWNERSHIP 7 +#define SEC_PRIV_DEBUG 8 +#define SEC_PRIV_SYSTEM_ENVIRONMENT 9 +#define SEC_PRIV_SYSTEM_PROFILE 10 +#define SEC_PRIV_PROFILE_SINGLE_PROCESS 11 +#define SEC_PRIV_INCREASE_BASE_PRIORITY 12 +#define SEC_PRIV_LOAD_DRIVER 13 +#define SEC_PRIV_CREATE_PAGEFILE 14 +#define SEC_PRIV_INCREASE_QUOTA 15 +#define SEC_PRIV_CHANGE_NOTIFY 16 +#define SEC_PRIV_UNDOCK 17 +#define SEC_PRIV_MANAGE_VOLUME 18 +#define SEC_PRIV_IMPERSONATE 19 +#define SEC_PRIV_CREATE_GLOBAL 20 +#define SEC_PRIV_ENABLE_DELEGATION 21 +#define SEC_PRIV_INTERACTIVE_LOGON 22 +#define SEC_PRIV_NETWORK_LOGON 23 +#define SEC_PRIV_REMOTE_INTERACTIVE_LOGON 24 +#endif + +struct dom_sid { + BYTE sid_rev_num; + BYTE num_auths; + BYTE id_auth[6]; + DWORD *sub_auths; +}; + +/* + * bitmap security_ace_flags + */ +#define SEC_ACE_FLAG_OBJECT_INHERIT 0x01 +#define SEC_ACE_FLAG_CONTAINER_INHERIT 0x02 +#define SEC_ACE_FLAG_NO_PROPAGATE_INHERIT 0x04 +#define SEC_ACE_FLAG_INHERIT_ONLY 0x08 +#define SEC_ACE_FLAG_INHERITED_ACE 0x10 +#define SEC_ACE_FLAG_VALID_INHERIT 0x0f +#define SEC_ACE_FLAG_SUCCESSFUL_ACCESS 0x40 +#define SEC_ACE_FLAG_FAILED_ACCESS 0x80 + +#ifndef USE_UINT_ENUMS +enum security_ace_type { + SEC_ACE_TYPE_ACCESS_ALLOWED=0, + SEC_ACE_TYPE_ACCESS_DENIED=1, + SEC_ACE_TYPE_SYSTEM_AUDIT=2, + SEC_ACE_TYPE_SYSTEM_ALARM=3, + SEC_ACE_TYPE_ALLOWED_COMPOUND=4, + SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT=5, + SEC_ACE_TYPE_ACCESS_DENIED_OBJECT=6, + SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT=7, + SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT=8 +}; +#else +#define SEC_ACE_TYPE_ACCESS_ALLOWED 0 +#define SEC_ACE_TYPE_ACCESS_DENIED 1 +#define SEC_ACE_TYPE_SYSTEM_AUDIT 2 +#define SEC_ACE_TYPE_SYSTEM_ALARM 3 +#define SEC_ACE_TYPE_ALLOWED_COMPOUND 4 +#define SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT 5 +#define SEC_ACE_TYPE_ACCESS_DENIED_OBJECT 6 +#define SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT 7 +#define SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT 8 +#endif + +/* + * bitmap security_ace_object_flags + */ +#define SEC_ACE_OBJECT_TYPE_PRESENT 0x00000001 +#define SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT 0x00000002 + +union security_ace_object_type { + CASE(0) struct GUID type; +}; + +union security_ace_object_inherited_type { + CASE(0) struct GUID inherited_type; +}; + +struct security_ace_object { + DWORD flags; +}; + +union security_ace_object_ctr { + CASE(0) struct security_ace_object object; +}; + +struct security_ace { + DWORD security_ace_type; + BYTE flags; + WORD size; + DWORD access_mask; + struct dom_sid trustee; +}; + +#ifndef USE_UINT_ENUMS +enum security_acl_revision { + SECURITY_ACL_REVISION_NT4=2, + SECURITY_ACL_REVISION_ADS=4 +}; +#else +#define SECURITY_ACL_REVISION_NT4 2 +#define SECURITY_ACL_REVISION_ADS 4 +#endif + +struct security_acl { + DWORD security_acl_revision; + WORD size; + DWORD num_aces; + struct security_ace *aces; +}; + +#ifndef USE_UINT_ENUMS +enum security_descriptor_revision { + SECURITY_DESCRIPTOR_REVISION_1=1 +}; +#else +#define SECURITY_DESCRIPTOR_REVISION_1 1 +#endif + +/* + * bitmap security_descriptor_type + */ +#define SEC_DESC_OWNER_DEFAULTED 0x0001 +#define SEC_DESC_GROUP_DEFAULTED 0x0002 +#define SEC_DESC_DACL_PRESENT 0x0004 +#define SEC_DESC_DACL_DEFAULTED 0x0008 +#define SEC_DESC_SACL_PRESENT 0x0010 +#define SEC_DESC_SACL_DEFAULTED 0x0020 +#define SEC_DESC_DACL_TRUSTED 0x0040 +#define SEC_DESC_SERVER_SECURITY 0x0080 +#define SEC_DESC_DACL_AUTO_INHERIT_REQ 0x0100 +#define SEC_DESC_SACL_AUTO_INHERIT_REQ 0x0200 +#define SEC_DESC_DACL_AUTO_INHERITED 0x0400 +#define SEC_DESC_SACL_AUTO_INHERITED 0x0800 +#define SEC_DESC_DACL_PROTECTED 0x1000 +#define SEC_DESC_SACL_PROTECTED 0x2000 +#define SEC_DESC_RM_CONTROL_VALID 0x4000 +#define SEC_DESC_SELF_RELATIVE 0x8000 + +struct security_descriptor { + WORD revision; + WORD type; + DWORD ownersid; + DWORD groupsid; + DWORD sacl; + DWORD dacl; +}; + +struct sec_desc_buf { + DWORD sd_size; + struct security_descriptor *sd; +}; + +struct security_token { + struct dom_sid *user_sid; + struct dom_sid *group_sid; + DWORD num_sids; + DWORD privilege_mask1; + DWORD privilege_mask2; +}; + +/* + * bitmap security_secinfo + */ +#define SECINFO_OWNER 0x00000001 +#define SECINFO_GROUP 0x00000002 +#define SECINFO_DACL 0x00000004 +#define SECINFO_SACL 0x00000008 + +#endif /* _SECURITY_NDL_ */
--- a/usr/src/uts/common/smbsrv/ndl/spoolss.ndl Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/smbsrv/ndl/spoolss.ndl Thu Jul 22 14:53:56 2010 -0700 @@ -19,84 +19,132 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ -#ifndef _MLSVC_SPOOLSS_NDL_ -#define _MLSVC_SPOOLSS_NDL_ - -/* - * Printing and Spooling RPC interface definition. - */ +#ifndef _SPOOLSS_NDL_ +#define _SPOOLSS_NDL_ #include "ndrtypes.ndl" - +#include "security.ndl" -/* - * The spoolss opcodes. - */ +#define TABLE_STRING 1 +#define TABLE_DWORD 2 +#define TABLE_TIME 3 +#define TABLE_DEVMODE 4 +#define TABLE_SECURITY_DESCRIPTOR 5 + #define SPOOLSS_OPNUM_OpenPrinter 0x01 #define SPOOLSS_OPNUM_GetJob 0x03 +#define SPOOLSS_OPNUM_EnumJobs 0x04 #define SPOOLSS_OPNUM_DeletePrinter 0x06 +#define SPOOLSS_OPNUM_GetPrinter 0x08 #define SPOOLSS_OPNUM_GetPrinterDriver 0x0b #define SPOOLSS_OPNUM_DeletePrinterDriver 0x0d -#define SPOOLSS_OPNUM_AddPrintProcessor 0x0e -#define SPOOLSS_OPNUM_GetPrintProcessorDirectory 0x10 +#define SPOOLSS_OPNUM_StartDocPrinter 0x11 +#define SPOOLSS_OPNUM_StartPagePrinter 0x12 +#define SPOOLSS_OPNUM_WritePrinter 0x13 +#define SPOOLSS_OPNUM_EndPagePrinter 0x14 #define SPOOLSS_OPNUM_AbortPrinter 0x15 -#define SPOOLSS_OPNUM_ReadPrinter 0x16 -#define SPOOLSS_OPNUM_WaitForPrinterChange 0x1c -#define SPOOLSS_OPNUM_AddForm 0x1e -#define SPOOLSS_OPNUM_DeleteForm 0x1f -#define SPOOLSS_OPNUM_GetForm 0x20 -#define SPOOLSS_OPNUM_SetForm 0x21 -#define SPOOLSS_OPNUM_EnumMonitors 0x24 -#define SPOOLSS_OPNUM_AddPort 0x25 -#define SPOOLSS_OPNUM_ConfigurePort 0x26 -#define SPOOLSS_OPNUM_DeletePort 0x27 -#define SPOOLSS_OPNUM_CreatePrinterIc 0x28 -#define SPOOLSS_OPNUM_PlayDescriptionPrinterIc 0x29 -#define SPOOLSS_OPNUM_DeletePrinterIc 0x2a -#define SPOOLSS_OPNUM_AddPrinterConnection 0x2b -#define SPOOLSS_OPNUM_DeletePrinterConnection 0x2c -#define SPOOLSS_OPNUM_PrinterMessageBox 0x2d -#define SPOOLSS_OPNUM_AddMonitor 0x2e -#define SPOOLSS_OPNUM_DeleteMonitor 0x2f -#define SPOOLSS_OPNUM_DeletePrintProcessor 0x30 -#define SPOOLSS_OPNUM_AddPrintProvider 0x31 -#define SPOOLSS_OPNUM_DeletePrintProvider 0x32 +#define SPOOLSS_OPNUM_AddJob 0x18 +#define SPOOLSS_OPNUM_ScheduleJob 0x19 +#define SPOOLSS_OPNUM_GetPrinterData 0x1a +#define SPOOLSS_OPNUM_ClosePrinter 0x1d +#define SPOOLSS_OPNUM_EndDocPrinter 0x17 +#define SPOOLSS_OPNUM_EnumForms 0x22 +#define SPOOLSS_OPNUM_CreatePrinterIC 0x28 #define SPOOLSS_OPNUM_ResetPrinter 0x34 -#define SPOOLSS_OPNUM_FindFirstChangeNotify 0x36 -#define SPOOLSS_OPNUM_FindNextChangeNotify 0x37 -#define SPOOLSS_OPNUM_RouterFindFirstNotify 0x39 +#define SPOOLSS_OPNUM_GetPrinterDriver2 0x35 +#define SPOOLSS_OPNUM_FCPN 0x38 #define SPOOLSS_OPNUM_ReplyOpenPrinter 0x3a -#define SPOOLSS_OPNUM_RouterReplyPrinter 0x3b #define SPOOLSS_OPNUM_ReplyClosePrinter 0x3c -#define SPOOLSS_OPNUM_AddPortEx 0x3d -#define SPOOLSS_OPNUM_RemoteFindFirstChangeNotify 0x3e -#define SPOOLSS_OPNUM_SpoolerInitialize 0x3f -#define SPOOLSS_OPNUM_ResetPrinterEx 0x40 -#define SPOOLSS_OPNUM_RouterRefreshChangeNotify 0x42 -#define SPOOLSS_OPNUM_OpenPrinter2 0x45 - +#define SPOOLSS_OPNUM_RFFPCNEX 0x41 +#define SPOOLSS_OPNUM_RRPCN 0x42 +#define SPOOLSS_OPNUM_RFNPCNEX 0x43 +#define SPOOLSS_OPNUM_OpenPrinterEx 0x45 +#define SPOOLSS_OPNUM_EnumPrinterData 0x48 +#define SPOOLSS_OPNUM_EnumPrinterDataEx 0x4f +#define SPOOLSS_OPNUM_EnumPrinterKey 0x50 CONTEXT_HANDLE(spoolss_handle) spoolss_handle_t; +struct spoolssDevmodeContainer { + BYTE DevContCount; + SIZE_IS(DevContCount) + BYTE *DevMode; +}; -OPERATION(SPOOLSS_OPNUM_OpenPrinter) -struct spoolss_OpenPrinter { - IN DWORD dontcare; - OUT spoolss_handle_t handle; + +struct spoolss_DeviceMode { + BYTE devicename[64]; + WORD specversion; + WORD driverversion; + WORD size; + WORD driverextra_length; + DWORD fields; + WORD orientation; + WORD papersize; + WORD paperlength; + WORD paperwidth; + WORD scale; + WORD copies; + WORD defaultsource; + WORD printquality; + WORD color; + WORD duplex; + WORD yresolution; + WORD ttoption; + WORD collate; + BYTE formname[64]; + WORD logpixels; + DWORD bitsperpel; + DWORD pelswidth; + DWORD pelsheight; + DWORD displayflags; + DWORD displayfrequency; + DWORD icmmethod; + DWORD icmintent; + DWORD mediatype; + DWORD dithertype; + DWORD reserved1; + DWORD reserved2; + DWORD panningwidth; + DWORD panningheight; + struct spoolssDevmodeContainer driverextra_data; +}; + +OPERATION(SPOOLSS_OPNUM_CreatePrinterIC) +struct spoolss_CreatePrinterIC { + IN spoolss_handle_t handle; + OUT spoolss_handle_t gdi_handle; + IN struct spoolssDevmodeContainer dmodeContainer; OUT DWORD status; }; - -OPERATION(SPOOLSS_OPNUM_GetJob) -struct spoolss_GetJob { - IN DWORD dontcare; +OPERATION(SPOOLSS_OPNUM_OpenPrinter) +struct spoolss_OpenPrinter { + IN LPTSTR printer_name; + OUT spoolss_handle_t handle; + IN LPTSTR data_type; + IN struct spoolssDevmodeContainer dmodeContainer; + IN DWORD AccessRequired; OUT DWORD status; }; +OPERATION(SPOOLSS_OPNUM_EnumJobs) +struct spoolss_EnumJobs { + IN spoolss_handle_t handle; + IN DWORD FirstJob; + IN DWORD NoJobs; + IN DWORD level; + IN DWORD Buf2; + IN DWORD BufCount; + SIZE_IS(BufCount) + OUT BYTE *pJob; + OUT DWORD needed; + OUT DWORD needed2; + OUT DWORD status; +}; OPERATION(SPOOLSS_OPNUM_DeletePrinter) struct spoolss_DeletePrinter { @@ -104,6 +152,311 @@ OUT DWORD status; }; +#define SPOOLSS_ARCHITECTURE_NT_X86 ( "Windows NT x86" ) +struct spoolss_Time { + WORD year; + WORD month; + WORD day_of_week; + WORD day; + WORD hour; + WORD minute; + WORD second; + WORD millisecond; +}; + +struct spoolss_GetPrinter0 { + DWORD printername; + DWORD servername; + DWORD cjobs; + DWORD total_jobs; + DWORD total_bytes; + DWORD time0; + DWORD time1; + DWORD time2; + DWORD time3; + DWORD global_counter; + DWORD total_pages; + DWORD version; + DWORD ffreebuild; + DWORD cspooling; + DWORD cmaxspooling; + DWORD session_counter; + DWORD out_of_paper; + DWORD not_ready; + DWORD job_error; + DWORD num_processors; + DWORD type_processor; + DWORD high_part_total_bytes; + DWORD change_id; + DWORD last_error; + DWORD status; + DWORD enum_network_printers; + DWORD c_setprinter; + WORD processor_arch; + WORD processor_level; + DWORD ref; + DWORD reserved2; + DWORD reserved3; +}; + +/* bitmap spoolss_EnumPrinterFlags */ +#define PRINTER_ENUM_DEFAULT ( 0x00000001 ) +#define PRINTER_ENUM_LOCAL ( 0x00000002 ) +#define PRINTER_ENUM_CONNECTIONS ( 0x00000004 ) +#define PRINTER_ENUM_FAVORITE ( 0x00000004 ) +#define PRINTER_ENUM_NAME ( 0x00000008 ) +#define PRINTER_ENUM_REMOTE ( 0x00000010 ) +#define PRINTER_ENUM_SHARED ( 0x00000020 ) +#define PRINTER_ENUM_NETWORK ( 0x00000040 ) +#define PRINTER_ENUM_EXPAND ( 0x00004000 ) +#define PRINTER_ENUM_CONTAINER ( 0x00008000 ) +#define PRINTER_ENUM_ICON1 ( 0x00010000 ) +#define PRINTER_ENUM_ICON2 ( 0x00020000 ) +#define PRINTER_ENUM_ICON3 ( 0x00040000 ) +#define PRINTER_ENUM_ICON4 ( 0x00080000 ) +#define PRINTER_ENUM_ICON5 ( 0x00100000 ) +#define PRINTER_ENUM_ICON6 ( 0x00200000 ) +#define PRINTER_ENUM_ICON7 ( 0x00400000 ) +#define PRINTER_ENUM_ICON8 ( 0x00800000 ) +#define PRINTER_ENUM_HIDE ( 0x01000000 ) + +struct spoolss_GetPrinter1 { + DWORD flags; + DWORD name; + DWORD description; + DWORD comment; +}; + +/* bitmap spoolss_PrinterAttributes */ +#define PRINTER_ATTRIBUTE_QUEUED ( 0x00000001 ) +#define PRINTER_ATTRIBUTE_DIRECT ( 0x00000002 ) +#define PRINTER_ATTRIBUTE_DEFAULT ( 0x00000004 ) +#define PRINTER_ATTRIBUTE_SHARED ( 0x00000008 ) +#define PRINTER_ATTRIBUTE_NETWORK ( 0x00000010 ) +#define PRINTER_ATTRIBUTE_HIDDEN ( 0x00000020 ) +#define PRINTER_ATTRIBUTE_LOCAL ( 0x00000040 ) +#define PRINTER_ATTRIBUTE_ENABLE_DEVQ ( 0x00000080 ) +#define PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS ( 0x00000100 ) +#define PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST ( 0x00000200 ) +#define PRINTER_ATTRIBUTE_WORK_OFFLINE ( 0x00000400 ) +#define PRINTER_ATTRIBUTE_ENABLE_BIDI ( 0x00000800 ) +#define PRINTER_ATTRIBUTE_RAW_ONLY ( 0x00001000 ) +#define PRINTER_ATTRIBUTE_PUBLISHED ( 0x00002000 ) +#define PRINTER_ATTRIBUTE_FAX ( 0x00004000 ) +#define PRINTER_ATTRIBUTE_TS ( 0x00008000 ) + +/* bitmap spoolss_PrinterStatus */ +#define PRINTER_STATUS_PAUSED ( 0x00000001 ) +#define PRINTER_STATUS_ERROR ( 0x00000002 ) +#define PRINTER_STATUS_PENDING_DELETION ( 0x00000004 ) +#define PRINTER_STATUS_PAPER_JAM ( 0x00000008 ) +#define PRINTER_STATUS_PAPER_OUT ( 0x00000010 ) +#define PRINTER_STATUS_MANUAL_FEED ( 0x00000020 ) +#define PRINTER_STATUS_PAPER_PROBLEM ( 0x00000040 ) +#define PRINTER_STATUS_OFFLINE ( 0x00000080 ) +#define PRINTER_STATUS_IO_ACTIVE ( 0x00000100 ) +#define PRINTER_STATUS_BUSY ( 0x00000200 ) +#define PRINTER_STATUS_PRINTING ( 0x00000400 ) +#define PRINTER_STATUS_OUTPUT_BIN_FULL ( 0x00000800 ) +#define PRINTER_STATUS_NOT_AVAILABLE ( 0x00001000 ) +#define PRINTER_STATUS_WAITING ( 0x00002000 ) +#define PRINTER_STATUS_PROCESSING ( 0x00004000 ) +#define PRINTER_STATUS_INITIALIZING ( 0x00008000 ) +#define PRINTER_STATUS_WARMING_UP ( 0x00010000 ) +#define PRINTER_STATUS_TONER_LOW ( 0x00020000 ) +#define PRINTER_STATUS_NO_TONER ( 0x00040000 ) +#define PRINTER_STATUS_PAGE_PUNT ( 0x00080000 ) +#define PRINTER_STATUS_USER_INTERVENTION ( 0x00100000 ) +#define PRINTER_STATUS_OUT_OF_MEMORY ( 0x00200000 ) +#define PRINTER_STATUS_DOOR_OPEN ( 0x00400000 ) +#define PRINTER_STATUS_SERVER_UNKNOWN ( 0x00800000 ) +#define PRINTER_STATUS_POWER_SAVE ( 0x01000000 ) + +struct spoolss_GetPrinter2 { + DWORD servername; + DWORD printername; + DWORD sharename; + DWORD portname; + DWORD drivername; + DWORD comment; + DWORD location; + DWORD devmode; + DWORD sepfile; + DWORD printprocessor; + DWORD datatype; + DWORD parameters; + DWORD secdesc; + DWORD attributes; + DWORD priority; + DWORD defaultpriority; + DWORD starttime; + DWORD untiltime; + DWORD status; + DWORD cjobs; + DWORD averageppm; +}; + +typedef struct spoolss_GetPrinter2 spoolss_GetPrinter2_t; + +struct spoolss_GetPrinter3 { + DWORD dummy; +}; + +struct spoolss_GetPrinter4 { + DWORD printername; + DWORD servername; + DWORD attributes; +}; + +struct spoolss_GetPrinter5 { + DWORD printername; + DWORD portname; + DWORD attributes; + DWORD device_not_selected_timeout; + DWORD transmission_retry_timeout; +}; + +struct spoolss_GetPrinter6 { + DWORD status; +}; + +/* bitmap spoolss_DsPrintAction */ +#define DSPRINT_PUBLISH ( 0x00000001 ) +#define DSPRINT_UPDATE ( 0x00000002 ) +#define DSPRINT_UNPUBLISH ( 0x00000004 ) +#define DSPRINT_REPUBLISH ( 0x00000008 ) +#define DSPRINT_PENDING ( 0x80000000 ) + +struct spoolss_GetPrinter7 { + DWORD guid; + DWORD action; +}; + +struct spoolss_GetPrinter8 { + DWORD flags; + DWORD name; + DWORD description; + DWORD comment; +}; + +union spoolss_GetPrinter_result_u { + UNION_INFO_ENT(0, spoolss_GetPrinter); + UNION_INFO_ENT(1, spoolss_GetPrinter); + UNION_INFO_ENT(2, spoolss_GetPrinter); + UNION_INFO_ENT(3, spoolss_GetPrinter); + UNION_INFO_ENT(4, spoolss_GetPrinter); + UNION_INFO_ENT(5, spoolss_GetPrinter); + UNION_INFO_ENT(6, spoolss_GetPrinter); + UNION_INFO_ENT(7, spoolss_GetPrinter); + UNION_INFO_ENT(8, spoolss_GetPrinter); + DEFAULT char *nullptr; +}; + +struct spoolss_GetPrinter_result { + DWORD switch_value; + SWITCH(switch_value) + union spoolss_GetPrinter_result_u ru; +}; + +struct spoolss_RPC_V2_NOTIFY_OPTIONS_TYPE { + WORD type; + WORD reserved0; + DWORD reserved1; + DWORD reserved2; + DWORD count; + SIZE_IS(count) + WORD *pFields; +}; + +struct spoolss_RPC_V2_NOTIFY_OPTIONS { + DWORD version; + DWORD reserved; + DWORD count; + SIZE_IS(count) + struct spoolss_RPC_V2_NOTIFY_OPTIONS_TYPE *ptypes; +}; + +struct SYSTEMTIME { + WORD year; + WORD month; + WORD dayofweek; + WORD day; + WORD hour; + WORD minute; + WORD second; + WORD millisecs; +}; + +struct SECURITY_CONTAINER { + DWORD count; + SIZE_IS(count) + BYTE *psecurity; +}; + +struct SYSTEMTIME_CONTAINER { + DWORD count; + struct SYSTEMTIME *psystemtime; +}; + +struct STRING_CONTAINER { + DWORD count; + SIZE_IS(count / 2) + LPTSTR pstring; +}; + +union spoolss_RPC_V2_NOTIFY_INFO_DATA_DATA { + CASE(TABLE_STRING) + struct STRING_CONTAINER pcont; + CASE(TABLE_DWORD) + DWORD data[2]; + CASE(TABLE_TIME) + struct SYSTEMTIME_CONTAINER system_time; + CASE(TABLE_DEVMODE) + struct spoolssDevmodeContainer devmode; + CASE(TABLE_SECURITY_DESCRIPTOR) + struct SECURITY_CONTAINER security_descriptor; +}; + +struct spoolss_RPC_V2_NOTIFY_INFO_DATA { + WORD Type; + WORD Field; + DWORD Reserved; + DWORD Id; + SWITCH(Reserved & 0x0000FFFF) + union spoolss_RPC_V2_NOTIFY_INFO_DATA_DATA data; +}; + +struct spoolss_RPC_V2_NOTIFY_INFO { + DWORD Version; + DWORD Flags; + DWORD Count; + SIZE_IS(Count) + struct spoolss_RPC_V2_NOTIFY_INFO_DATA *aData; +}; + +OPERATION(SPOOLSS_OPNUM_GetPrinter) +struct spoolss_GetPrinter { + IN spoolss_handle_t handle; + IN DWORD switch_value; + IN DWORD Buf2; + IN DWORD BufCount; + SIZE_IS(BufCount) + OUT BYTE *Buf; + OUT DWORD needed; + OUT DWORD status; +}; + +OPERATION(SPOOLSS_OPNUM_GetPrinterData) +struct spoolss_GetPrinterData { + IN spoolss_handle_t handle; + IN REFERENCE LPTSTR pValueName; + OUT DWORD pType; + SIZE_IS(Size) + OUT LPBYTE Buf; + IN DWORD Size; + OUT DWORD Needed; + OUT DWORD status; +}; OPERATION(SPOOLSS_OPNUM_GetPrinterDriver) struct spoolss_GetPrinterDriver { @@ -111,224 +464,142 @@ OUT DWORD status; }; - OPERATION(SPOOLSS_OPNUM_DeletePrinterDriver) struct spoolss_DeletePrinterDriver { IN DWORD dontcare; OUT DWORD status; }; +struct spoolss_DocInfo { + LPTSTR doc_name; + LPTSTR printer_name; + LPTSTR type; +}; +typedef struct spoolss_DocInfo spoolss_DocInfo_t; -OPERATION(SPOOLSS_OPNUM_AddPrintProcessor) -struct spoolss_AddPrintProcessor { - IN DWORD dontcare; +struct spoolss_DocInfo_Container { + DWORD level; + DWORD switch_value; + spoolss_DocInfo_t *DocInfoContainer; +}; +typedef struct spoolss_DocInfo_Container spoolss_DocInfo_Container_t; + +OPERATION(SPOOLSS_OPNUM_StartDocPrinter) +struct spoolss_StartDocPrinter { + IN spoolss_handle_t handle; + IN spoolss_DocInfo_Container_t dinfo; + OUT DWORD JobId; OUT DWORD status; }; - -OPERATION(SPOOLSS_OPNUM_GetPrintProcessorDirectory) -struct spoolss_GetPrintProcessorDirectory { - IN DWORD dontcare; - OUT DWORD status; -}; - - OPERATION(SPOOLSS_OPNUM_AbortPrinter) struct spoolss_AbortPrinter { - IN DWORD dontcare; + IN spoolss_handle_t handle; OUT DWORD status; }; - -OPERATION(SPOOLSS_OPNUM_ReadPrinter) -struct spoolss_ReadPrinter { - IN DWORD dontcare; +OPERATION(SPOOLSS_OPNUM_ResetPrinter) +struct spoolss_ResetPrinter { + IN spoolss_handle_t handle; OUT DWORD status; }; - -OPERATION(SPOOLSS_OPNUM_WaitForPrinterChange) -struct spoolss_WaitForPrinterChange { - IN DWORD dontcare; +OPERATION(SPOOLSS_OPNUM_StartPagePrinter) +struct spoolss_StartPagePrinter { + IN spoolss_handle_t handle; OUT DWORD status; }; +OPERATION(SPOOLSS_OPNUM_EndPagePrinter) +struct spoolss_EndPagePrinter { + IN spoolss_handle_t handle; + OUT DWORD status; +}; -OPERATION(SPOOLSS_OPNUM_AddForm) -struct spoolss_AddForm { - IN DWORD dontcare; +OPERATION(SPOOLSS_OPNUM_WritePrinter) +struct spoolss_WritePrinter { + IN spoolss_handle_t handle; + IN DWORD BufCount; + SIZE_IS(BufCount) + IN REFERENCE LPBYTE pBuf; + OUT DWORD written; OUT DWORD status; }; - -OPERATION(SPOOLSS_OPNUM_DeleteForm) -struct spoolss_DeleteForm { - IN DWORD dontcare; +OPERATION(SPOOLSS_OPNUM_ScheduleJob) +struct spoolss_ScheduleJob { + IN spoolss_handle_t handle; + IN DWORD JobId; OUT DWORD status; }; - -OPERATION(SPOOLSS_OPNUM_GetForm) -struct spoolss_GetForm { - IN DWORD dontcare; - OUT DWORD status; -}; - - -OPERATION(SPOOLSS_OPNUM_SetForm) -struct spoolss_SetForm { - IN DWORD dontcare; +OPERATION(SPOOLSS_OPNUM_GetJob) +struct spoolss_GetJob { + IN spoolss_handle_t handle; + IN DWORD JobId; + IN DWORD level; + SIZE_IS(BufCount) + INOUT BYTE *pJob; + IN DWORD BufCount; + OUT DWORD needed; OUT DWORD status; }; - -OPERATION(SPOOLSS_OPNUM_EnumMonitors) -struct spoolss_EnumMonitors { - IN DWORD dontcare; +OPERATION(SPOOLSS_OPNUM_AddJob) +struct spoolss_AddJob { + IN spoolss_handle_t handle; + IN DWORD level; + IN DWORD Buf2; + IN DWORD BufCount; + SIZE_IS(BufCount) + OUT BYTE *pAddJob; + OUT DWORD needed; OUT DWORD status; }; - -OPERATION(SPOOLSS_OPNUM_AddPort) -struct spoolss_AddPort { - IN DWORD dontcare; +OPERATION(SPOOLSS_OPNUM_ClosePrinter) +struct spoolss_ClosePrinter { + IN spoolss_handle_t handle; + OUT spoolss_handle_t result_handle; OUT DWORD status; }; - -OPERATION(SPOOLSS_OPNUM_ConfigurePort) -struct spoolss_ConfigurePort { - IN DWORD dontcare; +OPERATION(SPOOLSS_OPNUM_EndDocPrinter) +struct spoolss_EndDocPrinter { + IN spoolss_handle_t handle; OUT DWORD status; }; - -OPERATION(SPOOLSS_OPNUM_DeletePort) -struct spoolss_DeletePort { - IN DWORD dontcare; +OPERATION(SPOOLSS_OPNUM_EnumForms) +struct spoolss_EnumForms { + IN spoolss_handle_t handle; + IN DWORD level; + IN DWORD BufCount; + SIZE_IS(BufCount) + INOUT BYTE *pEnumForms; + OUT DWORD needed; + OUT DWORD pcRet; OUT DWORD status; }; - -OPERATION(SPOOLSS_OPNUM_CreatePrinterIc) -struct spoolss_CreatePrinterIc { +OPERATION(SPOOLSS_OPNUM_GetPrinterDriver2) +struct spoolss_GetPrinterDriver2 { IN DWORD dontcare; OUT DWORD status; }; - -OPERATION(SPOOLSS_OPNUM_PlayDescriptionPrinterIc) -struct spoolss_PlayDescriptionPrinterIc { - IN DWORD dontcare; - OUT DWORD status; -}; - - -OPERATION(SPOOLSS_OPNUM_DeletePrinterIc) -struct spoolss_DeletePrinterIc { - IN DWORD dontcare; - OUT DWORD status; -}; - - -OPERATION(SPOOLSS_OPNUM_AddPrinterConnection) -struct spoolss_AddPrinterConnection { - IN DWORD dontcare; - OUT DWORD status; -}; - - -OPERATION(SPOOLSS_OPNUM_DeletePrinterConnection) -struct spoolss_DeletePrinterConnection { - IN DWORD dontcare; - OUT DWORD status; -}; - - -OPERATION(SPOOLSS_OPNUM_PrinterMessageBox) -struct spoolss_PrinterMessageBox { - IN DWORD dontcare; - OUT DWORD status; -}; - - -OPERATION(SPOOLSS_OPNUM_AddMonitor) -struct spoolss_AddMonitor { - IN DWORD dontcare; - OUT DWORD status; -}; - - -OPERATION(SPOOLSS_OPNUM_DeleteMonitor) -struct spoolss_DeleteMonitor { +OPERATION(SPOOLSS_OPNUM_FCPN) +struct spoolss_FCPN { IN DWORD dontcare; OUT DWORD status; }; - -OPERATION(SPOOLSS_OPNUM_DeletePrintProcessor) -struct spoolss_DeletePrintProcessor { - IN DWORD dontcare; - OUT DWORD status; -}; - - -OPERATION(SPOOLSS_OPNUM_AddPrintProvider) -struct spoolss_AddPrintProvider { - IN DWORD dontcare; - OUT DWORD status; -}; - - -OPERATION(SPOOLSS_OPNUM_DeletePrintProvider) -struct spoolss_DeletePrintProvider { - IN DWORD dontcare; - OUT DWORD status; -}; - - -OPERATION(SPOOLSS_OPNUM_ResetPrinter) -struct spoolss_ResetPrinter { - IN DWORD dontcare; - OUT DWORD status; -}; - - -OPERATION(SPOOLSS_OPNUM_FindFirstChangeNotify) -struct spoolss_FindFirstChangeNotify { - IN DWORD dontcare; - OUT DWORD status; -}; - - -OPERATION(SPOOLSS_OPNUM_FindNextChangeNotify) -struct spoolss_FindNextChangeNotify { - IN DWORD dontcare; - OUT DWORD status; -}; - - -OPERATION(SPOOLSS_OPNUM_RouterFindFirstNotify) -struct spoolss_RouterFindFirstNotify { - IN DWORD dontcare; - OUT DWORD status; -}; - - OPERATION(SPOOLSS_OPNUM_ReplyOpenPrinter) struct spoolss_ReplyOpenPrinter { IN DWORD dontcare; OUT DWORD status; }; - -OPERATION(SPOOLSS_OPNUM_RouterReplyPrinter) -struct spoolss_RouterReplyPrinter { - IN DWORD dontcare; - OUT DWORD status; -}; - - OPERATION(SPOOLSS_OPNUM_ReplyClosePrinter) struct spoolss_ReplyClosePrinter { IN DWORD dontcare; @@ -336,146 +607,127 @@ }; -OPERATION(SPOOLSS_OPNUM_AddPortEx) -struct spoolss_AddPortEx { - IN DWORD dontcare; +OPERATION(SPOOLSS_OPNUM_RFFPCNEX) +struct spoolss_RFFPCNEX { + IN spoolss_handle_t handle; OUT DWORD status; }; +struct spoolss_infores { + DWORD entriesread; + struct spoolss_RPC_V2_NOTIFY_INFO *pinfo; +}; -OPERATION(SPOOLSS_OPNUM_RemoteFindFirstChangeNotify) -struct spoolss_RemoteFindFirstChangeNotify { - IN DWORD dontcare; +OPERATION(SPOOLSS_OPNUM_RFNPCNEX) +struct spoolss_RFNPCNEX { + IN spoolss_handle_t handle; + IN DWORD color; + IN struct spoolss_RPC_V2_NOTIFY_OPTIONS *poptions; + OUT struct spoolss_infores *ppinfo; OUT DWORD status; }; - -OPERATION(SPOOLSS_OPNUM_SpoolerInitialize) -struct spoolss_SpoolerInitialize { +OPERATION(SPOOLSS_OPNUM_RRPCN) +struct spoolss_RRPCN { IN DWORD dontcare; OUT DWORD status; }; +OPERATION(SPOOLSS_OPNUM_OpenPrinterEx) +struct spoolss_OpenPrinterEx { + IN LPTSTR printer_name; + OUT spoolss_handle_t handle; + OUT DWORD status; +}; -OPERATION(SPOOLSS_OPNUM_ResetPrinterEx) -struct spoolss_ResetPrinterEx { +OPERATION(SPOOLSS_OPNUM_EnumPrinterData) +struct spoolss_EnumPrinterData { IN DWORD dontcare; OUT DWORD status; }; - -OPERATION(SPOOLSS_OPNUM_RouterRefreshChangeNotify) -struct spoolss_RouterRefreshChangeNotify { +OPERATION(SPOOLSS_OPNUM_EnumPrinterDataEx) +struct spoolss_EnumPrinterDataEx { IN DWORD dontcare; OUT DWORD status; }; - -OPERATION(SPOOLSS_OPNUM_OpenPrinter2) -struct spoolss_OpenPrinter2 { +OPERATION(SPOOLSS_OPNUM_EnumPrinterKey) +struct spoolss_EnumPrinterKey { IN DWORD dontcare; - OUT spoolss_handle_t handle; OUT DWORD status; }; - /* *********************************************************************** * The spoolss interface definition. *********************************************************************** */ + INTERFACE(0) union spoolss_interface { CASE(SPOOLSS_OPNUM_OpenPrinter) - struct spoolss_OpenPrinter OpenPrinter; - CASE(SPOOLSS_OPNUM_GetJob) - struct spoolss_GetJob GetJob; + struct spoolss_OpenPrinter OpenPrinter; + CASE(SPOOLSS_OPNUM_DeletePrinter) - struct spoolss_DeletePrinter DeletePrinter; - CASE(SPOOLSS_OPNUM_GetPrinterDriver) - struct spoolss_GetPrinterDriver GetPrinterDriver; - CASE(SPOOLSS_OPNUM_DeletePrinterDriver) - struct spoolss_DeletePrinterDriver DeletePrinterDriver; - CASE(SPOOLSS_OPNUM_AddPrintProcessor) - struct spoolss_AddPrintProcessor AddPrintProcessor; - CASE(SPOOLSS_OPNUM_GetPrintProcessorDirectory) - struct spoolss_GetPrintProcessorDirectory - GetPrintProcessorDirectory; + struct spoolss_DeletePrinter DeletePrinter; + + CASE(SPOOLSS_OPNUM_GetPrinter) + struct spoolss_GetPrinter GetPrinter; + + CASE(SPOOLSS_OPNUM_GetPrinterData) + struct spoolss_GetPrinterData GetPrinterData; + CASE(SPOOLSS_OPNUM_AbortPrinter) - struct spoolss_AbortPrinter AbortPrinter; - CASE(SPOOLSS_OPNUM_ReadPrinter) - struct spoolss_ReadPrinter ReadPrinter; - CASE(SPOOLSS_OPNUM_WaitForPrinterChange) - struct spoolss_WaitForPrinterChange WaitForPrinterChange; - CASE(SPOOLSS_OPNUM_AddForm) - struct spoolss_AddForm AddForm; - CASE(SPOOLSS_OPNUM_DeleteForm) - struct spoolss_DeleteForm DeleteForm; - CASE(SPOOLSS_OPNUM_GetForm) - struct spoolss_GetForm GetForm; - CASE(SPOOLSS_OPNUM_SetForm) - struct spoolss_SetForm SetForm; - CASE(SPOOLSS_OPNUM_EnumMonitors) - struct spoolss_EnumMonitors EnumMonitors; - CASE(SPOOLSS_OPNUM_AddPort) - struct spoolss_AddPort AddPort; - CASE(SPOOLSS_OPNUM_ConfigurePort) - struct spoolss_ConfigurePort ConfigurePort; - CASE(SPOOLSS_OPNUM_DeletePort) - struct spoolss_DeletePort DeletePort; - CASE(SPOOLSS_OPNUM_CreatePrinterIc) - struct spoolss_CreatePrinterIc CreatePrinterIc; - CASE(SPOOLSS_OPNUM_PlayDescriptionPrinterIc) - struct spoolss_PlayDescriptionPrinterIc - PlayDescriptionPrinterIc; - CASE(SPOOLSS_OPNUM_DeletePrinterIc) - struct spoolss_DeletePrinterIc DeletePrinterIc; - CASE(SPOOLSS_OPNUM_AddPrinterConnection) - struct spoolss_AddPrinterConnection AddPrinterConnection; - CASE(SPOOLSS_OPNUM_DeletePrinterConnection) - struct spoolss_DeletePrinterConnection DeletePrinterConnection; - CASE(SPOOLSS_OPNUM_PrinterMessageBox) - struct spoolss_PrinterMessageBox PrinterMessageBox; - CASE(SPOOLSS_OPNUM_AddMonitor) - struct spoolss_AddMonitor AddMonitor; - CASE(SPOOLSS_OPNUM_DeleteMonitor) - struct spoolss_DeleteMonitor DeleteMonitor; - CASE(SPOOLSS_OPNUM_DeletePrintProcessor) - struct spoolss_DeletePrintProcessor DeletePrintProcessor; - CASE(SPOOLSS_OPNUM_AddPrintProvider) - struct spoolss_AddPrintProvider AddPrintProvider; - CASE(SPOOLSS_OPNUM_DeletePrintProvider) - struct spoolss_DeletePrintProvider DeletePrintProvider; + struct spoolss_AbortPrinter AbortPrinter; + + CASE(SPOOLSS_OPNUM_StartDocPrinter) + struct spoolss_StartDocPrinter StartDocPrinter; + + CASE(SPOOLSS_OPNUM_EndDocPrinter) + struct spoolss_EndDocPrinter EndDocPrinter; + + CASE(SPOOLSS_OPNUM_CreatePrinterIC) + struct spoolss_CreatePrinterIC CreatePrinterIC; + CASE(SPOOLSS_OPNUM_ResetPrinter) - struct spoolss_ResetPrinter ResetPrinter; - CASE(SPOOLSS_OPNUM_FindFirstChangeNotify) - struct spoolss_FindFirstChangeNotify FindFirstChangeNotify; - CASE(SPOOLSS_OPNUM_FindNextChangeNotify) - struct spoolss_FindNextChangeNotify FindNextChangeNotify; - CASE(SPOOLSS_OPNUM_RouterFindFirstNotify) - struct spoolss_RouterFindFirstNotify RouterFindFirstNotify; - CASE(SPOOLSS_OPNUM_ReplyOpenPrinter) - struct spoolss_ReplyOpenPrinter ReplyOpenPrinter; - CASE(SPOOLSS_OPNUM_RouterReplyPrinter) - struct spoolss_RouterReplyPrinter RouterReplyPrinter; - CASE(SPOOLSS_OPNUM_ReplyClosePrinter) - struct spoolss_ReplyClosePrinter ReplyClosePrinter; - CASE(SPOOLSS_OPNUM_AddPortEx) - struct spoolss_AddPortEx AddPortEx; - CASE(SPOOLSS_OPNUM_RemoteFindFirstChangeNotify) - struct spoolss_RemoteFindFirstChangeNotify - RemoteFindFirstChangeNotify; - CASE(SPOOLSS_OPNUM_SpoolerInitialize) - struct spoolss_SpoolerInitialize SpoolerInitialize; - CASE(SPOOLSS_OPNUM_ResetPrinterEx) - struct spoolss_ResetPrinterEx ResetPrinterEx; - CASE(SPOOLSS_OPNUM_RouterRefreshChangeNotify) - struct spoolss_RouterRefreshChangeNotify - RouterRefreshChangeNotify; - CASE(SPOOLSS_OPNUM_OpenPrinter2) - struct spoolss_OpenPrinter2 OpenPrinter2; + struct spoolss_ResetPrinter ResetPrinter; + + CASE(SPOOLSS_OPNUM_WritePrinter) + struct spoolss_WritePrinter WritePrinter; + + CASE(SPOOLSS_OPNUM_StartPagePrinter) + struct spoolss_StartPagePrinter StartPagePrinter; + + CASE(SPOOLSS_OPNUM_EndPagePrinter) + struct spoolss_EndPagePrinter EndPagePrinter; + + CASE(SPOOLSS_OPNUM_ClosePrinter) + struct spoolss_ClosePrinter ClosePrinter; + + CASE(SPOOLSS_OPNUM_OpenPrinterEx) + struct spoolss_OpenPrinterEx OpenPrinterEx; + + CASE(SPOOLSS_OPNUM_AddJob) + struct spoolss_AddJob AddJob; + + CASE(SPOOLSS_OPNUM_GetJob) + struct spoolss_GetJob GetJob; + + CASE(SPOOLSS_OPNUM_ScheduleJob) + struct spoolss_ScheduleJob ScheduleJob; + + CASE(SPOOLSS_OPNUM_EnumForms) + struct spoolss_EnumForms EnumForms; + + CASE(SPOOLSS_OPNUM_EnumJobs) + struct spoolss_EnumJobs EnumJobs; + + CASE(SPOOLSS_OPNUM_RFNPCNEX) + struct spoolss_RFNPCNEX RFNPCNEX; + }; typedef union spoolss_interface spoolss_interface_t; EXTERNTYPEINFO(spoolss_interface) -#endif /* _MLSVC_SPOOLSS_NDL_ */ +#endif /* _SPOOLSS_NDL_ */
--- a/usr/src/uts/common/smbsrv/smb.h Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/smbsrv/smb.h Thu Jul 22 14:53:56 2010 -0700 @@ -442,6 +442,7 @@ #define SMB_CSC_CACHE_NONE 0x000C #define SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM 0x0800 +#define SHI1005_FLAGS_ALLOW_NAMESPACE_CACHING 0x0400 /* * The subcommand codes, placed in SETUP[0], for named pipe operations are:
--- a/usr/src/uts/common/smbsrv/smb_dfs.h Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/smbsrv/smb_dfs.h Thu Jul 22 14:53:56 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SMB_DFS_H @@ -109,6 +108,8 @@ DfsGlobalLowPriorityClass = 4 } dfs_target_pclass_t; +#define DFS_PRIORITY_RANK_MAX 0x001F + #define DFS_PROPERTY_FLAG_INSITE_REFERRALS 0x00000001 #define DFS_PROPERTY_FLAG_ROOT_SCALABILITY 0x00000002 #define DFS_PROPERTY_FLAG_SITE_COSTING 0x00000004 @@ -171,10 +172,12 @@ char i_guid[UUID_PRINTABLE_STRING_LENGTH]; uint32_t i_state; uint32_t i_timeout; + uint32_t i_propflag_mask; uint32_t i_propflags; uint32_t i_type; uint32_t i_ntargets; dfs_target_t *i_targets; + uint32_t i_flavor; } dfs_info_t; #ifdef __cplusplus
--- a/usr/src/uts/common/smbsrv/smb_ioctl.h Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/smbsrv/smb_ioctl.h Thu Jul 22 14:53:56 2010 -0700 @@ -52,6 +52,8 @@ #define SMB_IOC_SESSION_CLOSE _IOW(SMB_IOC_BASE, 13, int) #define SMB_IOC_STOP _IOW(SMB_IOC_BASE, 14, int) #define SMB_IOC_EVENT _IOW(SMB_IOC_BASE, 15, int) +#define SMB_IOC_SHAREINFO _IOW(SMB_IOC_BASE, 16, int) +#define SMB_IOC_SPOOLDOC _IOW(SMB_IOC_BASE, 17, int) typedef struct smb_ioc_header { uint32_t version; @@ -60,6 +62,14 @@ int cmd; } smb_ioc_header_t; +typedef struct smb_ioc_spooldoc { + smb_ioc_header_t hdr; + smb_inaddr_t ipaddr; + uint32_t spool_num; + char username[MAXNAMELEN]; + char path[MAXPATHLEN]; +} smb_ioc_spooldoc_t; + typedef struct { smb_ioc_header_t hdr; int32_t offset; @@ -71,6 +81,12 @@ char shr[1]; } smb_ioc_share_t; +typedef struct smb_ioc_shareinfo { + smb_ioc_header_t hdr; + char shrname[MAXNAMELEN]; + uint32_t shortnames; +} smb_ioc_shareinfo_t; + typedef struct smb_ioc_listen { smb_ioc_header_t hdr; int error; @@ -150,6 +166,7 @@ int32_t sync_enable; int32_t secmode; int32_t ipv6_enable; + int32_t print_enable; uint32_t exec_flags; smb_version_t version; char nbdomain[NETBIOS_NAME_SZ]; @@ -170,6 +187,8 @@ smb_ioc_session_t ioc_session; smb_ioc_fileid_t ioc_fileid; smb_ioc_share_t ioc_share; + smb_ioc_shareinfo_t ioc_shareinfo; + smb_ioc_spooldoc_t ioc_spooldoc; } smb_ioc_t; uint32_t smb_crc_gen(uint8_t *, size_t);
--- a/usr/src/uts/common/smbsrv/smb_kproto.h Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/smbsrv/smb_kproto.h Thu Jul 22 14:53:56 2010 -0700 @@ -54,9 +54,20 @@ extern int smb_maxbufsize; extern int smb_flush_required; extern int smb_dirsymlink_enable; +extern int smb_oplock_levelII; extern int smb_oplock_timeout; +extern int smb_oplock_min_timeout; +extern int smb_shortnames; extern int smb_sign_debug; +extern int smb_raw_mode; extern uint_t smb_audit_flags; +extern int smb_ssetup_threshold; +extern int smb_tcon_threshold; +extern int smb_opipe_threshold; +extern int smb_ssetup_timeout; +extern int smb_tcon_timeout; +extern int smb_opipe_timeout; +extern int smb_threshold_debug; int fd_dealloc(int); @@ -198,37 +209,27 @@ void smb_process_file_notify_change_queue(smb_ofile_t *of); -void smb_oplock_acquire(smb_node_t *, smb_ofile_t *, smb_arg_open_t *); -boolean_t smb_oplock_break(smb_node_t *, smb_session_t *, boolean_t); +/* + * oplock functions - node operations + */ +int smb_oplock_init(void); +void smb_oplock_fini(void); +void smb_oplock_acquire(smb_request_t *sr, smb_node_t *, smb_ofile_t *); void smb_oplock_release(smb_node_t *, smb_ofile_t *); -boolean_t smb_oplock_conflict(smb_node_t *, smb_session_t *, smb_arg_open_t *); -boolean_t smb_oplock_broadcast(smb_node_t *); +int smb_oplock_break(smb_request_t *, smb_node_t *, uint32_t); +void smb_oplock_break_levelII(smb_node_t *); +void smb_oplock_ack(smb_node_t *, smb_ofile_t *, uint8_t); +void smb_oplock_broadcast(smb_node_t *); /* - * macros used in oplock processing - * - * SMB_ATTR_ONLY_OPEN: Checks to see if this is - * an attribute-only open with no contravening - * dispositions. Such an open cannot effect an - * oplock break. However, a contravening disposition - * of FILE_SUPERSEDE or FILE_OVERWRITE can allow - * an oplock break. + * range lock functions - node operations */ - -#define SMB_ATTR_ONLY_OPEN(op) \ - ((op) && (op)->desired_access && \ - (((op)->desired_access & ~(FILE_READ_ATTRIBUTES | \ - FILE_WRITE_ATTRIBUTES | SYNCHRONIZE)) == 0) && \ - ((op)->create_disposition != FILE_SUPERSEDE) && \ - ((op)->create_disposition != FILE_OVERWRITE)) \ - uint32_t smb_lock_get_lock_count(smb_node_t *, smb_ofile_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, uint32_t locktype); void smb_lock_range_error(smb_request_t *, uint32_t); - DWORD smb_range_check(smb_request_t *, smb_node_t *, uint64_t, uint64_t, boolean_t); @@ -236,8 +237,8 @@ int smb_unmangle(smb_node_t *, char *, char *, int, uint32_t); boolean_t smb_needs_mangled(const char *); boolean_t smb_maybe_mangled(char *); +boolean_t smb_is_reserved_dos_name(const char *); boolean_t smb_is_invalid_filename(const char *); -boolean_t smb_match_name(ino64_t, char *, char *); void smbsr_cleanup(smb_request_t *sr); @@ -382,6 +383,12 @@ void smb_server_reconnection_check(smb_server_t *, smb_session_t *); void smb_server_get_cfg(smb_server_t *, smb_kmod_cfg_t *); +int smb_server_spooldoc(smb_ioc_spooldoc_t *); +int smb_spool_add_doc(smb_kspooldoc_t *); +int smb_spool_add_fid(uint16_t); +boolean_t smb_spool_lookup_doc_byfid(uint16_t, smb_kspooldoc_t *); +uint16_t smb_spool_get_fid(); + void smb_server_inc_nbt_sess(smb_server_t *); void smb_server_dec_nbt_sess(smb_server_t *); void smb_server_inc_tcp_sess(smb_server_t *); @@ -398,10 +405,11 @@ void smb_server_add_txb(smb_server_t *, int64_t); void smb_server_inc_req(smb_server_t *); -smb_event_t *smb_event_create(void); +smb_event_t *smb_event_create(int); void smb_event_destroy(smb_event_t *); uint32_t smb_event_txid(smb_event_t *); int smb_event_wait(smb_event_t *); +void smb_event_notify(smb_server_t *, uint32_t); /* * SMB node functions (file smb_node.c) @@ -426,11 +434,12 @@ void smb_node_rdlock(smb_node_t *); void smb_node_wrlock(smb_node_t *); void smb_node_unlock(smb_node_t *); -uint32_t smb_node_get_ofile_count(smb_node_t *); void smb_node_add_ofile(smb_node_t *, smb_ofile_t *); void smb_node_rem_ofile(smb_node_t *, smb_ofile_t *); void smb_node_inc_open_ofiles(smb_node_t *); void smb_node_dec_open_ofiles(smb_node_t *); +void smb_node_inc_opening_count(smb_node_t *); +void smb_node_dec_opening_count(smb_node_t *); boolean_t smb_node_is_file(smb_node_t *); boolean_t smb_node_is_dir(smb_node_t *); boolean_t smb_node_is_symlink(smb_node_t *); @@ -442,6 +451,7 @@ uint32_t smb_node_open_check(smb_node_t *, uint32_t, uint32_t); DWORD smb_node_rename_check(smb_node_t *); DWORD smb_node_delete_check(smb_node_t *); +boolean_t smb_node_share_check(smb_node_t *); void smb_node_notify_change(smb_node_t *); void smb_node_notify_parents(smb_node_t *); int smb_node_getattr(smb_request_t *, smb_node_t *, smb_attr_t *); @@ -526,10 +536,11 @@ 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 *); +void smb_session_oplock_break(smb_session_t *, uint16_t, uint16_t, uint8_t); int smb_session_send(smb_session_t *, uint8_t type, mbuf_chain_t *); int smb_session_xprt_gethdr(smb_session_t *, smb_xprt_t *); boolean_t smb_session_oplocks_enable(smb_session_t *); +boolean_t smb_session_levelII_oplocks(smb_session_t *); #define SMB_SESSION_GET_ID(s) ((s)->s_kid) @@ -550,6 +561,7 @@ 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_request_complete(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); @@ -558,8 +570,8 @@ uint32_t smb_ofile_open_check(smb_ofile_t *, uint32_t, uint32_t); uint32_t smb_ofile_rename_check(smb_ofile_t *); uint32_t smb_ofile_delete_check(smb_ofile_t *); +boolean_t smb_ofile_share_check(smb_ofile_t *); cred_t *smb_ofile_getcred(smb_ofile_t *); -void smb_ofile_set_oplock_granted(smb_ofile_t *); void smb_ofile_set_delete_on_close(smb_ofile_t *); void smb_ofile_set_write_time_pending(smb_ofile_t *); boolean_t smb_ofile_write_time_pending(smb_ofile_t *); @@ -808,6 +820,7 @@ void smb_kshare_fini(void); int smb_kshare_export_list(smb_ioc_share_t *); int smb_kshare_unexport_list(smb_ioc_share_t *); +int smb_kshare_info(smb_ioc_shareinfo_t *); void smb_kshare_enum(smb_enumshare_info_t *); smb_kshare_t *smb_kshare_lookup(const char *); void smb_kshare_release(smb_kshare_t *); @@ -824,6 +837,10 @@ void smb_avl_iterinit(smb_avl_t *, smb_avl_cursor_t *); void *smb_avl_iterate(smb_avl_t *, smb_avl_cursor_t *); +void smb_threshold_init(smb_cmd_threshold_t *, char *, int, int); +void smb_threshold_fini(smb_cmd_threshold_t *); +int smb_threshold_enter(smb_cmd_threshold_t *); +void smb_threshold_exit(smb_cmd_threshold_t *, smb_server_t *); #ifdef __cplusplus } #endif
--- a/usr/src/uts/common/smbsrv/smb_kstat.h Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/smbsrv/smb_kstat.h Thu Jul 22 14:53:56 2010 -0700 @@ -63,6 +63,7 @@ typedef struct smb_kstat_req { char kr_name[KSTAT_STRLEN]; + char kr_pad[(~(KSTAT_STRLEN & 0x07) + 1) & 0x07]; uint64_t kr_sum; uint64_t kr_txb; uint64_t kr_rxb;
--- a/usr/src/uts/common/smbsrv/smb_ktypes.h Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/smbsrv/smb_ktypes.h Thu Jul 22 14:53:56 2010 -0700 @@ -386,6 +386,7 @@ kmutex_t ll_mutex; list_t ll_deleteq; uint32_t ll_deleteq_count; + boolean_t ll_flushing; } smb_llist_t; typedef struct smb_slist { @@ -531,43 +532,67 @@ #define MBC_ROOM_FOR(b, n) (((b)->chain_offset + (n)) <= (b)->max_bytes) +#define OPLOCK_MIN_TIMEOUT (5 * 1000) +#define OPLOCK_STD_TIMEOUT (30 * 1000) + /* - * ol_sess_id: - * - * ID of the session holding the oplock (if an oplock was granted). - * - * ol_xthread: - * - * Worker thread treating the command that was granted the oplock. Until - * that thread is done with that command and has submitted the response - * to the network stack, all the other threads will be suspended in - * smb_oplock_enter(). They will be awaken when the worker thread - * referenced in 'ol_xthread' calls smb_oplock_broadcast(). - * - * The purpose of this mechanism is to prevent another thread from - * triggering a oplock break before the response conveying the grant - * has been sent. - * - * ol_ofile - * - * Open file that was granted the oplock. - * - * ol_waiters_count - * - * Number of threads waiting for a call to smb_oplock_broadcast(). - * - * ol_level - * - * Level of the oplock granted. + * Oplock break flags: + * SMB_OPLOCK_BREAK_EXCLUSIVE - only break exclusive oplock + * (type SMB_OPLOCK_EXCLUSIVE or SMB_OPLOCK_BATCH) + * SMB_OPLOCK_BREAK_BATCH - only break exclusive BATCH oplock + * SMB_OPLOCK_BREAK_NOWAIT - do not wait for oplock break ack */ +#define SMB_OPLOCK_NO_BREAK 0x00 +#define SMB_OPLOCK_BREAK_TO_NONE 0x01 +#define SMB_OPLOCK_BREAK_TO_LEVEL_II 0x02 +#define SMB_OPLOCK_BREAK_EXCLUSIVE 0x04 +#define SMB_OPLOCK_BREAK_BATCH 0x08 +#define SMB_OPLOCK_BREAK_NOWAIT 0x10 + +/* + * Oplocks levels are defined to match the levels in the SMB + * protocol (nt_create_andx / nt_transact_create) and should + * not be changed + */ +#define SMB_OPLOCK_NONE 0 +#define SMB_OPLOCK_EXCLUSIVE 1 +#define SMB_OPLOCK_BATCH 2 +#define SMB_OPLOCK_LEVEL_II 3 + typedef struct smb_oplock { - uint64_t ol_sess_id; + kmutex_t ol_mutex; kcondvar_t ol_cv; kthread_t *ol_xthread; - struct smb_ofile *ol_ofile; - uint8_t ol_level; + boolean_t ol_fem; /* fem monitor installed? */ + uint8_t ol_break; + uint32_t ol_count; /* number of grants */ + list_t ol_grants; /* list of smb_oplock_grant_t */ } smb_oplock_t; +#define SMB_OPLOCK_GRANT_MAGIC 0x4F4C4B47 /* OLKG */ +#define SMB_OPLOCK_GRANT_VALID(p) \ + ASSERT((p)->og_magic == SMB_OPLOCK_GRANT_MAGIC) +typedef struct smb_oplock_grant { + uint32_t og_magic; + list_node_t og_lnd; + uint8_t og_level; + uint16_t og_fid; + uint16_t og_tid; + uint16_t og_uid; + struct smb_session *og_session; + struct smb_ofile *og_ofile; +} smb_oplock_grant_t; + +#define SMB_OPLOCK_BREAK_MAGIC 0x4F4C4B42 /* OLKB */ +#define SMB_OPLOCK_BREAK_VALID(p) \ + ASSERT((p)->ob_magic == SMB_OPLOCK_BREAK_MAGIC) +typedef struct smb_oplock_break { + uint32_t ob_magic; + list_node_t ob_lnd; + struct smb_node *ob_node; +} smb_oplock_break_t; + + #define SMB_VFS_MAGIC 0x534D4256 /* 'SMBV' */ typedef struct smb_vfs { @@ -587,7 +612,7 @@ * Timestamps remain cached while there are open ofiles for the node. * This includes open ofiles for named streams. t_open_ofiles is a * count of open ofiles on the node, including named streams' ofiles, - * n_open_ofiles cannot be used as it doesn't include ofiles opened + * n_open_count cannot be used as it doesn't include ofiles opened * for the node's named streams. */ typedef struct smb_times { @@ -604,8 +629,6 @@ typedef enum { SMB_NODE_STATE_AVAILABLE = 0, - SMB_NODE_STATE_OPLOCK_GRANTED, - SMB_NODE_STATE_OPLOCK_BREAKING, SMB_NODE_STATE_DESTROYING } smb_node_state_t; @@ -627,6 +650,7 @@ uint32_t n_hashkey; smb_llist_t *n_hash_bucket; uint32_t n_open_count; + uint32_t n_opening_count; smb_llist_t n_ofile_list; smb_llist_t n_lock_list; struct smb_ofile *readonly_creator; @@ -1012,8 +1036,8 @@ #define SMB_TREE_CASEINSENSITIVE 0x00000008 #define SMB_TREE_NO_CASESENSITIVE 0x00000010 #define SMB_TREE_NO_EXPORT 0x00000020 -#define SMB_TREE_NO_OPLOCKS 0x00000040 -#define SMB_TREE_NO_ATIME 0x00000080 +#define SMB_TREE_OPLOCKS 0x00000040 +#define SMB_TREE_SHORTNAMES 0x00000080 #define SMB_TREE_XVATTR 0x00000100 #define SMB_TREE_DIRENTFLAGS 0x00000200 #define SMB_TREE_ACLONCREATE 0x00000400 @@ -1093,6 +1117,10 @@ (((sr) && (sr)->tid_tree) ? \ smb_tree_has_feature((sr)->tid_tree, SMB_TREE_DFSROOT) : 0) +#define SMB_TREE_SUPPORTS_SHORTNAMES(sr) \ + (((sr) && (sr)->tid_tree) ? \ + smb_tree_has_feature((sr)->tid_tree, SMB_TREE_SHORTNAMES) : 0) + /* * SMB_TREE_CONTAINS_NODE is used to check that a node is in the same * file system as the tree. @@ -1225,8 +1253,6 @@ int f_mode; cred_t *f_cr; pid_t f_pid; - boolean_t f_oplock_granted; - boolean_t f_oplock_exit; uint32_t f_explicit_times; char f_quota_resume[SMB_SID_STRSZ]; } smb_ofile_t; @@ -1243,6 +1269,7 @@ #define SMB_ODIR_FLAG_EDIRENT 0x0008 #define SMB_ODIR_FLAG_CATIA 0x0010 #define SMB_ODIR_FLAG_ABE 0x0020 +#define SMB_ODIR_FLAG_SHORTNAMES 0x0040 typedef enum { SMB_ODIR_STATE_OPEN = 0, @@ -1412,10 +1439,6 @@ uint16_t flags; } smb_arg_dirop_t; -#define OPLOCK_MIN_TIMEOUT (5 * 1000) -#define OPLOCK_STD_TIMEOUT (15 * 1000) -#define OPLOCK_RETRIES 2 - typedef struct { uint32_t status; uint16_t errcls; @@ -1445,14 +1468,10 @@ smb_ofile_t *dir; /* This is only set by NTTransactCreate */ struct smb_sd *sd; - uint8_t op_oplock_level; + uint8_t op_oplock_level; /* requested/granted level */ + boolean_t op_oplock_levelII; /* TRUE if levelII supported */ } smb_arg_open_t; -#define SMB_OPLOCK_NONE 0 -#define SMB_OPLOCK_EXCLUSIVE 1 -#define SMB_OPLOCK_BATCH 2 -#define SMB_OPLOCK_LEVEL_II 3 - /* * SMB Request State Machine * ------------------------- @@ -1792,6 +1811,27 @@ smb_session_list_t ld_session_list; } smb_listener_daemon_t; +#define SMB_SSETUP_CMD "authentication" +#define SMB_TCON_CMD "share mapping" +#define SMB_OPIPE_CMD "pipe open" +#define SMB_THRESHOLD_REPORT_THROTTLE 50 +typedef struct smb_cmd_threshold { + char *ct_cmd; + kmutex_t ct_mutex; + volatile uint32_t ct_active_cnt; + volatile uint32_t ct_blocked_cnt; + volatile uint32_t ct_error_cnt; + uint32_t ct_threshold; + struct smb_event *ct_event; + uint32_t ct_event_id; +} smb_cmd_threshold_t; + +typedef struct { + kstat_named_t ls_files; + kstat_named_t ls_trees; + kstat_named_t ls_users; +} smb_server_legacy_kstat_t; + typedef enum smb_server_state { SMB_SERVER_STATE_CREATED = 0, SMB_SERVER_STATE_CONFIGURED, @@ -1801,6 +1841,14 @@ SMB_SERVER_STATE_SENTINEL } smb_server_state_t; +typedef struct { + kcondvar_t sp_cv; + kmutex_t sp_mutex; + uint32_t sp_cnt; + smb_llist_t sp_list; + smb_llist_t sp_fidlist; +} smb_spool_t; + #define SMB_SERVER_STATE_VALID(S) \ ASSERT(((S) == SMB_SERVER_STATE_CREATED) || \ ((S) == SMB_SERVER_STATE_CONFIGURED) || \ @@ -1857,24 +1905,47 @@ volatile uint64_t sv_rxb; volatile uint64_t sv_nreq; smb_srqueue_t sv_srqueue; + smb_spool_t sp_info; + smb_cmd_threshold_t sv_ssetup_ct; + smb_cmd_threshold_t sv_tcon_ct; + smb_cmd_threshold_t sv_opipe_ct; + kstat_t *sv_legacy_ksp; + kmutex_t sv_legacy_ksmtx; } smb_server_t; #define SMB_EVENT_MAGIC 0x45564E54 /* EVNT */ +#define SMB_EVENT_TIMEOUT 45 /* seconds */ #define SMB_EVENT_VALID(e) \ ASSERT(((e) != NULL) && ((e)->se_magic == SMB_EVENT_MAGIC)) - typedef struct smb_event { uint32_t se_magic; list_node_t se_lnd; kmutex_t se_mutex; kcondvar_t se_cv; - struct smb_server *se_server; + smb_server_t *se_server; uint32_t se_txid; boolean_t se_notified; int se_waittime; + int se_timeout; int se_errno; } smb_event_t; +typedef struct smb_kspooldoc { + uint32_t sd_magic; + list_node_t sd_lnd; + smb_inaddr_t sd_ipaddr; + uint32_t sd_spool_num; + uint16_t sd_fid; + char sd_username[MAXNAMELEN]; + char sd_path[MAXPATHLEN]; +} smb_kspooldoc_t; + +typedef struct smb_spoolfid { + uint32_t sf_magic; + list_node_t sf_lnd; + uint16_t sf_fid; +} smb_spoolfid_t; + #define SMB_INFO_NETBIOS_SESSION_SVC_RUNNING 0x0001 #define SMB_INFO_NETBIOS_SESSION_SVC_FAILED 0x0002 #define SMB_INFO_USER_LEVEL_SECURITY 0x40000000
--- a/usr/src/uts/common/smbsrv/smb_share.h Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/smbsrv/smb_share.h Thu Jul 22 14:53:56 2010 -0700 @@ -173,6 +173,8 @@ #define SMB_SHRF_PERM 0x20000000 #define SMB_SHRF_AUTOHOME 0x40000000 +#define SMB_SHARE_PRINT "print$" +#define SMB_SHARE_PRINT_LEN 6 /* * refcnt is currently only used for autohome. autohome needs a refcnt * because a user can map his autohome share from more than one client
--- a/usr/src/uts/common/smbsrv/smb_vops.h Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/smbsrv/smb_vops.h Thu Jul 22 14:53:56 2010 -0700 @@ -19,8 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _SMBSRV_SMB_VOPS_H @@ -148,6 +147,8 @@ int smb_vop_frlock(vnode_t *, cred_t *, int, flock64_t *); +int smb_vop_other_opens(vnode_t *, int); + void smb_vop_catia_v4tov5(char *, char *, int); char *smb_vop_catia_v5tov4(char *, char *, int);
--- a/usr/src/uts/common/smbsrv/smbinfo.h Thu Jul 22 12:31:36 2010 -0700 +++ b/usr/src/uts/common/smbsrv/smbinfo.h Thu Jul 22 14:53:56 2010 -0700 @@ -118,6 +118,7 @@ int32_t skc_sync_enable; int32_t skc_secmode; int32_t skc_ipv6_enable; + int32_t skc_print_enable; uint32_t skc_execflags; smb_version_t skc_version; char skc_nbdomain[NETBIOS_NAME_SZ];