Beispiel #1
0
/*
 * smb_tonetbiosname
 *
 * Creates a NetBIOS name based on the given name and suffix.
 * NetBIOS name is 15 capital characters, padded with space if needed
 * and the 16th byte is the suffix.
 */
void
smb_tonetbiosname(char *name, char *nb_name, char suffix)
{
	char tmp_name[NETBIOS_NAME_SZ];
	smb_wchar_t wtmp_name[NETBIOS_NAME_SZ];
	int len;
	size_t rc;

	len = 0;
	rc = smb_mbstowcs(wtmp_name, (const char *)name, NETBIOS_NAME_SZ);

	if (rc != (size_t)-1) {
		wtmp_name[NETBIOS_NAME_SZ - 1] = 0;
		rc = ucstooem(tmp_name, wtmp_name, NETBIOS_NAME_SZ,
		    OEM_CPG_850);
		if (rc > 0)
			len = strlen(tmp_name);
	}

	(void) memset(nb_name, ' ', NETBIOS_NAME_SZ - 1);
	if (len) {
		(void) smb_strupr(tmp_name);
		(void) memcpy(nb_name, tmp_name, len);
	}
	nb_name[NETBIOS_NAME_SZ - 1] = suffix;
}
Beispiel #2
0
/*
 * smb_pathname_preprocess_quota
 *
 * There is a special file required by windows so that the quota
 * tab will be displayed by windows clients. This is created in
 * a special directory, $EXTEND, at the root of the shared file
 * system. To hide this directory prepend a '.' (dot).
 */
static void
smb_pathname_preprocess_quota(smb_request_t *sr, smb_pathname_t *pn)
{
	char *name = "$EXTEND";
	char *new_name = ".$EXTEND";
	char *p, *slash;
	int len;

	if (!smb_node_is_vfsroot(sr->tid_tree->t_snode))
		return;

	p = pn->pn_path;

	/* ignore any initial "\\" */
	p += strspn(p, "\\");
	if (smb_strcasecmp(p, name, strlen(name)) != 0)
		return;

	p += strlen(name);
	if ((*p != ':') && (*p != '\\') && (*p != '\0'))
		return;

	slash = (pn->pn_path[0] == '\\') ? "\\" : "";
	len = strlen(pn->pn_path) + 2;
	pn->pn_path = smb_srm_alloc(sr, len);
	(void) snprintf(pn->pn_path, len, "%s%s%s", slash, new_name, p);
	(void) smb_strupr(pn->pn_path);
}
Beispiel #3
0
uint32_t
smb_is_executable(char *path)
{
	char	extension[5];
	int	len = strlen(path);

	if ((len >= 4) && (path[len - 4] == '.')) {
		(void) strcpy(extension, &path[len - 3]);
		(void) smb_strupr(extension);

		if (strcmp(extension, "EXE") == 0)
			return (NODE_FLAGS_EXECUTABLE);

		if (strcmp(extension, "COM") == 0)
			return (NODE_FLAGS_EXECUTABLE);

		if (strcmp(extension, "DLL") == 0)
			return (NODE_FLAGS_EXECUTABLE);

		if (strcmp(extension, "SYM") == 0)
			return (NODE_FLAGS_EXECUTABLE);
	}

	return (0);
}
Beispiel #4
0
/*
 * Get the current system node name.  The returned name is guaranteed
 * to be null-terminated (gethostname may not null terminate the name).
 * If the hostname has been fully-qualified for some reason, the domain
 * part will be removed.  The returned hostname is converted to the
 * specified case (lower, upper, or preserved).
 *
 * If gethostname fails, the returned buffer will contain an empty
 * string.
 */
