summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/idmap/idmap/idmap.c19
-rw-r--r--usr/src/cmd/idmap/idmapd/adutils.c454
-rw-r--r--usr/src/cmd/idmap/idmapd/adutils.h17
-rw-r--r--usr/src/cmd/idmap/idmapd/dbutils.c369
-rw-r--r--usr/src/cmd/idmap/idmapd/directory_provider_ad.c4
-rw-r--r--usr/src/cmd/idmap/idmapd/idmap_config.c438
-rw-r--r--usr/src/cmd/idmap/idmapd/idmap_config.h26
-rw-r--r--usr/src/cmd/idmap/idmapd/idmapd.h13
-rw-r--r--usr/src/cmd/idmap/idmapd/init.c164
-rw-r--r--usr/src/cmd/idmap/idmapd/server.c18
-rw-r--r--usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c6
-rw-r--r--usr/src/lib/libadutils/common/addisc.c5
-rw-r--r--usr/src/lib/libadutils/common/adutils.c95
-rw-r--r--usr/src/lib/libadutils/common/adutils_impl.h5
-rw-r--r--usr/src/lib/libadutils/common/libadutils.h7
-rw-r--r--usr/src/lib/libadutils/common/mapfile-vers4
-rw-r--r--usr/src/lib/libidmap/common/idmap_api.c15
-rw-r--r--usr/src/lib/libshare/smb/libshare_smb.c17
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/Makefile.com2
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h1
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h5
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c25
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c2
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c9
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/samlib.c10
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/samlib.h4
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/samr_lookup.c16
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c5
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/smb_share.c70
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c180
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.c20
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/svcctl_svc.c52
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/common/winreg_svc.c3
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/common/libsmbrdr.h13
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/common/mapfile-vers2
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/common/smbrdr.h2
-rw-r--r--usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_logon.c46
-rw-r--r--usr/src/uts/common/Makefile.files11
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_common_open.c24
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_create.c2
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_delete.c17
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_directory.c191
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_dispatch.c2
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_find.c6
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_fsops.c60
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_mangle_name.c5
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c52
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_node.c253
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c4
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c30
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_odir.c31
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_ofile.c14
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_open_andx.c9
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c79
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.c891
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_query_information.c145
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_query_information2.c127
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_rename.c193
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_set_fileinfo.c683
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_set_information.c172
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_set_information2.c130
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_find.c12
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c636
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c663
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c160
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c386
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c180
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_tree.c8
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_util.c63
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_vops.c13
-rw-r--r--usr/src/uts/common/fs/smbsrv/smb_write_raw.c19
-rw-r--r--usr/src/uts/common/rpcsvc/idmap_prot.x11
-rw-r--r--usr/src/uts/common/smbsrv/cifs.h80
-rw-r--r--usr/src/uts/common/smbsrv/ndl/srvsvc.ndl5
-rw-r--r--usr/src/uts/common/smbsrv/ndl/svcctl.ndl12
-rw-r--r--usr/src/uts/common/smbsrv/smb_fsops.h4
-rw-r--r--usr/src/uts/common/smbsrv/smb_kproto.h27
-rw-r--r--usr/src/uts/common/smbsrv/smb_ktypes.h55
-rw-r--r--usr/src/uts/common/smbsrv/smb_share.h8
-rw-r--r--usr/src/uts/common/smbsrv/smb_vops.h9
-rw-r--r--usr/src/uts/common/smbsrv/winioctl.h72
-rw-r--r--usr/src/uts/common/smbsrv/winsvc.h11
83 files changed, 3909 insertions, 3803 deletions
diff --git a/usr/src/cmd/idmap/idmap/idmap.c b/usr/src/cmd/idmap/idmap/idmap.c
index 92cd73a2c1..1a57428597 100644
--- a/usr/src/cmd/idmap/idmap/idmap.c
+++ b/usr/src/cmd/idmap/idmap/idmap.c
@@ -1440,6 +1440,15 @@ print_how(idmap_how *how)
case IDMAP_MAP_TYPE_KNOWN_SID:
(void) printf(gettext("Method:\tWell-Known mapping\n"));
break;
+
+ case IDMAP_MAP_TYPE_IDMU:
+ (void) printf(gettext("Method:\tIDMU\n"));
+ (void) printf(gettext("DN:\t%s\n"),
+ CHECK_NULL(how->idmap_how_u.idmu.dn));
+ (void) printf(gettext("Attribute:\t%s=%s\n"),
+ CHECK_NULL(how->idmap_how_u.idmu.attr),
+ CHECK_NULL(how->idmap_how_u.idmu.value));
+ break;
}
}
@@ -1542,6 +1551,16 @@ print_error_info(idmap_info *info)
(void) fprintf(stderr,
gettext("Failed Method:\tWell-Known mapping\n"));
break;
+
+ case IDMAP_MAP_TYPE_IDMU:
+ (void) fprintf(stderr,
+ gettext("Failed Method:\tIDMU\n"));
+ (void) fprintf(stderr, gettext("DN:\t%s\n"),
+ CHECK_NULL(how->idmap_how_u.idmu.dn));
+ (void) fprintf(stderr, gettext("Attribute:\t%s=%s\n"),
+ CHECK_NULL(how->idmap_how_u.idmu.attr),
+ CHECK_NULL(how->idmap_how_u.idmu.value));
+ break;
}
}
diff --git a/usr/src/cmd/idmap/idmapd/adutils.c b/usr/src/cmd/idmap/idmapd/adutils.c
index 554398dfc6..5af08aacbf 100644
--- a/usr/src/cmd/idmap/idmapd/adutils.c
+++ b/usr/src/cmd/idmap/idmapd/adutils.c
@@ -55,7 +55,11 @@
#define SAN "sAMAccountName"
#define OBJSID "objectSid"
#define OBJCLASS "objectClass"
-#define SANFILTER "(sAMAccountName=%.*s)"
+#define UIDNUMBER "uidNumber"
+#define GIDNUMBER "gidNumber"
+#define UIDNUMBERFILTER "(&(objectclass=user)(uidNumber=%u))"
+#define GIDNUMBERFILTER "(&(objectclass=group)(gidNumber=%u))"
+#define SANFILTER "(sAMAccountName=%s)"
#define OBJSIDFILTER "(objectSid=%s)"
void idmap_ldap_res_search_cb(LDAP *ld, LDAPMessage **res, int rc,
@@ -85,6 +89,7 @@ typedef struct idmap_q {
char **dn; /* DN of entry */
char **attr; /* Attr for name mapping */
char **value; /* value for name mapping */
+ posix_id_t *pid; /* Posix ID found via IDMU */
idmap_retcode *rc;
adutils_rc ad_rc;
adutils_result_t *result;
@@ -103,6 +108,8 @@ struct idmap_query_state {
uint32_t qcount; /* Number of queued requests */
const char *ad_unixuser_attr;
const char *ad_unixgroup_attr;
+ int directory_based_mapping; /* enum */
+ char *default_domain;
idmap_q_t queries[1]; /* array of query results */
};
@@ -185,6 +192,7 @@ map_adrc2idmaprc(adutils_rc adrc)
idmap_retcode
idmap_lookup_batch_start(adutils_ad_t *ad, int nqueries,
+ int directory_based_mapping, const char *default_domain,
idmap_query_state_t **state)
{
idmap_query_state_t *new_state;
@@ -202,10 +210,17 @@ idmap_lookup_batch_start(adutils_ad_t *ad, int nqueries,
if ((rc = adutils_lookup_batch_start(ad, nqueries,
idmap_ldap_res_search_cb, new_state, &new_state->qs))
!= ADUTILS_SUCCESS) {
- free(new_state);
+ idmap_lookup_release_batch(&new_state);
return (map_adrc2idmaprc(rc));
}
+ new_state->default_domain = strdup(default_domain);
+ if (new_state->default_domain == NULL) {
+ idmap_lookup_release_batch(&new_state);
+ return (IDMAP_ERR_MEMORY);
+ }
+
+ new_state->directory_based_mapping = directory_based_mapping;
new_state->qsize = nqueries;
*state = new_state;
return (IDMAP_SUCCESS);
@@ -227,12 +242,24 @@ idmap_lookup_batch_set_unixattr(idmap_query_state_t *state,
* it is the result that was desired and, if so, set the result fields
* of the given idmap_q_t.
*
- * Frees the unused char * values.
+ * Except for dn and attr, all strings are consumed, either by transferring
+ * them over into the request results (where the caller will eventually free
+ * them) or by freeing them here. Note that this aligns with the "const"
+ * declarations below.
*/
static
void
-idmap_setqresults(idmap_q_t *q, char *san, char *dn, const char *attr,
- char *sid, rid_t rid, int sid_type, char *unixname)
+idmap_setqresults(
+ idmap_q_t *q,
+ char *san,
+ const char *dn,
+ const char *attr,
+ char *value,
+ char *sid,
+ rid_t rid,
+ int sid_type,
+ char *unixname,
+ posix_id_t pid)
{
char *domain;
int err1;
@@ -263,8 +290,10 @@ idmap_setqresults(idmap_q_t *q, char *san, char *dn, const char *attr,
if (q->attr != NULL && attr != NULL)
*q->attr = strdup(attr);
- if (q->value != NULL && unixname != NULL)
- *q->value = strdup(unixname);
+ if (q->value != NULL && value != NULL) {
+ *q->value = value;
+ value = NULL;
+ }
/* Set results */
if (q->sid) {
@@ -294,6 +323,10 @@ idmap_setqresults(idmap_q_t *q, char *san, char *dn, const char *attr,
san = NULL;
}
+ if (q->pid != NULL && pid != SENTINEL_PID) {
+ *q->pid = pid;
+ }
+
q->ad_rc = ADUTILS_SUCCESS;
out:
@@ -302,6 +335,7 @@ out:
free(sid);
free(domain);
free(unixname);
+ free(value);
}
#define BVAL_CASEEQ(bv, str) \
@@ -323,19 +357,17 @@ idmap_bv_objclass2sidtype(BerValue **bvalues, int *sid_type)
return (0);
/*
- * We iterate over all the values because computer is a
- * sub-class of user.
+ * We consider Computer to be a subclass of User, so we can just
+ * ignore Computer entries and pay attention to the accompanying
+ * User entries.
*/
for (cbval = bvalues; *cbval != NULL; cbval++) {
- if (BVAL_CASEEQ(cbval, "Computer")) {
- *sid_type = _IDMAP_T_COMPUTER;
- break;
- } else if (BVAL_CASEEQ(cbval, "Group")) {
+ if (BVAL_CASEEQ(cbval, "group")) {
*sid_type = _IDMAP_T_GROUP;
break;
- } else if (BVAL_CASEEQ(cbval, "USER")) {
+ } else if (BVAL_CASEEQ(cbval, "user")) {
*sid_type = _IDMAP_T_USER;
- /* Continue looping -- this may be a computer yet */
+ break;
}
/*
* "else if (*sid_type = _IDMAP_T_USER)" then this is a
@@ -354,169 +386,121 @@ void
idmap_extract_object(idmap_query_state_t *state, idmap_q_t *q,
LDAPMessage *res, LDAP *ld)
{
- BerElement *ber = NULL;
BerValue **bvalues;
- char *attr;
- const char *unixuser_attr = NULL;
- const char *unixgroup_attr = NULL;
- char *unixuser = NULL;
- char *unixgroup = NULL;
- char *dn = NULL;
+ const char *attr = NULL;
+ char *value = NULL;
+ char *unix_name = NULL;
+ char *dn;
char *san = NULL;
char *sid = NULL;
rid_t rid = 0;
- int sid_type = _IDMAP_T_UNDEF;
- int has_class, has_san, has_sid;
- int has_unixuser, has_unixgroup;
+ int sid_type;
+ int ok;
+ posix_id_t pid = SENTINEL_PID;
assert(q->rc != NULL);
+ assert(q->domain == NULL || *q->domain == NULL);
if ((dn = ldap_get_dn(ld, res)) == NULL)
return;
- assert(q->domain == NULL || *q->domain == NULL);
-
- /*
- * If the caller has requested unixname then determine the
- * AD attribute name that will have the unixname.
- */
- if (q->unixname != NULL) {
- if (q->eunixtype == _IDMAP_T_USER)
- unixuser_attr = state->ad_unixuser_attr;
- else if (q->eunixtype == _IDMAP_T_GROUP)
- unixgroup_attr = state->ad_unixgroup_attr;
- else if (q->eunixtype == _IDMAP_T_UNDEF) {
- /*
- * This is the case where we don't know
- * before hand whether we need unixuser
- * or unixgroup. This will be determined
- * by the "sid_type" (i.e whether the given
- * winname is user or group). If sid_type
- * turns out to be user we will return
- * unixuser (if found) and if it is a group
- * we will return unixgroup (if found). We
- * lookup for both ad_unixuser_attr and
- * ad_unixgroup_attr and discard one of them
- * after we know the "sidtype". This
- * supports the following type of lookups.
- *
- * Example:
- * $idmap show -c winname:foo
- * In the above example, idmap will
- * return uid if winname is winuser
- * and gid if winname is wingroup.
- */
- unixuser_attr = state->ad_unixuser_attr;
- unixgroup_attr = state->ad_unixgroup_attr;
- }
+ bvalues = ldap_get_values_len(ld, res, OBJCLASS);
+ if (bvalues == NULL) {
+ /*
+ * Didn't find objectclass. Something's wrong with our
+ * AD data.
+ */
+ idmapdlog(LOG_ERR, "%s has no %s", dn, OBJCLASS);
+ goto out;
}
-
- has_class = has_san = has_sid = has_unixuser = has_unixgroup = 0;
- for (attr = ldap_first_attribute(ld, res, &ber); attr != NULL;
- attr = ldap_next_attribute(ld, res, ber)) {
- bvalues = NULL; /* for memory management below */
-
+ ok = idmap_bv_objclass2sidtype(bvalues, &sid_type);
+ ldap_value_free_len(bvalues);
+ if (!ok) {
/*
- * If this is an attribute we are looking for and
- * haven't seen it yet, parse it
+ * Didn't understand objectclass. Something's wrong with our
+ * AD data.
*/
- if (q->sid != NULL && !has_sid &&
- strcasecmp(attr, OBJSID) == 0) {
- bvalues = ldap_get_values_len(ld, res, attr);
- if (bvalues != NULL) {
- sid = adutils_bv_objsid2sidstr(
- bvalues[0], &rid);
- has_sid = (sid != NULL);
- }
- } else if (!has_san && strcasecmp(attr, SAN) == 0) {
+ idmapdlog(LOG_ERR, "%s has unexpected %s", dn, OBJCLASS);
+ goto out;
+ }
+
+ if (state->directory_based_mapping == DIRECTORY_MAPPING_IDMU &&
+ q->pid != NULL) {
+ if (sid_type == _IDMAP_T_USER)
+ attr = UIDNUMBER;
+ else if (sid_type == _IDMAP_T_GROUP)
+ attr = GIDNUMBER;
+ if (attr != NULL) {
bvalues = ldap_get_values_len(ld, res, attr);
if (bvalues != NULL) {
- san = adutils_bv_name2str(bvalues[0]);
- has_san = (san != NULL);
- }
- } else if (!has_class && strcasecmp(attr, OBJCLASS) == 0) {
- bvalues = ldap_get_values_len(ld, res, attr);
- has_class = idmap_bv_objclass2sidtype(bvalues,
- &sid_type);
- if (has_class && q->unixname != NULL &&
- q->eunixtype == _IDMAP_T_UNDEF) {
- /*
- * This is the case where we didn't
- * know whether we wanted unixuser or
- * unixgroup as described above.
- * Now since we know the "sid_type"
- * we discard the unwanted value
- * if it was retrieved before we
- * got here.
- */
- if (sid_type == _IDMAP_T_USER) {
- free(unixgroup);
- unixgroup_attr = unixgroup = NULL;
- } else if (sid_type == _IDMAP_T_GROUP) {
- free(unixuser);
- unixuser_attr = unixuser = NULL;
- } else {
- free(unixuser);
- free(unixgroup);
- unixuser_attr = unixuser = NULL;
- unixgroup_attr = unixgroup = NULL;
+ value = adutils_bv_str(bvalues[0]);
+ if (!adutils_bv_uint(bvalues[0], &pid)) {
+ idmapdlog(LOG_ERR,
+ "%s has Invalid %s value \"%s\"",
+ dn, attr, value);
}
+ ldap_value_free_len(bvalues);
}
- } else if (!has_unixuser && unixuser_attr != NULL &&
- strcasecmp(attr, unixuser_attr) == 0) {
- bvalues = ldap_get_values_len(ld, res, attr);
- if (bvalues != NULL) {
- unixuser = adutils_bv_name2str(bvalues[0]);
- has_unixuser = (unixuser != NULL);
- }
+ }
+ }
+
+ if (state->directory_based_mapping == DIRECTORY_MAPPING_NAME &&
+ q->unixname != NULL) {
+ /*
+ * If the caller has requested unixname then determine the
+ * AD attribute name that will have the unixname, and retrieve
+ * its value.
+ */
+ int unix_type;
+ /*
+ * Determine the target UNIX type.
+ *
+ * If the caller specified one, use that. Otherwise, give the
+ * same type that as we found for the Windows user.
+ */
+ unix_type = q->eunixtype;
+ if (unix_type == _IDMAP_T_UNDEF) {
+ if (sid_type == _IDMAP_T_USER)
+ unix_type = _IDMAP_T_USER;
+ else if (sid_type == _IDMAP_T_GROUP)
+ unix_type = _IDMAP_T_GROUP;
+ }
- } else if (!has_unixgroup && unixgroup_attr != NULL &&
- strcasecmp(attr, unixgroup_attr) == 0) {
+ if (unix_type == _IDMAP_T_USER)
+ attr = state->ad_unixuser_attr;
+ else if (unix_type == _IDMAP_T_GROUP)
+ attr = state->ad_unixgroup_attr;
+
+ if (attr != NULL) {
bvalues = ldap_get_values_len(ld, res, attr);
if (bvalues != NULL) {
- unixgroup = adutils_bv_name2str(bvalues[0]);
- has_unixgroup = (unixgroup != NULL);
+ unix_name = adutils_bv_str(bvalues[0]);
+ ldap_value_free_len(bvalues);
+ value = strdup(unix_name);
}
}
+ }
- if (bvalues != NULL)
- ldap_value_free_len(bvalues);
- ldap_memfree(attr);
-
- if (has_class && has_san &&
- (q->sid == NULL || has_sid) &&
- (unixuser_attr == NULL || has_unixuser) &&
- (unixgroup_attr == NULL || has_unixgroup)) {
- /* Got what we need */
- break;
- }
+ bvalues = ldap_get_values_len(ld, res, SAN);
+ if (bvalues != NULL) {
+ san = adutils_bv_str(bvalues[0]);
+ ldap_value_free_len(bvalues);
}
- if (!has_class) {
- /*
- * Didn't find objectclass. Something's wrong with our
- * AD data.
- */
- free(san);
- free(sid);
- free(unixuser);
- free(unixgroup);
- } else {
- /*
- * Either we got what we needed and came out of the loop
- * early OR we completed the loop in which case we didn't
- * find some attributes that we were looking for. In either
- * case set the result with what we got.
- */
- idmap_setqresults(q, san, dn,
- (unixuser != NULL) ? unixuser_attr : unixgroup_attr,
- sid, rid, sid_type,
- (unixuser != NULL) ? unixuser : unixgroup);
+ if (q->sid != NULL) {
+ bvalues = ldap_get_values_len(ld, res, OBJSID);
+ if (bvalues != NULL) {
+ sid = adutils_bv_objsid2sidstr(bvalues[0], &rid);
+ ldap_value_free_len(bvalues);
+ }
}
- if (ber != NULL)
- ber_free(ber, 0);
+ idmap_setqresults(q, san, dn,
+ attr, value,
+ sid, rid, sid_type,
+ unix_name, pid);
+out:
ldap_memfree(dn);
}
@@ -573,6 +557,7 @@ idmap_lookup_release_batch(idmap_query_state_t **state)
return;
adutils_lookup_batch_release(&(*state)->qs);
idmap_cleanup_batch(*state);
+ free((*state)->default_domain);
free(*state);
*state = NULL;
}
@@ -610,19 +595,13 @@ idmap_batch_add1(idmap_query_state_t *state, const char *filter,
char **dn, char **attr, char **value,
char **canonname, char **dname,
char **sid, rid_t *rid, int *sid_type, char **unixname,
+ posix_id_t *pid,
idmap_retcode *rc)
{
adutils_rc ad_rc;
int qid, i;
idmap_q_t *q;
- static char *attrs[] = {
- SAN,
- OBJSID,
- OBJCLASS,
- NULL, /* placeholder for unixname attr */
- NULL, /* placeholder for unixname attr */
- NULL
- };
+ char *attrs[20]; /* Plenty */
qid = atomic_inc_32_nv(&state->qcount) - 1;
q = &(state->queries[qid]);
@@ -648,18 +627,33 @@ idmap_batch_add1(idmap_query_state_t *state, const char *filter,
q->dn = dn;
q->attr = attr;
q->value = value;
+ q->pid = pid;
+
+ /* Add attributes that are not always needed */
+ i = 0;
+ attrs[i++] = SAN;
+ attrs[i++] = OBJSID;
+ attrs[i++] = OBJCLASS;
- /* Add unixuser/unixgroup attribute names to the attrs list */
if (unixname != NULL) {
- i = 3;
+ /* Add unixuser/unixgroup attribute names to the attrs list */
if (eunixtype != _IDMAP_T_GROUP &&
state->ad_unixuser_attr != NULL)
attrs[i++] = (char *)state->ad_unixuser_attr;
if (eunixtype != _IDMAP_T_USER &&
state->ad_unixgroup_attr != NULL)
- attrs[i] = (char *)state->ad_unixgroup_attr;
+ attrs[i++] = (char *)state->ad_unixgroup_attr;
}
+ if (pid != NULL) {
+ if (eunixtype != _IDMAP_T_GROUP)
+ attrs[i++] = UIDNUMBER;
+ if (eunixtype != _IDMAP_T_USER)
+ attrs[i++] = GIDNUMBER;
+ }
+
+ attrs[i] = NULL;
+
/*
* Provide sane defaults for the results in case we never hear
* back from the DS before closing the connection.
@@ -707,11 +701,11 @@ idmap_name2sid_batch_add1(idmap_query_state_t *state,
const char *name, const char *dname, int eunixtype,
char **dn, char **attr, char **value,
char **canonname, char **sid, rid_t *rid,
- int *sid_type, char **unixname, idmap_retcode *rc)
+ int *sid_type, char **unixname,
+ posix_id_t *pid, idmap_retcode *rc)
{
idmap_retcode retcode;
- int len, samAcctNameLen;
- char *filter = NULL, *s_name;
+ char *filter, *s_name;
char *ecanonname, *edomain; /* expected canonname */
/*
@@ -725,37 +719,16 @@ idmap_name2sid_batch_add1(idmap_query_state_t *state,
* the user/group and whether it is a user or a group.
*/
- /*
- * We need the name and the domain name separately and as
- * name@domain. We also allow the domain to be provided
- * separately.
- */
- samAcctNameLen = strlen(name);
-
if ((ecanonname = strdup(name)) == NULL)
return (IDMAP_ERR_MEMORY);
if (dname == NULL || *dname == '\0') {
- if ((dname = strchr(name, '@')) != NULL) {
- /* 'name' is qualified with a domain name */
- if ((edomain = strdup(dname + 1)) == NULL) {
- free(ecanonname);
- return (IDMAP_ERR_MEMORY);
- }
- *strchr(ecanonname, '@') = '\0';
- } else {
- /* 'name' not qualified and dname not given */
- dname = adutils_lookup_batch_getdefdomain(state->qs);
- assert(dname != NULL);
- if (*dname == '\0') {
- free(ecanonname);
- return (IDMAP_ERR_DOMAIN);
- }
- edomain = strdup(dname);
- if (edomain == NULL) {
- free(ecanonname);
- return (IDMAP_ERR_MEMORY);
- }
+ /* 'name' not qualified and dname not given */
+ dname = state->default_domain;
+ edomain = strdup(dname);
+ if (edomain == NULL) {
+ free(ecanonname);
+ return (IDMAP_ERR_MEMORY);
}
} else {
if ((edomain = strdup(dname)) == NULL) {
@@ -778,21 +751,18 @@ idmap_name2sid_batch_add1(idmap_query_state_t *state,
}
/* Assemble filter */
- len = snprintf(NULL, 0, SANFILTER, samAcctNameLen, s_name) + 1;
- if ((filter = (char *)malloc(len)) == NULL) {
+ (void) asprintf(&filter, SANFILTER, s_name);
+ if (s_name != name)
+ free(s_name);
+ if (filter == NULL) {
free(ecanonname);
free(edomain);
- if (s_name != name)
- free(s_name);
return (IDMAP_ERR_MEMORY);
}
- (void) snprintf(filter, len, SANFILTER, samAcctNameLen, s_name);
- if (s_name != name)
- free(s_name);
retcode = idmap_batch_add1(state, filter, ecanonname, edomain,
eunixtype, dn, attr, value, canonname, NULL, sid, rid, sid_type,
- unixname, rc);
+ unixname, pid, rc);
free(filter);
@@ -804,11 +774,11 @@ idmap_sid2name_batch_add1(idmap_query_state_t *state,
const char *sid, const rid_t *rid, int eunixtype,
char **dn, char **attr, char **value,
char **name, char **dname, int *sid_type,
- char **unixname, idmap_retcode *rc)
+ char **unixname, posix_id_t *pid, idmap_retcode *rc)
{
idmap_retcode retcode;
- int flen, ret;
- char *filter = NULL;
+ int ret;
+ char *filter;
char cbinsid[ADUTILS_MAXHEXBINSID + 1];
/*
@@ -827,13 +797,13 @@ idmap_sid2name_batch_add1(idmap_query_state_t *state,
return (IDMAP_ERR_SID);
/* Assemble filter */
- flen = snprintf(NULL, 0, OBJSIDFILTER, cbinsid) + 1;
- if ((filter = (char *)malloc(flen)) == NULL)
+ (void) asprintf(&filter, OBJSIDFILTER, cbinsid);
+ if (filter == NULL)
return (IDMAP_ERR_MEMORY);
- (void) snprintf(filter, flen, OBJSIDFILTER, cbinsid);
retcode = idmap_batch_add1(state, filter, NULL, NULL, eunixtype,
- dn, attr, value, name, dname, NULL, NULL, sid_type, unixname, rc);
+ dn, attr, value, name, dname, NULL, NULL, sid_type, unixname,
+ pid, rc);
free(filter);
@@ -848,9 +818,8 @@ idmap_unixname2sid_batch_add1(idmap_query_state_t *state,
char **dname, int *sid_type, idmap_retcode *rc)
{
idmap_retcode retcode;
- int len, ulen;
- char *filter = NULL, *s_unixname;
- const char *attrname = NULL;
+ char *filter, *s_unixname;
+ const char *attrname;
/* Get unixuser or unixgroup AD attribute name */
attrname = (is_user) ?
@@ -863,22 +832,17 @@ idmap_unixname2sid_batch_add1(idmap_query_state_t *state,
return (IDMAP_ERR_MEMORY);
/* Assemble filter */
- ulen = strlen(unixname);
- len = snprintf(NULL, 0, "(&(objectclass=%s)(%s=%.*s))",
- is_wuser ? "user" : "group", attrname, ulen, s_unixname) + 1;
- if ((filter = (char *)malloc(len)) == NULL) {
- if (s_unixname != unixname)
- free(s_unixname);
- return (IDMAP_ERR_MEMORY);
- }
- (void) snprintf(filter, len, "(&(objectclass=%s)(%s=%.*s))",
- is_wuser ? "user" : "group", attrname, ulen, s_unixname);
+ (void) asprintf(&filter, "(&(objectclass=%s)(%s=%s))",
+ is_wuser ? "user" : "group", attrname, s_unixname);
if (s_unixname != unixname)
free(s_unixname);
+ if (filter == NULL) {
+ return (IDMAP_ERR_MEMORY);
+ }
retcode = idmap_batch_add1(state, filter, NULL, NULL,
_IDMAP_T_UNDEF, dn, NULL, NULL, name, dname, sid, rid, sid_type,
- NULL, rc);
+ NULL, NULL, rc);
if (retcode == IDMAP_SUCCESS && attr != NULL) {
if ((*attr = strdup(attrname)) == NULL)
@@ -886,12 +850,50 @@ idmap_unixname2sid_batch_add1(idmap_query_state_t *state,
}
if (retcode == IDMAP_SUCCESS && value != NULL) {
- if (ulen > 0) {
- if ((*value = strdup(unixname)) == NULL)
- retcode = IDMAP_ERR_MEMORY;
- }
- else
- *value = NULL;
+ if ((*value = strdup(unixname)) == NULL)
+ retcode = IDMAP_ERR_MEMORY;
+ }
+
+ free(filter);
+
+ return (retcode);
+}
+
+idmap_retcode
+idmap_pid2sid_batch_add1(idmap_query_state_t *state,
+ posix_id_t pid, int is_user,
+ char **dn, char **attr, char **value,
+ char **sid, rid_t *rid, char **name,
+ char **dname, int *sid_type, idmap_retcode *rc)
+{
+ idmap_retcode retcode;
+ char *filter;
+ const char *attrname;
+
+ /* Assemble filter */
+ if (is_user) {
+ (void) asprintf(&filter, UIDNUMBERFILTER, pid);
+ attrname = UIDNUMBER;
+ } else {
+ (void) asprintf(&filter, GIDNUMBERFILTER, pid);
+ attrname = GIDNUMBER;
+ }
+ if (filter == NULL)
+ return (IDMAP_ERR_MEMORY);
+
+ retcode = idmap_batch_add1(state, filter, NULL, NULL,
+ _IDMAP_T_UNDEF, dn, NULL, NULL, name, dname, sid, rid, sid_type,
+ NULL, NULL, rc);
+
+ if (retcode == IDMAP_SUCCESS && attr != NULL) {
+ if ((*attr = strdup(attrname)) == NULL)
+ retcode = IDMAP_ERR_MEMORY;
+ }
+
+ if (retcode == IDMAP_SUCCESS && value != NULL) {
+ (void) asprintf(value, "%u", pid);
+ if (*value == NULL)
+ retcode = IDMAP_ERR_MEMORY;
}
free(filter);
diff --git a/usr/src/cmd/idmap/idmapd/adutils.h b/usr/src/cmd/idmap/idmapd/adutils.h
index a6195bf035..88807f01d8 100644
--- a/usr/src/cmd/idmap/idmapd/adutils.h
+++ b/usr/src/cmd/idmap/idmapd/adutils.h
@@ -65,9 +65,9 @@ extern "C" {
#define _IDMAP_T_USER -1004
#define _IDMAP_T_GROUP -1005
#define _IDMAP_T_DOMAIN -1006
-#define _IDMAP_T_COMPUTER -1007
typedef uint32_t rid_t;
+typedef uid_t posix_id_t;
typedef struct idmap_query_state idmap_query_state_t;
@@ -95,7 +95,8 @@ int idmap_add_ds(adutils_ad_t *ad, const char *host, int port);
/* Start a batch of lookups */
idmap_retcode idmap_lookup_batch_start(adutils_ad_t *ad, int nqueries,
- idmap_query_state_t **state);
+ int directory_based_mapping, const char *default_domain,
+ idmap_query_state_t **state);
/* End a batch and release its idmap_query_state_t object */
idmap_retcode idmap_lookup_batch_end(idmap_query_state_t **state);
@@ -120,7 +121,7 @@ idmap_retcode idmap_name2sid_batch_add1(idmap_query_state_t *state,
const char *name, const char *dname, int eunixtype,
char **dn, char **attr, char **value, char **canonname,
char **sid, rid_t *rid, int *sid_type, char **unixname,
- idmap_retcode *rc);
+ posix_id_t *pid, idmap_retcode *rc);
/*
* Add a SID->name lookup
*
@@ -139,7 +140,7 @@ idmap_retcode idmap_sid2name_batch_add1(idmap_query_state_t *state,
const char *sid, const rid_t *rid, int eunixtype,
char **dn, char **attr, char **value, char **name,
char **dname, int *sid_type, char **unixname,
- idmap_retcode *rc);
+ posix_id_t *pid, idmap_retcode *rc);
/*
* Add a unixname->SID lookup
@@ -150,6 +151,14 @@ idmap_retcode idmap_unixname2sid_batch_add1(idmap_query_state_t *state,
char **name, char **dname, int *sid_type, idmap_retcode *rc);
/*
+ * Add a PID->SID lookup
+ */
+idmap_retcode idmap_pid2sid_batch_add1(idmap_query_state_t *state,
+ posix_id_t pid, int is_user,
+ char **dn, char **attr, char **value, char **sid, rid_t *rid,
+ char **name, char **dname, int *sid_type, idmap_retcode *rc);
+
+/*
* Set unixname attribute names for the batch for AD-based name mapping
*/
void idmap_lookup_batch_set_unixattr(idmap_query_state_t *state,
diff --git a/usr/src/cmd/idmap/idmapd/dbutils.c b/usr/src/cmd/idmap/idmapd/dbutils.c
index 651a364b5d..6b2c3d3723 100644
--- a/usr/src/cmd/idmap/idmapd/dbutils.c
+++ b/usr/src/cmd/idmap/idmapd/dbutils.c
@@ -102,7 +102,12 @@ typedef struct idmap_tsd {
struct idmap_busy db_busy;
} idmap_tsd_t;
-
+/*
+ * Flags to indicate how local the directory we're consulting is.
+ * If neither is set, it means the directory belongs to a remote forest.
+ */
+#define DOMAIN_IS_LOCAL 0x01
+#define FOREST_IS_LOCAL 0x02
static const int cache_delay_table[] =
{ 1, 2, 5, 10, 15, 20, 25, 30, 35, 40,
@@ -1051,13 +1056,13 @@ sql_compile_n_step_once(sqlite *db, char *sql, sqlite_vm **vm, int *ncol,
* requests.
*
* sid2uid/uid2sid:
- * none -> ds_name_mapping_enabled != true
+ * none -> directory_based_mapping != DIRECTORY_MAPPING_NAME
* AD-mode -> !nldap_winname_attr && ad_unixuser_attr
* nldap-mode -> nldap_winname_attr && !ad_unixuser_attr
* mixed-mode -> nldap_winname_attr && ad_unixuser_attr
*
* sid2gid/gid2sid:
- * none -> ds_name_mapping_enabled != true
+ * none -> directory_based_mapping != DIRECTORY_MAPPING_NAME
* AD-mode -> !nldap_winname_attr && ad_unixgroup_attr
* nldap-mode -> nldap_winname_attr && !ad_unixgroup_attr
* mixed-mode -> nldap_winname_attr && ad_unixgroup_attr
@@ -1073,6 +1078,9 @@ load_cfg_in_state(lookup_state_t *state)
if (_idmapdstate.cfg->pgcfg.eph_map_unres_sids)
state->eph_map_unres_sids = 1;
+ state->directory_based_mapping =
+ _idmapdstate.cfg->pgcfg.directory_based_mapping;
+
if (_idmapdstate.cfg->pgcfg.default_domain != NULL) {
state->defdom =
strdup(_idmapdstate.cfg->pgcfg.default_domain);
@@ -1084,10 +1092,13 @@ load_cfg_in_state(lookup_state_t *state)
UNLOCK_CONFIG();
return (IDMAP_SUCCESS);
}
- if (!_idmapdstate.cfg->pgcfg.ds_name_mapping_enabled) {
+
+ if (_idmapdstate.cfg->pgcfg.directory_based_mapping !=
+ DIRECTORY_MAPPING_NAME) {
UNLOCK_CONFIG();
return (IDMAP_SUCCESS);
}
+
if (_idmapdstate.cfg->pgcfg.nldap_winname_attr != NULL) {
state->nm_siduid =
(_idmapdstate.cfg->pgcfg.ad_unixuser_attr != NULL)
@@ -1649,8 +1660,17 @@ out:
case IDMAP_MAP_TYPE_KNOWN_SID:
break;
+ case IDMAP_MAP_TYPE_IDMU:
+ res->info.how.idmap_how_u.idmu.dn =
+ strdup(values[7]);
+ res->info.how.idmap_how_u.idmu.attr =
+ strdup(values[8]);
+ res->info.how.idmap_how_u.idmu.value =
+ strdup(values[9]);
+ break;
+
default:
- /* Unknow mapping type */
+ /* Unknown mapping type */
assert(FALSE);
}
}
@@ -1804,10 +1824,11 @@ lookup_name_cache(sqlite *cache, idmap_mapping *req, idmap_id_res *res)
static int
ad_lookup_batch_int(lookup_state_t *state, idmap_mapping_batch *batch,
- idmap_ids_res *result, int index, int *num_processed)
+ idmap_ids_res *result, adutils_ad_t *dir, int how_local,
+ int *num_processed)
{
idmap_retcode retcode;
- int i, num_queued, type, is_wuser, is_user;
+ int i, num_queued, is_wuser, is_user;
int next_request;
int retries = 0, eunixtype;
char **unixname;
@@ -1829,10 +1850,17 @@ ad_lookup_batch_int(lookup_state_t *state, idmap_mapping_batch *batch,
* call. But why un-necessarily allocate memory. That may
* be an option if req->id2.idtype cannot be re-used in
* future.
+ *
+ * Similarly, we use req->id2.idmap_id_u.uid to return uidNumber
+ * or gidNumber supplied by IDMU, and reset it back to SENTINEL_PID
+ * when we're done. Note that the query always puts the result in
+ * req->id2.idmap_id_u.uid, not .gid.
*/
retry:
- retcode = idmap_lookup_batch_start(_idmapdstate.ads[index],
- state->ad_nqueries, &qs);
+ retcode = idmap_lookup_batch_start(dir, state->ad_nqueries,
+ state->directory_based_mapping,
+ state->defdom,
+ &qs);
if (retcode != IDMAP_SUCCESS) {
if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR &&
retries++ < ADUTILS_DEF_NUM_RETRIES)
@@ -1844,10 +1872,10 @@ retry:
restore_svc();
- if (index == 0) {
+ if (how_local & FOREST_IS_LOCAL) {
/*
* Directory based name mapping is only performed within the
- * joined forest (index == 0). We don't trust other "trusted"
+ * joined forest. We don't trust other "trusted"
* forests to provide DS-based name mapping information because
* AD's definition of "cross-forest trust" does not encompass
* this sort of behavior.
@@ -1863,12 +1891,17 @@ retry:
retcode = IDMAP_SUCCESS;
req->id2.idtype = IDMAP_NONE;
+ req->id2.idmap_id_u.uid = SENTINEL_PID;
- /* Skip if not marked for this AD lookup */
- if (!(req->direction & _IDMAP_F_LOOKUP_AD) ||
- (req->direction & _IDMAP_F_LOOKUP_OTHER_AD))
+ /* Skip if no AD lookup required */
+ if (!(req->direction & _IDMAP_F_LOOKUP_AD))
+ continue;
+
+ /* Skip if we've already tried and gotten a "not found" */
+ if (req->direction & _IDMAP_F_LOOKUP_OTHER_AD)
continue;
+ /* Skip if we've already either succeeded or failed */
if (res->retcode != IDMAP_ERR_RETRIABLE_NET_ERR)
continue;
@@ -1876,9 +1909,12 @@ retry:
/* win2unix request: */
+ posix_id_t *pid = NULL;
unixname = dn = attr = value = NULL;
eunixtype = _IDMAP_T_UNDEF;
- if (req->id2name == NULL) {
+ if (state->directory_based_mapping ==
+ DIRECTORY_MAPPING_NAME &&
+ req->id2name == NULL) {
if (res->id.idtype == IDMAP_UID &&
AD_OR_MIXED(state->nm_siduid)) {
eunixtype = _IDMAP_T_USER;
@@ -1891,21 +1927,39 @@ retry:
AD_OR_MIXED(state->nm_sidgid)) {
unixname = &req->id2name;
}
- }
- if (unixname != NULL) {
+ if (unixname != NULL) {
+ /*
+ * Get how info for DS-based name
+ * mapping only if AD or MIXED
+ * mode is enabled.
+ */
+ idmap_info_free(&res->info);
+ res->info.src = IDMAP_MAP_SRC_NEW;
+ how->map_type = IDMAP_MAP_TYPE_DS_AD;
+ dn = &how->idmap_how_u.ad.dn;
+ attr = &how->idmap_how_u.ad.attr;
+ value = &how->idmap_how_u.ad.value;
+ }
+ } else if (state->directory_based_mapping ==
+ DIRECTORY_MAPPING_IDMU &&
+ (how_local & DOMAIN_IS_LOCAL)) {
/*
- * Get how info for DS-based name
- * mapping only if AD or MIXED
- * mode is enabled.
+ * Ensure that we only do IDMU processing
+ * when querying the domain we've joined.
+ */
+ pid = &req->id2.idmap_id_u.uid;
+ /*
+ * Get how info for IDMU based mapping.
*/
idmap_info_free(&res->info);
res->info.src = IDMAP_MAP_SRC_NEW;
- how->map_type = IDMAP_MAP_TYPE_DS_AD;
- dn = &how->idmap_how_u.ad.dn;
- attr = &how->idmap_how_u.ad.attr;
- value = &how->idmap_how_u.ad.value;
+ how->map_type = IDMAP_MAP_TYPE_IDMU;
+ dn = &how->idmap_how_u.idmu.dn;
+ attr = &how->idmap_how_u.idmu.attr;
+ value = &how->idmap_how_u.idmu.value;
}
+
if (req->id1.idmap_id_u.sid.prefix != NULL) {
/* Lookup AD by SID */
retcode = idmap_sid2name_batch_add1(
@@ -1917,6 +1971,7 @@ retry:
(req->id1domain == NULL) ?
&req->id1domain : NULL,
(int *)&req->id2.idtype, unixname,
+ pid,
&res->retcode);
if (retcode == IDMAP_SUCCESS)
num_queued++;
@@ -1931,6 +1986,7 @@ retry:
&req->id1.idmap_id_u.sid.prefix,
&req->id1.idmap_id_u.sid.rid,
(int *)&req->id2.idtype, unixname,
+ pid,
&res->retcode);
if (retcode == IDMAP_SUCCESS)
num_queued++;
@@ -1963,7 +2019,7 @@ retry:
NULL, NULL, NULL,
&req->id2name,
&req->id2domain, (int *)&req->id2.idtype,
- NULL, &res->retcode);
+ NULL, NULL, &res->retcode);
if (retcode == IDMAP_SUCCESS)
num_queued++;
} else if (req->id2name != NULL) {
@@ -1981,9 +2037,40 @@ retry:
&res->id.idmap_id_u.sid.prefix,
&res->id.idmap_id_u.sid.rid,
(int *)&req->id2.idtype, NULL,
+ NULL,
&res->retcode);
if (retcode == IDMAP_SUCCESS)
num_queued++;
+ } else if (state->directory_based_mapping ==
+ DIRECTORY_MAPPING_IDMU &&
+ (how_local & DOMAIN_IS_LOCAL)) {
+ assert(req->id1.idmap_id_u.uid != SENTINEL_PID);
+ is_user = IS_REQUEST_UID(*req);
+ if (res->id.idtype == IDMAP_USID)
+ is_wuser = 1;
+ else if (res->id.idtype == IDMAP_GSID)
+ is_wuser = 0;
+ else
+ is_wuser = is_user;
+
+ /* IDMU can't do diagonal mappings */
+ if (is_user != is_wuser)
+ continue;
+
+ idmap_info_free(&res->info);
+ res->info.src = IDMAP_MAP_SRC_NEW;
+ how->map_type = IDMAP_MAP_TYPE_IDMU;
+ retcode = idmap_pid2sid_batch_add1(
+ qs, req->id1.idmap_id_u.uid, is_user,
+ &how->idmap_how_u.ad.dn,
+ &how->idmap_how_u.ad.attr,
+ &how->idmap_how_u.ad.value,
+ &res->id.idmap_id_u.sid.prefix,
+ &res->id.idmap_id_u.sid.rid,
+ &req->id2name, &req->id2domain,
+ (int *)&req->id2.idtype, &res->retcode);
+ if (retcode == IDMAP_SUCCESS)
+ num_queued++;
} else if (req->id1name != NULL) {
/*
* No SID and no winname but we've unixname.
@@ -2018,9 +2105,6 @@ retry:
req->direction |= _IDMAP_F_LOOKUP_OTHER_AD;
retcode = IDMAP_SUCCESS;
} else if (retcode != IDMAP_SUCCESS) {
- idmap_lookup_release_batch(&qs);
- num_queued = 0;
- next_request = i + 1;
break;
}
} /* End of for loop */
@@ -2031,6 +2115,10 @@ retry:
retcode = idmap_lookup_batch_end(&qs);
else
idmap_lookup_release_batch(&qs);
+ } else {
+ idmap_lookup_release_batch(&qs);
+ num_queued = 0;
+ next_request = i + 1;
}
if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR &&
@@ -2063,15 +2151,31 @@ out:
* and update the idtype in request.
*/
for (i = 0; i < batch->idmap_mapping_batch_len; i++) {
+ int type;
+ uid_t posix_id;
+
req = &batch->idmap_mapping_batch_val[i];
type = req->id2.idtype;
req->id2.idtype = IDMAP_NONE;
+ posix_id = req->id2.idmap_id_u.uid;
+ req->id2.idmap_id_u.uid = SENTINEL_PID;
res = &result->ids.ids_val[i];
- how = &res->info.how;
- if (!(req->direction & _IDMAP_F_LOOKUP_AD) ||
- (req->direction & _IDMAP_F_LOOKUP_OTHER_AD))
+
+ /*
+ * If it didn't need AD lookup, ignore it.
+ */
+ if (!(req->direction & _IDMAP_F_LOOKUP_AD))
continue;
+ /*
+ * If we deferred it this time, reset for the next
+ * AD server.
+ */
+ if (req->direction & _IDMAP_F_LOOKUP_OTHER_AD) {
+ req->direction &= ~_IDMAP_F_LOOKUP_OTHER_AD;
+ continue;
+ }
+
/* Count number processed */
(*num_processed)++;
@@ -2101,12 +2205,38 @@ out:
case _IDMAP_T_USER:
if (res->id.idtype == IDMAP_POSIXID)
res->id.idtype = IDMAP_UID;
+ /*
+ * We found a user. If we got information
+ * from IDMU and we were expecting a user,
+ * copy the id.
+ */
+ if (posix_id != SENTINEL_PID &&
+ res->id.idtype == IDMAP_UID) {
+ res->id.idmap_id_u.uid = posix_id;
+ res->direction = IDMAP_DIRECTION_BI;
+ res->info.how.map_type =
+ IDMAP_MAP_TYPE_IDMU;
+ res->info.src = IDMAP_MAP_SRC_NEW;
+ }
req->id1.idtype = IDMAP_USID;
break;
case _IDMAP_T_GROUP:
if (res->id.idtype == IDMAP_POSIXID)
res->id.idtype = IDMAP_GID;
+ /*
+ * We found a group. If we got information
+ * from IDMU and we were expecting a group,
+ * copy the id.
+ */
+ if (posix_id != SENTINEL_PID &&
+ res->id.idtype == IDMAP_GID) {
+ res->id.idmap_id_u.gid = posix_id;
+ res->direction = IDMAP_DIRECTION_BI;
+ res->info.how.map_type =
+ IDMAP_MAP_TYPE_IDMU;
+ res->info.src = IDMAP_MAP_SRC_NEW;
+ }
req->id1.idtype = IDMAP_GSID;
break;
@@ -2126,10 +2256,9 @@ out:
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->id1name != NULL) /* unixname */
+ req->id2name == NULL) /* no winname */
/*
- * If AD lookup by unixname
+ * If AD lookup by unixname or pid
* failed with non fatal error
* then clear the error (ie set
* res->retcode to success).
@@ -2196,42 +2325,8 @@ ad_lookup_batch(lookup_state_t *state, idmap_mapping_batch *batch,
RDLOCK_CONFIG();
num_queries = state->ad_nqueries;
- if (_idmapdstate.num_ads > 0) {
- for (i = 0; i < _idmapdstate.num_ads && num_queries > 0; i++) {
-
- retcode = ad_lookup_batch_int(state, batch, result, i,
- &num_processed);
- num_queries -= num_processed;
- if (num_queries > 0) {
- for (j = 0; j < batch->idmap_mapping_batch_len;
- j++) {
- req =
- &batch->idmap_mapping_batch_val[j];
- res = &result->ids.ids_val[j];
- if (!(req->direction &
- _IDMAP_F_LOOKUP_AD))
- continue;
- /*
- * Reset the other AD lookup flag so
- * that we can try the next AD
- */
- req->direction &=
- ~(_IDMAP_F_LOOKUP_OTHER_AD);
-
- if ((i + 1) >= _idmapdstate.num_ads) {
- /*
- * There are no more ADs to try
- */
- req->direction &=
- ~(_IDMAP_F_LOOKUP_AD);
- res->retcode =
- IDMAP_ERR_DOMAIN_NOTFOUND;
- }
- }
- }
- }
- } else {
+ if (_idmapdstate.num_gcs == 0 && _idmapdstate.num_dcs == 0) {
/* Case of no ADs */
retcode = IDMAP_ERR_NO_ACTIVEDIRECTORY;
for (i = 0; i < batch->idmap_mapping_batch_len; i++) {
@@ -2242,7 +2337,47 @@ ad_lookup_batch(lookup_state_t *state, idmap_mapping_batch *batch,
req->direction &= ~(_IDMAP_F_LOOKUP_AD);
res->retcode = IDMAP_ERR_NO_ACTIVEDIRECTORY;
}
+ goto out;
}
+
+ if (state->directory_based_mapping == DIRECTORY_MAPPING_IDMU) {
+ for (i = 0; i < _idmapdstate.num_dcs && num_queries > 0; i++) {
+
+ retcode = ad_lookup_batch_int(state, batch,
+ result, _idmapdstate.dcs[i],
+ i == 0 ? DOMAIN_IS_LOCAL|FOREST_IS_LOCAL : 0,
+ &num_processed);
+ num_queries -= num_processed;
+
+ }
+ }
+
+ for (i = 0; i < _idmapdstate.num_gcs && num_queries > 0; i++) {
+
+ retcode = ad_lookup_batch_int(state, batch, result,
+ _idmapdstate.gcs[i],
+ i == 0 ? FOREST_IS_LOCAL : 0,
+ &num_processed);
+ num_queries -= num_processed;
+
+ }
+
+ /*
+ * There are no more ADs to try. Return errors for any
+ * remaining requests.
+ */
+ if (num_queries > 0) {
+ for (j = 0; j < batch->idmap_mapping_batch_len; j++) {
+ req = &batch->idmap_mapping_batch_val[j];
+ res = &result->ids.ids_val[j];
+ if (!(req->direction & _IDMAP_F_LOOKUP_AD))
+ continue;
+ req->direction &= ~(_IDMAP_F_LOOKUP_AD);
+ res->retcode = IDMAP_ERR_DOMAIN_NOTFOUND;
+ }
+ }
+
+out:
UNLOCK_CONFIG();
/* AD lookups done. Reset state->ad_nqueries and return */
@@ -2300,8 +2435,10 @@ ad_lookup_batch(lookup_state_t *state, idmap_mapping_batch *batch,
* sid_type obtained by the batched AD lookups and after
* use resets it to IDMAP_NONE to prevent xdr from
* mis-interpreting the contents of req->id2.
- * req->id2..[uid or gid or sid] =
- * NOT USED
+ * req->id2.idmap_id_u.uid =
+ * INTERNAL USE. If the AD lookup finds IDMU data
+ * (uidNumber or gidNumber, depending on the type of
+ * the entry), it's left here.
*/
/*
@@ -2394,7 +2531,9 @@ sid2pid_first_pass(lookup_state_t *state, idmap_mapping *req,
*/
if (retcode != IDMAP_SUCCESS ||
(!wksid && req->id2name == NULL &&
- AD_OR_MIXED_MODE(res->id.idtype, state))) {
+ AD_OR_MIXED_MODE(res->id.idtype, state)) ||
+ (!wksid && res->id.idmap_id_u.uid == SENTINEL_PID &&
+ state->directory_based_mapping == DIRECTORY_MAPPING_IDMU)) {
retcode = IDMAP_SUCCESS;
req->direction |= _IDMAP_F_LOOKUP_AD;
state->ad_nqueries++;
@@ -3063,6 +3202,28 @@ sid2pid_second_pass(lookup_state_t *state,
goto out;
/*
+ * There are two ways we might get here with a Posix ID:
+ * - It could be from an expired ephemeral cache entry.
+ * - It could be from IDMU.
+ * If it's from IDMU, we need to look up the name, for name-based
+ * requests and the cache.
+ */
+ if (!IS_EPHEMERAL(res->id.idmap_id_u.uid) &&
+ res->id.idmap_id_u.uid != SENTINEL_PID) {
+ if (req->id2name == NULL) {
+ /*
+ * If the lookup fails, go ahead anyway.
+ * The general UNIX rule is that it's OK to
+ * have a UID or GID that isn't in the
+ * name service.
+ */
+ (void) ns_lookup_bypid(res->id.idmap_id_u.uid,
+ res->id.idtype == IDMAP_UID, &req->id2name);
+ }
+ goto out;
+ }
+
+ /*
* If directory-based name mapping is enabled then the unixname
* may already have been retrieved from the AD object (AD-mode or
* mixed-mode) or from native LDAP object (nldap-mode) -- done.
@@ -3197,6 +3358,24 @@ update_cache_pid2sid(lookup_state_t *state,
assert(req->id1.idmap_id_u.uid != SENTINEL_PID);
assert(res->id.idtype != IDMAP_SID);
+ /*
+ * If we've gotten to this point and we *still* don't know the
+ * unixname, well, we'd like to have it now for the cache.
+ *
+ * If we truly always need it for the cache, we should probably
+ * look it up once at the beginning, rather than "at need" in
+ * several places as is now done. However, it's not really clear
+ * that we *do* need it in the cache; there's a decent argument
+ * that the cache should contain only SIDs and PIDs, so we'll
+ * leave our options open by doing it "at need" here too.
+ *
+ * If we can't find it... c'est la vie.
+ */
+ if (req->id1name == NULL) {
+ (void) ns_lookup_bypid(req->id1.idmap_id_u.uid,
+ req->id1.idtype == IDMAP_UID, &req->id1name);
+ }
+
assert(res->info.how.map_type != IDMAP_MAP_TYPE_UNKNOWN);
switch (res->info.how.map_type) {
case IDMAP_MAP_TYPE_DS_AD:
@@ -3224,6 +3403,12 @@ update_cache_pid2sid(lookup_state_t *state,
case IDMAP_MAP_TYPE_LOCAL_SID:
break;
+ case IDMAP_MAP_TYPE_IDMU:
+ map_dn = res->info.how.idmap_how_u.idmu.dn;
+ map_attr = res->info.how.idmap_how_u.idmu.attr;
+ map_value = res->info.how.idmap_how_u.idmu.value;
+ break;
+
default:
/* Dont cache other mapping types */
assert(FALSE);
@@ -3371,6 +3556,12 @@ update_cache_sid2pid(lookup_state_t *state,
case IDMAP_MAP_TYPE_EPHEMERAL:
break;
+ case IDMAP_MAP_TYPE_IDMU:
+ map_dn = res->info.how.idmap_how_u.idmu.dn;
+ map_attr = res->info.how.idmap_how_u.idmu.attr;
+ map_value = res->info.how.idmap_how_u.idmu.value;
+ break;
+
default:
/* Dont cache other mapping types */
assert(FALSE);
@@ -3610,8 +3801,17 @@ lookup_cache_pid2sid(sqlite *cache, idmap_mapping *req, idmap_id_res *res,
case IDMAP_MAP_TYPE_KNOWN_SID:
break;
+ case IDMAP_MAP_TYPE_IDMU:
+ res->info.how.idmap_how_u.idmu.dn =
+ strdup(values[7]);
+ res->info.how.idmap_how_u.idmu.attr =
+ strdup(values[8]);
+ res->info.how.idmap_how_u.idmu.value =
+ strdup(values[9]);
+ break;
+
default:
- /* Unknow mapping type */
+ /* Unknown mapping type */
assert(FALSE);
}
}
@@ -3748,12 +3948,16 @@ ad_lookup_by_winname(lookup_state_t *state,
int found_ad = 0;
RDLOCK_CONFIG();
- if (_idmapdstate.num_ads > 0) {
- for (i = 0; i < _idmapdstate.num_ads && !found_ad; i++) {
+ if (_idmapdstate.num_gcs > 0) {
+ for (i = 0; i < _idmapdstate.num_gcs && !found_ad; i++) {
retries = 0;
retry:
- retcode = idmap_lookup_batch_start(_idmapdstate.ads[i],
- 1, &qs);
+ retcode = idmap_lookup_batch_start(
+ _idmapdstate.gcs[i],
+ 1,
+ _idmapdstate.cfg->pgcfg.directory_based_mapping,
+ _idmapdstate.cfg->pgcfg.default_domain,
+ &qs);
if (retcode != IDMAP_SUCCESS) {
if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR &&
retries++ < ADUTILS_DEF_NUM_RETRIES)
@@ -3782,7 +3986,7 @@ retry:
retcode = idmap_name2sid_batch_add1(qs, name, domain,
eunixtype, dn, attr, value, canonname, sidprefix,
- rid, wintype, unixname, &rc);
+ rid, wintype, unixname, NULL, &rc);
if (retcode == IDMAP_ERR_DOMAIN_NOTFOUND) {
idmap_lookup_release_batch(&qs);
continue;
@@ -4225,7 +4429,10 @@ pid2sid_first_pass(lookup_state_t *state, idmap_mapping *req,
}
/* Set flags for the next stage */
- if (AD_MODE(req->id1.idtype, state)) {
+ if (state->directory_based_mapping == DIRECTORY_MAPPING_IDMU) {
+ req->direction |= _IDMAP_F_LOOKUP_AD;
+ state->ad_nqueries++;
+ } else if (AD_MODE(req->id1.idtype, state)) {
/*
* If AD-based name mapping is enabled then the next stage
* will need to lookup AD using unixname to get the
@@ -4300,7 +4507,9 @@ pid2sid_second_pass(lookup_state_t *state, idmap_mapping *req,
retcode = IDMAP_ERR_NOTFOUND;
goto out;
}
- if (AD_MODE(req->id1.idtype, state))
+ if (state->directory_based_mapping == DIRECTORY_MAPPING_IDMU)
+ res->direction = IDMAP_DIRECTION_BI;
+ else if (AD_MODE(req->id1.idtype, state))
res->direction = IDMAP_DIRECTION_BI;
else if (NLDAP_MODE(req->id1.idtype, state))
res->direction = IDMAP_DIRECTION_BI;
diff --git a/usr/src/cmd/idmap/idmapd/directory_provider_ad.c b/usr/src/cmd/idmap/idmapd/directory_provider_ad.c
index 2626c26ce6..7f45574019 100644
--- a/usr/src/cmd/idmap/idmapd/directory_provider_ad.c
+++ b/usr/src/cmd/idmap/idmapd/directory_provider_ad.c
@@ -146,7 +146,7 @@ directory_provider_ad_get(
/*
* If we don't have any AD servers handy, we can't find anything.
*/
- if (_idmapdstate.num_ads < 1) {
+ if (_idmapdstate.num_gcs < 1) {
return (NULL);
}
@@ -295,7 +295,7 @@ directory_provider_ad_lookup(
* NEEDSWORK: Should eventually handle other forests.
* NEEDSWORK: Should eventually handle non-GC attributes.
*/
- ad = _idmapdstate.ads[0];
+ ad = _idmapdstate.gcs[0];
/* Stash away information for the callback function. */
cbinfo.attrs = attrs;
diff --git a/usr/src/cmd/idmap/idmapd/idmap_config.c b/usr/src/cmd/idmap/idmapd/idmap_config.c
index 493802af5b..e11d0f8d47 100644
--- a/usr/src/cmd/idmap/idmapd/idmap_config.c
+++ b/usr/src/cmd/idmap/idmapd/idmap_config.c
@@ -58,6 +58,13 @@ static pthread_t update_thread_handle = 0;
static int idmapd_ev_port = -1;
static int rt_sock = -1;
+struct enum_lookup_map directory_mapping_map[] = {
+ { DIRECTORY_MAPPING_NONE, "none" },
+ { DIRECTORY_MAPPING_NAME, "name" },
+ { DIRECTORY_MAPPING_IDMU, "idmu" },
+ { 0, NULL },
+};
+
static int
generate_machine_sid(char **machine_sid)
{
@@ -71,7 +78,7 @@ generate_machine_sid(char **machine_sid)
* machine_sid will be of the form S-1-5-21-N1-N2-N3 (that's
* four RIDs altogether).
*
- * Technically we could use upto 14 random RIDs here, but it
+ * Technically we could use up to 14 random RIDs here, but it
* turns out that with some versions of Windows using SIDs with
* more than five RIDs in security descriptors causes problems.
*/
@@ -107,7 +114,7 @@ generate_machine_sid(char **machine_sid)
/* In the case of error, exists is set to FALSE anyway */
static int
-prop_exists(idmap_cfg_handles_t *handles, char *name, boolean_t *exists)
+prop_exists(idmap_cfg_handles_t *handles, const char *name, boolean_t *exists)
{
scf_property_t *scf_prop;
@@ -140,17 +147,18 @@ prop_exists(idmap_cfg_handles_t *handles, char *name, boolean_t *exists)
/* Check if in the case of failure the original value of *val is preserved */
static int
-get_val_int(idmap_cfg_handles_t *handles, char *name,
+get_val_int(idmap_cfg_handles_t *handles, const char *name,
void *val, scf_type_t type)
{
int rc = 0;
scf_property_t *scf_prop;
scf_value_t *value;
+ uint8_t b;
switch (type) {
case SCF_TYPE_BOOLEAN:
- *(uint8_t *)val = 0;
+ *(boolean_t *)val = B_FALSE;
break;
case SCF_TYPE_COUNT:
*(uint64_t *)val = 0;
@@ -189,7 +197,8 @@ get_val_int(idmap_cfg_handles_t *handles, char *name,
switch (type) {
case SCF_TYPE_BOOLEAN:
- rc = scf_value_get_boolean(value, val);
+ rc = scf_value_get_boolean(value, &b);
+ *(boolean_t *)val = b;
break;
case SCF_TYPE_COUNT:
rc = scf_value_get_count(value, val);
@@ -197,8 +206,15 @@ get_val_int(idmap_cfg_handles_t *handles, char *name,
case SCF_TYPE_INTEGER:
rc = scf_value_get_integer(value, val);
break;
+ default:
+ abort(); /* tested above */
+ /* NOTREACHED */
}
+ if (rc != 0) {
+ idmapdlog(LOG_ERR, "Can not retrieve config/%s: %s",
+ name, scf_strerror(scf_error()));
+ }
destruction:
scf_value_destroy(value);
@@ -208,43 +224,25 @@ destruction:
}
static char *
-scf_value2string(scf_value_t *value)
+scf_value2string(const char *name, scf_value_t *value)
{
- int rc = -1;
- char buf_size = 127;
- int length;
- char *buf = NULL;
- buf = (char *) malloc(sizeof (char) * buf_size);
+ static size_t max_val = 0;
- for (;;) {
- length = scf_value_get_astring(value, buf, buf_size);
- if (length < 0) {
- rc = -1;
- goto destruction;
- }
+ if (max_val == 0)
+ max_val = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
- if (length == buf_size - 1) {
- buf_size *= 2;
- buf = (char *)realloc(buf, buf_size * sizeof (char));
- if (!buf) {
- idmapdlog(LOG_ERR, "Out of memory");
- rc = -1;
- goto destruction;
- }
- } else {
- rc = 0;
- break;
- }
+ char buf[max_val + 1];
+ if (scf_value_get_astring(value, buf, max_val + 1) < 0) {
+ idmapdlog(LOG_ERR, "Can not retrieve config/%s: %s",
+ name, scf_strerror(scf_error()));
+ return (NULL);
}
-destruction:
- if (rc < 0) {
- if (buf)
- free(buf);
- buf = NULL;
- }
+ char *s = strdup(buf);
+ if (s == NULL)
+ idmapdlog(LOG_ERR, "Out of memory");
- return (buf);
+ return (s);
}
static int
@@ -327,7 +325,7 @@ restart:
servers[i].priority = 0;
servers[i].weight = 100;
servers[i].port = defport;
- if ((host = scf_value2string(value)) == NULL) {
+ if ((host = scf_value2string(name, value)) == NULL) {
goto destruction;
}
if ((portstr = strchr(host, ':')) != NULL) {
@@ -367,7 +365,7 @@ destruction:
static int
-get_val_astring(idmap_cfg_handles_t *handles, char *name, char **val)
+get_val_astring(idmap_cfg_handles_t *handles, const char *name, char **val)
{
int rc = 0;
@@ -402,7 +400,8 @@ get_val_astring(idmap_cfg_handles_t *handles, char *name, char **val)
goto destruction;
}
- if (!(*val = scf_value2string(value)))
+ *val = scf_value2string(name, value);
+ if (*val == NULL)
rc = -1;
destruction:
@@ -420,7 +419,77 @@ destruction:
static int
-set_val_astring(idmap_cfg_handles_t *handles, char *name, const char *val)
+del_val(idmap_cfg_handles_t *handles, const char *name)
+{
+ int rc = -1;
+ int ret;
+ scf_transaction_t *tx = NULL;
+ scf_transaction_entry_t *ent = NULL;
+
+ if ((tx = scf_transaction_create(handles->main)) == NULL) {
+ idmapdlog(LOG_ERR,
+ "scf_transaction_create() failed: %s",
+ scf_strerror(scf_error()));
+ goto destruction;
+ }
+ if ((ent = scf_entry_create(handles->main)) == NULL) {
+ idmapdlog(LOG_ERR,
+ "scf_entry_create() failed: %s",
+ scf_strerror(scf_error()));
+ goto destruction;
+ }
+
+ do {
+ if (scf_pg_update(handles->config_pg) == -1) {
+ idmapdlog(LOG_ERR,
+ "scf_pg_update(%s) failed: %s",
+ name, scf_strerror(scf_error()));
+ goto destruction;
+ }
+ if (scf_transaction_start(tx, handles->config_pg) != 0) {
+ idmapdlog(LOG_ERR,
+ "scf_transaction_start(%s) failed: %s",
+ name, scf_strerror(scf_error()));
+ goto destruction;
+ }
+
+ if (scf_transaction_property_delete(tx, ent, name) != 0) {
+ /* Don't complain if it already doesn't exist. */
+ if (scf_error() != SCF_ERROR_NOT_FOUND) {
+ idmapdlog(LOG_ERR,
+ "scf_transaction_property_delete() failed:"
+ " %s",
+ scf_strerror(scf_error()));
+ }
+ goto destruction;
+ }
+
+ ret = scf_transaction_commit(tx);
+
+ if (ret == 0)
+ scf_transaction_reset(tx);
+ } while (ret == 0);
+
+ if (ret == -1) {
+ idmapdlog(LOG_ERR,
+ "scf_transaction_commit(%s) failed: %s",
+ name, scf_strerror(scf_error()));
+ goto destruction;
+ }
+
+ rc = 0;
+
+destruction:
+ if (ent != NULL)
+ scf_entry_destroy(ent);
+ if (tx != NULL)
+ scf_transaction_destroy(tx);
+ return (rc);
+}
+
+
+static int
+set_val_astring(idmap_cfg_handles_t *handles, const char *name, const char *val)
{
int rc = -1;
int ret = -2;
@@ -549,6 +618,18 @@ update_string(char **value, char **new, char *name)
return (1);
}
+static int
+update_enum(int *value, int *new, char *name, struct enum_lookup_map *map)
+{
+ if (*value == *new)
+ return (0);
+
+ idmapdlog(LOG_INFO, "change %s=%s", name, enum_lookup(*new, map));
+
+ *value = *new;
+
+ return (1);
+}
/*
* This function updates a directory service structure.
@@ -801,6 +882,16 @@ not_equal:
return (1);
}
+const char *
+enum_lookup(int value, struct enum_lookup_map *map)
+{
+ for (; map->string != NULL; map++) {
+ if (value == map->value) {
+ return (map->string);
+ }
+ }
+ return ("(invalid)");
+}
#define MAX_CHECK_TIME (20 * 60)
@@ -1030,6 +1121,32 @@ valid_ldap_attr(const char *attr) {
return (1);
}
+static
+int
+check_smf_debug_mode(idmap_cfg_handles_t *handles)
+{
+ boolean_t new_debug_mode;
+ int rc;
+
+ rc = prop_exists(handles, "debug", &new_debug_mode);
+ if (rc != 0)
+ return (rc);
+
+ if (_idmapdstate.debug_mode != new_debug_mode) {
+ if (!_idmapdstate.debug_mode) {
+ _idmapdstate.debug_mode = new_debug_mode;
+ idmap_log_stderr(LOG_DEBUG);
+ idmapdlog(LOG_DEBUG, "debug mode enabled");
+ } else {
+ idmapdlog(LOG_DEBUG, "debug mode disabled");
+ idmap_log_stderr(-1);
+ _idmapdstate.debug_mode = new_debug_mode;
+ }
+ }
+
+ return (0);
+}
+
/*
* This is the half of idmap_cfg_load() that loads property values from
* SMF (using the config/ property group of the idmap FMRI).
@@ -1041,12 +1158,12 @@ valid_ldap_attr(const char *attr) {
static
int
idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg,
- int *errors)
+ int * const errors)
{
int rc;
- uint8_t bool_val;
- char *str = NULL;
- boolean_t new_debug_mode;
+ char *s;
+
+ *errors = 0;
if (scf_pg_update(handles->config_pg) < 0) {
idmapdlog(LOG_ERR, "scf_pg_update() failed: %s",
@@ -1060,37 +1177,42 @@ idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg,
return (-2);
}
-
- rc = prop_exists(handles, "debug", &new_debug_mode);
+ rc = check_smf_debug_mode(handles);
if (rc != 0)
- errors++;
-
- if (_idmapdstate.debug_mode != new_debug_mode) {
- if (!_idmapdstate.debug_mode) {
- _idmapdstate.debug_mode = new_debug_mode;
- idmap_log_stderr(LOG_DEBUG);
- idmapdlog(LOG_DEBUG, "debug mode enabled");
- } else {
- idmapdlog(LOG_DEBUG, "debug mode disabled");
- idmap_log_stderr(-1);
- _idmapdstate.debug_mode = new_debug_mode;
- }
- }
+ (*errors)++;
rc = get_val_int(handles, "unresolvable_sid_mapping",
&pgcfg->eph_map_unres_sids, SCF_TYPE_BOOLEAN);
if (rc != 0)
- errors++;
+ (*errors)++;
+
+ rc = get_val_astring(handles, "directory_based_mapping", &s);
+ if (rc != 0)
+ (*errors)++;
+ else if (s == NULL || strcasecmp(s, "none") == 0)
+ pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NONE;
+ else if (strcasecmp(s, "name") == 0)
+ pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NAME;
+ else if (strcasecmp(s, "idmu") == 0)
+ pgcfg->directory_based_mapping = DIRECTORY_MAPPING_IDMU;
+ else {
+ pgcfg->directory_based_mapping = DIRECTORY_MAPPING_NONE;
+ idmapdlog(LOG_ERR,
+ "config/directory_based_mapping: invalid value \"%s\" ignored",
+ s);
+ (*errors)++;
+ }
+ free(s);
rc = get_val_int(handles, "list_size_limit",
&pgcfg->list_size_limit, SCF_TYPE_COUNT);
if (rc != 0)
- errors++;
+ (*errors)++;
rc = get_val_astring(handles, "domain_name",
&pgcfg->domain_name);
if (rc != 0)
- errors++;
+ (*errors)++;
else {
(void) ad_disc_set_DomainName(handles->ad_ctx,
pgcfg->domain_name);
@@ -1108,45 +1230,13 @@ idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg,
return (-2);
}
- rc = get_val_astring(handles, "mapping_domain", &str);
- if (rc != 0)
- errors++;
-
- /*
- * We treat default_domain as having been specified in SMF IFF
- * either (the config/default_domain property was set) or (the
- * old, obsolete, never documented config/mapping_domain
- * property was set and the new config/domain_name property was
- * not set).
- */
- pgcfg->dflt_dom_set_in_smf = B_TRUE;
- if (pgcfg->default_domain == NULL) {
-
- pgcfg->dflt_dom_set_in_smf = B_FALSE;
-
- if (pgcfg->domain_name != NULL) {
- pgcfg->default_domain = strdup(pgcfg->domain_name);
- if (str != NULL) {
- idmapdlog(LOG_WARNING,
- "Ignoring obsolete, undocumented "
- "config/mapping_domain property");
- }
- } else if (str != NULL) {
- pgcfg->default_domain = strdup(str);
- pgcfg->dflt_dom_set_in_smf = B_TRUE;
- idmapdlog(LOG_WARNING,
- "The config/mapping_domain property is "
- "obsolete; support for it will be removed, "
- "please use config/default_domain instead");
- }
+ if (pgcfg->default_domain == NULL && pgcfg->domain_name != NULL) {
+ pgcfg->default_domain = strdup(pgcfg->domain_name);
}
- if (str != NULL)
- free(str);
-
rc = get_val_astring(handles, "machine_sid", &pgcfg->machine_sid);
if (rc != 0)
- errors++;
+ (*errors)++;
if (pgcfg->machine_sid == NULL) {
/* If machine_sid not configured, generate one */
if (generate_machine_sid(&pgcfg->machine_sid) < 0)
@@ -1154,14 +1244,13 @@ idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg,
rc = set_val_astring(handles, "machine_sid",
pgcfg->machine_sid);
if (rc != 0)
- errors++;
+ (*errors)++;
}
- str = NULL;
rc = get_val_ds(handles, "domain_controller", 389,
&pgcfg->domain_controller);
if (rc != 0)
- errors++;
+ (*errors)++;
else {
(void) ad_disc_set_DomainController(handles->ad_ctx,
pgcfg->domain_controller);
@@ -1170,7 +1259,7 @@ idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg,
rc = get_val_astring(handles, "forest_name", &pgcfg->forest_name);
if (rc != 0)
- errors++;
+ (*errors)++;
else {
(void) ad_disc_set_ForestName(handles->ad_ctx,
pgcfg->forest_name);
@@ -1179,33 +1268,24 @@ idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg,
rc = get_val_astring(handles, "site_name", &pgcfg->site_name);
if (rc != 0)
- errors++;
+ (*errors)++;
else
(void) ad_disc_set_SiteName(handles->ad_ctx, pgcfg->site_name);
- str = NULL;
rc = get_val_ds(handles, "global_catalog", 3268,
&pgcfg->global_catalog);
if (rc != 0)
- errors++;
+ (*errors)++;
else {
(void) ad_disc_set_GlobalCatalog(handles->ad_ctx,
pgcfg->global_catalog);
pgcfg->global_catalog_auto_disc = B_FALSE;
}
- /*
- * Read directory-based name mappings related SMF properties
- */
- rc = get_val_int(handles, "ds_name_mapping_enabled",
- &bool_val, SCF_TYPE_BOOLEAN);
- if (rc != 0)
- return (-2);
-
- if (!bool_val)
- return (rc);
+ /* Unless we're doing directory-based name mapping, we're done. */
+ if (pgcfg->directory_based_mapping != DIRECTORY_MAPPING_NAME)
+ return (0);
- pgcfg->ds_name_mapping_enabled = B_TRUE;
rc = get_val_astring(handles, "ad_unixuser_attr",
&pgcfg->ad_unixuser_attr);
if (rc != 0)
@@ -1242,8 +1322,8 @@ idmap_cfg_load_smf(idmap_cfg_handles_t *handles, idmap_pg_config_t *pgcfg,
pgcfg->ad_unixgroup_attr == NULL &&
pgcfg->nldap_winname_attr == NULL) {
idmapdlog(LOG_ERR,
- "If config/ds_name_mapping_enabled property is set to "
- "true then atleast one of the following name mapping "
+ "If config/directory_based_mapping property is set to "
+ "\"name\" then at least one of the following name mapping "
"attributes must be specified. (config/ad_unixuser_attr OR "
"config/ad_unixgroup_attr OR config/nldap_winname_attr)");
return (-3);
@@ -1474,7 +1554,7 @@ int
idmap_cfg_load(idmap_cfg_t *cfg, int flags)
{
int rc = 0;
- int errors = 0;
+ int errors;
int changed = 0;
int ad_reload_required = 0;
idmap_pg_config_t new_pgcfg, *live_pgcfg;
@@ -1504,10 +1584,9 @@ idmap_cfg_load(idmap_cfg_t *cfg, int flags)
changed += update_bool(&live_pgcfg->eph_map_unres_sids,
&new_pgcfg.eph_map_unres_sids, "unresolvable_sid_mapping");
- changed += live_pgcfg->ds_name_mapping_enabled !=
- new_pgcfg.ds_name_mapping_enabled;
- live_pgcfg->ds_name_mapping_enabled =
- new_pgcfg.ds_name_mapping_enabled;
+ changed += update_enum(&live_pgcfg->directory_based_mapping,
+ &new_pgcfg.directory_based_mapping, "directory_based_mapping",
+ directory_mapping_map);
changed += update_string(&live_pgcfg->ad_unixuser_attr,
&new_pgcfg.ad_unixuser_attr, "ad_unixuser_attr");
@@ -1519,9 +1598,8 @@ idmap_cfg_load(idmap_cfg_t *cfg, int flags)
&new_pgcfg.nldap_winname_attr, "nldap_winname_attr");
/* Props that can be discovered and set in SMF updated here */
- if (!live_pgcfg->dflt_dom_set_in_smf)
- changed += update_string(&live_pgcfg->default_domain,
- &new_pgcfg.default_domain, "default_domain");
+ changed += update_string(&live_pgcfg->default_domain,
+ &new_pgcfg.default_domain, "default_domain");
changed += update_string(&live_pgcfg->domain_name,
&new_pgcfg.domain_name, "domain_name");
@@ -1657,6 +1735,9 @@ idmap_cfg_init()
goto error;
}
+ if (check_smf_debug_mode(handles) != 0)
+ goto error;
+
/* Initialize AD Auto Discovery context */
handles->ad_ctx = ad_disc_init();
if (handles->ad_ctx == NULL)
@@ -1756,3 +1837,110 @@ idmap_cfg_hup_handler(int sig)
if (idmapd_ev_port >= 0)
(void) port_send(idmapd_ev_port, RECONFIGURE, NULL);
}
+
+/*
+ * Upgrade the DS mapping flags.
+ *
+ * If the old ds_name_mapping_enabled flag is present, then
+ * if the new directory_based_mapping value is present, then
+ * if the two are compatible, delete the old and note it
+ * else delete the old and warn
+ * else
+ * set the new based on the old, and note it
+ * delete the old
+ */
+static
+int
+upgrade_directory_mapping(idmap_cfg_handles_t *handles)
+{
+ boolean_t legacy_ds_name_mapping_present;
+ const char DS_NAME_MAPPING_ENABLED[] = "ds_name_mapping_enabled";
+ const char DIRECTORY_BASED_MAPPING[] = "directory_based_mapping";
+ int rc;
+
+ rc = prop_exists(handles, DS_NAME_MAPPING_ENABLED,
+ &legacy_ds_name_mapping_present);
+
+ if (rc != 0)
+ return (rc);
+
+ if (!legacy_ds_name_mapping_present)
+ return (0);
+
+ boolean_t legacy_ds_name_mapping_enabled;
+ rc = get_val_int(handles, DS_NAME_MAPPING_ENABLED,
+ &legacy_ds_name_mapping_enabled, SCF_TYPE_BOOLEAN);
+ if (rc != 0)
+ return (rc);
+
+ char *legacy_mode;
+ char *legacy_bool_string;
+ if (legacy_ds_name_mapping_enabled) {
+ legacy_mode = "name";
+ legacy_bool_string = "true";
+ } else {
+ legacy_mode = "none";
+ legacy_bool_string = "false";
+ }
+
+ char *directory_based_mapping;
+ rc = get_val_astring(handles, DIRECTORY_BASED_MAPPING,
+ &directory_based_mapping);
+ if (rc != 0)
+ return (rc);
+
+ if (directory_based_mapping == NULL) {
+ idmapdlog(LOG_INFO,
+ "Upgrading old %s=%s setting\n"
+ "to %s=%s.",
+ DS_NAME_MAPPING_ENABLED, legacy_bool_string,
+ DIRECTORY_BASED_MAPPING, legacy_mode);
+ rc = set_val_astring(handles, DIRECTORY_BASED_MAPPING,
+ legacy_mode);
+ if (rc != 0)
+ return (rc);
+ } else {
+ boolean_t new_name_mapping;
+ if (strcasecmp(directory_based_mapping, "name") == 0)
+ new_name_mapping = B_TRUE;
+ else
+ new_name_mapping = B_FALSE;
+
+ if (legacy_ds_name_mapping_enabled == new_name_mapping) {
+ idmapdlog(LOG_INFO,
+ "Automatically removing old %s=%s setting\n"
+ "in favor of %s=%s.",
+ DS_NAME_MAPPING_ENABLED, legacy_bool_string,
+ DIRECTORY_BASED_MAPPING, directory_based_mapping);
+ } else {
+ idmapdlog(LOG_WARNING,
+ "Removing conflicting %s=%s setting\n"
+ "in favor of %s=%s.",
+ DS_NAME_MAPPING_ENABLED, legacy_bool_string,
+ DIRECTORY_BASED_MAPPING, directory_based_mapping);
+ }
+ free(directory_based_mapping);
+ }
+
+ rc = del_val(handles, DS_NAME_MAPPING_ENABLED);
+ if (rc != 0)
+ return (rc);
+
+ return (0);
+}
+
+/*
+ * Do whatever is necessary to upgrade idmap's configuration before
+ * we load it.
+ */
+int
+idmap_cfg_upgrade(idmap_cfg_t *cfg)
+{
+ int rc;
+
+ rc = upgrade_directory_mapping(&cfg->handles);
+ if (rc != 0)
+ return (rc);
+
+ return (0);
+}
diff --git a/usr/src/cmd/idmap/idmapd/idmap_config.h b/usr/src/cmd/idmap/idmapd/idmap_config.h
index d8a6f4c810..bdee366906 100644
--- a/usr/src/cmd/idmap/idmapd/idmap_config.h
+++ b/usr/src/cmd/idmap/idmapd/idmap_config.h
@@ -38,6 +38,18 @@ extern "C" {
#define MAX_POLICY_SIZE 1023
+#define DIRECTORY_MAPPING_NONE 0
+#define DIRECTORY_MAPPING_NAME 1
+#define DIRECTORY_MAPPING_IDMU 2
+
+struct enum_lookup_map {
+ int value;
+ char *string;
+};
+
+extern struct enum_lookup_map directory_mapping_map[];
+extern const char *enum_lookup(int value, struct enum_lookup_map *map);
+
/* SMF and auto-discovery context handles */
typedef struct idmap_cfg_handles {
pthread_mutex_t mutex;
@@ -63,19 +75,8 @@ typedef struct idmap_trustedforest {
typedef struct idmap_pg_config {
uint64_t list_size_limit;
- /*
- * The idmap_cfg_update_thread() uses the ad_disc_t context in
- * the idmap_cfg_handles_t (see above) to track which values
- * came from SMF and which values didn't. This works for all
- * items that are discoverable, but default_domain (the domain
- * that we qualify unqualified names passed to idmap show) is
- * not discoverable independently of domain_name. So we need to
- * track its procedence separately. The dflt_dom_set_in_smf
- * field does just that.
- */
char *machine_sid; /* machine sid */
char *default_domain; /* default domain name */
- boolean_t dflt_dom_set_in_smf;
char *domain_name; /* AD domain name */
boolean_t domain_name_auto_disc;
idmap_ad_disc_ds_t
@@ -103,7 +104,7 @@ typedef struct idmap_pg_config {
char *ad_unixuser_attr;
char *ad_unixgroup_attr;
char *nldap_winname_attr;
- boolean_t ds_name_mapping_enabled;
+ int directory_based_mapping; /* enum */
boolean_t eph_map_unres_sids;
} idmap_pg_config_t;
@@ -118,6 +119,7 @@ extern void idmap_cfg_unload(idmap_pg_config_t *);
extern int idmap_cfg_load(idmap_cfg_t *, int);
extern idmap_cfg_t *idmap_cfg_init(void);
extern int idmap_cfg_fini(idmap_cfg_t *);
+extern int idmap_cfg_upgrade(idmap_cfg_t *);
extern int idmap_cfg_start_updates(void);
extern void idmap_cfg_poke_updates(void);
extern void idmap_cfg_hup_handler(int);
diff --git a/usr/src/cmd/idmap/idmapd/idmapd.h b/usr/src/cmd/idmap/idmapd/idmapd.h
index 63eb9d4143..738fb0e9a0 100644
--- a/usr/src/cmd/idmap/idmapd/idmapd.h
+++ b/usr/src/cmd/idmap/idmapd/idmapd.h
@@ -62,7 +62,6 @@ typedef enum idmap_namemap_mode {
/*
* Global state of idmapd daemon.
*/
-#define IDMAP_MAX_NAME_LEN 512
typedef struct idmapd_state {
rwlock_t rwlk_cfg; /* config lock */
idmap_cfg_t *cfg; /* config */
@@ -74,9 +73,10 @@ typedef struct idmapd_state {
uid_t limit_uid;
gid_t limit_gid;
int new_eph_db; /* was the ephem ID db [re-]created? */
- bool_t eph_map_unres_sids;
- int num_ads;
- adutils_ad_t **ads;
+ int num_gcs;
+ adutils_ad_t **gcs;
+ int num_dcs;
+ adutils_ad_t **dcs;
} idmapd_state_t;
extern idmapd_state_t _idmapdstate;
@@ -98,6 +98,7 @@ typedef struct lookup_state {
int ad_nqueries;
int nldap_nqueries;
bool_t eph_map_unres_sids;
+ int directory_based_mapping; /* enum */
uint_t curpos;
hashentry_t *sid_history;
uint_t sid_history_size;
@@ -158,7 +159,7 @@ typedef struct wksids_table {
const char *domain;
const char *winname;
int is_wuser;
- uid_t pid;
+ posix_id_t pid;
int is_user;
int direction;
} wksids_table_t;
@@ -303,7 +304,7 @@ extern void idmap_log_stderr(int);
extern void idmap_log_syslog(boolean_t);
extern void idmap_log_degraded(boolean_t);
-extern const wksids_table_t *find_wksid_by_pid(uid_t pid, int is_user);
+extern const wksids_table_t *find_wksid_by_pid(posix_id_t pid, int is_user);
extern const wksids_table_t *find_wksid_by_sid(const char *sid, int rid,
int type);
extern const wksids_table_t *find_wksid_by_name(const char *name,
diff --git a/usr/src/cmd/idmap/idmapd/init.c b/usr/src/cmd/idmap/idmapd/init.c
index 2e60fb40f5..3d18ee5af0 100644
--- a/usr/src/cmd/idmap/idmapd/init.c
+++ b/usr/src/cmd/idmap/idmapd/init.c
@@ -76,6 +76,12 @@ load_config()
return (-1);
}
+ rc = idmap_cfg_upgrade(_idmapdstate.cfg);
+ if (rc != 0) {
+ degrade_svc(0, "fatal error while upgrading configuration");
+ return (rc);
+ }
+
rc = idmap_cfg_load(_idmapdstate.cfg, 0);
if (rc < -1) {
/* Total failure */
@@ -101,13 +107,13 @@ load_config()
void
-reload_ad()
+reload_gcs()
{
int i, j;
- adutils_ad_t **new_ads = NULL;
- adutils_ad_t **old_ads;
- int new_num_ads;
- int old_num_ads;
+ adutils_ad_t **new_gcs;
+ adutils_ad_t **old_gcs;
+ int new_num_gcs;
+ int old_num_gcs;
idmap_pg_config_t *pgcfg = &_idmapdstate.cfg->pgcfg;
idmap_trustedforest_t *trustfor = pgcfg->trusted_forests;
int num_trustfor = pgcfg->num_trusted_forests;
@@ -126,31 +132,31 @@ reload_ad()
return;
}
- old_ads = _idmapdstate.ads;
- old_num_ads = _idmapdstate.num_ads;
+ old_gcs = _idmapdstate.gcs;
+ old_num_gcs = _idmapdstate.num_gcs;
- new_num_ads = 1 + num_trustfor;
- new_ads = calloc(new_num_ads, sizeof (adutils_ad_t *));
- if (new_ads == NULL) {
+ new_num_gcs = 1 + num_trustfor;
+ new_gcs = calloc(new_num_gcs, sizeof (adutils_ad_t *));
+ if (new_gcs == NULL) {
degrade_svc(0, "could not allocate AD context array "
"(out of memory)");
return;
}
- if (adutils_ad_alloc(&new_ads[0], pgcfg->default_domain,
- ADUTILS_AD_GLOBAL_CATALOG) != ADUTILS_SUCCESS) {
- free(new_ads);
+ if (adutils_ad_alloc(&new_gcs[0], NULL, ADUTILS_AD_GLOBAL_CATALOG) !=
+ ADUTILS_SUCCESS) {
+ free(new_gcs);
degrade_svc(0, "could not initialize AD context "
"(out of memory)");
return;
}
for (i = 0; pgcfg->global_catalog[i].host[0] != '\0'; i++) {
- if (idmap_add_ds(new_ads[0],
+ if (idmap_add_ds(new_gcs[0],
pgcfg->global_catalog[i].host,
pgcfg->global_catalog[i].port) != 0) {
- adutils_ad_free(&new_ads[0]);
- free(new_ads);
+ adutils_ad_free(&new_gcs[0]);
+ free(new_gcs);
degrade_svc(0, "could not set AD hosts "
"(out of memory)");
return;
@@ -160,11 +166,11 @@ reload_ad()
if (pgcfg->domains_in_forest != NULL) {
for (i = 0; pgcfg->domains_in_forest[i].domain[0] != '\0';
i++) {
- if (adutils_add_domain(new_ads[0],
+ if (adutils_add_domain(new_gcs[0],
pgcfg->domains_in_forest[i].domain,
pgcfg->domains_in_forest[i].sid) != 0) {
- adutils_ad_free(&new_ads[0]);
- free(new_ads);
+ adutils_ad_free(&new_gcs[0]);
+ free(new_gcs);
degrade_svc(0, "could not set AD domains "
"(out of memory)");
return;
@@ -173,22 +179,22 @@ reload_ad()
}
for (i = 0; i < num_trustfor; i++) {
- if (adutils_ad_alloc(&new_ads[i + 1], NULL,
+ if (adutils_ad_alloc(&new_gcs[i + 1], NULL,
ADUTILS_AD_GLOBAL_CATALOG) != ADUTILS_SUCCESS) {
degrade_svc(0, "could not initialize trusted AD "
"context (out of memory)");
- new_num_ads = i + 1;
+ new_num_gcs = i + 1;
goto out;
}
for (j = 0; trustfor[i].global_catalog[j].host[0] != '\0';
j++) {
- if (idmap_add_ds(new_ads[i + 1],
+ if (idmap_add_ds(new_gcs[i + 1],
trustfor[i].global_catalog[j].host,
trustfor[i].global_catalog[j].port) != 0) {
- adutils_ad_free(&new_ads[i + 1]);
+ adutils_ad_free(&new_gcs[i + 1]);
degrade_svc(0, "could not set trusted "
"AD hosts (out of memory)");
- new_num_ads = i + 1;
+ new_num_gcs = i + 1;
goto out;
}
}
@@ -197,13 +203,13 @@ reload_ad()
domain_in_forest = &trustfor[i].domains_in_forest[j];
/* Only add domains which are marked */
if (domain_in_forest->trusted) {
- if (adutils_add_domain(new_ads[i + 1],
+ if (adutils_add_domain(new_gcs[i + 1],
domain_in_forest->domain,
domain_in_forest->sid) != 0) {
- adutils_ad_free(&new_ads[i + 1]);
+ adutils_ad_free(&new_gcs[i + 1]);
degrade_svc(0, "could not set trusted "
"AD domains (out of memory)");
- new_num_ads = i + 1;
+ new_num_gcs = i + 1;
goto out;
}
}
@@ -211,19 +217,107 @@ reload_ad()
}
out:
- _idmapdstate.ads = new_ads;
- _idmapdstate.num_ads = new_num_ads;
+ _idmapdstate.gcs = new_gcs;
+ _idmapdstate.num_gcs = new_num_gcs;
+
+
+ if (old_gcs != NULL) {
+ for (i = 0; i < old_num_gcs; i++)
+ adutils_ad_free(&old_gcs[i]);
+ free(old_gcs);
+ }
+}
+
+/*
+ * NEEDSWORK: This should load entries for domain servers for all known
+ * domains - the joined domain, other domains in the forest, and trusted
+ * domains in other forests. However, we don't yet discover any DCs other
+ * than the DCs for the joined domain.
+ */
+static
+void
+reload_dcs(void)
+{
+ int i;
+ adutils_ad_t **new_dcs;
+ adutils_ad_t **old_dcs;
+ int new_num_dcs;
+ int old_num_dcs;
+ idmap_pg_config_t *pgcfg = &_idmapdstate.cfg->pgcfg;
+
+ if (pgcfg->domain_controller == NULL ||
+ pgcfg->domain_controller[0].host[0] == '\0') {
+ /*
+ * No DCs. Continue to use the previous AD config in case
+ * that's still good but auto-discovery had a transient failure.
+ * If that stops working we'll go into degraded mode anyways
+ * when it does.
+ */
+ degrade_svc(0,
+ "Domain controller servers not configured/discoverable");
+ return;
+ }
+
+ old_dcs = _idmapdstate.dcs;
+ old_num_dcs = _idmapdstate.num_dcs;
+
+ new_num_dcs = 1;
+ new_dcs = calloc(new_num_dcs, sizeof (adutils_ad_t *));
+ if (new_dcs == NULL)
+ goto nomem;
+
+ if (adutils_ad_alloc(&new_dcs[0], pgcfg->domain_name,
+ ADUTILS_AD_DATA) != ADUTILS_SUCCESS)
+ goto nomem;
+
+ for (i = 0; pgcfg->domain_controller[i].host[0] != '\0'; i++) {
+ if (idmap_add_ds(new_dcs[0],
+ pgcfg->domain_controller[i].host,
+ pgcfg->domain_controller[i].port) != 0)
+ goto nomem;
+ }
+
+ /* NEEDSWORK: isn't there an easier way to find the domain SID? */
+ for (i = 0; pgcfg->domains_in_forest[i].domain[0] != '\0'; i++) {
+ if (domain_eq(pgcfg->domain_name,
+ pgcfg->domains_in_forest[i].domain)) {
+ if (adutils_add_domain(new_dcs[0], pgcfg->domain_name,
+ pgcfg->domains_in_forest[i].sid) != 0)
+ goto nomem;
+ break;
+ }
+ }
+
+ _idmapdstate.dcs = new_dcs;
+ _idmapdstate.num_dcs = new_num_dcs;
+
+ if (old_dcs != NULL) {
+ for (i = 0; i < old_num_dcs; i++)
+ adutils_ad_free(&old_dcs[i]);
+ free(old_dcs);
+ }
+ return;
- if (old_ads != NULL) {
- for (i = 0; i < old_num_ads; i++)
- adutils_ad_free(&old_ads[i]);
- free(old_ads);
+nomem:
+ degrade_svc(0, "out of memory");
+
+ if (new_dcs != NULL) {
+ if (new_dcs[0] != NULL)
+ adutils_ad_free(&new_dcs[0]);
+ free(new_dcs);
}
}
void
+reload_ad(void)
+{
+ reload_gcs();
+ reload_dcs();
+}
+
+void
print_idmapdstate()
{
int i, j;
@@ -302,8 +396,8 @@ print_idmapdstate()
}
}
- idmapdlog(LOG_DEBUG, "ds_name_mapping_enabled=%s",
- (pgcfg->ds_name_mapping_enabled) ? "true" : "false");
+ idmapdlog(LOG_DEBUG, "directory_based_mapping=%s",
+ enum_lookup(pgcfg->directory_based_mapping, directory_mapping_map));
idmapdlog(LOG_DEBUG, "ad_unixuser_attr=%s",
CHECK_NULL(pgcfg->ad_unixuser_attr));
idmapdlog(LOG_DEBUG, "ad_unixgroup_attr=%s",
diff --git a/usr/src/cmd/idmap/idmapd/server.c b/usr/src/cmd/idmap/idmapd/server.c
index 6a14d1dbef..8c26069a9f 100644
--- a/usr/src/cmd/idmap/idmapd/server.c
+++ b/usr/src/cmd/idmap/idmapd/server.c
@@ -524,8 +524,17 @@ list_mappings_cb(void *parg, int argc, char **argv, char **colnames)
case IDMAP_MAP_TYPE_LOCAL_SID:
break;
+ case IDMAP_MAP_TYPE_IDMU:
+ how->idmap_how_u.idmu.dn =
+ strdup(argv[12]);
+ how->idmap_how_u.idmu.attr =
+ strdup(argv[13]);
+ how->idmap_how_u.idmu.value =
+ strdup(argv[14]);
+ break;
+
default:
- /* Unknow mapping type */
+ /* Unknown mapping type */
assert(FALSE);
}
@@ -1069,9 +1078,10 @@ idmap_get_prop_1_svc(idmap_prop_type request,
pgcfg->nldap_winname_attr);
result->auto_discovered = FALSE;
break;
- case PROP_DS_NAME_MAPPING_ENABLED:
- result->value.idmap_prop_val_u.boolval =
- pgcfg->ds_name_mapping_enabled;
+ case PROP_DIRECTORY_BASED_MAPPING:
+ STRDUP_CHECK(result->value.idmap_prop_val_u.utf8val,
+ enum_lookup(pgcfg->directory_based_mapping,
+ directory_mapping_map));
result->auto_discovered = FALSE;
break;
default:
diff --git a/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c b/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c
index 8fffbab78f..a2485a5181 100644
--- a/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c
+++ b/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c
@@ -1179,13 +1179,13 @@ smb_dcmd_odir(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
} else {
if (DCMD_HDRSPEC(flags))
mdb_printf(
- "%<u>%-?s "
+ "%<b>%<u>%-?s "
"%-5s "
"%-?s "
- "%-16s%</u>\n",
+ "%-16s%</u>%</b>\n",
"ODIR", "SID", "VNODE", "PATTERN");
- mdb_printf("%?p %-5u %-16s %s\n",
+ mdb_printf("%?p %-5u %-16p %s\n",
addr, od->d_odid, od->d_dnode, od->d_pattern);
}
}
diff --git a/usr/src/lib/libadutils/common/addisc.c b/usr/src/lib/libadutils/common/addisc.c
index aeda77fbe2..f98461554d 100644
--- a/usr/src/lib/libadutils/common/addisc.c
+++ b/usr/src/lib/libadutils/common/addisc.c
@@ -708,12 +708,13 @@ srv_query(res_state state, const char *svc_name, const char *dname,
return (NULL);
}
} else if (dname != NULL) {
- len = res_nquerydomain(state, svc_name, dname, C_IN, T_SRV,
- msg.buf, sizeof (msg.buf));
logger(LOG_DEBUG,
"Querying DNS for SRV RRs named '%s' for '%s' ",
svc_name, dname);
+ len = res_nquerydomain(state, svc_name, dname, C_IN, T_SRV,
+ msg.buf, sizeof (msg.buf));
+
if (len < 0) {
logger(LOG_DEBUG,
"DNS query for '%s' for '%s' failed (%s)",
diff --git a/usr/src/lib/libadutils/common/adutils.c b/usr/src/lib/libadutils/common/adutils.c
index 006236789e..d18ccc3ff3 100644
--- a/usr/src/lib/libadutils/common/adutils.c
+++ b/usr/src/lib/libadutils/common/adutils.c
@@ -396,9 +396,41 @@ adutils_sid_ber2str(BerValue *bval)
}
+/*
+ * Extract an int from the Ber value
+ * Return B_TRUE if a valid integer was found, B_FALSE if not.
+ */
+boolean_t
+adutils_bv_uint(BerValue *bval, unsigned int *result)
+{
+ char buf[40]; /* big enough for any int */
+ unsigned int tmp;
+ char *p;
+
+ *result = 0; /* for error cases */
+
+ if (bval == NULL || bval->bv_val == NULL)
+ return (B_FALSE);
+ if (bval->bv_len >= sizeof (buf))
+ return (B_FALSE);
+
+ (void) memcpy(buf, bval->bv_val, bval->bv_len);
+ buf[bval->bv_len] = '\0';
+
+ tmp = strtoul(buf, &p, 10);
+
+ /* Junk after the number? */
+ if (*p != '\0')
+ return (B_FALSE);
+
+ *result = tmp;
+
+ return (B_TRUE);
+}
+
/* Return a NUL-terminated string from the Ber value */
char *
-adutils_bv_name2str(BerValue *bval)
+adutils_bv_str(BerValue *bval)
{
char *s;
@@ -461,32 +493,38 @@ adutils_reap_idle_connections()
adutils_rc
-adutils_ad_alloc(adutils_ad_t **new_ad, const char *default_domain,
+adutils_ad_alloc(adutils_ad_t **new_ad, const char *domain_name,
adutils_ad_partition_t part)
{
adutils_ad_t *ad;
*new_ad = NULL;
- if ((default_domain == NULL || *default_domain == '\0') &&
- part != ADUTILS_AD_GLOBAL_CATALOG)
- return (ADUTILS_ERR_DOMAIN);
if ((ad = calloc(1, sizeof (*ad))) == NULL)
return (ADUTILS_ERR_MEMORY);
ad->ref = 1;
ad->partition = part;
- if (default_domain == NULL)
- default_domain = "";
- if ((ad->dflt_w2k_dom = strdup(default_domain)) == NULL)
+
+ /* domain_name is required iff we are talking directly to a DC */
+ if (part == ADUTILS_AD_DATA) {
+ assert(domain_name != NULL);
+ assert(*domain_name != '\0');
+
+ ad->basedn = adutils_dns2dn(domain_name);
+ } else {
+ assert(domain_name == NULL);
+ ad->basedn = strdup("");
+ }
+ if (ad->basedn == NULL)
goto err;
+
if (pthread_mutex_init(&ad->lock, NULL) != 0)
goto err;
*new_ad = ad;
return (ADUTILS_SUCCESS);
err:
- if (ad->dflt_w2k_dom != NULL)
- free(ad->dflt_w2k_dom);
+ free(ad->basedn);
free(ad);
return (ADUTILS_ERR_MEMORY);
}
@@ -531,7 +569,7 @@ adutils_ad_free(adutils_ad_t **ad)
if ((*ad)->known_domains)
free((*ad)->known_domains);
- free((*ad)->dflt_w2k_dom);
+ free((*ad)->basedn);
free(*ad);
*ad = NULL;
@@ -587,9 +625,10 @@ open_conn(adutils_host_t *adh, int timeoutsecs)
logger(LOG_INFO, "ldap_sasl_interactive_bind_s() to server "
"%s port %d failed. (%s)", adh->host, adh->port,
ldap_err2string(rc));
+ goto out;
}
- logger(LOG_DEBUG, "Using global catalog server %s:%d",
+ logger(LOG_DEBUG, "Using server %s:%d",
adh->host, adh->port);
out:
@@ -922,26 +961,6 @@ adutils_lookup_batch_start(adutils_ad_t *ad, int nqueries,
if (new_state == NULL)
return (ADUTILS_ERR_MEMORY);
- /*
- * Save default domain from the ad object so that we don't
- * have to access the 'ad' object later.
- */
- new_state->default_domain = strdup(adh->owner->dflt_w2k_dom);
- if (new_state->default_domain == NULL) {
- free(new_state);
- return (ADUTILS_ERR_MEMORY);
- }
-
- if (ad->partition == ADUTILS_AD_DATA)
- new_state->basedn = adutils_dns2dn(new_state->default_domain);
- else
- new_state->basedn = strdup("");
- if (new_state->basedn == NULL) {
- free(new_state->default_domain);
- free(new_state);
- return (ADUTILS_ERR_MEMORY);
- }
-
new_state->ref_cnt = 1;
new_state->qadh = adh;
new_state->qsize = nqueries;
@@ -1485,8 +1504,6 @@ adutils_lookup_batch_release(adutils_query_state_t **state)
adutils_freeresult((*state)->queries[i].result);
}
}
- free((*state)->default_domain);
- free((*state)->basedn);
free(*state);
*state = NULL;
}
@@ -1545,12 +1562,6 @@ adutils_lookup_batch_end(adutils_query_state_t **state)
return (ad_rc);
}
-const char *
-adutils_lookup_batch_getdefdomain(adutils_query_state_t *state)
-{
- return (state->default_domain);
-}
-
/*
* Send one prepared search, queue up msgid, process what results are
* available
@@ -1605,7 +1616,9 @@ adutils_lookup_batch_add(adutils_query_state_t *state,
if (!state->qadh->dead) {
state->qadh->idletime = time(NULL);
- lrc = ldap_search_ext(state->qadh->ld, state->basedn,
+
+ lrc = ldap_search_ext(state->qadh->ld,
+ state->qadh->owner->basedn,
LDAP_SCOPE_SUBTREE, filter, (char **)attrs,
0, NULL, NULL, NULL, -1, &q->msgid);
diff --git a/usr/src/lib/libadutils/common/adutils_impl.h b/usr/src/lib/libadutils/common/adutils_impl.h
index 563fa892ec..9660d585ec 100644
--- a/usr/src/lib/libadutils/common/adutils_impl.h
+++ b/usr/src/lib/libadutils/common/adutils_impl.h
@@ -60,13 +60,14 @@ struct known_domain {
/* A set of DSs for a given AD partition */
struct adutils_ad {
- char *dflt_w2k_dom; /* used to qualify bare names */
int num_known_domains;
struct known_domain *known_domains;
pthread_mutex_t lock;
uint32_t ref;
struct adutils_host *last_adh;
adutils_ad_partition_t partition; /* Data or global catalog? */
+ /* If this is a reference to DC, this is the base DN for that DC */
+ char *basedn;
};
typedef struct adutils_attr {
@@ -141,8 +142,6 @@ struct adutils_query_state {
uint64_t qadh_gen; /* same as qadh->generation */
adutils_ldap_res_search_cb ldap_res_search_cb;
void *ldap_res_search_argp;
- char *default_domain;
- char *basedn;
adutils_q_t queries[1]; /* array of query results */
};
diff --git a/usr/src/lib/libadutils/common/libadutils.h b/usr/src/lib/libadutils/common/libadutils.h
index 39adf1a677..a184769cd0 100644
--- a/usr/src/lib/libadutils/common/libadutils.h
+++ b/usr/src/lib/libadutils/common/libadutils.h
@@ -133,7 +133,7 @@ typedef void (*adutils_logger)(int, const char *, ...);
extern adutils_rc adutils_ad_alloc(adutils_ad_t **new_ad,
- const char *default_domain,
+ const char *domain_name,
adutils_ad_partition_t part);
extern void adutils_ad_free(adutils_ad_t **ad);
extern adutils_rc adutils_add_ds(adutils_ad_t *ad,
@@ -153,7 +153,8 @@ extern const adutils_entry_t *adutils_getfirstentry(
extern int adutils_txtsid2hexbinsid(const char *txt,
const uint32_t *rid,
char *hexbinsid, int hexbinsidlen);
-extern char *adutils_bv_name2str(BerValue *bval);
+extern char *adutils_bv_str(BerValue *bval);
+extern boolean_t adutils_bv_uint(BerValue *bval, unsigned int *result);
extern char *adutils_bv_objsid2sidstr(BerValue *bval,
uint32_t *rid);
extern void adutils_reap_idle_connections(void);
@@ -171,8 +172,6 @@ extern adutils_rc adutils_lookup_batch_end(
adutils_query_state_t **state);
extern void adutils_lookup_batch_release(
adutils_query_state_t **state);
-extern const char *adutils_lookup_batch_getdefdomain(
- adutils_query_state_t *state);
extern int adutils_lookup_check_domain(
adutils_query_state_t *state,
const char *domain);
diff --git a/usr/src/lib/libadutils/common/mapfile-vers b/usr/src/lib/libadutils/common/mapfile-vers
index ffde67ee30..d7e1687ef2 100644
--- a/usr/src/lib/libadutils/common/mapfile-vers
+++ b/usr/src/lib/libadutils/common/mapfile-vers
@@ -40,8 +40,9 @@
SUNWprivate {
global:
adutils_txtsid2hexbinsid;
- adutils_bv_name2str;
+ adutils_bv_uint;
adutils_bv_objsid2sidstr;
+ adutils_bv_str;
adutils_getattr;
adutils_getfirstentry;
adutils_freeresult;
@@ -50,7 +51,6 @@ SUNWprivate {
adutils_lookup_batch_add;
adutils_lookup_batch_end;
adutils_lookup_batch_release;
- adutils_lookup_batch_getdefdomain;
adutils_lookup_check_domain;
adutils_lookup_check_sid_prefix;
adutils_dn2dns;
diff --git a/usr/src/lib/libidmap/common/idmap_api.c b/usr/src/lib/libidmap/common/idmap_api.c
index f19e0f1dda..a6d773e195 100644
--- a/usr/src/lib/libidmap/common/idmap_api.c
+++ b/usr/src/lib/libidmap/common/idmap_api.c
@@ -2257,7 +2257,6 @@ idmap_how_ds_based_cpy(idmap_how_ds_based *to, idmap_how_ds_based *from)
return (retval);
}
-
idmap_stat
idmap_info_cpy(idmap_info *to, idmap_info *from)
{
@@ -2294,6 +2293,11 @@ idmap_info_cpy(idmap_info *to, idmap_info *from)
case IDMAP_MAP_TYPE_KNOWN_SID:
break;
+
+ case IDMAP_MAP_TYPE_IDMU:
+ retval = idmap_how_ds_based_cpy(&to->how.idmap_how_u.idmu,
+ &from->how.idmap_how_u.idmu);
+ break;
}
return (retval);
}
@@ -2366,6 +2370,15 @@ idmap_info_free(idmap_info *info)
case IDMAP_MAP_TYPE_LOCAL_SID:
break;
+
+ case IDMAP_MAP_TYPE_IDMU:
+ free(how->idmap_how_u.idmu.dn);
+ how->idmap_how_u.idmu.dn = NULL;
+ free(how->idmap_how_u.idmu.attr);
+ how->idmap_how_u.idmu.attr = NULL;
+ free(how->idmap_how_u.idmu.value);
+ how->idmap_how_u.idmu.value = NULL;
+ break;
}
how->map_type = IDMAP_MAP_TYPE_UNKNOWN;
info->src = IDMAP_MAP_SRC_UNKNOWN;
diff --git a/usr/src/lib/libshare/smb/libshare_smb.c b/usr/src/lib/libshare/smb/libshare_smb.c
index 7bf25db802..0c6a0f5ad9 100644
--- a/usr/src/lib/libshare/smb/libshare_smb.c
+++ b/usr/src/lib/libshare/smb/libshare_smb.c
@@ -161,6 +161,7 @@ struct sa_plugin_ops sa_plugin_ops = {
struct option_defs optdefs[] = {
{ SHOPT_AD_CONTAINER, OPT_TYPE_STRING },
+ { SHOPT_ABE, OPT_TYPE_BOOLEAN },
{ SHOPT_NAME, OPT_TYPE_NAME },
{ SHOPT_RO, OPT_TYPE_ACCLIST },
{ SHOPT_RW, OPT_TYPE_ACCLIST },
@@ -1541,6 +1542,9 @@ smb_add_transient(sa_handle_t handle, smb_share_t *si)
if ((opt = smb_csc_name(si)) != NULL)
(void) sa_set_resource_attr(resource, SHOPT_CSC, opt);
+ opt = (si->shr_flags & SMB_SHRF_ABE) ? "true" : "false";
+ (void) sa_set_resource_attr(resource, SHOPT_ABE, opt);
+
opt = (si->shr_flags & SMB_SHRF_GUEST_OK) ? "true" : "false";
(void) sa_set_resource_attr(resource, SHOPT_GUEST, opt);
@@ -2035,6 +2039,19 @@ smb_build_shareinfo(sa_share_t share, sa_resource_t resource, smb_share_t *si)
}
}
+ prop = sa_get_property(opts, SHOPT_ABE);
+ if (prop != NULL) {
+ if ((val = sa_get_property_attr(prop, "value")) != NULL) {
+ if ((strcasecmp(val, "true") == 0) ||
+ (strcmp(val, "1") == 0)) {
+ si->shr_flags |= SMB_SHRF_ABE;
+ } else {
+ si->shr_flags &= ~SMB_SHRF_ABE;
+ }
+ free(val);
+ }
+ }
+
prop = sa_get_property(opts, SHOPT_CSC);
if (prop != NULL) {
if ((val = sa_get_property_attr(prop, "value")) != NULL) {
diff --git a/usr/src/lib/smbsrv/libmlsvc/Makefile.com b/usr/src/lib/smbsrv/libmlsvc/Makefile.com
index bd8e4cbad3..c10cab0b67 100644
--- a/usr/src/lib/smbsrv/libmlsvc/Makefile.com
+++ b/usr/src/lib/smbsrv/libmlsvc/Makefile.com
@@ -84,7 +84,7 @@ INCS += -I$(SRC)/common/smbsrv
LDLIBS += $(MACH_LDLIBS)
LDLIBS += -lmlrpc -lsmbrdr -lsmb -lsmbns -lshare -lresolv -lnsl -lpkcs11 -lscf \
- -luutil -lzfs -lc
+ -lnvpair -luutil -lzfs -lc
CPPFLAGS += $(INCS) -D_REENTRANT
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h b/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h
index aa71d92438..176bde8ca1 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h
+++ b/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h
@@ -161,6 +161,7 @@ int ndr_rpc_call(mlsvc_handle_t *, int, void *);
void ndr_rpc_server_setinfo(mlsvc_handle_t *, const srvsvc_server_info_t *);
void ndr_rpc_server_getinfo(mlsvc_handle_t *, srvsvc_server_info_t *);
int ndr_rpc_server_os(mlsvc_handle_t *);
+int ndr_rpc_get_ssnkey(mlsvc_handle_t *, unsigned char *, size_t);
void *ndr_rpc_malloc(mlsvc_handle_t *, size_t);
ndr_heap_t *ndr_rpc_get_heap(mlsvc_handle_t *);
void ndr_rpc_release(mlsvc_handle_t *);
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h
index 58794a4f64..0f41819eec 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h
@@ -64,6 +64,11 @@ uint32_t srvsvc_sd_set(smb_share_t *, uint8_t *);
uint32_t smb_logon_init(void);
void smb_logon_fini(void);
+/* Locking for process-wide settings (i.e. privileges) */
+void smb_proc_initsem(void); /* init (or re-init in child) */
+int smb_proc_takesem(void); /* parent before */
+void smb_proc_givesem(void); /* parent after */
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c
index f2e17f35c6..1929213c4d 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_client.c
@@ -208,6 +208,31 @@ ndr_rpc_server_os(mlsvc_handle_t *handle)
return (handle->remote_os);
}
+/*
+ * Get the session key from a bound RPC client handle.
+ *
+ * The key returned is the 16-byte "user session key"
+ * established by the underlying authentication protocol
+ * (either Kerberos or NTLM). This key is needed for
+ * SAM RPC calls such as SamrSetInformationUser, etc.
+ * See [MS-SAMR] sections: 2.2.3.3, 2.2.7.21, 2.2.7.25.
+ *
+ * Returns zero (success) or an errno.
+ */
+int
+ndr_rpc_get_ssnkey(mlsvc_handle_t *handle,
+ unsigned char *ssn_key, size_t len)
+{
+ ndr_client_t *clnt = handle->clnt;
+ int rc;
+
+ if (clnt == NULL)
+ return (EINVAL);
+
+ rc = smbrdr_get_ssnkey(clnt->fid, ssn_key, len);
+ return (rc);
+}
+
void *
ndr_rpc_malloc(mlsvc_handle_t *handle, size_t size)
{
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c
index afb51685c5..b48ba9b4e0 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c
@@ -52,6 +52,8 @@ mlsvc_init(void)
pthread_attr_t tattr;
int rc;
+ smb_proc_initsem();
+
if (smb_logon_init() != NT_STATUS_SUCCESS)
return (-1);
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c
index adc83a5756..ee63914a1a 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c
@@ -52,7 +52,6 @@ static boolean_t mlsvc_ntjoin_support = B_FALSE;
extern int netr_open(char *, char *, mlsvc_handle_t *);
extern int netr_close(mlsvc_handle_t *);
extern DWORD netlogon_auth(char *, mlsvc_handle_t *, DWORD);
-extern int mlsvc_user_getauth(char *, char *, smb_auth_info_t *);
/*
* mlsvc_lookup_name
@@ -141,7 +140,6 @@ mlsvc_netlogon(char *server, char *domain)
DWORD
mlsvc_join(smb_domain_t *dinfo, char *user, char *plain_text)
{
- smb_auth_info_t auth;
int erc;
DWORD status;
char machine_passwd[NETR_MACHINE_ACCT_PASSWD_MAX];
@@ -168,14 +166,9 @@ mlsvc_join(smb_domain_t *dinfo, char *user, char *plain_text)
status = NT_STATUS_UNSUCCESSFUL;
}
} else {
- if (mlsvc_user_getauth(dinfo->d_dc, user, &auth)
- != 0) {
- status = NT_STATUS_INVALID_PARAMETER;
- return (status);
- }
status = sam_create_trust_account(dinfo->d_dc,
- domain->di_nbname, &auth);
+ domain->di_nbname);
if (status == NT_STATUS_SUCCESS) {
(void) smb_getnetbiosname(machine_passwd,
sizeof (machine_passwd));
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samlib.c b/usr/src/lib/smbsrv/libmlsvc/common/samlib.c
index 5e891abfd6..18b69c89bc 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/samlib.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samlib.c
@@ -45,7 +45,7 @@
#define SAM_PASSWORD_516 516
#define SAM_KEYLEN 16
-extern DWORD samr_set_user_info(mlsvc_handle_t *, smb_auth_info_t *);
+extern DWORD samr_set_user_info(mlsvc_handle_t *);
static struct samr_sid *sam_get_domain_sid(mlsvc_handle_t *, char *, char *);
/*
@@ -59,7 +59,7 @@ static struct samr_sid *sam_get_domain_sid(mlsvc_handle_t *, char *, char *);
* Returns NT status codes.
*/
DWORD
-sam_create_trust_account(char *server, char *domain, smb_auth_info_t *auth)
+sam_create_trust_account(char *server, char *domain)
{
char account_name[SMB_SAMACCT_MAXLEN];
DWORD status;
@@ -73,7 +73,7 @@ sam_create_trust_account(char *server, char *domain, smb_auth_info_t *auth)
* information is set on this account.
*/
status = sam_create_account(server, domain, account_name,
- auth, SAMR_AF_WORKSTATION_TRUST_ACCOUNT);
+ SAMR_AF_WORKSTATION_TRUST_ACCOUNT);
/*
* Based on network traces, a Windows 2000 client will
@@ -104,7 +104,7 @@ sam_create_trust_account(char *server, char *domain, smb_auth_info_t *auth)
*/
DWORD
sam_create_account(char *server, char *domain_name, char *account_name,
- smb_auth_info_t *auth, DWORD account_flags)
+ DWORD account_flags)
{
mlsvc_handle_t samr_handle;
mlsvc_handle_t domain_handle;
@@ -140,7 +140,7 @@ sam_create_account(char *server, char *domain_name, char *account_name,
SAMR_QUERY_USER_UNKNOWN16, &sui);
(void) samr_get_user_pwinfo(&user_handle);
- (void) samr_set_user_info(&user_handle, auth);
+ (void) samr_set_user_info(&user_handle);
(void) samr_close_handle(&user_handle);
} else if (status != NT_STATUS_USER_EXISTS) {
smb_tracef("SamCreateAccount[%s]: %s",
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samlib.h b/usr/src/lib/smbsrv/libmlsvc/common/samlib.h
index 4a12235b14..3a3932e40f 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/samlib.h
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samlib.h
@@ -61,8 +61,8 @@ extern "C" {
/*
* samlib.c
*/
-DWORD sam_create_trust_account(char *, char *, smb_auth_info_t *);
-DWORD sam_create_account(char *, char *, char *, smb_auth_info_t *, DWORD);
+DWORD sam_create_trust_account(char *, char *);
+DWORD sam_create_account(char *, char *, char *, DWORD);
DWORD sam_remove_trust_account(char *, char *);
DWORD sam_delete_account(char *, char *, char *);
DWORD sam_get_local_domains(char *, char *);
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samr_lookup.c b/usr/src/lib/smbsrv/libmlsvc/common/samr_lookup.c
index 55f4e42364..6d858ab02d 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/samr_lookup.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samr_lookup.c
@@ -45,7 +45,7 @@ static int samr_setup_user_info(WORD, struct samr_QueryUserInfo *,
union samr_user_info *);
static void samr_set_user_unknowns(struct samr_SetUserInfo23 *);
static void samr_set_user_logon_hours(struct samr_SetUserInfo *);
-static int samr_set_user_password(smb_auth_info_t *, BYTE *);
+static int samr_set_user_password(unsigned char *, BYTE *);
/*
* samr_lookup_domain
@@ -389,8 +389,9 @@ samr_get_user_pwinfo(mlsvc_handle_t *user_handle)
*/
/*ARGSUSED*/
DWORD
-samr_set_user_info(mlsvc_handle_t *user_handle, smb_auth_info_t *auth)
+samr_set_user_info(mlsvc_handle_t *user_handle)
{
+ unsigned char ssn_key[SMBAUTH_SESSION_KEY_SZ];
struct samr_SetUserInfo arg;
int opnum;
DWORD status = 0;
@@ -398,6 +399,9 @@ samr_set_user_info(mlsvc_handle_t *user_handle, smb_auth_info_t *auth)
if (ndr_is_null_handle(user_handle))
return (NT_STATUS_INVALID_PARAMETER);
+ if (ndr_rpc_get_ssnkey(user_handle, ssn_key, sizeof (ssn_key)))
+ return (NT_STATUS_INVALID_PARAMETER);
+
opnum = SAMR_OPNUM_SetUserInfo;
bzero(&arg, sizeof (struct samr_SetUserInfo));
(void) memcpy(&arg.user_handle, &user_handle->handle,
@@ -409,7 +413,7 @@ samr_set_user_info(mlsvc_handle_t *user_handle, smb_auth_info_t *auth)
samr_set_user_unknowns(&arg.info.ru.info23);
samr_set_user_logon_hours(&arg);
- if (samr_set_user_password(auth, arg.info.ru.info23.password) < 0)
+ if (samr_set_user_password(ssn_key, arg.info.ru.info23.password) < 0)
status = NT_STATUS_INTERNAL_ERROR;
if (ndr_rpc_call(user_handle, opnum, &arg) != 0) {
@@ -494,9 +498,8 @@ samr_set_user_logon_hours(struct samr_SetUserInfo *sui)
* key.
*/
static int
-samr_set_user_password(smb_auth_info_t *auth, BYTE *oem_password)
+samr_set_user_password(unsigned char *nt_key, BYTE *oem_password)
{
- unsigned char nt_key[SMBAUTH_SESSION_KEY_SZ];
char hostname[NETBIOS_NAME_SZ];
randomize((char *)oem_password, SAMR_SET_USER_DATA_SZ);
@@ -510,9 +513,6 @@ samr_set_user_password(smb_auth_info_t *auth, BYTE *oem_password)
(void) utf8_strlwr(hostname);
- if (smb_auth_gen_session_key(auth, nt_key) != SMBAUTH_SUCCESS)
- return (-1);
-
/*
* Generate the OEM password from the hostname and the user session
* key(nt_key).
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c b/usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c
index c777254684..695bfb55b7 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c
@@ -452,6 +452,11 @@ smb_autohome_parse_options(smb_share_t *si)
continue;
}
+ if (strncasecmp(value, "abe=", 4) == 0) {
+ smb_shr_sa_abe_option((value + 4), si);
+ continue;
+ }
+
if (strncasecmp(value, "description=", 12) == 0) {
(void) strlcpy(si->shr_cmnt, (value + 12),
SMB_SHARE_CMNT_MAX);
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c b/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c
index bb3789f709..d099db11b5 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c
@@ -52,6 +52,7 @@
#include <smbsrv/smb_share.h>
#include <smbsrv/cifs.h>
#include <smbsrv/nterror.h>
+#include <mlsvc.h>
#define SMB_SHR_ERROR_THRESHOLD 3
@@ -210,6 +211,13 @@ static char smb_shr_exec_unmap[MAXPATHLEN];
static mutex_t smb_shr_exec_mtx;
/*
+ * Semaphore held during temporary, process-wide changes
+ * such as process privileges. It is a seamaphore and
+ * not a mutex so a child of fork can reset it.
+ */
+static sema_t smb_proc_sem = DEFAULTSEMA;
+
+/*
* Creates and initializes the cache and starts the publisher
* thread.
*/
@@ -574,6 +582,7 @@ smb_shr_get(char *sharename, smb_share_t *si)
* o comment
* o AD container
* o host access
+ * o abe
*/
uint32_t
smb_shr_modify(smb_share_t *new_si)
@@ -581,9 +590,7 @@ smb_shr_modify(smb_share_t *new_si)
smb_share_t *si;
boolean_t adc_changed = B_FALSE;
char old_container[MAXPATHLEN];
- uint32_t catia;
- uint32_t cscflg;
- uint32_t access;
+ uint32_t catia, cscflg, access, abe;
assert(new_si != NULL);
@@ -612,6 +619,10 @@ smb_shr_modify(smb_share_t *new_si)
sizeof (si->shr_container));
}
+ abe = (new_si->shr_flags & SMB_SHRF_ABE);
+ si->shr_flags &= ~SMB_SHRF_ABE;
+ si->shr_flags |= abe;
+
catia = (new_si->shr_flags & SMB_SHRF_CATIA);
si->shr_flags &= ~SMB_SHRF_CATIA;
si->shr_flags |= catia;
@@ -949,6 +960,9 @@ smb_shr_exec(char *share, smb_execsub_info_t *subs, int exec_type)
if (*cmd == '\0')
return (0);
+ if (smb_proc_takesem() != 0)
+ return (-1);
+
pact.sa_handler = smb_shr_sig_child;
pact.sa_flags = 0;
(void) sigemptyset(&pact.sa_mask);
@@ -958,6 +972,7 @@ smb_shr_exec(char *share, smb_execsub_info_t *subs, int exec_type)
if ((child_pid = fork()) == -1) {
(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
+ smb_proc_givesem();
return (-1);
}
@@ -979,6 +994,8 @@ smb_shr_exec(char *share, smb_execsub_info_t *subs, int exec_type)
if (smb_shr_enable_all_privs())
_exit(-1);
+ smb_proc_initsem();
+
(void) trim_whitespace(cmd);
(void) strcanon(cmd, " ");
@@ -999,6 +1016,9 @@ smb_shr_exec(char *share, smb_execsub_info_t *subs, int exec_type)
_exit(-1);
}
+ (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
+ smb_proc_givesem();
+
/* parent process */
while (waitpid(child_pid, &child_status, 0) < 0) {
@@ -1010,8 +1030,6 @@ smb_shr_exec(char *share, smb_execsub_info_t *subs, int exec_type)
continue;
}
- (void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
-
if (WIFEXITED(child_status))
return (WEXITSTATUS(child_status));
@@ -1019,6 +1037,27 @@ smb_shr_exec(char *share, smb_execsub_info_t *subs, int exec_type)
}
/*
+ * Locking for process-wide settings (i.e. privileges)
+ */
+void
+smb_proc_initsem(void)
+{
+ (void) sema_init(&smb_proc_sem, 1, USYNC_THREAD, NULL);
+}
+
+int
+smb_proc_takesem(void)
+{
+ return (sema_wait(&smb_proc_sem));
+}
+
+void
+smb_proc_givesem(void)
+{
+ (void) sema_post(&smb_proc_sem);
+}
+
+/*
* ============================================
* Private helper/utility functions
* ============================================
@@ -1527,6 +1566,14 @@ smb_shr_sa_get(sa_share_t share, sa_resource_t resource, smb_share_t *si)
}
}
+ prop = (sa_property_t)sa_get_property(opts, SHOPT_ABE);
+ if (prop != NULL) {
+ if ((val = sa_get_property_attr(prop, "value")) != NULL) {
+ smb_shr_sa_abe_option(val, si);
+ free(val);
+ }
+ }
+
prop = (sa_property_t)sa_get_property(opts, SHOPT_CSC);
if (prop != NULL) {
if ((val = sa_get_property_attr(prop, "value")) != NULL) {
@@ -1645,6 +1692,19 @@ smb_shr_sa_catia_option(const char *value, smb_share_t *si)
}
/*
+ * set SMB_SHRF_ABE in accordance with abe property value
+ */
+void
+smb_shr_sa_abe_option(const char *value, smb_share_t *si)
+{
+ if ((strcasecmp(value, "true") == 0) || (strcmp(value, "1") == 0)) {
+ si->shr_flags |= SMB_SHRF_ABE;
+ } else {
+ si->shr_flags &= ~SMB_SHRF_ABE;
+ }
+}
+
+/*
* set SMB_SHRF_GUEST_OK in accordance with guestok property value
*/
static void
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c
index 9000acd425..616701292f 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c
@@ -45,6 +45,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <libshare.h>
+#include <libnvpair.h>
#include <smbsrv/libsmb.h>
#include <smbsrv/libmlsvc.h>
#include <smbsrv/lmerr.h>
@@ -139,11 +140,12 @@ static uint32_t srvsvc_modify_share(smb_share_t *,
static uint32_t srvsvc_modify_transient_share(smb_share_t *,
srvsvc_netshare_setinfo_t *);
static uint32_t srvsvc_update_share_flags(smb_share_t *, uint32_t);
+static uint32_t srvsvc_get_share_flags(smb_share_t *);
static uint32_t srvsvc_sa_add(char *, char *, char *);
static uint32_t srvsvc_sa_delete(char *);
static uint32_t srvsvc_sa_modify(smb_share_t *, srvsvc_netshare_setinfo_t *);
-static uint32_t srvsvc_sa_setattr(smb_share_t *);
+static uint32_t srvsvc_sa_setprop(smb_share_t *, nvlist_t *);
static char empty_string[1];
@@ -881,7 +883,7 @@ srvsvc_s_NetShareGetInfo(void *arg, ndr_xa_t *mxa)
info501->shi501_netname = netname;
info501->shi501_comment = comment;
info501->shi501_type = si.shr_type;
- info501->shi501_reserved = 0;
+ info501->shi501_flags = srvsvc_get_share_flags(&si);
param->result.ru.info501 = info501;
break;
@@ -942,26 +944,7 @@ srvsvc_s_NetShareGetInfo(void *arg, ndr_xa_t *mxa)
case 1005:
info1005 = &info->nsg_info1005;
- info1005->shi1005_flags = 0;
-
- switch (si.shr_flags & SMB_SHRF_CSC_MASK) {
- case SMB_SHRF_CSC_DISABLED:
- info1005->shi1005_flags |= CSC_CACHE_NONE;
- break;
- case SMB_SHRF_CSC_AUTO:
- info1005->shi1005_flags |= CSC_CACHE_AUTO_REINT;
- break;
- case SMB_SHRF_CSC_VDO:
- info1005->shi1005_flags |= CSC_CACHE_VDO;
- break;
- case SMB_SHRF_CSC_MANUAL:
- default:
- /*
- * Default to CSC_CACHE_MANUAL_REINT.
- */
- break;
- }
-
+ info1005->shi1005_flags = srvsvc_get_share_flags(&si);
param->result.ru.info1005 = info1005;
break;
@@ -1108,6 +1091,9 @@ srvsvc_s_NetShareSetInfo(void *arg, ndr_xa_t *mxa)
info.nss_comment = (char *)info501->shi501_comment;
info.nss_type = info501->shi501_type;
status = srvsvc_modify_share(&si, &info);
+ if (status == ERROR_SUCCESS)
+ status = srvsvc_update_share_flags(&si,
+ info501->shi501_flags);
break;
case 502:
@@ -1230,43 +1216,103 @@ srvsvc_modify_transient_share(smb_share_t *si, srvsvc_netshare_setinfo_t *info)
return (NERR_Success);
}
+/*
+ * srvsvc_update_share_flags
+ *
+ * This function updates flags for shares.
+ * Flags for Persistent shares are updated in both libshare and the local cache.
+ * Flags for Transient shares are updated only in the local cache.
+ */
static uint32_t
srvsvc_update_share_flags(smb_share_t *si, uint32_t shi_flags)
{
- uint32_t cscflg = 0;
uint32_t nerr = NERR_Success;
+ uint32_t flag = 0;
+ char *csc_value;
+ char *abe_value = "false";
+ nvlist_t *nvl;
+ int err = 0;
+
+ if (shi_flags & SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM) {
+ flag = SMB_SHRF_ABE;
+ abe_value = "true";
+ }
+
+ si->shr_flags &= ~SMB_SHRF_ABE;
+ si->shr_flags |= flag;
switch ((shi_flags & CSC_MASK)) {
case CSC_CACHE_AUTO_REINT:
- cscflg = SMB_SHRF_CSC_AUTO;
+ flag = SMB_SHRF_CSC_AUTO;
break;
case CSC_CACHE_VDO:
- cscflg = SMB_SHRF_CSC_VDO;
+ flag = SMB_SHRF_CSC_VDO;
break;
case CSC_CACHE_NONE:
- cscflg = SMB_SHRF_CSC_DISABLED;
+ flag = SMB_SHRF_CSC_DISABLED;
break;
case CSC_CACHE_MANUAL_REINT:
- cscflg = SMB_SHRF_CSC_MANUAL;
+ flag = SMB_SHRF_CSC_MANUAL;
break;
default:
- return (NERR_Success);
+ return (NERR_InternalError);
}
- if (cscflg == (si->shr_flags & SMB_SHRF_CSC_MASK))
- return (NERR_Success);
-
si->shr_flags &= ~SMB_SHRF_CSC_MASK;
- si->shr_flags |= cscflg;
+ si->shr_flags |= flag;
if ((si->shr_flags & SMB_SHRF_TRANS) == 0) {
- if ((nerr = srvsvc_sa_setattr(si)) != NERR_Success)
+ csc_value = smb_shr_sa_csc_name(si);
+
+ if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
+ return (NERR_InternalError);
+
+ err |= nvlist_add_string(nvl, SHOPT_CSC, csc_value);
+ err |= nvlist_add_string(nvl, SHOPT_ABE, abe_value);
+ if (err) {
+ nvlist_free(nvl);
+ return (NERR_InternalError);
+ }
+
+ nerr = srvsvc_sa_setprop(si, nvl);
+ nvlist_free(nvl);
+
+ if (nerr != NERR_Success)
return (nerr);
}
return (smb_shr_modify(si));
}
+static uint32_t
+srvsvc_get_share_flags(smb_share_t *si)
+{
+ uint32_t flags = 0;
+
+ switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
+ case SMB_SHRF_CSC_DISABLED:
+ flags |= CSC_CACHE_NONE;
+ break;
+ case SMB_SHRF_CSC_AUTO:
+ flags |= CSC_CACHE_AUTO_REINT;
+ break;
+ case SMB_SHRF_CSC_VDO:
+ flags |= CSC_CACHE_VDO;
+ break;
+ case SMB_SHRF_CSC_MANUAL:
+ default:
+ /*
+ * Default to CSC_CACHE_MANUAL_REINT.
+ */
+ break;
+ }
+
+ if (si->shr_flags & SMB_SHRF_ABE)
+ flags |= SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM;
+
+ return (flags);
+}
+
/*
* srvsvc_s_NetSessionEnum
*
@@ -1977,7 +2023,7 @@ srvsvc_estimate_limit(smb_svcenum_t *se, uint32_t obj_size)
* Level 0: share names.
* Level 1: share name, share type and comment field.
* Level 2: everything that we know about the shares.
- * Level 501: level 1 + flags (flags must be zero).
+ * Level 501: level 1 + flags.
* Level 502: level 2 + security descriptor.
*/
static int
@@ -2541,7 +2587,7 @@ mlsvc_NetShareEnumCommon(ndr_xa_t *mxa, smb_svcenum_t *se,
info501[i].shi501_netname = netname;
info501[i].shi501_comment = comment;
info501[i].shi501_type = si->shr_type;
- info501[i].shi501_reserved = 0;
+ info501[i].shi501_flags = srvsvc_get_share_flags(si);
break;
case 502:
@@ -2889,15 +2935,25 @@ srvsvc_sa_modify(smb_share_t *si, srvsvc_netshare_setinfo_t *info)
}
/*
- * Update the share flags.
+ * Update the share properties.
+ *
+ * Updates the optionset properties of the share resource.
+ * The properties are given as a list of name-value pair.
+ * The name argument should be the optionset property name and the value
+ * should be a valid value for the specified property.
*/
static uint32_t
-srvsvc_sa_setattr(smb_share_t *si)
+srvsvc_sa_setprop(smb_share_t *si, nvlist_t *nvl)
{
sa_handle_t handle;
sa_share_t share;
sa_resource_t resource;
- char *value;
+ sa_property_t prop;
+ sa_optionset_t opts;
+ uint32_t nerr = NERR_Success;
+ nvpair_t *cur;
+ int err = 0;
+ char *name, *val;
if ((handle = smb_shr_sa_enter()) == NULL)
return (NERR_InternalError);
@@ -2912,16 +2968,54 @@ srvsvc_sa_setattr(smb_share_t *si)
return (NERR_InternalError);
}
- if ((value = smb_shr_sa_csc_name(si)) == NULL) {
- smb_shr_sa_exit();
- return (NERR_InternalError);
+ if ((opts = sa_get_optionset(resource, SMB_PROTOCOL_NAME)) == NULL) {
+ opts = sa_create_optionset(resource, SMB_PROTOCOL_NAME);
+ if (opts == NULL) {
+ smb_shr_sa_exit();
+ return (NERR_InternalError);
+ }
+ }
+
+ cur = nvlist_next_nvpair(nvl, NULL);
+ while (cur != NULL) {
+ name = nvpair_name(cur);
+ err = nvpair_value_string(cur, &val);
+ if ((err != 0) || (name == NULL) || (val == NULL)) {
+ nerr = NERR_InternalError;
+ break;
+ }
+
+ prop = NULL;
+ if ((prop = sa_get_property(opts, name)) == NULL) {
+ prop = sa_create_property(name, val);
+ if (prop != NULL) {
+ nerr = sa_valid_property(handle, opts,
+ SMB_PROTOCOL_NAME, prop);
+ if (nerr != NERR_Success) {
+ (void) sa_remove_property(prop);
+ break;
+ }
+ }
+ nerr = sa_add_property(opts, prop);
+ if (nerr != NERR_Success)
+ break;
+ } else {
+ nerr = sa_update_property(prop, val);
+ if (nerr != NERR_Success)
+ break;
+ }
+
+ cur = nvlist_next_nvpair(nvl, cur);
}
- (void) sa_set_resource_attr(resource, SHOPT_CSC, value);
+ if (nerr == NERR_Success)
+ nerr = sa_commit_properties(opts, 0);
+
smb_shr_sa_exit();
- return (NERR_Success);
+ return (nerr);
}
+
static ndr_stub_table_t srvsvc_stub_table[] = {
{ srvsvc_s_NetConnectEnum, SRVSVC_OPNUM_NetConnectEnum },
{ srvsvc_s_NetFileEnum, SRVSVC_OPNUM_NetFileEnum },
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.c b/usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.c
index 342a810385..977b3874c9 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.c
@@ -573,7 +573,7 @@ svcctl_scm_enum_services(svcctl_manager_context_t *mgr_ctx, uint8_t *buf,
}
}
- offset = base_offset;
+ offset = buflen;
node = uu_avl_first(mgr_ctx->mc_svcs);
for (ns = 0; ((ns < *resume_handle) && (node != NULL)); ++ns)
@@ -587,38 +587,36 @@ svcctl_scm_enum_services(svcctl_manager_context_t *mgr_ctx, uint8_t *buf,
for (ns = 0; ((ns < numsvcs) && (node != NULL)); ++ns) {
node_name = node->sn_name;
namelen = strlen(node_name) + 1;
- svc[ns].svc_name = offset;
-
if (use_wchar) {
+ offset -= SVCCTL_WNSTRLEN(node_name);
/*LINTED E_BAD_PTR_CAST_ALIGN*/
w_name = (mts_wchar_t *)&buf[offset];
(void) mts_mbstowcs(w_name, node_name, namelen);
- offset += SVCCTL_WNSTRLEN(node_name);
} else {
+ offset -= namelen;
a_name = (char *)&buf[offset];
(void) strlcpy(a_name, node_name, namelen);
- offset += namelen;
}
+ svc[ns].svc_name = offset;
- if (offset >= buflen)
+ if (offset <= base_offset)
break;
node_name = node->sn_fmri;
namelen = strlen(node_name) + 1;
- svc[ns].display_name = offset;
-
if (use_wchar) {
+ offset -= SVCCTL_WNSTRLEN(node_name);
/*LINTED E_BAD_PTR_CAST_ALIGN*/
w_name = (mts_wchar_t *)&buf[offset];
(void) mts_mbstowcs(w_name, node_name, namelen);
- offset += SVCCTL_WNSTRLEN(node_name);
} else {
+ offset -= namelen;
a_name = (char *)&buf[offset];
(void) strlcpy(a_name, node_name, namelen);
- offset += namelen;
}
+ svc[ns].display_name = offset;
- if (offset >= buflen)
+ if (offset <= base_offset)
break;
svc[ns].svc_status.cur_state =
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/svcctl_svc.c b/usr/src/lib/smbsrv/libmlsvc/common/svcctl_svc.c
index d6669b361a..23964f7d9a 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/svcctl_svc.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/svcctl_svc.c
@@ -52,6 +52,14 @@
((S) & SERVICE_STOP) || \
((S) & SERVICE_ENUMERATE_DEPENDENTS)
+typedef union {
+ uint8_t *svc_buf;
+ svc_description_t *svc_desc;
+ svc_failure_actions_t *svc_fac;
+ svc_delayed_auto_start_t *svc_dstart;
+ svc_config_failure_action_t *svc_cfa;
+} svc_config_rsp_t;
+
static int svcctl_s_Close(void *, ndr_xa_t *);
static int svcctl_s_ControlService(void *, ndr_xa_t *);
static int svcctl_s_DeleteService(void *, ndr_xa_t *);
@@ -844,7 +852,7 @@ svcctl_s_QueryServiceConfig(void *arg, ndr_xa_t *mxa)
cfg = &param->service_cfg;
cfg->service_type = SERVICE_WIN32_SHARE_PROCESS;
cfg->start_type = SERVICE_AUTO_START;
- cfg->error_control = SERVICE_AUTO_START;
+ cfg->error_control = SERVICE_ERROR_IGNORE;
cfg->binary_pathname = NDR_STRDUP(mxa, "");
cfg->loadorder_group = NDR_STRDUP(mxa, "");
cfg->tag_id = 0;
@@ -1184,8 +1192,7 @@ svcctl_s_QueryServiceConfig2W(void *arg, ndr_xa_t *mxa)
svcctl_manager_context_t *mgr_ctx;
svcctl_service_context_t *svc_ctx;
svcctl_svc_node_t *svc;
- svc_description_t *svc_desc;
- svc_failure_actions_t *fac;
+ svc_config_rsp_t svc_rsp;
int offset, input_bufsize, bytes_needed = 0;
mts_wchar_t *wide_desc;
char *desc;
@@ -1209,6 +1216,7 @@ svcctl_s_QueryServiceConfig2W(void *arg, ndr_xa_t *mxa)
}
bzero(param->buffer, input_bufsize);
+ svc_rsp.svc_buf = param->buffer;
status = ERROR_SUCCESS;
switch (param->info_level) {
case SERVICE_CONFIG_DESCRIPTION:
@@ -1235,25 +1243,41 @@ svcctl_s_QueryServiceConfig2W(void *arg, ndr_xa_t *mxa)
}
offset = sizeof (svc_description_t);
- /*LINTED E_BAD_PTR_CAST_ALIGN*/
- svc_desc = (svc_description_t *)param->buffer;
- svc_desc->desc = offset;
+ svc_rsp.svc_desc->desc = offset;
/*LINTED E_BAD_PTR_CAST_ALIGN*/
wide_desc = (mts_wchar_t *)&param->buffer[offset];
(void) mts_mbstowcs(wide_desc, desc, (strlen(desc) + 1));
- offset = SVCCTL_WNSTRLEN(desc);
+ offset += SVCCTL_WNSTRLEN(desc);
param->bytes_needed = offset;
break;
case SERVICE_CONFIG_FAILURE_ACTIONS:
- /*LINTED E_BAD_PTR_CAST_ALIGN*/
- fac = (svc_failure_actions_t *)param->buffer;
- bzero(fac, sizeof (svc_failure_actions_t));
+ bzero(svc_rsp.svc_fac, sizeof (svc_failure_actions_t));
+ bytes_needed = sizeof (svc_failure_actions_t);
+ if (input_bufsize <= bytes_needed) {
+ param->bytes_needed = bytes_needed;
+ param->status = ERROR_INSUFFICIENT_BUFFER;
+ return (NDR_DRC_OK);
+ }
+ param->bytes_needed = bytes_needed;
+ break;
+
+ case SERVICE_CONFIG_DELAYED_AUTO_START_INFO:
+ svc_rsp.svc_dstart->dstart = 0;
+ param->bytes_needed = sizeof (svc_delayed_auto_start_t);
+ break;
- param->bytes_needed = input_bufsize;
+ case SERVICE_CONFIG_FAILURE_ACTIONS_FLAG:
+ svc_rsp.svc_cfa->cfa = 0;
+ param->bytes_needed = sizeof (svc_config_failure_action_t);
break;
+ case SERVICE_CONFIG_SERVICE_SID_INFO:
+ case SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO:
+ case SERVICE_CONFIG_PRESHUTDOWN_INFO:
+ case SERVICE_CONFIG_TRIGGER_INFO:
+ case SERVICE_CONFIG_PREFERRED_NODE:
default:
status = ERROR_INVALID_LEVEL;
break;
@@ -1305,7 +1329,7 @@ svcctl_s_QueryServiceStatusEx(void *arg, ndr_xa_t *mxa)
goto query_service_status_ex_error;
}
- bytes_needed = sizeof (struct svcctl_QueryServiceStatusEx);
+ bytes_needed = sizeof (svc_status_ex_t);
if ((input_bufsize = param->buf_size) < bytes_needed) {
bzero(param, sizeof (struct svcctl_QueryServiceStatusEx));
@@ -1338,8 +1362,8 @@ svcctl_s_QueryServiceStatusEx(void *arg, ndr_xa_t *mxa)
svc_status_ex->service_flags = 1;
param->buffer = (uint8_t *)svc_status_ex;
- param->buf_size = bytes_needed;
- param->bytes_needed = 0;
+ param->buf_size = input_bufsize;
+ param->bytes_needed = bytes_needed;
param->status = ERROR_SUCCESS;
return (NDR_DRC_OK);
diff --git a/usr/src/lib/smbsrv/libmlsvc/common/winreg_svc.c b/usr/src/lib/smbsrv/libmlsvc/common/winreg_svc.c
index d24e174bc5..212c4933b2 100644
--- a/usr/src/lib/smbsrv/libmlsvc/common/winreg_svc.c
+++ b/usr/src/lib/smbsrv/libmlsvc/common/winreg_svc.c
@@ -64,6 +64,8 @@ static char *winreg_keys[] = {
"HKU",
"HKLM\\SOFTWARE",
"HKLM\\SYSTEM",
+ "Application",
+ "Security",
"System",
"CurrentControlSet",
"System\\CurrentControlSet\\Services\\Eventlog",
@@ -830,6 +832,7 @@ winreg_lookup_value(const char *name)
char *name;
char *value;
} registry[] = {
+ { "CurrentVersion", "4.0" },
{ "ProductType", "ServerNT" },
{ "Sources", NULL } /* product name */
};
diff --git a/usr/src/lib/smbsrv/libsmbrdr/common/libsmbrdr.h b/usr/src/lib/smbsrv/libsmbrdr/common/libsmbrdr.h
index 684b5c51c0..2ce1606254 100644
--- a/usr/src/lib/smbsrv/libsmbrdr/common/libsmbrdr.h
+++ b/usr/src/lib/smbsrv/libsmbrdr/common/libsmbrdr.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -54,14 +54,13 @@ extern unsigned char *smbrdr_ipc_get_passwd(void);
/* Redirector LOGON function */
extern int mlsvc_logon(char *, char *, char *);
-
-extern int smbrdr_readx(int, char *, int);
-
+extern int smbrdr_get_ssnkey(int, unsigned char *, size_t);
/* Redirector named pipe functions */
extern int smbrdr_open_pipe(char *, char *, char *, char *);
extern int smbrdr_close_pipe(int);
-
+extern int smbrdr_readx(int, char *, int);
+extern int smbrdr_transact(int, char *, int, char *, int);
/* Redirector session functions */
extern void smbrdr_init(void);
@@ -69,10 +68,6 @@ extern int smbrdr_session_info(int, smbrdr_session_info_t *);
extern int mlsvc_echo(char *);
extern void mlsvc_disconnect(char *);
-
-extern int smbrdr_transact(int, char *, int, char *, int);
-
-
/* DEBUG functions */
extern void smbrdr_dump_ofiles(void);
extern void smbrdr_dump_sessions(void);
diff --git a/usr/src/lib/smbsrv/libsmbrdr/common/mapfile-vers b/usr/src/lib/smbsrv/libsmbrdr/common/mapfile-vers
index ddf8ab2d8d..18922e7328 100644
--- a/usr/src/lib/smbsrv/libsmbrdr/common/mapfile-vers
+++ b/usr/src/lib/smbsrv/libsmbrdr/common/mapfile-vers
@@ -42,11 +42,11 @@ SUNWprivate {
mlsvc_disconnect;
mlsvc_echo;
mlsvc_logon;
- mlsvc_user_getauth;
smbrdr_close_pipe;
smbrdr_dump_netuse;
smbrdr_dump_ofiles;
smbrdr_dump_sessions;
+ smbrdr_get_ssnkey;
smbrdr_init;
smbrdr_ipc_commit;
smbrdr_ipc_get_user;
diff --git a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr.h b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr.h
index 9046cad16b..c4dfaa7a82 100644
--- a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr.h
+++ b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr.h
@@ -32,6 +32,7 @@
#include <synch.h>
#include <sys/types.h>
+#include <smbsrv/libsmb.h>
#include <smbsrv/libsmbrdr.h>
#include <smbsrv/cifs.h>
@@ -82,6 +83,7 @@ typedef struct sdb_logon {
unsigned int type;
unsigned short state;
smb_auth_info_t auth;
+ unsigned char ssn_key[SMBAUTH_SESSION_KEY_SZ];
} sdb_logon_t;
/*
diff --git a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_logon.c b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_logon.c
index c6612f71e1..5c9b73e9b1 100644
--- a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_logon.c
+++ b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_logon.c
@@ -98,24 +98,38 @@ smbrdr_anonymous_logon(char *domain_controller, char *domain_name)
return (0);
}
+/*
+ * Get the user session key from an already open named pipe.
+ * The RPC library needs this. See ndr_rpc_get_ssnkey()
+ *
+ * Returns zero (success) or an errno.
+ */
int
-mlsvc_user_getauth(char *domain_controller, char *username,
- smb_auth_info_t *auth)
+smbrdr_get_ssnkey(int fid, unsigned char *ssn_key, size_t key_len)
{
+ struct sdb_logon *logon;
struct sdb_session *session;
+ struct sdb_netuse *netuse;
+ struct sdb_ofile *ofile;
- if (auth) {
- bzero(auth, sizeof (smb_auth_info_t));
- session = smbrdr_session_lock(domain_controller, username,
- SDB_SLCK_READ);
- if (session) {
- *auth = session->logon.auth;
- smbrdr_session_unlock(session);
- return (0);
- }
- }
+ if (ssn_key == NULL || key_len < SMBAUTH_SESSION_KEY_SZ)
+ return (EINVAL);
- return (-1);
+ ofile = smbrdr_ofile_get(fid);
+ if (ofile == NULL)
+ return (EBADF);
+
+ netuse = ofile->netuse;
+ session = netuse->session;
+ logon = &session->logon;
+
+ if (key_len > SMBAUTH_SESSION_KEY_SZ)
+ bzero(ssn_key, key_len);
+ bcopy(logon->ssn_key, ssn_key,
+ SMBAUTH_SESSION_KEY_SZ);
+
+ smbrdr_ofile_put(ofile);
+ return (0);
}
/*
@@ -559,6 +573,12 @@ smbrdr_logon_init(struct sdb_session *session, char *username,
session->domain, session->challenge_key,
session->challenge_len, smbrdr_lmcompl, &logon->auth);
+ /* Generate (and save) the session key. */
+ if (rc == 0) {
+ rc = smb_auth_gen_session_key(&logon->auth,
+ logon->ssn_key);
+ }
+
if (rc != 0) {
free(logon);
return (0);
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 0f1faf78d4..a705ce383f 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -1168,8 +1168,7 @@ SMBSRV_OBJS += $(SMBSRV_SHARED_OBJS) \
smb_path_name_reduction.o \
smb_print.o \
smb_process_exit.o \
- smb_query_information.o \
- smb_query_information2.o \
+ smb_query_fileinfo.o \
smb_query_information_disk.o \
smb_read.o \
smb_rename.o \
@@ -1178,19 +1177,13 @@ SMBSRV_OBJS += $(SMBSRV_SHARED_OBJS) \
smb_server.o \
smb_session.o \
smb_session_setup_andx.o \
- smb_set_information.o \
- smb_set_information2.o \
+ smb_set_fileinfo.o \
smb_signing.o \
smb_tree.o \
smb_trans2_create_directory.o \
smb_trans2_dfs.o \
smb_trans2_find.o \
- smb_trans2_query_file_info.o \
smb_trans2_query_fs_information.o \
- smb_trans2_query_path_info.o \
- smb_trans2_set_file_information.o \
- smb_trans2_set_information.o \
- smb_trans2_set_path_information.o \
smb_tree_connect.o \
smb_unlock_byte_range.o \
smb_upcalls.o \
diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_open.c b/usr/src/uts/common/fs/smbsrv/smb_common_open.c
index 8525dcb4b7..74049d0c60 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_common_open.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_open.c
@@ -441,14 +441,11 @@ smb_open_subr(smb_request_t *sr)
if (rc == 0) {
last_comp_found = B_TRUE;
- (void) strcpy(op->fqi.fq_od_name,
- op->fqi.fq_fnode->od_name);
rc = smb_node_getattr(sr, op->fqi.fq_fnode,
&op->fqi.fq_fattr);
if (rc != 0) {
smb_node_release(op->fqi.fq_fnode);
smb_node_release(op->fqi.fq_dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
ERRDOS, ERROR_INTERNAL_ERROR);
return (sr->smb_error.status);
@@ -459,7 +456,6 @@ smb_open_subr(smb_request_t *sr)
rc = 0;
} else {
smb_node_release(op->fqi.fq_dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_errno(sr, rc);
return (sr->smb_error.status);
}
@@ -481,7 +477,6 @@ smb_open_subr(smb_request_t *sr)
smb_node_release(op->fqi.fq_fnode);
smb_node_release(op->fqi.fq_dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
ERRnoaccess);
return (NT_STATUS_ACCESS_DENIED);
@@ -501,7 +496,6 @@ smb_open_subr(smb_request_t *sr)
if (op->create_options & FILE_NON_DIRECTORY_FILE) {
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_error(sr, NT_STATUS_FILE_IS_A_DIRECTORY,
ERRDOS, ERROR_ACCESS_DENIED);
return (NT_STATUS_FILE_IS_A_DIRECTORY);
@@ -511,7 +505,6 @@ smb_open_subr(smb_request_t *sr)
(op->nt_flags & NT_CREATE_FLAG_OPEN_TARGET_DIR)) {
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
ERRDOS, ERROR_DIRECTORY);
return (NT_STATUS_NOT_A_DIRECTORY);
@@ -525,7 +518,6 @@ smb_open_subr(smb_request_t *sr)
if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_error(sr, NT_STATUS_DELETE_PENDING,
ERRDOS, ERROR_ACCESS_DENIED);
return (NT_STATUS_DELETE_PENDING);
@@ -537,7 +529,6 @@ smb_open_subr(smb_request_t *sr)
if (op->create_disposition == FILE_CREATE) {
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_error(sr, NT_STATUS_OBJECT_NAME_COLLISION,
ERRDOS, ERROR_FILE_EXISTS);
return (NT_STATUS_OBJECT_NAME_COLLISION);
@@ -557,7 +548,6 @@ smb_open_subr(smb_request_t *sr)
FILE_APPEND_DATA)) {
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
ERRDOS, ERRnoaccess);
return (NT_STATUS_ACCESS_DENIED);
@@ -582,7 +572,6 @@ smb_open_subr(smb_request_t *sr)
smb_node_unlock(node);
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
ERRDOS, ERRnoaccess);
return (NT_STATUS_ACCESS_DENIED);
@@ -596,7 +585,6 @@ smb_open_subr(smb_request_t *sr)
smb_node_unlock(node);
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
return (status);
}
@@ -609,7 +597,6 @@ smb_open_subr(smb_request_t *sr)
smb_node_unlock(node);
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
if (status == NT_STATUS_PRIVILEGE_NOT_HELD) {
smbsr_error(sr, status,
@@ -631,7 +618,6 @@ smb_open_subr(smb_request_t *sr)
smb_node_unlock(node);
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
ERRDOS, ERROR_ACCESS_DENIED);
return (NT_STATUS_ACCESS_DENIED);
@@ -654,7 +640,6 @@ smb_open_subr(smb_request_t *sr)
smb_node_unlock(node);
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_errno(sr, rc);
return (sr->smb_error.status);
}
@@ -671,7 +656,6 @@ smb_open_subr(smb_request_t *sr)
smb_node_unlock(node);
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
return (sr->smb_error.status);
}
}
@@ -696,7 +680,6 @@ smb_open_subr(smb_request_t *sr)
if ((op->create_disposition == FILE_OPEN) ||
(op->create_disposition == FILE_OVERWRITE)) {
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
ERRDOS, ERROR_FILE_NOT_FOUND);
return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
@@ -705,7 +688,6 @@ smb_open_subr(smb_request_t *sr)
if ((is_dir == 0) && (!is_stream) &&
smb_is_invalid_filename(op->fqi.fq_last_comp)) {
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
ERRDOS, ERROR_INVALID_NAME);
return (NT_STATUS_OBJECT_NAME_INVALID);
@@ -752,7 +734,6 @@ smb_open_subr(smb_request_t *sr)
if (rc != 0) {
smb_node_unlock(dnode);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_errno(sr, rc);
return (sr->smb_error.status);
}
@@ -769,7 +750,6 @@ smb_open_subr(smb_request_t *sr)
smb_node_release(node);
smb_node_unlock(dnode);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
return (status);
}
} else {
@@ -785,7 +765,6 @@ smb_open_subr(smb_request_t *sr)
if (rc != 0) {
smb_node_unlock(dnode);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
smbsr_errno(sr, rc);
return (sr->smb_error.status);
}
@@ -796,7 +775,6 @@ smb_open_subr(smb_request_t *sr)
created = B_TRUE;
op->action_taken = SMB_OACT_CREATED;
- node->flags |= NODE_FLAGS_CREATED;
}
if (max_requested) {
@@ -857,7 +835,6 @@ smb_open_subr(smb_request_t *sr)
if (created)
smb_node_unlock(dnode);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
return (status);
}
@@ -896,7 +873,6 @@ smb_open_subr(smb_request_t *sr)
smb_node_release(node);
smb_node_release(dnode);
- SMB_NULL_FQI_NODES(op->fqi);
return (NT_STATUS_SUCCESS);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_create.c b/usr/src/uts/common/fs/smbsrv/smb_create.c
index fe01c89490..ddc8408248 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_create.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_create.c
@@ -185,7 +185,7 @@ smb_common_create(smb_request_t *sr)
uint32_t status;
if ((op->mtime.tv_sec != 0) && (op->mtime.tv_sec != UINT_MAX))
- op->mtime.tv_sec = smb_local2gmt(sr, op->mtime.tv_sec);
+ op->mtime.tv_sec = smb_time_local_to_gmt(sr, op->mtime.tv_sec);
op->mtime.tv_nsec = 0;
op->dsize = 0;
op->omode = SMB_DA_ACCESS_READ_WRITE | SMB_DA_SHARE_COMPATIBILITY;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_delete.c b/usr/src/uts/common/fs/smbsrv/smb_delete.c
index c486ae9f30..7c1481bfae 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_delete.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_delete.c
@@ -31,7 +31,7 @@
static int smb_delete_check_path(smb_request_t *, boolean_t *);
static int smb_delete_single_file(smb_request_t *, smb_error_t *);
static int smb_delete_multiple_files(smb_request_t *, smb_error_t *);
-static int smb_delete_find_fname(smb_request_t *, smb_odir_t *);
+static int smb_delete_find_fname(smb_request_t *, smb_odir_t *, char *, int);
static int smb_delete_check_dosattr(smb_request_t *, smb_error_t *);
static int smb_delete_remove_file(smb_request_t *, smb_error_t *);
@@ -276,6 +276,7 @@ smb_delete_multiple_files(smb_request_t *sr, smb_error_t *err)
smb_fqi_t *fqi;
uint16_t odid;
smb_odir_t *od;
+ char namebuf[MAXNAMELEN];
fqi = &sr->arg.dirop.fqi;
@@ -292,13 +293,13 @@ smb_delete_multiple_files(smb_request_t *sr, smb_error_t *err)
return (-1);
for (;;) {
- rc = smb_delete_find_fname(sr, od);
+ rc = smb_delete_find_fname(sr, od, namebuf, MAXNAMELEN);
if (rc != 0)
break;
rc = smb_fsop_lookup_name(sr, sr->user_cr, 0,
sr->tid_tree->t_snode, fqi->fq_dnode,
- fqi->fq_od_name, &fqi->fq_fnode);
+ namebuf, &fqi->fq_fnode);
if (rc != 0)
break;
@@ -351,8 +352,8 @@ smb_delete_multiple_files(smb_request_t *sr, smb_error_t *err)
/*
* smb_delete_find_fname
*
- * Find next filename that matches search pattern (fqi->fq_last_comp)
- * and save it in fqi->fq_od_name.
+ * Find next filename that matches search pattern and return it
+ * in namebuf.
*
* Case insensitivity note:
* If the tree is case insensitive and there's a case conflict
@@ -365,7 +366,7 @@ smb_delete_multiple_files(smb_request_t *sr, smb_error_t *err)
* errno
*/
static int
-smb_delete_find_fname(smb_request_t *sr, smb_odir_t *od)
+smb_delete_find_fname(smb_request_t *sr, smb_odir_t *od, char *namebuf, int len)
{
int rc;
smb_odirent_t *odirent;
@@ -373,9 +374,7 @@ smb_delete_find_fname(smb_request_t *sr, smb_odir_t *od)
char *name;
char shortname[SMB_SHORTNAMELEN];
char name83[SMB_SHORTNAMELEN];
- smb_fqi_t *fqi;
- fqi = &sr->arg.dirop.fqi;
odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP);
rc = smb_odir_read(sr, od, odirent, &eos);
@@ -397,7 +396,7 @@ smb_delete_find_fname(smb_request_t *sr, smb_odir_t *od)
} else {
name = odirent->od_name;
}
- (void) strlcpy(fqi->fq_od_name, name, sizeof (fqi->fq_od_name));
+ (void) strlcpy(namebuf, name, len);
kmem_free(odirent, sizeof (smb_odirent_t));
return (0);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_directory.c b/usr/src/uts/common/fs/smbsrv/smb_directory.c
index c59d8cce2e..60d95d0198 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_directory.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_directory.c
@@ -91,9 +91,9 @@ smb_sdrc_t
smb_com_create_directory(smb_request_t *sr)
{
smb_dirpath_t *spp;
- smb_attr_t *attr;
DWORD status;
int rc = 0;
+ char *path = sr->arg.dirop.fqi.fq_path.pn_path;
if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
@@ -101,13 +101,13 @@ smb_com_create_directory(smb_request_t *sr)
return (SDRC_ERROR);
}
- if (!smb_dirpath_isvalid(sr->arg.dirop.fqi.fq_path.pn_path)) {
+ if (!smb_dirpath_isvalid(path)) {
smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
ERRDOS, ERROR_BAD_PATHNAME);
return (SDRC_ERROR);
}
- status = smb_validate_dirname(sr->arg.dirop.fqi.fq_path.pn_path);
+ status = smb_validate_dirname(path);
if (status != 0) {
smbsr_error(sr, status, ERRDOS, ERROR_INVALID_NAME);
return (SDRC_ERROR);
@@ -126,20 +126,17 @@ smb_com_create_directory(smb_request_t *sr)
case 0:
break;
case EEXIST:
- attr = &sr->arg.dirop.fqi.fq_fattr;
-
- if (attr->sa_vattr.va_type != VDIR) {
- smbsr_error(sr, NT_STATUS_OBJECT_NAME_COLLISION,
- ERRDOS, ERROR_PATH_NOT_FOUND);
- return (SDRC_ERROR);
- }
break;
case ENOENT:
smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
ERRDOS, ERROR_FILE_NOT_FOUND);
return (SDRC_ERROR);
case ENOTDIR:
- smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
+ /*
+ * Spec says status should be OBJECT_PATH_INVALID
+ * but testing shows OBJECT_PATH_NOT_FOUND
+ */
+ smbsr_error(sr, NT_STATUS_OBJECT_PATH_NOT_FOUND,
ERRDOS, ERROR_PATH_NOT_FOUND);
return (SDRC_ERROR);
default:
@@ -149,7 +146,11 @@ smb_com_create_directory(smb_request_t *sr)
}
if (rc != 0) {
- smbsr_errno(sr, rc);
+ if (rc == EEXIST)
+ smbsr_error(sr, NT_STATUS_OBJECT_NAME_COLLISION,
+ ERRDOS, ERROR_FILE_EXISTS);
+ else
+ smbsr_errno(sr, rc);
return (SDRC_ERROR);
}
@@ -195,25 +196,36 @@ smb_common_create_directory(smb_request_t *sr)
{
int rc;
smb_attr_t new_attr;
- smb_node_t *dnode;
- smb_node_t *node;
+ smb_fqi_t *fqi;
+ smb_node_t *tnode;
- sr->arg.dirop.fqi.fq_sattr = 0;
+ fqi = &sr->arg.dirop.fqi;
+ tnode = sr->tid_tree->t_snode;
- rc = smbd_fs_query(sr, &sr->arg.dirop.fqi, FQM_PATH_MUST_NOT_EXIST);
- if (rc)
+ rc = smb_pathname_reduce(sr, sr->user_cr, fqi->fq_path.pn_path,
+ tnode, tnode, &fqi->fq_dnode, fqi->fq_last_comp);
+ if (rc != 0)
return (rc);
- /*
- * Because of FQM_PATH_MUST_NOT_EXIST and the successful return
- * value, only fqi.fq_dnode has a valid parameter (fqi.fq_fnode
- * is NULL).
- */
- dnode = sr->arg.dirop.fqi.fq_dnode;
+ /* lookup node - to ensure that it does NOT exist */
+ rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode);
+ if (rc == 0) {
+ smb_node_release(fqi->fq_dnode);
+ smb_node_release(fqi->fq_fnode);
+ return (EEXIST);
+ }
+ if (rc != ENOENT) {
+ smb_node_release(fqi->fq_dnode);
+ return (rc);
+ }
- rc = smb_fsop_access(sr, sr->user_cr, dnode, FILE_ADD_SUBDIRECTORY);
- if (rc != NT_STATUS_SUCCESS)
+ rc = smb_fsop_access(sr, sr->user_cr, fqi->fq_dnode,
+ FILE_ADD_SUBDIRECTORY);
+ if (rc != NT_STATUS_SUCCESS) {
+ smb_node_release(fqi->fq_dnode);
return (EACCES);
+ }
/*
* Explicitly set sa_dosattr, otherwise the file system may
@@ -226,28 +238,17 @@ smb_common_create_directory(smb_request_t *sr)
new_attr.sa_vattr.va_mode = 0777;
new_attr.sa_mask = SMB_AT_TYPE | SMB_AT_MODE | SMB_AT_DOSATTR;
- if ((rc = smb_fsop_mkdir(sr, sr->user_cr, dnode,
- sr->arg.dirop.fqi.fq_last_comp, &new_attr,
- &sr->arg.dirop.fqi.fq_fnode)) != 0) {
- smb_node_release(dnode);
- SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
- return (rc);
- }
-
- node = sr->arg.dirop.fqi.fq_fnode;
- rc = smb_node_getattr(sr, node, &sr->arg.dirop.fqi.fq_fattr);
+ rc = smb_fsop_mkdir(sr, sr->user_cr, fqi->fq_dnode, fqi->fq_last_comp,
+ &new_attr, &fqi->fq_fnode);
if (rc != 0) {
- smb_node_release(dnode);
- SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+ smb_node_release(fqi->fq_dnode);
return (rc);
}
- node->flags |= NODE_FLAGS_CREATED;
sr->arg.open.create_options = FILE_DIRECTORY_FILE;
- smb_node_release(node);
- smb_node_release(dnode);
- SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+ smb_node_release(fqi->fq_dnode);
+ smb_node_release(fqi->fq_fnode);
return (0);
}
@@ -364,10 +365,10 @@ smb_post_delete_directory(smb_request_t *sr)
smb_sdrc_t
smb_com_delete_directory(smb_request_t *sr)
{
- smb_node_t *dnode;
- smb_attr_t *attr;
int rc;
uint32_t flags = 0;
+ smb_fqi_t *fqi;
+ smb_node_t *tnode;
if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
@@ -375,50 +376,64 @@ smb_com_delete_directory(smb_request_t *sr)
return (SDRC_ERROR);
}
- sr->arg.dirop.fqi.fq_sattr = 0;
+ fqi = &sr->arg.dirop.fqi;
+ tnode = sr->tid_tree->t_snode;
- rc = smbd_fs_query(sr, &sr->arg.dirop.fqi, FQM_PATH_MUST_EXIST);
- if (rc) {
+ rc = smb_pathname_reduce(sr, sr->user_cr, fqi->fq_path.pn_path,
+ tnode, tnode, &fqi->fq_dnode, fqi->fq_last_comp);
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ return (SDRC_ERROR);
+ }
+
+ rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode);
+ if (rc != 0) {
if (rc == ENOENT)
smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
ERRDOS, ERROR_FILE_NOT_FOUND);
else
smbsr_errno(sr, rc);
+ smb_node_release(fqi->fq_dnode);
return (SDRC_ERROR);
}
- attr = &sr->arg.dirop.fqi.fq_fattr;
- if (attr->sa_vattr.va_type != VDIR) {
+ rc = smb_node_getattr(sr, fqi->fq_fnode, &fqi->fq_fattr);
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ smb_node_release(fqi->fq_dnode);
+ smb_node_release(fqi->fq_fnode);
+ return (SDRC_ERROR);
+ }
+
+ if (fqi->fq_fattr.sa_vattr.va_type != VDIR) {
smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
ERRDOS, ERROR_PATH_NOT_FOUND);
+ smb_node_release(fqi->fq_dnode);
+ smb_node_release(fqi->fq_fnode);
return (SDRC_ERROR);
}
- dnode = sr->arg.dirop.fqi.fq_fnode;
- rc = smb_fsop_access(sr, sr->user_cr, dnode, DELETE);
-
- if ((rc != NT_STATUS_SUCCESS) ||
- attr->sa_dosattr & FILE_ATTRIBUTE_READONLY) {
- smb_node_release(dnode);
- smb_node_release(sr->arg.dirop.fqi.fq_dnode);
- SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+ if ((fqi->fq_fattr.sa_dosattr & FILE_ATTRIBUTE_READONLY) ||
+ (smb_fsop_access(sr, sr->user_cr, fqi->fq_fnode, DELETE)
+ != NT_STATUS_SUCCESS)) {
smbsr_error(sr, NT_STATUS_CANNOT_DELETE,
ERRDOS, ERROR_ACCESS_DENIED);
+ smb_node_release(fqi->fq_dnode);
+ smb_node_release(fqi->fq_fnode);
return (SDRC_ERROR);
}
- smb_node_release(dnode);
-
- dnode = sr->arg.dirop.fqi.fq_dnode;
-
if (SMB_TREE_SUPPORTS_CATIA(sr))
flags |= SMB_CATIA;
- rc = smb_fsop_rmdir(sr, sr->user_cr, dnode,
- sr->arg.dirop.fqi.fq_od_name, flags);
+ rc = smb_fsop_rmdir(sr, sr->user_cr, fqi->fq_dnode,
+ fqi->fq_fnode->od_name, flags);
+
+ smb_node_release(fqi->fq_fnode);
+ smb_node_release(fqi->fq_dnode);
+
if (rc != 0) {
- smb_node_release(dnode);
- SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
if (rc == EEXIST)
smbsr_error(sr, NT_STATUS_DIRECTORY_NOT_EMPTY,
ERRDOS, ERROR_DIR_NOT_EMPTY);
@@ -427,9 +442,6 @@ smb_com_delete_directory(smb_request_t *sr)
return (SDRC_ERROR);
}
- smb_node_release(dnode);
- SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
-
rc = smbsr_encode_empty_result(sr);
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
@@ -483,8 +495,10 @@ smb_post_check_directory(smb_request_t *sr)
smb_sdrc_t
smb_com_check_directory(smb_request_t *sr)
{
- smb_node_t *dnode;
int rc;
+ smb_fqi_t *fqi;
+ smb_node_t *tnode;
+ char *path;
if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
@@ -492,21 +506,33 @@ smb_com_check_directory(smb_request_t *sr)
return (SDRC_ERROR);
}
- if (sr->arg.dirop.fqi.fq_path.pn_path[0] == '\0') {
+ fqi = &sr->arg.dirop.fqi;
+ path = fqi->fq_path.pn_path;
+
+ if (path[0] == '\0') {
rc = smbsr_encode_empty_result(sr);
return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
}
- if (!smb_dirpath_isvalid(sr->arg.dirop.fqi.fq_path.pn_path)) {
+ if (!smb_dirpath_isvalid(path)) {
smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
ERRDOS, ERROR_PATH_NOT_FOUND);
return (SDRC_ERROR);
}
- sr->arg.dirop.fqi.fq_sattr = 0;
+ tnode = sr->tid_tree->t_snode;
- rc = smbd_fs_query(sr, &sr->arg.dirop.fqi, FQM_PATH_MUST_EXIST);
- if (rc) {
+ rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
+ &fqi->fq_dnode, fqi->fq_last_comp);
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ return (SDRC_ERROR);
+ }
+
+ rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ tnode, fqi->fq_dnode, fqi->fq_last_comp, &fqi->fq_fnode);
+ smb_node_release(fqi->fq_dnode);
+ if (rc != 0) {
if (rc == ENOENT)
smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
ERRDOS, ERROR_PATH_NOT_FOUND);
@@ -515,22 +541,23 @@ smb_com_check_directory(smb_request_t *sr)
return (SDRC_ERROR);
}
- smb_node_release(sr->arg.dirop.fqi.fq_dnode);
-
- dnode = sr->arg.dirop.fqi.fq_fnode;
+ rc = smb_node_getattr(sr, fqi->fq_fnode, &fqi->fq_fattr);
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ smb_node_release(fqi->fq_fnode);
+ return (SDRC_ERROR);
+ }
- if (sr->arg.dirop.fqi.fq_fattr.sa_vattr.va_type != VDIR) {
- smb_node_release(dnode);
- SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+ if (fqi->fq_fattr.sa_vattr.va_type != VDIR) {
smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
ERRDOS, ERROR_PATH_NOT_FOUND);
+ smb_node_release(fqi->fq_fnode);
return (SDRC_ERROR);
}
- rc = smb_fsop_access(sr, sr->user_cr, dnode, FILE_TRAVERSE);
+ rc = smb_fsop_access(sr, sr->user_cr, fqi->fq_fnode, FILE_TRAVERSE);
- smb_node_release(dnode);
- SMB_NULL_FQI_NODES(sr->arg.dirop.fqi);
+ smb_node_release(fqi->fq_fnode);
if (rc != 0) {
smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
diff --git a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c
index d4e7747c83..75b42e37bb 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c
@@ -1158,7 +1158,7 @@ smbsr_lookup_xa(smb_request_t *sr)
}
void
-smbsr_disconnect_file(smb_request_t *sr)
+smbsr_release_file(smb_request_t *sr)
{
smb_ofile_t *of = sr->fid_ofile;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_find.c b/usr/src/uts/common/fs/smbsrv/smb_find.c
index 99ec45c8e4..ec55d1e6ba 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_find.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_find.c
@@ -340,7 +340,7 @@ smb_com_search(smb_request_t *sr)
fileinfo.fi_name83, fileinfo.fi_name83+9,
index, odid, client_key,
fileinfo.fi_dosattr & 0xff,
- smb_gmt2local(sr, fileinfo.fi_mtime.tv_sec),
+ smb_time_gmt_to_local(sr, fileinfo.fi_mtime.tv_sec),
(int32_t)fileinfo.fi_size,
name);
@@ -476,7 +476,7 @@ smb_com_find(smb_request_t *sr)
fileinfo.fi_name83, fileinfo.fi_name83+9,
index, odid, client_key,
fileinfo.fi_dosattr & 0xff,
- smb_gmt2local(sr, fileinfo.fi_mtime.tv_sec),
+ smb_time_gmt_to_local(sr, fileinfo.fi_mtime.tv_sec),
(int32_t)fileinfo.fi_size,
name);
@@ -654,7 +654,7 @@ smb_com_find_unique(struct smb_request *sr)
fileinfo.fi_name83, fileinfo.fi_name83+9,
index, odid, client_key,
fileinfo.fi_dosattr & 0xff,
- smb_gmt2local(sr, fileinfo.fi_mtime.tv_sec),
+ smb_time_gmt_to_local(sr, fileinfo.fi_mtime.tv_sec),
(int32_t)fileinfo.fi_size,
name);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_fsops.c b/usr/src/uts/common/fs/smbsrv/smb_fsops.c
index 358fc93c3a..c427df5632 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_fsops.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_fsops.c
@@ -340,6 +340,8 @@ smb_fsop_create(smb_request_t *sr, cred_t *cr, smb_node_t *dnode,
flags = SMB_IGNORE_CASE;
if (SMB_TREE_SUPPORTS_CATIA(sr))
flags |= SMB_CATIA;
+ if (SMB_TREE_SUPPORTS_ABE(sr))
+ flags |= SMB_ABE;
if (smb_is_stream_name(name)) {
fname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
@@ -358,7 +360,8 @@ smb_fsop_create(smb_request_t *sr, cred_t *cr, smb_node_t *dnode,
if (smb_maybe_mangled_name(name)) {
longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
- rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN);
+ rc = smb_unmangle_name(dnode, name, longname,
+ MAXNAMELEN, flags);
kmem_free(longname, MAXNAMELEN);
if (rc == 0)
@@ -575,10 +578,13 @@ smb_fsop_mkdir(
return (EROFS);
if (SMB_TREE_SUPPORTS_CATIA(sr))
flags |= SMB_CATIA;
+ if (SMB_TREE_SUPPORTS_ABE(sr))
+ flags |= SMB_ABE;
if (smb_maybe_mangled_name(name)) {
longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
- rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN);
+ rc = smb_unmangle_name(dnode, name, longname,
+ MAXNAMELEN, flags);
kmem_free(longname, MAXNAMELEN);
/*
@@ -733,8 +739,11 @@ smb_fsop_remove(
}
longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ if (SMB_TREE_SUPPORTS_ABE(sr))
+ flags |= SMB_ABE;
+
rc = smb_unmangle_name(dnode, name,
- longname, MAXNAMELEN);
+ longname, MAXNAMELEN, flags);
if (rc == 0) {
/*
@@ -866,7 +875,11 @@ smb_fsop_rmdir(
return (rc);
longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
- rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN);
+
+ if (SMB_TREE_SUPPORTS_ABE(sr))
+ flags |= SMB_ABE;
+ rc = smb_unmangle_name(dnode, name, longname,
+ MAXNAMELEN, flags);
if (rc == 0) {
/*
@@ -989,10 +1002,13 @@ smb_fsop_link(smb_request_t *sr, cred_t *cr, smb_node_t *to_dnode,
flags = SMB_IGNORE_CASE;
if (SMB_TREE_SUPPORTS_CATIA(sr))
flags |= SMB_CATIA;
+ if (SMB_TREE_SUPPORTS_ABE(sr))
+ flags |= SMB_ABE;
if (smb_maybe_mangled_name(to_name)) {
longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
- rc = smb_unmangle_name(to_dnode, to_name, longname, MAXNAMELEN);
+ rc = smb_unmangle_name(to_dnode, to_name,
+ longname, MAXNAMELEN, flags);
kmem_free(longname, MAXNAMELEN);
if (rc == 0)
@@ -1116,7 +1132,8 @@ smb_fsop_rename(
* Please document any direct call to explain the reason
* for avoiding this wrapper.
*
- * It is assumed that a reference exists on snode coming into this routine.
+ * It is assumed that a reference exists on snode coming into
+ * this function.
* A null smb_request might be passed to this function.
*/
int
@@ -1149,6 +1166,11 @@ smb_fsop_setattr(
ACE_WRITE_ATTRIBUTES | ACE_WRITE_NAMED_ATTRS) == 0)
return (EACCES);
+ /*
+ * The file system cannot detect pending READDONLY
+ * (i.e. if the file has been opened readonly but
+ * not yet closed) so we need to test READONLY here.
+ */
if (sr && (set_attr->sa_mask & SMB_AT_SIZE)) {
if (sr->fid_ofile) {
if (SMB_OFILE_IS_READONLY(sr->fid_ofile))
@@ -1159,14 +1181,29 @@ smb_fsop_setattr(
}
}
- /* sr could be NULL in some cases */
+ /*
+ * SMB checks access on open and retains an access granted
+ * mask for use while the file is open. ACL changes should
+ * not affect access to an open file.
+ *
+ * If the setattr is being performed on an ofile:
+ * - Check the ofile's access granted mask to see if the
+ * setattr is permitted.
+ * UID, GID - require WRITE_OWNER
+ * SIZE, ALLOCSZ - require FILE_WRITE_DATA
+ * all other attributes require FILE_WRITE_ATTRIBUTES
+ *
+ * - If the file system does access checking, set the
+ * ATTR_NOACLCHECK flag to ensure that the file system
+ * does not check permissions on subsequent calls.
+ */
if (sr && sr->fid_ofile) {
sa_mask = set_attr->sa_mask;
access = 0;
- if (sa_mask & SMB_AT_SIZE) {
+ if (sa_mask & (SMB_AT_SIZE | SMB_AT_ALLOCSZ)) {
access |= FILE_WRITE_DATA;
- sa_mask &= ~SMB_AT_SIZE;
+ sa_mask &= ~(SMB_AT_SIZE | SMB_AT_ALLOCSZ);
}
if (sa_mask & (SMB_AT_UID|SMB_AT_GID)) {
@@ -1645,6 +1682,8 @@ smb_fsop_lookup(
flags |= SMB_IGNORE_CASE;
if (SMB_TREE_SUPPORTS_CATIA(sr))
flags |= SMB_CATIA;
+ if (SMB_TREE_SUPPORTS_ABE(sr))
+ flags |= SMB_ABE;
od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
@@ -1658,7 +1697,8 @@ smb_fsop_lookup(
}
longname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
- rc = smb_unmangle_name(dnode, name, longname, MAXNAMELEN);
+ rc = smb_unmangle_name(dnode, name, longname,
+ MAXNAMELEN, flags);
if (rc != 0) {
kmem_free(od_name, MAXNAMELEN);
kmem_free(longname, MAXNAMELEN);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c b/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c
index e8b17c6d96..2d73bb38ac 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c
@@ -664,7 +664,8 @@ int smb_mangle_name(
*/
#define SMB_UNMANGLE_BUFSIZE (4 * 1024)
int
-smb_unmangle_name(smb_node_t *dnode, char *name, char *namebuf, int buflen)
+smb_unmangle_name(smb_node_t *dnode, char *name, char *namebuf,
+ int buflen, uint32_t flags)
{
int err, eof, bufsize, reclen;
uint64_t offset;
@@ -700,7 +701,7 @@ smb_unmangle_name(smb_node_t *dnode, char *name, char *namebuf, int buflen)
offset = 0;
while ((err = smb_vop_readdir(vp, offset, buf, &bufsize,
- &eof, kcred)) == 0) {
+ &eof, flags, kcred)) == 0) {
if (bufsize == 0) {
err = ENOENT;
break;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c b/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c
index 7e0ee57629..3eb054e383 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c
@@ -29,6 +29,9 @@
#include <smbsrv/smb_incl.h>
+#include <sys/sunddi.h>
+
+
#define MALLOC_QUANTUM 80
#define DECODE_NO_ERROR 0
@@ -36,6 +39,7 @@
#define DECODE_ALLOCATION_ERROR 2
#define DECODE_CONVERSION_ERROR 3
+static int mbc_marshal_cstou8(char *, char *, size_t, char *, size_t);
static int mbc_marshal_make_room(mbuf_chain_t *, int32_t);
static void mbc_marshal_store_byte(mbuf_chain_t *, uint8_t);
static int mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t);
@@ -323,7 +327,7 @@ unicode_translation:
if (mbc_marshal_get_short(mbc,
(uint16_t *)&d) != 0)
return (-1);
- *lvalp++ = smb_dos_to_ux_time(d, t);
+ *lvalp++ = smb_time_dos_to_unix(d, t);
}
break;
@@ -338,7 +342,7 @@ unicode_translation:
if (mbc_marshal_get_short(mbc,
(uint16_t *)&t) != 0)
return (-1);
- *lvalp++ = smb_dos_to_ux_time(d, t);
+ *lvalp++ = smb_time_dos_to_unix(d, t);
}
break;
@@ -554,7 +558,7 @@ smb_mbc_vencodef(mbuf_chain_t *mbc, char *fmt, va_list ap)
case 'T':
tvp = va_arg(ap, timestruc_t *);
- nt_time = unix_to_nt_time(tvp);
+ nt_time = smb_time_unix_to_nt(tvp);
if (mbc_marshal_put_long_long(mbc, nt_time) != 0)
return (DECODE_NO_MORE_DATA);
break;
@@ -653,7 +657,7 @@ ascii_conversion: cvalp = va_arg(ap, uint8_t *);
uint16_t d, t;
lval = va_arg(ap, uint32_t);
- (void) smb_ux_to_dos_time(lval,
+ smb_time_unix_to_dos(lval,
(short *)&d, (short *)&t);
if (mbc_marshal_put_short(mbc, t) != 0)
return (DECODE_NO_MORE_DATA);
@@ -667,7 +671,7 @@ ascii_conversion: cvalp = va_arg(ap, uint8_t *);
uint16_t d, t;
lval = va_arg(ap, uint32_t);
- (void) smb_ux_to_dos_time(lval,
+ smb_time_unix_to_dos(lval,
(short *)&d, (short *)&t);
if (mbc_marshal_put_short(mbc, d) != 0)
return (DECODE_NO_MORE_DATA);
@@ -1218,10 +1222,8 @@ mbc_marshal_get_ascii_string(
{
char *rcvbuf;
char *ch;
- mts_wchar_t *wtmpbuf;
int max;
int length = 0;
- uint_t cpid = oem_get_smb_cpid();
max = MALLOC_QUANTUM;
rcvbuf = smbsr_malloc(ml, max);
@@ -1254,15 +1256,9 @@ multibyte_encode:
* UTF-8 encode the string for internal system use.
*/
length = strlen(rcvbuf) + 1;
- wtmpbuf = smbsr_malloc(ml, length*sizeof (mts_wchar_t));
*ascii = smbsr_malloc(ml, length * MTS_MB_CHAR_MAX);
-
- if (oemstounicodes(wtmpbuf, rcvbuf, length, cpid) > 0)
- (void) mts_wcstombs((char *)*ascii, wtmpbuf,
- length * MTS_MB_CHAR_MAX);
- else
- (void) mts_stombs((char *)*ascii, rcvbuf, length * 2);
- return (0);
+ return (mbc_marshal_cstou8("CP850", (char *)*ascii,
+ (size_t)length * MTS_MB_CHAR_MAX, rcvbuf, (size_t)length));
}
static int
@@ -1403,3 +1399,29 @@ mbc_marshal_get_skip(mbuf_chain_t *mbc, uint_t skip)
mbc->chain_offset += skip;
return (0);
}
+
+/*
+ * Converts oem string to UTF-8 string with an output string of max
+ * maxconv bytes. The string may be truncated or not null-terminated if
+ * there is not enough room.
+ *
+ * returns -1, cnt (partial conversion) or 0 (success)
+ */
+
+static int
+mbc_marshal_cstou8(char *cs, char *outbuf, size_t maxconv,
+ char *inbuf, size_t srcbytes)
+{
+ kiconv_t t2u;
+ size_t inlen = srcbytes;
+ size_t outlen = maxconv;
+ int err = 0;
+ size_t rc;
+
+ if ((t2u = kiconv_open("UTF-8", cs)) == (kiconv_t)-1)
+ return (-1);
+
+ rc = kiconv(t2u, &inbuf, &inlen, &outbuf, &outlen, &err);
+ (void) kiconv_close(t2u);
+ return ((int)rc);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_node.c b/usr/src/uts/common/fs/smbsrv/smb_node.c
index 3b0da29344..4df9749094 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_node.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_node.c
@@ -145,16 +145,28 @@ static void smb_node_free(smb_node_t *);
static int smb_node_constructor(void *, void *, int);
static void smb_node_destructor(void *, void *);
static smb_llist_t *smb_node_get_hash(fsid_t *, smb_attr_t *, uint32_t *);
-static void smb_node_init_cached_timestamps(smb_node_t *);
+
+static void smb_node_init_cached_data(smb_node_t *);
+static void smb_node_clear_cached_data(smb_node_t *);
+
+static void smb_node_init_cached_timestamps(smb_node_t *, smb_attr_t *);
static void smb_node_clear_cached_timestamps(smb_node_t *);
static void smb_node_get_cached_timestamps(smb_node_t *, smb_attr_t *);
static void smb_node_set_cached_timestamps(smb_node_t *, smb_attr_t *);
+static void smb_node_init_cached_allocsz(smb_node_t *, smb_attr_t *);
+static void smb_node_clear_cached_allocsz(smb_node_t *);
+static void smb_node_get_cached_allocsz(smb_node_t *, smb_attr_t *);
+static void smb_node_set_cached_allocsz(smb_node_t *, smb_attr_t *);
+
#define VALIDATE_DIR_NODE(_dir_, _node_) \
ASSERT((_dir_)->n_magic == SMB_NODE_MAGIC); \
ASSERT(((_dir_)->vp->v_xattrdir) || ((_dir_)->vp->v_type == VDIR)); \
ASSERT((_dir_)->n_dnode != (_node_));
+/* round sz to DEV_BSIZE block */
+#define SMB_ALLOCSZ(sz) (((sz) + DEV_BSIZE-1) & ~(DEV_BSIZE-1))
+
static kmem_cache_t *smb_node_cache = NULL;
static boolean_t smb_node_initialized = B_FALSE;
static smb_llist_t smb_node_hash_table[SMBND_HASH_MASK+1];
@@ -898,7 +910,7 @@ smb_node_inc_open_ofiles(smb_node_t *node)
node->n_open_count++;
mutex_exit(&node->n_mutex);
- smb_node_init_cached_timestamps(node);
+ smb_node_init_cached_data(node);
}
/*
@@ -913,7 +925,7 @@ smb_node_dec_open_ofiles(smb_node_t *node)
node->n_open_count--;
mutex_exit(&node->n_mutex);
- smb_node_clear_cached_timestamps(node);
+ smb_node_clear_cached_data(node);
}
uint32_t
@@ -1135,6 +1147,7 @@ smb_node_file_is_readonly(smb_node_t *node)
* The ofile may be NULL, for example when a client request
* specifies the file by pathname.
*
+ * Timestamps
* When attributes are set on an ofile, any pending timestamps
* from a write request on the ofile are implicitly set to "now".
* For compatibility with windows the following timestamps are
@@ -1142,13 +1155,21 @@ smb_node_file_is_readonly(smb_node_t *node)
* - if any attribute is being explicitly set, set ctime to now
* - if file size is being explicitly set, set atime & ctime to now
*
- * Any attribute that is being explicitly set, or has previously
+ * Any timestamp that is being explicitly set, or has previously
* been explicitly set on the ofile, is excluded from implicit
* (now) setting.
*
* Updates the node's cached timestamp values.
* Updates the ofile's explicit times flag.
*
+ * File allocation size
+ * When the file allocation size is set it is first rounded up
+ * to block size. If the file size is smaller than the allocation
+ * size the file is truncated by setting the filesize to allocsz.
+ * If there are open ofiles, the allocsz is cached on the node.
+ *
+ * Updates the node's cached allocsz value.
+ *
* Returns: errno
*/
int
@@ -1156,56 +1177,77 @@ smb_node_setattr(smb_request_t *sr, smb_node_t *node,
cred_t *cr, smb_ofile_t *of, smb_attr_t *attr)
{
int rc;
- uint32_t what;
- uint32_t now_times = 0;
+ uint32_t pending_times = 0;
+ uint32_t explicit_times = 0;
timestruc_t now;
+ smb_attr_t tmp_attr;
ASSERT(attr);
SMB_NODE_VALID(node);
- what = attr->sa_mask;
+ /* set attributes specified in attr */
+ if (attr->sa_mask != 0) {
+ /* if allocation size is < file size, truncate the file */
+ if (attr->sa_mask & SMB_AT_ALLOCSZ) {
+ attr->sa_allocsz = SMB_ALLOCSZ(attr->sa_allocsz);
- /* determine which timestamps to implicitly set to "now" */
- if (what)
- now_times |= SMB_AT_CTIME;
- if (what & SMB_AT_SIZE)
- now_times |= (SMB_AT_MTIME | SMB_AT_CTIME);
- if (of) {
- if (smb_ofile_write_time_pending(of))
- now_times |=
- (SMB_AT_MTIME | SMB_AT_CTIME | SMB_AT_ATIME);
- now_times &= ~(smb_ofile_explicit_times(of));
- }
- now_times &= ~what;
+ bzero(&tmp_attr, sizeof (smb_attr_t));
+ tmp_attr.sa_mask = SMB_AT_SIZE;
+ (void) smb_fsop_getattr(NULL, kcred, node, &tmp_attr);
- if (now_times) {
- gethrestime(&now);
-
- if (now_times & SMB_AT_ATIME) {
- attr->sa_vattr.va_atime = now;
- attr->sa_mask |= SMB_AT_ATIME;
- }
- if (now_times & SMB_AT_MTIME) {
- attr->sa_vattr.va_mtime = now;
- attr->sa_mask |= SMB_AT_MTIME;
+ if (tmp_attr.sa_vattr.va_size > attr->sa_allocsz) {
+ attr->sa_vattr.va_size = attr->sa_allocsz;
+ attr->sa_mask |= SMB_AT_SIZE;
+ }
}
- if (now_times & SMB_AT_CTIME) {
- attr->sa_vattr.va_ctime = now;
- attr->sa_mask |= SMB_AT_CTIME;
+
+ rc = smb_fsop_setattr(sr, cr, node, attr);
+ if (rc != 0)
+ return (rc);
+
+ smb_node_set_cached_allocsz(node, attr);
+ smb_node_set_cached_timestamps(node, attr);
+ if (of) {
+ smb_ofile_set_explicit_times(of,
+ (attr->sa_mask & SMB_AT_TIMES));
}
}
- if (attr->sa_mask == 0)
- return (0);
+ /*
+ * Determine which timestamps to implicitly set to "now".
+ * Don't overwrite timestamps already explicitly set.
+ */
+ bzero(&tmp_attr, sizeof (smb_attr_t));
+ gethrestime(&now);
+ tmp_attr.sa_vattr.va_atime = now;
+ tmp_attr.sa_vattr.va_mtime = now;
+ tmp_attr.sa_vattr.va_ctime = now;
- rc = smb_fsop_setattr(sr, cr, node, attr);
- if (rc != 0)
- return (rc);
+ /* pending write timestamps */
+ if (of) {
+ if (smb_ofile_write_time_pending(of)) {
+ pending_times |=
+ (SMB_AT_MTIME | SMB_AT_CTIME | SMB_AT_ATIME);
+ }
+ explicit_times |= (smb_ofile_explicit_times(of));
+ }
+ explicit_times |= (attr->sa_mask & SMB_AT_TIMES);
+ pending_times &= ~explicit_times;
- smb_node_set_cached_timestamps(node, attr);
+ if (pending_times) {
+ tmp_attr.sa_mask = pending_times;
+ (void) smb_fsop_setattr(NULL, kcred, node, &tmp_attr);
+ }
- if (of)
- smb_ofile_set_explicit_times(of, (what & SMB_AT_TIMES));
+ /* additional timestamps to update in cache */
+ if (attr->sa_mask)
+ tmp_attr.sa_mask |= SMB_AT_CTIME;
+ if (attr->sa_mask & (SMB_AT_SIZE | SMB_AT_ALLOCSZ))
+ tmp_attr.sa_mask |= SMB_AT_MTIME;
+ tmp_attr.sa_mask &= ~explicit_times;
+
+ if (tmp_attr.sa_mask)
+ smb_node_set_cached_timestamps(node, &tmp_attr);
return (0);
}
@@ -1238,21 +1280,136 @@ smb_node_getattr(smb_request_t *sr, smb_node_t *node, smb_attr_t *attr)
mutex_enter(&node->n_mutex);
- if (node->vp->v_type == VDIR)
+ if (node->vp->v_type == VDIR) {
attr->sa_vattr.va_size = 0;
+ attr->sa_allocsz = 0;
+ }
if (node->readonly_creator)
attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY;
if (attr->sa_dosattr == 0)
attr->sa_dosattr = FILE_ATTRIBUTE_NORMAL;
+
mutex_exit(&node->n_mutex);
+ smb_node_get_cached_allocsz(node, attr);
smb_node_get_cached_timestamps(node, attr);
+
return (0);
}
/*
+ * smb_node_init_cached_data
+ */
+static void
+smb_node_init_cached_data(smb_node_t *node)
+{
+ smb_attr_t attr;
+
+ bzero(&attr, sizeof (smb_attr_t));
+ attr.sa_mask = SMB_AT_ALL;
+ (void) smb_fsop_getattr(NULL, kcred, node, &attr);
+
+ smb_node_init_cached_allocsz(node, &attr);
+ smb_node_init_cached_timestamps(node, &attr);
+}
+
+/*
+ * smb_node_clear_cached_data
+ */
+static void
+smb_node_clear_cached_data(smb_node_t *node)
+{
+ smb_node_clear_cached_allocsz(node);
+ smb_node_clear_cached_timestamps(node);
+}
+
+/*
+ * File allocation size (allocsz) caching
+ *
+ * When there are open ofiles on the node, the file allocsz is cached.
+ * The cached value (n_allocsz) is initialized when the first ofile is
+ * opened and cleared when the last is closed. Allocsz calculated from
+ * the filesize (rounded up to block size).
+ * When the allocation size is queried, if the cached allocsz is less
+ * than the filesize, it is recalculated from the filesize.
+ */
+
+/*
+ * smb_node_init_cached_allocsz
+ *
+ * If there are open ofiles, cache the allocsz in the node.
+ * Calculate the allocsz from the filesizes.
+ * block size).
+ */
+static void
+smb_node_init_cached_allocsz(smb_node_t *node, smb_attr_t *attr)
+{
+ mutex_enter(&node->n_mutex);
+ if (node->n_open_count == 1)
+ node->n_allocsz = SMB_ALLOCSZ(attr->sa_vattr.va_size);
+ mutex_exit(&node->n_mutex);
+}
+
+/*
+ * smb_node_clear_cached_allocsz
+ */
+static void
+smb_node_clear_cached_allocsz(smb_node_t *node)
+{
+ mutex_enter(&node->n_mutex);
+ if (node->n_open_count == 0)
+ node->n_allocsz = 0;
+ mutex_exit(&node->n_mutex);
+}
+
+/*
+ * smb_node_get_cached_allocsz
+ *
+ * If there is no cached allocsz (no open files), calculate
+ * allocsz from the filesize.
+ * If the allocsz is cached but is smaller than the filesize
+ * recalculate the cached allocsz from the filesize.
+ *
+ * Return allocs in attr->sa_allocsz.
+ */
+static void
+smb_node_get_cached_allocsz(smb_node_t *node, smb_attr_t *attr)
+{
+ if (node->vp->v_type == VDIR)
+ return;
+
+ mutex_enter(&node->n_mutex);
+ if (node->n_open_count == 0) {
+ attr->sa_allocsz = SMB_ALLOCSZ(attr->sa_vattr.va_size);
+ } else {
+ if (node->n_allocsz < attr->sa_vattr.va_size)
+ node->n_allocsz = SMB_ALLOCSZ(attr->sa_vattr.va_size);
+ attr->sa_allocsz = node->n_allocsz;
+ }
+ mutex_exit(&node->n_mutex);
+}
+
+/*
+ * smb_node_set_cached_allocsz
+ *
+ * attr->sa_allocsz has already been rounded to block size by
+ * the caller.
+ */
+static void
+smb_node_set_cached_allocsz(smb_node_t *node, smb_attr_t *attr)
+{
+ mutex_enter(&node->n_mutex);
+ if (attr->sa_mask & SMB_AT_ALLOCSZ) {
+ if (node->n_open_count > 0)
+ node->n_allocsz = attr->sa_allocsz;
+ }
+ mutex_exit(&node->n_mutex);
+}
+
+
+/*
* Timestamp caching
*
* Solaris file systems handle timestamps different from NTFS. For
@@ -1282,10 +1439,9 @@ smb_node_getattr(smb_request_t *sr, smb_node_t *node, smb_attr_t *attr)
* file system values.
*/
static void
-smb_node_init_cached_timestamps(smb_node_t *node)
+smb_node_init_cached_timestamps(smb_node_t *node, smb_attr_t *attr)
{
smb_node_t *unode;
- smb_attr_t attr;
if ((unode = SMB_IS_STREAM(node)) != NULL)
node = unode;
@@ -1293,13 +1449,10 @@ smb_node_init_cached_timestamps(smb_node_t *node)
mutex_enter(&node->n_mutex);
++(node->n_timestamps.t_open_ofiles);
if (node->n_timestamps.t_open_ofiles == 1) {
- bzero(&attr, sizeof (smb_attr_t));
- attr.sa_mask = SMB_AT_TIMES;
- (void) smb_fsop_getattr(NULL, kcred, node, &attr);
- node->n_timestamps.t_mtime = attr.sa_vattr.va_mtime;
- node->n_timestamps.t_atime = attr.sa_vattr.va_atime;
- node->n_timestamps.t_ctime = attr.sa_vattr.va_ctime;
- node->n_timestamps.t_crtime = attr.sa_crtime;
+ node->n_timestamps.t_mtime = attr->sa_vattr.va_mtime;
+ node->n_timestamps.t_atime = attr->sa_vattr.va_atime;
+ node->n_timestamps.t_ctime = attr->sa_vattr.va_ctime;
+ node->n_timestamps.t_crtime = attr->sa_crtime;
node->n_timestamps.t_cached = B_TRUE;
}
mutex_exit(&node->n_mutex);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c b/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c
index 36300171cf..aa12b2c96b 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c
@@ -269,7 +269,7 @@ smb_com_nt_create_andx(struct smb_request *sr)
}
op->fqi.fq_dnode = sr->fid_ofile->f_node;
- smbsr_disconnect_file(sr);
+ smbsr_release_file(sr);
}
if (smb_common_open(sr) != NT_STATUS_SUCCESS)
@@ -315,7 +315,7 @@ smb_com_nt_create_andx(struct smb_request *sr)
&attr.sa_vattr.va_mtime,
&attr.sa_vattr.va_ctime,
op->dattr & FILE_ATTRIBUTE_MASK,
- attr.sa_vattr.va_size,
+ attr.sa_allocsz,
attr.sa_vattr.va_size,
op->ftype,
op->devstate,
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c
index f0791b5573..80f2319a96 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c
@@ -185,7 +185,7 @@ smb_nt_transact_create(smb_request_t *sr, smb_xa_t *xa)
}
op->fqi.fq_dnode = sr->fid_ofile->f_node;
- smbsr_disconnect_file(sr);
+ smbsr_release_file(sr);
}
status = smb_common_open(sr);
@@ -231,7 +231,7 @@ smb_nt_transact_create(smb_request_t *sr, smb_xa_t *xa)
&attr.sa_vattr.va_mtime,
&attr.sa_vattr.va_ctime,
op->dattr & FILE_ATTRIBUTE_MASK,
- attr.sa_vattr.va_size,
+ attr.sa_allocsz,
attr.sa_vattr.va_size,
op->ftype,
op->devstate,
diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c
index 68f86a155c..d1290e5889 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c
@@ -27,29 +27,30 @@
#include <smbsrv/winioctl.h>
#include <smbsrv/ntstatus.h>
+
+static uint32_t smb_nt_trans_ioctl_noop(smb_request_t *, smb_xa_t *);
static uint32_t smb_nt_trans_ioctl_invalid_parm(smb_request_t *,
smb_xa_t *);
/*
- * This table defines the list of IOCTL/FSCTL values for which we'll
- * call a funtion to return a specific processing.
+ * This table defines the list of FSCTL values for which we'll
+ * call a funtion to perform specific processing.
*/
static struct {
uint32_t fcode;
uint32_t (*ioctl_func)(smb_request_t *sr, smb_xa_t *xa);
} ioctl_ret_tbl[] = {
- { FSCTL_GET_OBJECT_ID, smb_nt_trans_ioctl_invalid_parm },
- { FSCTL_QUERY_ALLOCATED_RANGES, smb_nt_trans_ioctl_invalid_parm },
- { FSCTL_SRV_ENUMERATE_SNAPSHOTS, smb_vss_ioctl_enumerate_snaps }
+ { FSCTL_GET_OBJECT_ID, smb_nt_trans_ioctl_invalid_parm },
+ { FSCTL_QUERY_ALLOCATED_RANGES, smb_nt_trans_ioctl_invalid_parm },
+ { FSCTL_SRV_ENUMERATE_SNAPSHOTS, smb_vss_ioctl_enumerate_snaps },
+ { FSCTL_SET_SPARSE, smb_nt_trans_ioctl_noop }
};
/*
* smb_nt_transact_ioctl
*
* This command allows device and file system control functions to be
- * transferred transparently from client to server. This is currently
- * a stub to work out whether or not we need to return an NT status
- * code.
+ * transferred transparently from client to server.
*
* Setup Words Encoding Description
* =========================== =========================================
@@ -78,7 +79,7 @@ static struct {
smb_sdrc_t
smb_nt_transact_ioctl(smb_request_t *sr, smb_xa_t *xa)
{
- uint32_t status = NT_STATUS_SUCCESS;
+ uint32_t status = NT_STATUS_NOT_SUPPORTED;
uint32_t fcode;
unsigned short fid;
unsigned char is_fsctl;
@@ -91,6 +92,10 @@ smb_nt_transact_ioctl(smb_request_t *sr, smb_xa_t *xa)
return (SDRC_ERROR);
}
+ /*
+ * Invoke handler if specified, otherwise the default
+ * behavior is to return NT_STATUS_NOT_SUPPORTED
+ */
for (i = 0; i < sizeof (ioctl_ret_tbl) / sizeof (ioctl_ret_tbl[0]);
i++) {
if (ioctl_ret_tbl[i].fcode == fcode) {
@@ -110,6 +115,13 @@ smb_nt_transact_ioctl(smb_request_t *sr, smb_xa_t *xa)
/* ARGSUSED */
static uint32_t
+smb_nt_trans_ioctl_noop(smb_request_t *sr, smb_xa_t *xa)
+{
+ return (NT_STATUS_SUCCESS);
+}
+
+/* ARGSUSED */
+static uint32_t
smb_nt_trans_ioctl_invalid_parm(smb_request_t *sr, smb_xa_t *xa)
{
return (NT_STATUS_INVALID_PARAMETER);
diff --git a/usr/src/uts/common/fs/smbsrv/smb_odir.c b/usr/src/uts/common/fs/smbsrv/smb_odir.c
index 61e92b3366..c953aa05a5 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_odir.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_odir.c
@@ -246,6 +246,7 @@
#include <smbsrv/smb_incl.h>
#include <smbsrv/smb_kproto.h>
#include <smbsrv/smb_fsops.h>
+#include <smbsrv/smb_share.h>
#include <sys/extdirent.h>
/* static functions */
@@ -659,9 +660,8 @@ smb_odir_read_streaminfo(smb_request_t *sr, smb_odir_t *od,
{
int rc;
smb_odirent_t *odirent;
- vnode_t *vp;
+ smb_node_t *fnode;
smb_attr_t attr;
- int tmpflg;
ASSERT(sr);
ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
@@ -702,15 +702,11 @@ smb_odir_read_streaminfo(smb_request_t *sr, smb_odir_t *od,
continue;
}
- /*
- * since we only care about the size attributes we don't need
- * to pass the vp of the unnamed stream file to smb_vop_getattr
- */
- rc = smb_vop_lookup(od->d_dnode->vp, odirent->od_name, &vp,
- NULL, 0, &tmpflg, od->d_tree->t_snode->vp, od->d_cred);
+ rc = smb_fsop_lookup(sr, od->d_cred, 0, od->d_tree->t_snode,
+ od->d_dnode, odirent->od_name, &fnode);
if (rc == 0) {
- rc = smb_vop_getattr(vp, NULL, &attr, 0, od->d_cred);
- VN_RELE(vp);
+ rc = smb_node_getattr(sr, fnode, &attr);
+ smb_node_release(fnode);
}
if (rc == 0) {
@@ -718,8 +714,7 @@ smb_odir_read_streaminfo(smb_request_t *sr, smb_odir_t *od,
odirent->od_name + SMB_STREAM_PREFIX_LEN,
sizeof (sinfo->si_name));
sinfo->si_size = attr.sa_vattr.va_size;
- sinfo->si_alloc_size =
- attr.sa_vattr.va_nblocks * DEV_BSIZE;
+ sinfo->si_alloc_size = attr.sa_allocsz;
break;
}
}
@@ -872,6 +867,8 @@ smb_odir_create(smb_request_t *sr, smb_node_t *dnode,
od->d_flags |= SMB_ODIR_FLAG_IGNORE_CASE;
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;
od->d_eof = B_FALSE;
smb_llist_enter(&tree->t_odir_list, RW_WRITER);
@@ -939,6 +936,7 @@ smb_odir_next_odirent(smb_odir_t *od, smb_odirent_t *odirent)
dirent64_t *dp;
edirent_t *edp;
char *np;
+ uint32_t abe_flag = 0;
ASSERT(MUTEX_HELD(&od->d_mutex));
@@ -965,8 +963,11 @@ smb_odir_next_odirent(smb_odir_t *od, smb_odirent_t *odirent)
od->d_bufsize = sizeof (od->d_buf);
+ if (od->d_flags & SMB_ODIR_FLAG_ABE)
+ abe_flag = SMB_ABE;
+
rc = smb_vop_readdir(od->d_dnode->vp, od->d_offset,
- od->d_buf, &od->d_bufsize, &eof, od->d_cred);
+ od->d_buf, &od->d_bufsize, &eof, abe_flag, od->d_cred);
if ((rc == 0) && (od->d_bufsize == 0))
rc = ENOENT;
@@ -1109,7 +1110,7 @@ smb_odir_single_fileinfo(smb_request_t *sr, smb_odir_t *od,
fileinfo->fi_dosattr = attr.sa_dosattr;
fileinfo->fi_nodeid = attr.sa_vattr.va_nodeid;
fileinfo->fi_size = attr.sa_vattr.va_size;
- fileinfo->fi_alloc_size = attr.sa_vattr.va_nblocks * DEV_BSIZE;
+ fileinfo->fi_alloc_size = attr.sa_allocsz;
fileinfo->fi_atime = attr.sa_vattr.va_atime;
fileinfo->fi_mtime = attr.sa_vattr.va_mtime;
fileinfo->fi_ctime = attr.sa_vattr.va_ctime;
@@ -1200,7 +1201,7 @@ smb_odir_wildcard_fileinfo(smb_request_t *sr, smb_odir_t *od,
fileinfo->fi_dosattr = attr.sa_dosattr;
fileinfo->fi_nodeid = attr.sa_vattr.va_nodeid;
fileinfo->fi_size = attr.sa_vattr.va_size;
- fileinfo->fi_alloc_size = attr.sa_vattr.va_nblocks * DEV_BSIZE;
+ fileinfo->fi_alloc_size = attr.sa_allocsz;
fileinfo->fi_atime = attr.sa_vattr.va_atime;
fileinfo->fi_mtime = attr.sa_vattr.va_mtime;
fileinfo->fi_ctime = attr.sa_vattr.va_ctime;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_ofile.c b/usr/src/uts/common/fs/smbsrv/smb_ofile.c
index 56eb9b8c8d..8d7ec2f06d 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_ofile.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_ofile.c
@@ -764,6 +764,11 @@ smb_ofile_set_write_time_pending(smb_ofile_t *of)
mutex_exit(&of->f_mutex);
}
+/*
+ * smb_ofile_write_time_pending
+ *
+ * Get and reset the write times pending flag.
+ */
boolean_t
smb_ofile_write_time_pending(smb_ofile_t *of)
{
@@ -771,8 +776,10 @@ smb_ofile_write_time_pending(smb_ofile_t *of)
SMB_OFILE_VALID(of);
mutex_enter(&of->f_mutex);
- if (of->f_flags & SMB_OFLAGS_TIMESTAMPS_PENDING)
+ if (of->f_flags & SMB_OFLAGS_TIMESTAMPS_PENDING) {
rc = B_TRUE;
+ of->f_flags &= ~SMB_OFLAGS_TIMESTAMPS_PENDING;
+ }
mutex_exit(&of->f_mutex);
return (rc);
@@ -782,16 +789,13 @@ smb_ofile_write_time_pending(smb_ofile_t *of)
* smb_ofile_set_explicit_time_flag
*
* Note the timestamps specified in "what", as having been
- * explicity set for the ofile. Also clear the flag for pending
- * timestamps as the pending timestamps will have been applied
- * by the explicit set.
+ * explicity set for the ofile.
*/
void
smb_ofile_set_explicit_times(smb_ofile_t *of, uint32_t what)
{
SMB_OFILE_VALID(of);
mutex_enter(&of->f_mutex);
- of->f_flags &= ~SMB_OFLAGS_TIMESTAMPS_PENDING;
of->f_explicit_times |= (what & SMB_AT_TIMES);
mutex_exit(&of->f_mutex);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_open_andx.c b/usr/src/uts/common/fs/smbsrv/smb_open_andx.c
index e0730d580f..f701f35c7b 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_open_andx.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_open_andx.c
@@ -290,7 +290,7 @@ smb_com_open(smb_request_t *sr)
7,
sr->smb_fid,
file_attr,
- smb_gmt2local(sr, attr.sa_vattr.va_mtime.tv_sec),
+ smb_time_gmt_to_local(sr, attr.sa_vattr.va_mtime.tv_sec),
(uint32_t)op->dsize,
op->omode,
(uint16_t)0); /* bcc */
@@ -331,7 +331,8 @@ smb_pre_open_andx(smb_request_t *sr)
op->op_oplock_level = SMB_OPLOCK_NONE;
if ((creation_time != 0) && (creation_time != UINT_MAX))
- op->crtime.tv_sec = smb_local2gmt(sr, creation_time);
+ op->crtime.tv_sec =
+ smb_time_local_to_gmt(sr, creation_time);
op->crtime.tv_nsec = 0;
op->create_disposition = smb_ofun_to_crdisposition(op->ofun);
@@ -399,7 +400,7 @@ smb_com_open_andx(smb_request_t *sr)
sr->andx_com, VAR_BCC,
sr->smb_fid,
file_attr,
- smb_gmt2local(sr, attr.sa_vattr.va_mtime.tv_sec),
+ smb_time_gmt_to_local(sr, attr.sa_vattr.va_mtime.tv_sec),
(uint32_t)op->dsize,
op->omode, op->ftype,
op->devstate,
@@ -442,7 +443,7 @@ smb_com_trans2_open2(smb_request_t *sr, smb_xa_t *xa)
return (SDRC_ERROR);
if ((creation_time != 0) && (creation_time != UINT_MAX))
- op->crtime.tv_sec = smb_local2gmt(sr, creation_time);
+ op->crtime.tv_sec = smb_time_local_to_gmt(sr, creation_time);
op->crtime.tv_nsec = 0;
op->dattr = file_attr;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c b/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c
index e585d4cf3c..cfc1956044 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c
@@ -60,79 +60,6 @@ smb_is_executable(char *path)
}
/*
- * smbd_fs_query
- *
- * Upon success, the caller will need to call smb_node_release() on
- * fqi.fq_fnode (if it isn't already set to NULL by this routine) and
- * and fqi.fq_dnode. These pointers will not be used after the caller
- * is done with them and should be released immediately. (The position
- * of smb_fqi in a union in the smb_request structure makes it difficult
- * to free these pointers at smb_request deallocation time.)
- *
- * If smbd_fs_query() returns error, no smb_nodes will need to be released
- * by callers as a result of references taken in this routine, and
- * fqi.fq_fnode and fqi.fq_dnode will be set to NULL.
- */
-
-int
-smbd_fs_query(smb_request_t *sr, smb_fqi_t *fqi, int fqm)
-{
- int rc;
-
- rc = smb_pathname_reduce(sr, sr->user_cr, fqi->fq_path.pn_path,
- sr->tid_tree->t_snode, sr->tid_tree->t_snode, &fqi->fq_dnode,
- fqi->fq_last_comp);
-
- if (rc)
- return (rc);
-
- rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
- sr->tid_tree->t_snode, fqi->fq_dnode, fqi->fq_last_comp,
- &fqi->fq_fnode);
-
- if (rc == 0) {
- (void) strcpy(fqi->fq_od_name, fqi->fq_fnode->od_name);
-
- /*
- * fqi->fq_fattr MUST be set even if returning EEXIST, as it
- * is used by some callers to determine how to handle EEXIST
- */
- rc = smb_node_getattr(sr, fqi->fq_fnode, &fqi->fq_fattr);
- if (rc != 0) {
- smb_node_release(fqi->fq_dnode);
- smb_node_release(fqi->fq_fnode);
- SMB_NULL_FQI_NODES(*fqi);
- return (rc);
- }
-
- if (fqm == FQM_PATH_MUST_NOT_EXIST) {
- smb_node_release(fqi->fq_dnode);
- smb_node_release(fqi->fq_fnode);
- SMB_NULL_FQI_NODES(*fqi);
- return (EEXIST);
- }
-
- return (0);
- }
-
- if (fqm == FQM_PATH_MUST_EXIST) {
- smb_node_release(fqi->fq_dnode);
- SMB_NULL_FQI_NODES(*fqi);
- return (rc);
- }
-
- if (rc == ENOENT) {
- fqi->fq_fnode = NULL;
- return (0);
- }
-
- smb_node_release(fqi->fq_dnode);
- SMB_NULL_FQI_NODES(*fqi);
-
- return (rc);
-}
-
-/*
* smb_pathname_reduce
*
* smb_pathname_reduce() takes a path and returns the smb_node for the
@@ -398,6 +325,7 @@ smb_pathname(smb_request_t *sr, char *path, int flags,
int err = 0;
int nlink = 0;
int local_flags;
+ uint32_t abe_flag = 0;
char namebuf[MAXNAMELEN];
if (path == NULL)
@@ -419,6 +347,9 @@ smb_pathname(smb_request_t *sr, char *path, int flags,
return (err);
}
+ if (SMB_TREE_SUPPORTS_ABE(sr))
+ abe_flag = SMB_ABE;
+
(void) pn_alloc(&pn);
(void) pn_alloc(&rpn);
@@ -458,7 +389,7 @@ smb_pathname(smb_request_t *sr, char *path, int flags,
break;
if ((err = smb_unmangle_name(dnode, component,
- real_name, MAXNAMELEN)) != 0)
+ real_name, MAXNAMELEN, abe_flag)) != 0)
break;
if ((namep = smb_pathname_catia_v5tov4(sr, real_name,
diff --git a/usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.c b/usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.c
new file mode 100644
index 0000000000..377baec57e
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.c
@@ -0,0 +1,891 @@
+/*
+ * 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.
+ */
+
+#include <smbsrv/smb_vops.h>
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+/*
+ * Trans2 Query File/Path Information Levels:
+ *
+ * SMB_INFO_STANDARD
+ * SMB_INFO_QUERY_EA_SIZE
+ * SMB_INFO_QUERY_EAS_FROM_LIST
+ * SMB_INFO_QUERY_ALL_EAS - not valid for pipes
+ * SMB_INFO_IS_NAME_VALID - only valid when query is by path
+ *
+ * SMB_QUERY_FILE_BASIC_INFO
+ * SMB_QUERY_FILE_STANDARD_INFO
+ * SMB_QUERY_FILE_EA_INFO
+ * SMB_QUERY_FILE_NAME_INFO
+ * SMB_QUERY_FILE_ALL_INFO
+ * SMB_QUERY_FILE_ALT_NAME_INFO - not valid for pipes
+ * SMB_QUERY_FILE_STREAM_INFO - not valid for pipes
+ * SMB_QUERY_FILE_COMPRESSION_INFO - not valid for pipes
+ *
+ * Supported Passthrough levels:
+ * SMB_FILE_BASIC_INFORMATION
+ * 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_NAME_INFORMATION
+ * SMB_FILE_ALL_INFORMATION
+ * SMB_FILE_ALT_NAME_INFORMATION - not valid for pipes
+ * SMB_FILE_STREAM_INFORMATION - not valid for pipes
+ * SMB_FILE_COMPRESSION_INFORMATION - not valid for pipes
+ * SMB_FILE_ATTR_TAG_INFORMATION - not valid for pipes
+ *
+ * Internal levels representing non trans2 requests
+ * SMB_QUERY_INFORMATION
+ * SMB_QUERY_INFORMATION2
+ */
+
+typedef struct smb_queryinfo {
+ smb_node_t *qi_node; /* NULL for pipes */
+ smb_attr_t qi_attr;
+ boolean_t qi_delete_on_close;
+ uint32_t qi_namelen;
+ char qi_name83[SMB_SHORTNAMELEN];
+ char qi_shortname[SMB_SHORTNAMELEN];
+ char qi_name[MAXPATHLEN];
+} smb_queryinfo_t;
+#define qi_mtime qi_attr.sa_vattr.va_mtime
+#define qi_ctime qi_attr.sa_vattr.va_ctime
+#define qi_atime qi_attr.sa_vattr.va_atime
+#define qi_crtime qi_attr.sa_crtime
+
+static int smb_query_by_fid(smb_request_t *, smb_xa_t *, uint16_t);
+static int smb_query_by_path(smb_request_t *, smb_xa_t *,
+ uint16_t, char *);
+
+static int smb_query_fileinfo(smb_request_t *, smb_node_t *,
+ uint16_t, smb_queryinfo_t *);
+static int smb_query_pipeinfo(smb_request_t *, smb_opipe_t *,
+ uint16_t, smb_queryinfo_t *);
+static boolean_t smb_query_pipe_valid_infolev(smb_request_t *, uint16_t);
+
+static int smb_query_encode_response(smb_request_t *, smb_xa_t *,
+ uint16_t, smb_queryinfo_t *);
+static void smb_encode_stream_info(smb_request_t *, smb_xa_t *,
+ smb_queryinfo_t *);
+static int smb_all_info_filename(smb_tree_t *, smb_node_t *, char *, size_t);
+uint32_t smb_pad_align(uint32_t offset, uint32_t align);
+
+
+/*
+ * smb_com_trans2_query_file_information
+ */
+smb_sdrc_t
+smb_com_trans2_query_file_information(struct smb_request *sr, struct smb_xa *xa)
+{
+ uint16_t infolev;
+
+ if (smb_mbc_decodef(&xa->req_param_mb, "ww",
+ &sr->smb_fid, &infolev) != 0)
+ return (SDRC_ERROR);
+
+ if (smb_query_by_fid(sr, xa, infolev) != 0)
+ return (SDRC_ERROR);
+
+ return (SDRC_SUCCESS);
+}
+
+/*
+ * smb_com_trans2_query_path_information
+ */
+smb_sdrc_t
+smb_com_trans2_query_path_information(smb_request_t *sr, smb_xa_t *xa)
+{
+ uint16_t infolev;
+ char *path;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST,
+ ERRDOS, ERROR_INVALID_FUNCTION);
+ return (SDRC_ERROR);
+ }
+
+ if (smb_mbc_decodef(&xa->req_param_mb, "%w4.u",
+ sr, &infolev, &path) != 0)
+ return (SDRC_ERROR);
+
+ if (smb_query_by_path(sr, xa, infolev, path) != 0)
+ return (SDRC_ERROR);
+
+ return (SDRC_SUCCESS);
+}
+
+/*
+ * smb_com_query_information (aka getattr)
+ */
+smb_sdrc_t
+smb_pre_query_information(smb_request_t *sr)
+{
+ int rc;
+ smb_fqi_t *fqi = &sr->arg.dirop.fqi;
+
+ rc = smbsr_decode_data(sr, "%S", sr, &fqi->fq_path.pn_path);
+
+ DTRACE_SMB_2(op__QueryInformation__start, smb_request_t *, sr,
+ smb_fqi_t *, fqi);
+
+ return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
+}
+
+void
+smb_post_query_information(smb_request_t *sr)
+{
+ DTRACE_SMB_1(op__QueryInformation__done, smb_request_t *, sr);
+}
+
+smb_sdrc_t
+smb_com_query_information(smb_request_t *sr)
+{
+ char *path = sr->arg.dirop.fqi.fq_path.pn_path;
+ uint16_t infolev = SMB_QUERY_INFORMATION;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ return (SDRC_ERROR);
+ }
+
+ if (smb_query_by_path(sr, NULL, infolev, path) != 0)
+ return (SDRC_ERROR);
+
+ return (SDRC_SUCCESS);
+}
+
+/*
+ * smb_com_query_information2 (aka getattre)
+ */
+smb_sdrc_t
+smb_pre_query_information2(smb_request_t *sr)
+{
+ int rc;
+ rc = smbsr_decode_vwv(sr, "w", &sr->smb_fid);
+
+ DTRACE_SMB_1(op__QueryInformation2__start, smb_request_t *, sr);
+
+ return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
+}
+
+void
+smb_post_query_information2(smb_request_t *sr)
+{
+ DTRACE_SMB_1(op__QueryInformation2__done, smb_request_t *, sr);
+}
+
+smb_sdrc_t
+smb_com_query_information2(smb_request_t *sr)
+{
+ uint16_t infolev = SMB_QUERY_INFORMATION2;
+
+ if (smb_query_by_fid(sr, NULL, infolev) != 0)
+ return (SDRC_ERROR);
+
+ return (SDRC_SUCCESS);
+}
+
+/*
+ * smb_query_by_fid
+ *
+ * Common code for querying file information by open file (or pipe) id.
+ * Use the id to identify the node / pipe object and request the
+ * smb_queryinfo_t data for that object.
+ */
+static int
+smb_query_by_fid(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev)
+{
+ int rc;
+ smb_queryinfo_t *qinfo;
+ smb_node_t *node;
+ smb_opipe_t *opipe;
+
+ smbsr_lookup_file(sr);
+
+ if (sr->fid_ofile == NULL) {
+ smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
+ return (-1);
+ }
+
+ if (infolev == SMB_INFO_IS_NAME_VALID) {
+ smbsr_error(sr, 0, ERRDOS, ERRunknownlevel);
+ smbsr_release_file(sr);
+ return (-1);
+ }
+
+ if ((sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE) &&
+ (!smb_query_pipe_valid_infolev(sr, infolev))) {
+ smbsr_release_file(sr);
+ return (-1);
+ }
+
+ qinfo = kmem_alloc(sizeof (smb_queryinfo_t), KM_SLEEP);
+
+ switch (sr->fid_ofile->f_ftype) {
+ case SMB_FTYPE_DISK:
+ node = sr->fid_ofile->f_node;
+ rc = smb_query_fileinfo(sr, node, infolev, qinfo);
+ break;
+ case SMB_FTYPE_MESG_PIPE:
+ opipe = sr->fid_ofile->f_pipe;
+ rc = smb_query_pipeinfo(sr, opipe, infolev, qinfo);
+ break;
+ default:
+ smbsr_error(sr, 0, ERRDOS, ERRbadfile);
+ rc = -1;
+ break;
+ }
+
+ if (rc == 0)
+ rc = smb_query_encode_response(sr, xa, infolev, qinfo);
+
+ kmem_free(qinfo, sizeof (smb_queryinfo_t));
+ smbsr_release_file(sr);
+ return (rc);
+}
+
+/*
+ * smb_query_by_path
+ *
+ * Common code for querying file information by file name.
+ * Use the file name to identify the node object and request the
+ * smb_queryinfo_t data for that node.
+ *
+ * Querying attributes on a named pipe by name is an error and
+ * is handled in the calling functions so that they can return
+ * the appropriate error status code (which differs by caller).
+ */
+static int
+smb_query_by_path(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev, char *path)
+{
+ smb_queryinfo_t *qinfo;
+ smb_node_t *node, *dnode;
+ int rc;
+ int len;
+
+ /* VALID, but not yet supported */
+ if (infolev == SMB_FILE_ACCESS_INFORMATION) {
+ smbsr_error(sr, 0, ERRDOS, ERRunknownlevel);
+ return (-1);
+ }
+
+ /*
+ * Some MS clients pass NULL file names. NT interprets this as "\".
+ * Otherwise, if path is not "\\", remove the terminating slash.
+ */
+ if ((len = strlen(path)) == 0)
+ path = "\\";
+ else {
+ if ((len > 1) && (path[len - 1] == '\\')) {
+ path[len - 1] = 0;
+ }
+ }
+
+ qinfo = kmem_alloc(sizeof (smb_queryinfo_t), KM_SLEEP);
+
+ rc = smb_pathname_reduce(sr, sr->user_cr, path, sr->tid_tree->t_snode,
+ sr->tid_tree->t_snode, &dnode, qinfo->qi_name);
+ if (rc == 0) {
+ rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ sr->tid_tree->t_snode, dnode, qinfo->qi_name, &node);
+ smb_node_release(dnode);
+ }
+
+ if (rc != 0) {
+ if (rc == ENOENT)
+ smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+ ERRDOS, ERROR_FILE_NOT_FOUND);
+ else
+ smbsr_errno(sr, rc);
+
+ kmem_free(qinfo, sizeof (smb_queryinfo_t));
+ return (-1);
+ }
+
+ rc = smb_query_fileinfo(sr, node, infolev, qinfo);
+ if (rc != 0) {
+ kmem_free(qinfo, sizeof (smb_queryinfo_t));
+ smb_node_release(node);
+ return (rc);
+ }
+
+ /* If delete_on_close - NT_STATUS_DELETE_PENDING */
+ if (qinfo->qi_delete_on_close) {
+ smbsr_error(sr, NT_STATUS_DELETE_PENDING,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ kmem_free(qinfo, sizeof (smb_queryinfo_t));
+ smb_node_release(node);
+ return (-1);
+ }
+
+ rc = smb_query_encode_response(sr, xa, infolev, qinfo);
+ kmem_free(qinfo, sizeof (smb_queryinfo_t));
+ smb_node_release(node);
+ return (rc);
+}
+
+/*
+ * smb_size32
+ * Some responses only support 32 bit file sizes. If the file size
+ * exceeds UINT_MAX (32 bit) we return UINT_MAX in the response.
+ */
+static uint32_t
+smb_size32(u_offset_t size)
+{
+ return ((size > UINT_MAX) ? UINT_MAX : (uint32_t)size);
+}
+
+/*
+ * smb_query_encode_response
+ *
+ * Encode the data from smb_queryinfo_t into client response
+ */
+int
+smb_query_encode_response(smb_request_t *sr, smb_xa_t *xa,
+ uint16_t infolev, smb_queryinfo_t *qinfo)
+{
+ uint16_t dattr;
+ u_offset_t datasz, allocsz;
+
+ dattr = qinfo->qi_attr.sa_dosattr & FILE_ATTRIBUTE_MASK;
+ datasz = qinfo->qi_attr.sa_vattr.va_size;
+ allocsz = qinfo->qi_attr.sa_allocsz;
+
+ switch (infolev) {
+ case SMB_QUERY_INFORMATION:
+ (void) smbsr_encode_result(sr, 10, 0, "bwll10.w",
+ 10,
+ dattr,
+ smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
+ smb_size32(datasz),
+ 0);
+ break;
+
+ case SMB_QUERY_INFORMATION2:
+ (void) smbsr_encode_result(sr, 11, 0, "byyyllww",
+ 11,
+ smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec),
+ smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec),
+ smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
+ smb_size32(datasz), smb_size32(allocsz), dattr, 0);
+ break;
+
+ case SMB_FILE_ACCESS_INFORMATION:
+ ASSERT(sr->fid_ofile);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "l",
+ sr->fid_ofile->f_granted_access);
+ break;
+
+ case SMB_INFO_STANDARD:
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb,
+ ((sr->session->native_os == NATIVE_OS_WIN95) ?
+ "YYYllw" : "yyyllw"),
+ smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec),
+ smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec),
+ smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
+ smb_size32(datasz), smb_size32(allocsz), dattr);
+ break;
+
+ case SMB_INFO_QUERY_EA_SIZE:
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb,
+ ((sr->session->native_os == NATIVE_OS_WIN95) ?
+ "YYYllwl" : "yyyllwl"),
+ smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec),
+ smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec),
+ smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec),
+ smb_size32(datasz), smb_size32(allocsz), dattr, 0);
+ break;
+
+ case SMB_INFO_QUERY_ALL_EAS:
+ case SMB_INFO_QUERY_EAS_FROM_LIST:
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
+ break;
+
+ case SMB_INFO_IS_NAME_VALID:
+ break;
+
+ case SMB_QUERY_FILE_BASIC_INFO:
+ case SMB_FILE_BASIC_INFORMATION:
+ /*
+ * NT includes 6 bytes (spec says 4) at the end of this
+ * response, which are required by NetBench 5.01.
+ */
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.",
+ &qinfo->qi_crtime,
+ &qinfo->qi_atime,
+ &qinfo->qi_mtime,
+ &qinfo->qi_ctime,
+ dattr);
+ break;
+
+ case SMB_QUERY_FILE_STANDARD_INFO:
+ case SMB_FILE_STANDARD_INFORMATION:
+ /* 2-byte pad at end */
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "qqlbb2.",
+ (uint64_t)allocsz,
+ (uint64_t)datasz,
+ qinfo->qi_attr.sa_vattr.va_nlink,
+ qinfo->qi_delete_on_close,
+ (qinfo->qi_attr.sa_vattr.va_type == VDIR));
+ break;
+
+ case SMB_QUERY_FILE_EA_INFO:
+ case SMB_FILE_EA_INFORMATION:
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
+ break;
+
+ case SMB_QUERY_FILE_NAME_INFO:
+ case SMB_FILE_NAME_INFORMATION:
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr,
+ qinfo->qi_namelen, qinfo->qi_name);
+ break;
+
+ case SMB_QUERY_FILE_ALL_INFO:
+ case SMB_FILE_ALL_INFORMATION:
+ /*
+ * There is a 6-byte pad between Attributes and AllocationSize,
+ * and a 2-byte pad after the Directory field.
+ */
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.qqlbb2.l",
+ &qinfo->qi_crtime,
+ &qinfo->qi_atime,
+ &qinfo->qi_mtime,
+ &qinfo->qi_ctime,
+ dattr,
+ (uint64_t)allocsz,
+ (uint64_t)datasz,
+ qinfo->qi_attr.sa_vattr.va_nlink,
+ qinfo->qi_delete_on_close,
+ (qinfo->qi_attr.sa_vattr.va_type == VDIR),
+ 0);
+
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "%lu",
+ sr, qinfo->qi_namelen, qinfo->qi_name);
+ break;
+
+ case SMB_QUERY_FILE_ALT_NAME_INFO:
+ case SMB_FILE_ALT_NAME_INFORMATION:
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "%lU", sr,
+ mts_wcequiv_strlen(qinfo->qi_shortname),
+ qinfo->qi_shortname);
+ break;
+
+ case SMB_QUERY_FILE_STREAM_INFO:
+ case SMB_FILE_STREAM_INFORMATION:
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ smb_encode_stream_info(sr, xa, qinfo);
+ break;
+
+ case SMB_QUERY_FILE_COMPRESSION_INFO:
+ case SMB_FILE_COMPRESSION_INFORMATION:
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "qwbbb3.",
+ datasz, 0, 0, 0, 0);
+ break;
+
+ case SMB_FILE_INTERNAL_INFORMATION:
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "q",
+ qinfo->qi_attr.sa_vattr.va_nodeid);
+ break;
+
+ case SMB_FILE_ATTR_TAG_INFORMATION:
+ /*
+ * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the
+ * second dword should be the reparse tag. Otherwise
+ * the tag value should be set to zero.
+ * We don't support reparse points, so we set the tag
+ * to zero.
+ */
+ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "ll",
+ (uint32_t)dattr, 0);
+ break;
+
+ default:
+ smbsr_error(sr, 0, ERRDOS, ERRunknownlevel);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_encode_stream_info
+ *
+ * This function encodes the streams information.
+ * The following rules about how have been derived from observed NT
+ * behaviour.
+ *
+ * If the target is a file:
+ * 1. If there are no named streams, the response should still contain
+ * an entry for the unnamed stream.
+ * 2. If there are named streams, the response should contain an entry
+ * for the unnamed stream followed by the entries for the named
+ * streams.
+ *
+ * If the target is a directory:
+ * 1. If there are no streams, the response is complete. Directories
+ * do not report the unnamed stream.
+ * 2. If there are streams, the response should contain entries for
+ * those streams but there should not be an entry for the unnamed
+ * stream.
+ *
+ * Note that the stream name lengths exclude the null terminator but
+ * the field lengths (i.e. next offset calculations) need to include
+ * the null terminator and be padded to a multiple of 8 bytes. The
+ * last entry does not seem to need any padding.
+ *
+ * If an error is encountered when trying to read the stream entries
+ * (smb_odir_read_streaminfo) it is treated as if there are no [more]
+ * 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
+ */
+static void
+smb_encode_stream_info(smb_request_t *sr, smb_xa_t *xa, smb_queryinfo_t *qinfo)
+{
+ char *stream_name;
+ uint32_t next_offset;
+ uint32_t stream_nlen;
+ uint32_t pad;
+ u_offset_t datasz, allocsz;
+ boolean_t is_dir;
+ smb_streaminfo_t *sinfo, *sinfo_next;
+ int rc = 0;
+ boolean_t done = B_FALSE;
+ boolean_t eos = B_FALSE;
+ uint16_t odid;
+ smb_odir_t *od = NULL;
+
+ smb_node_t *fnode = qinfo->qi_node;
+ smb_attr_t *attr = &qinfo->qi_attr;
+
+ ASSERT(fnode);
+ if (SMB_IS_STREAM(fnode)) {
+ fnode = fnode->n_unode;
+ ASSERT(fnode);
+ }
+ ASSERT(fnode->n_magic == SMB_NODE_MAGIC);
+ ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING);
+
+ sinfo = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP);
+ sinfo_next = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP);
+ is_dir = (attr->sa_vattr.va_type == VDIR);
+ datasz = attr->sa_vattr.va_size;
+ allocsz = attr->sa_allocsz;
+
+ odid = smb_odir_openat(sr, fnode);
+ if (odid != 0)
+ od = smb_tree_lookup_odir(sr->tid_tree, odid);
+ if (od != NULL)
+ rc = smb_odir_read_streaminfo(sr, od, sinfo, &eos);
+
+ if ((od == NULL) || (rc != 0) || (eos))
+ done = B_TRUE;
+
+ /* If not a directory, encode an entry for the unnamed stream. */
+ if (!is_dir) {
+ stream_name = "::$DATA";
+ stream_nlen = smb_ascii_or_unicode_strlen(sr, stream_name);
+
+ if (done)
+ next_offset = 0;
+ else
+ next_offset = 24 + stream_nlen +
+ smb_ascii_or_unicode_null_len(sr);
+
+ (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
+ */
+ while (!done) {
+ stream_nlen = smb_ascii_or_unicode_strlen(sr, sinfo->si_name);
+ sinfo_next->si_name[0] = 0;
+
+ 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 +
+ smb_ascii_or_unicode_null_len(sr);
+ pad = smb_pad_align(next_offset, 8);
+ next_offset += pad;
+ }
+ (void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu#.",
+ sr, next_offset, stream_nlen,
+ sinfo->si_size, sinfo->si_alloc_size,
+ sinfo->si_name, pad);
+
+ (void) memcpy(sinfo, sinfo_next, sizeof (smb_streaminfo_t));
+ }
+
+ kmem_free(sinfo, sizeof (smb_streaminfo_t));
+ kmem_free(sinfo_next, sizeof (smb_streaminfo_t));
+ if (od) {
+ smb_odir_close(od);
+ smb_odir_release(od);
+ }
+}
+
+/*
+ * smb_pad_align
+ *
+ * Returns the number of bytes required to pad an offset to the
+ * specified alignment.
+ */
+uint32_t
+smb_pad_align(uint32_t offset, uint32_t align)
+{
+ uint32_t pad = offset % align;
+
+ if (pad != 0)
+ pad = align - pad;
+
+ return (pad);
+}
+
+/*
+ * smb_all_info_filename
+ *
+ * This format of filename is only used by the ALL_INFO levels.
+ *
+ * Determine the absolute pathname of 'node' within the share.
+ * For example if the node represents file "test1.txt" in directory
+ * "dir1" on share "share1", the path would be: \share1\dir1\test1.txt
+ *
+ * If node represents a named stream, construct the pathname for the
+ * associated unnamed stream then append the stream name.
+ */
+static int
+smb_all_info_filename(smb_tree_t *tree, smb_node_t *node,
+ char *buf, size_t buflen)
+{
+ char *sharename = tree->t_sharename;
+ int rc;
+ size_t len;
+ vnode_t *vp;
+
+ len = snprintf(buf, buflen, "\\%s", sharename);
+ if (len == (buflen - 1))
+ return (ENAMETOOLONG);
+
+ buf += len;
+ buflen -= len;
+
+ if (SMB_IS_STREAM(node))
+ vp = node->n_unode->vp;
+ else
+ vp = node->vp;
+
+ rc = vnodetopath(tree->t_snode->vp, vp, buf, buflen, kcred);
+ if (rc == 0) {
+ (void) strsubst(buf, '/', '\\');
+
+ if (SMB_IS_STREAM(node))
+ (void) strlcat(buf, node->od_name, buflen);
+ }
+
+ return (rc);
+}
+
+/*
+ * smb_query_fileinfo
+ *
+ * Populate smb_queryinfo_t structure for SMB_FTYPE_DISK
+ * (This should become an smb_ofile / smb_node function.)
+ */
+int
+smb_query_fileinfo(smb_request_t *sr, smb_node_t *node, uint16_t infolev,
+ smb_queryinfo_t *qinfo)
+{
+ char *namep = node->od_name;
+ int rc;
+
+ (void) bzero(qinfo, sizeof (smb_queryinfo_t));
+
+ if (smb_node_getattr(sr, node, &qinfo->qi_attr) != 0) {
+ smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
+ ERRDOS, ERROR_INTERNAL_ERROR);
+ return (-1);
+ }
+
+ qinfo->qi_node = node;
+ qinfo->qi_delete_on_close =
+ (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0;
+
+ /*
+ * The number of links reported should be the number of
+ * non-deleted links. Thus if delete_on_close is set,
+ * decrement the link count.
+ */
+ if (qinfo->qi_delete_on_close &&
+ qinfo->qi_attr.sa_vattr.va_nlink > 0) {
+ --(qinfo->qi_attr.sa_vattr.va_nlink);
+ }
+
+ /* populate name, namelen and shortname */
+
+ /* ALL_INFO levels are a special case for name field */
+ if ((infolev == SMB_QUERY_FILE_ALL_INFO) ||
+ (infolev == SMB_FILE_ALL_INFORMATION)) {
+ rc = smb_all_info_filename(sr->tid_tree, node,
+ qinfo->qi_name, MAXPATHLEN);
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ return (-1);
+ }
+ qinfo->qi_namelen =
+ smb_ascii_or_unicode_strlen(sr, qinfo->qi_name);
+ return (0);
+ }
+
+ /*
+ * It looks like NT doesn't know what to do with the name "."
+ * so we convert it to "\\" to indicate the root directory.
+ * If the leading \ is missing, add it.
+ */
+ if (strcmp(namep, ".") == 0)
+ (void) strlcpy(qinfo->qi_name, "\\", MAXNAMELEN);
+ else if (*namep != '\\')
+ (void) snprintf(qinfo->qi_name, MAXNAMELEN, "\\%s", namep);
+ else
+ (void) strlcpy(qinfo->qi_name, namep, MAXNAMELEN);
+
+ qinfo->qi_namelen = smb_ascii_or_unicode_strlen(sr, qinfo->qi_name);
+
+ /*
+ * For some reason NT will not show the security tab in the root
+ * directory of a mapped drive unless the filename length is
+ * greater than one. So we hack the length here to persuade NT
+ * to show the tab. It should be safe because of the null
+ * terminator character.
+ */
+ if (qinfo->qi_namelen == 1)
+ qinfo->qi_namelen = 2;
+
+ /*
+ * If the shortname is generated by smb_mangle_name()
+ * it will be returned as the alternative name.
+ * Otherwise, convert the original name to upper-case
+ * and return it as the alternative name.
+ */
+ (void) smb_mangle_name(qinfo->qi_attr.sa_vattr.va_nodeid,
+ namep, qinfo->qi_shortname, qinfo->qi_name83, 0);
+ if (*qinfo->qi_shortname == 0) {
+ (void) strlcpy(qinfo->qi_shortname, namep, SMB_SHORTNAMELEN);
+ (void) utf8_strupr(qinfo->qi_shortname);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_query_pipeinfo
+ *
+ * Populate smb_queryinfo_t structure for SMB_FTYPE_MESG_PIPE
+ * (This should become an smb_opipe function.)
+ */
+static int
+smb_query_pipeinfo(smb_request_t *sr, smb_opipe_t *opipe, uint16_t infolev,
+ smb_queryinfo_t *qinfo)
+{
+ char *namep = opipe->p_name;
+
+ (void) bzero(qinfo, sizeof (smb_queryinfo_t));
+ qinfo->qi_node = NULL;
+ qinfo->qi_attr.sa_vattr.va_nlink = 1;
+ qinfo->qi_delete_on_close = 1;
+
+ if ((infolev == SMB_INFO_STANDARD) ||
+ (infolev == SMB_INFO_QUERY_EA_SIZE) ||
+ (infolev == SMB_QUERY_INFORMATION2)) {
+ qinfo->qi_attr.sa_dosattr = 0;
+ } else {
+ qinfo->qi_attr.sa_dosattr = FILE_ATTRIBUTE_NORMAL;
+ }
+
+ /* If the leading \ is missing from the pipe name, add it. */
+ if (*namep != '\\')
+ (void) snprintf(qinfo->qi_name, MAXNAMELEN, "\\%s", namep);
+ else
+ (void) strlcpy(qinfo->qi_name, namep, MAXNAMELEN);
+
+ qinfo->qi_namelen=
+ smb_ascii_or_unicode_strlen(sr, qinfo->qi_name);
+
+ return (0);
+}
+
+/*
+ * smb_query_pipe_valid_infolev
+ *
+ * If the infolev is not valid for a message pipe, the error
+ * information is set in sr and B_FALSE is returned.
+ * Otherwise, returns B_TRUE.
+ */
+static boolean_t
+smb_query_pipe_valid_infolev(smb_request_t *sr, uint16_t infolev)
+{
+ switch (infolev) {
+ case SMB_INFO_QUERY_ALL_EAS:
+ smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ return (B_FALSE);
+
+ case SMB_QUERY_FILE_ALT_NAME_INFO:
+ case SMB_FILE_ALT_NAME_INFORMATION:
+ case SMB_QUERY_FILE_STREAM_INFO:
+ case SMB_FILE_STREAM_INFORMATION:
+ case SMB_QUERY_FILE_COMPRESSION_INFO:
+ case SMB_FILE_COMPRESSION_INFORMATION:
+ case SMB_FILE_ATTR_TAG_INFORMATION:
+ smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ return (B_FALSE);
+ }
+
+ return (B_TRUE);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_query_information.c b/usr/src/uts/common/fs/smbsrv/smb_query_information.c
deleted file mode 100644
index 8718361d06..0000000000
--- a/usr/src/uts/common/fs/smbsrv/smb_query_information.c
+++ /dev/null
@@ -1,145 +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.
- */
-
-/*
- * SMB: query_information
- *
- * This request is sent to obtain information about a file.
- *
- * Client Request Description
- * ================================== =================================
- *
- * UCHAR WordCount; Count of parameter words = 0
- * USHORT ByteCount; Count of data bytes; min = 2
- * UCHAR BufferFormat; 0x04
- * STRING FileName[]; File name
- *
- * FileName is the fully qualified name of the file relative to the Tid in
- * the header.
- *
- * Server Response Description
- * ================================== =================================
- *
- * UCHAR WordCount; Count of parameter words = 10
- * USHORT FileAttributes;
- * UTIME LastWriteTime; Time of last write
- * ULONG FileSize; File size
- * USHORT Reserved [5]; Reserved - client should ignore
- * USHORT ByteCount; Count of data bytes = 0
- *
- * FileAttributes are as described in the "Attributes Encoding" section of
- * this document.
- *
- * Note that FileSize is limited to 32 bits, this request is inappropriate
- * for files whose size is too large.
- *
- * NOTES:
- * Some clients send a NULL file name. Right now we return ERRbadfile
- * until we find out what a MS client would send...
- */
-
-#include <smbsrv/smb_incl.h>
-#include <smbsrv/smb_fsops.h>
-
-smb_sdrc_t
-smb_pre_query_information(smb_request_t *sr)
-{
- smb_fqi_t *fqi = &sr->arg.dirop.fqi;
- int rc;
-
- rc = smbsr_decode_data(sr, "%S", sr, &fqi->fq_path.pn_path);
- if (rc == 0) {
- if (strlen(fqi->fq_path.pn_path) == 0)
- fqi->fq_path.pn_path = "\\";
- }
-
- DTRACE_SMB_2(op__QueryInformation__start, smb_request_t *, sr,
- smb_fqi_t *, fqi);
-
- return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
-}
-
-void
-smb_post_query_information(smb_request_t *sr)
-{
- DTRACE_SMB_1(op__QueryInformation__done, smb_request_t *, sr);
-}
-
-smb_sdrc_t
-smb_com_query_information(smb_request_t *sr)
-{
- char *path = sr->arg.dirop.fqi.fq_path.pn_path;
- char *name = sr->arg.dirop.fqi.fq_last_comp;
- int rc;
- uint16_t dattr;
- uint32_t write_time;
- u_offset_t datasz;
- smb_node_t *dir_node;
- smb_node_t *node;
- smb_attr_t attr;
- timestruc_t *mtime;
-
- if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
- smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
- ERROR_ACCESS_DENIED);
- return (SDRC_ERROR);
- }
-
- if ((rc = smb_pathname_reduce(sr, sr->user_cr, path,
- sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dir_node, name))
- != 0) {
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- if ((rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
- sr->tid_tree->t_snode, dir_node, name, &node)) != 0) {
- smb_node_release(dir_node);
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- smb_node_release(dir_node);
- rc = smb_node_getattr(sr, node, &attr);
- smb_node_release(node);
-
- if (rc != 0) {
- smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
- ERRDOS, ERROR_INTERNAL_ERROR);
- return (SDRC_ERROR);
- }
-
- dattr = attr.sa_dosattr & FILE_ATTRIBUTE_MASK;
- mtime = &attr.sa_vattr.va_mtime;
- write_time = smb_gmt2local(sr, mtime->tv_sec);
- datasz = attr.sa_vattr.va_size;
- if (datasz > UINT_MAX)
- datasz = UINT_MAX;
-
- rc = smbsr_encode_result(sr, 10, 0, "bwll10.w",
- 10, dattr, write_time, (uint32_t)datasz, 0);
-
- return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
-}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_query_information2.c b/usr/src/uts/common/fs/smbsrv/smb_query_information2.c
deleted file mode 100644
index 0c03e480fc..0000000000
--- a/usr/src/uts/common/fs/smbsrv/smb_query_information2.c
+++ /dev/null
@@ -1,127 +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.
- */
-
-/*
- * SMB: query_information2
- *
- * This SMB is gets information about the file represented by Fid.
- *
- * Client Request Description
- * ================================== =================================
- *
- * UCHAR WordCount; Count of parameter words = 2
- * USHORT Fid; File handle
- * USHORT ByteCount; Count of data bytes = 0
- *
- * Server Response Description
- * ================================== =================================
- *
- * UCHAR WordCount; Count of parameter words = 11
- * SMB_DATE CreationDate;
- * SMB_TIME CreationTime;
- * SMB_DATE LastAccessDate;
- * SMB_TIME LastAccessTime;
- * SMB_DATE LastWriteDate;
- * SMB_TIME LastWriteTime;
- * ULONG FileDataSize; File end of data
- * ULONG FileAllocationSize; File allocation size
- * USHORT FileAttributes;
- * USHORT ByteCount; Count of data bytes; min = 0
- *
- * The file being interrogated is specified by Fid, which must possess at
- * least read permission.
- *
- * FileAttributes are described in the "File Attribute Encoding" section
- * elsewhere in this document.
- */
-
-#include <smbsrv/smb_incl.h>
-
-smb_sdrc_t
-smb_pre_query_information2(smb_request_t *sr)
-{
- int rc;
-
- rc = smbsr_decode_vwv(sr, "w", &sr->smb_fid);
-
- DTRACE_SMB_1(op__QueryInformation2__start, smb_request_t *, sr);
-
- return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
-}
-
-void
-smb_post_query_information2(smb_request_t *sr)
-{
- DTRACE_SMB_1(op__QueryInformation2__done, smb_request_t *, sr);
-}
-
-smb_sdrc_t
-smb_com_query_information2(smb_request_t *sr)
-{
- smb_node_t *node;
- smb_attr_t attr;
- u_offset_t size64;
- uint32_t datasz, allocsz;
- int rc;
-
- smbsr_lookup_file(sr);
- if (sr->fid_ofile == NULL) {
- smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
- return (SDRC_ERROR);
- }
-
- if (sr->fid_ofile->f_ftype != SMB_FTYPE_DISK) {
- rc = smbsr_encode_result(sr, 11, 0, "blllllww",
- 11, 0, 0, 0, 0, 0, 0, 0);
- return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
- }
-
- node = sr->fid_ofile->f_node;
- if (smb_node_getattr(sr, node, &attr) != 0) {
- smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
- ERRDOS, ERROR_INTERNAL_ERROR);
- return (SDRC_ERROR);
- }
-
- size64 = attr.sa_vattr.va_size;
- datasz = (size64 > UINT_MAX) ? UINT_MAX : (uint32_t)size64;
-
- size64 = attr.sa_vattr.va_nblocks * DEV_BSIZE;
- allocsz = (size64 > UINT_MAX) ? UINT_MAX : (uint32_t)size64;
-
- rc = smbsr_encode_result(sr, 11, 0, "byyyllww",
- 11, /* wct */
- smb_gmt2local(sr, attr.sa_crtime.tv_sec),
- /* LastAccessTime */
- smb_gmt2local(sr, attr.sa_vattr.va_atime.tv_sec),
- /* LastWriteTime */
- smb_gmt2local(sr, attr.sa_vattr.va_mtime.tv_sec),
- datasz,
- allocsz,
- attr.sa_dosattr & FILE_ATTRIBUTE_MASK,
- 0); /* bcc */
-
- return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
-}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_rename.c b/usr/src/uts/common/fs/smbsrv/smb_rename.c
index 18365da04e..6da6809374 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_rename.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_rename.c
@@ -130,19 +130,36 @@ smb_com_rename(smb_request_t *sr)
static int
smb_do_rename(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
{
- smb_node_t *src_node;
+ smb_node_t *src_node, *tnode;
char *dstname;
DWORD status;
int rc;
int count;
+ char *path;
- if ((rc = smbd_fs_query(sr, src_fqi, FQM_PATH_MUST_EXIST)) != 0)
+ tnode = sr->tid_tree->t_snode;
+
+ /* Lookup the source node. It MUST exist. */
+ path = src_fqi->fq_path.pn_path;
+ rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
+ &src_fqi->fq_dnode, src_fqi->fq_last_comp);
+ if (rc != 0)
return (rc);
- src_node = src_fqi->fq_fnode;
+ rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, tnode,
+ src_fqi->fq_dnode, src_fqi->fq_last_comp, &src_fqi->fq_fnode);
+ if (rc != 0) {
+ smb_node_release(src_fqi->fq_dnode);
+ return (rc);
+ }
- if ((rc = smb_rename_check_attr(sr, src_node, src_fqi->fq_sattr)) != 0)
- goto rename_cleanup_nodes;
+ src_node = src_fqi->fq_fnode;
+ rc = smb_rename_check_attr(sr, src_node, src_fqi->fq_sattr);
+ if (rc != 0) {
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ return (rc);
+ }
/*
* Break the oplock before access checks. If a client
@@ -167,88 +184,100 @@ smb_do_rename(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
if (status == NT_STATUS_SHARING_VIOLATION) {
smb_node_end_crit(src_node);
- rc = EPIPE; /* = ERRbadshare */
- goto rename_cleanup_nodes;
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ return (EPIPE); /* = ERRbadshare */
}
status = smb_range_check(sr, src_node, 0, UINT64_MAX, B_TRUE);
if (status != NT_STATUS_SUCCESS) {
smb_node_end_crit(src_node);
- rc = EACCES;
- goto rename_cleanup_nodes;
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ return (EACCES);
+ }
+
+ /* Lookup destination node. */
+ path = dst_fqi->fq_path.pn_path;
+ rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
+ &dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
+ if (rc != 0) {
+ smb_node_end_crit(src_node);
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ return (rc);
+ }
+
+ rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, tnode,
+ dst_fqi->fq_dnode, dst_fqi->fq_last_comp, &dst_fqi->fq_fnode);
+ if ((rc != 0) && (rc != ENOENT)) {
+ smb_node_end_crit(src_node);
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ smb_node_release(dst_fqi->fq_dnode);
+ return (rc);
}
if (utf8_strcasecmp(src_fqi->fq_path.pn_path,
dst_fqi->fq_path.pn_path) == 0) {
- if ((rc = smbd_fs_query(sr, dst_fqi, 0)) != 0) {
- smb_node_end_crit(src_node);
- goto rename_cleanup_nodes;
- }
- /*
- * Because the fqm parameter to smbd_fs_query() was 0,
- * dst_fqi->fq_fnode may be NULL.
- */
if (dst_fqi->fq_fnode)
smb_node_release(dst_fqi->fq_fnode);
- rc = strcmp(src_fqi->fq_od_name, dst_fqi->fq_last_comp);
+ rc = strcmp(src_fqi->fq_fnode->od_name, dst_fqi->fq_last_comp);
if (rc == 0) {
smb_node_end_crit(src_node);
- goto rename_cleanup_nodes;
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ smb_node_release(dst_fqi->fq_dnode);
+ return (0);
}
rc = smb_fsop_rename(sr, sr->user_cr,
- src_fqi->fq_dnode, src_fqi->fq_od_name,
+ src_fqi->fq_dnode, src_fqi->fq_fnode->od_name,
dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
smb_node_end_crit(src_node);
if (rc == 0)
smb_node_notify_change(dst_fqi->fq_dnode);
- goto rename_cleanup_nodes;
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ smb_node_release(dst_fqi->fq_dnode);
+ return (rc);
}
- rc = smbd_fs_query(sr, dst_fqi, FQM_PATH_MUST_NOT_EXIST);
- if (rc != 0) {
+ /* dst node must not exist */
+ if (dst_fqi->fq_fnode) {
smb_node_end_crit(src_node);
- goto rename_cleanup_nodes;
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ smb_node_release(dst_fqi->fq_fnode);
+ smb_node_release(dst_fqi->fq_dnode);
+ return (EEXIST);
}
/*
- * On success of FQM_PATH_MUST_NOT_EXIST only dst_fqi->fq_dnode
- * is valid (dst_fqi->fq_fnode is NULL).
- */
-
- /*
* If the source name is mangled but the source and destination
* on-disk names are identical, we'll use the on-disk name.
*/
if ((smb_maybe_mangled_name(src_fqi->fq_last_comp)) &&
(strcmp(src_fqi->fq_last_comp, dst_fqi->fq_last_comp) == 0)) {
- dstname = src_fqi->fq_od_name;
+ dstname = src_fqi->fq_fnode->od_name;
} else {
dstname = dst_fqi->fq_last_comp;
}
rc = smb_fsop_rename(sr, sr->user_cr,
- src_fqi->fq_dnode, src_fqi->fq_od_name,
+ src_fqi->fq_dnode, src_fqi->fq_fnode->od_name,
dst_fqi->fq_dnode, dstname);
smb_node_end_crit(src_node);
-
if (rc == 0)
smb_node_notify_change(dst_fqi->fq_dnode);
-
-rename_cleanup_nodes:
- smb_node_release(src_node);
+ smb_node_release(src_fqi->fq_fnode);
smb_node_release(src_fqi->fq_dnode);
-
- if (dst_fqi->fq_dnode)
- smb_node_release(dst_fqi->fq_dnode);
-
- SMB_NULL_FQI_NODES(*src_fqi);
- SMB_NULL_FQI_NODES(*dst_fqi);
+ smb_node_release(dst_fqi->fq_dnode);
return (rc);
}
@@ -377,18 +406,35 @@ smb_com_nt_rename(smb_request_t *sr)
static int
smb_make_link(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
{
- smb_node_t *src_fnode;
+ smb_node_t *src_fnode, *tnode;
DWORD status;
int rc;
int count;
+ char *path;
- if ((rc = smbd_fs_query(sr, src_fqi, FQM_PATH_MUST_EXIST)) != 0)
+ tnode = sr->tid_tree->t_snode;
+
+ /* Lookup the source node. It MUST exist. */
+ path = src_fqi->fq_path.pn_path;
+ rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
+ &src_fqi->fq_dnode, src_fqi->fq_last_comp);
+ if (rc != 0)
return (rc);
- src_fnode = src_fqi->fq_fnode;
+ rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, tnode,
+ src_fqi->fq_dnode, src_fqi->fq_last_comp, &src_fqi->fq_fnode);
+ if (rc != 0) {
+ smb_node_release(src_fqi->fq_dnode);
+ return (rc);
+ }
- if ((rc = smb_rename_check_attr(sr, src_fnode, src_fqi->fq_sattr)) != 0)
- goto link_cleanup_nodes;
+ src_fnode = src_fqi->fq_fnode;
+ rc = smb_rename_check_attr(sr, src_fnode, src_fqi->fq_sattr);
+ if (rc != 0) {
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ return (rc);
+ }
/*
* Break the oplock before access checks. If a client
@@ -412,52 +458,61 @@ smb_make_link(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
if (status == NT_STATUS_SHARING_VIOLATION) {
smb_node_end_crit(src_fnode);
- rc = EPIPE; /* = ERRbadshare */
- goto link_cleanup_nodes;
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ return (EPIPE); /* = ERRbadshare */
}
status = smb_range_check(sr, src_fnode, 0, UINT64_MAX, B_TRUE);
-
if (status != NT_STATUS_SUCCESS) {
smb_node_end_crit(src_fnode);
- rc = EACCES;
- goto link_cleanup_nodes;
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ return (EACCES);
}
if (utf8_strcasecmp(src_fqi->fq_path.pn_path,
dst_fqi->fq_path.pn_path) == 0) {
smb_node_end_crit(src_fnode);
- rc = 0;
- goto link_cleanup_nodes;
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ return (0);
}
- rc = smbd_fs_query(sr, dst_fqi, FQM_PATH_MUST_NOT_EXIST);
+ /* Lookup the destination node. It MUST NOT exist. */
+ path = dst_fqi->fq_path.pn_path;
+ rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
+ &dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
if (rc != 0) {
smb_node_end_crit(src_fnode);
- goto link_cleanup_nodes;
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ return (rc);
+ }
+
+ rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, tnode,
+ dst_fqi->fq_dnode, dst_fqi->fq_last_comp, &dst_fqi->fq_fnode);
+ if (rc == 0) {
+ smb_node_release(dst_fqi->fq_fnode);
+ rc = EEXIST;
+ }
+ if (rc != ENOENT) {
+ smb_node_end_crit(src_fnode);
+ smb_node_release(src_fqi->fq_fnode);
+ smb_node_release(src_fqi->fq_dnode);
+ smb_node_release(dst_fqi->fq_dnode);
+ return (rc);
}
- /*
- * On success of FQM_PATH_MUST_NOT_EXIST only dst_fqi->fq_dnode
- * is valid (dst_fqi->fq_fnode is NULL).
- */
rc = smb_fsop_link(sr, sr->user_cr, dst_fqi->fq_dnode, src_fnode,
dst_fqi->fq_last_comp);
smb_node_end_crit(src_fnode);
-
if (rc == 0)
smb_node_notify_change(dst_fqi->fq_dnode);
-
-link_cleanup_nodes:
- smb_node_release(src_fnode);
+ smb_node_release(src_fqi->fq_fnode);
smb_node_release(src_fqi->fq_dnode);
-
- if (dst_fqi->fq_dnode)
- smb_node_release(dst_fqi->fq_dnode);
-
- SMB_NULL_FQI_NODES(*src_fqi);
- SMB_NULL_FQI_NODES(*dst_fqi);
+ smb_node_release(dst_fqi->fq_dnode);
return (rc);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_set_fileinfo.c b/usr/src/uts/common/fs/smbsrv/smb_set_fileinfo.c
new file mode 100644
index 0000000000..2f9111516d
--- /dev/null
+++ b/usr/src/uts/common/fs/smbsrv/smb_set_fileinfo.c
@@ -0,0 +1,683 @@
+/*
+ * 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.
+ */
+
+/*
+ * Trans2 Set File/Path Information Levels:
+ *
+ * SMB_INFO_STANDARD
+ * SMB_INFO_SET_EAS
+ * SMB_SET_FILE_BASIC_INFO
+ * SMB_SET_FILE_DISPOSITION_INFO
+ * SMB_SET_FILE_END_OF_FILE_INFO
+ * SMB_SET_FILE_ALLOCATION_INFO
+ *
+ * Supported Passthrough levels:
+ * SMB_FILE_BASIC_INFORMATION
+ * SMB_FILE_DISPOSITION_INFORMATION
+ * SMB_FILE_END_OF_FILE_INFORMATION
+ * SMB_FILE_ALLOCATION_INFORMATION
+ *
+ * Internal levels representing non trans2 requests
+ * SMB_SET_INFORMATION
+ * SMB_SET_INFORMATION2
+ */
+
+/*
+ * Setting timestamps:
+ * The behaviour when the time field is set to -1 is not documented
+ * but is generally treated like 0, meaning that that server file
+ * system assigned value need not be changed.
+ *
+ * Setting attributes - FILE_ATTRIBUTE_NORMAL:
+ * SMB_SET_INFORMATION -
+ * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set
+ * do NOT change the file's attributes.
+ * SMB_SET_BASIC_INFO -
+ * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set
+ * clear (0) the file's attributes.
+ * - if the specified attributes are 0 do NOT change the file's
+ * attributes.
+ */
+
+#include <smbsrv/smb_incl.h>
+#include <smbsrv/smb_fsops.h>
+
+typedef struct smb_setinfo {
+ uint16_t si_infolev;
+ smb_xa_t *si_xa;
+ smb_node_t *si_node;
+} smb_setinfo_t;
+
+/*
+ * These functions all return 0 (success) or -1 (error).
+ * They set error details in the sr when appropriate.
+ */
+static int smb_set_by_fid(smb_request_t *, smb_xa_t *, uint16_t);
+static int smb_set_by_path(smb_request_t *, smb_xa_t *, uint16_t, char *);
+static int smb_set_fileinfo(smb_request_t *, smb_setinfo_t *);
+static int smb_set_information(smb_request_t *, smb_setinfo_t *);
+static int smb_set_information2(smb_request_t *, smb_setinfo_t *);
+static int smb_set_standard_info(smb_request_t *, smb_setinfo_t *);
+static int smb_set_basic_info(smb_request_t *, smb_setinfo_t *);
+static int smb_set_disposition_info(smb_request_t *, smb_setinfo_t *);
+static int smb_set_eof_info(smb_request_t *sr, smb_setinfo_t *);
+static int smb_set_alloc_info(smb_request_t *sr, smb_setinfo_t *);
+
+/*
+ * smb_com_trans2_set_file_information
+ */
+smb_sdrc_t
+smb_com_trans2_set_file_information(smb_request_t *sr, smb_xa_t *xa)
+{
+ uint16_t infolev;
+
+ if (smb_mbc_decodef(&xa->req_param_mb, "ww",
+ &sr->smb_fid, &infolev) != 0)
+ return (SDRC_ERROR);
+
+ if (smb_set_by_fid(sr, xa, infolev) != 0)
+ return (SDRC_ERROR);
+
+ return (SDRC_SUCCESS);
+}
+
+/*
+ * smb_com_trans2_set_path_information
+ */
+smb_sdrc_t
+smb_com_trans2_set_path_information(smb_request_t *sr, smb_xa_t *xa)
+{
+ uint16_t infolev;
+ char *path;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST,
+ ERRDOS, ERROR_INVALID_FUNCTION);
+ return (SDRC_ERROR);
+ }
+
+ if (smb_mbc_decodef(&xa->req_param_mb, "%w4.u",
+ sr, &infolev, &path) != 0)
+ return (SDRC_ERROR);
+
+ if (smb_set_by_path(sr, xa, infolev, path) != 0)
+ return (SDRC_ERROR);
+
+ return (SDRC_SUCCESS);
+}
+
+/*
+ * smb_com_set_information (aka setattr)
+ */
+smb_sdrc_t
+smb_pre_set_information(smb_request_t *sr)
+{
+ DTRACE_SMB_1(op__SetInformation__start, smb_request_t *, sr);
+ return (SDRC_SUCCESS);
+}
+
+void
+smb_post_set_information(smb_request_t *sr)
+{
+ DTRACE_SMB_1(op__SetInformation__done, smb_request_t *, sr);
+}
+
+smb_sdrc_t
+smb_com_set_information(smb_request_t *sr)
+{
+ uint16_t infolev = SMB_SET_INFORMATION;
+ char *path;
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
+ smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ return (SDRC_ERROR);
+ }
+
+ if (smbsr_decode_data(sr, "%S", sr, &path) != 0)
+ return (SDRC_ERROR);
+
+ if (smb_set_by_path(sr, NULL, infolev, path) != 0)
+ return (SDRC_ERROR);
+
+ if (smbsr_encode_empty_result(sr) != 0)
+ return (SDRC_ERROR);
+
+ return (SDRC_SUCCESS);
+}
+
+/*
+ * smb_com_set_information2 (aka setattre)
+ */
+smb_sdrc_t
+smb_pre_set_information2(smb_request_t *sr)
+{
+ DTRACE_SMB_1(op__SetInformation2__start, smb_request_t *, sr);
+ return (SDRC_SUCCESS);
+}
+
+void
+smb_post_set_information2(smb_request_t *sr)
+{
+ DTRACE_SMB_1(op__SetInformation2__done, smb_request_t *, sr);
+}
+
+smb_sdrc_t
+smb_com_set_information2(smb_request_t *sr)
+{
+ uint16_t infolev = SMB_SET_INFORMATION2;
+
+ if (smbsr_decode_vwv(sr, "w", &sr->smb_fid) != 0)
+ return (SDRC_ERROR);
+
+ if (smb_set_by_fid(sr, NULL, infolev) != 0)
+ return (SDRC_ERROR);
+
+ if (smbsr_encode_empty_result(sr) != 0)
+ return (SDRC_ERROR);
+
+ return (SDRC_SUCCESS);
+}
+
+/*
+ * smb_set_by_fid
+ *
+ * Common code for setting file information by open file id.
+ * Use the id to identify the node object and invoke smb_set_fileinfo
+ * for that node.
+ *
+ * Setting attributes on a named pipe by id is handled by simply
+ * returning success.
+ */
+static int
+smb_set_by_fid(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev)
+{
+ int rc;
+ smb_setinfo_t sinfo;
+
+ if (SMB_TREE_IS_READONLY(sr)) {
+ smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ return (-1);
+ }
+
+ if (!STYPE_ISDSK(sr->tid_tree->t_res_type))
+ return (0);
+
+ smbsr_lookup_file(sr);
+ if (sr->fid_ofile == NULL) {
+ smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
+ return (-1);
+ }
+
+ if (!SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) {
+ smbsr_release_file(sr);
+ return (0);
+ }
+
+ sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
+
+ sinfo.si_xa = xa;
+ sinfo.si_infolev = infolev;
+ sinfo.si_node = sr->fid_ofile->f_node;
+ rc = smb_set_fileinfo(sr, &sinfo);
+
+ smbsr_release_file(sr);
+ return (rc);
+}
+
+/*
+ * smb_set_by_path
+ *
+ * Common code for setting file information by file name.
+ * Use the file name to identify the node object and invoke
+ * smb_set_fileinfo for that node.
+ *
+ * Setting attributes on a named pipe by name is an error and
+ * is handled in the calling functions so that they can return
+ * the appropriate error status code (which differs by caller).
+ */
+static int
+smb_set_by_path(smb_request_t *sr, smb_xa_t *xa,
+ uint16_t infolev, char *path)
+{
+ int rc;
+ smb_setinfo_t sinfo;
+ smb_node_t *node, *dnode;
+ char *name;
+
+ if (SMB_TREE_IS_READONLY(sr)) {
+ smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ return (-1);
+ }
+
+ name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
+ rc = smb_pathname_reduce(sr, sr->user_cr, path,
+ sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dnode, name);
+ if (rc == 0) {
+ rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
+ sr->tid_tree->t_snode, dnode, name, &node);
+ smb_node_release(dnode);
+ }
+ kmem_free(name, MAXNAMELEN);
+
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ 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;
+ rc = smb_set_fileinfo(sr, &sinfo);
+
+ smb_node_release(node);
+ return (rc);
+}
+
+/*
+ * smb_set_fileinfo
+ */
+static int
+smb_set_fileinfo(smb_request_t *sr, smb_setinfo_t *sinfo)
+{
+ switch (sinfo->si_infolev) {
+ case SMB_SET_INFORMATION:
+ return (smb_set_information(sr, sinfo));
+
+ case SMB_SET_INFORMATION2:
+ return (smb_set_information2(sr, sinfo));
+
+ case SMB_INFO_STANDARD:
+ return (smb_set_standard_info(sr, sinfo));
+
+ case SMB_INFO_SET_EAS:
+ /* EAs not supported */
+ return (0);
+
+ case SMB_SET_FILE_BASIC_INFO:
+ case SMB_FILE_BASIC_INFORMATION:
+ return (smb_set_basic_info(sr, sinfo));
+
+ case SMB_SET_FILE_DISPOSITION_INFO:
+ case SMB_FILE_DISPOSITION_INFORMATION:
+ return (smb_set_disposition_info(sr, sinfo));
+
+ case SMB_SET_FILE_END_OF_FILE_INFO:
+ case SMB_FILE_END_OF_FILE_INFORMATION:
+ return (smb_set_eof_info(sr, sinfo));
+
+ case SMB_SET_FILE_ALLOCATION_INFO:
+ case SMB_FILE_ALLOCATION_INFORMATION:
+ return (smb_set_alloc_info(sr, sinfo));
+
+ default:
+ break;
+ }
+
+ smbsr_error(sr, NT_STATUS_INVALID_INFO_CLASS,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ return (-1);
+}
+
+/*
+ * smb_set_information
+ *
+ * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the
+ * target is not a directory.
+ *
+ * For compatibility with Windows Servers, if the specified
+ * attributes have ONLY FILE_ATTRIBUTE_NORMAL set do NOT change
+ * the file's attributes.
+ */
+static int
+smb_set_information(smb_request_t *sr, smb_setinfo_t *sinfo)
+{
+ int rc;
+ uint16_t attributes;
+ smb_node_t *node = sinfo->si_node;
+ smb_attr_t attr;
+ uint32_t mtime;
+
+ if (smbsr_decode_vwv(sr, "wl10.", &attributes, &mtime) != 0)
+ return (-1);
+
+ if ((attributes & FILE_ATTRIBUTE_DIRECTORY) &&
+ (!smb_node_is_dir(node))) {
+ smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ return (-1);
+ }
+
+ bzero(&attr, sizeof (smb_attr_t));
+ if (attributes != FILE_ATTRIBUTE_NORMAL) {
+ attr.sa_dosattr = attributes;
+ attr.sa_mask |= SMB_AT_DOSATTR;
+ }
+
+ if (mtime != 0 && mtime != UINT_MAX) {
+ attr.sa_vattr.va_mtime.tv_sec =
+ smb_time_local_to_gmt(sr, mtime);
+ attr.sa_mask |= SMB_AT_MTIME;
+ }
+
+ rc = smb_node_setattr(sr, node, sr->user_cr, NULL, &attr);
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_set_information2
+ */
+static int
+smb_set_information2(smb_request_t *sr, smb_setinfo_t *sinfo)
+{
+ int rc;
+ uint32_t crtime, atime, mtime;
+ smb_attr_t attr;
+
+ if (smbsr_decode_vwv(sr, "yyy", &crtime, &atime, &mtime) != 0)
+ return (-1);
+
+ bzero(&attr, sizeof (smb_attr_t));
+ if (mtime != 0 && mtime != UINT_MAX) {
+ attr.sa_vattr.va_mtime.tv_sec =
+ smb_time_local_to_gmt(sr, mtime);
+ attr.sa_mask |= SMB_AT_MTIME;
+ }
+
+ if (crtime != 0 && crtime != UINT_MAX) {
+ attr.sa_crtime.tv_sec = smb_time_local_to_gmt(sr, crtime);
+ attr.sa_mask |= SMB_AT_CRTIME;
+ }
+
+ if (atime != 0 && atime != UINT_MAX) {
+ attr.sa_vattr.va_atime.tv_sec =
+ smb_time_local_to_gmt(sr, atime);
+ attr.sa_mask |= SMB_AT_ATIME;
+ }
+
+ rc = smb_node_setattr(sr, sinfo->si_node, sr->user_cr,
+ sr->fid_ofile, &attr);
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_set_standard_info
+ *
+ * Sets standard file/path information.
+ */
+static int
+smb_set_standard_info(smb_request_t *sr, smb_setinfo_t *sinfo)
+{
+ smb_attr_t attr;
+ uint32_t crtime, atime, mtime;
+ smb_node_t *node = sinfo->si_node;
+ int rc;
+
+ if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "yyy",
+ &crtime, &atime, &mtime) != 0) {
+ return (-1);
+ }
+
+ bzero(&attr, sizeof (smb_attr_t));
+ if (mtime != 0 && mtime != (uint32_t)-1) {
+ attr.sa_vattr.va_mtime.tv_sec =
+ smb_time_local_to_gmt(sr, mtime);
+ attr.sa_mask |= SMB_AT_MTIME;
+ }
+
+ if (crtime != 0 && crtime != (uint32_t)-1) {
+ attr.sa_crtime.tv_sec = smb_time_local_to_gmt(sr, crtime);
+ attr.sa_mask |= SMB_AT_CRTIME;
+ }
+
+ if (atime != 0 && atime != (uint32_t)-1) {
+ attr.sa_vattr.va_atime.tv_sec =
+ smb_time_local_to_gmt(sr, atime);
+ attr.sa_mask |= SMB_AT_ATIME;
+ }
+
+ rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_set_basic_info
+ *
+ * Sets basic file/path information.
+ *
+ * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the
+ * target is not a directory.
+ *
+ * For compatibility with windows servers:
+ * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set
+ * clear (0) the file's attributes.
+ * - if the specified attributes are 0 do NOT change the file's attributes.
+ */
+static int
+smb_set_basic_info(smb_request_t *sr, smb_setinfo_t *sinfo)
+{
+ int rc;
+ uint64_t crtime, atime, mtime, ctime;
+ uint16_t attributes;
+ smb_attr_t attr;
+ smb_node_t *node = sinfo->si_node;
+
+ if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "qqqqw",
+ &crtime, &atime, &mtime, &ctime, &attributes) != 0) {
+ return (-1);
+ }
+
+ if ((attributes & FILE_ATTRIBUTE_DIRECTORY) &&
+ (!smb_node_is_dir(node))) {
+ smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ return (-1);
+ }
+
+ bzero(&attr, sizeof (smb_attr_t));
+ if (ctime != 0 && ctime != (uint64_t)-1) {
+ smb_time_nt_to_unix(ctime, &attr.sa_vattr.va_ctime);
+ attr.sa_mask |= SMB_AT_CTIME;
+ }
+
+ if (crtime != 0 && crtime != (uint64_t)-1) {
+ smb_time_nt_to_unix(crtime, &attr.sa_crtime);
+ attr.sa_mask |= SMB_AT_CRTIME;
+ }
+
+ if (mtime != 0 && mtime != (uint64_t)-1) {
+ smb_time_nt_to_unix(mtime, &attr.sa_vattr.va_mtime);
+ attr.sa_mask |= SMB_AT_MTIME;
+ }
+
+ if (atime != 0 && atime != (uint64_t)-1) {
+ smb_time_nt_to_unix(atime, &attr.sa_vattr.va_atime);
+ attr.sa_mask |= SMB_AT_ATIME;
+ }
+
+ if (attributes != 0) {
+ attr.sa_dosattr = attributes;
+ attr.sa_mask |= SMB_AT_DOSATTR;
+ }
+
+ rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_set_eof_info
+ */
+static int
+smb_set_eof_info(smb_request_t *sr, smb_setinfo_t *sinfo)
+{
+ int rc;
+ smb_attr_t attr;
+ uint64_t eof;
+ smb_node_t *node = sinfo->si_node;
+
+ if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "q", &eof) != 0)
+ return (-1);
+
+ if (smb_node_is_dir(node)) {
+ smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ return (-1);
+ }
+
+ bzero(&attr, sizeof (smb_attr_t));
+ attr.sa_mask = SMB_AT_SIZE;
+ attr.sa_vattr.va_size = (u_offset_t)eof;
+ rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_set_alloc_info
+ */
+static int
+smb_set_alloc_info(smb_request_t *sr, smb_setinfo_t *sinfo)
+{
+ int rc;
+ smb_attr_t attr;
+ uint64_t allocsz;
+ smb_node_t *node = sinfo->si_node;
+
+ if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "q", &allocsz) != 0)
+ return (-1);
+
+ if (smb_node_is_dir(node)) {
+ smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
+ ERRDOS, ERROR_INVALID_PARAMETER);
+ return (-1);
+ }
+
+ bzero(&attr, sizeof (smb_attr_t));
+ attr.sa_mask = SMB_AT_ALLOCSZ;
+ attr.sa_allocsz = (u_offset_t)allocsz;
+ rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
+ if (rc != 0) {
+ smbsr_errno(sr, rc);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*
+ * smb_set_disposition_info
+ *
+ * Set/Clear DELETE_ON_CLOSE flag for an open file.
+ * File should have been opened with DELETE access otherwise
+ * the operation is not permitted.
+ *
+ * NOTE: The node should be marked delete-on-close upon the receipt
+ * of the Trans2SetFileInfo(SetDispositionInfo) if mark_delete is set.
+ * It is different than both SmbNtCreateAndX and SmbNtTransact, which
+ * set delete-on-close on the ofile and defer setting the flag on the
+ * node until the file is closed.
+ *
+ * Observation of Windows 2000 indicates the following:
+ *
+ * 1) If a file is not opened with delete-on-close create options and
+ * the delete-on-close is set via Trans2SetFileInfo(SetDispositionInfo)
+ * using that open file handle, any subsequent open requests will fail
+ * with DELETE_PENDING.
+ *
+ * 2) If a file is opened with delete-on-close create options and the
+ * client attempts to unset delete-on-close via Trans2SetFileInfo
+ * (SetDispositionInfo) prior to the file close, any subsequent open
+ * requests will still fail with DELETE_PENDING after the file is closed.
+ *
+ * 3) If a file is opened with delete-on-close create options and that
+ * file handle (not the last open handle and the only file handle
+ * with delete-on-close set) is closed. Any subsequent open requests
+ * will fail with DELETE_PENDING. Unsetting delete-on-close via
+ * Trans2SetFileInfo(SetDispositionInfo) at this time will unset the
+ * node delete-on-close flag, which will result in the file not being
+ * removed even after the last file handle is closed.
+ */
+static int
+smb_set_disposition_info(smb_request_t *sr, smb_setinfo_t *sinfo)
+{
+ unsigned char mark_delete;
+ uint32_t flags = 0;
+
+ if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "b", &mark_delete) != 0)
+ return (-1);
+
+ if ((sr->fid_ofile == NULL) ||
+ !(smb_ofile_granted_access(sr->fid_ofile) & DELETE)) {
+ smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ return (-1);
+ }
+
+ if (mark_delete) {
+ if (SMB_TREE_SUPPORTS_CATIA(sr))
+ flags |= SMB_CATIA;
+
+ if (smb_node_set_delete_on_close(sinfo->si_node,
+ sr->user_cr, flags)) {
+ smbsr_error(sr, NT_STATUS_CANNOT_DELETE,
+ ERRDOS, ERROR_ACCESS_DENIED);
+ return (-1);
+ }
+ } else {
+ smb_node_reset_delete_on_close(sinfo->si_node);
+ }
+ return (0);
+}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_set_information.c b/usr/src/uts/common/fs/smbsrv/smb_set_information.c
deleted file mode 100644
index e4073921b2..0000000000
--- a/usr/src/uts/common/fs/smbsrv/smb_set_information.c
+++ /dev/null
@@ -1,172 +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.
- */
-
-/*
- * SMB: set_information
- *
- * This message is sent to change the information about a file.
- *
- * Client Request Description
- * ================================== =================================
- *
- * UCHAR WordCount; Count of parameter words = 8
- * USHORT FileAttributes; Attributes of the file
- * UTIME LastWriteTime; Time of last write
- * USHORT Reserved [5]; Reserved (must be 0)
- * USHORT ByteCount; Count of data bytes; min = 2
- * UCHAR BufferFormat; 0x04
- * STRING FileName[]; File name
- *
- * FileName is the fully qualified name of the file relative to the Tid.
- *
- * Support of all parameters is optional. A server which does not
- * implement one of the parameters will ignore that field. If the
- * LastWriteTime field contain zero then the file's time is not changed.
- *
- * Server Response Description
- * ================================== =================================
- *
- * UCHAR WordCount; Count of parameter words = 0
- * USHORT ByteCount; Count of data bytes = 0
- *
- */
-
-#include <smbsrv/smb_incl.h>
-#include <smbsrv/smb_fsops.h>
-
-smb_sdrc_t
-smb_pre_set_information(smb_request_t *sr)
-{
- DTRACE_SMB_1(op__SetInformation__start, smb_request_t *, sr);
- return (SDRC_SUCCESS);
-}
-
-void
-smb_post_set_information(smb_request_t *sr)
-{
- DTRACE_SMB_1(op__SetInformation__done, smb_request_t *, sr);
-}
-
-smb_sdrc_t
-smb_com_set_information(smb_request_t *sr)
-{
- int rc;
- unsigned short dattr;
- char *path;
- smb_node_t *dir_node;
- smb_node_t *node;
- smb_attr_t attr;
- char *name;
- uint32_t last_wtime;
-
- if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
- (void) smbsr_encode_empty_result(sr);
- return (SDRC_SUCCESS);
- }
-
- name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
- if (smbsr_decode_vwv(sr, "wl10.", &dattr, &last_wtime) != 0) {
- kmem_free(name, MAXNAMELEN);
- return (SDRC_ERROR);
- }
-
- if (smbsr_decode_data(sr, "%S", sr, &path) != 0) {
- kmem_free(name, MAXNAMELEN);
- return (SDRC_ERROR);
- }
-
- rc = smb_pathname_reduce(sr, sr->user_cr, path,
- sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dir_node, name);
- if (rc != 0) {
- kmem_free(name, MAXNAMELEN);
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
- sr->tid_tree->t_snode, dir_node, name, &node);
- if (rc != 0) {
- smb_node_release(dir_node);
- kmem_free(name, MAXNAMELEN);
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- smb_node_release(dir_node);
-
- /*
- * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the
- * target is not a directory.
- */
- if ((dattr & FILE_ATTRIBUTE_DIRECTORY) &&
- (!smb_node_is_dir(node))) {
- smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
- ERRDOS, ERROR_INVALID_PARAMETER);
- return (SDRC_ERROR);
- }
-
- if (smb_oplock_conflict(node, sr->session, NULL)) {
- /*
- * for the benefit of attribute setting later on
- */
- (void) smb_oplock_break(node, sr->session, B_FALSE);
- }
-
- bzero(&attr, sizeof (smb_attr_t));
-
- /*
- * For compatibility with Windows Servers, if the specified
- * attributes have ONLY FILE_ATTRIBUTE_NORMAL set do NOT change
- * the file's attributes.
- * Note - this is different from TRANS2_SET_PATH/FILE_INFORMATION
- */
- if (dattr != FILE_ATTRIBUTE_NORMAL) {
- attr.sa_dosattr = dattr;
- attr.sa_mask |= SMB_AT_DOSATTR;
- }
-
- /*
- * The behaviour when the time field is set to -1
- * is not documented but is generally treated like 0,
- * meaning that that server file system assigned value
- * need not be changed.
- */
- if (last_wtime != 0 && last_wtime != 0xFFFFFFFF) {
- attr.sa_vattr.va_mtime.tv_sec = smb_local2gmt(sr, last_wtime);
- attr.sa_mask |= SMB_AT_MTIME;
- }
-
- rc = smb_node_setattr(sr, node, sr->user_cr, NULL, &attr);
- smb_node_release(node);
- kmem_free(name, MAXNAMELEN);
-
- if (rc) {
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- rc = smbsr_encode_empty_result(sr);
- return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
-}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_set_information2.c b/usr/src/uts/common/fs/smbsrv/smb_set_information2.c
deleted file mode 100644
index c3a5257598..0000000000
--- a/usr/src/uts/common/fs/smbsrv/smb_set_information2.c
+++ /dev/null
@@ -1,130 +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.
- */
-
-/*
- * SMB: set_information2
- *
- * Client Request Description
- * ================================== =================================
- *
- * UCHAR WordCount; Count of parameter words = 7
- * USHORT Fid; File handle
- * SMB_DATE CreationDate;
- * SMB_TIME CreationTime;
- * SMB_DATE LastAccessDate;
- * SMB_TIME LastAccessTime;
- * SMB_DATE LastWriteDate;
- * SMB_TIME LastWriteTime;
- * USHORT ByteCount; Count of data bytes = 0
- *
- * SMB_COM_SET_INFORMATION2 sets information about the file represented by
- * Fid. The target file is updated from the values specified. A date or
- * time value or zero indicates to leave that specific date and time
- * unchanged.
- *
- * Server Response Description
- * ================================== =================================
- *
- * UCHAR WordCount; Count of parameter words = 0
- * USHORT ByteCount; Count of data bytes = 0
- *
- * Fid must be open with (at least) write permission.
- */
-
-#include <smbsrv/smb_incl.h>
-
-smb_sdrc_t
-smb_pre_set_information2(smb_request_t *sr)
-{
- DTRACE_SMB_1(op__SetInformation2__start, smb_request_t *, sr);
- return (SDRC_SUCCESS);
-}
-
-void
-smb_post_set_information2(smb_request_t *sr)
-{
- DTRACE_SMB_1(op__SetInformation2__done, smb_request_t *, sr);
-}
-
-smb_sdrc_t
-smb_com_set_information2(smb_request_t *sr)
-{
- uint32_t creation, last_access, last_write; /* times */
- smb_attr_t attr;
- smb_node_t *node;
- int rc;
-
- rc = smbsr_decode_vwv(sr, "wyyy", &sr->smb_fid,
- &creation, &last_access, &last_write);
- if (rc != 0)
- return (SDRC_ERROR);
-
- smbsr_lookup_file(sr);
- if (sr->fid_ofile == NULL) {
- smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
- return (SDRC_ERROR);
- }
-
- sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
-
- node = sr->fid_ofile->f_node;
-
- if (node == 0 || sr->fid_ofile->f_ftype != SMB_FTYPE_DISK) {
- smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
- return (SDRC_ERROR);
- }
-
- bzero(&attr, sizeof (smb_attr_t));
-
- /*
- * The behaviour when the time field is set to -1
- * is not documented but is generally treated like 0,
- * meaning that that server file system assigned value
- * need not be changed.
- */
- if (last_write != 0 && last_write != UINT_MAX) {
- attr.sa_vattr.va_mtime.tv_sec = smb_local2gmt(sr, last_write);
- attr.sa_mask |= SMB_AT_MTIME;
- }
-
- if (creation != 0 && creation != UINT_MAX) {
- attr.sa_crtime.tv_sec = smb_local2gmt(sr, creation);
- attr.sa_mask |= SMB_AT_CRTIME;
- }
-
- if (last_access != 0 && last_access != UINT_MAX) {
- attr.sa_vattr.va_atime.tv_sec = smb_local2gmt(sr, last_access);
- attr.sa_mask |= SMB_AT_ATIME;
- }
-
- rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
- if (rc) {
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- rc = smbsr_encode_empty_result(sr);
- return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
-}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c
index d2b618fd5c..f3aef8da99 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c
@@ -664,9 +664,9 @@ smb_trans2_find_mbc_encode(smb_request_t *sr, smb_xa_t *xa,
fileinfo->fi_cookie);
(void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwbu", sr,
- smb_gmt2local(sr, fileinfo->fi_crtime.tv_sec),
- smb_gmt2local(sr, fileinfo->fi_atime.tv_sec),
- smb_gmt2local(sr, fileinfo->fi_mtime.tv_sec),
+ smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec),
+ smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec),
+ smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec),
dsize32,
asize32,
fileinfo->fi_dosattr,
@@ -697,9 +697,9 @@ smb_trans2_find_mbc_encode(smb_request_t *sr, smb_xa_t *xa,
tmpbuf[namelen] = '\0';
(void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwlb#c", sr,
- smb_gmt2local(sr, fileinfo->fi_crtime.tv_sec),
- smb_gmt2local(sr, fileinfo->fi_atime.tv_sec),
- smb_gmt2local(sr, fileinfo->fi_mtime.tv_sec),
+ smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec),
+ smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec),
+ smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec),
dsize32,
asize32,
fileinfo->fi_dosattr,
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c
deleted file mode 100644
index 1141fb6d12..0000000000
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c
+++ /dev/null
@@ -1,636 +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.
- */
-
-/*
- * SMB: trans2_query_file_information
- *
- * This request is used to get information about a specific file or
- * subdirectory given a handle to it.
- *
- * Client Request Value
- * ========================== ==========================================
- *
- * WordCount 15
- * MaxSetupCount 0
- * SetupCount 1
- * Setup[0] TRANS2_QUERY_FILE_INFORMATION
- *
- * Parameter Block Encoding Description
- * ========================== ==========================================
- *
- * USHORT Fid; Handle of file for request
- * USHORT InformationLevel; Level of information requested
- *
- * The available information levels, as well as the format of the response
- * are identical to TRANS2_QUERY_PATH_INFORMATION.
- */
-
-#include <smbsrv/smb_vops.h>
-#include <smbsrv/smb_incl.h>
-#include <smbsrv/smb_fsops.h>
-
-uint32_t smb_pad_align(uint32_t offset, uint32_t align);
-void smb_encode_smb_datetimes(smb_request_t *, smb_xa_t *, smb_attr_t *);
-void smb_encode_nt_times(smb_request_t *, smb_xa_t *, smb_attr_t *);
-extern int smb_query_all_info_filename(smb_tree_t *, smb_node_t *,
- char *, size_t);
-
-
-/*
- * smb_com_trans2_query_file_information
- *
- * Observation of Windows 2000 indicates the following:
- *
- * 1) If a file is opened with delete-on-close create options, the
- * delete-on-close status returned by the Trans2QueryFileInfo will not
- * be set. The delete-on-close status will only be set when the above
- * file handle is closed.
- *
- * 2) If a file is not opened with delete-on-close create options but the
- * delete-on-close is set via Trans2SetFileInfo/DispositionInfo, the
- * delete-on-close status returned by Trans2QueryFileInfo will be set
- * immediately.
- */
-smb_sdrc_t
-smb_com_trans2_query_file_information(struct smb_request *sr, struct smb_xa *xa)
-{
- static smb_attr_t pipe_attr;
- smb_attr_t file_attr;
- unsigned short infolev, dattr = 0;
- u_offset_t datasz = 0, allocsz = 0;
- smb_attr_t *ap = NULL;
- char *namep = NULL;
- char *filename = NULL;
- int filename_len = 0;
- smb_node_t *node = NULL; /* only set for SMB_FTYPE_DISK files */
- smb_node_t *dnode = NULL;
- unsigned char delete_on_close = 0;
- unsigned char is_dir = 0;
- char *filebuf = NULL;
- char short_name[SMB_SHORTNAMELEN];
- char name83[SMB_SHORTNAMELEN];
- int rc;
-
- if (smb_mbc_decodef(&xa->req_param_mb, "ww", &sr->smb_fid,
- &infolev) != 0) {
- return (SDRC_ERROR);
- }
-
- smbsr_lookup_file(sr);
- if (sr->fid_ofile == NULL) {
- smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
- return (SDRC_ERROR);
- }
-
- switch (sr->fid_ofile->f_ftype) {
- case SMB_FTYPE_DISK:
- {
- /* The node is only valid for SMB_FTYPE_DISK files. */
- node = sr->fid_ofile->f_node;
-
- /*
- * For some reason NT will not show the security tab in the root
- * directory of a mapped drive unless the filename length is
- * greater than one.
- * This may be a NT vs Windows9x UNICODE check.
- * So we hack the length here to persuade NT to show the tab. It
- * should be safe because of the null terminator character.
- */
- /* be careful here we need od_name now rather than node_name */
- /* do we want to use node_name in the case of softlinks ?? */
- namep = node->od_name;
- filename = namep;
- filename_len = smb_ascii_or_unicode_strlen(sr, filename);
- if (strcmp(namep, ".") == 0 && filename_len == 1)
- filename_len = 2;
-
- ap = &file_attr;
- if (smb_node_getattr(sr, node, ap) != 0) {
- smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
- ERRDOS, ERROR_INTERNAL_ERROR);
- return (SDRC_ERROR);
- }
-
- dattr = ap->sa_dosattr;
-
- if (smb_node_is_dir(node)) {
- is_dir = 1;
- datasz = allocsz = 0;
- } else {
- is_dir = 0;
- datasz = ap->sa_vattr.va_size;
- allocsz = ap->sa_vattr.va_nblocks * DEV_BSIZE;
- }
-
- dnode = node->n_dnode;
- delete_on_close =
- (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0;
-
- /*
- * The number of links reported should be the number of
- * non-deleted links. Thus if delete_on_close is set,
- * decrement the link count.
- */
- if (delete_on_close && ap->sa_vattr.va_nlink > 0)
- --(ap->sa_vattr.va_nlink);
-
- }
- break;
-
- case SMB_FTYPE_MESG_PIPE:
- {
- /* The pipe is only valid for SMB_FTYPE_MESG_PIPE files */
- namep = sr->fid_ofile->f_pipe->p_name;
- filename = namep;
- filename_len = smb_ascii_or_unicode_strlen(sr, filename);
-
- ap = &pipe_attr;
- ap->sa_vattr.va_nlink = 1;
- dattr = FILE_ATTRIBUTE_NORMAL;
- datasz = allocsz = 0;
-
- delete_on_close = 1;
- is_dir = 0;
-
- /* some levels are not valid for pipes */
- switch (infolev) {
- case SMB_QUERY_FILE_ALT_NAME_INFO:
- case SMB_FILE_ALT_NAME_INFORMATION:
- case SMB_QUERY_FILE_STREAM_INFO:
- case SMB_FILE_STREAM_INFORMATION:
- case SMB_QUERY_FILE_COMPRESSION_INFO:
- case SMB_FILE_COMPRESSION_INFORMATION:
- case SMB_FILE_ATTR_TAG_INFORMATION:
- smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
- ERRDOS, ERROR_INVALID_PARAMETER);
- return (SDRC_ERROR);
- case SMB_INFO_QUERY_ALL_EAS:
- smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
- ERRDOS, ERROR_ACCESS_DENIED);
- return (SDRC_ERROR);
- }
- }
- break;
- default:
- smbsr_error(sr, 0, ERRDOS, ERRbadfile);
- return (SDRC_ERROR);
- }
-
- filebuf = kmem_alloc(MAXPATHLEN+1, KM_SLEEP);
-
- switch (infolev) {
- case SMB_FILE_ACCESS_INFORMATION:
- (void) smb_mbc_encodef(&xa->rep_data_mb, "l",
- sr->fid_ofile->f_granted_access);
- break;
-
- case SMB_INFO_STANDARD:
- if (datasz > UINT_MAX)
- datasz = UINT_MAX;
- if (allocsz > UINT_MAX)
- allocsz = UINT_MAX;
-
- /* unlike other levels attributes should be 0 here for pipes */
- if (sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE)
- dattr = 0;
-
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- smb_encode_smb_datetimes(sr, xa, ap);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "llw",
- (uint32_t)datasz, (uint32_t)allocsz, dattr);
- break;
-
- case SMB_INFO_QUERY_EA_SIZE:
- if (datasz > UINT_MAX)
- datasz = UINT_MAX;
- if (allocsz > UINT_MAX)
- allocsz = UINT_MAX;
-
- /* unlike other levels attributes should be 0 here for pipes */
- if (sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE)
- dattr = 0;
-
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- smb_encode_smb_datetimes(sr, xa, ap);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "llwl",
- (uint32_t)datasz, (uint32_t)allocsz, dattr, 0);
- break;
-
- case SMB_INFO_QUERY_ALL_EAS:
- case SMB_INFO_QUERY_EAS_FROM_LIST:
- case SMB_FILE_EA_INFORMATION:
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
- break;
-
- case SMB_INFO_IS_NAME_VALID:
- break;
-
- case SMB_QUERY_FILE_BASIC_INFO:
- case SMB_FILE_BASIC_INFORMATION:
- /*
- * NT includes 6 undocumented bytes at the end of this
- * response, which are required by NetBench 5.01.
- * Similar change in smb_trans2_query_path_information.c.
- */
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- smb_encode_nt_times(sr, xa, ap);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "w6.", dattr);
- break;
-
- case SMB_QUERY_FILE_STANDARD_INFO:
- case SMB_FILE_STANDARD_INFORMATION:
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- /*
- * Add 2 bytes to pad data to long. It is
- * necessary because Win2k expects the padded bytes.
- */
- (void) smb_mbc_encodef(&xa->rep_data_mb, "qqlbb2.",
- (uint64_t)allocsz,
- (uint64_t)datasz,
- ap->sa_vattr.va_nlink,
- delete_on_close,
- is_dir);
- break;
-
- case SMB_QUERY_FILE_EA_INFO:
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
- break;
-
- case SMB_QUERY_FILE_NAME_INFO:
- case SMB_FILE_NAME_INFORMATION:
- /*
- * It looks like NT doesn't know what to do with the name "."
- * so we convert it to "\\" to indicate the root directory.
- *
- * If the leading \ is missing, add it.
- */
- if (strcmp(namep, ".") == 0) {
- filename = "\\";
- filename_len = 2;
- } else if (*namep != '\\') {
- filename = filebuf;
- (void) snprintf(filename, MAXNAMELEN + 1, "\\%s",
- namep);
- filename_len =
- smb_ascii_or_unicode_strlen(sr, filename);
- } else {
- filename = namep;
- filename_len =
- smb_ascii_or_unicode_strlen(sr, filename);
- }
-
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr,
- filename_len, filename);
- break;
-
- case SMB_QUERY_FILE_ALL_INFO:
- case SMB_FILE_ALL_INFORMATION:
- if (sr->fid_ofile->f_ftype == SMB_FTYPE_DISK) {
- rc = smb_query_all_info_filename(sr->tid_tree, node,
- filebuf, MAXPATHLEN);
- if (rc != 0) {
- smbsr_errno(sr, rc);
- kmem_free(filebuf, MAXPATHLEN+1);
- return (SDRC_ERROR);
- }
- filename = filebuf;
- } else {
- /* If the leading \ is missing, add it. */
- if (*namep != '\\') {
- (void) snprintf(filebuf, MAXNAMELEN,
- "\\%s", namep);
- filename = filebuf;
- }
- }
- filename_len = smb_ascii_or_unicode_strlen(sr, filename);
-
- /*
- * There is a 6-byte pad between Attributes and AllocationSize,
- * and a 2-byte pad after the Directory field.
- */
- if (node) {
- rc = smb_query_all_info_filename(sr->tid_tree, node,
- filebuf, MAXPATHLEN);
- if (rc != 0) {
- smbsr_errno(sr, rc);
- kmem_free(filebuf, MAXPATHLEN+1);
- return (SDRC_ERROR);
- }
- filename = filebuf;
- filename_len = smb_ascii_or_unicode_strlen(sr,
- filename);
- }
-
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- smb_encode_nt_times(sr, xa, ap);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "w6.qqlbb2.l",
- dattr,
- (uint64_t)allocsz,
- (uint64_t)datasz,
- ap->sa_vattr.va_nlink,
- delete_on_close,
- is_dir,
- 0);
-
- (void) smb_mbc_encodef(&xa->rep_data_mb, "%lu",
- sr, filename_len, filename);
- break;
-
- case SMB_QUERY_FILE_ALT_NAME_INFO:
- case SMB_FILE_ALT_NAME_INFORMATION:
- /*
- * If the shortname is generated by smb_mangle_name()
- * it will be returned as the alternative name.
- * Otherwise, convert the original name to upper-case
- * and return it as the alternative name.
- */
- (void) smb_mangle_name(ap->sa_vattr.va_nodeid,
- filename, short_name, name83, 0);
- if (*short_name == 0) {
- (void) strlcpy(short_name, filename, SMB_SHORTNAMELEN);
- (void) utf8_strupr(short_name);
- }
-
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "%lU", sr,
- mts_wcequiv_strlen(short_name), short_name);
- break;
-
- case SMB_QUERY_FILE_STREAM_INFO:
- case SMB_FILE_STREAM_INFORMATION:
- {
- struct smb_node *node = sr->fid_ofile->f_node;
- if (dnode == NULL) {
- kmem_free(filebuf, MAXPATHLEN+1);
- smbsr_error(sr, 0, ERRDOS, ERRbadfile);
- return (SDRC_ERROR);
- }
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- if (SMB_IS_STREAM(node)) {
- ASSERT(node->n_unode);
- ASSERT(node->n_unode->n_magic == SMB_NODE_MAGIC);
- ASSERT(node->n_unode->n_state !=
- SMB_NODE_STATE_DESTROYING);
-
- (void) smb_encode_stream_info(sr, xa,
- node->n_unode, ap);
- } else {
- (void) smb_encode_stream_info(sr, xa, node, ap);
- }
- break;
- }
- case SMB_QUERY_FILE_COMPRESSION_INFO:
- case SMB_FILE_COMPRESSION_INFORMATION:
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "qwbbb3.",
- datasz, 0, 0, 0, 0);
- break;
-
- case SMB_FILE_INTERNAL_INFORMATION:
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "q",
- ap->sa_vattr.va_nodeid);
- break;
-
- case SMB_FILE_ATTR_TAG_INFORMATION:
- /*
- * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the
- * second dword should be the reparse tag. Otherwise
- * the tag value should be set to zero.
- * We don't support reparse points, so we set the tag
- * to zero.
- */
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "ll",
- (uint32_t)dattr, 0);
- break;
-
- default:
- kmem_free(filebuf, MAXPATHLEN+1);
- smbsr_error(sr, 0, ERRDOS, ERRunknownlevel);
- return (SDRC_ERROR);
- }
-
- kmem_free(filebuf, MAXPATHLEN+1);
- return (SDRC_SUCCESS);
-}
-
-/*
- * smb_encode_stream_info
- *
- * This function encodes the streams information for both T2QueryFileInfo
- * and T2QueryPathInfo. The rules about how to do this are not documented.
- * They have been derived using observed NT behaviour and the IR's listed
- * below.
- *
- * IR101680: ArcServe2000 problem. ArcServe doesn't like the null-
- * stream data on directories that don't have any associated streams.
- *
- * IR103484 and KB article Q234765: Citrix problem. If there are no
- * streams, only return the unnamed stream data if the target is a
- * file. The Citrix Metaframe cdm.sys driver crashes the Windows server,
- * on which it's running, if it receives the unexpected stream data
- * for a directory.
- *
- * If there are streams, on files or directories, we need to return
- * them to support Mac/DAVE clients. Mac clients make this request
- * to see if there is a comment stream. If we don't provide the
- * information, the client won't try to access the comment stream.
- *
- * If the target is a file:
- * 1. If there are no named streams, the response should still contain
- * an entry for the unnamed stream.
- * 2. If there are named streams, the response should contain an entry
- * for the unnamed stream followed by the entries for the named
- * streams.
- *
- * If the target is a directory:
- * 1. If there are no streams, the response is complete. Directories
- * do not report the unnamed stream.
- * 2. If there are streams, the response should contain entries for
- * those streams but there should not be an entry for the unnamed
- * stream.
- *
- * Note that the stream name lengths exclude the null terminator but
- * the field lengths (i.e. next offset calculations) need to include
- * the null terminator and be padded to a multiple of 8 bytes. The
- * last entry does not seem to need any padding.
- *
- * If an error is encountered when trying to read the directory
- * entries (smb_fsop_stream_readdir) it is treated as if there are
- * no [more] directory 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
- */
-void
-smb_encode_stream_info(
- struct smb_request *sr,
- struct smb_xa *xa,
- struct smb_node *fnode,
- smb_attr_t *attr)
-{
- char *stream_name;
- uint32_t next_offset;
- uint32_t stream_nlen;
- uint32_t pad;
- u_offset_t datasz, allocsz;
- boolean_t is_dir;
- smb_streaminfo_t *sinfo, *sinfo_next;
- int rc = 0;
- boolean_t done = B_FALSE;
- boolean_t eos = B_FALSE;
- uint16_t odid;
- smb_odir_t *od = NULL;
-
- sinfo = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP);
- sinfo_next = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP);
- is_dir = (attr->sa_vattr.va_type == VDIR);
- datasz = attr->sa_vattr.va_size;
- allocsz = attr->sa_vattr.va_nblocks * DEV_BSIZE;
-
- odid = smb_odir_openat(sr, fnode);
- if (odid != 0)
- od = smb_tree_lookup_odir(sr->tid_tree, odid);
- if (od != NULL)
- rc = smb_odir_read_streaminfo(sr, od, sinfo, &eos);
-
- if ((od == NULL) || (rc != 0) || (eos))
- done = B_TRUE;
-
- /*
- * If not a directory, encode an entry for the unnamed stream.
- */
- if (!is_dir) {
- stream_name = "::$DATA";
- stream_nlen = smb_ascii_or_unicode_strlen(sr, stream_name);
-
- if (done)
- next_offset = 0;
- else
- next_offset = 24 + stream_nlen +
- smb_ascii_or_unicode_null_len(sr);
-
- (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
- */
- while (!done) {
- stream_nlen = smb_ascii_or_unicode_strlen(sr, sinfo->si_name);
- sinfo_next->si_name[0] = 0;
-
- 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 +
- smb_ascii_or_unicode_null_len(sr);
- pad = smb_pad_align(next_offset, 8);
- next_offset += pad;
- }
- (void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu#.",
- sr, next_offset, stream_nlen,
- sinfo->si_size, sinfo->si_alloc_size,
- sinfo->si_name, pad);
-
- (void) memcpy(sinfo, sinfo_next, sizeof (smb_streaminfo_t));
- }
-
- kmem_free(sinfo, sizeof (smb_streaminfo_t));
- kmem_free(sinfo_next, sizeof (smb_streaminfo_t));
- if (od) {
- smb_odir_close(od);
- smb_odir_release(od);
- }
-}
-
-/*
- * smb_pad_align
- *
- * Returns the number of bytes required to get pad an offset to the
- * specified alignment.
- */
-uint32_t
-smb_pad_align(uint32_t offset, uint32_t align)
-{
- uint32_t pad = offset % align;
-
- if (pad != 0)
- pad = align - pad;
-
- return (pad);
-}
-
-/*
- * smb_encode_smb_datetimes
- *
- * Encode timestamps in the SMB_DATE / SMB_TIME format.
- */
-void
-smb_encode_smb_datetimes(smb_request_t *sr, smb_xa_t *xa, smb_attr_t *attr)
-{
- if ((sr->fid_ofile) &&
- (sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE)) {
- (void) smb_mbc_encodef(&xa->rep_data_mb, "lll", 0, 0, 0);
- return;
- }
-
- (void) smb_mbc_encodef(&xa->rep_data_mb,
- ((sr->session->native_os == NATIVE_OS_WIN95) ? "YYY" : "yyy"),
- smb_gmt2local(sr, attr->sa_crtime.tv_sec),
- smb_gmt2local(sr, attr->sa_vattr.va_atime.tv_sec),
- smb_gmt2local(sr, attr->sa_vattr.va_mtime.tv_sec));
-}
-
-/*
- * smb_encode_nt_times
- *
- * Encode timestamps in LARGE INTEGER format NT Times.
- */
-void
-smb_encode_nt_times(smb_request_t *sr, smb_xa_t *xa, smb_attr_t *attr)
-{
- if ((sr->fid_ofile) &&
- (sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE)) {
- (void) smb_mbc_encodef(&xa->rep_data_mb, "qqqq", 0, 0, 0, 0);
- return;
- }
-
- (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTT",
- &attr->sa_crtime,
- &attr->sa_vattr.va_atime,
- &attr->sa_vattr.va_mtime,
- &attr->sa_vattr.va_ctime);
-}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c
deleted file mode 100644
index 078fd4e4af..0000000000
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c
+++ /dev/null
@@ -1,663 +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.
- */
-
-
-/*
- * SMB: trans2_query_path_information
- *
- * This request is used to get information about a specific file or
- * subdirectory.
- *
- * Client Request Value
- * ========================== =========================================
- *
- * WordCount 15
- * MaxSetupCount 0
- * SetupCount 1
- * Setup[0] TRANS2_QUERY_PATH_INFORMATION
- *
- * Parameter Block Encoding Description
- * ========================== =========================================
- *
- * USHORT InformationLevel; Level of information requested
- * ULONG Reserved; Must be zero
- * STRING FileName; File or directory name
- *
- * The following InformationLevels may be requested:
- *
- * Information Level Value
- *
- * ================================ =====
- *
- * SMB_INFO_STANDARD 1
- * SMB_INFO_QUERY_EA_SIZE 2
- * SMB_INFO_QUERY_EAS_FROM_LIST 3
- * SMB_INFO_QUERY_ALL_EAS 4
- * SMB_INFO_IS_NAME_VALID 6
- * SMB_QUERY_FILE_BASIC_INFO 0x101
- * SMB_QUERY_FILE_STANDARD_INFO 0x102
- * SMB_QUERY_FILE_EA_INFO 0x103
- * SMB_QUERY_FILE_NAME_INFO 0x104
- * SMB_QUERY_FILE_ALL_INFO 0x107
- * SMB_QUERY_FILE_ALT_NAME_INFO 0x108
- * SMB_QUERY_FILE_STREAM_INFO 0x109
- * SMB_QUERY_FILE_COMPRESSION_INFO 0x10B
- * SMB_FILE_INTERNAL_INFORMATION 1006
- *
- * The requested information is placed in the Data portion of the
- * transaction response. For the information levels greater than 0x100,
- * the transaction response has 1 parameter word which should be ignored by
- * the client.
- *
- * The following sections describe the InformationLevel dependent encoding
- * of the data part of the transaction response.
- *
- * 4.2.14.1 SMB_INFO_STANDARD & SMB_INFO_QUERY_EA_SIZE
- *
- * Data Block Encoding Description
- * =============================== ====================================
- *
- * SMB_DATE CreationDate; Date when file was created
- * SMB_TIME CreationTime; Time when file was created
- * SMB_DATE LastAccessDate; Date of last file access
- * SMB_TIME LastAccessTime; Time of last file access
- * SMB_DATE LastWriteDate; Date of last write to the file
- * SMB_TIME LastWriteTime; Time of last write to the file
- * ULONG DataSize; File Size
- * ULONG AllocationSize; Size of filesystem allocation unit
- * USHORT Attributes; File Attributes
- * ULONG EaSize; Size of file's EA information
- * (SMB_INFO_QUERY_EA_SIZE)
- *
- * 4.2.14.2 SMB_INFO_QUERY_EAS_FROM_LIST & SMB_INFO_QUERY_ALL_EAS
- *
- * Response Field Value
- * ==================== ===============================================
- *
- * MaxDataCount Length of EAlist found (minimum value is 4)
- *
- * Parameter Block Description
- * Encoding ===============================================
- * ====================
- *
- * USHORT EaErrorOffset Offset into EAList of EA error
- *
- * Data Block Encoding Description
- * ==================== ===============================================
- *
- * ULONG ListLength; Length of the remaining data
- * UCHAR EaList[] The extended attributes list
- *
- * 4.2.14.3 SMB_INFO_IS_NAME_VALID
- *
- * This requests checks to see if the name of the file contained in the
- * request's Data field has a valid path syntax. No parameters or data are
- * returned on this information request. An error is returned if the syntax
- * of the name is incorrect. Success indicates the server accepts the path
- * syntax, but it does not ensure the file or directory actually exists.
- *
- * 4.2.14.4 SMB_QUERY_FILE_BASIC_INFO
- *
- * Data Block Encoding Description
- * =============================== ====================================
- *
- * LARGE_INTEGER CreationTime; Time when file was created
- * LARGE_INTEGER LastAccessTime; Time of last file access
- * LARGE_INTEGER LastWriteTime; Time of last write to the file
- * LARGE_INTEGER ChangeTime Time when file was last changed
- * USHORT Attributes; File Attributes
- *
- * 4.2.14.5 SMB_QUERY_FILE_STANDARD_INFO
- *
- * Data Block Encoding Description
- * =============================== ====================================
- *
- * LARGE_INTEGER AllocationSize Allocated size of the file in number
- * of bytes
- * LARGE_INTEGER EndofFile; Offset to the first free byte in the
- * file
- * ULONG NumberOfLinks Number of hard links to the file
- * BOOLEAN DeletePending Indicates whether the file is marked
- * for deletion
- * BOOLEAN Directory Indicates whether the file is a
- * directory
- *
- * 4.2.14.6 SMB_QUERY_FILE_EA_INFO
- *
- * Data Block Encoding Description
- * =============================== ====================================
- *
- * ULONG EASize Size of the file's extended
- * attributes in number of bytes
- *
- * 4.2.14.7 SMB_QUERY_FILE_NAME_INFO
- *
- * Data Block Encoding Description
- * =============================== ====================================
- *
- * ULONG FileNameLength Length of the file name in number of
- * bytes
- * STRING FileName Name of the file
- *
- * 4.2.14.8 SMB_QUERY_FILE_ALL_INFO
- *
- * Data Block Encoding Description
- * =============================== ====================================
- *
- * LARGE_INTEGER CreationTime; Time when file was created
- * LARGE_INTEGER LastAccessTime; Time of last file access
- * LARGE_INTEGER LastWriteTime; Time of last write to the file
- * LARGE_INTEGER ChangeTime Time when file was last changed
- * USHORT Attributes; File Attributes
- * LARGE_INTEGER AllocationSize Allocated size of the file in number
- * of bytes
- * LARGE_INTEGER EndofFile; Offset to the first free byte in the
- * file
- * ULONG NumberOfLinks Number of hard links to the file
- * BOOLEAN DeletePending Indicates whether the file is marked
- * for deletion
- * BOOLEAN Directory Indicates whether the file is a
- * directory
- * LARGE_INTEGER Index Number A file system unique identifier
- * ULONG EASize Size of the file's extended
- * attributes in number of bytes
- * ULONG AccessFlags Access that a caller has to the
- * file; Possible values and meanings
- * are specified below
- * LARGE_INTEGER Index Number A file system unique identifier
- * LARGE_INTEGER CurrentByteOffset Current byte offset within the file
- * ULONG Mode Current Open mode of the file handle
- * to the file; possible values and
- * meanings are detailed below
- * ULONG AlignmentRequirement Buffer Alignment required by device;
- * possible values detailed below
- * ULONG FileNameLength Length of the file name in number of
- * bytes
- * STRING FileName Name of the file
- *
- * The AccessFlags specifies the access permissions a caller has to the
- * file and can have any suitable combination of the following values:
- *
- * Value Meaning
- *
- * ILE_READ_DATA 0x00000001 Data can be read from the file
- * ILE_WRITE_DATA 0x00000002 Data can be written to the file
- * ILE_APPEND_DATA 0x00000004 Data can be appended to the file
- * ILE_READ_EA 0x00000008 Extended attributes associated
- * with the file can be read
- * ILE_WRITE_EA 0x00000010 Extended attributes associated
- * with the file can be written
- * ILE_EXECUTE 0x00000020 Data can be read into memory from
- * the file using system paging I/O
- * ILE_READ_ATTRIBUTES 0x00000080 Attributes associated with the
- * file can be read
- * ILE_WRITE_ATTRIBUTES 0x00000100 Attributes associated with the
- * file can be written
- * ELETE 0x00010000 The file can be deleted
- * EAD_CONTROL 0x00020000 The access control list and
- * ownership associated with the
- * file can be read
- * RITE_DAC 0x00040000 The access control list and
- * ownership associated with the
- * file can be written.
- * RITE_OWNER 0x00080000 Ownership information associated
- * with the file can be written
- * YNCHRONIZE 0x00100000 The file handle can waited on to
- * synchronize with the completion
- * of an input/output request
- *
- * The Mode field specifies the mode in which the file is currently opened.
- * The possible values may be a suitable and logical combination of the
- * following:
- *
- * Value Meaning
- *
- * FILE_WRITE_THROUGH 0x00000002 File is opened in mode
- * where data is written to
- * file before the driver
- * completes a write request
- * FILE_SEQUENTIAL_ONLY 0x00000004 All access to the file is
- * sequential
- * FILE_SYNCHRONOUS_IO_ALERT 0x00000010 All operations on the
- * file are performed
- * synchronously
- * FILE_SYNCHRONOUS_IO_NONALER 0x00000020 All operations on the
- * T file are to be performed
- * synchronously. Waits in
- * the system to synchronize
- * I/O queuing and
- * completion are not
- * subject to alerts.
- *
- * The AlignmentRequirement field specifies buffer alignment required by
- * the device and can have any one of the following values:
- *
- * Value Meaning
- *
- * FILE_BYTE_ALIGNMENT 0x00000000 The buffer needs to be aligned
- * on a byte boundary
- * FILE_WORD_ALIGNMENT 0x00000001 The buffer needs to be aligned
- * on a word boundary
- * FILE_LONG_ALIGNMENT 0x00000003 The buffer needs to be aligned
- * on a 4 byte boundary
- * FILE_QUAD_ALIGNMENT 0x00000007 The buffer needs to be aligned
- * on an 8 byte boundary
- * FILE_OCTA_ALIGNMENT 0x0000000f The buffer needs to be aligned
- * on a 16 byte boundary
- * FILE_32_BYTE_ALIGNMENT 0x0000001f The buffer needs to be aligned
- * on a 32 byte boundary
- * FILE_64_BYTE_ALIGNMENT 0x0000003f The buffer needs to be aligned
- * on a 64 byte boundary
- * FILE_128_BYTE_ALIGNMENT 0x0000007f The buffer needs to be aligned
- * on a 128 byte boundary
- * FILE_256_BYTE_ALIGNMENT 0x000000ff The buffer needs to be aligned
- * on a 256 byte boundary
- * FILE_512_BYTE_ALIGNMENT 0x000001ff The buffer needs to be aligned
- * on a 512 byte boundary
- *
- * 4.2.14.9 SMB_QUERY_FILE_ALT_NAME_INFO
- *
- * Data Block Encoding Description
- * ===================== =================================
- * ULONG FileNameLength Length of the file name in number of bytes
- * STRING FileName Name of the file
- *
- * 4.2.14.10 SMB_QUERY_FILE_STREAM_INFO
- *
- * Data Block Encoding Description
- * =============================== ====================================
- * ULONG NextEntryOffset Offset to the next entry (in bytes)
- * ULONG StreamNameLength Length of the stream name in # of bytes
- * LARGE_INTEGER StreamSize Size of the stream in number of bytes
- * LARGE_INTEGER AllocationSize Allocated size of stream in bytes
- * STRING FileName Name of the stream
- *
- * 4.2.14.11 SMB_QUERY_FILE_COMPRESSION_INFO
- *
- * Data Block Encoding Description
- * =============================== ====================================
- * LARGE_INTEGER Size of the compressed file in
- * CompressedFileSize number of bytes
- * USHORT CompressionFormat compression algorithm used
- * UCHAR CompressionUnitShift Size of the stream in number of bytes
- * UCHAR ChunkShift Allocated size of the stream in # of bytes
- * UCHAR ClusterShift Allocated size of the stream in # of bytes
- * UCHAR Reserved[3] Name of the stream
- *
- * typedef struct {
- * LARGE_INTEGER CompressedFileSize;
- * USHORT CompressionFormat;
- * UCHAR CompressionUnitShift;
- * UCHAR ChunkShift;
- * UCHAR ClusterShift;
- * UCHAR Reserved[3];
- * } FILE_COMPRESSION_INFORMATION;
- */
-
-#include <smbsrv/smb_incl.h>
-#include <smbsrv/msgbuf.h>
-#include <smbsrv/smb_vops.h>
-#include <smbsrv/smb_fsops.h>
-
-int smb_query_all_info_filename(smb_tree_t *, smb_node_t *, char *, size_t);
-extern void smb_encode_smb_datetimes(smb_request_t *, smb_xa_t *, smb_attr_t *);
-extern void smb_encode_nt_times(smb_request_t *, smb_xa_t *, smb_attr_t *);
-
-/*
- * Function: int smb_com_trans2_query_path_information(struct smb_request *)
- */
-smb_sdrc_t
-smb_com_trans2_query_path_information(struct smb_request *sr, struct smb_xa *xa)
-{
- char *path, *alt_nm_ptr;
- int rc;
- u_offset_t datasz, allocsz;
- unsigned short infolev, dattr;
- smb_attr_t *ap, ret_attr;
- struct smb_node *dir_node;
- struct smb_node *node;
- char *name, *namep;
- char short_name[SMB_SHORTNAMELEN];
- char name83[SMB_SHORTNAMELEN];
- unsigned char is_dir;
- unsigned char delete_on_close;
- int len;
-
- if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
- smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST, ERRDOS,
- ERROR_INVALID_FUNCTION);
- return (SDRC_ERROR);
- }
-
-
- if (smb_mbc_decodef(&xa->req_param_mb, "%w4.u", sr,
- &infolev, &path) != 0) {
- return (SDRC_ERROR);
- }
-
- /*
- * Some MS clients pass NULL file names
- * NT interprets this as "\"
- */
- if ((len = strlen(path)) == 0)
- path = "\\";
- else {
- if ((len > 1) && (path[len - 1] == '\\')) {
- /*
- * Remove the terminating slash to prevent
- * sending back '.' instead of path name.
- */
- path[len - 1] = 0;
- }
- }
-
- ap = &ret_attr;
- name = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
-
- if ((rc = smb_pathname_reduce(sr, sr->user_cr, path,
- sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dir_node, name))
- != 0) {
- kmem_free(name, MAXPATHLEN);
- if (rc == ENOENT)
- smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
- ERRDOS, ERROR_FILE_NOT_FOUND);
- else
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- if ((rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
- sr->tid_tree->t_snode, dir_node, name, &node)) != 0) {
- smb_node_release(dir_node);
- kmem_free(name, MAXPATHLEN);
-
- if (rc == ENOENT)
- smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
- ERRDOS, ERROR_FILE_NOT_FOUND);
- else
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- smb_node_release(dir_node);
-
- if (smb_node_getattr(sr, node, ap) != 0) {
- smb_node_release(node);
- kmem_free(name, MAXPATHLEN);
- smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
- ERRDOS, ERROR_INTERNAL_ERROR);
- return (SDRC_ERROR);
- }
-
- (void) strcpy(name, node->od_name);
- namep = node->od_name;
- dattr = ap->sa_dosattr;
-
- if (smb_node_is_dir(node)) {
- is_dir = 1;
- /* Win2K and NT reply with the size of directory file */
- datasz = allocsz = 0;
- } else {
- is_dir = 0;
- datasz = ap->sa_vattr.va_size;
- allocsz = ap->sa_vattr.va_nblocks * DEV_BSIZE;
- }
-
- delete_on_close =
- (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) != 0;
-
- /*
- * The number of links reported should be the number of
- * non-deleted links. Thus if delete_on_close is set,
- * decrement the link count.
- */
- if (delete_on_close && ap->sa_vattr.va_nlink > 0)
- --(ap->sa_vattr.va_nlink);
-
-
-
- switch (infolev) {
- case SMB_INFO_STANDARD:
- if (datasz > UINT_MAX)
- datasz = UINT_MAX;
- if (allocsz > UINT_MAX)
- allocsz = UINT_MAX;
-
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- smb_encode_smb_datetimes(sr, xa, ap);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "llw",
- (uint32_t)datasz, (uint32_t)allocsz, dattr);
- break;
-
- case SMB_INFO_QUERY_EA_SIZE:
- if (datasz > UINT_MAX)
- datasz = UINT_MAX;
- if (allocsz > UINT_MAX)
- allocsz = UINT_MAX;
-
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- smb_encode_smb_datetimes(sr, xa, ap);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "llwl",
- (uint32_t)datasz, (uint32_t)allocsz, dattr, 0);
- break;
-
- case SMB_INFO_QUERY_EAS_FROM_LIST:
- case SMB_INFO_QUERY_ALL_EAS:
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
- break;
-
- case SMB_INFO_IS_NAME_VALID:
- break;
-
- case SMB_QUERY_FILE_BASIC_INFO:
- case SMB_FILE_BASIC_INFORMATION:
- /*
- * NT includes 6 undocumented bytes at the end of this
- * response, which are required by NetBench 5.01.
- * Similar change in smb_trans2_query_file_information.c.
- */
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- smb_encode_nt_times(sr, xa, ap);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "w6.", dattr);
- break;
-
- case SMB_QUERY_FILE_STANDARD_INFO:
- case SMB_FILE_STANDARD_INFORMATION:
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- /*
- * Add 2 bytes to pad data to long. It is
- * necessary because Win2k expects the padded bytes.
- */
- (void) smb_mbc_encodef(&xa->rep_data_mb, "qqlbb2.",
- (uint64_t)allocsz,
- (uint64_t)datasz,
- ap->sa_vattr.va_nlink,
- delete_on_close,
- (char)(ap->sa_vattr.va_type == VDIR));
- break;
-
- case SMB_QUERY_FILE_EA_INFO:
- case SMB_FILE_EA_INFORMATION:
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0);
- break;
-
- case SMB_QUERY_FILE_NAME_INFO:
- case SMB_FILE_NAME_INFORMATION:
- /* If the leading \ is missing, add it. */
- if (*namep != '\\') {
- (void) snprintf(name, MAXNAMELEN, "\\%s", namep);
- namep = name;
- }
- len = smb_ascii_or_unicode_strlen(sr, namep);
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr, len, namep);
- break;
-
- case SMB_QUERY_FILE_ALL_INFO:
- case SMB_FILE_ALL_INFORMATION:
- rc = smb_query_all_info_filename(sr->tid_tree, node,
- name, MAXPATHLEN);
- if (rc != 0) {
- smbsr_errno(sr, rc);
- smb_node_release(node);
- kmem_free(name, MAXPATHLEN);
- return (SDRC_ERROR);
- }
-
- /*
- * There is a 6-byte pad between Attributes and AllocationSize,
- * and a 2-byte pad after the Directory field.
- */
- rc = smb_query_all_info_filename(sr->tid_tree, node,
- name, MAXPATHLEN);
- if (rc != 0) {
- smbsr_errno(sr, rc);
- smb_node_release(node);
- kmem_free(name, MAXPATHLEN);
- return (SDRC_ERROR);
- }
-
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- smb_encode_nt_times(sr, xa, ap);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "w6.qqlbb2.l",
- dattr,
- (uint64_t)allocsz,
- (uint64_t)datasz,
- ap->sa_vattr.va_nlink,
- 0,
- is_dir,
- 0);
-
- (void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr,
- smb_ascii_or_unicode_strlen(sr, name), name);
- break;
-
- case SMB_QUERY_FILE_ALT_NAME_INFO:
- case SMB_FILE_ALT_NAME_INFORMATION:
- /*
- * If the shortname is generated by smb_mangle_name()
- * it will be returned as the alternative name.
- * Otherwise, convert the original name to upper-case
- * and return it as the alternative name.
- */
- (void) smb_mangle_name(ap->sa_vattr.va_nodeid,
- name, short_name, name83, 0);
- alt_nm_ptr = ((*short_name == 0) ?
- utf8_strupr(name) : short_name);
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "%lU", sr,
- mts_wcequiv_strlen(alt_nm_ptr), alt_nm_ptr);
- break;
-
- case SMB_QUERY_FILE_STREAM_INFO:
- case SMB_FILE_STREAM_INFORMATION:
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- smb_encode_stream_info(sr, xa, node, ap);
- break;
-
- case SMB_QUERY_FILE_COMPRESSION_INFO:
- case SMB_FILE_COMPRESSION_INFORMATION:
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb,
- "qwbbb3.", datasz, 0, 0, 0, 0);
- break;
-
- case SMB_FILE_INTERNAL_INFORMATION:
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "q",
- ap->sa_vattr.va_nodeid);
- break;
-
- case SMB_FILE_ATTR_TAG_INFORMATION:
- /*
- * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the
- * second dword should be the reparse tag. Otherwise
- * the tag value should be set to zero.
- * We don't support reparse points, so we set the tag
- * to zero.
- */
- (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
- (void) smb_mbc_encodef(&xa->rep_data_mb, "ll",
- (uint32_t)dattr, 0);
- break;
-
- default:
- smb_node_release(node);
- kmem_free(name, MAXPATHLEN);
- smbsr_error(sr, 0, ERRDOS, ERRunknownlevel);
- return (SDRC_ERROR);
- }
-
- smb_node_release(node);
- kmem_free(name, MAXPATHLEN);
- return (SDRC_SUCCESS);
-}
-
-
-/*
- * smb_query_all_info_filename
- *
- * This format of filename is only used by the ALL_INFO level.
- *
- * Determine the absolute pathname of 'node' within the share.
- * For example if the node represents file "test1.txt" in directory
- * "dir1" on share "share1", the path would be: \share1\dir1\test1.txt
- *
- * If node represents a named stream, construct the pathname for the
- * associated unnamed stream then append the stream name.
- */
-int
-smb_query_all_info_filename(smb_tree_t *tree, smb_node_t *node,
- char *buf, size_t buflen)
-{
- char *sharename = tree->t_sharename;
- int rc;
- size_t len;
- vnode_t *vp;
-
- len = snprintf(buf, buflen, "\\%s", sharename);
- if (len == (buflen - 1))
- return (ENAMETOOLONG);
-
- buf += len;
- buflen -= len;
-
- if (SMB_IS_STREAM(node))
- vp = node->n_unode->vp;
- else
- vp = node->vp;
-
- rc = vnodetopath(tree->t_snode->vp, vp, buf, buflen, kcred);
- if (rc == 0) {
- (void) strsubst(buf, '/', '\\');
-
- if (SMB_IS_STREAM(node))
- (void) strlcat(buf, node->od_name, buflen);
- }
-
- return (rc);
-}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c
deleted file mode 100644
index c57c58d8aa..0000000000
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c
+++ /dev/null
@@ -1,160 +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.
- */
-
-/*
- * SMB: trans2_set_file_information
- *
- * This request is used to set information about a specific file or
- * subdirectory given a handle to the file or subdirectory.
- *
- * Client Request Value
- * ========================== ==========================================
- *
- * WordCount 15
- * MaxSetupCount 0
- * SetupCount 1
- * Setup[0] TRANS2_SET_FILE_INFORMATION
- *
- * Parameter Block Encoding Description
- * ========================== ==========================================
- *
- * USHORT Fid; Handle of file for request
- * USHORT InformationLevel; Level of information requested
- * USHORT Reserved; Ignored by the server
- *
- * The following InformationLevels may be set:
- *
- * Information Level Value
- * ================================ =====
- *
- * SMB_INFO_STANDARD 1
- * SMB_INFO_QUERY_EA_SIZE 2
- * SMB_SET_FILE_BASIC_INFO 0x101
- * SMB_SET_FILE_DISPOSITION_INFO 0x102
- * SMB_SET_FILE_ALLOCATION_INFO 0x103
- * SMB_SET_FILE_END_OF_FILE_INFO 0x104
- *
- * The two levels below 0x101 are as described in the
- * NT_SET_PATH_INFORMATION transaction. The requested information is
- * placed in the Data portion of the transaction response. For the
- * information levels greater than 0x100, the transaction response has 1
- * parameter word which should be ignored by the client.
- *
- * 4.2.17.1 SMB_FILE_DISPOSITION_INFO
- *
- * Response Field Value
- * ==================== ===============================================
- *
- * BOOLEAN A boolean which is TRUE if the file is marked
- * FileIsDeleted for deletion
- *
- * 4.2.17.2 SMB_FILE_ALLOCATION_INFO
- *
- * Response Field Value
- * ==================== ===============================================
- *
- * LARGE_INTEGER File Allocation size in number of bytes
- *
- * 4.2.17.3 SMB_FILE_END_OF_FILE_INFO
- *
- * Response Field Value
- * ==================== ===============================================
- *
- * LARGE_INTEGER The total number of bytes that need to be
- * traversed from the beginning of the file in
- * order to locate the end of the file
- *
- * Undocumented things:
- * Poorly documented information levels. Information must be infered
- * from other commands.
- *
- * NULL Attributes means don't set them. NT sets the high bit to
- * set attributes to 0.
- */
-
-#include <smbsrv/smb_incl.h>
-
-/*
- * smb_com_trans2_set_file_information
- */
-smb_sdrc_t
-smb_com_trans2_set_file_information(struct smb_request *sr, struct smb_xa *xa)
-{
- smb_trans2_setinfo_t *info;
- smb_error_t smberr;
- uint32_t status;
- int rc;
-
- info = kmem_zalloc(sizeof (smb_trans2_setinfo_t), KM_SLEEP);
- info->ts_xa = xa;
-
- rc = smb_mbc_decodef(&xa->req_param_mb, "ww", &sr->smb_fid,
- &info->level);
- if (rc != 0) {
- kmem_free(info, sizeof (smb_trans2_setinfo_t));
- return (SDRC_ERROR);
- }
-
- if (!STYPE_ISDSK(sr->tid_tree->t_res_type) ||
- SMB_TREE_IS_READONLY(sr)) {
- kmem_free(info, sizeof (smb_trans2_setinfo_t));
- smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
- ERRDOS, ERROR_ACCESS_DENIED);
- return (SDRC_ERROR);
- }
-
- smbsr_lookup_file(sr);
- if (sr->fid_ofile == NULL) {
- kmem_free(info, sizeof (smb_trans2_setinfo_t));
- smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
- return (SDRC_ERROR);
- }
-
- sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
-
- info->node = sr->fid_ofile->f_node;
-
- if (info->node == 0 ||
- !SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) {
- cmn_err(CE_NOTE, "SmbT2SetFileInfo: access denied");
- kmem_free(info, sizeof (smb_trans2_setinfo_t));
- smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
- ERRDOS, ERROR_ACCESS_DENIED);
- return (SDRC_ERROR);
- }
-
- status = smb_trans2_set_information(sr, info, &smberr);
- kmem_free(info, sizeof (smb_trans2_setinfo_t));
-
- if (status == NT_STATUS_DATA_ERROR)
- return (SDRC_ERROR);
-
- if (status != NT_STATUS_SUCCESS) {
- smbsr_error(sr, smberr.status, smberr.errcls, smberr.errcode);
- return (SDRC_ERROR);
- }
-
- return (SDRC_SUCCESS);
-}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c
deleted file mode 100644
index 8c8efeb7a0..0000000000
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c
+++ /dev/null
@@ -1,386 +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.
- */
-
-/*
- * This file contains the common code used by
- * Trans2SetFileInfo and Trans2SetPathInfo SMBs.
- */
-
-#include <smbsrv/smb_incl.h>
-#include <smbsrv/smb_fsops.h>
-
-static uint32_t smb_set_standard_info(smb_request_t *,
- smb_trans2_setinfo_t *, smb_error_t *);
-
-static uint32_t smb_set_basic_info(smb_request_t *,
- smb_trans2_setinfo_t *, smb_error_t *);
-
-static uint32_t smb_set_disposition_info(smb_request_t *,
- smb_trans2_setinfo_t *, smb_error_t *);
-
-static uint32_t smb_set_alloc_info(smb_request_t *sr,
- smb_trans2_setinfo_t *, smb_error_t *);
-
-/*LINTED E_STATIC_UNUSED*/
-static uint32_t smb_set_mac_info(smb_request_t *,
- smb_trans2_setinfo_t *, smb_error_t *);
-
-/*LINTED E_STATIC_UNUSED*/
-static uint32_t smb_set_mac_addappl(smb_request_t *,
- smb_trans2_setinfo_t *, smb_error_t *);
-
-/*LINTED E_STATIC_UNUSED*/
-static uint32_t smb_set_mac_rmvappl(smb_request_t *,
- smb_trans2_setinfo_t *, smb_error_t *);
-
-/*LINTED E_STATIC_UNUSED*/
-static uint32_t smb_set_mac_addicon(smb_request_t *,
- smb_trans2_setinfo_t *, smb_error_t *);
-
-static unsigned short smb_info_passthru(unsigned short infolevel);
-
-/*
- * smb_trans2_set_information
- *
- * This is a common function called by both Trans2SetFileInfo
- * and Trans2SetPathInfo.
- */
-uint32_t
-smb_trans2_set_information(smb_request_t *sr, smb_trans2_setinfo_t *info,
- smb_error_t *smberr)
-{
- info->level = smb_info_passthru(info->level);
-
- switch (info->level) {
- case SMB_INFO_STANDARD:
- return (smb_set_standard_info(sr, info, smberr));
-
- case SMB_INFO_SET_EAS:
- /* EAs not supported */
- return (NT_STATUS_SUCCESS);
-
- case SMB_SET_FILE_BASIC_INFO:
- return (smb_set_basic_info(sr, info, smberr));
-
- case SMB_SET_FILE_DISPOSITION_INFO:
- return (smb_set_disposition_info(sr, info, smberr));
-
- case SMB_SET_FILE_END_OF_FILE_INFO:
- case SMB_SET_FILE_ALLOCATION_INFO:
- return (smb_set_alloc_info(sr, info, smberr));
-
- default:
- break;
- }
-
- smberr->status = NT_STATUS_INVALID_INFO_CLASS;
- smberr->errcls = ERRDOS;
- smberr->errcode = ERROR_INVALID_PARAMETER;
- return (NT_STATUS_UNSUCCESSFUL);
-}
-
-/*
- * smb_info_passthru
- *
- * SMB_INFO_PASSTHROUGH
- * If the server supports information level request passing through,
- * the client may add the information level with SMB_INFO_PASSTHROUGH
- * and submit the file information in NT data format instead of SMB
- * data format. Please refer to MSDN for related NT file information
- * data structure.
- *
- * SMB_INFO_PASSTHROUGH (1000) is defined in win32/cifs.h and the file
- * information class values are defined in win32/ntifs.h. we have
- * observed:
- * 0x3EC = SMB_INFO_PASSTHROUGH + FileBasicInformation (4)
- * 0x3F5 = SMB_INFO_PASSTHROUGH + FileDispositionInformation (13)
- * 0x3FC = SMB_INFO_PASSTHROUGH + FileEndOfFileInformation (20)
- *
- * Based on network traces between two Win2K systems:
- * FileBasicInformation <=> SMB_SET_FILE_BASIC_INFO
- * FileDispositionInformation <=> SMB_SET_FILE_DISPOSITION_INFO
- * FileEndOfFileInformation <=> SMB_SET_FILE_END_OF_FILE_INFO
- */
-static unsigned short
-smb_info_passthru(unsigned short infolevel)
-{
- if (infolevel <= SMB_INFO_PASSTHROUGH)
- return (infolevel);
-
- infolevel -= SMB_INFO_PASSTHROUGH;
-
- switch (infolevel) {
- case FileBasicInformation:
- return (SMB_SET_FILE_BASIC_INFO);
-
- case FileDispositionInformation:
- return (SMB_SET_FILE_DISPOSITION_INFO);
-
- case FileEndOfFileInformation:
- return (SMB_SET_FILE_END_OF_FILE_INFO);
-
- case FileAllocationInformation:
- return (SMB_SET_FILE_ALLOCATION_INFO);
- }
-
- return (infolevel);
-}
-
-/*
- * smb_set_standard_info
- *
- * Sets standard file/path information.
- */
-static uint32_t
-smb_set_standard_info(smb_request_t *sr, smb_trans2_setinfo_t *info,
- smb_error_t *smberr)
-{
- smb_attr_t attr;
- uint32_t Creation, LastAccess, LastWrite; /* times */
- uint32_t status = NT_STATUS_SUCCESS;
- smb_node_t *node = info->node;
- int rc;
-
- if (smb_mbc_decodef(&info->ts_xa->req_data_mb, "yyy",
- &Creation, /* CreationDate/Time */
- &LastAccess, /* LastAccessDate/Time */
- &LastWrite) != 0) { /* LastWriteDate/Time */
- return (NT_STATUS_DATA_ERROR);
- }
-
- bzero(&attr, sizeof (smb_attr_t));
-
- /*
- * The behaviour when the time field is set to -1
- * is not documented but is generally treated like 0,
- * meaning that that server file system assigned value
- * need not be changed.
- */
- if (LastWrite != 0 && LastWrite != (uint32_t)-1) {
- attr.sa_vattr.va_mtime.tv_sec = smb_local2gmt(sr, LastWrite);
- attr.sa_mask |= SMB_AT_MTIME;
- }
-
- if (Creation != 0 && Creation != (uint32_t)-1) {
- attr.sa_crtime.tv_sec = smb_local2gmt(sr, Creation);
- attr.sa_mask |= SMB_AT_CRTIME;
- }
-
- if (LastAccess != 0 && LastAccess != (uint32_t)-1) {
- attr.sa_vattr.va_atime.tv_sec = smb_local2gmt(sr, LastAccess);
- attr.sa_mask |= SMB_AT_ATIME;
- }
-
- rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
- if (rc) {
- smbsr_map_errno(rc, smberr);
- status = NT_STATUS_UNSUCCESSFUL;
- }
-
- return (status);
-}
-
-/*
- * smb_set_basic_info
- *
- * Sets basic file/path information.
- */
-static uint32_t
-smb_set_basic_info(smb_request_t *sr, smb_trans2_setinfo_t *info,
- smb_error_t *smberr)
-{
- smb_attr_t attr;
- uint64_t NT_Creation, NT_LastAccess, NT_LastWrite, NT_Change;
- unsigned short Attributes;
- smb_node_t *node = info->node;
- uint32_t status = NT_STATUS_SUCCESS;
- int rc;
-
- if (smb_mbc_decodef(&info->ts_xa->req_data_mb, "qqqqw",
- &NT_Creation, /* CreationDate/Time */
- &NT_LastAccess, /* LastAccessDate/Time */
- &NT_LastWrite, /* LastWriteDate/Time */
- &NT_Change, /* LastWriteDate/Time */
- &Attributes) != 0) { /* File Attributes */
- return (NT_STATUS_DATA_ERROR);
- }
-
- bzero(&attr, sizeof (smb_attr_t));
-
- /*
- * The behaviour when the time field is set to -1
- * is not documented but is generally treated like 0,
- * meaning that that server file system assigned value
- * need not be changed.
- */
- if (NT_Change != 0 && NT_Change != (uint64_t)-1) {
- (void) nt_to_unix_time(NT_Change, &attr.sa_vattr.va_ctime);
- attr.sa_mask |= SMB_AT_CTIME;
- }
-
- if (NT_Creation != 0 && NT_Creation != (uint64_t)-1) {
- (void) nt_to_unix_time(NT_Creation, &attr.sa_crtime);
- attr.sa_mask |= SMB_AT_CRTIME;
- }
-
- if (NT_LastWrite != 0 && NT_LastWrite != (uint64_t)-1) {
- (void) nt_to_unix_time(NT_LastWrite, &attr.sa_vattr.va_mtime);
- attr.sa_mask |= SMB_AT_MTIME;
- }
-
- if (NT_LastAccess != 0 && NT_LastAccess != (uint64_t)-1) {
- (void) nt_to_unix_time(NT_LastAccess, &attr.sa_vattr.va_atime);
- attr.sa_mask |= SMB_AT_ATIME;
- }
-
- /*
- * If Attributes are 0 this means that the file's attributes
- * should be left unchanged. If the client wanted to 0 (clear)
- * all of the attributes Attributes would be FILE_ATTRIBUTE_NORMAL.
- * Note - this is different from SMBsetatr (SMBSetInformation).
- *
- * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the
- * target is not a directory.
- */
- if (Attributes != 0) {
- if ((Attributes & FILE_ATTRIBUTE_DIRECTORY) &&
- (!smb_node_is_dir(node))) {
- smberr->status = NT_STATUS_INVALID_PARAMETER;
- smberr->errcls = ERRDOS;
- smberr->errcode = ERROR_INVALID_PARAMETER;
- return (NT_STATUS_UNSUCCESSFUL);
- }
-
- attr.sa_dosattr = Attributes;
- attr.sa_mask |= SMB_AT_DOSATTR;
- }
-
- rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
- if (rc) {
- smbsr_map_errno(rc, smberr);
- status = NT_STATUS_UNSUCCESSFUL;
- }
-
- return (status);
-}
-
-
-/*
- * smb_set_alloc_info
- *
- * Sets file allocation/end_of_file info
- */
-static uint32_t
-smb_set_alloc_info(smb_request_t *sr, smb_trans2_setinfo_t *info,
- smb_error_t *smberr)
-{
- smb_attr_t attr;
- uint64_t DataSize;
- uint32_t status = NT_STATUS_SUCCESS;
- smb_node_t *node = info->node;
- int rc;
-
- if (smb_mbc_decodef(&info->ts_xa->req_data_mb, "q", &DataSize) != 0)
- return (NT_STATUS_DATA_ERROR);
-
- bzero(&attr, sizeof (smb_attr_t));
- attr.sa_mask = SMB_AT_SIZE;
- attr.sa_vattr.va_size = (u_offset_t)DataSize;
- rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr);
- if (rc) {
- smbsr_map_errno(rc, smberr);
- status = NT_STATUS_UNSUCCESSFUL;
- }
-
- return (status);
-}
-
-/*
- * smb_set_disposition_info
- *
- * Set/Clear DELETE_ON_CLOSE flag for an open file.
- * File should have been opened with DELETE access otherwise
- * the operation is not permitted.
- *
- * NOTE: The node should be marked delete-on-close upon the receipt
- * of the Trans2SetFileInfo(SetDispositionInfo) if mark_delete is set.
- * It is different than both SmbNtCreateAndX and SmbNtTransact, which
- * set delete-on-close on the ofile and defer setting the flag on the
- * node until the file is closed.
- *
- * Observation of Windows 2000 indicates the following:
- *
- * 1) If a file is not opened with delete-on-close create options and
- * the delete-on-close is set via Trans2SetFileInfo(SetDispositionInfo)
- * using that open file handle, any subsequent open requests will fail
- * with DELETE_PENDING.
- *
- * 2) If a file is opened with delete-on-close create options and the
- * client attempts to unset delete-on-close via Trans2SetFileInfo
- * (SetDispositionInfo) prior to the file close, any subsequent open
- * requests will still fail with DELETE_PENDING after the file is closed.
- *
- * 3) If a file is opened with delete-on-close create options and that
- * file handle (not the last open handle and the only file handle
- * with delete-on-close set) is closed. Any subsequent open requests
- * will fail with DELETE_PENDING. Unsetting delete-on-close via
- * Trans2SetFileInfo(SetDispositionInfo) at this time will unset the
- * node delete-on-close flag, which will result in the file not being
- * removed even after the last file handle is closed.
- */
-static uint32_t
-smb_set_disposition_info(smb_request_t *sr, smb_trans2_setinfo_t *info,
- smb_error_t *smberr)
-{
- unsigned char mark_delete;
- uint32_t flags = 0;
-
- if (smb_mbc_decodef(&info->ts_xa->req_data_mb, "b", &mark_delete) != 0)
- return (NT_STATUS_DATA_ERROR);
-
- if ((sr->fid_ofile == NULL) ||
- !(smb_ofile_granted_access(sr->fid_ofile) & DELETE)) {
- smberr->status = NT_STATUS_ACCESS_DENIED;
- smberr->errcls = ERRDOS;
- smberr->errcode = ERROR_ACCESS_DENIED;
- return (NT_STATUS_UNSUCCESSFUL);
- }
-
- if (mark_delete) {
- if (SMB_TREE_SUPPORTS_CATIA(sr))
- flags |= SMB_CATIA;
-
- if (smb_node_set_delete_on_close(info->node,
- sr->user_cr, flags)) {
- smberr->status = NT_STATUS_CANNOT_DELETE;
- smberr->errcls = ERRDOS;
- smberr->errcode = ERROR_ACCESS_DENIED;
- return (NT_STATUS_UNSUCCESSFUL);
- }
- } else {
- smb_node_reset_delete_on_close(info->node);
- }
- return (NT_STATUS_SUCCESS);
-}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c
deleted file mode 100644
index 204018072d..0000000000
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_path_information.c
+++ /dev/null
@@ -1,180 +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.
- */
-/*
- * SMB: trans2_set_path_information
- *
- * This request is used to set information about a specific file or
- * subdirectory.
- *
- * Client Request Value
- * ========================== =========================================
- *
- * WordCount 15
- * MaxSetupCount 0
- * SetupCount 1
- * Setup[0] TRANS2_SET_PATH_INFORMATION
- *
- * Parameter Block Encoding Description
- * ========================== =========================================
- *
- * USHORT InformationLevel; Level of information to set
- * ULONG Reserved; Must be zero
- * STRING FileName; File or directory name
- *
- * The following InformationLevels may be set:
- *
- * Information Level Value
- * ========================== =========================================
- *
- * SMB_INFO_STANDARD 1
- * SMB_INFO_QUERY_EA_SIZE 2
- * SMB_INFO_QUERY_ALL_EAS 4
- *
- * The response formats are:
- *
- * 4.2.16.1 SMB_INFO_STANDARD & SMB_INFO_QUERY_EA_SIZE
- *
- * Parameter Block Encoding Description
- * ================================== =================================
- *
- * USHORT Reserved 0
- *
- * Data Block Encoding Description
- * ================================== =================================
- *
- * SMB_DATE CreationDate; Date when file was created
- * SMB_TIME CreationTime; Time when file was created
- * SMB_DATE LastAccessDate; Date of last file access
- * SMB_TIME LastAccessTime; Time of last file access
- * SMB_DATE LastWriteDate; Date of last write to the file
- * SMB_TIME LastWriteTime; Time of last write to the file
- * ULONG DataSize; File Size
- * ULONG AllocationSize; Size of filesystem allocation
- * unit
- * USHORT Attributes; File Attributes
- * ULONG EaSize; Size of file's EA information
- * (SMB_INFO_QUERY_EA_SIZE)
- *
- * 4.2.16.2 SMB_INFO_QUERY_ALL_EAS
- *
- * Response Field Value
- * ==================== ===============================================
- *
- * MaxDataCount Length of FEAlist found (minimum value is 4)
- *
- * Parameter Block Description
- * Encoding ===============================================
- * ====================
- *
- * USHORT EaErrorOffset Offset into EAList of EA error
- *
- * Data Block Encoding Description
- * ==================== ===============================================
- *
- * ULONG ListLength; Length of the remaining data
- * UCHAR EaList[] The extended attributes list
- *
- * Undocumented things:
- * Poorly documented information levels. Information must be infered
- * from other commands.
- *
- * NULL Attributes means don't set them. NT sets the high bit to
- * set attributes to 0.
- */
-
-#include <smbsrv/smb_incl.h>
-#include <smbsrv/smb_fsops.h>
-
-smb_sdrc_t
-smb_com_trans2_set_path_information(struct smb_request *sr, struct smb_xa *xa)
-{
- smb_trans2_setinfo_t *info;
- struct smb_node *dir_node;
- struct smb_node *ret_snode;
- smb_error_t smberr;
- uint32_t status;
- int rc = 0;
-
- info = kmem_zalloc(sizeof (smb_trans2_setinfo_t), KM_SLEEP);
- info->ts_xa = xa;
-
- if (smb_mbc_decodef(&xa->req_param_mb, "%w4.u", sr, &info->level,
- &info->path) != 0) {
- kmem_free(info, sizeof (smb_trans2_setinfo_t));
- return (SDRC_ERROR);
- }
-
- if (!STYPE_ISDSK(sr->tid_tree->t_res_type) ||
- SMB_TREE_IS_READONLY(sr)) {
- kmem_free(info, sizeof (smb_trans2_setinfo_t));
- smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
- ERRDOS, ERROR_ACCESS_DENIED);
- return (SDRC_ERROR);
- }
-
- rc = smb_pathname_reduce(sr, sr->user_cr, info->path,
- sr->tid_tree->t_snode, sr->tid_tree->t_snode,
- &dir_node, info->name);
-
- if (rc != 0) {
- kmem_free(info, sizeof (smb_trans2_setinfo_t));
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS,
- sr->tid_tree->t_snode, dir_node, info->name, &ret_snode);
-
- smb_node_release(dir_node);
-
- if (rc != 0) {
- kmem_free(info, sizeof (smb_trans2_setinfo_t));
- smbsr_errno(sr, rc);
- return (SDRC_ERROR);
- }
-
- if (smb_oplock_conflict(ret_snode, sr->session, NULL)) {
- /*
- * for the benefit of attribute setting later on
- */
- (void) smb_oplock_break(ret_snode, sr->session, B_FALSE);
- }
-
- info->node = ret_snode;
- status = smb_trans2_set_information(sr, info, &smberr);
- info->node = NULL;
- smb_node_release(ret_snode);
- kmem_free(info, sizeof (smb_trans2_setinfo_t));
-
- if (status == NT_STATUS_DATA_ERROR)
- return (SDRC_ERROR);
-
- if (status != NT_STATUS_SUCCESS) {
- smbsr_error(sr, smberr.status, smberr.errcls, smberr.errcode);
- return (SDRC_ERROR);
- }
-
- return (SDRC_SUCCESS);
-}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_tree.c b/usr/src/uts/common/fs/smbsrv/smb_tree.c
index 66c3095851..ebe14f4cae 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_tree.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree.c
@@ -581,6 +581,11 @@ smb_tree_connect_disk(smb_request_t *sr, const char *sharename)
break;
}
+ /* ABE support */
+ if (si->shr_flags & SMB_SHRF_ABE)
+ sr->arg.tcon.optional_support |=
+ SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM;
+
access = si->shr_access_value & SMB_SHRF_ACC_ALL;
if (access == SMB_SHRF_ACC_RO) {
@@ -1022,6 +1027,9 @@ smb_tree_get_flags(const smb_share_t *si, vfs_t *vfsp, smb_tree_t *tree)
if (si->shr_flags & SMB_SHRF_CATIA)
flags |= SMB_TREE_CATIA;
+ if (si->shr_flags & SMB_SHRF_ABE)
+ flags |= SMB_TREE_ABE;
+
if (vfsp->vfs_flag & VFS_RDONLY)
flags |= SMB_TREE_READONLY;
diff --git a/usr/src/uts/common/fs/smbsrv/smb_util.c b/usr/src/uts/common/fs/smbsrv/smb_util.c
index dab839fbf9..870c68ae51 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_util.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_util.c
@@ -1613,32 +1613,64 @@ smb_idmap_batch_getmappings(smb_idmap_batch_t *sib)
}
uint64_t
-unix_to_nt_time(timestruc_t *unix_time)
+smb_time_unix_to_nt(timestruc_t *unix_time)
{
uint64_t nt_time;
+ if ((unix_time->tv_sec == 0) && (unix_time->tv_nsec == 0))
+ return (0);
+
nt_time = unix_time->tv_sec;
nt_time *= 10000000; /* seconds to 100ns */
nt_time += unix_time->tv_nsec / 100;
return (nt_time + NT_TIME_BIAS);
}
-uint32_t
-nt_to_unix_time(uint64_t nt_time, timestruc_t *unix_time)
+void
+smb_time_nt_to_unix(uint64_t nt_time, timestruc_t *unix_time)
{
uint32_t seconds;
+ ASSERT(unix_time);
+
+ if ((nt_time == 0) || (nt_time == -1)) {
+ unix_time->tv_sec = 0;
+ unix_time->tv_nsec = 0;
+ return;
+ }
+
nt_time -= NT_TIME_BIAS;
seconds = nt_time / 10000000;
- if (unix_time) {
- unix_time->tv_sec = seconds;
- unix_time->tv_nsec = (nt_time % 10000000) * 100;
- }
- return (seconds);
+ unix_time->tv_sec = seconds;
+ unix_time->tv_nsec = (nt_time % 10000000) * 100;
+}
+
+/*
+ * smb_time_gmt_to_local, smb_time_local_to_gmt
+ *
+ * Apply the gmt offset to convert between local time and gmt
+ */
+int32_t
+smb_time_gmt_to_local(smb_request_t *sr, int32_t gmt)
+{
+ if ((gmt == 0) || (gmt == -1))
+ return (0);
+
+ return (gmt - sr->sr_gmtoff);
}
+int32_t
+smb_time_local_to_gmt(smb_request_t *sr, int32_t local)
+{
+ if ((local == 0) || (local == -1))
+ return (0);
+
+ return (local + sr->sr_gmtoff);
+}
+
+
/*
- * smb_dos_to_ux_time
+ * smb_time_dos_to_unix
*
* Convert SMB_DATE & SMB_TIME values to a unix timestamp.
*
@@ -1650,7 +1682,7 @@ nt_to_unix_time(uint64_t nt_time, timestruc_t *unix_time)
* so that the caller can identify and handle this special case.
*/
int32_t
-smb_dos_to_ux_time(int16_t date, int16_t time)
+smb_time_dos_to_unix(int16_t date, int16_t time)
{
struct tm atm;
@@ -1669,13 +1701,19 @@ smb_dos_to_ux_time(int16_t date, int16_t time)
return (smb_timegm(&atm));
}
-int32_t
-smb_ux_to_dos_time(int32_t ux_time, int16_t *date_p, int16_t *time_p)
+void
+smb_time_unix_to_dos(int32_t ux_time, int16_t *date_p, int16_t *time_p)
{
struct tm atm;
int i;
time_t tmp_time;
+ if (ux_time == 0) {
+ *date_p = 0;
+ *time_p = 0;
+ return;
+ }
+
tmp_time = (time_t)ux_time;
(void) smb_gmtime_r(&tmp_time, &atm);
@@ -1699,7 +1737,6 @@ smb_ux_to_dos_time(int32_t ux_time, int16_t *date_p, int16_t *time_p)
*time_p = (short)i;
}
- return (ux_time);
}
diff --git a/usr/src/uts/common/fs/smbsrv/smb_vops.c b/usr/src/uts/common/fs/smbsrv/smb_vops.c
index 9cda0fe7cf..386e02af4b 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_vops.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_vops.c
@@ -890,13 +890,15 @@ smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr)
* If the file system supports extended directory entries (has features
* VFSFT_DIRENTFLAGS), set V_RDDIR_ENTFLAGS to cause the buffer to be
* filled with edirent_t structures, instead of dirent64_t structures.
+ * If the file system supports access based enumeration (abe), set
+ * V_RDDIR_ACCFILTER to filter directory entries based on user cred.
*/
int
smb_vop_readdir(vnode_t *vp, uint32_t offset,
- void *buf, int *count, int *eof, cred_t *cr)
+ void *buf, int *count, int *eof, uint32_t rddir_flag, cred_t *cr)
{
int error = 0;
- int rdirent_flags = 0;
+ int flags = 0;
int rdirent_size;
struct uio auio;
struct iovec aiov;
@@ -905,7 +907,7 @@ smb_vop_readdir(vnode_t *vp, uint32_t offset,
return (ENOTDIR);
if (vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS)) {
- rdirent_flags = V_RDDIR_ENTFLAGS;
+ flags |= V_RDDIR_ENTFLAGS;
rdirent_size = sizeof (edirent_t);
} else {
rdirent_size = sizeof (dirent64_t);
@@ -914,6 +916,9 @@ smb_vop_readdir(vnode_t *vp, uint32_t offset,
if (*count < rdirent_size)
return (EINVAL);
+ if (rddir_flag & SMB_ABE)
+ flags |= V_RDDIR_ACCFILTER;
+
aiov.iov_base = buf;
aiov.iov_len = *count;
auio.uio_iov = &aiov;
@@ -924,7 +929,7 @@ smb_vop_readdir(vnode_t *vp, uint32_t offset,
auio.uio_fmode = 0;
(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &smb_ct);
- error = VOP_READDIR(vp, &auio, cr, eof, &smb_ct, rdirent_flags);
+ error = VOP_READDIR(vp, &auio, cr, eof, &smb_ct, flags);
VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &smb_ct);
if (error == 0)
diff --git a/usr/src/uts/common/fs/smbsrv/smb_write_raw.c b/usr/src/uts/common/fs/smbsrv/smb_write_raw.c
index 1872c9ef46..a1d7948412 100644
--- a/usr/src/uts/common/fs/smbsrv/smb_write_raw.c
+++ b/usr/src/uts/common/fs/smbsrv/smb_write_raw.c
@@ -349,11 +349,10 @@ smb_com_write_raw(struct smb_request *sr)
/*
* smb_write_raw_helper will call smb_opipe_write or
- * smb_fsop_write as appropriate, handle the NODE_FLAGS_SET_SIZE
- * flag (if set) and update the other f_node fields. It's possible
- * that data_length may be 0 for this transfer but we still want
- * process it since it will update the file state (seek position,
- * file size (possibly), etc).
+ * smb_fsop_write as appropriate, and update the other f_node fields.
+ * It's possible that data_length may be 0 for this transfer but
+ * we still want to process it since it will update the file state
+ * (seek position, file size (possibly), etc).
*/
rc = smb_write_raw_helper(sr, &uio, stability, &off, &lcount);
@@ -475,11 +474,11 @@ notify_write_raw_complete:
/*
* smb_write_raw_helper
*
- * This function will call smb_opipe_write or smb_fsop_write as appropriate,
- * handle the NODE_FLAGS_SET_SIZE flag (if set) and update the other f_node
- * fields. It's possible that data_length may be 0 for this transfer but
- * we still want process it since it will update the file state (seek
- * position, file size (possibly), etc).
+ * This function will call smb_opipe_write or smb_fsop_write
+ * as appropriate, and update the other f_node fields.
+ * It's possible that data_length may be 0 for this transfer but
+ * we still want process it since it will update the file state
+ * (seek position, file size (possibly), etc).
*
* Returns 0 for success, non-zero for failure
*/
diff --git a/usr/src/uts/common/rpcsvc/idmap_prot.x b/usr/src/uts/common/rpcsvc/idmap_prot.x
index 3485fab29c..81b0ab6ca5 100644
--- a/usr/src/uts/common/rpcsvc/idmap_prot.x
+++ b/usr/src/uts/common/rpcsvc/idmap_prot.x
@@ -49,7 +49,8 @@ enum idmap_map_type {
IDMAP_MAP_TYPE_RULE_BASED,
IDMAP_MAP_TYPE_EPHEMERAL,
IDMAP_MAP_TYPE_LOCAL_SID,
- IDMAP_MAP_TYPE_KNOWN_SID
+ IDMAP_MAP_TYPE_KNOWN_SID,
+ IDMAP_MAP_TYPE_IDMU
};
@@ -103,7 +104,7 @@ struct idmap_how_ds_based {
idmap_utf8str attr;
idmap_utf8str value;
};
-
+
union idmap_how switch(idmap_map_type map_type) {
case IDMAP_MAP_TYPE_UNKNOWN: void;
case IDMAP_MAP_TYPE_DS_AD: idmap_how_ds_based ad;
@@ -112,6 +113,7 @@ union idmap_how switch(idmap_map_type map_type) {
case IDMAP_MAP_TYPE_EPHEMERAL: void;
case IDMAP_MAP_TYPE_LOCAL_SID: void;
case IDMAP_MAP_TYPE_KNOWN_SID: void;
+ case IDMAP_MAP_TYPE_IDMU: idmap_how_ds_based idmu;
};
struct idmap_info {
@@ -239,7 +241,7 @@ enum idmap_prop_type {
PROP_AD_UNIXUSER_ATTR = 9,
PROP_AD_UNIXGROUP_ATTR = 10,
PROP_NLDAP_WINNAME_ATTR = 11,
- PROP_DS_NAME_MAPPING_ENABLED = 12
+ PROP_DIRECTORY_BASED_MAPPING = 12
};
union idmap_prop_val switch(idmap_prop_type prop) {
@@ -253,9 +255,8 @@ union idmap_prop_val switch(idmap_prop_type prop) {
case PROP_AD_UNIXUSER_ATTR:
case PROP_AD_UNIXGROUP_ATTR:
case PROP_NLDAP_WINNAME_ATTR:
+ case PROP_DIRECTORY_BASED_MAPPING:
idmap_utf8str utf8val;
- case PROP_DS_NAME_MAPPING_ENABLED:
- bool boolval;
case PROP_DOMAIN_CONTROLLER:
case PROP_GLOBAL_CATALOG:
idmap_ad_disc_ds_t dsval;
diff --git a/usr/src/uts/common/smbsrv/cifs.h b/usr/src/uts/common/smbsrv/cifs.h
index ca8ad6877d..da683f4590 100644
--- a/usr/src/uts/common/smbsrv/cifs.h
+++ b/usr/src/uts/common/smbsrv/cifs.h
@@ -304,6 +304,10 @@ extern "C" {
* allowed and clients are permitted to work from
* their local cache even while offline.
* SMB_CSC_CACHE_NONE Client-side caching is disabled for this share.
+ *
+ * SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM
+ * The server will filter directory entries based
+ * on the access permissions of the client.
*/
#define SMB_SUPPORT_SEARCH_BITS 0x0001
#define SMB_SHARE_IS_IN_DFS 0x0002
@@ -316,6 +320,8 @@ extern "C" {
#define SMB_CSC_CACHE_VDO 0x0008
#define SMB_CSC_CACHE_NONE 0x000C
+#define SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM 0x0800
+
/*
* The subcommand codes, placed in SETUP[0], for named pipe operations are:
* SubCommand Code Value Description
@@ -565,34 +571,46 @@ extern "C" {
#define SMB_MAC_QUERY_FS_INFO MAC_QUERY_FS_INFO
-/* TRANS2_QUERY_{PATH,FILE}_INFORMATION */
+/*
+ * Internal use only.
+ * Define information levels to represent the following requests:
+ * smb_query_information
+ * smb_query_information2
+ * smb_set_information
+ * smb_set_information2
+ */
+#define SMB_QUERY_INFORMATION 0x3001
+#define SMB_QUERY_INFORMATION2 0x3002
+#define SMB_SET_INFORMATION 0x3001
+#define SMB_SET_INFORMATION2 0x3002
-#define SMB_INFO_STANDARD 1
-#define SMB_INFO_QUERY_EA_SIZE 2
-#define SMB_INFO_SET_EAS 2
-#define SMB_INFO_QUERY_EAS_FROM_LIST 3
-#define SMB_INFO_QUERY_ALL_EAS 4
-#define SMB_INFO_QUERY_FULL_NAME 5
-#define SMB_INFO_IS_NAME_VALID 6
+/* TRANS2_QUERY_{PATH,FILE}_INFORMATION */
+#define SMB_INFO_STANDARD 1 /* query, set */
+#define SMB_INFO_QUERY_EA_SIZE 2 /* query */
+#define SMB_INFO_SET_EAS 2 /* set */
+#define SMB_INFO_QUERY_EAS_FROM_LIST 3 /* query */
+#define SMB_INFO_QUERY_ALL_EAS 4 /* query */
+#define SMB_INFO_QUERY_FULL_NAME 5 /* unused */
+#define SMB_INFO_IS_NAME_VALID 6 /* query */
#define SMB_QUERY_FILE_BASIC_INFO 0x101
#define SMB_QUERY_FILE_STANDARD_INFO 0x102
#define SMB_QUERY_FILE_EA_INFO 0x103
#define SMB_QUERY_FILE_NAME_INFO 0x104
-#define SMB_QUERY_FILE_ALLOCATION_INFO 0x105
-#define SMB_QUERY_FILE_END_OF_FILEINFO 0x106
+#define SMB_QUERY_FILE_ALLOCATION_INFO 0x105 /* unused */
+#define SMB_QUERY_FILE_END_OF_FILE_INFO 0x106 /* unused */
#define SMB_QUERY_FILE_ALL_INFO 0x107
#define SMB_QUERY_FILE_ALT_NAME_INFO 0x108
#define SMB_QUERY_FILE_STREAM_INFO 0x109
#define SMB_QUERY_FILE_COMPRESSION_INFO 0x10B
-#define SMB_MAC_SET_FINDER_INFO MAC_SET_FINDER_INFO
-#define SMB_MAC_DT_ADD_APPL MAC_DT_ADD_APPL
-#define SMB_MAC_DT_REMOVE_APPL MAC_DT_REMOVE_APPL
-#define SMB_MAC_DT_GET_APPL MAC_DT_GET_APPL
-#define SMB_MAC_DT_GET_ICON MAC_DT_GET_ICON
-#define SMB_MAC_DT_GET_ICON_INFO MAC_DT_GET_ICON_INFO
-#define SMB_MAC_DT_ADD_ICON MAC_DT_ADD_ICON
+#define SMB_MAC_SET_FINDER_INFO MAC_SET_FINDER_INFO
+#define SMB_MAC_DT_ADD_APPL MAC_DT_ADD_APPL
+#define SMB_MAC_DT_REMOVE_APPL MAC_DT_REMOVE_APPL
+#define SMB_MAC_DT_GET_APPL MAC_DT_GET_APPL
+#define SMB_MAC_DT_GET_ICON MAC_DT_GET_ICON
+#define SMB_MAC_DT_GET_ICON_INFO MAC_DT_GET_ICON_INFO
+#define SMB_MAC_DT_ADD_ICON MAC_DT_ADD_ICON
#define SMB_SET_FILE_BASIC_INFO 0x101
#define SMB_SET_FILE_DISPOSITION_INFO 0x102
@@ -600,19 +618,21 @@ extern "C" {
#define SMB_SET_FILE_END_OF_FILE_INFO 0x104
-/* NT passthrough levels */
-#define SMB_INFO_PASSTHROUGH 1000
-#define SMB_FILE_BASIC_INFORMATION (SMB_INFO_PASSTHROUGH + 4)
-#define SMB_FILE_STANDARD_INFORMATION (SMB_INFO_PASSTHROUGH + 5)
-#define SMB_FILE_INTERNAL_INFORMATION (SMB_INFO_PASSTHROUGH + 6)
-#define SMB_FILE_EA_INFORMATION (SMB_INFO_PASSTHROUGH + 7)
-#define SMB_FILE_ACCESS_INFORMATION (SMB_INFO_PASSTHROUGH + 8)
-#define SMB_FILE_NAME_INFORMATION (SMB_INFO_PASSTHROUGH + 9)
-#define SMB_FILE_ALL_INFORMATION (SMB_INFO_PASSTHROUGH + 18)
-#define SMB_FILE_ALT_NAME_INFORMATION (SMB_INFO_PASSTHROUGH + 21)
-#define SMB_FILE_STREAM_INFORMATION (SMB_INFO_PASSTHROUGH + 22)
-#define SMB_FILE_COMPRESSION_INFORMATION (SMB_INFO_PASSTHROUGH + 28)
-#define SMB_FILE_ATTR_TAG_INFORMATION (SMB_INFO_PASSTHROUGH + 35)
+/* NT passthrough levels - see ntifs.h FILE_INFORMATION_CLASS */
+#define SMB_FILE_BASIC_INFORMATION 1004
+#define SMB_FILE_STANDARD_INFORMATION 1005
+#define SMB_FILE_INTERNAL_INFORMATION 1006
+#define SMB_FILE_EA_INFORMATION 1007
+#define SMB_FILE_ACCESS_INFORMATION 1008
+#define SMB_FILE_NAME_INFORMATION 1009
+#define SMB_FILE_DISPOSITION_INFORMATION 1013
+#define SMB_FILE_ALL_INFORMATION 1018
+#define SMB_FILE_ALLOCATION_INFORMATION 1019
+#define SMB_FILE_END_OF_FILE_INFORMATION 1020
+#define SMB_FILE_ALT_NAME_INFORMATION 1021
+#define SMB_FILE_STREAM_INFORMATION 1022
+#define SMB_FILE_COMPRESSION_INFORMATION 1028
+#define SMB_FILE_ATTR_TAG_INFORMATION 1035
/*
* The following bits may be set in the SecurityMode field of the
diff --git a/usr/src/uts/common/smbsrv/ndl/srvsvc.ndl b/usr/src/uts/common/smbsrv/ndl/srvsvc.ndl
index e56d6bb1a5..d10a7dd2b8 100644
--- a/usr/src/uts/common/smbsrv/ndl/srvsvc.ndl
+++ b/usr/src/uts/common/smbsrv/ndl/srvsvc.ndl
@@ -640,14 +640,11 @@ struct mslm_NetShareInfo_2 {
LPTSTR shi2_passwd;
};
-/*
- * shi501_reserved (AKA shi501_flags) must be zero.
- */
struct mslm_NetShareInfo_501 {
LPTSTR shi501_netname;
DWORD shi501_type;
LPTSTR shi501_comment;
- DWORD shi501_reserved;
+ DWORD shi501_flags;
};
struct mslm_NetShareInfo_502 {
diff --git a/usr/src/uts/common/smbsrv/ndl/svcctl.ndl b/usr/src/uts/common/smbsrv/ndl/svcctl.ndl
index 03f00b241a..5a6a9d034e 100644
--- a/usr/src/uts/common/smbsrv/ndl/svcctl.ndl
+++ b/usr/src/uts/common/smbsrv/ndl/svcctl.ndl
@@ -236,6 +236,18 @@ struct svc_description {
};
typedef struct svc_description svc_description_t;
+/* Boolean flag to control delayed start of service. Set 1=true, 0=false */
+struct svc_delayed_auto_start {
+ DWORD dstart;
+};
+typedef struct svc_delayed_auto_start svc_delayed_auto_start_t;
+
+/* Boolean flag to control configured failure action. Set 1=true, 0=false */
+struct svc_config_failure_action {
+ DWORD cfa;
+};
+typedef struct svc_config_failure_action svc_config_failure_action_t;
+
/*
***********************************************************************
* Close
diff --git a/usr/src/uts/common/smbsrv/smb_fsops.h b/usr/src/uts/common/smbsrv/smb_fsops.h
index a8d411323d..4f1e573a5c 100644
--- a/usr/src/uts/common/smbsrv/smb_fsops.h
+++ b/usr/src/uts/common/smbsrv/smb_fsops.h
@@ -110,12 +110,14 @@ int smb_fsop_frlock(smb_node_t *, smb_lock_t *, boolean_t, cred_t *);
*
* SMB_FOLLOW_LINKS Follow symbolic links.
* SMB_IGNORE_CASE Perform case-insensitive lookup.
- * SMB_CATIA Perform CATIA character substitution
+ * SMB_CATIA Perform CATIA character substitution.
+ * SMB_ABE Perform Access based enumeration/lookup.
*/
#define SMB_FOLLOW_LINKS 0x00000001
#define SMB_IGNORE_CASE 0x00000002
#define SMB_CATIA 0x00000004
+#define SMB_ABE 0x00000008
#ifdef __cplusplus
}
diff --git a/usr/src/uts/common/smbsrv/smb_kproto.h b/usr/src/uts/common/smbsrv/smb_kproto.h
index 2f9e5d6869..e924f189cb 100644
--- a/usr/src/uts/common/smbsrv/smb_kproto.h
+++ b/usr/src/uts/common/smbsrv/smb_kproto.h
@@ -53,9 +53,6 @@ extern int smb_oplock_timeout;
extern int smb_sign_debug;
extern uint_t smb_audit_flags;
-#define smb_gmt2local(_sr_, _gmt_) ((_gmt_) - (_sr_)->sr_gmtoff)
-#define smb_local2gmt(_sr_, _local_) ((_local_) + (_sr_)->sr_gmtoff)
-
int fd_dealloc(int);
off_t lseek(int fildes, off_t offset, int whence);
@@ -209,7 +206,7 @@ DWORD smb_range_check(smb_request_t *, smb_node_t *, uint64_t, uint64_t,
boolean_t);
int smb_mangle_name(ino64_t, char *, char *, char *, int);
-int smb_unmangle_name(smb_node_t *, char *, char *, int);
+int smb_unmangle_name(smb_node_t *, char *, char *, int, uint32_t);
int smb_maybe_mangled_name(char *);
int smb_maybe_mangled_path(const char *, size_t);
int smb_needs_mangle(char *, char **);
@@ -243,10 +240,9 @@ uint32_t smb_omode_to_amask(uint32_t desired_access);
void sshow_distribution_info(char *);
boolean_t smb_dispatch_request(smb_request_t *);
-void smbsr_disconnect_file(smb_request_t *);
-void smbsr_disconnect_dir(smb_request_t *);
int smbsr_encode_empty_result(smb_request_t *);
void smbsr_lookup_file(smb_request_t *);
+void smbsr_release_file(smb_request_t *);
int smbsr_decode_vwv(smb_request_t *sr, char *fmt, ...);
int smbsr_decode_data(smb_request_t *sr, char *fmt, ...);
@@ -261,8 +257,6 @@ void smbsr_warn(smb_request_t *, DWORD, uint16_t, uint16_t);
void smbsr_error(smb_request_t *, DWORD, uint16_t, uint16_t);
int clock_get_milli_uptime(void);
-int32_t smb_dos_to_ux_time(int16_t, int16_t);
-int32_t smb_ux_to_dos_time(int32_t, int16_t *, int16_t *);
int smb_mbc_vencodef(mbuf_chain_t *, char *, va_list);
int smb_mbc_vdecodef(mbuf_chain_t *, char *, va_list);
@@ -278,8 +272,6 @@ int smb_xlate_dialect_str_to_cd(char *);
char *smb_xlate_com_cd_to_str(int);
char *smb_xlate_dialect_cd_to_str(int);
-int smbd_fs_query(smb_request_t *, smb_fqi_t *, int);
-
int smb_lock_range_access(smb_request_t *, smb_node_t *,
uint64_t, uint64_t, boolean_t);
@@ -413,10 +405,6 @@ boolean_t smb_vfs_is_readonly(vfs_t *);
*/
char *smb_kstrdup(const char *s, size_t n);
-
-void smb_encode_stream_info(smb_request_t *sr, smb_xa_t *xa,
- smb_node_t *snode, smb_attr_t *attr);
-
/* NOTIFY CHANGE */
void smb_process_session_notify_change_queue(smb_session_t *, smb_tree_t *);
void smb_process_node_notify_change_queue(smb_node_t *);
@@ -440,9 +428,6 @@ void smbsr_free_malloc_list(smb_malloc_list *);
unsigned short smb_worker_getnum();
-uint32_t smb_trans2_set_information(smb_request_t *,
- smb_trans2_setinfo_t *, smb_error_t *);
-
/* SMB signing routines smb_signing.c */
void smb_sign_init(smb_request_t *, smb_session_key_t *, char *, int);
int smb_sign_check_request(smb_request_t *);
@@ -618,8 +603,12 @@ int smb_handle_write_raw(smb_session_t *session, smb_request_t *sr);
void smb_reconnection_check(smb_session_t *);
-uint32_t nt_to_unix_time(uint64_t nt_time, timestruc_t *unix_time);
-uint64_t unix_to_nt_time(timestruc_t *);
+int32_t smb_time_gmt_to_local(smb_request_t *, int32_t);
+int32_t smb_time_local_to_gmt(smb_request_t *, int32_t);
+int32_t smb_time_dos_to_unix(int16_t, int16_t);
+void smb_time_unix_to_dos(int32_t, int16_t *, int16_t *);
+void smb_time_nt_to_unix(uint64_t nt_time, timestruc_t *unix_time);
+uint64_t smb_time_unix_to_nt(timestruc_t *);
int netbios_name_isvalid(char *in, char *out);
diff --git a/usr/src/uts/common/smbsrv/smb_ktypes.h b/usr/src/uts/common/smbsrv/smb_ktypes.h
index 3aad3437c3..9e4824cdd3 100644
--- a/usr/src/uts/common/smbsrv/smb_ktypes.h
+++ b/usr/src/uts/common/smbsrv/smb_ktypes.h
@@ -507,6 +507,7 @@ typedef struct smb_node {
volatile int flags; /* FILE_NOTIFY_CHANGE_* */
volatile int waiting_event; /* # of clients requesting FCN */
smb_times_t n_timestamps; /* cached timestamps */
+ u_offset_t n_allocsz; /* cached file allocation size */
smb_oplock_t n_oplock;
struct smb_node *n_dnode; /* directory node */
struct smb_node *n_unode; /* unnamed stream node */
@@ -518,32 +519,15 @@ typedef struct smb_node {
smb_audit_buf_node_t *n_audit_buf;
} smb_node_t;
-#define NODE_FLAGS_NOTIFY_CHANGE 0x10000fff
-#define NODE_OPLOCKS_IN_FORCE 0x0000f000
-#define NODE_OPLOCK_NONE 0x00000000
-#define NODE_EXCLUSIVE_OPLOCK 0x00001000
-#define NODE_BATCH_OPLOCK 0x00002000
-#define NODE_LEVEL_II_OPLOCK 0x00003000
-#define NODE_CAP_LEVEL_II 0x00010000
-#define NODE_PROTOCOL_LOCK 0x00020000
+#define NODE_FLAGS_WATCH_TREE 0x10000000
+#define NODE_FLAGS_NOTIFY_CHANGE \
+ (NODE_FLAGS_WATCH_TREE | FILE_NOTIFY_VALID_MASK)
+#define NODE_FLAGS_CHANGED 0x08000000
#define NODE_FLAGS_WRITE_THROUGH 0x00100000
-#define NODE_FLAGS_SYNCATIME 0x00200000
-#define NODE_FLAGS_LOCKED 0x00400000
#define NODE_XATTR_DIR 0x01000000
-#define NODE_FLAGS_CREATED 0x04000000
-#define NODE_FLAGS_CHANGED 0x08000000
-#define NODE_FLAGS_WATCH_TREE 0x10000000
-#define NODE_FLAGS_SET_SIZE 0x20000000
#define NODE_FLAGS_DELETE_ON_CLOSE 0x40000000
#define NODE_FLAGS_EXECUTABLE 0x80000000
-#define OPLOCK_TYPE(n) ((n)->flags & NODE_OPLOCKS_IN_FORCE)
-#define OPLOCKS_IN_FORCE(n) (OPLOCK_TYPE(n) != NODE_OPLOCK_NONE)
-#define EXCLUSIVE_OPLOCK_IN_FORCE(n) \
- (OPLOCK_TYPE(n) == NODE_EXCLUSIVE_OPLOCK)
-#define BATCH_OPLOCK_IN_FORCE(n) (OPLOCK_TYPE(n) == NODE_BATCH_OPLOCK)
-#define LEVEL_II_OPLOCK_IN_FORCE(n) (OPLOCK_TYPE(n) == NODE_LEVEL_II_OPLOCK)
-
#define SMB_NODE_VFS(node) ((node)->vp->v_vfsp)
#define SMB_NODE_FSID(node) ((node)->vp->v_vfsp->vfs_fsid)
@@ -567,7 +551,7 @@ typedef struct smb_node {
*/
#define SMB_SESSION_INACTIVITY_TIMEOUT (15 * 60)
-#define SMB_SESSION_OFILE_MAX (16 * 1024)
+#define SMB_SESSION_OFILE_MAX (16 * 1024)
/*
* When a connection is set up we need to remember both the client
@@ -835,6 +819,7 @@ typedef struct smb_user {
#define SMB_TREE_NFS_MOUNTED 0x00001000
#define SMB_TREE_UNICODE_ON_DISK 0x00002000
#define SMB_TREE_CATIA 0x00004000
+#define SMB_TREE_ABE 0x00008000
typedef enum {
SMB_TREE_STATE_CONNECTED = 0,
@@ -896,6 +881,10 @@ typedef struct smb_tree {
(((sr) && (sr)->tid_tree) ? \
smb_tree_has_feature((sr)->tid_tree, SMB_TREE_CATIA) : 0)
+#define SMB_TREE_SUPPORTS_ABE(sr) \
+ (((sr) && (sr)->tid_tree) ? \
+ smb_tree_has_feature((sr)->tid_tree, SMB_TREE_ABE) : 0)
+
/*
* SMB_TREE_CONTAINS_NODE is used to check that a node is in the same
* file system as the tree.
@@ -1035,6 +1024,7 @@ typedef struct smb_ofile {
#define SMB_ODIR_FLAG_XATTR 0x0004
#define SMB_ODIR_FLAG_EDIRENT 0x0008
#define SMB_ODIR_FLAG_CATIA 0x0010
+#define SMB_ODIR_FLAG_ABE 0x0020
typedef enum {
SMB_ODIR_STATE_OPEN = 0,
@@ -1192,17 +1182,8 @@ typedef struct smb_fqi {
smb_node_t *fq_fnode;
smb_attr_t fq_fattr;
char fq_last_comp[MAXNAMELEN];
- char fq_od_name[MAXNAMELEN];
} smb_fqi_t;
-#define SMB_NULL_FQI_NODES(fqi) \
- (fqi).fq_fnode = NULL; \
- (fqi).fq_dnode = NULL;
-
-#define FQM_DIR_MUST_EXIST 1
-#define FQM_PATH_MUST_EXIST 2
-#define FQM_PATH_MUST_NOT_EXIST 3
-
#define OPLOCK_MIN_TIMEOUT (5 * 1000)
#define OPLOCK_STD_TIMEOUT (15 * 1000)
#define OPLOCK_RETRIES 2
@@ -1645,18 +1626,6 @@ typedef struct smb_server {
#define SMB_NEW_KID() atomic_inc_64_nv(&smb_kids)
#define SMB_UNIQ_FID() atomic_inc_32_nv(&smb_fids)
-/*
- * This is to be used by Trans2SetFileInfo
- * and Trans2SetPathInfo
- */
-typedef struct smb_trans2_setinfo {
- uint16_t level;
- struct smb_xa *ts_xa;
- struct smb_node *node;
- char *path;
- char name[MAXNAMELEN];
-} smb_trans2_setinfo_t;
-
#define SMB_IS_STREAM(node) ((node)->n_unode)
typedef struct smb_tsd {
diff --git a/usr/src/uts/common/smbsrv/smb_share.h b/usr/src/uts/common/smbsrv/smb_share.h
index 89336b2948..1c1bf02111 100644
--- a/usr/src/uts/common/smbsrv/smb_share.h
+++ b/usr/src/uts/common/smbsrv/smb_share.h
@@ -51,6 +51,9 @@ extern "C" {
* ad-container Active directory container in which the share
* will be published
*
+ * abe Determines whether Access Based Enumeration is applied
+ * to a share
+ *
* csc Client-side caching (CSC) options applied to this share
* disabled The client MUST NOT cache any files
* manual The client should not automatically cache every file
@@ -70,6 +73,7 @@ extern "C" {
* none list of hosts that won't be allowed access
*/
#define SHOPT_AD_CONTAINER "ad-container"
+#define SHOPT_ABE "abe"
#define SHOPT_NAME "name"
#define SHOPT_CSC "csc"
#define SHOPT_CATIA "catia"
@@ -123,7 +127,7 @@ extern "C" {
* SMB_SHRF_ADMIN Admin share
* SMB_SHRF_CATIA CATIA character translation on/off
* SMB_SHRF_GUEST_OK Guest access on/off
- *
+ * SMB_SHRF_ABE Access Based Enumeration on/off
* SMB_SHRF_MAP Map command is specified
* SMB_SHRF_UNMAP Unmap command is specified
* SMB_SHRF_DISP_TERM Disposition is set to terminate
@@ -154,6 +158,7 @@ extern "C" {
#define SMB_SHRF_ADMIN 0x1000
#define SMB_SHRF_CATIA 0x2000
#define SMB_SHRF_GUEST_OK 0x4000
+#define SMB_SHRF_ABE 0x8000
/* Exec Flags */
#define SMB_SHRF_MAP 0x10000
@@ -266,6 +271,7 @@ void smb_shr_sa_exit(void);
void smb_shr_sa_csc_option(const char *, smb_share_t *);
char *smb_shr_sa_csc_name(const smb_share_t *);
void smb_shr_sa_catia_option(const char *, smb_share_t *);
+void smb_shr_sa_abe_option(const char *, smb_share_t *);
/*
* CIFS share management API exported for other processes
diff --git a/usr/src/uts/common/smbsrv/smb_vops.h b/usr/src/uts/common/smbsrv/smb_vops.h
index 3732ece854..4952eea170 100644
--- a/usr/src/uts/common/smbsrv/smb_vops.h
+++ b/usr/src/uts/common/smbsrv/smb_vops.h
@@ -71,6 +71,7 @@ typedef struct smb_attr {
vattr_t sa_vattr; /* Legacy vattr */
uint32_t sa_dosattr; /* DOS attributes */
timestruc_t sa_crtime; /* Creation time */
+ u_offset_t sa_allocsz; /* File allocation size in bytes */
} smb_attr_t;
#define SMB_AT_TYPE 0x00001
@@ -91,12 +92,15 @@ typedef struct smb_attr {
#define SMB_AT_DOSATTR 0x00100000
#define SMB_AT_CRTIME 0x00200000
-#define SMB_AT_SMB 0x00300000
+#define SMB_AT_ALLOCSZ 0x00400000
+
+#define SMB_AT_SMB (SMB_AT_DOSATTR|SMB_AT_CRTIME|SMB_AT_ALLOCSZ)
#define SMB_AT_ALL (SMB_AT_TYPE|SMB_AT_MODE|SMB_AT_UID|SMB_AT_GID|\
SMB_AT_FSID|SMB_AT_NODEID|SMB_AT_NLINK|SMB_AT_SIZE|\
SMB_AT_ATIME|SMB_AT_MTIME|SMB_AT_CTIME|SMB_AT_RDEV|\
SMB_AT_BLKSIZE|SMB_AT_NBLOCKS|SMB_AT_SEQ|SMB_AT_SMB)
+
#define SMB_AT_TIMES (SMB_AT_ATIME | SMB_AT_MTIME |\
SMB_AT_CTIME | SMB_AT_CRTIME)
@@ -123,7 +127,8 @@ int smb_vop_rename(vnode_t *, char *, vnode_t *, char *, int, cred_t *);
int smb_vop_mkdir(vnode_t *, char *, smb_attr_t *, vnode_t **, int, cred_t *,
vsecattr_t *);
int smb_vop_rmdir(vnode_t *, char *, int, cred_t *);
-int smb_vop_readdir(vnode_t *, uint32_t, void *, int *, int *, cred_t *);
+int smb_vop_readdir(vnode_t *, uint32_t, void *, int *, int *,
+ uint32_t, cred_t *);
int smb_vop_commit(vnode_t *, cred_t *);
int smb_vop_statfs(vnode_t *, struct statvfs64 *, cred_t *);
int smb_vop_stream_lookup(vnode_t *, char *, vnode_t **, char *, vnode_t **,
diff --git a/usr/src/uts/common/smbsrv/winioctl.h b/usr/src/uts/common/smbsrv/winioctl.h
index 67150ca387..4564b3e8a3 100644
--- a/usr/src/uts/common/smbsrv/winioctl.h
+++ b/usr/src/uts/common/smbsrv/winioctl.h
@@ -305,10 +305,11 @@ extern "C" {
#define _FILESYSTEMFSCTL_
/*
* The following is a list of the native file system fsctls followed by
- * additional network file system fsctls. Some values have been
- * decommissioned.
+ * additional network file system fsctls, DFS fsctls and Named Pipe fsctls.
+ * Some values have been decommissioned.
*/
+/* FILE_DEVICE_FILE_SYSTEM */
#define FSCTL_REQUEST_OPLOCK_LEVEL_1 \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 0, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSCTL_REQUEST_OPLOCK_LEVEL_2 \
@@ -351,17 +352,14 @@ extern "C" {
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 20, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSCTL_INVALIDATE_VOLUMES \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 21, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
/* FSCTL_QUERY_FAT_BPB_BUFFER */
#define FSCTL_QUERY_FAT_BPB \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 22, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSCTL_REQUEST_FILTER_OPLOCK \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 23, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
/* FILESYSTEM_STATISTICS */
#define FSCTL_FILESYSTEM_GET_STATISTICS \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 24, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
/* NTFS_VOLUME_DATA_BUFFER */
#define FSCTL_GET_NTFS_VOLUME_DATA \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 25, METHOD_BUFFERED, FILE_ANY_ACCESS)
@@ -429,8 +427,7 @@ extern "C" {
#define FSCTL_CREATE_OR_GET_OBJECT_ID \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 48, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define FSCTL_SET_SPARSE \
- CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 49, METHOD_BUFFERED, \
- FILE_WRITE_ACCESS)
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 49, METHOD_BUFFERED, FILE_ANY_ACCESS)
/* FILE_ZERO_DATA_INFORMATION, */
#define FSCTL_SET_ZERO_DATA \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 50, METHOD_BUFFERED, \
@@ -463,11 +460,70 @@ extern "C" {
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 59, METHOD_NEITHER, FILE_READ_ACCESS)
#define FSCTL_EXTEND_VOLUME \
CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 60, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
+#define FSCTL_SIS_COPYFILE \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 64, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_RECALL_FILE \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 69, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define FSCTL_SET_DEFECT_MANAGEMENT \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 77, \
+ METHOD_BUFFERED, FILE_WRITE_ACCESS)
+#define FSCTL_QUERY_SPARING_INFO \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 78, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_QUERY_ON_DISK_VOLUME_INFO \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 79, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_SET_ZERO_ON_DEALLOCATION \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 101, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_SET_SHORT_NAME_BEHAVIOR \
+ CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 109, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+/* FILE_DEVICE_NETWORK_FILE_SYSTEM */
/* Read the snapshot info for Volume Shadow Copy Services */
#define FSCTL_SRV_ENUMERATE_SNAPSHOTS \
CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x19, \
METHOD_BUFFERED, FILE_READ_ACCESS)
+/* Retrieve an opaque file reference for server-side data movement */
+#define FSCTL_SRV_REQUEST_RESUME_KEY \
+ CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x1e, \
+ METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_SRV_LMR_GET_LINK_TRACKING_INFORMATION \
+ CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x3a, \
+ METHOD_BUFFERED, FILE_ACCESS_ANY)
+#define FSCTL_SRV_LMR_SET_LINK_TRACKING_INFORMATION \
+ CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x3b, \
+ METHOD_BUFFERED, FILE_ACCESS_ANY)
+/* server-side data movement */
+#define FSCTL_SRV_COPYCHUNK \
+ CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x3c, \
+ METHOD_OUT_DIRECT, FILE_READ_ACCESS)
+/* server-side data movement */
+#define FSCTL_SRV_COPYCHUNK_WRITE \
+ CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x3c, \
+ METHOD_OUT_DIRECT, FILE_WRITE_ACCESS)
+#define FSCTL_SRV_NOTIFY_TRANSACTION \
+ CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x46, \
+ METHOD_BUFFERED, FILE_WRITE_ACCESS)
+#define FSCTL_SRV_READ_HASH \
+ CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x6e, \
+ METHOD_NEITHER, FILE_READ_ACCESS)
+#define FSCTL_SRV_UNKNOWN_x71 \
+ CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x71, \
+ METHOD_BUFFERED, FILE_ACCESS_ANY)
+#define FSCTL_SRV_LMR_REQUEST_RESILIENCY \
+ CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 0x75, \
+ METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+/* FILE_DEVICE_DFS */
+#define FSCTL_DFS_GET_REFERRALS \
+ CTL_CODE(FILE_DEVICE_DFS, 0x65, METHOD_BUFFERED, FILE_ACCESS_ANY)
+
+/* FILE_DEVICE_NAMED_PIPE */
+#define FSCTL_PIPE_PEEK \
+ CTL_CODE(FILE_DEVICE_NAMED_PIPE, 0x3, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define FSCTL_PIPE_TRANSCEIVE \
+ CTL_CODE(FILE_DEVICE_NAMED_PIPE, 0x5, \
+ METHOD_NEITHER, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define FSCTL_PIPE_WAIT \
+ CTL_CODE(FILE_DEVICE_NAMED_PIPE, 0x6, METHOD_BUFFERED, FILE_ANY_ACCESS)
#endif /* _FILESYSTEMFSCTL_ */
diff --git a/usr/src/uts/common/smbsrv/winsvc.h b/usr/src/uts/common/smbsrv/winsvc.h
index 544209792a..132a6e7895 100644
--- a/usr/src/uts/common/smbsrv/winsvc.h
+++ b/usr/src/uts/common/smbsrv/winsvc.h
@@ -197,8 +197,15 @@ extern "C" {
/*
* Info levels for ChangeServiceConfig2 and QueryServiceConfig2.
*/
-#define SERVICE_CONFIG_DESCRIPTION 1
-#define SERVICE_CONFIG_FAILURE_ACTIONS 2
+#define SERVICE_CONFIG_DESCRIPTION 1
+#define SERVICE_CONFIG_FAILURE_ACTIONS 2
+#define SERVICE_CONFIG_DELAYED_AUTO_START_INFO 3
+#define SERVICE_CONFIG_FAILURE_ACTIONS_FLAG 4
+#define SERVICE_CONFIG_SERVICE_SID_INFO 5
+#define SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO 6
+#define SERVICE_CONFIG_PRESHUTDOWN_INFO 7
+#define SERVICE_CONFIG_TRIGGER_INFO 8
+#define SERVICE_CONFIG_PREFERRED_NODE 9
/*
* Actions to take on service failure (SC_ACTION_TYPE).