Exemple #1
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);
}
Exemple #2
0
/*
 * smb_transfer_write_raw_data
 *
 * Handles the second transfer phase of SMB_COM_WRITE_RAW.  smb_com_write_raw()
 * will process the parameters and data from the SMB and send the initial
 * SMB response.  This function reads the remaining data from the socket
 * as it arrives from the client.
 *
 * Clients may send KEEP_ALIVE messages (when using NBT) between the first
 * and second parts of write raw requests.  The only session transport
 * types accepted here are SESSION_MESSAGE or SESSION_KEEP_ALIVE.
 *
 * Returns 0 for success, non-zero for failure
 */
int
smb_transfer_write_raw_data(smb_request_t *sr, smb_rw_param_t *param)
{
	smb_session_t *session = sr->session;
	smb_xprt_t hdr;
	void *pbuf;

	do {
		if (smb_session_xprt_gethdr(session, &hdr) != 0)
			return (-1);

		if ((hdr.xh_type == SESSION_MESSAGE) ||
		    (hdr.xh_type == SESSION_KEEP_ALIVE)) {
			session->keep_alive = smb_keep_alive;
		} else {
			return (-1);
		}
	} while (hdr.xh_type == SESSION_KEEP_ALIVE);

	if (hdr.xh_length < param->rw_vdb.vdb_uio.uio_resid)
		return (-1); /* Less data than we were expecting. */

	pbuf = smb_srm_alloc(sr, hdr.xh_length);
	if (smb_sorecv(session->sock, pbuf, hdr.xh_length) != 0)
		return (-1);

	param->rw_vdb.vdb_iovec[0].iov_base = pbuf;
	param->rw_vdb.vdb_uio.uio_iovcnt = 1;
	param->rw_vdb.vdb_uio.uio_segflg = UIO_SYSSPACE;
	param->rw_vdb.vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
	return (0);
}
Exemple #3
0
char *
smb_srm_strdup(smb_request_t *sr, const char *s)
{
	char	*p;
	size_t	size;

	size = strlen(s) + 1;
	p = smb_srm_alloc(sr, size);
	bcopy(s, p, size);
	return (p);
}
Exemple #4
0
/*
 * sr - the request info, used to find root of dataset,
 *      unicode or ascii, where the share is rooted in the
 *      dataset
 * root_node - root of the share
 * cur_node - where in the share for the command
 * buf - is the path for the command to be processed
 *       returned without @GMT if processed
 * vss_cur_node - returned value for the snapshot version
 *                of the cur_node
 * vss_root_node - returned value for the snapshot version
 *                 of the root_node
 *
 * This routine is the processing for handling the
 * SMB_FLAGS2_REPARSE_PATH bit being set in the smb header.
 *
 * By using the cur_node passed in, a new node is found or
 * created that is the same place in the directory tree, but
 * in the snapshot. We also use root_node to do the same for
 * the root.
 * Once the new smb node is found, the path is modified by
 * removing the @GMT token from the path in the buf.
 */
int
smb_vss_lookup_nodes(smb_request_t *sr, smb_node_t *root_node,
    smb_node_t *cur_node, char *buf, smb_node_t **vss_cur_node,
    smb_node_t **vss_root_node)
{
	smb_arg_open_t	*op = &sr->arg.open;
	smb_node_t	*tnode;
	char		*snapname, *path;
	char		*gmttoken;
	char		gmttok_buf[SMB_VSS_GMT_SIZE];
	vnode_t		*fsrootvp = NULL;
	time_t		toktime;
	int		err = 0;
	boolean_t	smb1;

	if (sr->tid_tree == NULL)
		return (ESTALE);

	tnode = sr->tid_tree->t_snode;

	ASSERT(tnode);
	ASSERT(tnode->vp);
	ASSERT(tnode->vp->v_vfsp);

	smb1 = (sr->session->dialect < 0x200);
	if (smb1) {
		const char *p;

		/* get gmttoken from buf */
		if ((p = smb_vss_find_gmttoken(buf)) == NULL)
			return (ENOENT);

		bcopy(p, gmttok_buf, SMB_VSS_GMT_SIZE);
		gmttok_buf[SMB_VSS_GMT_SIZE - 1] = '\0';
		gmttoken = gmttok_buf;
		toktime = 0;
	} else {
		/* SMB2 and later */
		gmttoken = NULL;
		toktime = op->timewarp.tv_sec;
	}

	path = smb_srm_alloc(sr, MAXPATHLEN);
	snapname = smb_srm_alloc(sr, MAXPATHLEN);

	err = smb_node_getmntpath(tnode, path, MAXPATHLEN);
	if (err != 0)
		return (err);

	/*
	 * Find the corresponding snapshot name.  If snapname is
	 * empty after the map call, no such snapshot was found.
	 */
	*snapname = '\0';
	smb_vss_map_gmttoken(sr->tid_tree, path, gmttoken, toktime,
	    snapname);
	if (*snapname == '\0')
		return (ENOENT);

	/* find snapshot nodes */
	err = VFS_ROOT(tnode->vp->v_vfsp, &fsrootvp);
	if (err != 0)
		return (err);

	/* find snapshot node corresponding to root_node */
	err = smb_vss_lookup_node(sr, root_node, fsrootvp,
	    snapname, cur_node, vss_root_node);
	if (err == 0) {
		/* find snapshot node corresponding to cur_node */
		err = smb_vss_lookup_node(sr, cur_node, fsrootvp,
		    snapname, cur_node, vss_cur_node);
		if (err != 0)
			smb_node_release(*vss_root_node);
	}

	VN_RELE(fsrootvp);

	if (smb1)
		smb_vss_remove_first_token_from_path(buf);

	return (err);
}
Exemple #5
0
/*
 * Handle new-style (extended security) session setup.
 * Returns zero: success, non-zero: error (value not used)
 *
 * Note that this style uses a sequence of session setup requests,
 * where the first has SMB UID=0, and subsequent requests in the
 * same authentication sequence have the SMB UID returned for that
 * first request.  We allocate a USER object when the first request
 * in the sequence arrives (SMB_USER_STATE_LOGGING_ON) and use that
 * to maintain state between requests in this sequence.  The state
 * for one sequence includes an AF_UNIX "authsock" connection to the
 * user-space smbd.  The neat part of this is: in smbd, the handler
 * for the server-side of one authsock gets only request specific to
 * one authentication sequence, simplifying it's work immensely.
 * When the authentication sequence is finished, with either success
 * or failure, the local side of the authsock is closed.
 *
 * As with the old-style authentication, if we succeed, then the
 * last message from smbd will be an smb_token_t encoding the
 * information about the new user.
 *
 * Outline:
 * (a) On the first request (UID==0) create a USER object,
 *     and on subsequent requests, find USER by SMB UID.
 * (b) Send message / recv. response as above,
 * (c) If response says "we're done", close authsock
 *     (both success and failure must close authsock)
 */