int
smb_gethostname(char *buf, size_t buflen, smb_caseconv_t which)
{
	char *p;

	if (buf == NULL || buflen == 0)
		return (-1);

	if (gethostname(buf, buflen) != 0) {
		*buf = '\0';
		return (-1);
	}

	buf[buflen - 1] = '\0';

	if ((p = strchr(buf, '.')) != NULL)
		*p = '\0';

	switch (which) {
	case SMB_CASE_LOWER:
		(void) smb_strlwr(buf);
		break;

	case SMB_CASE_UPPER:
		(void) smb_strupr(buf);
		break;

	case SMB_CASE_PRESERVE:
	default:
		break;
	}

	return (0);
}
Beispiel #5
0
static boolean_t
smb_lmv2_password_ok(
    unsigned char *challenge,
    uint32_t clen,
    unsigned char *ntlm_hash,
    unsigned char *passwd,
    char *domain,
    char *username)
{
    unsigned char *clnt_challenge;
    unsigned char ntlmv2_hash[SMBAUTH_HASH_SZ];
    unsigned char lmv2_resp[SMBAUTH_LM_RESP_SZ];
    boolean_t ok = B_FALSE;
    char *dest[3];
    int i;

    clnt_challenge = &passwd[SMBAUTH_HASH_SZ];
    dest[0] = domain;
    if ((dest[1] = strdup(domain)) == NULL)
        return (B_FALSE);
    (void) smb_strupr(dest[1]);
    dest[2] = "";

    /*
     * 15.5.2 The NTLMv2 Password Hash, pg. 279, of the "Implementing CIFS"
     *
     * The NTLMv2 Hash is created from:
     * - NTLM hash
     * - user's username, and
     * - the name of the logon destination(i.e. the NetBIOS name of either
     *   the SMB server or NT Domain against which the suer is trying to
     *   authenticate.
     *
     * Experiments show this is not exactly the case.
     * For Windows Server 2003, the domain name needs to be included and
     * converted to uppercase. For Vista, the domain name needs to be
     * included also, but leave the case alone.  And in some cases it needs
     * to be empty. All three variants are tried here.
     */

    for (i = 0; i < (sizeof (dest) / sizeof (char *)); i++) {
        if (smb_auth_ntlmv2_hash(ntlm_hash, username, dest[i],
                                 ntlmv2_hash) != SMBAUTH_SUCCESS)
            break;

        if (smb_auth_v2_response(ntlmv2_hash, challenge,
                                 clen, clnt_challenge, SMBAUTH_V2_CLNT_CHALLENGE_SZ,
                                 lmv2_resp) < 0)
            break;

        ok = (bcmp(passwd, lmv2_resp, SMBAUTH_LM_RESP_SZ) == 0);
        if (ok)
            break;
    }

    free(dest[1]);
    return (ok);
}
Beispiel #6
0
/*
 * smb_encode_netbios_name
 *
 * Set up the name and scope fields in the destination name_entry structure.
 * The name is padded with spaces to 15 bytes. The suffix is copied into the
 * last byte, i.e. "netbiosname    <suffix>". The scope is copied and folded
 * to uppercase.
 */
void
smb_encode_netbios_name(unsigned char *name, char suffix, unsigned char *scope,
    struct name_entry *dest)
{
	smb_tonetbiosname((char *)name, (char *)dest->name, suffix);

	if (scope) {
		(void) strlcpy((char *)dest->scope, (const char *)scope,
		    sizeof (dest->scope));
	} else {
		(void) smb_config_getstr(SMB_CI_NBSCOPE, (char *)dest->scope,
		    sizeof (dest->scope));
	}

	(void) smb_strupr((char *)dest->scope);
}
/*
 * smb_query_shortname
 *
 * If the node is a named stream, use its associated
 * unnamed stream name to determine the shortname.
 * If a shortname is required (smb_needs_mangle()), generate it
 * using smb_mangle(), otherwise, convert the original name to
 * upper-case and return it as the alternative name.
 */
static void
smb_query_shortname(smb_node_t *node, smb_queryinfo_t *qinfo)
{
	char *namep;

	if (SMB_IS_STREAM(node))
		namep = node->n_unode->od_name;
	else
		namep = node->od_name;

	if (smb_needs_mangled(namep)) {
		smb_mangle(namep, qinfo->qi_attr.sa_vattr.va_nodeid,
		    qinfo->qi_shortname, SMB_SHORTNAMELEN);
	} else {
		(void) strlcpy(qinfo->qi_shortname, namep, SMB_SHORTNAMELEN);
		(void) smb_strupr(qinfo->qi_shortname);
	}
}
Beispiel #8
0
/*
 * smb_stream_parse_name
 *
 * smb_stream_parse_name should only be called for a path that
 * contains a valid named stream.  Path validation should have
 * been performed before this function is called.
 *
 * Find the last component of path and split it into filename
 * and stream name.
 *
 * On return the named stream type will be present.  The stream
 * type defaults to ":$DATA", if it has not been defined
 * For exmaple, 'stream' contains :<sname>:$DATA
 */
