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