1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22/* 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26/* 27 * SMB transaction functions. 28 */ 29 30#include <strings.h> 31 32#include <smbsrv/libsmbrdr.h> 33#include <smbsrv/smb.h> 34#include <smbrdr.h> 35 36/* 37 * The pipe filename, length (including the null terminator) 38 * and the buffer size for the transaction. Moving to unicode 39 * revealed that the length should not include the null. 40 */ 41#define TX_FILENAME "\\PIPE\\" 42#define TX_FILENAME_ASCII_LEN 6 43#define TX_FILENAME_WCHAR_LEN 14 44 45 46static int prep_smb_transact(smb_msgbuf_t *, unsigned short, char *, 47 unsigned short, unsigned short, unsigned); 48static int decode_smb_transact(smb_msgbuf_t *, char *, unsigned, 49 smb_transact_rsp_t *); 50 51/* 52 * smbrdr_transact 53 * 54 * Send a SMB_COM_TRANSACTION request. 55 */ 56int 57smbrdr_transact(int fid, char *out_buf, int out_len, char *in_buf, int in_len) 58{ 59 struct sdb_session *session; 60 struct sdb_netuse *netuse; 61 struct sdb_ofile *ofile; 62 struct sdb_logon *logon; 63 smb_transact_rsp_t rsp; 64 smbrdr_handle_t srh; 65 smb_msgbuf_t *mb; 66 DWORD status; 67 int rc; 68 unsigned short rcv_dcnt; 69 int cur_inlen; 70 int first_rsp; 71 72 if ((ofile = smbrdr_ofile_get(fid)) == 0) 73 return (-1); 74 75 netuse = ofile->netuse; 76 session = netuse->session; 77 logon = &session->logon; 78 79 status = smbrdr_request_init(&srh, SMB_COM_TRANSACTION, 80 session, logon, netuse); 81 82 if (status != NT_STATUS_SUCCESS) { 83 smb_log(smbrdr_log_hdl, LOG_DEBUG, "smbrdr_transact: %s", 84 xlate_nt_status(status)); 85 smbrdr_ofile_put(ofile); 86 return (-1); 87 } 88 89 mb = &srh.srh_mbuf; 90 91 rc = prep_smb_transact(mb, ofile->fid, out_buf, out_len, in_len, 92 session->remote_caps & CAP_UNICODE); 93 if (rc < 0) { 94 smb_log(smbrdr_log_hdl, LOG_DEBUG, 95 "smbrdr_transact: prep failed"); 96 smbrdr_handle_free(&srh); 97 smbrdr_ofile_put(ofile); 98 return (rc); 99 } 100 101 smbrdr_lock_transport(); 102 103 status = smbrdr_send(&srh); 104 if (status != NT_STATUS_SUCCESS) { 105 smbrdr_unlock_transport(); 106 smbrdr_handle_free(&srh); 107 smbrdr_ofile_put(ofile); 108 smb_log(smbrdr_log_hdl, LOG_DEBUG, 109 "smbrdr_transact: send failed"); 110 return (-1); 111 } 112 113 rcv_dcnt = 0; 114 cur_inlen = in_len; 115 first_rsp = 1; 116 117 do { 118 if (smbrdr_rcv(&srh, first_rsp) != NT_STATUS_SUCCESS) { 119 smb_log(smbrdr_log_hdl, LOG_DEBUG, 120 "smbrdr_transact: nb_rcv failed"); 121 rc = -1; 122 break; 123 } 124 125 rc = decode_smb_transact(mb, in_buf, cur_inlen, &rsp); 126 if (rc < 0 || rsp.TotalDataCount > in_len) { 127 smb_log(smbrdr_log_hdl, LOG_DEBUG, 128 "smbrdr_transact: decode failed"); 129 rc = -1; 130 break; 131 } 132 133 rcv_dcnt += rsp.DataCount; 134 cur_inlen -= rsp.DataCount; 135 first_rsp = 0; 136 137 } while (rcv_dcnt < rsp.TotalDataCount); 138 139 smbrdr_unlock_transport(); 140 smbrdr_handle_free(&srh); 141 smbrdr_ofile_put(ofile); 142 143 return ((rc < 0) ? rc : rcv_dcnt); 144} 145 146 147/* 148 * prep_smb_transact 149 * 150 * Prepare the SMB_COM_TRANSACTION request. 151 */ 152static int 153prep_smb_transact(smb_msgbuf_t *mb, unsigned short fid, char *out, 154 unsigned short out_len, unsigned short in_max, unsigned unicode) 155{ 156 int data_off; 157 int rc; 158 unsigned short bcc; 159 160 /* 161 * The byte count seems to include the pad 162 * byte to word align the filename and two 163 * spurious pad bytes between the filename 164 * and the transaction data. 165 */ 166 bcc = out_len + 3; 167 bcc += (unicode) ? TX_FILENAME_WCHAR_LEN : TX_FILENAME_ASCII_LEN; 168 169 data_off = 32; /* sizeof SMB header up to smb_wct */ 170 data_off += 1; /* sizeof smb_wct */ 171 data_off += 16*2; /* sizeof word parameters */ 172 data_off += 2; /* sizeof smb_bcc */ 173 data_off += (unicode) ? TX_FILENAME_WCHAR_LEN : TX_FILENAME_ASCII_LEN; 174 data_off += 3; 175 /* this is where data starts */ 176 177 rc = smb_msgbuf_encode(mb, 178 "(wct)b" 179 "(tpscnt)w (tdscnt)w (mprcnt)w (mdrcnt)w (msrcnt)b" 180 "(rsvd). (flags)w (timeo)l (rsvd1)2." 181 "(pscnt)w (psoff)w (dscnt)w (dsoff)w (suwcnt)b" 182 "(rsvd2). (pipop)w (fid)w (bcc)w (fname)u", 183 16, /* smb_wct */ 184 0, /* total parm bytes */ 185 out_len, /* total data bytes */ 186 0, /* max parm bytes to ret */ 187 in_max, /* max data bytes to ret */ 188 0, /* max setup words to ret */ 189 0, /* transact flags */ 190 0, /* transact timeout */ 191 0, /* parameter bytes */ 192 data_off, /* parameter offset */ 193 out_len, /* data bytes */ 194 data_off, /* data offset */ 195 2, /* total setup words */ 196 0x0026, /* OP=TransactNmPipe */ 197 fid, /* FID */ 198 bcc, /* byte count */ 199 TX_FILENAME); /* file name */ 200 201 /* 202 * Transaction data - padded. 203 */ 204 rc = smb_msgbuf_encode(mb, "..#c", out_len, out); 205 return (rc); 206} 207 208 209/* 210 * decode_smb_transact 211 * 212 * Decode the response from the SMB_COM_TRANSACTION request. 213 */ 214static int 215decode_smb_transact(smb_msgbuf_t *mb, char *in, unsigned in_len, 216 smb_transact_rsp_t *rsp) 217{ 218 int rc; 219 220 rc = smb_msgbuf_decode(mb, "b", &rsp->WordCount); 221 if (rc <= 0 || rsp->WordCount < 10) { 222 return (-1); 223 } 224 225 rc = smb_msgbuf_decode(mb, 226 "(tpscnt)w (tdscnt)w (rsvd)2." 227 "(pscnt)w (psoff)w (psdisp)w (dscnt)w (dsoff)w" 228 "(dsdisp)w (suwcnt)b (rsvd). (bcc)w", 229 &rsp->TotalParamCount, /* Total parm bytes */ 230 &rsp->TotalDataCount, /* Total data bytes */ 231 &rsp->ParamCount, /* Parm bytes this buffer */ 232 &rsp->ParamOffset, /* Parm offset from hdr */ 233 &rsp->ParamDisplacement, /* Parm displacement */ 234 &rsp->DataCount, /* Data bytes this buffer */ 235 &rsp->DataOffset, /* Data offset from hdr */ 236 &rsp->DataDisplacement, /* Data displacement */ 237 &rsp->SetupCount, /* Setup word count */ 238 &rsp->BCC); /* smb_bcc */ 239 240 if (rc <= 0) 241 return (-1); 242 243 if (rsp->DataCount > in_len) 244 return (-1); 245 246 bcopy(mb->base + rsp->DataOffset, 247 in + rsp->DataDisplacement, rsp->DataCount); 248 249 return (0); 250} 251