root/source4/smb_server/smb/trans2.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. trans2_setup_reply
  2. trans2_push_fsinfo
  3. trans2_qfsinfo_send
  4. trans2_qfsinfo
  5. trans2_open_send
  6. trans2_open
  7. trans2_simple_send
  8. trans2_mkdir
  9. trans2_push_fileinfo
  10. trans2_fileinfo_send
  11. trans2_qpathinfo
  12. trans2_qfileinfo
  13. trans2_parse_sfileinfo
  14. trans2_setfileinfo
  15. trans2_setpathinfo
  16. find_fill_info
  17. find_callback
  18. trans2_findfirst_send
  19. trans2_findfirst
  20. trans2_findnext_send
  21. trans2_findnext
  22. trans2_backend
  23. smbsrv_trans_partial_destructor
  24. reply_trans_continue
  25. reply_trans_send
  26. reply_trans_complete
  27. reply_trans_generic
  28. reply_transs_generic
  29. smbsrv_reply_trans2
  30. smbsrv_reply_trans
  31. smbsrv_reply_transs
  32. smbsrv_reply_transs2

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    transaction2 handling
   4    Copyright (C) Andrew Tridgell 2003
   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    This file handles the parsing of transact2 requests
  21 */
  22 
  23 #include "includes.h"
  24 #include "../lib/util/dlinklist.h"
  25 #include "smb_server/smb_server.h"
  26 #include "librpc/gen_ndr/ndr_misc.h"
  27 #include "ntvfs/ntvfs.h"
  28 #include "libcli/raw/libcliraw.h"
  29 #include "libcli/raw/raw_proto.h"
  30 
  31 #define TRANS2_CHECK_ASYNC_STATUS_SIMPLE do { \
  32         if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) { \
  33                 trans2_setup_reply(trans, 0, 0, 0);\
  34                 return req->ntvfs->async_states->status; \
  35         } \
  36 } while (0)
  37 #define TRANS2_CHECK_ASYNC_STATUS(ptr, type) do { \
  38         TRANS2_CHECK_ASYNC_STATUS_SIMPLE; \
  39         ptr = talloc_get_type(op->op_info, type); \
  40 } while (0)
  41 #define TRANS2_CHECK(cmd) do { \
  42         NTSTATUS _status; \
  43         _status = cmd; \
  44         NT_STATUS_NOT_OK_RETURN(_status); \
  45 } while (0)
  46 
  47 /*
  48   hold the state of a nttrans op while in progress. Needed to allow for async backend
  49   functions.
  50 */
  51 struct trans_op {
  52         struct smbsrv_request *req;
  53         struct smb_trans2 *trans;
  54         uint8_t command;
  55         NTSTATUS (*send_fn)(struct trans_op *);
  56         void *op_info;
  57 };
  58 
  59 #define CHECK_MIN_BLOB_SIZE(blob, size) do { \
  60         if ((blob)->length < (size)) { \
  61                 return NT_STATUS_INFO_LENGTH_MISMATCH; \
  62         }} while (0)
  63 
  64 /* setup a trans2 reply, given the data and params sizes */
  65 static NTSTATUS trans2_setup_reply(struct smb_trans2 *trans,
     /* [<][>][^][v][top][bottom][index][help] */
  66                                    uint16_t param_size, uint16_t data_size,
  67                                    uint8_t setup_count)
  68 {
  69         trans->out.setup_count = setup_count;
  70         if (setup_count > 0) {
  71                 trans->out.setup = talloc_zero_array(trans, uint16_t, setup_count);
  72                 NT_STATUS_HAVE_NO_MEMORY(trans->out.setup);
  73         }
  74         trans->out.params = data_blob_talloc(trans, NULL, param_size);
  75         if (param_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.params.data);
  76 
  77         trans->out.data = data_blob_talloc(trans, NULL, data_size);
  78         if (data_size > 0) NT_STATUS_HAVE_NO_MEMORY(trans->out.data.data);
  79 
  80         return NT_STATUS_OK;
  81 }
  82 
  83 static NTSTATUS trans2_push_fsinfo(struct smbsrv_connection *smb_conn,
     /* [<][>][^][v][top][bottom][index][help] */
  84                                    TALLOC_CTX *mem_ctx,
  85                                    DATA_BLOB *blob,
  86                                    union smb_fsinfo *fsinfo,
  87                                    int default_str_flags)
  88 {
  89         enum smb_fsinfo_level passthru_level;
  90 
  91         switch (fsinfo->generic.level) {
  92         case RAW_QFS_ALLOCATION:
  93                 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 18));
  94 
  95                 SIVAL(blob->data,  0, fsinfo->allocation.out.fs_id);
  96                 SIVAL(blob->data,  4, fsinfo->allocation.out.sectors_per_unit);
  97                 SIVAL(blob->data,  8, fsinfo->allocation.out.total_alloc_units);
  98                 SIVAL(blob->data, 12, fsinfo->allocation.out.avail_alloc_units);
  99                 SSVAL(blob->data, 16, fsinfo->allocation.out.bytes_per_sector);
 100 
 101                 return NT_STATUS_OK;
 102 
 103         case RAW_QFS_VOLUME:
 104                 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 5));
 105 
 106                 SIVAL(blob->data,       0, fsinfo->volume.out.serial_number);
 107                 /* w2k3 implements this incorrectly for unicode - it
 108                  * leaves the last byte off the string */
 109                 TRANS2_CHECK(smbsrv_blob_append_string(mem_ctx, blob,
 110                                                        fsinfo->volume.out.volume_name.s,
 111                                                        4, default_str_flags,
 112                                                        STR_LEN8BIT|STR_NOALIGN));
 113 
 114                 return NT_STATUS_OK;
 115 
 116         case RAW_QFS_VOLUME_INFO:
 117                 passthru_level = RAW_QFS_VOLUME_INFORMATION;
 118                 break;
 119 
 120         case RAW_QFS_SIZE_INFO:
 121                 passthru_level = RAW_QFS_SIZE_INFORMATION;
 122                 break;
 123 
 124         case RAW_QFS_DEVICE_INFO:
 125                 passthru_level = RAW_QFS_DEVICE_INFORMATION;
 126                 break;
 127 
 128         case RAW_QFS_ATTRIBUTE_INFO:
 129                 passthru_level = RAW_QFS_ATTRIBUTE_INFORMATION;
 130                 break;
 131 
 132         default:
 133                 passthru_level = fsinfo->generic.level;
 134                 break;
 135         }
 136 
 137         return smbsrv_push_passthru_fsinfo(mem_ctx, blob,
 138                                            passthru_level, fsinfo,
 139                                            default_str_flags);
 140 }
 141 
 142 /*
 143   trans2 qfsinfo implementation send
 144 */
 145 static NTSTATUS trans2_qfsinfo_send(struct trans_op *op)
     /* [<][>][^][v][top][bottom][index][help] */
 146 {
 147         struct smbsrv_request *req = op->req;
 148         struct smb_trans2 *trans = op->trans;
 149         union smb_fsinfo *fsinfo;
 150 
 151         TRANS2_CHECK_ASYNC_STATUS(fsinfo, union smb_fsinfo);
 152 
 153         TRANS2_CHECK(trans2_setup_reply(trans, 0, 0, 0));
 154 
 155         TRANS2_CHECK(trans2_push_fsinfo(req->smb_conn, trans,
 156                                         &trans->out.data, fsinfo,
 157                                         SMBSRV_REQ_DEFAULT_STR_FLAGS(req)));
 158 
 159         return NT_STATUS_OK;
 160 }
 161 
 162 /*
 163   trans2 qfsinfo implementation
 164 */
 165 static NTSTATUS trans2_qfsinfo(struct smbsrv_request *req, struct trans_op *op)
     /* [<][>][^][v][top][bottom][index][help] */
 166 {
 167         struct smb_trans2 *trans = op->trans;
 168         union smb_fsinfo *fsinfo;
 169         uint16_t level;
 170 
 171         /* make sure we got enough parameters */
 172         if (trans->in.params.length != 2) {
 173                 return NT_STATUS_FOOBAR;
 174         }
 175 
 176         fsinfo = talloc(op, union smb_fsinfo);
 177         NT_STATUS_HAVE_NO_MEMORY(fsinfo);
 178 
 179         level = SVAL(trans->in.params.data, 0);
 180 
 181         /* work out the backend level - we make it 1-1 in the header */
 182         fsinfo->generic.level = (enum smb_fsinfo_level)level;
 183         if (fsinfo->generic.level >= RAW_QFS_GENERIC) {
 184                 return NT_STATUS_INVALID_LEVEL;
 185         }
 186 
 187         op->op_info = fsinfo;
 188         op->send_fn = trans2_qfsinfo_send;
 189 
 190         return ntvfs_fsinfo(req->ntvfs, fsinfo);
 191 }
 192 
 193 
 194 /*
 195   trans2 open implementation send
 196 */
 197 static NTSTATUS trans2_open_send(struct trans_op *op)
     /* [<][>][^][v][top][bottom][index][help] */
 198 {
 199         struct smbsrv_request *req = op->req;
 200         struct smb_trans2 *trans = op->trans;
 201         union smb_open *io;
 202 
 203         TRANS2_CHECK_ASYNC_STATUS(io, union smb_open);
 204 
 205         TRANS2_CHECK(trans2_setup_reply(trans, 30, 0, 0));
 206 
 207         smbsrv_push_fnum(trans->out.params.data, VWV(0), io->t2open.out.file.ntvfs);
 208         SSVAL(trans->out.params.data, VWV(1), io->t2open.out.attrib);
 209         srv_push_dos_date3(req->smb_conn, trans->out.params.data, 
 210                            VWV(2), io->t2open.out.write_time);
 211         SIVAL(trans->out.params.data, VWV(4), io->t2open.out.size);
 212         SSVAL(trans->out.params.data, VWV(6), io->t2open.out.access);
 213         SSVAL(trans->out.params.data, VWV(7), io->t2open.out.ftype);
 214         SSVAL(trans->out.params.data, VWV(8), io->t2open.out.devstate);
 215         SSVAL(trans->out.params.data, VWV(9), io->t2open.out.action);
 216         SIVAL(trans->out.params.data, VWV(10), 0); /* reserved */
 217         SSVAL(trans->out.params.data, VWV(12), 0); /* EaErrorOffset */
 218         SIVAL(trans->out.params.data, VWV(13), 0); /* EaLength */
 219 
 220         return NT_STATUS_OK;
 221 }
 222 
 223 /*
 224   trans2 open implementation
 225 */
 226 static NTSTATUS trans2_open(struct smbsrv_request *req, struct trans_op *op)
     /* [<][>][^][v][top][bottom][index][help] */
 227 {
 228         struct smb_trans2 *trans = op->trans;
 229         union smb_open *io;
 230 
 231         /* make sure we got enough parameters */
 232         if (trans->in.params.length < 29) {
 233                 return NT_STATUS_FOOBAR;
 234         }
 235 
 236         io = talloc(op, union smb_open);
 237         NT_STATUS_HAVE_NO_MEMORY(io);
 238 
 239         io->t2open.level           = RAW_OPEN_T2OPEN;
 240         io->t2open.in.flags        = SVAL(trans->in.params.data, VWV(0));
 241         io->t2open.in.open_mode    = SVAL(trans->in.params.data, VWV(1));
 242         io->t2open.in.search_attrs = SVAL(trans->in.params.data, VWV(2));
 243         io->t2open.in.file_attrs   = SVAL(trans->in.params.data, VWV(3));
 244         io->t2open.in.write_time   = srv_pull_dos_date(req->smb_conn, 
 245                                                     trans->in.params.data + VWV(4));
 246         io->t2open.in.open_func    = SVAL(trans->in.params.data, VWV(6));
 247         io->t2open.in.size         = IVAL(trans->in.params.data, VWV(7));
 248         io->t2open.in.timeout      = IVAL(trans->in.params.data, VWV(9));
 249         io->t2open.in.num_eas      = 0;
 250         io->t2open.in.eas          = NULL;
 251 
 252         smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 28, &io->t2open.in.fname, 0);
 253         if (io->t2open.in.fname == NULL) {
 254                 return NT_STATUS_FOOBAR;
 255         }
 256 
 257         TRANS2_CHECK(ea_pull_list(&trans->in.data, io, &io->t2open.in.num_eas, &io->t2open.in.eas));
 258 
 259         op->op_info = io;
 260         op->send_fn = trans2_open_send;
 261 
 262         return ntvfs_open(req->ntvfs, io);
 263 }
 264 
 265 
 266 /*
 267   trans2 simple send
 268 */
 269 static NTSTATUS trans2_simple_send(struct trans_op *op)
     /* [<][>][^][v][top][bottom][index][help] */
 270 {
 271         struct smbsrv_request *req = op->req;
 272         struct smb_trans2 *trans = op->trans;
 273 
 274         TRANS2_CHECK_ASYNC_STATUS_SIMPLE;
 275 
 276         TRANS2_CHECK(trans2_setup_reply(trans, 2, 0, 0));
 277 
 278         SSVAL(trans->out.params.data, VWV(0), 0);
 279 
 280         return NT_STATUS_OK;
 281 }
 282 
 283 /*
 284   trans2 mkdir implementation
 285 */
 286 static NTSTATUS trans2_mkdir(struct smbsrv_request *req, struct trans_op *op)
     /* [<][>][^][v][top][bottom][index][help] */
 287 {
 288         struct smb_trans2 *trans = op->trans;
 289         union smb_mkdir *io;
 290 
 291         /* make sure we got enough parameters */
 292         if (trans->in.params.length < 5) {
 293                 return NT_STATUS_FOOBAR;
 294         }
 295 
 296         io = talloc(op, union smb_mkdir);
 297         NT_STATUS_HAVE_NO_MEMORY(io);
 298 
 299         io->t2mkdir.level = RAW_MKDIR_T2MKDIR;
 300         smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 4, &io->t2mkdir.in.path, 0);
 301         if (io->t2mkdir.in.path == NULL) {
 302                 return NT_STATUS_FOOBAR;
 303         }
 304 
 305         TRANS2_CHECK(ea_pull_list(&trans->in.data, io, 
 306                                   &io->t2mkdir.in.num_eas, 
 307                                   &io->t2mkdir.in.eas));
 308 
 309         op->op_info = io;
 310         op->send_fn = trans2_simple_send;
 311 
 312         return ntvfs_mkdir(req->ntvfs, io);
 313 }
 314 
 315 static NTSTATUS trans2_push_fileinfo(struct smbsrv_connection *smb_conn,
     /* [<][>][^][v][top][bottom][index][help] */
 316                                      TALLOC_CTX *mem_ctx,
 317                                      DATA_BLOB *blob,
 318                                      union smb_fileinfo *st,
 319                                      int default_str_flags)
 320 {
 321         uint32_t list_size;
 322         enum smb_fileinfo_level passthru_level;
 323 
 324         switch (st->generic.level) {
 325         case RAW_FILEINFO_GENERIC:
 326         case RAW_FILEINFO_GETATTR:
 327         case RAW_FILEINFO_GETATTRE:
 328         case RAW_FILEINFO_SEC_DESC:
 329         case RAW_FILEINFO_SMB2_ALL_EAS:
 330         case RAW_FILEINFO_SMB2_ALL_INFORMATION:
 331                 /* handled elsewhere */
 332                 return NT_STATUS_INVALID_LEVEL;
 333 
 334         case RAW_FILEINFO_UNIX_BASIC:
 335         case RAW_FILEINFO_UNIX_LINK:
 336                 /* not implemented yet */
 337                 return NT_STATUS_INVALID_LEVEL;
 338 
 339         case RAW_FILEINFO_STANDARD:
 340                 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 22));
 341 
 342                 srv_push_dos_date2(smb_conn, blob->data, 0, st->standard.out.create_time);
 343                 srv_push_dos_date2(smb_conn, blob->data, 4, st->standard.out.access_time);
 344                 srv_push_dos_date2(smb_conn, blob->data, 8, st->standard.out.write_time);
 345                 SIVAL(blob->data,        12, st->standard.out.size);
 346                 SIVAL(blob->data,        16, st->standard.out.alloc_size);
 347                 SSVAL(blob->data,        20, st->standard.out.attrib);
 348                 return NT_STATUS_OK;
 349 
 350         case RAW_FILEINFO_EA_SIZE:
 351                 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 26));
 352 
 353                 srv_push_dos_date2(smb_conn, blob->data, 0, st->ea_size.out.create_time);
 354                 srv_push_dos_date2(smb_conn, blob->data, 4, st->ea_size.out.access_time);
 355                 srv_push_dos_date2(smb_conn, blob->data, 8, st->ea_size.out.write_time);
 356                 SIVAL(blob->data,        12, st->ea_size.out.size);
 357                 SIVAL(blob->data,        16, st->ea_size.out.alloc_size);
 358                 SSVAL(blob->data,        20, st->ea_size.out.attrib);
 359                 SIVAL(blob->data,        22, st->ea_size.out.ea_size);
 360                 return NT_STATUS_OK;
 361 
 362         case RAW_FILEINFO_EA_LIST:
 363                 list_size = ea_list_size(st->ea_list.out.num_eas,
 364                                          st->ea_list.out.eas);
 365                 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, list_size));
 366 
 367                 ea_put_list(blob->data, 
 368                             st->ea_list.out.num_eas, st->ea_list.out.eas);
 369                 return NT_STATUS_OK;
 370 
 371         case RAW_FILEINFO_ALL_EAS:
 372                 list_size = ea_list_size(st->all_eas.out.num_eas,
 373                                                   st->all_eas.out.eas);
 374                 TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, list_size));
 375 
 376                 ea_put_list(blob->data, 
 377                             st->all_eas.out.num_eas, st->all_eas.out.eas);
 378                 return NT_STATUS_OK;
 379 
 380         case RAW_FILEINFO_IS_NAME_VALID:
 381                 return NT_STATUS_OK;
 382 
 383         case RAW_FILEINFO_BASIC_INFO:
 384                 passthru_level = RAW_FILEINFO_BASIC_INFORMATION;
 385                 break;
 386 
 387         case RAW_FILEINFO_STANDARD_INFO:
 388                 passthru_level = RAW_FILEINFO_STANDARD_INFORMATION;
 389                 break;
 390 
 391         case RAW_FILEINFO_EA_INFO:
 392                 passthru_level = RAW_FILEINFO_EA_INFORMATION;
 393                 break;
 394 
 395         case RAW_FILEINFO_COMPRESSION_INFO:
 396                 passthru_level = RAW_FILEINFO_COMPRESSION_INFORMATION;
 397                 break;
 398 
 399         case RAW_FILEINFO_ALL_INFO:
 400                 passthru_level = RAW_FILEINFO_ALL_INFORMATION;
 401                 break;
 402 
 403         case RAW_FILEINFO_NAME_INFO:
 404                 passthru_level = RAW_FILEINFO_NAME_INFORMATION;
 405                 break;
 406 
 407         case RAW_FILEINFO_ALT_NAME_INFO:
 408                 passthru_level = RAW_FILEINFO_ALT_NAME_INFORMATION;
 409                 break;
 410 
 411         case RAW_FILEINFO_STREAM_INFO:
 412                 passthru_level = RAW_FILEINFO_STREAM_INFORMATION;
 413                 break;
 414 
 415         default:
 416                 passthru_level = st->generic.level;
 417                 break;
 418         }
 419 
 420         return smbsrv_push_passthru_fileinfo(mem_ctx, blob,
 421                                              passthru_level, st,
 422                                              default_str_flags);
 423 }
 424 
 425 /*
 426   fill in the reply from a qpathinfo or qfileinfo call
 427 */
 428 static NTSTATUS trans2_fileinfo_send(struct trans_op *op)
     /* [<][>][^][v][top][bottom][index][help] */
 429 {
 430         struct smbsrv_request *req = op->req;
 431         struct smb_trans2 *trans = op->trans;
 432         union smb_fileinfo *st;
 433 
 434         TRANS2_CHECK_ASYNC_STATUS(st, union smb_fileinfo);
 435 
 436         TRANS2_CHECK(trans2_setup_reply(trans, 2, 0, 0));
 437         SSVAL(trans->out.params.data, 0, 0);
 438 
 439         TRANS2_CHECK(trans2_push_fileinfo(req->smb_conn, trans,
 440                                           &trans->out.data, st,
 441                                           SMBSRV_REQ_DEFAULT_STR_FLAGS(req)));
 442 
 443         return NT_STATUS_OK;
 444 }
 445 
 446 /*
 447   trans2 qpathinfo implementation
 448 */
 449 static NTSTATUS trans2_qpathinfo(struct smbsrv_request *req, struct trans_op *op)
     /* [<][>][^][v][top][bottom][index][help] */
 450 {
 451         struct smb_trans2 *trans = op->trans;
 452         union smb_fileinfo *st;
 453         uint16_t level;
 454 
 455         /* make sure we got enough parameters */
 456         if (trans->in.params.length < 2) {
 457                 return NT_STATUS_FOOBAR;
 458         }
 459 
 460         st = talloc(op, union smb_fileinfo);
 461         NT_STATUS_HAVE_NO_MEMORY(st);
 462 
 463         level = SVAL(trans->in.params.data, 0);
 464 
 465         smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 6, &st->generic.in.file.path, 0);
 466         if (st->generic.in.file.path == NULL) {
 467                 return NT_STATUS_FOOBAR;
 468         }
 469 
 470         /* work out the backend level - we make it 1-1 in the header */
 471         st->generic.level = (enum smb_fileinfo_level)level;
 472         if (st->generic.level >= RAW_FILEINFO_GENERIC) {
 473                 return NT_STATUS_INVALID_LEVEL;
 474         }
 475 
 476         if (st->generic.level == RAW_FILEINFO_EA_LIST) {
 477                 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req, 
 478                                                &st->ea_list.in.num_names,
 479                                                &st->ea_list.in.ea_names));
 480         }
 481 
 482         op->op_info = st;
 483         op->send_fn = trans2_fileinfo_send;
 484 
 485         return ntvfs_qpathinfo(req->ntvfs, st);
 486 }
 487 
 488 
 489 /*
 490   trans2 qpathinfo implementation
 491 */
 492 static NTSTATUS trans2_qfileinfo(struct smbsrv_request *req, struct trans_op *op)
     /* [<][>][^][v][top][bottom][index][help] */
 493 {
 494         struct smb_trans2 *trans = op->trans;
 495         union smb_fileinfo *st;
 496         uint16_t level;
 497         struct ntvfs_handle *h;
 498 
 499         /* make sure we got enough parameters */
 500         if (trans->in.params.length < 4) {
 501                 return NT_STATUS_FOOBAR;
 502         }
 503 
 504         st = talloc(op, union smb_fileinfo);
 505         NT_STATUS_HAVE_NO_MEMORY(st);
 506 
 507         h     = smbsrv_pull_fnum(req, trans->in.params.data, 0);
 508         level = SVAL(trans->in.params.data, 2);
 509 
 510         st->generic.in.file.ntvfs = h;
 511         /* work out the backend level - we make it 1-1 in the header */
 512         st->generic.level = (enum smb_fileinfo_level)level;
 513         if (st->generic.level >= RAW_FILEINFO_GENERIC) {
 514                 return NT_STATUS_INVALID_LEVEL;
 515         }
 516 
 517         if (st->generic.level == RAW_FILEINFO_EA_LIST) {
 518                 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req, 
 519                                                &st->ea_list.in.num_names,
 520                                                &st->ea_list.in.ea_names));
 521         }
 522 
 523         op->op_info = st;
 524         op->send_fn = trans2_fileinfo_send;
 525 
 526         SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
 527         return ntvfs_qfileinfo(req->ntvfs, st);
 528 }
 529 
 530 
 531 /*
 532   parse a trans2 setfileinfo/setpathinfo data blob
 533 */
 534 static NTSTATUS trans2_parse_sfileinfo(struct smbsrv_request *req,
     /* [<][>][^][v][top][bottom][index][help] */
 535                                        union smb_setfileinfo *st,
 536                                        const DATA_BLOB *blob)
 537 {
 538         enum smb_setfileinfo_level passthru_level;
 539 
 540         switch (st->generic.level) {
 541         case RAW_SFILEINFO_GENERIC:
 542         case RAW_SFILEINFO_SETATTR:
 543         case RAW_SFILEINFO_SETATTRE:
 544         case RAW_SFILEINFO_SEC_DESC:
 545                 /* handled elsewhere */
 546                 return NT_STATUS_INVALID_LEVEL;
 547 
 548         case RAW_SFILEINFO_STANDARD:
 549                 CHECK_MIN_BLOB_SIZE(blob, 12);
 550 
 551                 st->standard.in.create_time = srv_pull_dos_date2(req->smb_conn, blob->data + 0);
 552                 st->standard.in.access_time = srv_pull_dos_date2(req->smb_conn, blob->data + 4);
 553                 st->standard.in.write_time  = srv_pull_dos_date2(req->smb_conn, blob->data + 8);
 554 
 555                 return NT_STATUS_OK;
 556 
 557         case RAW_SFILEINFO_EA_SET:
 558                 return ea_pull_list(blob, req, 
 559                                     &st->ea_set.in.num_eas, 
 560                                     &st->ea_set.in.eas);
 561 
 562         case SMB_SFILEINFO_BASIC_INFO:
 563         case SMB_SFILEINFO_BASIC_INFORMATION:
 564                 passthru_level = SMB_SFILEINFO_BASIC_INFORMATION;
 565                 break;
 566 
 567         case SMB_SFILEINFO_DISPOSITION_INFO:
 568         case SMB_SFILEINFO_DISPOSITION_INFORMATION:
 569                 passthru_level = SMB_SFILEINFO_DISPOSITION_INFORMATION;
 570                 break;
 571 
 572         case SMB_SFILEINFO_ALLOCATION_INFO:
 573         case SMB_SFILEINFO_ALLOCATION_INFORMATION:
 574                 passthru_level = SMB_SFILEINFO_ALLOCATION_INFORMATION;
 575                 break;
 576 
 577         case RAW_SFILEINFO_END_OF_FILE_INFO:
 578         case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
 579                 passthru_level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
 580                 break;
 581 
 582         case RAW_SFILEINFO_RENAME_INFORMATION:
 583         case RAW_SFILEINFO_POSITION_INFORMATION:
 584         case RAW_SFILEINFO_MODE_INFORMATION:
 585                 passthru_level = st->generic.level;
 586                 break;
 587 
 588         case RAW_SFILEINFO_UNIX_BASIC:
 589         case RAW_SFILEINFO_UNIX_LINK:
 590         case RAW_SFILEINFO_UNIX_HLINK:
 591         case RAW_SFILEINFO_PIPE_INFORMATION:
 592         case RAW_SFILEINFO_VALID_DATA_INFORMATION:
 593         case RAW_SFILEINFO_SHORT_NAME_INFORMATION:
 594         case RAW_SFILEINFO_1025:
 595         case RAW_SFILEINFO_1027:
 596         case RAW_SFILEINFO_1029:
 597         case RAW_SFILEINFO_1030:
 598         case RAW_SFILEINFO_1031:
 599         case RAW_SFILEINFO_1032:
 600         case RAW_SFILEINFO_1036:
 601         case RAW_SFILEINFO_1041:
 602         case RAW_SFILEINFO_1042:
 603         case RAW_SFILEINFO_1043:
 604         case RAW_SFILEINFO_1044:
 605                 return NT_STATUS_INVALID_LEVEL;
 606 
 607         default:
 608                 /* we need a default here to cope with invalid values on the wire */
 609                 return NT_STATUS_INVALID_LEVEL;
 610         }
 611 
 612         return smbsrv_pull_passthru_sfileinfo(st, passthru_level, st,
 613                                               blob, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
 614                                               &req->in.bufinfo);
 615 }
 616 
 617 /*
 618   trans2 setfileinfo implementation
 619 */
 620 static NTSTATUS trans2_setfileinfo(struct smbsrv_request *req, struct trans_op *op)
     /* [<][>][^][v][top][bottom][index][help] */
 621 {
 622         struct smb_trans2 *trans = op->trans;
 623         union smb_setfileinfo *st;
 624         uint16_t level;
 625         struct ntvfs_handle *h;
 626 
 627         /* make sure we got enough parameters */
 628         if (trans->in.params.length < 4) {
 629                 return NT_STATUS_FOOBAR;
 630         }
 631 
 632         st = talloc(op, union smb_setfileinfo);
 633         NT_STATUS_HAVE_NO_MEMORY(st);
 634 
 635         h     = smbsrv_pull_fnum(req, trans->in.params.data, 0);
 636         level = SVAL(trans->in.params.data, 2);
 637 
 638         st->generic.in.file.ntvfs = h;
 639         /* work out the backend level - we make it 1-1 in the header */
 640         st->generic.level = (enum smb_setfileinfo_level)level;
 641         if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
 642                 return NT_STATUS_INVALID_LEVEL;
 643         }
 644 
 645         TRANS2_CHECK(trans2_parse_sfileinfo(req, st, &trans->in.data));
 646 
 647         op->op_info = st;
 648         op->send_fn = trans2_simple_send;
 649 
 650         SMBSRV_CHECK_FILE_HANDLE_NTSTATUS(st->generic.in.file.ntvfs);
 651         return ntvfs_setfileinfo(req->ntvfs, st);
 652 }
 653 
 654 /*
 655   trans2 setpathinfo implementation
 656 */
 657 static NTSTATUS trans2_setpathinfo(struct smbsrv_request *req, struct trans_op *op)
     /* [<][>][^][v][top][bottom][index][help] */
 658 {
 659         struct smb_trans2 *trans = op->trans;
 660         union smb_setfileinfo *st;
 661         uint16_t level;
 662 
 663         /* make sure we got enough parameters */
 664         if (trans->in.params.length < 4) {
 665                 return NT_STATUS_FOOBAR;
 666         }
 667 
 668         st = talloc(op, union smb_setfileinfo);
 669         NT_STATUS_HAVE_NO_MEMORY(st);
 670 
 671         level = SVAL(trans->in.params.data, 0);
 672 
 673         smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 6, &st->generic.in.file.path, 0);
 674         if (st->generic.in.file.path == NULL) {
 675                 return NT_STATUS_FOOBAR;
 676         }
 677 
 678         /* work out the backend level - we make it 1-1 in the header */
 679         st->generic.level = (enum smb_setfileinfo_level)level;
 680         if (st->generic.level >= RAW_SFILEINFO_GENERIC) {
 681                 return NT_STATUS_INVALID_LEVEL;
 682         }
 683 
 684         TRANS2_CHECK(trans2_parse_sfileinfo(req, st, &trans->in.data));
 685 
 686         op->op_info = st;
 687         op->send_fn = trans2_simple_send;
 688 
 689         return ntvfs_setpathinfo(req->ntvfs, st);
 690 }
 691 
 692 
 693 /* a structure to encapsulate the state information about an in-progress ffirst/fnext operation */
 694 struct find_state {
 695         struct trans_op *op;
 696         void *search;
 697         enum smb_search_data_level data_level;
 698         uint16_t last_entry_offset;
 699         uint16_t flags;
 700 };
 701 
 702 /*
 703   fill a single entry in a trans2 find reply 
 704 */
 705 static NTSTATUS find_fill_info(struct find_state *state,
     /* [<][>][^][v][top][bottom][index][help] */
 706                                const union smb_search_data *file)
 707 {
 708         struct smbsrv_request *req = state->op->req;
 709         struct smb_trans2 *trans = state->op->trans;
 710         uint8_t *data;
 711         uint_t ofs = trans->out.data.length;
 712         uint32_t ea_size;
 713 
 714         switch (state->data_level) {
 715         case RAW_SEARCH_DATA_GENERIC:
 716         case RAW_SEARCH_DATA_SEARCH:
 717                 /* handled elsewhere */
 718                 return NT_STATUS_INVALID_LEVEL;
 719 
 720         case RAW_SEARCH_DATA_STANDARD:
 721                 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
 722                         TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27));
 723                         SIVAL(trans->out.data.data, ofs, file->standard.resume_key);
 724                         ofs += 4;
 725                 } else {
 726                         TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 23));
 727                 }
 728                 data = trans->out.data.data + ofs;
 729                 srv_push_dos_date2(req->smb_conn, data, 0, file->standard.create_time);
 730                 srv_push_dos_date2(req->smb_conn, data, 4, file->standard.access_time);
 731                 srv_push_dos_date2(req->smb_conn, data, 8, file->standard.write_time);
 732                 SIVAL(data, 12, file->standard.size);
 733                 SIVAL(data, 16, file->standard.alloc_size);
 734                 SSVAL(data, 20, file->standard.attrib);
 735                 TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->standard.name.s, 
 736                                                        ofs + 22, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
 737                                                        STR_LEN8BIT | STR_TERMINATE | STR_LEN_NOTERM));
 738                 break;
 739 
 740         case RAW_SEARCH_DATA_EA_SIZE:
 741                 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
 742                         TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 31));
 743                         SIVAL(trans->out.data.data, ofs, file->ea_size.resume_key);
 744                         ofs += 4;
 745                 } else {
 746                         TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27));
 747                 }
 748                 data = trans->out.data.data + ofs;
 749                 srv_push_dos_date2(req->smb_conn, data, 0, file->ea_size.create_time);
 750                 srv_push_dos_date2(req->smb_conn, data, 4, file->ea_size.access_time);
 751                 srv_push_dos_date2(req->smb_conn, data, 8, file->ea_size.write_time);
 752                 SIVAL(data, 12, file->ea_size.size);
 753                 SIVAL(data, 16, file->ea_size.alloc_size);
 754                 SSVAL(data, 20, file->ea_size.attrib);
 755                 SIVAL(data, 22, file->ea_size.ea_size);
 756                 TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->ea_size.name.s, 
 757                                                        ofs + 26, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
 758                                                        STR_LEN8BIT | STR_NOALIGN));
 759                 TRANS2_CHECK(smbsrv_blob_fill_data(trans, &trans->out.data, trans->out.data.length + 1));
 760                 break;
 761 
 762         case RAW_SEARCH_DATA_EA_LIST:
 763                 ea_size = ea_list_size(file->ea_list.eas.num_eas, file->ea_list.eas.eas);
 764                 if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
 765                         TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27 + ea_size));
 766                         SIVAL(trans->out.data.data, ofs, file->ea_list.resume_key);
 767                         ofs += 4;
 768                 } else {
 769                         TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 23 + ea_size));
 770                 }
 771                 data = trans->out.data.data + ofs;
 772                 srv_push_dos_date2(req->smb_conn, data, 0, file->ea_list.create_time);
 773                 srv_push_dos_date2(req->smb_conn, data, 4, file->ea_list.access_time);
 774                 srv_push_dos_date2(req->smb_conn, data, 8, file->ea_list.write_time);
 775                 SIVAL(data, 12, file->ea_list.size);
 776                 SIVAL(data, 16, file->ea_list.alloc_size);
 777                 SSVAL(data, 20, file->ea_list.attrib);
 778                 ea_put_list(data+22, file->ea_list.eas.num_eas, file->ea_list.eas.eas);
 779                 TRANS2_CHECK(smbsrv_blob_append_string(trans, &trans->out.data, file->ea_list.name.s, 
 780                                                        ofs + 22 + ea_size, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
 781                                                        STR_LEN8BIT | STR_NOALIGN));
 782                 TRANS2_CHECK(smbsrv_blob_fill_data(trans, &trans->out.data, trans->out.data.length + 1));
 783                 break;
 784 
 785         case RAW_SEARCH_DATA_DIRECTORY_INFO:
 786         case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO:
 787         case RAW_SEARCH_DATA_NAME_INFO:
 788         case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO:
 789         case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO:
 790         case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO:
 791                 return smbsrv_push_passthru_search(trans, &trans->out.data, state->data_level, file,
 792                                                    SMBSRV_REQ_DEFAULT_STR_FLAGS(req));
 793 
 794         case RAW_SEARCH_DATA_UNIX_INFO:
 795         case RAW_SEARCH_DATA_UNIX_INFO2:
 796                 return NT_STATUS_INVALID_LEVEL;
 797         }
 798 
 799         return NT_STATUS_OK;
 800 }
 801 
 802 /* callback function for trans2 findfirst/findnext */
 803 static bool find_callback(void *private_data, const union smb_search_data *file)
     /* [<][>][^][v][top][bottom][index][help] */
 804 {
 805         struct find_state *state = talloc_get_type(private_data, struct find_state);
 806         struct smb_trans2 *trans = state->op->trans;
 807         uint_t old_length;
 808 
 809         old_length = trans->out.data.length;
 810 
 811         if (!NT_STATUS_IS_OK(find_fill_info(state, file)) ||
 812             trans->out.data.length > trans->in.max_data) {
 813                 /* restore the old length and tell the backend to stop */
 814                 smbsrv_blob_grow_data(trans, &trans->out.data, old_length);
 815                 return false;
 816         }
 817 
 818         state->last_entry_offset = old_length;  
 819         return true;
 820 }
 821 
 822 /*
 823   trans2 findfirst send
 824  */
 825 static NTSTATUS trans2_findfirst_send(struct trans_op *op)
     /* [<][>][^][v][top][bottom][index][help] */
 826 {
 827         struct smbsrv_request *req = op->req;
 828         struct smb_trans2 *trans = op->trans;
 829         union smb_search_first *search;
 830         struct find_state *state;
 831         uint8_t *param;
 832 
 833         TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
 834         search = talloc_get_type(state->search, union smb_search_first);
 835 
 836         /* fill in the findfirst reply header */
 837         param = trans->out.params.data;
 838         SSVAL(param, VWV(0), search->t2ffirst.out.handle);
 839         SSVAL(param, VWV(1), search->t2ffirst.out.count);
 840         SSVAL(param, VWV(2), search->t2ffirst.out.end_of_search);
 841         SSVAL(param, VWV(3), 0);
 842         SSVAL(param, VWV(4), state->last_entry_offset);
 843 
 844         return NT_STATUS_OK;
 845 }
 846 
 847 
 848 /*
 849   trans2 findfirst implementation
 850 */
 851 static NTSTATUS trans2_findfirst(struct smbsrv_request *req, struct trans_op *op)
     /* [<][>][^][v][top][bottom][index][help] */
 852 {
 853         struct smb_trans2 *trans = op->trans;
 854         union smb_search_first *search;
 855         uint16_t level;
 856         struct find_state *state;
 857 
 858         /* make sure we got all the parameters */
 859         if (trans->in.params.length < 14) {
 860                 return NT_STATUS_FOOBAR;
 861         }
 862 
 863         search = talloc(op, union smb_search_first);
 864         NT_STATUS_HAVE_NO_MEMORY(search);
 865 
 866         search->t2ffirst.in.search_attrib = SVAL(trans->in.params.data, 0);
 867         search->t2ffirst.in.max_count     = SVAL(trans->in.params.data, 2);
 868         search->t2ffirst.in.flags         = SVAL(trans->in.params.data, 4);
 869         level                             = SVAL(trans->in.params.data, 6);
 870         search->t2ffirst.in.storage_type  = IVAL(trans->in.params.data, 8);
 871 
 872         smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 12, &search->t2ffirst.in.pattern, 0);
 873         if (search->t2ffirst.in.pattern == NULL) {
 874                 return NT_STATUS_FOOBAR;
 875         }
 876 
 877         search->t2ffirst.level = RAW_SEARCH_TRANS2;
 878         search->t2ffirst.data_level = (enum smb_search_data_level)level;
 879         if (search->t2ffirst.data_level >= RAW_SEARCH_DATA_GENERIC) {
 880                 return NT_STATUS_INVALID_LEVEL;
 881         }
 882 
 883         if (search->t2ffirst.data_level == RAW_SEARCH_DATA_EA_LIST) {
 884                 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
 885                                                &search->t2ffirst.in.num_names, 
 886                                                &search->t2ffirst.in.ea_names));
 887         }
 888 
 889         /* setup the private state structure that the backend will
 890            give us in the callback */
 891         state = talloc(op, struct find_state);
 892         NT_STATUS_HAVE_NO_MEMORY(state);
 893         state->op               = op;
 894         state->search           = search;
 895         state->data_level       = search->t2ffirst.data_level;
 896         state->last_entry_offset= 0;
 897         state->flags            = search->t2ffirst.in.flags;
 898 
 899         /* setup for just a header in the reply */
 900         TRANS2_CHECK(trans2_setup_reply(trans, 10, 0, 0));
 901 
 902         op->op_info = state;
 903         op->send_fn = trans2_findfirst_send;
 904 
 905         return ntvfs_search_first(req->ntvfs, search, state, find_callback);
 906 }
 907 
 908 
 909 /*
 910   trans2 findnext send
 911 */
 912 static NTSTATUS trans2_findnext_send(struct trans_op *op)
     /* [<][>][^][v][top][bottom][index][help] */
 913 {
 914         struct smbsrv_request *req = op->req;
 915         struct smb_trans2 *trans = op->trans;
 916         union smb_search_next *search;
 917         struct find_state *state;
 918         uint8_t *param;
 919 
 920         TRANS2_CHECK_ASYNC_STATUS(state, struct find_state);
 921         search = talloc_get_type(state->search, union smb_search_next);
 922 
 923         /* fill in the findfirst reply header */
 924         param = trans->out.params.data;
 925         SSVAL(param, VWV(0), search->t2fnext.out.count);
 926         SSVAL(param, VWV(1), search->t2fnext.out.end_of_search);
 927         SSVAL(param, VWV(2), 0);
 928         SSVAL(param, VWV(3), state->last_entry_offset);
 929         
 930         return NT_STATUS_OK;
 931 }
 932 
 933 
 934 /*
 935   trans2 findnext implementation
 936 */
 937 static NTSTATUS trans2_findnext(struct smbsrv_request *req, struct trans_op *op)
     /* [<][>][^][v][top][bottom][index][help] */
 938 {
 939         struct smb_trans2 *trans = op->trans;
 940         union smb_search_next *search;
 941         uint16_t level;
 942         struct find_state *state;
 943 
 944         /* make sure we got all the parameters */
 945         if (trans->in.params.length < 12) {
 946                 return NT_STATUS_FOOBAR;
 947         }
 948 
 949         search = talloc(op, union smb_search_next);
 950         NT_STATUS_HAVE_NO_MEMORY(search);
 951 
 952         search->t2fnext.in.handle        = SVAL(trans->in.params.data, 0);
 953         search->t2fnext.in.max_count     = SVAL(trans->in.params.data, 2);
 954         level                            = SVAL(trans->in.params.data, 4);
 955         search->t2fnext.in.resume_key    = IVAL(trans->in.params.data, 6);
 956         search->t2fnext.in.flags         = SVAL(trans->in.params.data, 10);
 957 
 958         smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 12, &search->t2fnext.in.last_name, 0);
 959         if (search->t2fnext.in.last_name == NULL) {
 960                 return NT_STATUS_FOOBAR;
 961         }
 962 
 963         search->t2fnext.level = RAW_SEARCH_TRANS2;
 964         search->t2fnext.data_level = (enum smb_search_data_level)level;
 965         if (search->t2fnext.data_level >= RAW_SEARCH_DATA_GENERIC) {
 966                 return NT_STATUS_INVALID_LEVEL;
 967         }
 968 
 969         if (search->t2fnext.data_level == RAW_SEARCH_DATA_EA_LIST) {
 970                 TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
 971                                                &search->t2fnext.in.num_names, 
 972                                                &search->t2fnext.in.ea_names));
 973         }
 974 
 975         /* setup the private state structure that the backend will give us in the callback */
 976         state = talloc(op, struct find_state);
 977         NT_STATUS_HAVE_NO_MEMORY(state);
 978         state->op               = op;
 979         state->search           = search;
 980         state->data_level       = search->t2fnext.data_level;
 981         state->last_entry_offset= 0;
 982         state->flags            = search->t2fnext.in.flags;
 983 
 984         /* setup for just a header in the reply */
 985         TRANS2_CHECK(trans2_setup_reply(trans, 8, 0, 0));
 986 
 987         op->op_info = state;
 988         op->send_fn = trans2_findnext_send;
 989 
 990         return ntvfs_search_next(req->ntvfs, search, state, find_callback);
 991 }
 992 
 993 
 994 /*
 995   backend for trans2 requests
 996 */
 997 static NTSTATUS trans2_backend(struct smbsrv_request *req, struct trans_op *op)
     /* [<][>][^][v][top][bottom][index][help] */
 998 {
 999         struct smb_trans2 *trans = op->trans;
1000         NTSTATUS status;
1001 
1002         /* direct trans2 pass thru */
1003         status = ntvfs_trans2(req->ntvfs, trans);
1004         if (!NT_STATUS_EQUAL(NT_STATUS_NOT_IMPLEMENTED, status)) {
1005                 return status;
1006         }
1007 
1008         /* must have at least one setup word */
1009         if (trans->in.setup_count < 1) {
1010                 return NT_STATUS_FOOBAR;
1011         }
1012 
1013         /* the trans2 command is in setup[0] */
1014         switch (trans->in.setup[0]) {
1015         case TRANSACT2_FINDFIRST:
1016                 return trans2_findfirst(req, op);
1017         case TRANSACT2_FINDNEXT:
1018                 return trans2_findnext(req, op);
1019         case TRANSACT2_QPATHINFO:
1020                 return trans2_qpathinfo(req, op);
1021         case TRANSACT2_QFILEINFO:
1022                 return trans2_qfileinfo(req, op);
1023         case TRANSACT2_SETFILEINFO:
1024                 return trans2_setfileinfo(req, op);
1025         case TRANSACT2_SETPATHINFO:
1026                 return trans2_setpathinfo(req, op);
1027         case TRANSACT2_QFSINFO:
1028                 return trans2_qfsinfo(req, op);
1029         case TRANSACT2_OPEN:
1030                 return trans2_open(req, op);
1031         case TRANSACT2_MKDIR:
1032                 return trans2_mkdir(req, op);
1033         }
1034 
1035         /* an unknown trans2 command */
1036         return NT_STATUS_FOOBAR;
1037 }
1038 
1039 int smbsrv_trans_partial_destructor(struct smbsrv_trans_partial *tp)
     /* [<][>][^][v][top][bottom][index][help] */
