All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.freedesktop.dbus.connections.SASL Maven / Gradle / Ivy

Go to download

Improved version of the DBus-Java library provided by freedesktop.org (https://dbus.freedesktop.org/doc/dbus-java/).

There is a newer version: 5.1.0
Show newest version
package org.freedesktop.dbus.connections;

import static org.freedesktop.dbus.connections.SASL.SaslCommand.*;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.NetworkChannel;
import java.nio.channels.SocketChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

import org.freedesktop.dbus.connections.transports.AbstractTransport;
import org.freedesktop.dbus.connections.transports.AbstractUnixTransport;
import org.freedesktop.dbus.messages.Message;
import org.freedesktop.dbus.utils.Hexdump;
import org.freedesktop.dbus.utils.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sun.security.auth.module.UnixSystem;


public class SASL {

    public static final int    LOCK_TIMEOUT                = 1000;
    public static final int    NEW_KEY_TIMEOUT_SECONDS     = 60 * 5;
    public static final int    EXPIRE_KEYS_TIMEOUT_SECONDS = NEW_KEY_TIMEOUT_SECONDS + (60 * 2);
    public static final int    MAX_TIME_TRAVEL_SECONDS     = 60 * 5;
    public static final int    COOKIE_TIMEOUT              = 240;
    public static final String COOKIE_CONTEXT              = "org_freedesktop_java";

    private static Collator col = Collator.getInstance();
    static {
        col.setDecomposition(Collator.FULL_DECOMPOSITION);
        col.setStrength(Collator.PRIMARY);
    }

    private String challenge = "";
    private String cookie    = "";


    private final Logger logger = LoggerFactory.getLogger(getClass());
    private boolean fileDescriptorSupported;
    /** whether file descriptor passing is supported on the current connection. */
    private boolean hasFileDescriptorSupport;

    /**
     * Create a new SASL auth handler.
     * Defaults to disable file descriptor passing.
     */
    public SASL() {
        this(false);
    }

    /**
     * Create a new SASL auth handler.
     *
     * @param _hasFileDescriptorSupport true to support file descriptor passing (usually only works with UNIX_SOCKET).
     */
    public SASL(boolean _hasFileDescriptorSupport) {
        hasFileDescriptorSupport = _hasFileDescriptorSupport;

    }

    private String findCookie(String context, String ID) throws IOException {
        String homedir = System.getProperty("user.home");
        File f = new File(homedir + "/.dbus-keyrings/" + context);
        BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(f)));
        String s = null;
        String lCookie = null;
        long now = System.currentTimeMillis() / 1000;
        while (null != (s = r.readLine())) {
            String[] line = s.split(" ");
            long timestamp = Long.parseLong(line[1]);
            if (line[0].equals(ID) && (!(timestamp < 0 || (now + MAX_TIME_TRAVEL_SECONDS) < timestamp || (now - EXPIRE_KEYS_TIMEOUT_SECONDS) > timestamp))) {
                lCookie = line[2];
                break;
            }
        }
        r.close();
        return lCookie;
    }

    private void addCookie(String _context, String _id, long _timestamp, String _cookie) throws IOException {
        String homedir = System.getProperty("user.home");
        File keydir = new File(homedir + "/.dbus-keyrings/");
        File cookiefile = new File(homedir + "/.dbus-keyrings/" + _context);
        File lock = new File(homedir + "/.dbus-keyrings/" + _context + ".lock");
        File temp = new File(homedir + "/.dbus-keyrings/" + _context + ".temp");

        // ensure directory exists
        if (!keydir.exists()) {
            keydir.mkdirs();
        }

        // acquire lock
        long start = System.currentTimeMillis();
        while (!lock.createNewFile() && LOCK_TIMEOUT > (System.currentTimeMillis() - start)) {
            ;
        }

        // read old file
        List lines = new ArrayList<>();
        if (cookiefile.exists()) {
            BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(cookiefile)));
            String s = null;
            while (null != (s = r.readLine())) {
                String[] line = s.split(" ");
                long time = Long.parseLong(line[1]);
                // expire stale cookies
                if ((_timestamp - time) < COOKIE_TIMEOUT) {
                    lines.add(s);
                }
            }
            r.close();
        }

        // add cookie
        lines.add(_id + " " + _timestamp + " " + _cookie);

        // write temp file
        PrintWriter w = new PrintWriter(new FileOutputStream(temp));
        for (String l : lines) {
            w.println(l);
        }
        w.close();

        // atomically move to old file
        if (!temp.renameTo(cookiefile)) {
            cookiefile.delete();
            temp.renameTo(cookiefile);
        }

        // remove lock
        lock.delete();
    }

    /**
     * Takes the string, encodes it as hex and then turns it into a string again.
     * No, I don't know why either.
     */
    private String stupidlyEncode(String data) {
        return Hexdump.toHex(data.getBytes()).replaceAll(" ", "");
    }

    private String stupidlyEncode(byte[] data) {
        return Hexdump.toHex(data).replaceAll(" ", "");
    }

    private byte getNibble(char c) {
        switch (c) {
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
            return (byte) (c - '0');
        case 'A':
        case 'B':
        case 'C':
        case 'D':
        case 'E':
        case 'F':
            return (byte) (c - 'A' + 10);
        case 'a':
        case 'b':
        case 'c':
        case 'd':
        case 'e':
        case 'f':
            return (byte) (c - 'a' + 10);
        default:
            return 0;
        }
    }

    private String stupidlyDecode(String data) {
        char[] cs = new char[data.length()];
        char[] res = new char[cs.length / 2];
        data.getChars(0, data.length(), cs, 0);
        for (int i = 0, j = 0; j < res.length; i += 2, j++) {
            int b = 0;
            b |= getNibble(cs[i]) << 4;
            b |= getNibble(cs[i + 1]);
            res[j] = (char) b;
        }
        return new String(res);
    }

    public static final int AUTH_NONE        = 0;
    public static final int AUTH_EXTERNAL    = 1;
    public static final int AUTH_SHA         = 2;
    public static final int AUTH_ANON        = 4;

    public SASL.Command receive(SocketChannel _sock) throws IOException {
        StringBuffer sb = new StringBuffer();
        ByteBuffer buf = ByteBuffer.allocate(64);

        boolean runLoop = true;
        while (runLoop) {
            int read = _sock.read(buf);
            buf.position(0);
            if (read == -1) {
                throw new IOException("Stream unexpectedly short (broken pipe)");
            }

            for (int i = buf.position(); i < read; i++) {
                byte c = buf.get();
                switch (c) {
                    case 0:
                    case '\r':
                        continue;
                    case '\n':
                        runLoop = false;
                        break;
                    default:
                        sb.append((char) c);
                    }
            }
            buf.clear();

        }

        logger.trace("received: {}", sb);
        try {
            return new Command(sb.toString());
        } catch (Exception e) {
            logger.error("Cannot create command.", e);
            return new Command();
        }
    }

    public void send(SocketChannel _sock, SaslCommand _command, String... _data) throws IOException {
        StringBuffer sb = new StringBuffer();
        sb.append(_command.name());

        for (String s : _data) {
            sb.append(' ');
            sb.append(s);
        }
        sb.append('\r');
        sb.append('\n');
        logger.trace("sending: {}", sb);
        _sock.write(ByteBuffer.wrap(sb.toString().getBytes()));
    }

    SaslResult doChallenge(int _auth, SASL.Command c) throws IOException {
        switch (_auth) {
        case AUTH_SHA:
            String[] reply = stupidlyDecode(c.getData()).split(" ");
            logger.trace(Arrays.toString(reply));
            if (3 != reply.length) {
                logger.debug("Reply is not length 3");
                return SaslResult.ERROR;
            }
            String context = reply[0];
            String id = reply[1];
            String serverchallenge = reply[2];
            MessageDigest md = null;
            try {
                md = MessageDigest.getInstance("SHA");
            } catch (NoSuchAlgorithmException nsae) {
                logger.debug("", nsae);
                return SaslResult.ERROR;
            }
            byte[] buf = new byte[8];
            Message.marshallintBig(System.currentTimeMillis(), buf, 0, 8);
            String clientchallenge = stupidlyEncode(md.digest(buf));
            md.reset();
            long start = System.currentTimeMillis();
            String lCookie = null;
            while (null == lCookie && (System.currentTimeMillis() - start) < LOCK_TIMEOUT) {
                lCookie = findCookie(context, id);
            }
            if (null == lCookie) {
                logger.debug("Did not find a cookie in context {}  with ID {}",context, id);
                return SaslResult.ERROR;
            }
            String response = serverchallenge + ":" + clientchallenge + ":" + lCookie;
            buf = md.digest(response.getBytes());

            logger.trace("Response: {} hash: {}", response, Hexdump.format(buf));

            response = stupidlyEncode(buf);
            c.setResponse(stupidlyEncode(clientchallenge + " " + response));
            return SaslResult.OK;
        default:
            logger.debug("Not DBUS_COOKIE_SHA1 authtype.");
            return SaslResult.ERROR;
        }
    }

    SaslResult doResponse(int _auth, String _uid, String _kernelUid, SASL.Command _c) {
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance("SHA");
        } catch (NoSuchAlgorithmException nsae) {
            logger.error("", nsae);
            return SaslResult.ERROR;
        }
        switch (_auth) {
            case AUTH_NONE:
                switch (_c.getMechs()) {
                case AUTH_ANON:
                    return SaslResult.OK;
                case AUTH_EXTERNAL:
                    if (0 == col.compare(_uid, _c.getData()) && (null == _kernelUid || 0 == col.compare(_uid, _kernelUid))) {
                        return SaslResult.OK;
                    } else {
                        return SaslResult.REJECT;
                    }
                case AUTH_SHA:
                    String context = COOKIE_CONTEXT;
                    long id = System.currentTimeMillis();
                    byte[] buf = new byte[8];
                    Message.marshallintBig(id, buf, 0, 8);
                    challenge = stupidlyEncode(md.digest(buf));
                    Random r = new Random();
                    r.nextBytes(buf);
                    cookie = stupidlyEncode(md.digest(buf));
                    try {
                        addCookie(context, "" + id, id / 1000, cookie);
                    } catch (IOException ioe) {
                        logger.debug("", ioe);
                    }

                    logger.debug("Sending challenge: {} {} {}", context, id, challenge);

                    _c.setResponse(stupidlyEncode(context + ' ' + id + ' ' + challenge));
                    return SaslResult.OK;
                default:
                    return SaslResult.ERROR;
                }
            case AUTH_SHA:
                String[] response = stupidlyDecode(_c.getData()).split(" ");
                if (response.length < 2) {
                    return SaslResult.ERROR;
                }
                String cchal = response[0];
                String hash = response[1];
                String prehash = challenge + ":" + cchal + ":" + cookie;
                byte[] buf = md.digest(prehash.getBytes());
                String posthash = stupidlyEncode(buf);
                logger.debug("Authenticating Hash; data={} remote-hash={} local-hash={}",prehash, hash, posthash);
                if (0 == col.compare(posthash, hash)) {
                    return SaslResult.OK;
                } else {
                    return SaslResult.ERROR;
                }
            default:
                return SaslResult.ERROR;
            }
    }

    public String[] getTypes(int types) {
        switch (types) {
            case AUTH_EXTERNAL:
                return new String[] {
                        "EXTERNAL"
                };
            case AUTH_SHA:
                return new String[] {
                        "DBUS_COOKIE_SHA1"
                };
            case AUTH_ANON:
                return new String[] {
                        "ANONYMOUS"
                };
            case AUTH_SHA + AUTH_EXTERNAL:
                return new String[] {
                        "EXTERNAL", "DBUS_COOKIE_SHA1"
                };
            case AUTH_SHA + AUTH_ANON:
                return new String[] {
                        "ANONYMOUS", "DBUS_COOKIE_SHA1"
                };
            case AUTH_EXTERNAL + AUTH_ANON:
                return new String[] {
                        "ANONYMOUS", "EXTERNAL"
                };
            case AUTH_EXTERNAL + AUTH_ANON + AUTH_SHA:
                return new String[] {
                        "ANONYMOUS", "EXTERNAL", "DBUS_COOKIE_SHA1"
                };
            default:
                return new String[] {};
        }
    }

    /**
     * Performs SASL auth on the given socketchannel.
     * Mode selects whether to run as a SASL server or client.
     * Types is a bitmask of the available auth types.
     *
     * @param _mode mode
     * @param _types types
     * @param _guid guid
     * @param _sock socket channel
     * @param _transport transport
     *
     * @return true if the auth was successful and false if it failed.
     * @throws IOException on failure
     */
    public boolean auth(SaslMode _mode, int _types, String _guid, SocketChannel _sock, AbstractTransport _transport) throws IOException {
        String luid = null;
        String kernelUid = null;

        long uid = getUserId();
        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:
                    // TODO: Howto do this for BSD?
//                    if (FreeBSDHelper.isFreeBSD()) {
//                        FreeBSDHelper.send_cred(_us);
//                    } else {
                    _sock.write(ByteBuffer.wrap(new byte[] {0}));
//                    }
                    send(_sock, AUTH);
                    state = SaslAuthState.WAIT_DATA;
                    break;
                case WAIT_DATA:
                    c = receive(_sock);
                    switch (c.getCommand()) {
                        case DATA:
                            switch (doChallenge(current, c)) {
                                case CONTINUE:
                                    send(_sock, DATA, c.getResponse());
                                    break;
                                case OK:
                                    send(_sock, DATA, c.getResponse());
                                    state = SaslAuthState.WAIT_OK;
                                    break;
                                case ERROR:
                                default:
                                    send(_sock, ERROR, c.getResponse());
                                    break;
                            }
                        break;
                        case REJECTED:
                            failed |= current;
                            int available = c.getMechs() & (~failed);
                            if (0 != (available & AUTH_EXTERNAL)) {
                                send(_sock, AUTH, "EXTERNAL", luid);
                                current = AUTH_EXTERNAL;
                            } else if (0 != (available & AUTH_SHA)) {
                                send(_sock, AUTH, "DBUS_COOKIE_SHA1", luid);
                                current = AUTH_SHA;
                            } else if (0 != (available & AUTH_ANON)) {
                                send(_sock, 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(_sock, BEGIN);
                            } else {
                                send(_sock, 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(_sock, SaslCommand.NEGOTIATE_UNIX_FD);
                            }else{
                                state = SaslAuthState.FINISHED;
                                send(_sock, BEGIN);
                            }
                            break;
                        case AGREE_UNIX_FD:
                            if (hasFileDescriptorSupport) {
                                state = SaslAuthState.FINISHED;
                                logger.trace("File descriptors supported by server");
                                fileDescriptorSupported = true;
                                send(_sock, BEGIN);
                            }
                            break;
                        default:
                            send(_sock, ERROR, "Got invalid command");
                            break;
                        }
                    break;
                case WAIT_OK:
                    c = receive(_sock);
                    switch (c.getCommand()) {
                    case OK:
                        send(_sock, BEGIN);
                        state = SaslAuthState.AUTHENTICATED;
                        break;
                    case ERROR:
                    case DATA:
                        send(_sock, 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(_sock, AUTH, "EXTERNAL", luid);
                            current = AUTH_EXTERNAL;
                        } else if (0 != (available & AUTH_SHA)) {
                            send(_sock, AUTH, "DBUS_COOKIE_SHA1", luid);
                            current = AUTH_SHA;
                        } else if (0 != (available & AUTH_ANON)) {
                            send(_sock, AUTH, "ANONYMOUS");
                            current = AUTH_ANON;
                        } else {
                            state = SaslAuthState.FAILED;
                        }
                        break;
                    default:
                        send(_sock, ERROR, "Got invalid command");
                        break;
                    }
                    break;
                case WAIT_REJECT:
                    c = receive(_sock);
                    switch (c.getCommand()) {
                        case REJECTED:
                            failed |= current;
                            int available = c.getMechs() & (~failed);
                            if (0 != (available & AUTH_EXTERNAL)) {
                                send(_sock, AUTH, "EXTERNAL", luid);
                                current = AUTH_EXTERNAL;
                            } else if (0 != (available & AUTH_SHA)) {
                                send(_sock, AUTH, "DBUS_COOKIE_SHA1", luid);
                                current = AUTH_SHA;
                            } else if (0 != (available & AUTH_ANON)) {
                                send(_sock, 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:
                        ByteBuffer buf = ByteBuffer.allocate(1);
                        if (_sock instanceof NetworkChannel) {
                            _sock.read(buf); // 0
                            state = SaslAuthState.WAIT_AUTH;
                        } else {
                            try {
                                // TODO: how to solve this in freebsd?
//                              if (FreeBSDHelper.isFreeBSD()) {
//                                  long euid = FreeBSDHelper.recv_cred(_us);
//                                  if (euid >= 0) {
//                                      kernelUid = stupidlyEncode("" + euid);
//                                  }
//                              }
                                int kuid = -1;
                                if (_transport instanceof AbstractUnixTransport) {
                                    kuid = ((AbstractUnixTransport) _transport).getUid(_sock);
                                }
                                if (kuid >= 0) {
                                    kernelUid = stupidlyEncode("" + kuid);
                                }
                                state = SaslAuthState.WAIT_AUTH;

                            } catch (SocketException _ex) {
                                state = SaslAuthState.FAILED;
                            }
                        }
                    break;
                    case WAIT_AUTH:
                        c = receive(_sock);
                        switch (c.getCommand()) {
                            case AUTH:
                                switch (doResponse(current, luid, kernelUid, c)) {
                                    case CONTINUE:
                                        send(_sock, DATA, c.getResponse());
                                        current = c.getMechs();
                                        state = SaslAuthState.WAIT_DATA;
                                        break;
                                    case OK:
                                        send(_sock, SaslCommand.OK, _guid);
                                        state = SaslAuthState.WAIT_BEGIN;
                                        current = 0;
                                        break;
                                    case REJECT:
                                    default:
                                        send(_sock, REJECTED, getTypes(_types));
                                        current = 0;
                                        break;
                                }
                                break;
                            case ERROR:
                                send(_sock, REJECTED, getTypes(_types));
                                break;
                            case BEGIN:
                                state = SaslAuthState.FAILED;
                                break;
                            default:
                                send(_sock, ERROR, "Got invalid command");
                                break;
                            }
                    break;
                    case WAIT_DATA:
                        c = receive(_sock);
                    switch (c.getCommand()) {
                    case DATA:
                        switch (doResponse(current, luid, kernelUid, c)) {
                            case CONTINUE:
                                send(_sock, DATA, c.getResponse());
                                state = SaslAuthState.WAIT_DATA;
                                break;
                            case OK:
                                send(_sock, SaslCommand.OK, _guid);
                                state = SaslAuthState.WAIT_BEGIN;
                                current = 0;
                                break;
                            case REJECT:
                            default:
                                send(_sock, REJECTED, getTypes(_types));
                                current = 0;
                                break;
                            }
                        break;
                        case ERROR:
                        case CANCEL:
                            send(_sock, REJECTED, getTypes(_types));
                            state = SaslAuthState.WAIT_AUTH;
                        break;
                        case BEGIN:
                            state = SaslAuthState.FAILED;
                        break;
                        default:
                            send(_sock, ERROR, "Got invalid command");
                        break;
                    }
                    break;
                    case WAIT_BEGIN:
                        c = receive(_sock);
                        switch (c.getCommand()) {
                            case ERROR:
                            case CANCEL:
                                send(_sock, 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(_sock, ERROR);
                                } else {
                                    send(_sock, AGREE_UNIX_FD);
                                }

                            break;
                            default:
                                send(_sock, ERROR, "Got invalid command");
                            break;
                        }
                    break;
                    default:
                        state = SaslAuthState.FAILED;
                    }
                break;
            default:
                return false;
            }
        }

        return state == SaslAuthState.FINISHED;
    }

    /**
     * Tries to get the UID (user ID) of the current JVM process.
     * Will always return 0 on windows.
     * @return long
     */
    private long getUserId() {
        if (!Util.isWindows()) {
            return new UnixSystem().getUid();
        }

        return 0;
    }

    public static enum SaslMode {
        SERVER, CLIENT;
    }

    public static enum SaslCommand {
        AUTH,
        DATA,
        REJECTED,
        OK,
        BEGIN,
        CANCEL,
        ERROR,
        NEGOTIATE_UNIX_FD,
        AGREE_UNIX_FD;
    }

    static enum SaslAuthState {
        INITIAL_STATE,
        WAIT_DATA,
        WAIT_OK,
        WAIT_REJECT,
        WAIT_AUTH,
        WAIT_BEGIN,
        AUTHENTICATED,
        NEGOTIATE_UNIX_FD,
        FINISHED,
        FAILED;
    }

    public static enum SaslResult {
        OK,
        CONTINUE,
        ERROR,
        REJECT;
    }

    public static class Command {
        private final Logger logger = LoggerFactory.getLogger(getClass());
        private SaslCommand    command;
        private int    mechs;
        private String data;
        private String response;

        public Command() {
        }

        public Command(String s) throws IOException {
            String[] ss = s.split(" ");
            logger.trace("Creating command from: {}", Arrays.toString(ss));
            if (0 == col.compare(ss[0], "OK")) {
                command = SaslCommand.OK;
                data = ss[1];
            } else if (0 == col.compare(ss[0], "AUTH")) {
                command = AUTH;
                if (ss.length > 1) {
                    if (0 == col.compare(ss[1], "EXTERNAL")) {
                        mechs = AUTH_EXTERNAL;
                    } else if (0 == col.compare(ss[1], "DBUS_COOKIE_SHA1")) {
                        mechs = AUTH_SHA;
                    } else if (0 == col.compare(ss[1], "ANONYMOUS")) {
                        mechs = AUTH_ANON;
                    }
                }
                if (ss.length > 2) {
                    data = ss[2];
                }
            } else if (0 == col.compare(ss[0], "DATA")) {
                command = DATA;
                data = ss[1];
            } else if (0 == col.compare(ss[0], "REJECTED")) {
                command = REJECTED;
                for (int i = 1; i < ss.length; i++) {
                    if (0 == col.compare(ss[i], "EXTERNAL")) {
                        mechs |= AUTH_EXTERNAL;
                    } else if (0 == col.compare(ss[i], "DBUS_COOKIE_SHA1")) {
                        mechs |= AUTH_SHA;
                    } else if (0 == col.compare(ss[i], "ANONYMOUS")) {
                        mechs |= AUTH_ANON;
                    }
                }
            } else if (0 == col.compare(ss[0], "BEGIN")) {
                command = BEGIN;
            } else if (0 == col.compare(ss[0], "CANCEL")) {
                command = CANCEL;
            } else if (0 == col.compare(ss[0], "ERROR")) {
                command = ERROR;
                data = ss[1];
            } else if (0 == col.compare(ss[0], "NEGOTIATE_UNIX_FD")) {
                command = NEGOTIATE_UNIX_FD;
            } else if (0 == col.compare(ss[0], "AGREE_UNIX_FD")) {
                command = AGREE_UNIX_FD;
            } else {
                throw new IOException("Invalid Command " + ss[0]);
            }
            logger.trace("Created command: {}", this);
        }

        public SaslCommand getCommand() {
            return command;
        }

        public int getMechs() {
            return mechs;
        }

        public String getData() {
            return data;
        }

        public String getResponse() {
            return response;
        }

        public void setResponse(String s) {
            response = s;
        }

        @Override
        public String toString() {
            return "Command(" + command + ", " + mechs + ", " + data + ")";
        }
    }

    public boolean isFileDescriptorSupported() {
        return fileDescriptorSupported;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy