Пример #1
0
        /// <summary>
        /// Initializes a new instance of the OxcropsClient class.
        /// </summary>
        /// <param name="mapiContext">The Mapi Context</param>
        public OxcropsClient(MapiContext mapiContext)
        {
            if (mapiContext == null)
            {
                throw new ArgumentNullException("mapiContext should not be null");
            }

            this.RegisterROPDeserializer();
            this.MapiContext = mapiContext;
            this.site        = mapiContext.TestSite;

            switch (mapiContext.TransportSequence.ToLower())
            {
            case "mapi_http":
                this.mapiHttpAdapter = new MapiHttpAdapter(this.site);
                break;

            case "ncacn_ip_tcp":
            case "ncacn_http":
                this.rpcAdapter = new RpcAdapter(this.site);
                break;

            default:
                this.site.Assert.Fail("TransportSeq \"{0}\" is not supported by the test suite.");
                break;
            }
        }
Пример #2
0
        /// <summary>
        /// Get default RPC CALL Context
        /// </summary>
        /// <param name="site">The instance of ITestSite</param>
        /// <returns>RPC CALL Context</returns>
        public static MapiContext GetDefaultRpcContext(ITestSite site)
        {
            MapiContext mapiContext = new MapiContext
            {
                AuthenLevel       = uint.Parse(Common.GetConfigurationPropertyValue("RpcAuthenticationLevel", site)),
                AuthenService     = uint.Parse(Common.GetConfigurationPropertyValue("RpcAuthenticationService", site)),
                TransportSequence = Common.GetConfigurationPropertyValue("TransportSeq", site),
                SpnFormat         = Common.GetConfigurationPropertyValue("ServiceSpnFormat", site)
            };

            if (mapiContext.TransportSequence.ToLower() == "ncacn_http")
            {
                bool rpchUseSsl;
                if (!bool.TryParse(Common.GetConfigurationPropertyValue("RpchUseSsl", site), out rpchUseSsl))
                {
                    site.Assert.Fail("Value of 'RpchUseSsl' property is invalid.");
                }

                mapiContext.RpchUseSsl     = rpchUseSsl;
                mapiContext.RpchAuthScheme = Common.GetConfigurationPropertyValue("RpchAuthScheme", site);
                if (mapiContext.RpchAuthScheme.ToLower() != "basic" && mapiContext.RpchAuthScheme.ToLower() != "ntlm")
                {
                    site.Assert.Fail("Value of 'RpchAuthScheme' property is invalid.");
                }
            }

            mapiContext.SetUuid         = bool.Parse(Common.GetConfigurationPropertyValue("SetUuid", site));
            mapiContext.TestSite        = site;
            mapiContext.EXServerVersion = new ushort[3] {
                0, 0, 0
            };
            mapiContext.AutoRedirect = true;
            mapiContext.CodePageId   = null;

            return(mapiContext);
        }
        /// <summary>
        /// Initializes a new instance of the OxcropsClient class.
        /// </summary>
        /// <param name="mapiContext">The Mapi Context</param>
        public OxcropsClient(MapiContext mapiContext)
        {
            if (mapiContext == null)
            {
                throw new ArgumentNullException("mapiContext should not be null");
            }

            this.RegisterROPDeserializer();
            this.MapiContext = mapiContext;
            this.site = mapiContext.TestSite;

            switch (mapiContext.TransportSequence.ToLower())
            {
                case "mapi_http":
                    this.mapiHttpAdapter = new MapiHttpAdapter(this.site);
                    break;
                case "ncacn_ip_tcp":
                case "ncacn_http":
                    this.rpcAdapter = new RpcAdapter(this.site);
                    break;
                default:
                    this.site.Assert.Fail("TransportSeq \"{0}\" is not supported by the test suite.");
                    break;
            }
        }
        /// <summary>
        /// Get default RPC CALL Context
        /// </summary>
        /// <param name="site">The instance of ITestSite</param>
        /// <returns>RPC CALL Context</returns>
        public static MapiContext GetDefaultRpcContext(ITestSite site)
        {
            MapiContext mapiContext = new MapiContext
            {
                AuthenLevel = uint.Parse(Common.GetConfigurationPropertyValue("RpcAuthenticationLevel", site)),
                AuthenService = uint.Parse(Common.GetConfigurationPropertyValue("RpcAuthenticationService", site)),
                TransportSequence = Common.GetConfigurationPropertyValue("TransportSeq", site),
                SpnFormat = Common.GetConfigurationPropertyValue("ServiceSpnFormat", site)
            };
            if (mapiContext.TransportSequence.ToLower() == "ncacn_http")
            {
                bool rpchUseSsl;
                if (!bool.TryParse(Common.GetConfigurationPropertyValue("RpchUseSsl", site), out rpchUseSsl))
                {
                    site.Assert.Fail("Value of 'RpchUseSsl' property is invalid.");
                }

                mapiContext.RpchUseSsl = rpchUseSsl;
                mapiContext.RpchAuthScheme = Common.GetConfigurationPropertyValue("RpchAuthScheme", site);
                if (mapiContext.RpchAuthScheme.ToLower() != "basic" && mapiContext.RpchAuthScheme.ToLower() != "ntlm")
                {
                    site.Assert.Fail("Value of 'RpchAuthScheme' property is invalid.");
                }
            }

            mapiContext.SetUuid = bool.Parse(Common.GetConfigurationPropertyValue("SetUuid", site));
            mapiContext.TestSite = site;
            mapiContext.EXServerVersion = new ushort[3] { 0, 0, 0 };
            mapiContext.AutoRedirect = true;
            mapiContext.CodePageId = null;

            return mapiContext;
        }
