Skip to content

Commit

Permalink
Add FreeBSD support (implement SCM_CREDS/cmsgcred).
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Gmelin committed May 25, 2020
1 parent 9179ac0 commit 4b340f3
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package org.freedesktop.dbus.connections;

import java.io.IOException;
import java.net.Socket;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import jnr.ffi.StructLayout;

import jnr.posix.POSIXFactory;

import jnr.constants.platform.*;
import jnr.posix.CmsgHdr;
import jnr.posix.MsgHdr;
import jnr.posix.NativePOSIX;
import jnr.posix.POSIXFactory;
import jnr.posix.util.Platform;

import jnr.unixsocket.UnixSocket;
import jnr.unixsocket.UnixSocketChannel;

/**
* Helpers to support FreeBSD. Ideally some of these will be abstracted
* and moved to jnr-unixsocket at some point.
*
* @author grembo
*/
public class FreeBSDHelper {

public static boolean isFreeBSD() {
return Platform.IS_FREEBSD;
}

public static class CmsgCredLayout extends StructLayout {
protected CmsgCredLayout(jnr.ffi.Runtime runtime) {
super(runtime);
}

public final pid_t cmcred_pid = new pid_t();
public final uid_t cmcred_uid = new uid_t();
public final uid_t cmcred_euid = new uid_t();
public final gid_t cmcred_gid = new gid_t();
public final Signed16 cmcred_ngroups = new Signed16();
public final gid_t[] cmcred_groups = array(new gid_t[16]);
}
public static final CmsgCredLayout cmsgCredLayout = new CmsgCredLayout(jnr.ffi.Runtime.getSystemRuntime());

public static void send_cred(Socket us) throws java.io.IOException {
NativePOSIX posix = (NativePOSIX) POSIXFactory.getNativePOSIX();
String data = "\0";
byte[] dataBytes = data.getBytes();

MsgHdr outMessage = posix.allocateMsgHdr();

ByteBuffer[] outIov = new ByteBuffer[1];
outIov[0] = ByteBuffer.allocateDirect(dataBytes.length);
outIov[0].put(dataBytes);
outIov[0].flip();

outMessage.setIov(outIov);

CmsgHdr outControl = outMessage.allocateControl(cmsgCredLayout.size());
outControl.setLevel(SocketLevel.SOL_SOCKET.intValue());
outControl.setType(0x03); // 0x03 == SCM_CREDS

ByteBuffer fdBuf = ByteBuffer.allocateDirect(cmsgCredLayout.size());
fdBuf.order(ByteOrder.nativeOrder());
//fdBuf.putInt(i, 0);
outControl.setData(fdBuf);

int fd = ((UnixSocketChannel)((UnixSocket) us).getChannel()).getFD();
int sentBytes = -1;
do
{
sentBytes = posix.sendmsg(fd, outMessage, 0);
}
while (sentBytes < 0 && Errno.EINTR.equals(posix.errno()));

if (sentBytes < 0)
{
long err = posix.errno();
/* This might've fail with EINVAL if the socket isn't AF_UNIX */
if (Errno.EINVAL.equals(err))
{
us.getOutputStream().write(dataBytes);
}
else
{
throw new IOException("Failed to write credentials byte: " +
LastError.valueOf(err).toString());
}
}
else if (sentBytes == 0)
{
throw new IOException("wrote zero bytes writing credentials byte");
}
}

public static long recv_cred(Socket us) {
NativePOSIX posix = (NativePOSIX) POSIXFactory.getNativePOSIX();
MsgHdr inMessage = posix.allocateMsgHdr();
ByteBuffer[] inIov = new ByteBuffer[1];
inIov[0] = ByteBuffer.allocateDirect(1);
inMessage.setIov(inIov);
CmsgHdr inControl = inMessage.allocateControl(cmsgCredLayout.size());

int fd = ((UnixSocketChannel)((UnixSocket) us).getChannel()).getFD();
int recvBytes = -1;
do
{
recvBytes = posix.recvmsg(fd, inMessage, 0);
}
while (recvBytes < 0 && Errno.EINTR.equals(posix.errno()));

if (recvBytes > 0 && inIov[0].get(0) == 0) {
for (CmsgHdr cmsg : inMessage.getControls()) {
if (cmsg.getType() == 0x03 && // 0x03 == SCM_CREDS
cmsg.getLevel() == SocketLevel.SOL_SOCKET.intValue() &&
cmsg.getLen() >= posix.socketMacros().CMSG_LEN(84))
{
ByteBuffer data = cmsg.getData();
final jnr.ffi.Pointer memory = jnr.ffi.Runtime.getSystemRuntime().getMemoryManager().allocateTemporary(cmsgCredLayout.size(), true);
for (int i=0; i<cmsgCredLayout.size(); ++i) {
memory.putByte(i, data.get(i));
}
return cmsgCredLayout.cmcred_euid.get(memory);
}
}
}
return -1;
}
}
26 changes: 18 additions & 8 deletions dbus-java/src/main/java/org/freedesktop/dbus/connections/SASL.java
Original file line number Diff line number Diff line change
Expand Up @@ -423,9 +423,13 @@ public boolean auth(SaslMode mode, int types, String guid, OutputStream out, Inp
case CLIENT:
switch (state) {
case INITIAL_STATE:
out.write(new byte[] {
0
});
if (FreeBSDHelper.isFreeBSD()) {
FreeBSDHelper.send_cred(us);
} else {
out.write(new byte[] {
0
});
}
send(out, AUTH);
state = SaslAuthState.WAIT_DATA;
break;
Expand Down Expand Up @@ -570,13 +574,19 @@ public boolean auth(SaslMode mode, int types, String guid, OutputStream out, Inp
if (null == us) {
in.read(buf);
} else {

Credentials credentials;
try {
credentials = ((UnixSocket) us).getCredentials();
int kuid = credentials.getUid();
if (kuid >= 0) {
kernelUid = stupidlyEncode("" + kuid);
if (FreeBSDHelper.isFreeBSD()) {
long euid = FreeBSDHelper.recv_cred(us);
if (euid >= 0) {
kernelUid = stupidlyEncode("" + euid);
}
} else {
credentials = ((UnixSocket) us).getCredentials();
int kuid = credentials.getUid();
if (kuid >= 0) {
kernelUid = stupidlyEncode("" + kuid);
}
}
state = SaslAuthState.WAIT_AUTH;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import jnr.posix.util.Platform;

import com.github.hypfvieh.util.StringUtil;

/** Handles a peer to peer connection between two applications withou a bus daemon.
Expand Down Expand Up @@ -138,7 +140,11 @@ public static String createDynamicSession() {
path = path.replaceAll("..........$", sb.toString());
LoggerFactory.getLogger(DirectConnection.class).trace("Trying path {}", path);
} while ((new File(path)).exists());
address += "abstract=" + path;
if (Platform.IS_FREEBSD) {
address += "path=" + path;
} else {
address += "abstract=" + path;
}
address += ",guid=" + TransportFactory.genGUID();
LoggerFactory.getLogger(DirectConnection.class).debug("Created Session address: {}", address);
return address;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.io.IOException;

import org.freedesktop.dbus.connections.BusAddress;
import org.freedesktop.dbus.connections.FreeBSDHelper;
import org.freedesktop.dbus.connections.SASL;

import com.github.hypfvieh.util.SystemUtil;
Expand Down Expand Up @@ -60,8 +61,8 @@ void connect() throws IOException {

us.configureBlocking(true);

// MacOS doesn't support SO_PASSCRED
if (!SystemUtil.isMacOs()) {
// MacOS and FreeBSD don't support SO_PASSCRED
if (!SystemUtil.isMacOs() && !FreeBSDHelper.isFreeBSD()) {
us.setOption(UnixSocketOptions.SO_PASSCRED, true);
}

Expand Down

0 comments on commit 4b340f3

Please sign in to comment.