int
smb_authenticate_ext(smb_request_t *sr)
{
	smb_lsa_msg_hdr_t	msg_hdr;
	smb_arg_sessionsetup_t *sinfo = sr->sr_ssetup;
	smb_user_t	*user = NULL;
	void		*rbuf = NULL;
	uint32_t	rlen = 0;
	uint32_t	status;

	ASSERT(sr->uid_user == NULL);

	/*
	 * On the first request (UID==0) create a USER object.
	 * On subsequent requests (UID!=0) find the USER object.
	 * Either way, sr->uid_user is set, so our ref. on the
	 * user object is dropped during normal cleanup work
	 * for the smb_request (sr).  Ditto u_authsock.
	 */
	if (sr->smb_uid == 0) {
		user = smb_user_new(sr->session);
		if (user == NULL)
			return (NT_STATUS_TOO_MANY_SESSIONS);

		/* user cleanup in smb_request_free */
		sr->uid_user = user;
		sr->smb_uid = user->u_uid;

		/*
		 * Open a connection to the local logon service.
		 * If we can't, it may be busy, or not running.
		 * Don't log here - this may be frequent.
		 */
		if ((status = smb_authsock_open(user)) != 0)
			goto errout;

		/*
		 * Tell the auth. svc who this client is.
		 */
		if ((status = smb_auth_do_clinfo(sr)) != 0)
			goto errout;

		msg_hdr.lmh_msgtype = LSA_MTYPE_ESFIRST;
	} else {
		user = smb_session_lookup_uid_st(sr->session,
		    sr->smb_uid, SMB_USER_STATE_LOGGING_ON);
		if (user == NULL)
			return (NT_STATUS_USER_SESSION_DELETED);

		/* user cleanup in smb_request_free */
		sr->uid_user = user;

		msg_hdr.lmh_msgtype = LSA_MTYPE_ESNEXT;
	}

	/*
	 * Wrap the "security blob" with our header
	 * (LSA_MTYPE_ESFIRST or LSA_MTYPE_ESNEXT)
	 * and send it up the authsock with either
	 */
	msg_hdr.lmh_msglen = sinfo->ssi_iseclen;
	status = smb_authsock_sendrecv(user, &msg_hdr,
	    sinfo->ssi_isecblob, &rbuf);
	if (status != 0)
		goto errout;
	rlen = msg_hdr.lmh_msglen;

	/*
	 * Decode the response message.
	 * Note: allocated rbuf
	 */
	switch (msg_hdr.lmh_msgtype) {

	case LSA_MTYPE_ES_CONT:
		sinfo->ssi_oseclen = (uint16_t)rlen;
		sinfo->ssi_osecblob = smb_srm_alloc(sr, sinfo->ssi_oseclen);
		bcopy(rbuf, sinfo->ssi_osecblob, sinfo->ssi_oseclen);
		/*
		 * This is not really an error, but tells the client
		 * it should send another session setup request.
		 */
		status = NT_STATUS_MORE_PROCESSING_REQUIRED;
		break;

	case LSA_MTYPE_ES_DONE:
		sinfo->ssi_oseclen = (uint16_t)rlen;
		sinfo->ssi_osecblob = smb_srm_alloc(sr, sinfo->ssi_oseclen);
		bcopy(rbuf, sinfo->ssi_osecblob, sinfo->ssi_oseclen);
		sinfo->ssi_ntpwlen = 0;
		/*
		 * Get the final auth. token.
		 */
		status = smb_auth_get_token(sr);
		break;

	case LSA_MTYPE_ERROR:
		/*
		 * Authentication failed.  Return the error
		 * provided in the reply message.
		 */
		if (rlen == sizeof (smb_lsa_eresp_t)) {
			smb_lsa_eresp_t *ler = rbuf;
			status = ler->ler_ntstatus;
			goto errout;
		}
		/* FALLTHROUGH */

	default:	/*  Bogus message type */
		status = NT_STATUS_INTERNAL_ERROR;
		goto errout;
	}

	if (status != 0 && status != NT_STATUS_MORE_PROCESSING_REQUIRED) {
	errout:
		smb_user_logoff(user);
	}

	if (rbuf != NULL)
		kmem_free(rbuf, rlen);

	return (status);
}