Пример #5
0
        /// <summary>
        /// It establishes a new Session Context with the server by calling native methods.
        /// </summary>
        /// <param name="server">The server name.</param>
        /// <param name="domain">The domain the server is deployed</param>
        /// <param name="userName">The domain account name.</param>
        /// <param name="userDN">User's distinguished name (DN).</param>
        /// <param name="password">>user Password.</param>
        /// <param name="userSpn">User's SPN.</param>
        /// <param name="mapiContext">The default parameters for rpc call, such as authentication level, authentication method, whether to compress request.</param>
        /// <param name="options">proxy attribute</param>
        /// <returns>n success, the server MUST return a unique value to be used as a CXH. This unique value serves as the CXH for the client</returns>
        public IntPtr Connect(string server, string domain, string userName, string userDN, string password, string userSpn, MapiContext mapiContext, string options)
        {
            // The default parameter for out session handle.
            IntPtr pcxh = IntPtr.Zero;

            // CreateIdentity
            NativeMethods.CreateIdentity(
                domain,
                userName,
                password);

            uint status = NativeMethods.BindToServer(server, mapiContext.AuthenLevel, mapiContext.AuthenService, mapiContext.TransportSequence.ToLower(), mapiContext.RpchUseSsl, mapiContext.RpchAuthScheme, userSpn, options, mapiContext.SetUuid);

            if (status != 0)
            {
                throw new Exception("Could not create binding handle with server");
            }

            this.bindingHandle = NativeMethods.GetBindHandle();

            int waitTime      = int.Parse(Common.GetConfigurationPropertyValue("WaitTime", this.site));
            int maxRetryCount = int.Parse(Common.GetConfigurationPropertyValue("ConnectRetryCount", this.site));

            int retryCount = 0;

            do
            {
                status = this.Connect_Internal(ref pcxh, userDN, ref mapiContext);
                if (status >= 1700 && status <= 1799)
                {
                    // If status is between 1700 and 1799, try to connect again.
                    retryCount++;
                    System.Threading.Thread.Sleep(waitTime);

                    if (retryCount > 0)
                    {
                        this.site.Log.Add(LogEntryKind.Comment, "Can't connect to RPC server, will try to connect the server again. Current retry number is {0}.", retryCount);
                    }
                }
                else
                {
                    break;
                }
            }while (retryCount < maxRetryCount);

            if (status != 0)
            {
                string errorCodeHexString   = "0x" + status.ToString("X8");
                string errorCodeMeaning     = GetErrorCodeMeaning(errorCodeHexString);
                string errorCodeDescription = string.Empty;
                if (string.IsNullOrEmpty(errorCodeMeaning))
                {
                    errorCodeDescription = string.Format("Error code '{0}' is not defined in protocol MS-OXCRPC. The error message is: {1}", errorCodeHexString, (new Win32Exception((int)status)).ToString());
                }
                else
                {
                    errorCodeDescription = string.Format("Error code '{0}' is defined in protocol MS-OXCRPC as: {1}", errorCodeHexString, errorCodeMeaning);
                }

                this.site.Assert.Fail("Connect method returned an error: {0}. {1}", errorCodeHexString, errorCodeDescription);
            }

            return(pcxh);
        }