1040 {
1041         DLIST_REMOVE(tp->req->smb_conn->trans_partial, tp);
1042         return 0;
1043 }
1044 
1045 
1046 /*
1047   send a continue request
1048 */
1049 static void reply_trans_continue(struct smbsrv_request *req, uint8_t command,
     /* [<][>][^][v][top][bottom][index][help] */
1050                                  struct smb_trans2 *trans)
1051 {
1052         struct smbsrv_request *req2;
1053         struct smbsrv_trans_partial *tp;
1054         int count;
1055 
1056         /* make sure they don't flood us */
1057         for (count=0,tp=req->smb_conn->trans_partial;tp;tp=tp->next) count++;
1058         if (count > 100) {
1059                 smbsrv_send_error(req, NT_STATUS_INSUFFICIENT_RESOURCES);
1060                 return;
1061         }
1062 
1063         tp = talloc(req, struct smbsrv_trans_partial);
1064 
1065         tp->req = req;
1066         tp->u.trans = trans;
1067         tp->command = command;
1068 
1069         DLIST_ADD(req->smb_conn->trans_partial, tp);
1070         talloc_set_destructor(tp, smbsrv_trans_partial_destructor);
1071 
1072         req2 = smbsrv_setup_secondary_request(req);
1073 
1074         /* send a 'please continue' reply */
1075         smbsrv_setup_reply(req2, 0, 0);
1076         smbsrv_send_reply(req2);
1077 }
1078 
1079 
1080 /*
1081   answer a reconstructed trans request
1082 */
1083 static void reply_trans_send(struct ntvfs_request *ntvfs)
     /* [<][>][^][v][top][bottom][index][help] */
