| import java.nio.ByteBuffer; |
| import java.util.*; |
| import jcifs.smb.*; |
| import java.io.*; |
| |
| public class Acl { |
| public static final String NAME = "system.cifs_acl"; |
| public static final int BUFFER_SIZE = 1024; |
| |
| public static final int UINT_MAX = 0xFFFF; |
| /** number of authority fields */ |
| public static final int NUM_AUTHS = 6; |
| public static final int SIZEOF_CIFS_CTRL_ACL = 8; |
| |
| private SidLookup lookup; |
| |
| private String owner; |
| private String group; |
| |
| private int revision; |
| private int osidoffset; |
| private int gsidoffset; |
| private int dacloffset; |
| private List<Ace> aces; |
| |
| static { |
| System.loadLibrary("acl"); |
| } |
| |
| public Acl(String path, SidLookup lookup) throws IOException, SmbException { |
| this.lookup = lookup; |
| ByteBuffer buffer = readRaw(path); |
| |
| revision = extractInt(2, 2, buffer); |
| osidoffset = extractInt(4, 4, buffer); |
| gsidoffset = extractInt(8, 4, buffer); |
| dacloffset = extractInt(16, 4, buffer); |
| |
| owner = lookup.resolve(extractSid(osidoffset, buffer)); |
| group = lookup.resolve(extractSid(gsidoffset, buffer)); |
| |
| aces = new LinkedList<>(); |
| extractAces(dacloffset, buffer); |
| } |
| |
| private native int getxattr(String path, String attributeName, ByteBuffer buffer); |
| |
| public String getOwner() { |
| return owner; |
| } |
| |
| public String getGroup() { |
| return group; |
| } |
| |
| // TODO: immutability |
| public List<Ace> getAces() { |
| return aces; |
| } |
| |
| public String toString() { |
| StringBuilder sb = new StringBuilder(); |
| sb.append("OWNER: ").append(owner).append("\n"); |
| sb.append("GROUP: ").append(group).append("\n"); |
| sb.append("ACES:\n"); |
| for (Ace ace : aces) { |
| sb.append("\t").append(ace.toString()).append("\n"); |
| } |
| return sb.toString(); |
| } |
| |
| private ByteBuffer readRaw(String path) { |
| ByteBuffer buffer = ByteBuffer.allocateDirect(BUFFER_SIZE); |
| getxattr(path, NAME, buffer); |
| return buffer; |
| } |
| |
| private int extractInt(int offset, int bytes, ByteBuffer buffer) { |
| int value = 0; |
| |
| for (int i = (offset + bytes - 1); i >= offset; i--) { |
| value |= (buffer.get(i) & 0xff) << ((i - offset) * 8); |
| } |
| |
| return value; |
| } |
| |
| private long extractLong(int offset, int bytes, ByteBuffer buffer) { |
| long value = buffer.get(offset + bytes - 1) & 0xff; |
| value <<= 8 * (bytes - 1); |
| |
| for (int i = (offset + bytes - 2); i >= offset; i--) { |
| value |= (buffer.get(i) & 0xff) << ((i - offset) * 8); |
| } |
| |
| return value; |
| } |
| |
| private String extractSid(int offset, ByteBuffer buffer) { |
| StringBuilder sb = new StringBuilder("S-"); |
| |
| // revision, bytes: offset |
| int revision = extractInt(offset, 1, buffer); |
| sb.append(revision); |
| // number of subauthorities, bytes: offset+1 |
| int subauth_num = extractInt(offset+1, 1, buffer); |
| // authorities, bytes: offset+1+1:offset+1+NUM_AUTHS |
| long id_auth_val = buffer.get(offset + 1 + 6) & 0xff; |
| id_auth_val += (buffer.get(offset + 1 + 5) & 0xff) << 8; |
| id_auth_val += (buffer.get(offset + 1 + 4) & 0xff) << 16; |
| id_auth_val += (buffer.get(offset + 1 + 3) & 0xff) << 24; |
| id_auth_val += (buffer.get(offset + 1 + 2) & 0xff) << 32; |
| id_auth_val += (buffer.get(offset + 1 + 1) & 0xff) << 48; |
| |
| if (id_auth_val <= UINT_MAX) { |
| sb.append("-" + id_auth_val); |
| } else { |
| sb.append("-0x" + Long.toHexString(id_auth_val)); |
| } |
| // actual subauthorities, bytes: offset+2+NUM_AUTHS+1:subauth_num |
| long val = 0; |
| int subauth_array_offset = offset + 1 + NUM_AUTHS + 1; |
| for (int i = 0; i < subauth_num; i++) { |
| val = extractLong(subauth_array_offset, 4, buffer); |
| sb.append("-" + val); |
| subauth_array_offset += 4; |
| } |
| return sb.toString(); |
| } |
| |
| private void extractAces(int offset, ByteBuffer buffer) throws IOException, SmbException { |
| int acl_size = extractInt(offset + 2, 2, buffer); |
| long ace_num = extractLong(offset + 4, 4, buffer); |
| int ace_offset = offset + SIZEOF_CIFS_CTRL_ACL; |
| |
| int ace_size = SIZEOF_CIFS_CTRL_ACL; |
| if (ace_num > 0) { |
| for (int i = 0; i < ace_num; i++) { |
| int type = buffer.get(ace_offset); |
| int flags = buffer.get(ace_offset + 1); |
| ace_size = extractInt(ace_offset + 2, 2, buffer); |
| aces.add(new Ace(flags, type, lookup.resolve(extractSid(ace_offset + 8, buffer)))); |
| ace_offset += ace_size; |
| } |
| } |
| } |
| |
| public static void main(String[] args) throws Exception { |
| SidLookup lookup = new SidLookup("172.25.51.36", "gsa-connectors", "Administrator", "p@assword123"); |
| Acl acl = new Acl("/mnt/10M-Windows/PDF/site11/0/11005.pdf", lookup); |
| System.out.println(acl); |
| } |
| } |