s3/vfs: add SMB_VFS_OFFLOAD_READ_SEND/RECV
[samba.git] / source3 / modules / offload_token.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Ralph Boehme 2017
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "smbd/smbd.h"
22 #include "smbd/globals.h"
23 #include "dbwrap/dbwrap.h"
24 #include "dbwrap/dbwrap_rbt.h"
25 #include "dbwrap/dbwrap_open.h"
26 #include "../lib/util/util_tdb.h"
27 #include "librpc/gen_ndr/ndr_ioctl.h"
28 #include "librpc/gen_ndr/ioctl.h"
29 #include "offload_token.h"
30
31 struct vfs_offload_ctx {
32         bool initialized;
33         struct db_context *db_ctx;
34 };
35
36 NTSTATUS vfs_offload_token_ctx_init(TALLOC_CTX *mem_ctx,
37                                     struct vfs_offload_ctx **_ctx)
38 {
39         struct vfs_offload_ctx *ctx = *_ctx;
40
41         if (ctx != NULL) {
42                 if (!ctx->initialized) {
43                         return NT_STATUS_INTERNAL_ERROR;
44                 }
45                 return NT_STATUS_OK;
46         }
47
48         ctx = talloc_zero(mem_ctx, struct vfs_offload_ctx);
49         if (ctx == NULL) {
50                 return NT_STATUS_NO_MEMORY;
51         }
52
53         ctx->db_ctx = db_open_rbt(mem_ctx);
54         if (ctx->db_ctx == NULL) {
55                 TALLOC_FREE(ctx);
56                 return NT_STATUS_INTERNAL_ERROR;
57         }
58
59         ctx->initialized = true;
60         *_ctx = ctx;
61         return NT_STATUS_OK;
62 }
63
64 struct fsp_token_link {
65         struct vfs_offload_ctx *ctx;
66         DATA_BLOB token_blob;
67 };
68
69 static int fsp_token_link_destructor(struct fsp_token_link *link)
70 {
71         DATA_BLOB token_blob = link->token_blob;
72         TDB_DATA key = make_tdb_data(token_blob.data, token_blob.length);
73         NTSTATUS status;
74
75         status = dbwrap_delete(link->ctx->db_ctx, key);
76         if (!NT_STATUS_IS_OK(status)) {
77                 DBG_ERR("dbwrap_delete failed: %s. Token:\n", nt_errstr(status));
78                 dump_data(0, token_blob.data, token_blob.length);
79                 return -1;
80         }
81
82         return 0;
83 }
84
85 NTSTATUS vfs_offload_token_db_store_fsp(struct vfs_offload_ctx *ctx,
86                                         const files_struct *fsp,
87                                         const DATA_BLOB *token_blob)
88 {
89         struct db_record *rec = NULL;
90         struct fsp_token_link *link = NULL;
91         TDB_DATA key = make_tdb_data(token_blob->data, token_blob->length);
92         TDB_DATA value;
93         NTSTATUS status;
94
95         rec = dbwrap_fetch_locked(ctx->db_ctx, talloc_tos(), key);
96         if (rec == NULL) {
97                 return NT_STATUS_INTERNAL_ERROR;
98         }
99
100         value = dbwrap_record_get_value(rec);
101         if (value.dsize != 0) {
102                 void *ptr = NULL;
103                 files_struct *token_db_fsp = NULL;
104
105                 if (value.dsize != sizeof(ptr)) {
106                         DBG_ERR("Bad db entry for token:\n");
107                         dump_data(1, token_blob->data, token_blob->length);
108                         TALLOC_FREE(rec);
109                         return NT_STATUS_INTERNAL_ERROR;
110                 }
111                 memcpy(&ptr, value.dptr, value.dsize);
112                 TALLOC_FREE(rec);
113
114                 token_db_fsp = talloc_get_type_abort(ptr, struct files_struct);
115                 if (token_db_fsp != fsp) {
116                         DBG_ERR("token for fsp [%s] matches already known "
117                                 "but different fsp [%s]:\n",
118                                 fsp_str_dbg(fsp), fsp_str_dbg(token_db_fsp));
119                         dump_data(1, token_blob->data, token_blob->length);
120                         return NT_STATUS_INTERNAL_ERROR;
121                 }
122
123                 return NT_STATUS_OK;
124         }
125
126         link = talloc_zero(fsp, struct fsp_token_link);
127         if (link == NULL) {
128                 return NT_STATUS_NO_MEMORY;
129         }
130         link->ctx = ctx;
131         link->token_blob = data_blob_talloc(link, token_blob->data,
132                                             token_blob->length);
133         if (link->token_blob.data == NULL) {
134                 TALLOC_FREE(link);
135                 return NT_STATUS_NO_MEMORY;
136         }
137         talloc_set_destructor(link, fsp_token_link_destructor);
138
139         value = make_tdb_data((uint8_t *)&fsp, sizeof(files_struct *));
140
141         status = dbwrap_record_store(rec, value, 0);
142         if (!NT_STATUS_IS_OK(status)) {
143                 DBG_ERR("dbwrap_record_store for [%s] failed: %s. Token\n",
144                         fsp_str_dbg(fsp), nt_errstr(status));
145                 dump_data(0, token_blob->data, token_blob->length);
146                 TALLOC_FREE(link);
147                 TALLOC_FREE(rec);
148                 return status;
149         }
150
151         TALLOC_FREE(rec);
152         return NT_STATUS_OK;
153 }
154
155 NTSTATUS vfs_offload_token_db_fetch_fsp(struct vfs_offload_ctx *ctx,
156                                         const DATA_BLOB *token_blob,
157                                         files_struct **fsp)
158 {
159         struct db_record *rec = NULL;
160         TDB_DATA key = make_tdb_data(token_blob->data, token_blob->length);
161         TDB_DATA value;
162         void *ptr = NULL;
163
164         rec = dbwrap_fetch_locked(ctx->db_ctx, talloc_tos(), key);
165         if (rec == NULL) {
166                 return NT_STATUS_INTERNAL_ERROR;
167         }
168
169         value = dbwrap_record_get_value(rec);
170         if (value.dsize == 0) {
171                 DBG_DEBUG("Unknown token:\n");
172                 dump_data(10, token_blob->data, token_blob->length);
173                 TALLOC_FREE(rec);
174                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
175         }
176
177         if (value.dsize != sizeof(ptr)) {
178                 DBG_ERR("Bad db entry for token:\n");
179                 dump_data(1, token_blob->data, token_blob->length);
180                 TALLOC_FREE(rec);
181                 return NT_STATUS_INTERNAL_ERROR;
182         }
183
184         memcpy(&ptr, value.dptr, value.dsize);
185         TALLOC_FREE(rec);
186
187         *fsp = talloc_get_type_abort(ptr, struct files_struct);
188         return NT_STATUS_OK;
189 }
190
191 NTSTATUS vfs_offload_token_create_blob(TALLOC_CTX *mem_ctx,
192                                        const files_struct *fsp,
193                                        uint32_t fsctl,
194                                        DATA_BLOB *token_blob)
195 {
196         size_t len;
197
198         switch (fsctl) {
199         case FSCTL_DUP_EXTENTS_TO_FILE:
200                 len = 20;
201                 break;
202         case FSCTL_SRV_REQUEST_RESUME_KEY:
203                 len = 24;
204                 break;
205         default:
206                 DBG_ERR("Invalid fsctl [%" PRIu32 "]\n", fsctl);
207                 return NT_STATUS_NOT_SUPPORTED;
208         }
209
210         *token_blob = data_blob_talloc_zero(mem_ctx, len);
211         if (token_blob->length == 0) {
212                 return NT_STATUS_NO_MEMORY;
213         }
214
215         /* combine persistent and volatile handles for the resume key */
216         SBVAL(token_blob->data,  0, fsp->op->global->open_persistent_id);
217         SBVAL(token_blob->data,  8, fsp->op->global->open_volatile_id);
218         SIVAL(token_blob->data, 16, fsctl);
219
220         return NT_STATUS_OK;
221 }
222