1084 {
1085         struct smbsrv_request *req;
1086         struct trans_op *op;
1087         struct smb_trans2 *trans;
1088         uint16_t params_left, data_left;
1089         uint8_t *params, *data;
1090         int i;
1091 
1092         SMBSRV_CHECK_ASYNC_STATUS_ERR(op, struct trans_op);
1093         trans = op->trans;
1094 
1095         /* if this function needs work to form the nttrans reply buffer, then
1096            call that now */
1097         if (op->send_fn != NULL) {
1098                 NTSTATUS status;
1099                 status = op->send_fn(op);
1100                 if (!NT_STATUS_IS_OK(status)) {
1101                         smbsrv_send_error(req, status);
1102                         return;
1103                 }
1104         }
1105 
1106         params_left = trans->out.params.length;
1107         data_left   = trans->out.data.length;
1108         params      = trans->out.params.data;
1109         data        = trans->out.data.data;
1110 
1111         smbsrv_setup_reply(req, 10 + trans->out.setup_count, 0);
1112 
1113         if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) {
1114                 smbsrv_setup_error(req, req->ntvfs->async_states->status);
1115         }
1116 
1117         /* we need to divide up the reply into chunks that fit into
1118            the negotiated buffer size */
1119         do {
1120                 uint16_t this_data, this_param, max_bytes;
1121                 uint_t align1 = 1, align2 = (params_left ? 2 : 0);
1122                 struct smbsrv_request *this_req;
1123 
1124                 max_bytes = req_max_data(req) - (align1 + align2);
1125 
1126                 this_param = params_left;
1127                 if (this_param > max_bytes) {
1128                         this_param = max_bytes;
1129                 }
1130                 max_bytes -= this_param;
1131 
1132                 this_data = data_left;
1133                 if (this_data > max_bytes) {
1134                         this_data = max_bytes;
1135                 }
1136 
1137                 /* don't destroy unless this is the last chunk */
1138                 if (params_left - this_param != 0 || 
1139                     data_left - this_data != 0) {
1140                         this_req = smbsrv_setup_secondary_request(req);
1141                 } else {
1142                         this_req = req;
1143                 }
1144 
1145                 req_grow_data(this_req, this_param + this_data + (align1 + align2));
1146 
1147                 SSVAL(this_req->out.vwv, VWV(0), trans->out.params.length);
1148                 SSVAL(this_req->out.vwv, VWV(1), trans->out.data.length);
1149                 SSVAL(this_req->out.vwv, VWV(2), 0);
1150 
1151                 SSVAL(this_req->out.vwv, VWV(3), this_param);
1152                 SSVAL(this_req->out.vwv, VWV(4), align1 + PTR_DIFF(this_req->out.data, this_req->out.hdr));
1153                 SSVAL(this_req->out.vwv, VWV(5), PTR_DIFF(params, trans->out.params.data));
1154 
1155                 SSVAL(this_req->out.vwv, VWV(6), this_data);
1156                 SSVAL(this_req->out.vwv, VWV(7), align1 + align2 + 
1157                       PTR_DIFF(this_req->out.data + this_param, this_req->out.hdr));
1158                 SSVAL(this_req->out.vwv, VWV(8), PTR_DIFF(data, trans->out.data.data));
1159 
1160                 SCVAL(this_req->out.vwv, VWV(9), trans->out.setup_count);
1161                 SCVAL(this_req->out.vwv, VWV(9)+1, 0); /* reserved */
1162                 for (i=0;i<trans->out.setup_count;i++) {
1163                         SSVAL(this_req->out.vwv, VWV(10+i), trans->out.setup[i]);
1164                 }
1165 
1166                 memset(this_req->out.data, 0, align1);
1167                 if (this_param != 0) {
1168                         memcpy(this_req->out.data + align1, params, this_param);
1169                 }
1170                 memset(this_req->out.data+this_param+align1, 0, align2);
1171                 if (this_data != 0) {
1172                         memcpy(this_req->out.data+this_param+align1+align2, data, this_data);
1173                 }
1174 
1175                 params_left -= this_param;
1176                 data_left -= this_data;
1177                 params += this_param;
1178                 data += this_data;
1179 
1180                 smbsrv_send_reply(this_req);
1181         } while (params_left != 0 || data_left != 0);
1182 }
1183 
1184 
1185 /*
1186   answer a reconstructed trans request
1187 */
1188 static void reply_trans_complete(struct smbsrv_request *req, uint8_t command,
     /* [<][>][^][v][top][bottom][index][help] */
1189                                  struct smb_trans2 *trans)
1190 {
1191         struct trans_op *op;
1192 
1193         SMBSRV_TALLOC_IO_PTR(op, struct trans_op);
1194         SMBSRV_SETUP_NTVFS_REQUEST(reply_trans_send, NTVFS_ASYNC_STATE_MAY_ASYNC);
1195 
1196         op->req         = req;
1197         op->trans       = trans;
1198         op->command     = command;
1199         op->op_info     = NULL;
1200         op->send_fn     = NULL;
1201 
1202         /* its a full request, give it to the backend */
1203         if (command == SMBtrans) {
1204                 SMBSRV_CALL_NTVFS_BACKEND(ntvfs_trans(req->ntvfs, trans));
1205                 return;
1206         } else {
1207                 SMBSRV_CALL_NTVFS_BACKEND(trans2_backend(req, op));
1208                 return;
1209         }
1210 }
1211 
1212 /*
1213   Reply to an SMBtrans or SMBtrans2 request
1214 */
1215 static void reply_trans_generic(struct smbsrv_request *req, uint8_t command)
     /* [<][>][^][v][top][bottom][index][help] */