void
smb_stream_parse_name(char *path, char *filename, char *stream)
{
	char *fname, *sname, *stype;

	ASSERT(path);
	ASSERT(filename);
	ASSERT(stream);

	fname = strrchr(path, '\\');
	fname = (fname == NULL) ? path : fname + 1;
	(void) strlcpy(filename, fname, MAXNAMELEN);

	sname = strchr(filename, ':');
	(void) strlcpy(stream, sname, MAXNAMELEN);
	*sname = '\0';

	stype = strchr(stream + 1, ':');
	if (stype == NULL)
		(void) strlcat(stream, ":$DATA", MAXNAMELEN);
	else
		(void) smb_strupr(stype);
}
Beispiel #9
0
/*
 * smb_auth_ntlmv2_hash
 *
 * The NTLM v2 hash will be created from the given NTLM hash, username,
 * and the NETBIOS name of the domain.
 *
 * The NTLMv2 hash will be returned via the ntlmv2_hash parameter which
 * will be used in the calculation of the NTLMv2 and LMv2 responses.
 */
int
smb_auth_ntlmv2_hash(unsigned char *ntlm_hash,
                     char *username,
                     char *ntdomain,
                     unsigned char *ntlmv2_hash)
{
    smb_wchar_t *data;
    int data_len;
    unsigned char *buf;
    int rc;

    if (username == NULL || ntdomain == NULL)
        return (SMBAUTH_FAILURE);

    (void) smb_strupr(username);

    data_len = strlen(username) + strlen(ntdomain);
    buf = (unsigned char *)malloc((data_len + 1) * sizeof (char));
    if (buf == NULL)
        return (SMBAUTH_FAILURE);

    (void) snprintf((char *)buf, data_len + 1, "%s%s", username, ntdomain);
    data = (smb_wchar_t *)malloc((data_len + 1) * sizeof (smb_wchar_t));
    if (data == NULL) {
        free(buf);
        return (SMBAUTH_FAILURE);
    }

    data_len = smb_auth_qnd_unicode(data, (char *)buf, data_len);
    rc = SMBAUTH_HMACT64((unsigned char *)data, data_len, ntlm_hash,
                         SMBAUTH_HASH_SZ, ntlmv2_hash);

    free(buf);
    free(data);
    return (rc);
}
Beispiel #10
0
/*
 * smb_pathname_init
 * Parse path: pname\\fname:sname:stype
 *
 * Elements of the smb_pathname_t structure are allocated using request
 * specific storage and will be free'd when the sr is destroyed.
 *
 * Populate pn structure elements with the individual elements
 * of pn->pn_path. pn->pn_sname will contain the whole stream name
 * including the stream type and preceding colon: :sname:%DATA
 * pn_stype will point to the stream type within pn_sname.
 *
 * If the pname element is missing pn_pname will be set to NULL.
 * If any other element is missing the pointer in pn will be NULL.
 */