Пример #6
0
        /// <summary>
        /// The Connect method establishes a new Session Context with the server.
        /// </summary>
        /// <param name="pcxh">On success, the server MUST return a unique value to be used as a CXH. This unique value serves as the CXH for the client.</param>
        /// <param name="userDN">User's distinguished name (DN).</param>
        /// <param name="mapiContext">RPC call context</param>
        /// <returns>If the method succeeds, the return value is 0.
        /// If the method fails, the return value is an implementation-specific error code or one of the protocol-defined error codes.</returns>
        private uint Connect_Internal(ref IntPtr pcxh, string userDN, ref MapiContext mapiContext)
        {
            #region Parameters for RPC connect operation.
            // For ordinary client calls this value MUST be 0x00000000.
            uint flags = 0x00000000;

            // The connection modulus is a client derived 32-bit hash value of the DN passed in field szUserDN and can be used by the server to decide
            // which public folder replica to use when accessing public folder information when more than one replica of a folder exists.
            // The hash can be used to distribute client access across replicas in a deterministic way for load balancing.
            uint conMod = 3741814581;

            // This field is reserved. A client MUST pass a value of 0x00000000.
            uint limit = 0;

            // The code page in which text data SHOULD be sent if Unicode format is not requested by the client on subsequent calls using this Session Context.
            uint cpid = 0x000004E4;
            if (mapiContext.CodePageId != null)
            {
                cpid = mapiContext.CodePageId.Value;
            }

            // The local ID for everything other than sorting.
            uint lcidString = 0x00000409;

            // The local ID for sorting.
            uint lcidSort = 0x00000409;

            // This value is used to link the Session Context created by this call with an existing Session Context on the server.
            // If no session linking is requested, this value will be 0xFFFFFFFF.
            uint licxrLink = 0xFFFFFFFF;

            // The client MUST pass a value of 0x01.
            ushort canConvertCodePages = 0x01;

            // The server returns the number of milliseconds that a client SHOULD wait between polling the server for event information.
            uint cmsPollsMax = 0;

            // The server returns the number of times a client SHOULD retry future RPC calls using the CXH returned in this call.
            // This is for client RPC calls that fail with RPC status code RPC_S_SERVER_TOO_BUSY.
            // This is a suggested retry count for the client and SHOULD NOT be enforced by the server.
            uint retry = 0;

            // The server returns the number of milliseconds a client SHOULD wait before retrying a failed RPC call.
            // If any future RPC call to the server using the CXH returned in this call fails with RPC status code RPC_S_SERVER_TOO_BUSY,
            // it SHOULD wait the number of milliseconds specified in this output parameter before retrying the call.
            // The number of times a client SHOULD retry is returned in parameter pcRetry.
            // This is a suggested delay for the client and SHOULD NOT be enforced by the server.
            uint cmsRetryDelay = 0;

            // The server returns a session index value that is associated with the CXH returned from this call.
            // This value in conjunction with the session creation time stamp value returned in pulTimeStamp will be passed to a subsequent EcDoConnectEx call,
            // if the client wants to link two Session Contexts. The server MUST NOT assign two active Session Contexts the same session index value.
            // The server is free to return any 16-bit value for the session index.
            ushort cxr = 0;

            // The server returns the distinguished name (DN) of the server.
            UIntPtr pszDNPrefix;

            // The server returns the display name of the server.
            UIntPtr pszDisplayName;

            ushort[] rgwClientVersion = new ushort[3];
            ushort[] rgwServerVersion = new ushort[3] {
                0, 0, 0
            };
            ushort[] rgwBestVersion = new ushort[3];

            // The client passes the client protocol version the server SHOULD use to determine what protocol functionality the client supports.
            // For more information about how version numbers are interpreted from the wire data, see section 3.1.9.[MS-OXCMSG]
            rgwClientVersion[0] = 0x000c;
            rgwClientVersion[1] = 0x183e;
            rgwClientVersion[2] = 0x03e8;

            // On input, this parameter and parameter ulIcxrLink are used for linking the Session Context created by this call with an existing Session Context.
            // If the ulIcxrLink parameter is not 0xFFFFFFFF, the client MUST pass in the pulTimeStamp value returned from the server on a previous call to
            // EcDoConnectEx (see the ulIcxrLink and piCxr parameters for more details).
            uint timeStamp = 0;

            // This parameter contains an auxiliary payload buffer. The auxiliary payload buffer is prefixed by an RPC_HEADER_EXT structure.
            // Information stored in this header determines how to interpret the data following the header.
            // The length of the auxiliary payload buffer that includes the RPC_HEADER_EXT header is contained in parameter cbAuxIn.
            byte[] payloadBufferAuxIn = null;

            // On input, this parameter contains the length of the auxiliary payload buffer passed in the rgbAuxIn parameter.
            // The server MUST fail with error code ecRpcFormat if the request buffer is larger than 0x00001008 bytes in size.
            uint auxinLength = 0;

            // 0x1008: Set the max size of the rgbAuxOut
            byte[] rgbAuxOut = new byte[RpcAdapter.PcbAuxOut];

            // 0x1008: Set the max size of the cbAuxOut
            uint auxOutLength = RpcAdapter.PcbAuxOut;
            #endregion

            uint returnValue = 0;
            try
            {
                // Connect to server.
                returnValue = NativeMethods.EcDoConnectEx(
                    this.bindingHandle,
                    ref pcxh,
                    userDN,
                    flags,
                    conMod,
                    limit,
                    cpid,
                    lcidString,
                    lcidSort,
                    licxrLink,
                    canConvertCodePages,
                    out cmsPollsMax,
                    out retry,
                    out cmsRetryDelay,
                    out cxr,
                    out pszDNPrefix,
                    out pszDisplayName,
                    rgwClientVersion,
                    rgwServerVersion,
                    rgwBestVersion,
                    ref timeStamp,
                    payloadBufferAuxIn,
                    auxinLength,
                    rgbAuxOut,
                    ref auxOutLength);

                if (returnValue != 0)
                {
                    this.site.Log.Add(LogEntryKind.Comment, "EcDoConnectEx returns error code {0}. Refers to [MS-OXCDATA] section 2.4 for more information.", returnValue);
                }

                Array.Copy(rgwServerVersion, mapiContext.EXServerVersion, 3);
            }
            catch (SEHException e)
            {
                returnValue = RpcExceptionCode(e);

                this.site.Log.Add(LogEntryKind.Comment, "EcDoConnectEx throws exception, system error code is {0}, the error message is: {1}", returnValue, (new Win32Exception((int)returnValue)).ToString());
            }

            return(returnValue);
        }
