1/* 2 Unix SMB/CIFS implementation. 3 4 Copyright (C) Andrew Tridgell 2008 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 a composite API for making SMB-like calls using SMB2. This is useful 21 as SMB2 often requires more than one requests where a single SMB 22 request would do. In converting code that uses SMB to use SMB2, 23 these routines make life a lot easier 24*/ 25 26 27#include "includes.h" 28#include "libcli/raw/libcliraw.h" 29#include "libcli/raw/raw_proto.h" 30#include "libcli/composite/composite.h" 31#include "libcli/smb_composite/smb_composite.h" 32#include "libcli/smb2/smb2_calls.h" 33 34/* 35 continue after a SMB2 close 36 */ 37static void continue_close(struct smb2_request *req) 38{ 39 struct composite_context *ctx = talloc_get_type(req->async.private_data, 40 struct composite_context); 41 NTSTATUS status; 42 struct smb2_close close_parm; 43 44 status = smb2_close_recv(req, &close_parm); 45 composite_error(ctx, status); 46} 47 48/* 49 continue after the create in a composite unlink 50 */ 51static void continue_unlink(struct smb2_request *req) 52{ 53 struct composite_context *ctx = talloc_get_type(req->async.private_data, 54 struct composite_context); 55 struct smb2_tree *tree = req->tree; 56 struct smb2_create create_parm; 57 struct smb2_close close_parm; 58 NTSTATUS status; 59 60 status = smb2_create_recv(req, ctx, &create_parm); 61 if (!NT_STATUS_IS_OK(status)) { 62 composite_error(ctx, status); 63 return; 64 } 65 66 ZERO_STRUCT(close_parm); 67 close_parm.in.file.handle = create_parm.out.file.handle; 68 69 req = smb2_close_send(tree, &close_parm); 70 composite_continue_smb2(ctx, req, continue_close, ctx); 71} 72 73/* 74 composite SMB2 unlink call 75*/ 76struct composite_context *smb2_composite_unlink_send(struct smb2_tree *tree, 77 union smb_unlink *io) 78{ 79 struct composite_context *ctx; 80 struct smb2_create create_parm; 81 struct smb2_request *req; 82 83 ctx = composite_create(tree, tree->session->transport->socket->event.ctx); 84 if (ctx == NULL) return NULL; 85 86 /* check for wildcards - we could support these with a 87 search, but for now they aren't necessary */ 88 if (strpbrk(io->unlink.in.pattern, "*?<>") != NULL) { 89 composite_error(ctx, NT_STATUS_NOT_SUPPORTED); 90 return ctx; 91 } 92 93 ZERO_STRUCT(create_parm); 94 create_parm.in.desired_access = SEC_STD_DELETE; 95 create_parm.in.create_disposition = NTCREATEX_DISP_OPEN; 96 create_parm.in.share_access = 97 NTCREATEX_SHARE_ACCESS_DELETE| 98 NTCREATEX_SHARE_ACCESS_READ| 99 NTCREATEX_SHARE_ACCESS_WRITE; 100 create_parm.in.create_options = 101 NTCREATEX_OPTIONS_DELETE_ON_CLOSE | 102 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE; 103 create_parm.in.fname = io->unlink.in.pattern; 104 if (create_parm.in.fname[0] == '\\') { 105 create_parm.in.fname++; 106 } 107 108 req = smb2_create_send(tree, &create_parm); 109 110 composite_continue_smb2(ctx, req, continue_unlink, ctx); 111 return ctx; 112} 113 114 115/* 116 composite unlink call - sync interface 117*/ 118NTSTATUS smb2_composite_unlink(struct smb2_tree *tree, union smb_unlink *io) 119{ 120 struct composite_context *c = smb2_composite_unlink_send(tree, io); 121 return composite_wait_free(c); 122} 123 124 125 126 127/* 128 continue after the create in a composite mkdir 129 */ 130static void continue_mkdir(struct smb2_request *req) 131{ 132 struct composite_context *ctx = talloc_get_type(req->async.private_data, 133 struct composite_context); 134 struct smb2_tree *tree = req->tree; 135 struct smb2_create create_parm; 136 struct smb2_close close_parm; 137 NTSTATUS status; 138 139 status = smb2_create_recv(req, ctx, &create_parm); 140 if (!NT_STATUS_IS_OK(status)) { 141 composite_error(ctx, status); 142 return; 143 } 144 145 ZERO_STRUCT(close_parm); 146 close_parm.in.file.handle = create_parm.out.file.handle; 147 148 req = smb2_close_send(tree, &close_parm); 149 composite_continue_smb2(ctx, req, continue_close, ctx); 150} 151 152/* 153 composite SMB2 mkdir call 154*/ 155struct composite_context *smb2_composite_mkdir_send(struct smb2_tree *tree, 156 union smb_mkdir *io) 157{ 158 struct composite_context *ctx; 159 struct smb2_create create_parm; 160 struct smb2_request *req; 161 162 ctx = composite_create(tree, tree->session->transport->socket->event.ctx); 163 if (ctx == NULL) return NULL; 164 165 ZERO_STRUCT(create_parm); 166 167 create_parm.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED; 168 create_parm.in.share_access = 169 NTCREATEX_SHARE_ACCESS_READ| 170 NTCREATEX_SHARE_ACCESS_WRITE; 171 create_parm.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; 172 create_parm.in.file_attributes = FILE_ATTRIBUTE_DIRECTORY; 173 create_parm.in.create_disposition = NTCREATEX_DISP_CREATE; 174 create_parm.in.fname = io->mkdir.in.path; 175 if (create_parm.in.fname[0] == '\\') { 176 create_parm.in.fname++; 177 } 178 179 req = smb2_create_send(tree, &create_parm); 180 181 composite_continue_smb2(ctx, req, continue_mkdir, ctx); 182 183 return ctx; 184} 185 186 187/* 188 composite mkdir call - sync interface 189*/ 190NTSTATUS smb2_composite_mkdir(struct smb2_tree *tree, union smb_mkdir *io) 191{ 192 struct composite_context *c = smb2_composite_mkdir_send(tree, io); 193 return composite_wait_free(c); 194} 195 196 197 198/* 199 continue after the create in a composite rmdir 200 */ 201static void continue_rmdir(struct smb2_request *req) 202{ 203 struct composite_context *ctx = talloc_get_type(req->async.private_data, 204 struct composite_context); 205 struct smb2_tree *tree = req->tree; 206 struct smb2_create create_parm; 207 struct smb2_close close_parm; 208 NTSTATUS status; 209 210 status = smb2_create_recv(req, ctx, &create_parm); 211 if (!NT_STATUS_IS_OK(status)) { 212 composite_error(ctx, status); 213 return; 214 } 215 216 ZERO_STRUCT(close_parm); 217 close_parm.in.file.handle = create_parm.out.file.handle; 218 219 req = smb2_close_send(tree, &close_parm); 220 composite_continue_smb2(ctx, req, continue_close, ctx); 221} 222 223/* 224 composite SMB2 rmdir call 225*/ 226struct composite_context *smb2_composite_rmdir_send(struct smb2_tree *tree, 227 struct smb_rmdir *io) 228{ 229 struct composite_context *ctx; 230 struct smb2_create create_parm; 231 struct smb2_request *req; 232 233 ctx = composite_create(tree, tree->session->transport->socket->event.ctx); 234 if (ctx == NULL) return NULL; 235 236 ZERO_STRUCT(create_parm); 237 create_parm.in.desired_access = SEC_STD_DELETE; 238 create_parm.in.create_disposition = NTCREATEX_DISP_OPEN; 239 create_parm.in.share_access = 240 NTCREATEX_SHARE_ACCESS_DELETE| 241 NTCREATEX_SHARE_ACCESS_READ| 242 NTCREATEX_SHARE_ACCESS_WRITE; 243 create_parm.in.create_options = 244 NTCREATEX_OPTIONS_DIRECTORY | 245 NTCREATEX_OPTIONS_DELETE_ON_CLOSE; 246 create_parm.in.fname = io->in.path; 247 if (create_parm.in.fname[0] == '\\') { 248 create_parm.in.fname++; 249 } 250 251 req = smb2_create_send(tree, &create_parm); 252 253 composite_continue_smb2(ctx, req, continue_rmdir, ctx); 254 return ctx; 255} 256 257 258/* 259 composite rmdir call - sync interface 260*/ 261NTSTATUS smb2_composite_rmdir(struct smb2_tree *tree, struct smb_rmdir *io) 262{ 263 struct composite_context *c = smb2_composite_rmdir_send(tree, io); 264 return composite_wait_free(c); 265} 266 267 268/* 269 continue after the setfileinfo in a composite setpathinfo 270 */ 271static void continue_setpathinfo_close(struct smb2_request *req) 272{ 273 struct composite_context *ctx = talloc_get_type(req->async.private_data, 274 struct composite_context); 275 struct smb2_tree *tree = req->tree; 276 struct smb2_close close_parm; 277 NTSTATUS status; 278 union smb_setfileinfo *io2 = talloc_get_type(ctx->private_data, 279 union smb_setfileinfo); 280 281 status = smb2_setinfo_recv(req); 282 if (!NT_STATUS_IS_OK(status)) { 283 composite_error(ctx, status); 284 return; 285 } 286 287 ZERO_STRUCT(close_parm); 288 close_parm.in.file.handle = io2->generic.in.file.handle; 289 290 req = smb2_close_send(tree, &close_parm); 291 composite_continue_smb2(ctx, req, continue_close, ctx); 292} 293 294 295/* 296 continue after the create in a composite setpathinfo 297 */ 298static void continue_setpathinfo(struct smb2_request *req) 299{ 300 struct composite_context *ctx = talloc_get_type(req->async.private_data, 301 struct composite_context); 302 struct smb2_tree *tree = req->tree; 303 struct smb2_create create_parm; 304 NTSTATUS status; 305 union smb_setfileinfo *io2 = talloc_get_type(ctx->private_data, 306 union smb_setfileinfo); 307 308 status = smb2_create_recv(req, ctx, &create_parm); 309 if (!NT_STATUS_IS_OK(status)) { 310 composite_error(ctx, status); 311 return; 312 } 313 314 io2->generic.in.file.handle = create_parm.out.file.handle; 315 316 req = smb2_setinfo_file_send(tree, io2); 317 composite_continue_smb2(ctx, req, continue_setpathinfo_close, ctx); 318} 319 320 321/* 322 composite SMB2 setpathinfo call 323*/ 324struct composite_context *smb2_composite_setpathinfo_send(struct smb2_tree *tree, 325 union smb_setfileinfo *io) 326{ 327 struct composite_context *ctx; 328 struct smb2_create create_parm; 329 struct smb2_request *req; 330 union smb_setfileinfo *io2; 331 332 ctx = composite_create(tree, tree->session->transport->socket->event.ctx); 333 if (ctx == NULL) return NULL; 334 335 ZERO_STRUCT(create_parm); 336 create_parm.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED; 337 create_parm.in.create_disposition = NTCREATEX_DISP_OPEN; 338 create_parm.in.share_access = 339 NTCREATEX_SHARE_ACCESS_DELETE| 340 NTCREATEX_SHARE_ACCESS_READ| 341 NTCREATEX_SHARE_ACCESS_WRITE; 342 create_parm.in.create_options = 0; 343 create_parm.in.fname = io->generic.in.file.path; 344 if (create_parm.in.fname[0] == '\\') { 345 create_parm.in.fname++; 346 } 347 348 req = smb2_create_send(tree, &create_parm); 349 350 io2 = talloc(ctx, union smb_setfileinfo); 351 if (composite_nomem(io2, ctx)) { 352 return ctx; 353 } 354 *io2 = *io; 355 356 ctx->private_data = io2; 357 358 composite_continue_smb2(ctx, req, continue_setpathinfo, ctx); 359 return ctx; 360} 361 362 363/* 364 composite setpathinfo call 365 */ 366NTSTATUS smb2_composite_setpathinfo(struct smb2_tree *tree, union smb_setfileinfo *io) 367{ 368 struct composite_context *c = smb2_composite_setpathinfo_send(tree, io); 369 return composite_wait_free(c); 370} 371