/* * 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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2017 Nexenta Systems, Inc. All rights reserved. */ #include #include static void smb_tcon_puterror(smb_request_t *sr, uint32_t status) { switch (status) { case NT_STATUS_BAD_NETWORK_NAME: /* Intentional status=0 */ smbsr_error(sr, 0, ERRSRV, ERRinvnetname); break; case NT_STATUS_ACCESS_DENIED: smbsr_error(sr, status, ERRSRV, ERRaccess); break; case NT_STATUS_BAD_DEVICE_TYPE: smbsr_error(sr, status, ERRDOS, ERROR_BAD_DEV_TYPE); break; default: case NT_STATUS_INTERNAL_ERROR: /* Intentional status=0 */ smbsr_error(sr, 0, ERRSRV, ERRsrverror); break; } } /* * SmbTreeConnect: Map a share to a tree and obtain a tree-id (TID). * * Client Request Description * ================================== ================================= * * UCHAR WordCount; Count of parameter words = 0 * USHORT ByteCount; Count of data bytes; min = 4 * UCHAR BufferFormat1; 0x04 * STRING Path[]; Server name and share name * UCHAR BufferFormat2; 0x04 * STRING Password[]; Password * UCHAR BufferFormat3; 0x04 * STRING Service[]; Service name * * The CIFS server responds with: * * Server Response Description * ================================ ================================= * * UCHAR WordCount; Count of parameter words = 2 * USHORT MaxBufferSize; Max size message the server handles * USHORT Tid; Tree ID * USHORT ByteCount; Count of data bytes = 0 * * If the negotiated dialect is MICROSOFT NETWORKS 1.03 or earlier, * MaxBufferSize in the response message indicates the maximum size * message that the server can handle. The client should not generate * messages, nor expect to receive responses, larger than this. This * must be constant for a given server. For newer dialects, this field * is ignored. */ smb_sdrc_t smb_pre_tree_connect(smb_request_t *sr) { smb_arg_tcon_t *tcon = &sr->sr_tcon; int rc; /* * Perhaps this should be "%A.sA" now that unicode is enabled. */ rc = smbsr_decode_data(sr, "%AAA", sr, &tcon->path, &tcon->password, &tcon->service); tcon->flags = 0; tcon->optional_support = 0; DTRACE_SMB_START(op__TreeConnect, smb_request_t *, sr); return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); } void smb_post_tree_connect(smb_request_t *sr) { DTRACE_SMB_DONE(op__TreeConnect, smb_request_t *, sr); } smb_sdrc_t smb_com_tree_connect(smb_request_t *sr) { uint32_t status; int rc; status = smb_tree_connect(sr); if (status) { smb_tcon_puterror(sr, status); return (SDRC_ERROR); } rc = smbsr_encode_result(sr, 2, 0, "bwww", 2, /* wct */ (WORD)smb_maxbufsize, /* MaxBufferSize */ sr->smb_tid, /* TID */ 0); /* bcc */ return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); } /* * SmbTreeConnectX: Map a share to a tree and obtain a tree-id (TID). * * Client Request Description * ================================= ================================= * * UCHAR WordCount; Count of parameter words = 4 * UCHAR AndXCommand; Secondary (X) command; 0xFF = none * UCHAR AndXReserved; Reserved (must be 0) * USHORT AndXOffset; Offset to next command WordCount * USHORT Flags; Additional information * bit 0 set = disconnect Tid * USHORT PasswordLength; Length of Password[] * USHORT ByteCount; Count of data bytes; min = 3 * UCHAR Password[]; Password * STRING Path[]; Server name and share name * STRING Service[]; Service name * * If the negotiated dialect is LANMAN1.0 or later, then it is a protocol * violation for the client to send this message prior to a successful * SMB_COM_SESSION_SETUP_ANDX, and the server ignores Password. * * If the negotiated dialect is prior to LANMAN1.0 and the client has not * sent a successful SMB_COM_SESSION_SETUP_ANDX request when the tree * connect arrives, a user level security mode server must nevertheless * validate the client's credentials. * * Flags (prefix with TREE_CONNECT_ANDX_): * ========================== ======================================== * 0x0001 DISCONECT_TID The tree specified by TID in the SMB header * should be disconnected - disconnect errors * should be ignored. * * 0x0004 EXTENDED_SIGNATURES Client request for signing key protection. * * 0x0008 EXTENDED_RESPONSE Client request for extended information. * * Path follows UNC style syntax (\\server\share) and indicates the name * of the resource to which the client wishes to connect. * * Because Password may be an authentication response, it is a variable * length field with the length specified by PasswordLength. If * authentication is not being used, Password should be a null terminated * ASCII string with PasswordLength set to the string size including the * terminating null. * * The server can enforce whatever policy it desires to govern share * access. Administrative privilege is required for administrative * shares (C$, etc.). * * The Service component indicates the type of resource the client * intends to access. Valid values are: * * Service Description Earliest Dialect Allowed * ======== ======================== ================================ * * A: disk share PC NETWORK PROGRAM 1.0 * LPT1: printer PC NETWORK PROGRAM 1.0 * IPC named pipe MICROSOFT NETWORKS 3.0 * COMM communications device MICROSOFT NETWORKS 3.0 * ????? any type of device MICROSOFT NETWORKS 3.0 * * If the negotiated dialect is earlier than DOS LANMAN2.1, the response to * this SMB is: * * Server Response Description * ================================ =================================== * * UCHAR WordCount; Count of parameter words = 2 * UCHAR AndXCommand; Secondary (X) command; 0xFF = none * UCHAR AndXReserved; Reserved (must be 0) * USHORT AndXOffset; Offset to next command WordCount * USHORT ByteCount; Count of data bytes; min = 3 * * If the negotiated is DOS LANMAN2.1 or later, the response to this SMB * is: * * Server Response Description * ================================ =================================== * * UCHAR WordCount; Count of parameter words = 3 * UCHAR AndXCommand; Secondary (X) command; 0xFF = none * UCHAR AndXReserved; Reserved (must be 0) * USHORT AndXOffset; Offset to next command WordCount * USHORT OptionalSupport; Optional support bits * USHORT ByteCount; Count of data bytes; min = 3 * UCHAR Service[]; Service type connected to. Always * ANSII. * STRING NativeFileSystem[]; Native file system for this tree * * NativeFileSystem is the name of the filesystem; values to be expected * include FAT, NTFS, etc. * * OptionalSupport: * ============================== ========================== * 0x0001 SMB_SUPPORT_SEARCH_BITS The server supports the use of Search * Attributes in client requests. * 0x0002 SMB_SHARE_IS_IN_DFS The share is managed by DFS. * 0x000C SMB_CSC_MASK Offline-caching mask - see CSC flags. * 0x0010 SMB_UNIQUE_FILE_NAME The server uses long names and does not * support short names. Indicator for * clients directory/name-space caching. * 0x0020 SMB_EXTENDED_SIGNATURES The server will use signing key protection. * * Client-side caching (offline files): * ============================== ========================== * 0x0000 SMB_CSC_CACHE_MANUAL_REINT Clients may cache files for offline use * but automatic file-by-file reintegration * is not allowed. * 0x0004 SMB_CSC_CACHE_AUTO_REINT Automatic file-by-file reintegration is * allowed. * 0x0008 SMB_CSC_CACHE_VDO File opens do not need to be flowed. * 0x000C SMB_CSC_CACHE_NONE CSC is disabled for this share. * * Some servers negotiate "DOS LANMAN2.1" dialect or later and still send * the "downlevel" (i.e. wordcount==2) response. Valid AndX following * commands are * * SMB_COM_OPEN SMB_COM_OPEN_ANDX SMB_COM_CREATE * SMB_COM_CREATE_NEW SMB_COM_CREATE_DIRECTORY SMB_COM_DELETE * SMB_COM_DELETE_DIRECTORY SMB_COM_FIND SMB_COM_COPY * SMB_COM_FIND_UNIQUE SMB_COM_RENAME * SMB_COM_CHECK_DIRECTORY SMB_COM_QUERY_INFORMATION * SMB_COM_GET_PRINT_QUEUE SMB_COM_OPEN_PRINT_FILE * SMB_COM_TRANSACTION SMB_COM_NO_ANDX_CMD * SMB_COM_SET_INFORMATION SMB_COM_NT_RENAME * * Errors: * ERRDOS/ERRnomem * ERRDOS/ERRbadpath * ERRDOS/ERRinvdevice * ERRSRV/ERRaccess * ERRSRV/ERRbadpw * ERRSRV/ERRinvnetname */ smb_sdrc_t smb_pre_tree_connect_andx(smb_request_t *sr) { smb_arg_tcon_t *tcon = &sr->sr_tcon; uint8_t *pwbuf = NULL; uint16_t pwlen = 0; int rc; rc = smbsr_decode_vwv(sr, "b.www", &sr->andx_com, &sr->andx_off, &tcon->flags, &pwlen); if (rc == 0) { if (pwlen != 0) pwbuf = smb_srm_zalloc(sr, pwlen); rc = smbsr_decode_data(sr, "%#cus", sr, pwlen, pwbuf, &tcon->path, &tcon->service); tcon->pwdlen = pwlen; tcon->password = (char *)pwbuf; } tcon->optional_support = 0; DTRACE_SMB_START(op__TreeConnectX, smb_request_t *, sr); return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); } void smb_post_tree_connect_andx(smb_request_t *sr) { DTRACE_SMB_DONE(op__TreeConnectX, smb_request_t *, sr); } smb_sdrc_t smb_com_tree_connect_andx(smb_request_t *sr) { smb_arg_tcon_t *tcon = &sr->sr_tcon; smb_tree_t *tree; char *service; uint32_t status; int rc; if (tcon->flags & SMB_TCONX_DISCONECT_TID) { tree = smb_session_lookup_tree(sr->session, sr->smb_tid); if (tree != NULL) { smb_tree_disconnect(tree, B_TRUE); smb_session_cancel_requests(sr->session, tree, sr); } } status = smb_tree_connect(sr); if (status) { smb_tcon_puterror(sr, status); return (SDRC_ERROR); } tree = sr->tid_tree; switch (tree->t_res_type & STYPE_MASK) { case STYPE_IPC: service = "IPC"; break; case STYPE_PRINTQ: service = "LPT1:"; break; case STYPE_DISKTREE: default: service = "A:"; } if (sr->session->dialect < NT_LM_0_12) { rc = smbsr_encode_result(sr, 2, VAR_BCC, "bb.ww%ss", (char)2, /* wct */ sr->andx_com, VAR_BCC, VAR_BCC, sr, service, tree->t_typename); } else if ((tcon->flags & SMB_TCONX_EXTENDED_RESPONSE) == 0) { rc = smbsr_encode_result(sr, 3, VAR_BCC, "bb.www%su", (char)3, /* wct */ sr->andx_com, (short)64, tcon->optional_support, VAR_BCC, sr, service, tree->t_typename); } else { rc = smbsr_encode_result(sr, 7, VAR_BCC, "bb.wwllw%su", (char)7, /* wct (b) */ sr->andx_com, /* AndXcmd (b) */ (short)72, /* AndXoff (w) */ tcon->optional_support, /* (w) */ tree->t_access, /* (l) */ 0, /* guest_access (l) */ VAR_BCC, /* (w) */ sr, /* (%) */ service, /* (s) */ tree->t_typename); /* (u) */ } return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); } /* * SmbTreeDisconnect: Disconnect a tree. * * Note: SDDF_SUPPRESS_UID is set for this operation, which means the sr * uid_user field will not be valid on entry to these functions. Do not * use it until it is set up in smb_com_tree_disconnect() or the system * will panic. * * Note: there are scenarios in which the client does not send a tree * disconnect request, for example, when ERRbaduid is returned from * SmbReadX after a user has logged off. Any open files will remain * around until the session is destroyed. * * Client Request Description * ================================== ================================= * * UCHAR WordCount; Count of parameter words = 0 * USHORT ByteCount; Count of data bytes = 0 * * The resource sharing connection identified by Tid in the SMB header is * logically disconnected from the server. Tid is invalidated; it will not * be recognized if used by the client for subsequent requests. All locks, * open files, etc. created on behalf of Tid are released. * * Server Response Description * ================================== ================================= * * UCHAR WordCount; Count of parameter words = 0 * USHORT ByteCount; Count of data bytes = 0 * * Errors: * ERRSRV/ERRinvnid * ERRSRV/ERRbaduid */ smb_sdrc_t smb_pre_tree_disconnect(smb_request_t *sr) { sr->uid_user = smb_session_lookup_uid(sr->session, sr->smb_uid); sr->tid_tree = smb_session_lookup_tree(sr->session, sr->smb_tid); DTRACE_SMB_START(op__TreeDisconnect, smb_request_t *, sr); return (SDRC_SUCCESS); } void smb_post_tree_disconnect(smb_request_t *sr) { DTRACE_SMB_DONE(op__TreeDisconnect, smb_request_t *, sr); } /* * SmbTreeDisconnect requires a valid UID as well as a valid TID. Some * clients logoff a user and then try to disconnect the trees connected * by the user who has just been logged off, which would normally fail * in the dispatch code with ERRbaduid but, unfortunately, ERRbaduid * causes a problem for some of those clients. Windows returns ERRinvnid. * * To prevent ERRbaduid being returned, the UID and TID are looked up here * rather than prior to dispatching SmbTreeDisconnect requests. If either * the UID or the TID is invalid, ERRinvnid is returned. */ smb_sdrc_t smb_com_tree_disconnect(smb_request_t *sr) { if (sr->uid_user == NULL || sr->tid_tree == NULL) { smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRinvnid); return (SDRC_ERROR); } sr->user_cr = smb_user_getcred(sr->uid_user); smb_tree_disconnect(sr->tid_tree, B_TRUE); smb_session_cancel_requests(sr->session, sr->tid_tree, sr); if (smbsr_encode_empty_result(sr)) return (SDRC_ERROR); return (SDRC_SUCCESS); }