in dbus-java/src/main/java/org/freedesktop/dbus/connections/SASL.java [406:702]
public boolean auth(SaslMode mode, int types, String guid, OutputStream out, InputStream in, Socket us) throws IOException {
String luid = null;
String kernelUid = null;
long uid = POSIXFactory.getJavaPOSIX().getuid();
luid = stupidlyEncode("" + uid);
SASL.Command c;
int failed = 0;
int current = 0;
SaslAuthState state = SaslAuthState.INITIAL_STATE;
while (state != SaslAuthState.FINISHED && state != SaslAuthState.FAILED) {
logger.trace("Mode: {} AUTH state: {}", mode, state);
switch (mode) {
case CLIENT:
switch (state) {
case INITIAL_STATE:
if (FreeBSDHelper.isFreeBSD()) {
FreeBSDHelper.send_cred(us);
} else {
out.write(new byte[] {
0
});
}
send(out, AUTH);
state = SaslAuthState.WAIT_DATA;
break;
case WAIT_DATA:
c = receive(in);
switch (c.getCommand()) {
case DATA:
switch (doChallenge(current, c)) {
case CONTINUE:
send(out, DATA, c.getResponse());
break;
case OK:
send(out, DATA, c.getResponse());
state = SaslAuthState.WAIT_OK;
break;
case ERROR:
default:
send(out, ERROR, c.getResponse());
break;
}
break;
case REJECTED:
failed |= current;
int available = c.getMechs() & (~failed);
if (0 != (available & AUTH_EXTERNAL)) {
send(out, AUTH, "EXTERNAL", luid);
current = AUTH_EXTERNAL;
} else if (0 != (available & AUTH_SHA)) {
send(out, AUTH, "DBUS_COOKIE_SHA1", luid);
current = AUTH_SHA;
} else if (0 != (available & AUTH_ANON)) {
send(out, AUTH, "ANONYMOUS");
current = AUTH_ANON;
} else {
state = SaslAuthState.FAILED;
}
break;
case ERROR:
// when asking for file descriptor support, ERROR means FD support is not supported
if (state == SaslAuthState.NEGOTIATE_UNIX_FD) {
state = SaslAuthState.FINISHED;
logger.trace("File descriptors NOT supported by server");
fileDescriptorSupported = false;
send(out, BEGIN);
} else {
send(out, CANCEL);
state = SaslAuthState.WAIT_REJECT;
}
break;
case OK:
logger.trace("Authenticated");
state = SaslAuthState.AUTHENTICATED;
if (hasFileDescriptorSupport) {
state = SaslAuthState.WAIT_DATA;
logger.trace("Asking for file descriptor support");
// if authentication was successful, ask remote end for file descriptor support
send(out, SaslCommand.NEGOTIATE_UNIX_FD);
}else{
state = SaslAuthState.FINISHED;
send(out, BEGIN);
}
break;
case AGREE_UNIX_FD:
if (hasFileDescriptorSupport) {
state = SaslAuthState.FINISHED;
logger.trace("File descriptors supported by server");
fileDescriptorSupported = true;
send(out, BEGIN);
}
break;
default:
send(out, ERROR, "Got invalid command");
break;
}
break;
case WAIT_OK:
c = receive(in);
switch (c.getCommand()) {
case OK:
send(out, BEGIN);
state = SaslAuthState.AUTHENTICATED;
break;
case ERROR:
case DATA:
send(out, CANCEL);
state = SaslAuthState.WAIT_REJECT;
break;
case REJECTED:
failed |= current;
int available = c.getMechs() & (~failed);
state = SaslAuthState.WAIT_DATA;
if (0 != (available & AUTH_EXTERNAL)) {
send(out, AUTH, "EXTERNAL", luid);
current = AUTH_EXTERNAL;
} else if (0 != (available & AUTH_SHA)) {
send(out, AUTH, "DBUS_COOKIE_SHA1", luid);
current = AUTH_SHA;
} else if (0 != (available & AUTH_ANON)) {
send(out, AUTH, "ANONYMOUS");
current = AUTH_ANON;
} else {
state = SaslAuthState.FAILED;
}
break;
default:
send(out, ERROR, "Got invalid command");
break;
}
break;
case WAIT_REJECT:
c = receive(in);
switch (c.getCommand()) {
case REJECTED:
failed |= current;
int available = c.getMechs() & (~failed);
if (0 != (available & AUTH_EXTERNAL)) {
send(out, AUTH, "EXTERNAL", luid);
current = AUTH_EXTERNAL;
} else if (0 != (available & AUTH_SHA)) {
send(out, AUTH, "DBUS_COOKIE_SHA1", luid);
current = AUTH_SHA;
} else if (0 != (available & AUTH_ANON)) {
send(out, AUTH, "ANONYMOUS");
current = AUTH_ANON;
} else {
state = SaslAuthState.FAILED;
}
break;
default:
state = SaslAuthState.FAILED;
break;
}
break;
default:
state = SaslAuthState.FAILED;
}
break;
case SERVER:
switch (state) {
case INITIAL_STATE:
byte[] buf = new byte[1];
if (null == us) {
in.read(buf); // 0
state = SaslAuthState.WAIT_AUTH;
} else {
Credentials credentials;
try {
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;
} catch (SocketException _ex) {
state = SaslAuthState.FAILED;
}
}
break;
case WAIT_AUTH:
c = receive(in);
switch (c.getCommand()) {
case AUTH:
switch (doResponse(current, luid, kernelUid, c)) {
case CONTINUE:
send(out, DATA, c.getResponse());
current = c.getMechs();
state = SaslAuthState.WAIT_DATA;
break;
case OK:
send(out, SaslCommand.OK, guid);
state = SaslAuthState.WAIT_BEGIN;
current = 0;
break;
case REJECT:
default:
send(out, REJECTED, getTypes(types));
current = 0;
break;
}
break;
case ERROR:
send(out, REJECTED, getTypes(types));
break;
case BEGIN:
state = SaslAuthState.FAILED;
break;
default:
send(out, ERROR, "Got invalid command");
break;
}
break;
case WAIT_DATA:
c = receive(in);
switch (c.getCommand()) {
case DATA:
switch (doResponse(current, luid, kernelUid, c)) {
case CONTINUE:
send(out, DATA, c.getResponse());
state = SaslAuthState.WAIT_DATA;
break;
case OK:
send(out, SaslCommand.OK, guid);
state = SaslAuthState.WAIT_BEGIN;
current = 0;
break;
case REJECT:
default:
send(out, REJECTED, getTypes(types));
current = 0;
break;
}
break;
case ERROR:
case CANCEL:
send(out, REJECTED, getTypes(types));
state = SaslAuthState.WAIT_AUTH;
break;
case BEGIN:
state = SaslAuthState.FAILED;
break;
default:
send(out, ERROR, "Got invalid command");
break;
}
break;
case WAIT_BEGIN:
c = receive(in);
switch (c.getCommand()) {
case ERROR:
case CANCEL:
send(out, REJECTED, getTypes(types));
state = SaslAuthState.WAIT_AUTH;
break;
case BEGIN:
state = SaslAuthState.FINISHED;
break;
case NEGOTIATE_UNIX_FD:
logger.debug("File descriptor negotiation requested");
if (!hasFileDescriptorSupport) {
send(out, ERROR);
} else {
send(out, AGREE_UNIX_FD);
}
break;
default:
send(out, ERROR, "Got invalid command");
break;
}
break;
default:
state = SaslAuthState.FAILED;
}
break;
default:
return false;
}
}
return state == SaslAuthState.FINISHED;
}