1 /* jcifs msrpc client library in Java 2 * Copyright (C) 2006 "Michael B. Allen" <jcifs at samba dot org> 3 * "Eric Glass" <jcifs at samba dot org> 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 */ 19 20 package jcifs.dcerpc; 21 22 import java.io.*; 23 import java.net.*; 24 import java.security.Principal; 25 26 import jcifs.smb.NtlmPasswordAuthentication; 27 import jcifs.util.Hexdump; 28 import jcifs.dcerpc.ndr.NdrBuffer; 29 30 public abstract class DcerpcHandle implements DcerpcConstants { 31 32 /* Bindings are in the form: 33 * proto:\\server[key1=val1,key2=val2] 34 * or 35 * proto:server[key1=val1,key2=val2] 36 * or 37 * proto:[key1=val1,key2=val2] 38 * 39 * If a key is absent it is assumed to be 'endpoint'. Thus the 40 * following are equivalent: 41 * proto:\\ts0.win.net[endpoint=\pipe\srvsvc] 42 * proto:ts0.win.net[\pipe\srvsvc] 43 * 44 * If the server is absent it is set to "127.0.0.1" 45 */ parseBinding(String str)46 protected static DcerpcBinding parseBinding(String str) throws DcerpcException { 47 int state, mark, si; 48 char[] arr = str.toCharArray(); 49 String proto = null, key = null; 50 DcerpcBinding binding = null; 51 52 state = mark = si = 0; 53 do { 54 char ch = arr[si]; 55 56 switch (state) { 57 case 0: 58 if (ch == ':') { 59 proto = str.substring(mark, si); 60 mark = si + 1; 61 state = 1; 62 } 63 break; 64 case 1: 65 if (ch == '\\') { 66 mark = si + 1; 67 break; 68 } 69 state = 2; 70 case 2: 71 if (ch == '[') { 72 String server = str.substring(mark, si).trim(); 73 if (server.length() == 0) 74 server = "127.0.0.1"; 75 binding = new DcerpcBinding(proto, str.substring(mark, si)); 76 mark = si + 1; 77 state = 5; 78 } 79 break; 80 case 5: 81 if (ch == '=') { 82 key = str.substring(mark, si).trim(); 83 mark = si + 1; 84 } else if (ch == ',' || ch == ']') { 85 String val = str.substring(mark, si).trim(); 86 if (key == null) 87 key = "endpoint"; 88 binding.setOption(key, val); 89 key = null; 90 } 91 break; 92 default: 93 si = arr.length; 94 } 95 96 si++; 97 } while (si < arr.length); 98 99 if (binding == null || binding.endpoint == null) 100 throw new DcerpcException("Invalid binding URL: " + str); 101 102 return binding; 103 } 104 105 protected DcerpcBinding binding; 106 protected int max_xmit = 4280; 107 protected int max_recv = max_xmit; 108 protected int state = 0; 109 protected DcerpcSecurityProvider securityProvider = null; 110 private static int call_id = 1; 111 getHandle(String url, NtlmPasswordAuthentication auth)112 public static DcerpcHandle getHandle(String url, 113 NtlmPasswordAuthentication auth) 114 throws UnknownHostException, MalformedURLException, DcerpcException { 115 if (url.startsWith("ncacn_np:")) { 116 return new DcerpcPipeHandle(url, auth); 117 } 118 throw new DcerpcException("DCERPC transport not supported: " + url); 119 } 120 bind()121 public void bind() throws DcerpcException, IOException { 122 synchronized (this) { 123 try { 124 state = 1; 125 DcerpcMessage bind = new DcerpcBind(binding, this); 126 sendrecv(bind); 127 } catch (IOException ioe) { 128 state = 0; 129 throw ioe; 130 } 131 } 132 } sendrecv(DcerpcMessage msg)133 public void sendrecv(DcerpcMessage msg) throws DcerpcException, IOException { 134 byte[] stub, frag; 135 NdrBuffer buf, fbuf; 136 boolean isLast, isDirect; 137 DcerpcException de; 138 139 if (state == 0) { 140 bind(); 141 } 142 143 isDirect = true; 144 145 stub = jcifs.smb.BufferCache.getBuffer(); 146 try { 147 int off, tot, n; 148 149 buf = new NdrBuffer(stub, 0); 150 151 msg.flags = DCERPC_FIRST_FRAG | DCERPC_LAST_FRAG; 152 msg.call_id = call_id++; 153 154 msg.encode(buf); 155 156 if (securityProvider != null) { 157 buf.setIndex(0); 158 securityProvider.wrap(buf); 159 } 160 161 tot = buf.getLength() - 24; 162 off = 0; 163 164 while (off < tot) { 165 n = tot - off; 166 167 if ((24 + n) > max_xmit) { 168 msg.flags &= ~DCERPC_LAST_FRAG; 169 n = max_xmit - 24; 170 } else { 171 msg.flags |= DCERPC_LAST_FRAG; 172 isDirect = false; 173 msg.alloc_hint = n; 174 } 175 176 msg.length = 24 + n; 177 178 if (off > 0) 179 msg.flags &= ~DCERPC_FIRST_FRAG; 180 181 if ((msg.flags & (DCERPC_FIRST_FRAG | DCERPC_LAST_FRAG)) != (DCERPC_FIRST_FRAG | DCERPC_LAST_FRAG)) { 182 buf.start = off; 183 buf.reset(); 184 msg.encode_header(buf); 185 buf.enc_ndr_long(msg.alloc_hint); 186 buf.enc_ndr_short(0); /* context id */ 187 buf.enc_ndr_short(msg.getOpnum()); 188 } 189 190 doSendFragment(stub, off, msg.length, isDirect); 191 off += n; 192 } 193 194 doReceiveFragment(stub, isDirect); 195 buf.reset(); 196 buf.setIndex(8); 197 buf.setLength(buf.dec_ndr_short()); 198 199 if (securityProvider != null) 200 securityProvider.unwrap(buf); 201 202 buf.setIndex(0); 203 204 msg.decode_header(buf); 205 206 off = 24; 207 if (msg.ptype == 2 && msg.isFlagSet(DCERPC_LAST_FRAG) == false) 208 off = msg.length; 209 210 frag = null; 211 fbuf = null; 212 while (msg.isFlagSet(DCERPC_LAST_FRAG) == false) { 213 int stub_frag_len; 214 215 if (frag == null) { 216 frag = new byte[max_recv]; 217 fbuf = new NdrBuffer(frag, 0); 218 } 219 220 doReceiveFragment(frag, isDirect); 221 fbuf.reset(); 222 fbuf.setIndex(8); 223 fbuf.setLength(fbuf.dec_ndr_short()); 224 225 if (securityProvider != null) 226 securityProvider.unwrap(fbuf); 227 228 fbuf.reset(); 229 msg.decode_header(fbuf); 230 stub_frag_len = msg.length - 24; 231 232 if ((off + stub_frag_len) > stub.length) { 233 // shouldn't happen if alloc_hint is correct or greater 234 byte[] tmp = new byte[off + stub_frag_len]; 235 System.arraycopy(stub, 0, tmp, 0, off); 236 stub = tmp; 237 } 238 239 System.arraycopy(frag, 24, stub, off, stub_frag_len); 240 off += stub_frag_len; 241 } 242 243 buf = new NdrBuffer(stub, 0); 244 msg.decode(buf); 245 } finally { 246 jcifs.smb.BufferCache.releaseBuffer(stub); 247 } 248 249 if ((de = msg.getResult()) != null) 250 throw de; 251 } 252 setDcerpcSecurityProvider(DcerpcSecurityProvider securityProvider)253 public void setDcerpcSecurityProvider(DcerpcSecurityProvider securityProvider) 254 { 255 this.securityProvider = securityProvider; 256 } getServer()257 public String getServer() { 258 if (this instanceof DcerpcPipeHandle) 259 return ((DcerpcPipeHandle)this).pipe.getServer(); 260 return null; 261 } getPrincipal()262 public Principal getPrincipal() { 263 if (this instanceof DcerpcPipeHandle) 264 return ((DcerpcPipeHandle)this).pipe.getPrincipal(); 265 return null; 266 } toString()267 public String toString() { 268 return binding.toString(); 269 } 270 doSendFragment(byte[] buf, int off, int length, boolean isDirect)271 protected abstract void doSendFragment(byte[] buf, 272 int off, 273 int length, 274 boolean isDirect) throws IOException; doReceiveFragment(byte[] buf, boolean isDirect)275 protected abstract void doReceiveFragment(byte[] buf, boolean isDirect) throws IOException; close()276 public abstract void close() throws IOException; 277 } 278