LCOV - code coverage report
Current view: top level - source4/libcli/smb_composite - smb2.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 158 177 89.3 %
Date: 2024-06-13 04:01:37 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       65978 : static void continue_close(struct smb2_request *req)
      40             : {
      41       65978 :         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       65978 :         status = smb2_close_recv(req, &close_parm);
      47       65978 :         composite_error(ctx, status);   
      48       65978 : }
      49             : 
      50             : /*
      51             :   continue after the create in a composite unlink
      52             :  */
      53      131972 : static void continue_unlink(struct smb2_request *req)
      54             : {
      55      131972 :         struct composite_context *ctx = talloc_get_type(req->async.private_data, 
      56             :                                                         struct composite_context);
      57      131972 :         struct smb2_tree *tree = req->tree;
      58             :         struct smb2_create create_parm;
      59             :         struct smb2_close close_parm;
      60             :         NTSTATUS status;
      61             : 
      62      131972 :         status = smb2_create_recv(req, ctx, &create_parm);
      63      131972 :         if (!NT_STATUS_IS_OK(status)) {
      64       66161 :                 composite_error(ctx, status);
      65       66161 :                 return;
      66             :         }
      67             : 
      68       65811 :         ZERO_STRUCT(close_parm);
      69       65811 :         close_parm.in.file.handle = create_parm.out.file.handle;
      70             :         
      71       65811 :         req = smb2_close_send(tree, &close_parm);
      72       65811 :         composite_continue_smb2(ctx, req, continue_close, ctx);
      73             : }
      74             : 
      75             : /*
      76             :   composite SMB2 unlink call
      77             : */
      78      131972 : 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      131972 :         ctx = composite_create(tree, tree->session->transport->ev);
      86      131972 :         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      131972 :         if (strpbrk(io->unlink.in.pattern, "*?<>") != NULL) {
      91           0 :                 composite_error(ctx, NT_STATUS_NOT_SUPPORTED);
      92           0 :                 return ctx;
      93             :         }
      94             : 
      95      131972 :         ZERO_STRUCT(create_parm);
      96      131972 :         create_parm.in.desired_access     = SEC_STD_DELETE;
      97      131972 :         create_parm.in.create_disposition = NTCREATEX_DISP_OPEN;
      98      131972 :         create_parm.in.share_access = 
      99             :                 NTCREATEX_SHARE_ACCESS_DELETE|
     100             :                 NTCREATEX_SHARE_ACCESS_READ|
     101             :                 NTCREATEX_SHARE_ACCESS_WRITE;
     102      131972 :         create_parm.in.create_options = 
     103             :                 NTCREATEX_OPTIONS_DELETE_ON_CLOSE |
     104             :                 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
     105      131972 :         create_parm.in.fname = io->unlink.in.pattern;
     106      131972 :         if (create_parm.in.fname[0] == '\\') {
     107           4 :                 create_parm.in.fname++;
     108             :         }
     109             : 
     110      131972 :         req = smb2_create_send(tree, &create_parm);
     111             : 
     112      131972 :         composite_continue_smb2(ctx, req, continue_unlink, ctx);
     113      131972 :         return ctx;
     114             : }
     115             : 
     116             : 
     117             : /*
     118             :   composite unlink call - sync interface
     119             : */
     120      131972 : NTSTATUS smb2_composite_unlink(struct smb2_tree *tree, union smb_unlink *io)
     121             : {
     122      131972 :         struct composite_context *c = smb2_composite_unlink_send(tree, io);
     123      131972 :         return composite_wait_free(c);
     124             : }
     125             : 
     126             : 
     127             : 
     128             : 
     129             : /*
     130             :   continue after the create in a composite mkdir
     131             :  */
     132           6 : static void continue_mkdir(struct smb2_request *req)
     133             : {
     134           6 :         struct composite_context *ctx = talloc_get_type(req->async.private_data, 
     135             :                                                         struct composite_context);
     136           6 :         struct smb2_tree *tree = req->tree;
     137             :         struct smb2_create create_parm;
     138             :         struct smb2_close close_parm;
     139             :         NTSTATUS status;
     140             : 
     141           6 :         status = smb2_create_recv(req, ctx, &create_parm);
     142           6 :         if (!NT_STATUS_IS_OK(status)) {
     143           0 :                 composite_error(ctx, status);
     144           0 :                 return;
     145             :         }
     146             : 
     147           6 :         ZERO_STRUCT(close_parm);
     148           6 :         close_parm.in.file.handle = create_parm.out.file.handle;
     149             :         
     150           6 :         req = smb2_close_send(tree, &close_parm);
     151           6 :         composite_continue_smb2(ctx, req, continue_close, ctx);
     152             : }
     153             : 
     154             : /*
     155             :   composite SMB2 mkdir call
     156             : */
     157           6 : 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           6 :         ctx = composite_create(tree, tree->session->transport->ev);
     165           6 :         if (ctx == NULL) return NULL;
     166             : 
     167           6 :         ZERO_STRUCT(create_parm);
     168             : 
     169           6 :         create_parm.in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED;
     170           6 :         create_parm.in.share_access = 
     171             :                 NTCREATEX_SHARE_ACCESS_READ|
     172             :                 NTCREATEX_SHARE_ACCESS_WRITE;
     173           6 :         create_parm.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
     174           6 :         create_parm.in.file_attributes   = FILE_ATTRIBUTE_DIRECTORY;
     175           6 :         create_parm.in.create_disposition = NTCREATEX_DISP_CREATE;
     176           6 :         create_parm.in.fname = io->mkdir.in.path;
     177           6 :         if (create_parm.in.fname[0] == '\\') {
     178           0 :                 create_parm.in.fname++;
     179             :         }
     180             : 
     181           6 :         req = smb2_create_send(tree, &create_parm);
     182             : 
     183           6 :         composite_continue_smb2(ctx, req, continue_mkdir, ctx);
     184             : 
     185           6 :         return ctx;
     186             : }
     187             : 
     188             : 
     189             : /*
     190             :   composite mkdir call - sync interface
     191             : */
     192           6 : NTSTATUS smb2_composite_mkdir(struct smb2_tree *tree, union smb_mkdir *io)
     193             : {
     194           6 :         struct composite_context *c = smb2_composite_mkdir_send(tree, io);
     195           6 :         return composite_wait_free(c);
     196             : }
     197             : 
     198             : 
     199             : 
     200             : /*
     201             :   continue after the create in a composite rmdir
     202             :  */
     203         172 : static void continue_rmdir(struct smb2_request *req)
     204             : {
     205         172 :         struct composite_context *ctx = talloc_get_type(req->async.private_data, 
     206             :                                                         struct composite_context);
     207         172 :         struct smb2_tree *tree = req->tree;
     208             :         struct smb2_create create_parm;
     209             :         struct smb2_close close_parm;
     210             :         NTSTATUS status;
     211             : 
     212         172 :         status = smb2_create_recv(req, ctx, &create_parm);
     213         172 :         if (!NT_STATUS_IS_OK(status)) {
     214          11 :                 composite_error(ctx, status);
     215          11 :                 return;
     216             :         }
     217             : 
     218         161 :         ZERO_STRUCT(close_parm);
     219         161 :         close_parm.in.file.handle = create_parm.out.file.handle;
     220             :         
     221         161 :         req = smb2_close_send(tree, &close_parm);
     222         161 :         composite_continue_smb2(ctx, req, continue_close, ctx);
     223             : }
     224             : 
     225             : /*
     226             :   composite SMB2 rmdir call
     227             : */
     228         172 : 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         172 :         ctx = composite_create(tree, tree->session->transport->ev);
     236         172 :         if (ctx == NULL) return NULL;
     237             : 
     238         172 :         ZERO_STRUCT(create_parm);
     239         172 :         create_parm.in.desired_access     = SEC_STD_DELETE;
     240         172 :         create_parm.in.create_disposition = NTCREATEX_DISP_OPEN;
     241         172 :         create_parm.in.share_access = 
     242             :                 NTCREATEX_SHARE_ACCESS_DELETE|
     243             :                 NTCREATEX_SHARE_ACCESS_READ|
     244             :                 NTCREATEX_SHARE_ACCESS_WRITE;
     245         172 :         create_parm.in.create_options = 
     246             :                 NTCREATEX_OPTIONS_DIRECTORY |
     247             :                 NTCREATEX_OPTIONS_DELETE_ON_CLOSE;
     248         172 :         create_parm.in.fname = io->in.path;
     249         172 :         if (create_parm.in.fname[0] == '\\') {
     250           0 :                 create_parm.in.fname++;
     251             :         }
     252             : 
     253         172 :         req = smb2_create_send(tree, &create_parm);
     254             : 
     255         172 :         composite_continue_smb2(ctx, req, continue_rmdir, ctx);
     256         172 :         return ctx;
     257             : }
     258             : 
     259             : 
     260             : /*
     261             :   composite rmdir call - sync interface
     262             : */
     263         172 : NTSTATUS smb2_composite_rmdir(struct smb2_tree *tree, struct smb_rmdir *io)
     264             : {
     265         172 :         struct composite_context *c = smb2_composite_rmdir_send(tree, io);
     266         172 :         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           3 : 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           3 :         req = tevent_req_create(mem_ctx, &state,
     292             :                                 struct smb2_composite_setpathinfo_state);
     293           3 :         if (req == NULL) {
     294           0 :                 return NULL;
     295             :         }
     296             : 
     297           3 :         state->tree = tree;
     298           3 :         state->io = *io;
     299             : 
     300           3 :         state->cr.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED;
     301           3 :         state->cr.in.create_disposition = NTCREATEX_DISP_OPEN;
     302           3 :         state->cr.in.share_access =
     303             :                 NTCREATEX_SHARE_ACCESS_DELETE|
     304             :                 NTCREATEX_SHARE_ACCESS_READ|
     305             :                 NTCREATEX_SHARE_ACCESS_WRITE;
     306           3 :         state->cr.in.create_options = 0;
     307           3 :         state->cr.in.fname = state->io.generic.in.file.path;
     308           3 :         if (state->cr.in.fname[0] == '\\') {
     309           0 :                 state->cr.in.fname++;
     310             :         }
     311             : 
     312           3 :         smb2req = smb2_create_send(tree, &state->cr);
     313           3 :         if (tevent_req_nomem(smb2req, req)) {
     314           0 :                 return tevent_req_post(req, ev);
     315             :         }
     316           3 :         smb2req->async.fn = smb2_composite_setpathinfo_create_done;
     317           3 :         smb2req->async.private_data = req;
     318             : 
     319           3 :         return req;
     320             : }
     321             : 
     322             : static void smb2_composite_setpathinfo_setinfo_done(struct smb2_request *smb2req);
     323             : 
     324           3 : static void smb2_composite_setpathinfo_create_done(struct smb2_request *smb2req)
     325             : {
     326           3 :         struct tevent_req *req =
     327           3 :                 talloc_get_type_abort(smb2req->async.private_data,
     328             :                 struct tevent_req);
     329           3 :         struct smb2_composite_setpathinfo_state *state =
     330           3 :                 tevent_req_data(req,
     331             :                 struct smb2_composite_setpathinfo_state);
     332             :         NTSTATUS status;
     333             : 
     334           3 :         status = smb2_create_recv(smb2req, state, &state->cr);
     335           3 :         if (tevent_req_nterror(req, status)) {
     336           2 :                 return;
     337             :         }
     338             : 
     339           2 :         state->io.generic.in.file.handle = state->cr.out.file.handle;
     340             : 
     341           2 :         smb2req = smb2_setinfo_file_send(state->tree, &state->io);
     342           2 :         if (tevent_req_nomem(smb2req, req)) {
     343           0 :                 return;
     344             :         }
     345           2 :         smb2req->async.fn = smb2_composite_setpathinfo_setinfo_done;
     346           2 :         smb2req->async.private_data = req;
     347             : }
     348             : 
     349             : static void smb2_composite_setpathinfo_close_done(struct smb2_request *smb2req);
     350             : 
     351           2 : static void smb2_composite_setpathinfo_setinfo_done(struct smb2_request *smb2req)
     352             : {
     353           2 :         struct tevent_req *req =
     354           2 :                 talloc_get_type_abort(smb2req->async.private_data,
     355             :                 struct tevent_req);
     356           2 :         struct smb2_composite_setpathinfo_state *state =
     357           2 :                 tevent_req_data(req,
     358             :                 struct smb2_composite_setpathinfo_state);
     359             :         NTSTATUS status;
     360             : 
     361           2 :         status = smb2_setinfo_recv(smb2req);
     362           2 :         state->set_status = status;
     363             : 
     364           2 :         state->cl.in.file.handle = state->io.generic.in.file.handle;
     365             : 
     366           2 :         smb2req = smb2_close_send(state->tree, &state->cl);
     367           2 :         if (tevent_req_nomem(smb2req, req)) {
     368           0 :                 return;
     369             :         }
     370           2 :         smb2req->async.fn = smb2_composite_setpathinfo_close_done;
     371           2 :         smb2req->async.private_data = req;
     372             : }
     373             : 
     374           2 : static void smb2_composite_setpathinfo_close_done(struct smb2_request *smb2req)
     375             : {
     376           2 :         struct tevent_req *req =
     377           2 :                 talloc_get_type_abort(smb2req->async.private_data,
     378             :                 struct tevent_req);
     379           2 :         struct smb2_composite_setpathinfo_state *state =
     380           2 :                 tevent_req_data(req,
     381             :                 struct smb2_composite_setpathinfo_state);
     382             :         NTSTATUS status;
     383             : 
     384           2 :         status = smb2_close_recv(smb2req, &state->cl);
     385             : 
     386           2 :         if (tevent_req_nterror(req, state->set_status)) {
     387           0 :                 return;
     388             :         }
     389             : 
     390           2 :         if (tevent_req_nterror(req, status)) {
     391           0 :                 return;
     392             :         }
     393             : 
     394           2 :         tevent_req_done(req);
     395             : }
     396             : 
     397           3 : NTSTATUS smb2_composite_setpathinfo_recv(struct tevent_req *req)
     398             : {
     399             :         NTSTATUS status;
     400             : 
     401           3 :         if (tevent_req_is_nterror(req, &status)) {
     402           1 :                 tevent_req_received(req);
     403           1 :                 return status;
     404             :         }
     405             : 
     406           2 :         tevent_req_received(req);
     407           2 :         return NT_STATUS_OK;
     408             : }
     409             : 
     410             : /*
     411             :   composite setpathinfo call
     412             :  */
     413           3 : 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           3 :         TALLOC_CTX *frame = talloc_stackframe();
     419           3 :         struct tevent_context *ev = tree->session->transport->ev;
     420             : 
     421           3 :         if (frame == NULL) {
     422           0 :                 return NT_STATUS_NO_MEMORY;
     423             :         }
     424             : 
     425           3 :         subreq = smb2_composite_setpathinfo_send(frame, ev, tree, io);
     426           3 :         if (subreq == NULL) {
     427           0 :                 TALLOC_FREE(frame);
     428           0 :                 return NT_STATUS_NO_MEMORY;
     429             :         }
     430             : 
     431           3 :         ok = tevent_req_poll(subreq, ev);
     432           3 :         if (!ok) {
     433           0 :                 status = map_nt_error_from_unix_common(errno);
     434           0 :                 TALLOC_FREE(frame);
     435           0 :                 return status;
     436             :         }
     437             : 
     438           3 :         status = smb2_composite_setpathinfo_recv(subreq);
     439           3 :         TALLOC_FREE(subreq);
     440           3 :         if (!NT_STATUS_IS_OK(status)) {
     441           1 :                 TALLOC_FREE(frame);
     442           1 :                 return status;
     443             :         }
     444             : 
     445           2 :         TALLOC_FREE(frame);
     446           2 :         return NT_STATUS_OK;
     447             : }

Generated by: LCOV version 1.13