// This code is derived from jcifs smb client library // Ported by J. Arturo // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA using System; using System.IO; using SharpCifs.Dcerpc.Ndr; using SharpCifs.Smb; using SharpCifs.Util.Sharpen; namespace SharpCifs.Dcerpc { public abstract class DcerpcHandle { /// protected internal static DcerpcBinding ParseBinding(string str) { int state; int mark; int si; char[] arr = str.ToCharArray(); string proto = null; string key = null; DcerpcBinding binding = null; state = mark = si = 0; do { char ch = arr[si]; switch (state) { case 0: { if (ch == ':') { proto = Runtime.Substring(str, mark, si); mark = si + 1; state = 1; } break; } case 1: { if (ch == '\\') { mark = si + 1; break; } state = 2; goto case 2; } case 2: { if (ch == '[') { string server = Runtime.Substring(str, mark, si).Trim(); if (server.Length == 0) { server = "127.0.0.1"; } binding = new DcerpcBinding(proto, Runtime.Substring(str, mark, si)); mark = si + 1; state = 5; } break; } case 5: { if (ch == '=') { key = Runtime.Substring(str, mark, si).Trim(); mark = si + 1; } else { if (ch == ',' || ch == ']') { string val = Runtime.Substring(str, mark, si).Trim(); if (key == null) { key = "endpoint"; } binding.SetOption(key, val); key = null; } } break; } default: { si = arr.Length; break; } } si++; } while (si < arr.Length); if (binding == null || binding.Endpoint == null) { throw new DcerpcException("Invalid binding URL: " + str); } return binding; } protected internal DcerpcBinding Binding; protected internal int MaxXmit = 4280; protected internal int MaxRecv; protected internal int State; protected internal IDcerpcSecurityProvider SecurityProvider; private static int _callId = 1; /// /// /// public static DcerpcHandle GetHandle(string url, NtlmPasswordAuthentication auth) { if (url.StartsWith("ncacn_np:")) { return new DcerpcPipeHandle(url, auth); } throw new DcerpcException("DCERPC transport not supported: " + url); } /// /// public virtual void Bind() { lock (this) { try { State = 1; DcerpcMessage bind = new DcerpcBind(Binding, this); Sendrecv(bind); } catch (IOException ioe) { State = 0; throw; } } } /// /// public virtual void Sendrecv(DcerpcMessage msg) { byte[] stub; byte[] frag; NdrBuffer buf; NdrBuffer fbuf; bool isLast; bool isDirect; DcerpcException de; if (State == 0) { Bind(); } isDirect = true; stub = BufferCache.GetBuffer(); try { int off; int tot; int n; buf = new NdrBuffer(stub, 0); msg.Flags = DcerpcConstants.DcerpcFirstFrag | DcerpcConstants.DcerpcLastFrag; msg.CallId = _callId++; msg.Encode(buf); if (SecurityProvider != null) { buf.SetIndex(0); SecurityProvider.Wrap(buf); } tot = buf.GetLength() - 24; off = 0; while (off < tot) { n = tot - off; if ((24 + n) > MaxXmit) { msg.Flags &= ~DcerpcConstants.DcerpcLastFrag; n = MaxXmit - 24; } else { msg.Flags |= DcerpcConstants.DcerpcLastFrag; isDirect = false; msg.AllocHint = n; } msg.Length = 24 + n; if (off > 0) { msg.Flags &= ~DcerpcConstants.DcerpcFirstFrag; } if ( (msg.Flags & (DcerpcConstants.DcerpcFirstFrag | DcerpcConstants.DcerpcLastFrag)) != (DcerpcConstants.DcerpcFirstFrag | DcerpcConstants.DcerpcLastFrag) ) { buf.Start = off; buf.Reset(); msg.Encode_header(buf); buf.Enc_ndr_long(msg.AllocHint); buf.Enc_ndr_short(0); buf.Enc_ndr_short(msg.GetOpnum()); } DoSendFragment(stub, off, msg.Length, isDirect); off += n; } DoReceiveFragment(stub, isDirect); buf.Reset(); buf.SetIndex(8); buf.SetLength(buf.Dec_ndr_short()); if (SecurityProvider != null) { SecurityProvider.Unwrap(buf); } buf.SetIndex(0); msg.Decode_header(buf); off = 24; if (msg.Ptype == 2 && msg.IsFlagSet(DcerpcConstants.DcerpcLastFrag) == false) { off = msg.Length; } frag = null; fbuf = null; while (msg.IsFlagSet(DcerpcConstants.DcerpcLastFrag) == false) { int stubFragLen; if (frag == null) { frag = new byte[MaxRecv]; fbuf = new NdrBuffer(frag, 0); } DoReceiveFragment(frag, isDirect); fbuf.Reset(); fbuf.SetIndex(8); fbuf.SetLength(fbuf.Dec_ndr_short()); if (SecurityProvider != null) { SecurityProvider.Unwrap(fbuf); } fbuf.Reset(); msg.Decode_header(fbuf); stubFragLen = msg.Length - 24; if ((off + stubFragLen) > stub.Length) { // shouldn't happen if alloc_hint is correct or greater byte[] tmp = new byte[off + stubFragLen]; Array.Copy(stub, 0, tmp, 0, off); stub = tmp; } Array.Copy(frag, 24, stub, off, stubFragLen); off += stubFragLen; } buf = new NdrBuffer(stub, 0); msg.Decode(buf); } finally { BufferCache.ReleaseBuffer(stub); } if ((de = msg.GetResult()) != null) { throw de; } } public virtual void SetDcerpcSecurityProvider(IDcerpcSecurityProvider securityProvider ) { this.SecurityProvider = securityProvider; } public virtual string GetServer() { if (this is DcerpcPipeHandle) { return ((DcerpcPipeHandle)this).Pipe.GetServer(); } return null; } public virtual Principal GetPrincipal() { if (this is DcerpcPipeHandle) { return ((DcerpcPipeHandle)this).Pipe.GetPrincipal(); } return null; } public override string ToString() { return Binding.ToString(); } /// protected internal abstract void DoSendFragment(byte[] buf, int off, int length, bool isDirect); /// protected internal abstract void DoReceiveFragment(byte[] buf, bool isDirect); /// public abstract void Close(); public DcerpcHandle() { MaxRecv = MaxXmit; } } }