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