1216 {
1217         struct smb_trans2 *trans;
1218         int i;
1219         uint16_t param_ofs, data_ofs;
1220         uint16_t param_count, data_count;
1221         uint16_t param_total, data_total;
1222 
1223         /* parse request */
1224         if (req->in.wct < 14) {
1225                 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1226                 return;
1227         }
1228 
1229         trans = talloc(req, struct smb_trans2);
1230         if (trans == NULL) {
1231                 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1232                 return;
1233         }
1234 
1235         param_total           = SVAL(req->in.vwv, VWV(0));
1236         data_total            = SVAL(req->in.vwv, VWV(1));
1237         trans->in.max_param   = SVAL(req->in.vwv, VWV(2));
1238         trans->in.max_data    = SVAL(req->in.vwv, VWV(3));
1239         trans->in.max_setup   = CVAL(req->in.vwv, VWV(4));
1240         trans->in.flags       = SVAL(req->in.vwv, VWV(5));
1241         trans->in.timeout     = IVAL(req->in.vwv, VWV(6));
1242         param_count           = SVAL(req->in.vwv, VWV(9));
1243         param_ofs             = SVAL(req->in.vwv, VWV(10));
1244         data_count            = SVAL(req->in.vwv, VWV(11));
1245         data_ofs              = SVAL(req->in.vwv, VWV(12));
1246         trans->in.setup_count = CVAL(req->in.vwv, VWV(13));
1247 
1248         if (req->in.wct != 14 + trans->in.setup_count) {
1249                 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
1250                 return;
1251         }
1252 
1253         /* parse out the setup words */
1254         trans->in.setup = talloc_array(trans, uint16_t, trans->in.setup_count);
1255         if (trans->in.setup_count && !trans->in.setup) {
1256                 smbsrv_send_error(req, NT_STATUS_NO_MEMORY);
1257                 return;
1258         }
1259         for (i=0;i<trans->in.setup_count;i++) {
1260                 trans->in.setup[i] = SVAL(req->in.vwv, VWV(14+i));
1261         }
1262 
1263         if (command == SMBtrans) {
1264                 req_pull_string(&req->in.bufinfo, &trans->in.trans_name, req->in.data, -1, STR_TERMINATE);
1265         }
1266 
1267         if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, &trans->in.params) ||
1268             !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &trans->in.data)) {
1269                 smbsrv_send_error(req, NT_STATUS_FOOBAR);
1270                 return;
1271         }
1272 
1273         /* is it a partial request? if so, then send a 'send more' message */
1274         if (param_total > param_count || data_total > data_count) {
1275                 reply_trans_continue(req, command, trans);
1276                 return;
1277         }
1278 
1279         reply_trans_complete(req, command, trans);
1280 }
1281 
1282 
1283 /*
1284   Reply to an SMBtranss2 request
1285 */
1286 static void reply_transs_generic(struct smbsrv_request *req, uint8_t command)
     /* [<][>][^][v][top][bottom][index][help] */