Пример #7
0
        /// <summary>
        /// It establishes a new Session Context with the server by calling native methods.
        /// </summary>
        /// <param name="server">The server name.</param>
        /// <param name="domain">The domain the server is deployed</param>
        /// <param name="userName">The domain account name.</param>
        /// <param name="userDN">User's distinguished name (DN).</param>
        /// <param name="password">>user Password.</param>
        /// <param name="userSpn">User's SPN.</param>
        /// <param name="mapiContext">The default parameters for rpc call, such as authentication level, authentication method, whether to compress request.</param>
        /// <param name="options">proxy attribute</param>
        /// <returns>n success, the server MUST return a unique value to be used as a CXH. This unique value serves as the CXH for the client</returns>
        public IntPtr Connect(string server, string domain, string userName, string userDN, string password, string userSpn, MapiContext mapiContext, string options)
        {
            // The default parameter for out session handle.
            IntPtr pcxh = IntPtr.Zero;

            // CreateIdentity
            NativeMethods.CreateIdentity(
                domain,
                userName,
                password);

            uint status = NativeMethods.BindToServer(server, mapiContext.AuthenLevel, mapiContext.AuthenService, mapiContext.TransportSequence.ToLower(), mapiContext.RpchUseSsl, mapiContext.RpchAuthScheme, userSpn, options, mapiContext.SetUuid);
            if (status != 0)
            {
                throw new Exception("Could not create binding handle with server");
            }

            this.bindingHandle = NativeMethods.GetBindHandle();

            int waitTime = int.Parse(Common.GetConfigurationPropertyValue("WaitTime", this.site));
            int maxRetryCount = int.Parse(Common.GetConfigurationPropertyValue("ConnectRetryCount", this.site));

            int retryCount = 0;
            do
            {
                status = this.Connect_Internal(ref pcxh, userDN, ref mapiContext);
                if (status >= 1700 && status <= 1799)
                {
                    // If status is between 1700 and 1799, try to connect again.
                    retryCount++;
                    System.Threading.Thread.Sleep(waitTime);

                    if (retryCount > 0)
                    {
                        this.site.Log.Add(LogEntryKind.Comment, "Can't connect to RPC server, will try to connect the server again. Current retry number is {0}.", retryCount);
                    }
                }
                else
                {
                    break;
                }
            }
            while (retryCount < maxRetryCount);

            if (status != 0)
            {
                string errorCodeHexString = "0x" + status.ToString("X8");
                string errorCodeMeaning = GetErrorCodeMeaning(errorCodeHexString);
                string errorCodeDescription = string.Empty;
                if (string.IsNullOrEmpty(errorCodeMeaning))
                {
                    errorCodeDescription = string.Format("Error code '{0}' is not defined in protocol MS-OXCRPC. The error message is: {1}", errorCodeHexString, (new Win32Exception((int)status)).ToString());
                }
                else
                {
                    errorCodeDescription = string.Format("Error code '{0}' is defined in protocol MS-OXCRPC as: {1}", errorCodeHexString, errorCodeMeaning);
                }

                this.site.Assert.Fail("Connect method returned an error: {0}. {1}", errorCodeHexString, errorCodeDescription);
            }

            return pcxh;
        }
