CredentialUnix.java

/**
 * Copyright 2016-2018 Dell Inc. or its subsidiaries. All rights reserved.
 *
 * <p>Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file
 * except in compliance with the License. A copy of the License is located at
 *
 * <p>http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 * <p>or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
package com.emc.ecs.nfsclient.rpc;

import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/** implement AUTH_UNIX for RPC, as specified by RFC 1831 (https://tools.ietf.org/html/rfc1831). */
public class CredentialUnix extends CredentialBase {

  private static final Logger LOG = LoggerFactory.getLogger(CredentialUnix.class);

  /**
   * Discriminant for a caller identifying itself as it is identified on a UNIX(tm) system.
   * Specified by RFC 1831 (https://tools.ietf.org/html/rfc1831).
   */
  private static final int AUTH_UNIX = 1;

  /** The caller's effective user ID. */
  private final int _uid;

  /** The caller's effective group ID. */
  private final int _gid;

  /** A counted array of groups which contain the caller as a member. */
  private final int[] _gids;

  /** The machine name. */
  private final String _host;

  /** The number of bytes needed for the Xdr buffer. */
  private final int _maximumXdrBytes;

  /**
   * Create the Credential.
   *
   * @param uid The caller's effective user ID.
   * @param gid The caller's effective group ID.
   * @param gids The set of groups which contain the caller as a member.
   */
  public CredentialUnix(int uid, int gid, Set<Integer> gids) {
    _uid = uid;
    _gid = gid;
    if (gids == null) {
      gids = new HashSet<Integer>(0);
    }
    _gids = new int[gids.size()];
    int index = 0;
    for (Integer id : gids) {
      _gids[index] = id.intValue();
      ++index;
    }
    _host = getHostname();
    _maximumXdrBytes = 24 + (4 * _gids.length) + _host.getBytes(RpcRequest.CHARSET).length;
  }

  /** Default constructor, with uid = 0 and gid = 0. */
  public CredentialUnix() {
    this(0, 0, null);
  }

  /** {@inheritDoc} */
  @Override
  protected int getCredentialFlavor() {
    return AUTH_UNIX;
  }

  /** {@inheritDoc} */
  @Override
  protected Xdr getCredential() {
    Xdr credentials = new Xdr(_maximumXdrBytes);
    credentials.setOffset(0);
    credentials.putInt((int) (System.currentTimeMillis() / 1000));
    credentials.putString(_host);
    credentials.putInt(_uid);
    credentials.putInt(_gid);
    if (_gids == null) {
      credentials.putInt(0);
    } else {
      credentials.putInt(_gids.length);
      for (int i = 0; i < _gids.length; i++) credentials.putInt(_gids[i]);
    }
    return credentials;
  }

  /**
   * @return The hostname, or "localhost" if it cannot be determined.
   */
  private static String getHostname() {
    try {
      return java.net.InetAddress.getLocalHost().getHostName();
    } catch (UnknownHostException e) {
      LOG.debug("Cannot determine local hostname for AUTH_SYS; using localhost", e);
    }

    // the hostname does not affect the correctness of RPC call, so
    // just return "localhost" if cannot get the host name
    return "localhost";
  }
}