Add win32 named pipe security level option

The sbtipcsocket by default restricts win32 named pipes to only allow
connections from the same login session. This makes connecting to a
remote server not work over ssh. We relax the default slightly in sbt to
allow the owner of the pipe to connect over any logon shell. The user
could restore the old behavior with:
```
Global / windowsServerSecurityLevel := Win32SecurityLevel.LOGON_DACL
```
or, if YOLO
```
Global / windowsServerSecurityLevel := Win32SecurityLevel.NO_SECURITY
```
This commit is contained in:
Ethan Atkins 2020-06-23 19:07:32 -07:00
parent 65599f2f84
commit f8e06def74
6 changed files with 23 additions and 1 deletions

View File

@ -76,6 +76,13 @@ object BasicKeys {
10000
)
val windowsServerSecurityLevel =
AttributeKey[Int](
"windowsServerSecurityLevel",
"Configures the security level of the named pipe. Values: 0 - No security; 1 - Logon user only; 2 - Process owner only",
10000
)
// Unlike other BasicKeys, this is not used directly as a setting key,
// and severLog / logLevel is used instead.
private[sbt] val serverLogLevel =

View File

@ -64,7 +64,13 @@ private[sbt] object Server {
connection.connectionType match {
case ConnectionType.Local if isWindows =>
// Named pipe already has an exclusive lock.
addServerError(new Win32NamedPipeServerSocket(pipeName))
addServerError(
new Win32NamedPipeServerSocket(
pipeName,
false,
connection.windowsServerSecurityLevel
)
)
case ConnectionType.Local =>
val maxSocketLength = new UnixDomainSocketLibrary.SockaddrUn().sunPath.length - 1
val path = socketfile.getAbsolutePath
@ -228,6 +234,7 @@ private[sbt] case class ServerConnection(
pipeName: String,
bspConnectionFile: File,
appConfiguration: AppConfiguration,
windowsServerSecurityLevel: Int
) {
def shortName: String = {
connectionType match {

View File

@ -17,6 +17,7 @@ import lmcoursier.CoursierDependencyResolution
import lmcoursier.definitions.{ Configuration => CConfiguration }
import org.apache.ivy.core.module.descriptor.ModuleDescriptor
import org.apache.ivy.core.module.id.ModuleRevisionId
import org.scalasbt.ipcsocket.Win32SecurityLevel
import sbt.Def.{ Initialize, ScopedKey, Setting, SettingsDefinition }
import sbt.Keys._
import sbt.Project.{
@ -386,6 +387,7 @@ object Defaults extends BuildCommon {
else Set()
},
serverHandlers :== Nil,
windowsServerSecurityLevel := Win32SecurityLevel.OWNER_DACL, // allows any owner logon session to access the server
fullServerHandlers := Nil,
insideCI :== sys.env.contains("BUILD_NUMBER") ||
sys.env.contains("CI") || SysProp.ci,

View File

@ -95,6 +95,7 @@ object Keys {
val serverHost = SettingKey(BasicKeys.serverHost)
val serverAuthentication = SettingKey(BasicKeys.serverAuthentication)
val serverConnectionType = SettingKey(BasicKeys.serverConnectionType)
val windowsServerSecurityLevel = SettingKey(BasicKeys.windowsServerSecurityLevel)
val fullServerHandlers = SettingKey(BasicKeys.fullServerHandlers)
val serverHandlers = settingKey[Seq[ServerHandler]]("User-defined server handlers.")

View File

@ -30,6 +30,7 @@ import Keys.{
serverConnectionType,
fullServerHandlers,
logLevel,
windowsServerSecurityLevel,
}
import Scope.{ Global, ThisScope }
import Def.{ Flattened, Initialize, ScopedKey, Setting }
@ -523,9 +524,11 @@ object Project extends ProjectExtra {
s.definedCommands,
projectCommand
)
val winSecurityLevel = get(windowsServerSecurityLevel).getOrElse(2)
val newAttrs =
s.attributes
.put(historyPath.key, history)
.put(windowsServerSecurityLevel.key, winSecurityLevel)
.setCond(autoStartServer.key, startSvr)
.setCond(serverPort.key, port)
.setCond(serverHost.key, host)

View File

@ -156,6 +156,7 @@ private[sbt] final class CommandExchange {
s.get(serverAuthentication).getOrElse(Set(ServerAuthentication.Token))
lazy val connectionType = s.get(serverConnectionType).getOrElse(ConnectionType.Tcp)
lazy val handlers = s.get(fullServerHandlers).getOrElse(Nil)
lazy val win32Level = s.get(windowsServerSecurityLevel).getOrElse(2)
def onIncomingSocket(socket: Socket, instance: ServerInstance): Unit = {
val name = newNetworkName
@ -193,6 +194,7 @@ private[sbt] final class CommandExchange {
pipeName,
bspConnectionFile,
s.configuration,
win32Level,
)
val serverInstance = Server.start(connection, onIncomingSocket, s.log)
// don't throw exception when it times out