1287 {
1288         struct smbsrv_trans_partial *tp;
1289         struct smb_trans2 *trans = NULL;
1290         uint16_t param_ofs, data_ofs;
1291         uint16_t param_count, data_count;
1292         uint16_t param_disp, data_disp;
1293         uint16_t param_total, data_total;
1294         DATA_BLOB params, data;
1295         uint8_t wct;
1296 
1297         if (command == SMBtrans2) {
1298                 wct = 9;
1299         } else {
1300                 wct = 8;
1301         }
1302 
1303         /* parse request */
1304         if (req->in.wct != wct) {
1305                 /*
1306                  * TODO: add some error code tests
1307                  *       w2k3 returns NT_STATUS_DOS(ERRSRV, ERRerror) here
1308                  */
1309                 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1310                 return;
1311         }
1312 
1313         for (tp=req->smb_conn->trans_partial;tp;tp=tp->next) {
1314                 if (tp->command == command &&
1315                     SVAL(tp->req->in.hdr, HDR_MID) == SVAL(req->in.hdr, HDR_MID)) {
1316 /* TODO: check the VUID, PID and TID too? */
1317                         break;
1318                 }
1319         }
1320 
1321         if (tp == NULL) {
1322                 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1323                 return;
1324         }
1325 
1326         trans = tp->u.trans;
1327 
1328         param_total           = SVAL(req->in.vwv, VWV(0));
1329         data_total            = SVAL(req->in.vwv, VWV(1));
1330         param_count           = SVAL(req->in.vwv, VWV(2));
1331         param_ofs             = SVAL(req->in.vwv, VWV(3));
1332         param_disp            = SVAL(req->in.vwv, VWV(4));
1333         data_count            = SVAL(req->in.vwv, VWV(5));
1334         data_ofs              = SVAL(req->in.vwv, VWV(6));
1335         data_disp             = SVAL(req->in.vwv, VWV(7));
1336 
1337         if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, &params) ||
1338             !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &data)) {
1339                 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1340                 return;
1341         }
1342 
1343         /* only allow contiguous requests */
1344         if ((param_count != 0 &&
1345              param_disp != trans->in.params.length) ||
1346             (data_count != 0 && 
1347              data_disp != trans->in.data.length)) {
1348                 smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
1349                 return;         
1350         }
1351 
1352         /* add to the existing request */
1353         if (param_count != 0) {
1354                 trans->in.params.data = talloc_realloc(trans, 
1355                                                          trans->in.params.data, 
1356                                                          uint8_t, 
1357                                                          param_disp + param_count);
1358                 if (trans->in.params.data == NULL) {
1359                         smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
1360                         return;
1361                 }
1362                 trans->in.params.length = param_disp + param_count;
1363         }
1364 
1365         if (data_count != 0) {
1366                 trans->in.data.data = talloc_realloc(trans, 
1367                                                        trans->in.data.data, 
1368                                                        uint8_t, 
1369                                                        data_disp + data_count);
1370                 if (trans->in.data.data == NULL) {
1371                         smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
1372                         return;
1373                 }
1374                 trans->in.data.length = data_disp + data_count;
1375         }
1376 
1377         memcpy(trans->in.params.data + param_disp, params.data, params.length);
1378         memcpy(trans->in.data.data + data_disp, data.data, data.length);
1379 
1380         /* the sequence number of the reply is taken from the last secondary
1381            response */
1382         tp->req->seq_num = req->seq_num;
1383 
1384         /* we don't reply to Transs2 requests */
1385         talloc_free(req);
1386 
1387         if (trans->in.params.length == param_total &&
1388             trans->in.data.length == data_total) {
1389                 /* its now complete */
1390                 req = tp->req;
1391                 talloc_free(tp);
1392                 reply_trans_complete(req, command, trans);
1393         }
1394         return;
1395 }
1396 
1397 
1398 /*
1399   Reply to an SMBtrans2
1400 */
1401 void smbsrv_reply_trans2(struct smbsrv_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
1402 {
1403         reply_trans_generic(req, SMBtrans2);
1404 }
1405 
1406 /*
1407   Reply to an SMBtrans
1408 */
1409 void smbsrv_reply_trans(struct smbsrv_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
1410 {
1411         reply_trans_generic(req, SMBtrans);
1412 }
1413 
1414 /*
1415   Reply to an SMBtranss request
1416 */
1417 void smbsrv_reply_transs(struct smbsrv_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
1418 {
1419         reply_transs_generic(req, SMBtrans);
1420 }
1421 
1422 /*
1423   Reply to an SMBtranss2 request
1424 */
1425 void smbsrv_reply_transs2(struct smbsrv_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
1426 {
1427         reply_transs_generic(req, SMBtrans2);
1428 }

/* [<][>][^][v][top][bottom][index][help] */