2 * Unix SMB/CIFS implementation.
3 * Util functions valid in the SMB1 server
5 * Copyright (C) Volker Lendecke 2019
6 * Copyright by the authors of the functions moved here eventually
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "smbd/smbd.h"
24 #include "smbd/globals.h"
25 #include "libcli/security/security.h"
26 #include "lib/util/sys_rw_data.h"
27 #include "smbd/fd_handle.h"
29 /****************************************************************************
30 Special FCB or DOS processing in the case of a sharing violation.
31 Try and find a duplicated file handle.
32 ****************************************************************************/
34 struct files_struct
*fcb_or_dos_open(
35 struct smb_request
*req
,
36 const struct smb_filename
*smb_fname
,
38 uint32_t create_options
,
39 uint32_t private_flags
)
41 struct connection_struct
*conn
= req
->conn
;
42 struct file_id id
= vfs_file_id_from_sbuf(conn
, &smb_fname
->st
);
43 struct files_struct
*fsp
= NULL
, *new_fsp
= NULL
;
47 (NTCREATEX_FLAG_DENY_DOS
|
48 NTCREATEX_FLAG_DENY_FCB
))
53 for(fsp
= file_find_di_first(conn
->sconn
, id
, true);
55 fsp
= file_find_di_next(fsp
, true)) {
57 DBG_DEBUG("Checking file %s, fd = %d, vuid = %"PRIu64
", "
58 "file_pid = %"PRIu16
", "
59 "private_options = 0x%"PRIx32
", "
60 "access_mask = 0x%"PRIx32
"\n",
62 fsp_get_pathref_fd(fsp
),
65 fh_get_private_options(fsp
->fh
),
68 if (fsp_get_pathref_fd(fsp
) != -1 &&
69 fsp
->vuid
== req
->vuid
&&
70 fsp
->file_pid
== req
->smbpid
&&
71 (fh_get_private_options(fsp
->fh
) &
72 (NTCREATEX_FLAG_DENY_DOS
|
73 NTCREATEX_FLAG_DENY_FCB
)) &&
74 (fsp
->access_mask
& FILE_WRITE_DATA
) &&
75 strequal(fsp
->fsp_name
->base_name
, smb_fname
->base_name
) &&
76 strequal(fsp
->fsp_name
->stream_name
,
77 smb_fname
->stream_name
)) {
78 DBG_DEBUG("file match\n");
87 /* quite an insane set of semantics ... */
88 if (is_executable(smb_fname
->base_name
) &&
89 (fh_get_private_options(fsp
->fh
) & NTCREATEX_FLAG_DENY_DOS
)) {
90 DBG_DEBUG("file fail due to is_executable.\n");
94 status
= file_new(req
, conn
, &new_fsp
);
95 if (!NT_STATUS_IS_OK(status
)) {
96 DBG_DEBUG("file_new failed: %s\n", nt_errstr(status
));
100 status
= dup_file_fsp(fsp
, access_mask
, new_fsp
);
102 if (!NT_STATUS_IS_OK(status
)) {
103 DBG_DEBUG("dup_file_fsp failed: %s\n", nt_errstr(status
));
104 file_free(req
, new_fsp
);
111 /****************************************************************************
112 Send a keepalive packet (rfc1002).
113 ****************************************************************************/
115 bool send_keepalive(int client
)
117 unsigned char buf
[4];
119 buf
[0] = NBSSkeepalive
;
120 buf
[1] = buf
[2] = buf
[3] = 0;
122 return(write_data(client
,(char *)buf
,4) == 4);
125 /*******************************************************************
126 Add a string to the end of a smb_buf, adjusting bcc and smb_len.
127 Return the bytes added
128 ********************************************************************/
130 ssize_t
message_push_string(uint8_t **outbuf
, const char *str
, int flags
)
132 size_t buf_size
= smb_len(*outbuf
) + 4;
139 * We need to over-allocate, now knowing what srvstr_push will
140 * actually use. This is very generous by incorporating potential
141 * padding, the terminating 0 and at most 4 chars per UTF-16 code
144 grow_size
= (strlen(str
) + 2) * 4;
146 if (!(tmp
= talloc_realloc(NULL
, *outbuf
, uint8_t,
147 buf_size
+ grow_size
))) {
148 DEBUG(0, ("talloc failed\n"));
152 status
= srvstr_push((char *)tmp
, SVAL(tmp
, smb_flg2
),
153 tmp
+ buf_size
, str
, grow_size
, flags
, &result
);
155 if (!NT_STATUS_IS_OK(status
)) {
156 DEBUG(0, ("srvstr_push failed\n"));
161 * Ensure we clear out the extra data we have
162 * grown the buffer by, but not written to.
164 if (buf_size
+ result
< buf_size
) {
167 if (grow_size
< result
) {
171 memset(tmp
+ buf_size
+ result
, '\0', grow_size
- result
);
173 set_message_bcc((char *)tmp
, smb_buflen(tmp
) + result
);
181 * Deal with the SMB1 semantics of sending a pathname with a
182 * wildcard as the terminal component for a SMB1search or
186 NTSTATUS
filename_convert_smb1_search_path(TALLOC_CTX
*ctx
,
187 connection_struct
*conn
,
190 struct files_struct
**_dirfsp
,
191 struct smb_filename
**_smb_fname_out
,
197 struct smb_filename
*smb_fname
= NULL
;
200 *_smb_fname_out
= NULL
;
204 DBG_DEBUG("name_in: %s\n", name_in
);
206 if (ucf_flags
& UCF_GMT_PATHNAME
) {
207 extract_snapshot_token(name_in
, &twrp
);
208 ucf_flags
&= ~UCF_GMT_PATHNAME
;
211 /* Get the original lcomp. */
212 mask
= get_original_lcomp(ctx
, conn
, name_in
, ucf_flags
);
214 return NT_STATUS_NO_MEMORY
;
217 if (mask
[0] == '\0') {
218 /* Windows and OS/2 systems treat search on the root as * */
220 mask
= talloc_strdup(ctx
, "*");
222 return NT_STATUS_NO_MEMORY
;
226 DBG_DEBUG("mask = %s\n", mask
);
229 * Remove the terminal component so
230 * filename_convert_dirfsp never sees the mask.
232 p
= strrchr_m(name_in
, '/');
234 /* filename_convert_dirfsp handles a '\0' name. */
240 DBG_DEBUG("For filename_convert_dirfsp: name_in = %s\n", name_in
);
242 /* Convert the parent directory path. */
243 status
= filename_convert_dirfsp(ctx
,
251 if (!NT_STATUS_IS_OK(status
)) {
252 DBG_DEBUG("filename_convert error for %s: %s\n",
257 *_smb_fname_out
= talloc_move(ctx
, &smb_fname
);
258 *_mask_out
= talloc_move(ctx
, &mask
);