LCOV - code coverage report
Current view: top level - source4/libcli/smb_composite - smb2.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 162 177 91.5 %
Date: 2021-09-23 10:06:22 Functions: 16 16 100.0 %

          Line data    Source code
       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 <tevent.h>
      29             : #include "lib/util/tevent_ntstatus.h"
      30             : #include "libcli/raw/libcliraw.h"
      31             : #include "libcli/raw/raw_proto.h"
      32             : #include "libcli/composite/composite.h"
      33             : #include "libcli/smb_composite/smb_composite.h"
      34             : #include "libcli/smb2/smb2_calls.h"
      35             : 
      36             : /*
      37             :   continue after a SMB2 close
      38             :  */
      39      215678 : static void continue_close(struct smb2_request *req)
      40             : {
      41      215678 :         struct composite_context *ctx = talloc_get_type(req->async.private_data, 
      42             :                                                         struct composite_context);
      43             :         NTSTATUS status;
      44             :         struct smb2_close close_parm;
      45             : 
      46      215678 :         status = smb2_close_recv(req, &close_parm);
      47      215678 :         composite_error(ctx, status);   
      48      215678 : }
      49             : 
      50             : /*
      51             :   continue after the create in a composite unlink
      52             :  */
      53      372215 : static void continue_unlink(struct smb2_request *req)
      54             : {
      55      372215 :         struct composite_context *ctx = talloc_get_type(req->async.private_data, 
      56             :                                                         struct composite_context);
      57      372215 :         struct smb2_tree *tree = req->tree;
      58             :         struct smb2_create create_parm;
      59             :         struct smb2_close close_parm;
      60             :         NTSTATUS status;
      61             : 
      62      372215 :         status = smb2_create_recv(req, ctx, &create_parm);
      63      372215 :         if (!NT_STATUS_IS_OK(status)) {
      64      158832 :                 composite_error(ctx, status);
      65      158832 :                 return;
      66             :         }
      67             : 
      68      213383 :         ZERO_STRUCT(close_parm);
      69      213383 :         close_parm.in.file.handle = create_parm.out.file.handle;
      70             :         
      71      213383 :         req = smb2_close_send(tree, &close_parm);
      72      213383 :         composite_continue_smb2(ctx, req, continue_close, ctx);
      73             : }
      74             : 
      75             : /*
      76             :   composite SMB2 unlink call
      77             : */
      78      372229 : struct composite_context *smb2_composite_unlink_send(struct smb2_tree *tree, 
      79             :                                                      union smb_unlink *io)
      80             : {
      81             :         struct composite_context *ctx;
      82             :         struct smb2_create create_parm;
      83             :         struct smb2_request *req;
      84             : 
      85      372229 :         ctx = composite_create(tree, tree->session->transport->ev);
      86      372229 :         if (ctx == NULL) return NULL;
      87             : 
      88             :         /* check for wildcards - we could support these with a
      89             :            search, but for now they aren't necessary */
      90      372229 :         if (strpbrk(io->unlink.in.pattern, "*?<>") != NULL) {
      91           4 :                 composite_error(ctx, NT_STATUS_NOT_SUPPORTED);
      92           4 :                 return ctx;
      93             :         }
      94             : 
      95      372225 :         ZERO_STRUCT(create_parm);
      96      372225 :         create_parm.in.desired_access     = SEC_STD_DELETE;
      97      372225 :         create_parm.in.create_disposition = NTCREATEX_DISP_OPEN;
      98      372225 :         create_parm.in.share_access = 
      99             :                 NTCREATEX_SHARE_ACCESS_DELETE|
     100             :                 NTCREATEX_SHARE_ACCESS_READ|
     101             :                 NTCREATEX_SHARE_ACCESS_WRITE;
     102      372225 :         create_parm.in.create_options = 
     103             :                 NTCREATEX_OPTIONS_DELETE_ON_CLOSE |
     104             :                 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
     105      372225 :         create_parm.in.fname = io->unlink.in.pattern;
     106      372225 :         if (create_parm.in.fname[0] == '\\') {
     107          12 :                 create_parm.in.fname++;
     108             :         }
     109             : 
     110      372225 :         req = smb2_create_send(tree, &create_parm);
     111             : 
     112      372225 :         composite_continue_smb2(ctx, req, continue_unlink, ctx);
     113      372225 :         return ctx;
     114             : }
     115             : 
     116             : 
     117             : /*
     118             :   composite unlink call - sync interface
     119             : */
     120      372229 : NTSTATUS smb2_composite_unlink(struct smb2_tree *tree, union smb_unlink *io)
     121             : {
     122      372229 :         struct composite_context *c = smb2_composite_unlink_send(tree, io);
     123      372229 :         return composite_wait_free(c);
     124             : }
     125             : 
     126             : 
     127             : 
     128             : 
     129             : /*
     130             :   continue after the create in a composite mkdir
     131             :  */
     132         398 : static void continue_mkdir(struct smb2_request *req)
     133             : {
     134         398 :         struct composite_context *ctx = talloc_get_type(req->async.private_data, 
     135             :                                                         struct composite_context);
     136         398 :         struct smb2_tree *tree = req->tree;
     137             :         struct smb2_create create_parm;
     138             :         struct smb2_close close_parm;
     139             :         NTSTATUS status;
     140             : 
     141         398 :         status = smb2_create_recv(req, ctx, &create_parm);
     142         398 :         if (!NT_STATUS_IS_OK(status)) {
     143          80 :                 composite_error(ctx, status);
     144          80 :                 return;
     145             :         }
     146             : 
     147         318 :         ZERO_STRUCT(close_parm);
     148         318 :         close_parm.in.file.handle = create_parm.out.file.handle;
     149             :         
     150         318 :         req = smb2_close_send(tree, &close_parm);
     151         318 :         composite_continue_smb2(ctx, req, continue_close, ctx);
     152             : }
     153             : 
     154             : /*
     155             :   composite SMB2 mkdir call
     156             : */
     157         398 : struct composite_context *smb2_composite_mkdir_send(struct smb2_tree *tree, 
     158             :                                                      union smb_mkdir *io)
     159             : {
     160             :         struct composite_context *ctx;
     161             :         struct smb2_create create_parm;
     162             :         struct smb2_request *req;
     163             : 
     164         398 :         ctx = composite_create(tree, tree->session->transport->ev);
     165         398 :         if (ctx == NULL) return NULL;
     166             : 
     167         398 :         ZERO_STRUCT(create_parm);
     168             : 
     169         398 :         create_parm.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
     170         398 :         create_parm.in.share_access = 
     171             :                 NTCREATEX_SHARE_ACCESS_READ|
     172             :                 NTCREATEX_SHARE_ACCESS_WRITE;
     173         398 :         create_parm.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
     174         398 :         create_parm.in.file_attributes   = FILE_ATTRIBUTE_DIRECTORY;
     175         398 :         create_parm.in.create_disposition = NTCREATEX_DISP_CREATE;
     176         398 :         create_parm.in.fname = io->mkdir.in.path;
     177         398 :         if (create_parm.in.fname[0] == '\\') {
     178           0 :                 create_parm.in.fname++;
     179             :         }
     180             : 
     181         398 :         req = smb2_create_send(tree, &create_parm);
     182             : 
     183         398 :         composite_continue_smb2(ctx, req, continue_mkdir, ctx);
     184             : 
     185         398 :         return ctx;
     186             : }
     187             : 
     188             : 
     189             : /*
     190             :   composite mkdir call - sync interface
     191             : */
     192         398 : NTSTATUS smb2_composite_mkdir(struct smb2_tree *tree, union smb_mkdir *io)
     193             : {
     194         398 :         struct composite_context *c = smb2_composite_mkdir_send(tree, io);
     195         398 :         return composite_wait_free(c);
     196             : }
     197             : 
     198             : 
     199             : 
     200             : /*
     201             :   continue after the create in a composite rmdir
     202             :  */
     203        2266 : static void continue_rmdir(struct smb2_request *req)
     204             : {
     205        2266 :         struct composite_context *ctx = talloc_get_type(req->async.private_data, 
     206             :                                                         struct composite_context);
     207        2266 :         struct smb2_tree *tree = req->tree;
     208             :         struct smb2_create create_parm;
     209             :         struct smb2_close close_parm;
     210             :         NTSTATUS status;
     211             : 
     212        2266 :         status = smb2_create_recv(req, ctx, &create_parm);
     213        2266 :         if (!NT_STATUS_IS_OK(status)) {
     214         289 :                 composite_error(ctx, status);
     215         289 :                 return;
     216             :         }
     217             : 
     218        1977 :         ZERO_STRUCT(close_parm);
     219        1977 :         close_parm.in.file.handle = create_parm.out.file.handle;
     220             :         
     221        1977 :         req = smb2_close_send(tree, &close_parm);
     222        1977 :         composite_continue_smb2(ctx, req, continue_close, ctx);
     223             : }
     224             : 
     225             : /*
     226             :   composite SMB2 rmdir call
     227             : */
     228        2266 : struct composite_context *smb2_composite_rmdir_send(struct smb2_tree *tree, 
     229             :                                                     struct smb_rmdir *io)
     230             : {
     231             :         struct composite_context *ctx;
     232             :         struct smb2_create create_parm;
     233             :         struct smb2_request *req;
     234             : 
     235        2266 :         ctx = composite_create(tree, tree->session->transport->ev);
     236        2266 :         if (ctx == NULL) return NULL;
     237             : 
     238        2266 :         ZERO_STRUCT(create_parm);
     239        2266 :         create_parm.in.desired_access     = SEC_STD_DELETE;
     240        2266 :         create_parm.in.create_disposition = NTCREATEX_DISP_OPEN;
     241        2266 :         create_parm.in.share_access = 
     242             :                 NTCREATEX_SHARE_ACCESS_DELETE|
     243             :                 NTCREATEX_SHARE_ACCESS_READ|
     244             :                 NTCREATEX_SHARE_ACCESS_WRITE;
     245        2266 :         create_parm.in.create_options = 
     246             :                 NTCREATEX_OPTIONS_DIRECTORY |
     247             :                 NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
     248        2266 :         create_parm.in.fname = io->in.path;
     249        2266 :         if (create_parm.in.fname[0] == '\\') {
     250           0 :                 create_parm.in.fname++;
     251             :         }
     252             : 
     253        2266 :         req = smb2_create_send(tree, &create_parm);
     254             : 
     255        2266 :         composite_continue_smb2(ctx, req, continue_rmdir, ctx);
     256        2266 :         return ctx;
     257             : }
     258             : 
     259             : 
     260             : /*
     261             :   composite rmdir call - sync interface
     262             : */
     263        2266 : NTSTATUS smb2_composite_rmdir(struct smb2_tree *tree, struct smb_rmdir *io)
     264             : {
     265        2266 :         struct composite_context *c = smb2_composite_rmdir_send(tree, io);
     266        2266 :         return composite_wait_free(c);
     267             : }
     268             : 
     269             : struct smb2_composite_setpathinfo_state {
     270             :         struct smb2_tree *tree;
     271             :         union smb_setfileinfo io;
     272             :         NTSTATUS set_status;
     273             :         struct smb2_create cr;
     274             :         struct smb2_close cl;
     275             : };
     276             : 
     277             : static void smb2_composite_setpathinfo_create_done(struct smb2_request *smb2req);
     278             : 
     279             : /*
     280             :   composite SMB2 setpathinfo call
     281             : */
     282         144 : struct tevent_req *smb2_composite_setpathinfo_send(TALLOC_CTX *mem_ctx,
     283             :                                                    struct tevent_context *ev,
     284             :                                                    struct smb2_tree *tree,
     285             :                                                    const union smb_setfileinfo *io)
     286             : {
     287             :         struct tevent_req *req;
     288             :         struct smb2_composite_setpathinfo_state *state;
     289             :         struct smb2_request *smb2req;
     290             : 
     291         144 :         req = tevent_req_create(mem_ctx, &state,
     292             :                                 struct smb2_composite_setpathinfo_state);
     293         144 :         if (req == NULL) {
     294           0 :                 return NULL;
     295             :         }
     296             : 
     297         144 :         state->tree = tree;
     298         144 :         state->io = *io;
     299             : 
     300         144 :         state->cr.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
     301         144 :         state->cr.in.create_disposition = NTCREATEX_DISP_OPEN;
     302         144 :         state->cr.in.share_access =
     303             :                 NTCREATEX_SHARE_ACCESS_DELETE|
     304             :                 NTCREATEX_SHARE_ACCESS_READ|
     305             :                 NTCREATEX_SHARE_ACCESS_WRITE;
     306         144 :         state->cr.in.create_options = 0;
     307         144 :         state->cr.in.fname = state->io.generic.in.file.path;
     308         144 :         if (state->cr.in.fname[0] == '\\') {
     309           0 :                 state->cr.in.fname++;
     310             :         }
     311             : 
     312         144 :         smb2req = smb2_create_send(tree, &state->cr);
     313         144 :         if (tevent_req_nomem(smb2req, req)) {
     314           0 :                 return tevent_req_post(req, ev);
     315             :         }
     316         144 :         smb2req->async.fn = smb2_composite_setpathinfo_create_done;
     317         144 :         smb2req->async.private_data = req;
     318             : 
     319         144 :         return req;
     320             : }
     321             : 
     322             : static void smb2_composite_setpathinfo_setinfo_done(struct smb2_request *smb2req);
     323             : 
     324         144 : static void smb2_composite_setpathinfo_create_done(struct smb2_request *smb2req)
     325             : {
     326         140 :         struct tevent_req *req =
     327         144 :                 talloc_get_type_abort(smb2req->async.private_data,
     328             :                 struct tevent_req);
     329         140 :         struct smb2_composite_setpathinfo_state *state =
     330         144 :                 tevent_req_data(req,
     331             :                 struct smb2_composite_setpathinfo_state);
     332             :         NTSTATUS status;
     333             : 
     334         144 :         status = smb2_create_recv(smb2req, state, &state->cr);
     335         144 :         if (tevent_req_nterror(req, status)) {
     336         260 :                 return;
     337             :         }
     338             : 
     339          12 :         state->io.generic.in.file.handle = state->cr.out.file.handle;
     340             : 
     341          12 :         smb2req = smb2_setinfo_file_send(state->tree, &state->io);
     342          12 :         if (tevent_req_nomem(smb2req, req)) {
     343           0 :                 return;
     344             :         }
     345          12 :         smb2req->async.fn = smb2_composite_setpathinfo_setinfo_done;
     346          12 :         smb2req->async.private_data = req;
     347             : }
     348             : 
     349             : static void smb2_composite_setpathinfo_close_done(struct smb2_request *smb2req);
     350             : 
     351          12 : static void smb2_composite_setpathinfo_setinfo_done(struct smb2_request *smb2req)
     352             : {
     353          12 :         struct tevent_req *req =
     354          12 :                 talloc_get_type_abort(smb2req->async.private_data,
     355             :                 struct tevent_req);
     356          12 :         struct smb2_composite_setpathinfo_state *state =
     357          12 :                 tevent_req_data(req,
     358             :                 struct smb2_composite_setpathinfo_state);
     359             :         NTSTATUS status;
     360             : 
     361          12 :         status = smb2_setinfo_recv(smb2req);
     362          12 :         state->set_status = status;
     363             : 
     364          12 :         state->cl.in.file.handle = state->io.generic.in.file.handle;
     365             : 
     366          12 :         smb2req = smb2_close_send(state->tree, &state->cl);
     367          12 :         if (tevent_req_nomem(smb2req, req)) {
     368           0 :                 return;
     369             :         }
     370          12 :         smb2req->async.fn = smb2_composite_setpathinfo_close_done;
     371          12 :         smb2req->async.private_data = req;
     372             : }
     373             : 
     374          12 : static void smb2_composite_setpathinfo_close_done(struct smb2_request *smb2req)
     375             : {
     376          12 :         struct tevent_req *req =
     377          12 :                 talloc_get_type_abort(smb2req->async.private_data,
     378             :                 struct tevent_req);
     379          12 :         struct smb2_composite_setpathinfo_state *state =
     380          12 :                 tevent_req_data(req,
     381             :                 struct smb2_composite_setpathinfo_state);
     382             :         NTSTATUS status;
     383             : 
     384          12 :         status = smb2_close_recv(smb2req, &state->cl);
     385             : 
     386          12 :         if (tevent_req_nterror(req, state->set_status)) {
     387           0 :                 return;
     388             :         }
     389             : 
     390          12 :         if (tevent_req_nterror(req, status)) {
     391           0 :                 return;
     392             :         }
     393             : 
     394          12 :         tevent_req_done(req);
     395             : }
     396             : 
     397         144 : NTSTATUS smb2_composite_setpathinfo_recv(struct tevent_req *req)
     398             : {
     399             :         NTSTATUS status;
     400             : 
     401         144 :         if (tevent_req_is_nterror(req, &status)) {
     402         132 :                 tevent_req_received(req);
     403         132 :                 return status;
     404             :         }
     405             : 
     406          12 :         tevent_req_received(req);
     407          12 :         return NT_STATUS_OK;
     408             : }
     409             : 
     410             : /*
     411             :   composite setpathinfo call
     412             :  */
     413         144 : NTSTATUS smb2_composite_setpathinfo(struct smb2_tree *tree, union smb_setfileinfo *io)
     414             : {
     415             :         struct tevent_req *subreq;
     416             :         NTSTATUS status;
     417             :         bool ok;
     418         144 :         TALLOC_CTX *frame = talloc_stackframe();
     419         144 :         struct tevent_context *ev = tree->session->transport->ev;
     420             : 
     421         144 :         if (frame == NULL) {
     422           0 :                 return NT_STATUS_NO_MEMORY;
     423             :         }
     424             : 
     425         144 :         subreq = smb2_composite_setpathinfo_send(frame, ev, tree, io);
     426         144 :         if (subreq == NULL) {
     427           0 :                 TALLOC_FREE(frame);
     428           0 :                 return NT_STATUS_NO_MEMORY;
     429             :         }
     430             : 
     431         144 :         ok = tevent_req_poll(subreq, ev);
     432         144 :         if (!ok) {
     433           0 :                 status = map_nt_error_from_unix_common(errno);
     434           0 :                 TALLOC_FREE(frame);
     435           0 :                 return status;
     436             :         }
     437             : 
     438         144 :         status = smb2_composite_setpathinfo_recv(subreq);
     439         144 :         TALLOC_FREE(subreq);
     440         144 :         if (!NT_STATUS_IS_OK(status)) {
     441         132 :                 TALLOC_FREE(frame);
     442         132 :                 return status;
     443             :         }
     444             : 
     445          12 :         TALLOC_FREE(frame);
     446          12 :         return NT_STATUS_OK;
     447             : }

Generated by: LCOV version 1.13