diff options
Diffstat (limited to 'usr/src')
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). |