void
smb_pathname_init(smb_request_t *sr, smb_pathname_t *pn, char *path)
{
	char *pname, *fname, *sname;
	int len;

	bzero(pn, sizeof (smb_pathname_t));
	pn->pn_path = smb_pathname_strdup(sr, path);

	smb_pathname_preprocess(sr, pn);

	/* parse pn->pn_path into its constituent parts */
	pname = pn->pn_path;
	fname = strrchr(pn->pn_path, '\\');

	if (fname) {
		if (fname == pname) {
			pn->pn_pname = NULL;
		} else {
			*fname = '\0';
			pn->pn_pname =
			    smb_pathname_strdup(sr, pname);
			*fname = '\\';
		}
		++fname;
	} else {
		fname = pname;
		pn->pn_pname = NULL;
	}

	if (fname[0] == '\0') {
		pn->pn_fname = NULL;
		return;
	}

	if (!smb_is_stream_name(fname)) {
		pn->pn_fname = smb_pathname_strdup(sr, fname);
		return;
	}

	/*
	 * find sname and stype in fname.
	 * sname can't be NULL smb_is_stream_name checks this
	 */
	sname = strchr(fname, ':');
	if (sname == fname)
		fname = NULL;
	else {
		*sname = '\0';
		pn->pn_fname =
		    smb_pathname_strdup(sr, fname);
		*sname = ':';
	}

	pn->pn_sname = smb_pathname_strdup(sr, sname);
	pn->pn_stype = strchr(pn->pn_sname + 1, ':');
	if (pn->pn_stype) {
		(void) smb_strupr(pn->pn_stype);
	} else {
		len = strlen(pn->pn_sname);
		pn->pn_sname = smb_pathname_strcat(sr, pn->pn_sname, ":$DATA");
		pn->pn_stype = pn->pn_sname + len;
	}
	++pn->pn_stype;
}
Beispiel #11
0
static boolean_t
smb_ntlmv2_password_ok(
    unsigned char *challenge,
    uint32_t clen,
    unsigned char *ntlm_hash,
    unsigned char *passwd,
    int pwdlen,
    char *domain,
    char *username,
    uchar_t *session_key)
{
    unsigned char *clnt_blob;
    int clnt_blob_len;
    unsigned char ntlmv2_hash[SMBAUTH_HASH_SZ];
    unsigned char *ntlmv2_resp;
    boolean_t ok = B_FALSE;
    char *dest[3];
    int i;
    int rc;

    clnt_blob_len = pwdlen - SMBAUTH_HASH_SZ;
    clnt_blob = &passwd[SMBAUTH_HASH_SZ];
    dest[0] = domain;
    if ((dest[1] = strdup(domain)) == NULL)
        return (B_FALSE);
    (void) smb_strupr(dest[1]);
    dest[2] = "";

    /*
     * 15.5.2 The NTLMv2 Password Hash, pg. 279, of the "Implementing CIFS"
     *
     * The NTLMv2 Hash is created from:
     * - NTLM hash
     * - user's username, and
     * - the name of the logon destination(i.e. the NetBIOS name of either
     *   the SMB server or NT Domain against which the user is trying to
     *   authenticate.
     *
     * Experiments show this is not exactly the case.
     * For Windows Server 2003, the domain name needs to be included and
     * converted to uppercase. For Vista, the domain name needs to be
     * included also, but leave the case alone.  And in some cases it needs
     * to be empty. All three variants are tried here.
     */

    ntlmv2_resp = (unsigned char *)malloc(SMBAUTH_HASH_SZ + clnt_blob_len);
    if (ntlmv2_resp == NULL) {
        free(dest[1]);
        return (B_FALSE);
    }

    for (i = 0; i < (sizeof (dest) / sizeof (char *)); i++) {
        if (smb_auth_ntlmv2_hash(ntlm_hash, username, dest[i],
                                 ntlmv2_hash) != SMBAUTH_SUCCESS)
            break;

        if (smb_auth_v2_response(ntlmv2_hash, challenge,
                                 clen, clnt_blob, clnt_blob_len, ntlmv2_resp) < 0)
            break;

        ok = (bcmp(passwd, ntlmv2_resp, pwdlen) == 0);
        if (ok && session_key) {
            rc = SMBAUTH_HMACT64(ntlmv2_resp,
                                 SMBAUTH_HASH_SZ, ntlmv2_hash,
                                 SMBAUTH_SESSION_KEY_SZ, session_key);
            if (rc != SMBAUTH_SUCCESS) {
                ok = B_FALSE;
            }
            break;
        }
    }

    free(dest[1]);
    free(ntlmv2_resp);
    return (ok);
}
Beispiel #12
0
/*
 * smb_first_level_name_decode
 *
 * The null terminated string "in" is the name to decode. The output
 * is placed in the name_entry structure "name".
 *
 * The scope field is a series of length designated labels as described
 * in the "Domain name representation and compression" section of RFC883.
 * The two high order two bits of the length field must be zero, the
 * remaining six bits contain the field length. The total length of the
 * domain name is restricted to 255 octets but note that the trailing
 * root label and its dot are not printed. When converting the labels,
 * the length fields are replaced by dots.
 *
 * Returns the number of bytes scanned or -1 to indicate an error.
 */