Пример #8
0
        /// <summary>
        /// The Connect method establishes a new Session Context with the server.
        /// </summary>
        /// <param name="pcxh">On success, the server MUST return a unique value to be used as a CXH. This unique value serves as the CXH for the client.</param>
        /// <param name="userDN">User's distinguished name (DN).</param>
        /// <param name="mapiContext">RPC call context</param>
        /// <returns>If the method succeeds, the return value is 0. 
        /// If the method fails, the return value is an implementation-specific error code or one of the protocol-defined error codes.</returns>
        private uint Connect_Internal(ref IntPtr pcxh, string userDN, ref MapiContext mapiContext)
        {
            #region Parameters for RPC connect operation.
            // For ordinary client calls this value MUST be 0x00000000.
            uint flags = 0x00000000;

            // The connection modulus is a client derived 32-bit hash value of the DN passed in field szUserDN and can be used by the server to decide 
            // which public folder replica to use when accessing public folder information when more than one replica of a folder exists. 
            // The hash can be used to distribute client access across replicas in a deterministic way for load balancing.
            uint conMod = 3741814581;

            // This field is reserved. A client MUST pass a value of 0x00000000.
            uint limit = 0;

            // The code page in which text data SHOULD be sent if Unicode format is not requested by the client on subsequent calls using this Session Context.
            uint cpid = 0x000004E4;
            if (mapiContext.CodePageId != null)
            {
                cpid = mapiContext.CodePageId.Value;
            }

            // The local ID for everything other than sorting.
            uint lcidString = 0x00000409;

            // The local ID for sorting.
            uint lcidSort = 0x00000409;

            // This value is used to link the Session Context created by this call with an existing Session Context on the server. 
            // If no session linking is requested, this value will be 0xFFFFFFFF.
            uint licxrLink = 0xFFFFFFFF;

            // The client MUST pass a value of 0x01.
            ushort canConvertCodePages = 0x01;

            // The server returns the number of milliseconds that a client SHOULD wait between polling the server for event information.
            uint cmsPollsMax = 0;

            // The server returns the number of times a client SHOULD retry future RPC calls using the CXH returned in this call. 
            // This is for client RPC calls that fail with RPC status code RPC_S_SERVER_TOO_BUSY. 
            // This is a suggested retry count for the client and SHOULD NOT be enforced by the server.
            uint retry = 0;

            // The server returns the number of milliseconds a client SHOULD wait before retrying a failed RPC call. 
            // If any future RPC call to the server using the CXH returned in this call fails with RPC status code RPC_S_SERVER_TOO_BUSY, 
            // it SHOULD wait the number of milliseconds specified in this output parameter before retrying the call. 
            // The number of times a client SHOULD retry is returned in parameter pcRetry. 
            // This is a suggested delay for the client and SHOULD NOT be enforced by the server.
            uint cmsRetryDelay = 0;

            // The server returns a session index value that is associated with the CXH returned from this call. 
            // This value in conjunction with the session creation time stamp value returned in pulTimeStamp will be passed to a subsequent EcDoConnectEx call, 
            // if the client wants to link two Session Contexts. The server MUST NOT assign two active Session Contexts the same session index value. 
            // The server is free to return any 16-bit value for the session index.
            ushort cxr = 0;

            // The server returns the distinguished name (DN) of the server.
            UIntPtr pszDNPrefix;

            // The server returns the display name of the server.
            UIntPtr pszDisplayName;

            ushort[] rgwClientVersion = new ushort[3];
            ushort[] rgwServerVersion = new ushort[3] { 0, 0, 0 };
            ushort[] rgwBestVersion = new ushort[3];

            // The client passes the client protocol version the server SHOULD use to determine what protocol functionality the client supports. 
            // For more information about how version numbers are interpreted from the wire data, see section 3.1.9.[MS-OXCMSG]
            rgwClientVersion[0] = 0x000c;
            rgwClientVersion[1] = 0x183e;
            rgwClientVersion[2] = 0x03e8;

            // On input, this parameter and parameter ulIcxrLink are used for linking the Session Context created by this call with an existing Session Context. 
            // If the ulIcxrLink parameter is not 0xFFFFFFFF, the client MUST pass in the pulTimeStamp value returned from the server on a previous call to 
            // EcDoConnectEx (see the ulIcxrLink and piCxr parameters for more details).
            uint timeStamp = 0;

            // This parameter contains an auxiliary payload buffer. The auxiliary payload buffer is prefixed by an RPC_HEADER_EXT structure. 
            // Information stored in this header determines how to interpret the data following the header. 
            // The length of the auxiliary payload buffer that includes the RPC_HEADER_EXT header is contained in parameter cbAuxIn.
            byte[] payloadBufferAuxIn = null;

            // On input, this parameter contains the length of the auxiliary payload buffer passed in the rgbAuxIn parameter. 
            // The server MUST fail with error code ecRpcFormat if the request buffer is larger than 0x00001008 bytes in size.
            uint auxinLength = 0;

            // 0x1008: Set the max size of the rgbAuxOut
            byte[] rgbAuxOut = new byte[RpcAdapter.PcbAuxOut];

            // 0x1008: Set the max size of the cbAuxOut
            uint auxOutLength = RpcAdapter.PcbAuxOut;
            #endregion

            uint returnValue = 0;
            try
            {
                // Connect to server.
                returnValue = NativeMethods.EcDoConnectEx(
                        this.bindingHandle,
                        ref pcxh,
                        userDN,
                        flags,
                        conMod,
                        limit,
                        cpid,
                        lcidString,
                        lcidSort,
                        licxrLink,
                        canConvertCodePages,
                        out cmsPollsMax,
                        out retry,
                        out cmsRetryDelay,
                        out cxr,
                        out pszDNPrefix,
                        out pszDisplayName,
                        rgwClientVersion,
                        rgwServerVersion,
                        rgwBestVersion,
                        ref timeStamp,
                        payloadBufferAuxIn,
                        auxinLength,
                        rgbAuxOut,
                        ref auxOutLength);

                if (returnValue != 0)
                {
                    this.site.Log.Add(LogEntryKind.Comment, "EcDoConnectEx returns error code {0}. Refers to [MS-OXCDATA] section 2.4 for more information.", returnValue);
                }

                Array.Copy(rgwServerVersion, mapiContext.EXServerVersion, 3);
            }
            catch (SEHException e)
            {
                returnValue = RpcExceptionCode(e);

                this.site.Log.Add(LogEntryKind.Comment, "EcDoConnectEx throws exception, system error code is {0}, the error message is: {1}", returnValue, (new Win32Exception((int)returnValue)).ToString());
            }

            return returnValue;
        }