// ---------------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // ---------------------------------------------------------------------------- // // //This file contains contracts and structure definitions for use with the SMB client. //The most important contract is SmbClientControlContract, which allows processes, //such as the SMB status / control tool, to query and display the state of an SMB //client process, and to send control requests to the client process. // // using System; using Microsoft.Singularity.Channels; using Microsoft.SingSharp; using Microsoft.Singularity.Directory; namespace Smb.PublicChannels { // // This contract allows control / management tools to communicate with the // SMB Client Manager service. The service is a singleton, which manages // (creates, configures, stops) the SMB client processes (instances of // SmbClient.exe). The importer of this contract is usually net.exe. // public contract SmbClientManagerContract : ServiceContract { out message Success(); override state Start: one { Success! -> Ready; } in message CreateClient(SmbClientConfig config); in message StopClient(char[]! in ExHeap clientId); in message BindClient(char[]! in ExHeap clientId, ServiceContract.Exp:Start! exp); in message EnumClients(); out message ClientList(char[][]! in ExHeap clientIdList); out message Ok(); out message RequestFailed(SmbErrorCode error, char[] in ExHeap errortext); in message QueryClientStatus(char[]! in ExHeap clientId); out message ClientStatusReport(SmbClientStatus status); in message QueryClientConfig(char[]! in ExHeap clientId); out message ClientConfigReport(SmbClientConfig status); state Ready : one { CreateClient? -> CreatingClient; StopClient? -> (Ok! or RequestFailed!) -> Ready; EnumClients? -> (ClientList! or RequestFailed!) -> Ready; BindClient? -> (Ok! or RequestFailed!) -> Ready; QueryClientStatus? -> (ClientStatusReport! or RequestFailed!) -> Ready; QueryClientConfig? -> (ClientConfigReport! or RequestFailed!) -> Ready; } state CreatingClient : one { Ok! -> Ready; RequestFailed! -> Ready; } public const string ManagerControlPath = "/service/smbfs"; } public enum SmbErrorCode { Success = 0, MountPathAlreadyExists, // a client with the same mount path already exists ClientExists, AuthorizationDenied, MountPathNotFound, InternalError, InvalidState, } // Each instance of the SMB client process (smbclient.exe) registers an instance of this // endpoint, usually as /dev/smb.xxx, where xxx is some arbitrary unique identifier. // This contract allows control / management tools, such as smb.exe, to query and display // information about running SMB clients, to send control requests to them (e.g. reconnect), // and to terminate (unmount) them. // // Note: This contract will be eliminated, and its equivalent control functions will be moved // to SmbClientManagerContract. public contract SmbClientControlContract : ServiceContract { #if false // This method polls the status of the client. The status can change // over time. in message GetStatus(); out message StatusReport(SmbClientStatus status); // This method polls the configuration of the client. The configuration // does not (currently) change over time. in message GetConfig(); out message ConfigReport(SmbClientConfig config); #endif // This method requests that the client disconnect from the remote // server (if it is connected), terminate all channel service threads, // and terminate the process. in message Terminate(); out message AckTerminate(); // This method disconnects the client from the remote server. // The client does not terminate. If the client receives any // requests (from local processes), then the client will attempt // to reconnect to the server. in message Disconnect(); out message AckDisconnect(); // This method disconnects the client and attempts to reconnect. in message Reconnect(); out message AckReconnect(); out message Success(); override state Start: one { Success! -> Ready; } state Ready : one { #if false GetStatus? -> StatusReport! -> Ready; GetConfig? -> ConfigReport! -> Ready; #endif Terminate? -> AckTerminate! -> Terminating; Disconnect? -> AckDisconnect! -> Ready; Reconnect? -> AckReconnect! -> Ready; } state Terminating : one { } } public enum SmbClientConnectionStatus { Invalid = 0, Disconnected, // no activity, so we are not connected TransportConnecting, // we're trying to establish connectivity at the transport level (TCP/IP or NBT) Negotiating, // transport is connected, now doing SMB negotiation, SESSION SETUP, etc. Authenticating, // Connected, // connected and ready to use } public enum SmbReasonDisconnected { Invalid = 0, Idle, // no one has asked to connect to the server yet TransportConnectFailed, // failed to connect NegotiationFailed, // SMB-level negotiation failed ResourceConnectFailed, // SMB server rejected TreeConnect AuthenticationFailed, // failed to prove identity AuthorizationFailed, // authenticated, but user is not authorized to use resource NoResponse, // no response to transport-level messages; assuming server is dead or unreachable ProtocolViolation, // received invalid SMB messages TransportFailure, // transport failure of some kind, after successful connection } // This structure describes the configuration of the SMB client. // It represents the "goal state" of the client. // The client will attempt to connect and service SMB requests, using // this configuration information. If any errors occur (TCP-level // connection failures, authentication failures, etc.), then the // client will periodically retry the connection. public rep struct SmbClientConfig : ITracked { public char[]! in ExHeap UncPath; // UNC of resource, such as \\foo\bar public char[]! in ExHeap MountPath; // local mount path, e.g. /share, implements DirectoryServiceContract public char[]! in ExHeap ControlPath; // local path of SmbClientControlContract, e.g. /dev/smb.xxx public char[]! in ExHeap CredentialsName; // auth principal name, e.g. domain\user, user@domain.com, OPTIONAL public char[]! in ExHeap Tag; // credentials tag, only set if CredentialsName != null } // This structure describes the current status of the SMB client. // The status is always sampled as a single snapshot in time, rather // than having multiple round-trips to query individual fields. public rep struct SmbClientStatus : ITracked { public SmbClientConnectionStatus ConnectionStatus; public SmbReasonDisconnected ReasonDisconnected; // If the client successfully connects to the SMB server, then these values // contain information that was received during SMB negotiation. These values // are useful for status displays. public char[] in ExHeap ServerMachineName; public char[] in ExHeap ServerDomainName; public char[] in ExHeap ServerOperatingSystem; public char[] in ExHeap ActiveCredentialsName; } // //This contract is used for communication between the SMB Client Manager service //(SmbClientManager) and instances SMB Client Process (SmbClient). The SMB Client Manager //service is the only process that creates any instances of the SmbClient executable; //it uses this contract to control the SmbClient processes. This allows detailed, //typed configuration information to be conveyed to the SmbClient (rather than relying //on command-line parameters), and also control messages (stop, etc.). // //The SmbClient process uses Process.GetStartupEndpoint (at index 0) to bind to its instance //of SmbClientControllerContract.Exp. // //The importer of this contract is always SmbClientManager. //The exporter of this contract is always SmbClient. // public contract SmbClientControllerContract { in message Configure(SmbClientConfig config); in message Bind(ServiceContract.Exp:Start! exp); out message Ok(); out message RequestFailed(SmbErrorCode error, char[] in ExHeap optionalErrorText); state Created : one { Configure? -> Configuring; } state Configuring : one { Ok! -> Running; RequestFailed! -> Created; } in message Stop(); state Running : one { Bind? -> (Ok! or RequestFailed!) -> Running; Stop? -> Ok! -> Stopped; } state Stopped : one { } } public contract SmbMuxNotifier { in message StatusChanged(SmbClientStatus muxstate); out message Ack(); state Ready : one { StatusChanged? -> Ack! -> Ready; } } }