diff options
author | Keyur Desai <Keyur.Desai@Sun.COM> | 2009-09-11 17:22:48 -0600 |
---|---|---|
committer | Keyur Desai <Keyur.Desai@Sun.COM> | 2009-09-11 17:22:48 -0600 |
commit | e3f2c991a8548408db0a2787bd8b43d5124821d3 (patch) | |
tree | 953b45b77a478c8ee85319e5e96ddb77f98dbd13 | |
parent | c4ddbbe1ca066fd6662bdb8c477ad412b97c5590 (diff) | |
download | illumos-joyent-e3f2c991a8548408db0a2787bd8b43d5124821d3.tar.gz |
6861127 Want an RPC function to get the session key
6865745 Consolidate request handlers for query file information requests
6864354 mdb dumps core in an smb dcmd
6841851 [Sparc] Can not make a mapped drive from Windows to any share on CIFS Server
6840783 Support IDMU userid and groupid data for joined domain
6845717 idmapd's scf_value2string unnecessarily complex, incorrect
PSARC/2009/398 IDMU Support for idmap
6867994 Rework handling of set and query of file allocation size
6863385 MMC - Unable to use Event Viewer in Windows 2008 - "RPC server is unavailable"
6863390 MMC - Issues with the Services list in Windows 2008
6868501 Unable to map a CIFS share after bfu to cifs nightly build
6870248 Consolidate request handlers for set file information requests
6864074 idmap cannot map computer accounts
6874207 Incorrect access permission check when setting file size
6875658 Need locking around process-wide changes
6877595 eliminate smbd_fs_query()
PSARC/2009/375 ABE share property for NFS and SMB
6802736 SMB share support for Access Based Enumeration
6875228 Issue with file copy from a CIFS share to the same share using Windows.
--HG--
rename : usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c => usr/src/uts/common/fs/smbsrv/smb_query_fileinfo.c
rename : usr/src/uts/common/fs/smbsrv/smb_trans2_set_information.c => usr/src/uts/common/fs/smbsrv/smb_set_fileinfo.c
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 = ¶m->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 *)¶m->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). |