int
netbios_first_level_name_decode(char *in, char *name, char *scope)
{
	unsigned int	length, bytes;
	char		c1, c2;
	char		*cp;
	char		*out;

	cp = in;

	if ((length = *cp++) != 0x20) {
		return (-1);
	}

	out = name;
	while (length > 0) {
		c1 = *cp++;
		c2 = *cp++;

		if ('A' <= c1 && c1 <= 'P' && 'A' <= c2 && c2 <= 'P') {
			c1 -= 'A';
			c2 -= 'A';
			*out++ = (c1 << 4) | (c2);
		} else {
			return (-1);		/* conversion error */
		}
		length -= 2;
	}

	out = scope;
	bytes = 0;
	for (length = *cp++; length != 0; length = *cp++) {
		if ((length & 0xc0) != 0x00) {
			/*
			 * This is a pointer or a reserved field. If it's
			 * a pointer (16-bits) we have to skip the next byte.
			 */
			if ((length & 0xc0) == 0xc0) {
				cp++;
				continue;
			}
		}

		/*
		 * Replace the length with a '.', except for the first one.
		 */
		if (out != scope) {
			*out++ = '.';
			bytes++;
		}

		while (length-- > 0) {
			if (bytes++ >= (NETBIOS_DOMAIN_NAME_MAX - 1)) {
				return (-1);
			}
			*out++ = *cp++;
		}
	}
	*out = 0;

	/*
	 * We are supposed to preserve all 8-bits of the domain name
	 * but due to the single byte representation in the name cache
	 * and UTF-8 encoding everywhere else, we restrict domain names
	 * to Appendix 1 - Domain Name Syntax Specification in RFC883.
	 */
	if (domainname_is_valid(scope))	{
		(void) smb_strupr(scope);
		/*LINTED E_PTRDIFF_OVERFLOW*/
		return (cp - in);
	}

	scope[0] = '\0';
	return (-1);
}
/*
 * 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)
{
	int rc;
	boolean_t include_sharename = B_FALSE;

	(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 include the sharename in the name field */
	if ((infolev == SMB_QUERY_FILE_ALL_INFO) ||
	    (infolev == SMB_FILE_ALL_INFORMATION)) {
		include_sharename = B_TRUE;
	}

	rc = smb_query_pathname(sr->tid_tree, node, include_sharename,
	    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);

	/*
	 * 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,
	    node->od_name, qinfo->qi_shortname, qinfo->qi_name83, 0);
	if (*qinfo->qi_shortname == 0) {
		(void) strlcpy(qinfo->qi_shortname, node->od_name,
		    SMB_SHORTNAMELEN);
		(void) smb_strupr(qinfo->qi_shortname);
	}

	return (0);
}
/*
 * Always set ACL support because the VFS will fake ACLs for file systems
 * that don't support them.
 *
 * Some flags are dependent on the typename, which is also set up here.
 * File system types are hardcoded in uts/common/os/vfs_conf.c.
 */
static void
smb_tree_get_flags(const smb_share_t *si, vfs_t *vfsp, smb_tree_t *tree)
{
	typedef struct smb_mtype {
		char		*mt_name;
		size_t		mt_namelen;
		uint32_t	mt_flags;
	} smb_mtype_t;

	static smb_mtype_t smb_mtype[] = {
		{ "zfs",	3,	SMB_TREE_UNICODE_ON_DISK },
		{ "ufs",	3,	SMB_TREE_UNICODE_ON_DISK },
		{ "nfs",	3,	SMB_TREE_NFS_MOUNTED },
		{ "tmpfs",	5,	SMB_TREE_NO_EXPORT }
	};
	smb_mtype_t	*mtype;
	char		*name;
	uint32_t	flags = SMB_TREE_SUPPORTS_ACLS;
	int		i;

	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;

	if (vfsp->vfs_flag & VFS_XATTR)
		flags |= SMB_TREE_STREAMS;

	if (vfs_optionisset(vfsp, MNTOPT_NOATIME, NULL))
		flags |= SMB_TREE_NO_ATIME;

	name = vfssw[vfsp->vfs_fstype].vsw_name;

	for (i = 0; i < sizeof (smb_mtype) / sizeof (smb_mtype[0]); ++i) {
		mtype = &smb_mtype[i];
		if (strncasecmp(name, mtype->mt_name, mtype->mt_namelen) == 0)
			flags |= mtype->mt_flags;
	}

	(void) strlcpy(tree->t_typename, name, SMB_TYPENAMELEN);
	(void) smb_strupr((char *)tree->t_typename);

	if (vfs_has_feature(vfsp, VFSFT_XVATTR))
		flags |= SMB_TREE_XVATTR;

	if (vfs_has_feature(vfsp, VFSFT_CASEINSENSITIVE))
		flags |= SMB_TREE_CASEINSENSITIVE;

	if (vfs_has_feature(vfsp, VFSFT_NOCASESENSITIVE))
		flags |= SMB_TREE_NO_CASESENSITIVE;

	if (vfs_has_feature(vfsp, VFSFT_DIRENTFLAGS))
		flags |= SMB_TREE_DIRENTFLAGS;

	if (vfs_has_feature(vfsp, VFSFT_ACLONCREATE))
		flags |= SMB_TREE_ACLONCREATE;

	if (vfs_has_feature(vfsp, VFSFT_ACEMASKONACCESS))
		flags |= SMB_TREE_ACEMASKONACCESS;

	DTRACE_PROBE2(smb__tree__flags, uint32_t, flags, char *, name);


	tree->t_flags = flags;
}