vfs_ceph: Implement SMB_VFS_FSET_DOS_ATTRIBUTES for precise btime
[Samba.git] / source3 / smbd / smb1_utils.c
blobbdd842c504fd3c6b553a668902114dc6f737891a
1 /*
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/>.
22 #include "includes.h"
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,
37 uint32_t access_mask,
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;
44 NTSTATUS status;
46 if ((private_flags &
47 (NTCREATEX_FLAG_DENY_DOS|
48 NTCREATEX_FLAG_DENY_FCB))
49 == 0) {
50 return NULL;
53 for(fsp = file_find_di_first(conn->sconn, id, true);
54 fsp != NULL;
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",
61 fsp_str_dbg(fsp),
62 fsp_get_pathref_fd(fsp),
63 fsp->vuid,
64 fsp->file_pid,
65 fh_get_private_options(fsp->fh),
66 fsp->access_mask);
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");
79 break;
83 if (fsp == NULL) {
84 return NULL;
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");
91 return NULL;
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));
97 return NULL;
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);
105 return NULL;
108 return 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;
133 size_t grow_size;
134 size_t result = 0;
135 uint8_t *tmp;
136 NTSTATUS status;
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
142 * point.
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"));
149 return -1;
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"));
157 return -1;
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) {
165 return -1;
167 if (grow_size < result) {
168 return -1;
171 memset(tmp + buf_size + result, '\0', grow_size - result);
173 set_message_bcc((char *)tmp, smb_buflen(tmp) + result);
175 *outbuf = tmp;
177 return result;
181 * Deal with the SMB1 semantics of sending a pathname with a
182 * wildcard as the terminal component for a SMB1search or
183 * trans2 findfirst.
186 NTSTATUS filename_convert_smb1_search_path(TALLOC_CTX *ctx,
187 connection_struct *conn,
188 char *name_in,
189 uint32_t ucf_flags,
190 struct files_struct **_dirfsp,
191 struct smb_filename **_smb_fname_out,
192 char **_mask_out)
194 NTSTATUS status;
195 char *p = NULL;
196 char *mask = NULL;
197 struct smb_filename *smb_fname = NULL;
198 NTTIME twrp = 0;
200 *_smb_fname_out = NULL;
201 *_dirfsp = NULL;
202 *_mask_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);
213 if (mask == NULL) {
214 return NT_STATUS_NO_MEMORY;
217 if (mask[0] == '\0') {
218 /* Windows and OS/2 systems treat search on the root as * */
219 TALLOC_FREE(mask);
220 mask = talloc_strdup(ctx, "*");
221 if (mask == NULL) {
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, '/');
233 if (p == NULL) {
234 /* filename_convert_dirfsp handles a '\0' name. */
235 name_in[0] = '\0';
236 } else {
237 *p = '\0';
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,
244 conn,
245 name_in,
246 ucf_flags,
247 twrp,
248 _dirfsp,
249 &smb_fname);
251 if (!NT_STATUS_IS_OK(status)) {
252 DBG_DEBUG("filename_convert error for %s: %s\n",
253 name_in,
254 nt_errstr(status));
257 *_smb_fname_out = talloc_move(ctx, &smb_fname);
258 *_mask_out = talloc_move(ctx, &mask);
260 return status;