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