You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2015/12/01 10:26:58 UTC
mina-sshd git commit: [SSHD-602] Add support for 'acl-supported'
extension
Repository: mina-sshd
Updated Branches:
refs/heads/master 9044f1b04 -> c11b57ad6
[SSHD-602] Add support for 'acl-supported' extension
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/c11b57ad
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/c11b57ad
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/c11b57ad
Branch: refs/heads/master
Commit: c11b57ad665db7910156f31738cce638f35cbb1c
Parents: 9044f1b
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Tue Dec 1 11:26:04 2015 +0200
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Tue Dec 1 11:26:04 2015 +0200
----------------------------------------------------------------------
.../client/subsystem/sftp/SftpFileChannel.java | 5 +-
.../org/apache/sshd/common/mac/BaseMac.java | 2 +-
.../common/subsystem/sftp/SftpConstants.java | 13 +-
.../sftp/extensions/AclSupportedParser.java | 210 +++++++++++++++++++
.../subsystem/sftp/extensions/ParserUtils.java | 1 +
.../apache/sshd/common/util/GenericUtils.java | 18 ++
.../sshd/server/subsystem/sftp/FileHandle.java | 35 ++--
.../server/subsystem/sftp/SftpSubsystem.java | 88 +++++++-
.../org/apache/sshd/PortForwardingLoadTest.java | 14 +-
.../org/apache/sshd/PortForwardingTest.java | 18 +-
.../java/org/apache/sshd/agent/AgentTest.java | 5 +-
.../sshd/client/subsystem/sftp/SftpTest.java | 19 +-
.../openssh/impl/OpenSSHExtensionsTest.java | 9 +-
.../deprecated/UserAuthKeyboardInteractive.java | 19 +-
14 files changed, 382 insertions(+), 74 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/c11b57ad/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileChannel.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileChannel.java b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileChannel.java
index b656582..7220623 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileChannel.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpFileChannel.java
@@ -40,12 +40,11 @@ import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.sshd.common.PropertyResolverUtils;
+import org.apache.sshd.common.subsystem.sftp.SftpConstants;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.io.IoUtils;
-import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FX_LOCK_CONFLICT;
-
public class SftpFileChannel extends FileChannel {
public static final String COPY_BUFSIZE_PROP = "sftp-channel-copy-buf-size";
public static final int DEFAULT_TRANSFER_BUFFER_SIZE = IoUtils.DEFAULT_COPY_SIZE;
@@ -322,7 +321,7 @@ public class SftpFileChannel extends FileChannel {
try {
sftp.lock(handle, position, size, 0);
} catch (SftpException e) {
- if (e.getStatus() == SSH_FX_LOCK_CONFLICT) {
+ if (e.getStatus() == SftpConstants.SSH_FX_LOCK_CONFLICT) {
throw new OverlappingFileLockException();
}
throw e;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/c11b57ad/sshd-core/src/main/java/org/apache/sshd/common/mac/BaseMac.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/mac/BaseMac.java b/sshd-core/src/main/java/org/apache/sshd/common/mac/BaseMac.java
index 76e09e8..5c9fc82 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/mac/BaseMac.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/mac/BaseMac.java
@@ -108,7 +108,7 @@ public class BaseMac implements Mac {
@Override
public String toString() {
return getClass().getSimpleName() + "[" + getAlgorithm() + "] - "
- + getBlockSize() + "/" + getDefaultBlockSize() + " bits";
+ + " block=" + getBlockSize() + "/" + getDefaultBlockSize() + " bytes";
}
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/c11b57ad/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpConstants.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpConstants.java b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpConstants.java
index ff7a081..21a7486 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpConstants.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/SftpConstants.java
@@ -20,7 +20,6 @@ package org.apache.sshd.common.subsystem.sftp;
import java.lang.reflect.Field;
import java.util.Map;
-
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.Predicate;
import org.apache.sshd.common.util.logging.LoggingUtils;
@@ -243,16 +242,28 @@ public final class SftpConstants {
public static final String EXT_TEXT_SEEK = "text-seek";
public static final String EXT_VERSION_SELECT = "version-select";
public static final String EXT_COPY_FILE = "copy-file";
+
public static final String EXT_MD5_HASH = "md5-hash";
public static final String EXT_MD5_HASH_HANDLE = "md5-hash-handle";
public static final int MD5_QUICK_HASH_SIZE = 2048;
+
public static final String EXT_CHECK_FILE_HANDLE = "check-file-handle";
public static final String EXT_CHECK_FILE_NAME = "check-file-name";
public static final int MIN_CHKFILE_BLOCKSIZE = 256;
+
public static final String EXT_CHECK_FILE = "check-file";
public static final String EXT_COPY_DATA = "copy-data";
public static final String EXT_SPACE_AVAILABLE = "space-available";
+ // see https://tools.ietf.org/html/draft-ietf-secsh-filexfer-11 section 5.4
+ public static final String EXT_ACL_SUPPORTED = "acl-supported";
+ public static final int SSH_ACL_CAP_ALLOW = 0x00000001;
+ public static final int SSH_ACL_CAP_DENY = 0x00000002;
+ public static final int SSH_ACL_CAP_AUDIT = 0x00000004;
+ public static final int SSH_ACL_CAP_ALARM = 0x00000008;
+ public static final int SSH_ACL_CAP_INHERIT_ACCESS = 0x00000010;
+ public static final int SSH_ACL_CAP_INHERIT_AUDIT_ALARM = 0x00000020;
+
private SftpConstants() {
throw new UnsupportedOperationException("No instance");
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/c11b57ad/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/AclSupportedParser.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/AclSupportedParser.java b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/AclSupportedParser.java
new file mode 100644
index 0000000..3859892
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/AclSupportedParser.java
@@ -0,0 +1,210 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License 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 org.apache.sshd.common.subsystem.sftp.extensions;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.sshd.common.subsystem.sftp.SftpConstants;
+import org.apache.sshd.common.subsystem.sftp.extensions.AclSupportedParser.AclCapabilities;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.logging.LoggingUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class AclSupportedParser extends AbstractParser<AclCapabilities> {
+ /**
+ * The "acl-supported" information as per
+ * <A HREF="https://tools.ietf.org/html/draft-ietf-secsh-filexfer-11">DRAFT 11 - section 5.4</A>
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+ public static class AclCapabilities implements Serializable, Cloneable {
+ private static final long serialVersionUID = -3118426327336468237L;
+ private int capabilities;
+
+ public AclCapabilities() {
+ this(0);
+ }
+
+ public AclCapabilities(int capabilities) {
+ this.capabilities = capabilities;
+ }
+
+ public int getCapabilities() {
+ return capabilities;
+ }
+
+ public void setCapabilities(int capabilities) {
+ this.capabilities = capabilities;
+ }
+
+ @Override
+ public int hashCode() {
+ return getCapabilities();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+
+ return ((AclCapabilities) obj).getCapabilities() == getCapabilities();
+ }
+
+ @Override
+ public AclCapabilities clone() {
+ try {
+ return getClass().cast(super.clone());
+ } catch (CloneNotSupportedException e) {
+ throw new RuntimeException("Failed to clone " + toString() + ": " + e.getMessage(), e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toString(decodeAclCapabilities(getCapabilities()));
+ }
+
+ private static class LazyAclCapabilityNameHolder {
+ private static final String ACL_CAP_NAME_PREFIX = "SSH_ACL_CAP_";
+ private static final Map<Integer, String> ACL_VALUES_MAP = LoggingUtils.generateMnemonicMap(SftpConstants.class, ACL_CAP_NAME_PREFIX);
+ private static final Map<String, Integer> ACL_NAMES_MAP =
+ Collections.unmodifiableMap(GenericUtils.flipMap(ACL_VALUES_MAP, GenericUtils.<Integer>caseInsensitiveMap(), false));
+ }
+
+ @SuppressWarnings("synthetic-access")
+ public static Map<String, Integer> getAclCapabilityNamesMap() {
+ return LazyAclCapabilityNameHolder.ACL_NAMES_MAP;
+ }
+
+ /**
+ * @param name The ACL capability name - may be without the "SSH_ACL_CAP_xxx" prefix.
+ * Ignored if {@code null}/empty
+ * @return The matching {@link Integer} value - or {@code null} if no match found
+ */
+ public static Integer getAclCapabilityValue(String name) {
+ if (GenericUtils.isEmpty(name)) {
+ return null;
+ }
+
+ name = name.toUpperCase();
+ if (!name.startsWith(LazyAclCapabilityNameHolder.ACL_CAP_NAME_PREFIX)) {
+ name += LazyAclCapabilityNameHolder.ACL_CAP_NAME_PREFIX;
+ }
+
+ Map<String, Integer> map = getAclCapabilityNamesMap();
+ return map.get(name);
+ }
+
+ @SuppressWarnings("synthetic-access")
+ public static Map<Integer, String> getAclCapabilityValuesMap() {
+ return LazyAclCapabilityNameHolder.ACL_VALUES_MAP;
+ }
+
+ public static String getAclCapabilityName(int aclCapValue) {
+ Map<Integer, String> map = getAclCapabilityValuesMap();
+ String name = map.get(aclCapValue);
+ if (GenericUtils.isEmpty(name)) {
+ return Integer.toString(aclCapValue);
+ } else {
+ return name;
+ }
+ }
+
+ public static Set<String> decodeAclCapabilities(int mask) {
+ if (mask == 0) {
+ return Collections.emptySet();
+ }
+
+ Set<String> caps = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
+ Map<Integer, String> map = getAclCapabilityValuesMap();
+ for (Map.Entry<Integer, String> ae : map.entrySet()) {
+ Integer value = ae.getKey();
+ String name = ae.getValue();
+ if ((mask & value.intValue()) != 0) {
+ caps.add(name);
+ }
+ }
+
+ return caps;
+ }
+
+ public static int constructAclCapabilities(Collection<Integer> maskValues) {
+ if (GenericUtils.isEmpty(maskValues)) {
+ return 0;
+ }
+
+ int mask = 0;
+ for (Integer v : maskValues) {
+ mask |= v.intValue();
+ }
+
+ return mask;
+ }
+
+ public static Set<Integer> deconstructAclCapabilities(int mask) {
+ if (mask == 0) {
+ return Collections.emptySet();
+ }
+
+ Map<Integer, String> map = getAclCapabilityValuesMap();
+ Set<Integer> caps = new HashSet<Integer>(map.size());
+ for (Integer v : map.keySet()) {
+ if ((mask & v.intValue()) != 0) {
+ caps.add(v);
+ }
+ }
+
+ return caps;
+ }
+ }
+
+ public static final AclSupportedParser INSTANCE = new AclSupportedParser();
+
+ public AclSupportedParser() {
+ super(SftpConstants.EXT_ACL_SUPPORTED);
+ }
+
+ @Override
+ public AclCapabilities parse(byte[] input, int offset, int len) {
+ return parse(new ByteArrayBuffer(input, offset, len));
+ }
+
+ public AclCapabilities parse(Buffer buffer) {
+ return new AclCapabilities(buffer.getInt());
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/c11b57ad/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/ParserUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/ParserUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/ParserUtils.java
index 7e16784..243d299 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/ParserUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/subsystem/sftp/extensions/ParserUtils.java
@@ -52,6 +52,7 @@ public final class ParserUtils {
VersionsParser.INSTANCE,
SupportedParser.INSTANCE,
Supported2Parser.INSTANCE,
+ AclSupportedParser.INSTANCE,
// OpenSSH extensions
PosixRenameExtensionParser.INSTANCE,
StatVfsExtensionParser.INSTANCE,
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/c11b57ad/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java
index 13fc270..ed5593e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java
@@ -330,6 +330,24 @@ public final class GenericUtils {
return CASE_INSENSITIVE_MAP_FACTORY;
}
+ public static <K, V> Map<V, K> flipMap(Map<? extends K, ? extends V> map, Factory<? extends Map<V, K>> mapCreator, boolean allowDuplicates) {
+ if (isEmpty(map)) {
+ return Collections.emptyMap();
+ }
+
+ Map<V, K> result = ValidateUtils.checkNotNull(mapCreator.create(), "No map created");
+ for (Map.Entry<? extends K, ? extends V> ee : map.entrySet()) {
+ K key = ee.getKey();
+ V value = ee.getValue();
+ K prev = result.put(value, key);
+ if ((prev != null) && (!allowDuplicates)) {
+ ValidateUtils.throwIllegalArgumentException("Multiple values for key=%s: current=%s, previous=%s", value, key, prev);
+ }
+ }
+
+ return result;
+ }
+
@SafeVarargs
public static <K, V> Map<K, V> mapValues(
Transformer<? super V, ? extends K> keyMapper, Factory<? extends Map<K, V>> mapCreator, V ... values) {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/c11b57ad/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/FileHandle.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/FileHandle.java b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/FileHandle.java
index bd54bdf..faed6a0 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/FileHandle.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/FileHandle.java
@@ -33,19 +33,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
-import static org.apache.sshd.common.subsystem.sftp.SftpConstants.ACE4_APPEND_DATA;
-import static org.apache.sshd.common.subsystem.sftp.SftpConstants.ACE4_READ_ATTRIBUTES;
-import static org.apache.sshd.common.subsystem.sftp.SftpConstants.ACE4_READ_DATA;
-import static org.apache.sshd.common.subsystem.sftp.SftpConstants.ACE4_WRITE_ATTRIBUTES;
-import static org.apache.sshd.common.subsystem.sftp.SftpConstants.ACE4_WRITE_DATA;
-
-import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FXF_ACCESS_DISPOSITION;
-import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FXF_APPEND_DATA;
-import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FXF_CREATE_NEW;
-import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FXF_CREATE_TRUNCATE;
-import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FXF_OPEN_EXISTING;
-import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FXF_OPEN_OR_CREATE;
-import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FXF_TRUNCATE_EXISTING;
+import org.apache.sshd.common.subsystem.sftp.SftpConstants;
+
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
@@ -62,31 +51,31 @@ public class FileHandle extends Handle {
this.access = access;
Set<OpenOption> options = new HashSet<>();
- if (((access & ACE4_READ_DATA) != 0) || ((access & ACE4_READ_ATTRIBUTES) != 0)) {
+ if (((access & SftpConstants.ACE4_READ_DATA) != 0) || ((access & SftpConstants.ACE4_READ_ATTRIBUTES) != 0)) {
options.add(StandardOpenOption.READ);
}
- if (((access & ACE4_WRITE_DATA) != 0) || ((access & ACE4_WRITE_ATTRIBUTES) != 0)) {
+ if (((access & SftpConstants.ACE4_WRITE_DATA) != 0) || ((access & SftpConstants.ACE4_WRITE_ATTRIBUTES) != 0)) {
options.add(StandardOpenOption.WRITE);
}
- switch (flags & SSH_FXF_ACCESS_DISPOSITION) {
- case SSH_FXF_CREATE_NEW:
+ switch (flags & SftpConstants.SSH_FXF_ACCESS_DISPOSITION) {
+ case SftpConstants.SSH_FXF_CREATE_NEW:
options.add(StandardOpenOption.CREATE_NEW);
break;
- case SSH_FXF_CREATE_TRUNCATE:
+ case SftpConstants.SSH_FXF_CREATE_TRUNCATE:
options.add(StandardOpenOption.CREATE);
options.add(StandardOpenOption.TRUNCATE_EXISTING);
break;
- case SSH_FXF_OPEN_EXISTING:
+ case SftpConstants.SSH_FXF_OPEN_EXISTING:
break;
- case SSH_FXF_OPEN_OR_CREATE:
+ case SftpConstants.SSH_FXF_OPEN_OR_CREATE:
options.add(StandardOpenOption.CREATE);
break;
- case SSH_FXF_TRUNCATE_EXISTING:
+ case SftpConstants.SSH_FXF_TRUNCATE_EXISTING:
options.add(StandardOpenOption.TRUNCATE_EXISTING);
break;
default: // ignored
}
- if ((flags & SSH_FXF_APPEND_DATA) != 0) {
+ if ((flags & SftpConstants.SSH_FXF_APPEND_DATA) != 0) {
options.add(StandardOpenOption.APPEND);
}
FileAttribute<?>[] attributes = new FileAttribute<?>[attrs.size()];
@@ -126,7 +115,7 @@ public class FileHandle extends Handle {
}
public boolean isOpenAppend() {
- return ACE4_APPEND_DATA == (getAccessMask() & ACE4_APPEND_DATA);
+ return SftpConstants.ACE4_APPEND_DATA == (getAccessMask() & SftpConstants.ACE4_APPEND_DATA);
}
public int read(byte[] data, long offset) throws IOException {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/c11b57ad/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
index fca8f5c..8449f5c 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
@@ -59,6 +59,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
@@ -86,6 +87,7 @@ import org.apache.sshd.common.file.FileSystemAware;
import org.apache.sshd.common.random.Random;
import org.apache.sshd.common.subsystem.sftp.SftpConstants;
import org.apache.sshd.common.subsystem.sftp.SftpHelper;
+import org.apache.sshd.common.subsystem.sftp.extensions.AclSupportedParser;
import org.apache.sshd.common.subsystem.sftp.extensions.SpaceAvailableExtensionInfo;
import org.apache.sshd.common.subsystem.sftp.extensions.openssh.AbstractOpenSSHExtensionParser.OpenSSHExtension;
import org.apache.sshd.common.subsystem.sftp.extensions.openssh.FsyncExtensionParser;
@@ -228,6 +230,19 @@ public class SftpSubsystem
public static final List<String> DEFAULT_UNIX_VIEW = Collections.singletonList("unix:*");
/**
+ * Comma separate list of {@code SSH_ACL_CAP_xxx} names - where name can be without
+ * the prefix. If not defined then {@link #DEFAULT_ACL_SUPPORTED_MASK} is used
+ */
+ public static final String ACL_SUPPORTED_MASK_PROP = "sftp-acl-supported-mask";
+ public static final Set<Integer> DEFAULT_ACL_SUPPORTED_MASK =
+ Collections.unmodifiableSet(
+ new HashSet<Integer>(Arrays.asList(
+ SftpConstants.SSH_ACL_CAP_ALLOW,
+ SftpConstants.SSH_ACL_CAP_DENY,
+ SftpConstants.SSH_ACL_CAP_AUDIT,
+ SftpConstants.SSH_ACL_CAP_ALARM)));
+
+ /**
* A {@link Map} of {@link FileInfoExtractor}s to be used to complete
* attributes that are deemed important enough to warrant an extra
* effort if not accessible via the file system attributes views
@@ -2198,13 +2213,7 @@ public class SftpSubsystem
appendNewlineExtension(buffer, IoUtils.EOL);
appendVendorIdExtension(buffer, VersionProperties.getVersionProperties());
appendOpenSSHExtensions(buffer);
-
- /* TODO updateAvailableExtensions(extensions, appendAclSupportedExtension(...)
- buffer.putString("acl-supported");
- buffer.putInt(4);
- // capabilities
- buffer.putInt(0);
- */
+ appendAclSupportedExtension(buffer);
Map<String, OptionalFeature> extensions = getSupportedClientExtensions();
int numExtensions = GenericUtils.size(extensions);
@@ -2227,8 +2236,56 @@ public class SftpSubsystem
appendSupported2Extension(buffer, extras);
}
+ protected int appendAclSupportedExtension(Buffer buffer) {
+ ServerSession session = getServerSession();
+ Collection<Integer> maskValues = resolveAclSupportedCapabilities(session);
+ int mask = AclSupportedParser.AclCapabilities.constructAclCapabilities(maskValues);
+ if (mask != 0) {
+ if (log.isTraceEnabled()) {
+ log.trace("appendAclSupportedExtension({}) capabilities={}",
+ session, AclSupportedParser.AclCapabilities.decodeAclCapabilities(mask));
+ }
+
+ buffer.putString(SftpConstants.EXT_ACL_SUPPORTED);
+
+ // placeholder for length
+ int lenPos = buffer.wpos();
+ buffer.putInt(0);
+ buffer.putInt(mask);
+ BufferUtils.updateLengthPlaceholder(buffer, lenPos);
+ }
+
+ return mask;
+ }
+
+ protected Collection<Integer> resolveAclSupportedCapabilities(ServerSession session) {
+ String override = PropertyResolverUtils.getString(session, ACL_SUPPORTED_MASK_PROP);
+ if (override == null) {
+ return DEFAULT_ACL_SUPPORTED_MASK;
+ }
+
+ // empty means not supported
+ if (log.isDebugEnabled()) {
+ log.debug("resolveAclSupportedCapabilities({}) override='{}'", session, override);
+ }
+
+ if (override.length() == 0) {
+ return Collections.emptySet();
+ }
+
+ String[] names = GenericUtils.split(override, ',');
+ Set<Integer> maskValues = new HashSet<Integer>(names.length);
+ for (String n : names) {
+ Integer v = ValidateUtils.checkNotNull(
+ AclSupportedParser.AclCapabilities.getAclCapabilityValue(n), "Unknown ACL capability: %s", n);
+ maskValues.add(v);
+ }
+
+ return maskValues;
+ }
+
protected List<OpenSSHExtension> appendOpenSSHExtensions(Buffer buffer) {
- List<OpenSSHExtension> extList = resolveOpenSSHExtensions();
+ List<OpenSSHExtension> extList = resolveOpenSSHExtensions(getServerSession());
if (GenericUtils.isEmpty(extList)) {
return extList;
}
@@ -2241,12 +2298,16 @@ public class SftpSubsystem
return extList;
}
- protected List<OpenSSHExtension> resolveOpenSSHExtensions() {
- String value = PropertyResolverUtils.getString(getServerSession(), OPENSSH_EXTENSIONS_PROP);
+ protected List<OpenSSHExtension> resolveOpenSSHExtensions(ServerSession session) {
+ String value = PropertyResolverUtils.getString(session, OPENSSH_EXTENSIONS_PROP);
if (value == null) { // No override
return DEFAULT_OPEN_SSH_EXTENSIONS;
}
+ if (log.isDebugEnabled()) {
+ log.debug("resolveOpenSSHExtensions({}) override='{}'", session, value);
+ }
+
String[] pairs = GenericUtils.split(value, ',');
int numExts = GenericUtils.length(pairs);
if (numExts <= 0) { // User does not want to report ANY extensions
@@ -2271,11 +2332,16 @@ public class SftpSubsystem
}
protected Map<String, OptionalFeature> getSupportedClientExtensions() {
- String value = PropertyResolverUtils.getString(getServerSession(), CLIENT_EXTENSIONS_PROP);
+ ServerSession session = getServerSession();
+ String value = PropertyResolverUtils.getString(session, CLIENT_EXTENSIONS_PROP);
if (value == null) {
return DEFAULT_SUPPORTED_CLIENT_EXTENSIONS;
}
+ if (log.isDebugEnabled()) {
+ log.debug("getSupportedClientExtensions({}) override='{}'", session, value);
+ }
+
if (value.length() <= 0) { // means don't report any extensions
return Collections.emptyMap();
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/c11b57ad/sshd-core/src/test/java/org/apache/sshd/PortForwardingLoadTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/PortForwardingLoadTest.java b/sshd-core/src/test/java/org/apache/sshd/PortForwardingLoadTest.java
index 8939797..d5720a9 100644
--- a/sshd-core/src/test/java/org/apache/sshd/PortForwardingLoadTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/PortForwardingLoadTest.java
@@ -18,8 +18,6 @@
*/
package org.apache.sshd;
-import static org.apache.sshd.util.test.Utils.getFreePort;
-
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -37,9 +35,6 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
-import com.jcraft.jsch.JSch;
-import com.jcraft.jsch.JSchException;
-import com.jcraft.jsch.Session;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpVersion;
@@ -55,6 +50,7 @@ import org.apache.sshd.server.forward.AcceptAllForwardingFilter;
import org.apache.sshd.util.test.BaseTestSupport;
import org.apache.sshd.util.test.JSchLogger;
import org.apache.sshd.util.test.SimpleUserInfo;
+import org.apache.sshd.util.test.Utils;
import org.junit.After;
import org.junit.Before;
import org.junit.FixMethodOrder;
@@ -63,6 +59,10 @@ import org.junit.runners.MethodSorters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.jcraft.jsch.JSch;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+
/**
* Port forwarding tests
*/
@@ -223,7 +223,7 @@ public class PortForwardingLoadTest extends BaseTestSupport {
ss.setReuseAddress(true);
ss.bind(new InetSocketAddress((InetAddress) null, 0));
int forwardedPort = ss.getLocalPort();
- int sinkPort = getFreePort();
+ int sinkPort = Utils.getFreePort();
session.setPortForwardingR(sinkPort, TEST_LOCALHOST, forwardedPort);
final boolean started[] = new boolean[1];
started[0] = false;
@@ -344,7 +344,7 @@ public class PortForwardingLoadTest extends BaseTestSupport {
Session session = createSession();
try {
final int forwardedPort1 = session.setPortForwardingL(0, host, port);
- final int forwardedPort2 = getFreePort();
+ final int forwardedPort2 = Utils.getFreePort();
session.setPortForwardingR(forwardedPort2, TEST_LOCALHOST, forwardedPort1);
System.err.println("URL: http://localhost:" + forwardedPort2);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/c11b57ad/sshd-core/src/test/java/org/apache/sshd/PortForwardingTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/PortForwardingTest.java b/sshd-core/src/test/java/org/apache/sshd/PortForwardingTest.java
index 6380390..490f884 100644
--- a/sshd-core/src/test/java/org/apache/sshd/PortForwardingTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/PortForwardingTest.java
@@ -18,8 +18,6 @@
*/
package org.apache.sshd;
-import static org.apache.sshd.util.test.Utils.getFreePort;
-
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
@@ -38,9 +36,6 @@ import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
-import com.jcraft.jsch.JSch;
-import com.jcraft.jsch.JSchException;
-import com.jcraft.jsch.Session;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.service.IoHandlerAdapter;
@@ -64,6 +59,7 @@ import org.apache.sshd.server.global.TcpipForwardHandler;
import org.apache.sshd.util.test.BaseTestSupport;
import org.apache.sshd.util.test.JSchLogger;
import org.apache.sshd.util.test.SimpleUserInfo;
+import org.apache.sshd.util.test.Utils;
import org.junit.After;
import org.junit.Before;
import org.junit.FixMethodOrder;
@@ -71,6 +67,10 @@ import org.junit.Test;
import org.junit.runners.MethodSorters;
import org.slf4j.LoggerFactory;
+import com.jcraft.jsch.JSch;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+
/**
* Port forwarding tests
*/
@@ -196,7 +196,7 @@ public class PortForwardingTest extends BaseTestSupport {
public void testRemoteForwarding() throws Exception {
Session session = createSession();
try {
- int forwardedPort = getFreePort();
+ int forwardedPort = Utils.getFreePort();
session.setPortForwardingR(forwardedPort, TEST_LOCALHOST, echoPort);
waitForForwardingRequest(TcpipForwardHandler.REQUEST, TimeUnit.SECONDS.toMillis(5L));
@@ -227,7 +227,7 @@ public class PortForwardingTest extends BaseTestSupport {
public void testRemoteForwardingSecondTimeInSameSession() throws Exception {
Session session = createSession();
try {
- int forwardedPort = getFreePort();
+ int forwardedPort = Utils.getFreePort();
session.setPortForwardingR(forwardedPort, TEST_LOCALHOST, echoPort);
waitForForwardingRequest(TcpipForwardHandler.REQUEST, TimeUnit.SECONDS.toMillis(5L));
@@ -323,7 +323,7 @@ public class PortForwardingTest extends BaseTestSupport {
public void testLocalForwarding() throws Exception {
Session session = createSession();
try {
- int forwardedPort = getFreePort();
+ int forwardedPort = Utils.getFreePort();
session.setPortForwardingL(forwardedPort, TEST_LOCALHOST, echoPort);
try (Socket s = new Socket(TEST_LOCALHOST, forwardedPort);
@@ -455,7 +455,7 @@ public class PortForwardingTest extends BaseTestSupport {
Session session = createSession();
try {
// 1. Create a Port Forward
- int forwardedPort = getFreePort();
+ int forwardedPort = Utils.getFreePort();
session.setPortForwardingR(forwardedPort, TEST_LOCALHOST, echoPort);
waitForForwardingRequest(TcpipForwardHandler.REQUEST, TimeUnit.SECONDS.toMillis(5L));
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/c11b57ad/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java b/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java
index e0f8d79..fbdc82b 100644
--- a/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/agent/AgentTest.java
@@ -18,8 +18,6 @@
*/
package org.apache.sshd.agent;
-import static org.apache.sshd.util.test.Utils.createTestKeyPairProvider;
-
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@@ -46,6 +44,7 @@ import org.apache.sshd.server.forward.AcceptAllForwardingFilter;
import org.apache.sshd.util.test.BaseTestSupport;
import org.apache.sshd.util.test.EchoShell;
import org.apache.sshd.util.test.EchoShellFactory;
+import org.apache.sshd.util.test.Utils;
import org.junit.Assume;
import org.junit.FixMethodOrder;
import org.junit.Test;
@@ -102,7 +101,7 @@ public class AgentTest extends BaseTestSupport {
ProxyAgentFactory agentFactory = new ProxyAgentFactory();
LocalAgentFactory localAgentFactory = new LocalAgentFactory();
String username = getCurrentTestName();
- KeyPair pair = createTestKeyPairProvider("dsaprivkey.pem").loadKey(KeyPairProvider.SSH_DSS);
+ KeyPair pair = Utils.createTestKeyPairProvider("dsaprivkey.pem").loadKey(KeyPairProvider.SSH_DSS);
localAgentFactory.getAgent().addIdentity(pair, username);
try (SshServer sshd1 = setupTestServer()) {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/c11b57ad/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
index a5a096d..9274c5b 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
@@ -39,6 +39,7 @@ import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.TreeSet;
import java.util.Vector;
import java.util.concurrent.TimeUnit;
@@ -61,6 +62,7 @@ import org.apache.sshd.common.file.FileSystemFactory;
import org.apache.sshd.common.random.Random;
import org.apache.sshd.common.session.Session;
import org.apache.sshd.common.subsystem.sftp.SftpConstants;
+import org.apache.sshd.common.subsystem.sftp.extensions.AclSupportedParser.AclCapabilities;
import org.apache.sshd.common.subsystem.sftp.extensions.ParserUtils;
import org.apache.sshd.common.subsystem.sftp.extensions.Supported2Parser.Supported2;
import org.apache.sshd.common.subsystem.sftp.extensions.SupportedParser.Supported;
@@ -931,7 +933,7 @@ public class SftpTest extends AbstractSftpClientTestSupport {
Map<String, byte[]> extensions = sftp.getServerExtensions();
for (String name : new String[]{
SftpConstants.EXT_NEWLINE, SftpConstants.EXT_VERSIONS,
- SftpConstants.EXT_VENDOR_ID,
+ SftpConstants.EXT_VENDOR_ID, SftpConstants.EXT_ACL_SUPPORTED,
SftpConstants.EXT_SUPPORTED, SftpConstants.EXT_SUPPORTED2
}) {
assertTrue("Missing extension=" + name, extensions.containsKey(name));
@@ -946,6 +948,14 @@ public class SftpTest extends AbstractSftpClientTestSupport {
assertSupportedExtensions(extName, ((Supported) extValue).extensionNames);
} else if (SftpConstants.EXT_SUPPORTED2.equalsIgnoreCase(extName)) {
assertSupportedExtensions(extName, ((Supported2) extValue).extensionNames);
+ } else if (SftpConstants.EXT_ACL_SUPPORTED.equalsIgnoreCase(extName)) {
+ assertSupportedAclCapabilities((AclCapabilities) extValue);
+ }
+ }
+
+ for (String extName : extensions.keySet()) {
+ if (!data.containsKey(extName)) {
+ outputDebugMessage("No parser for extension=%s", extName);
}
}
@@ -998,6 +1008,13 @@ public class SftpTest extends AbstractSftpClientTestSupport {
}
}
+ private static void assertSupportedAclCapabilities(AclCapabilities caps) {
+ Set<Integer> actual = AclCapabilities.deconstructAclCapabilities(caps.getCapabilities());
+ assertEquals("Mismatched ACL capabilities count", SftpSubsystem.DEFAULT_ACL_SUPPORTED_MASK.size(), actual.size());
+ assertTrue("Missing capabilities - expected=" + SftpSubsystem.DEFAULT_ACL_SUPPORTED_MASK + ", actual=" + actual,
+ actual.containsAll(SftpSubsystem.DEFAULT_ACL_SUPPORTED_MASK));
+ }
+
@Test
public void testSftpVersionSelector() throws Exception {
final AtomicInteger selected = new AtomicInteger(-1);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/c11b57ad/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/OpenSSHExtensionsTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/OpenSSHExtensionsTest.java b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/OpenSSHExtensionsTest.java
index 18b5ec3..10c5b5b 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/OpenSSHExtensionsTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/extensions/openssh/impl/OpenSSHExtensionsTest.java
@@ -50,6 +50,7 @@ import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.io.IoUtils;
import org.apache.sshd.server.Command;
+import org.apache.sshd.server.session.ServerSession;
import org.apache.sshd.server.subsystem.sftp.SftpSubsystem;
import org.apache.sshd.server.subsystem.sftp.SftpSubsystemFactory;
import org.apache.sshd.util.test.Utils;
@@ -59,8 +60,6 @@ import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
-import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FXP_EXTENDED_REPLY;
-
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
@@ -141,8 +140,8 @@ public class OpenSSHExtensionsTest extends AbstractSftpClientTestSupport {
public Command create() {
return new SftpSubsystem(getExecutorService(), isShutdownOnExit(), getUnsupportedAttributePolicy()) {
@Override
- protected List<OpenSSHExtension> resolveOpenSSHExtensions() {
- List<OpenSSHExtension> original = super.resolveOpenSSHExtensions();
+ protected List<OpenSSHExtension> resolveOpenSSHExtensions(ServerSession session) {
+ List<OpenSSHExtension> original = super.resolveOpenSSHExtensions(session);
int numOriginal = GenericUtils.size(original);
List<OpenSSHExtension> result = new ArrayList<OpenSSHExtension>(numOriginal + 2);
if (numOriginal > 0) {
@@ -166,7 +165,7 @@ public class OpenSSHExtensionsTest extends AbstractSftpClientTestSupport {
}
buffer.clear();
- buffer.putByte((byte) SSH_FXP_EXTENDED_REPLY);
+ buffer.putByte((byte) SftpConstants.SSH_FXP_EXTENDED_REPLY);
buffer.putInt(id);
OpenSSHStatExtensionInfo.encode(buffer, expected);
send(buffer);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/c11b57ad/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthKeyboardInteractive.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthKeyboardInteractive.java b/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthKeyboardInteractive.java
index 0732e06..9201607 100644
--- a/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthKeyboardInteractive.java
+++ b/sshd-core/src/test/java/org/apache/sshd/deprecated/UserAuthKeyboardInteractive.java
@@ -25,10 +25,6 @@ import org.apache.sshd.client.auth.UserInteraction;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.SshConstants;
import org.apache.sshd.common.util.buffer.Buffer;
-import static org.apache.sshd.common.SshConstants.SSH_MSG_USERAUTH_FAILURE;
-import static org.apache.sshd.common.SshConstants.SSH_MSG_USERAUTH_INFO_REQUEST;
-import static org.apache.sshd.common.SshConstants.SSH_MSG_USERAUTH_INFO_RESPONSE;
-import static org.apache.sshd.common.SshConstants.SSH_MSG_USERAUTH_SUCCESS;
/**
* Userauth with keyboard-interactive method.
@@ -62,12 +58,14 @@ public class UserAuthKeyboardInteractive extends AbstractUserAuth {
} else {
int cmd = buffer.getUByte();
switch (cmd) {
- case SSH_MSG_USERAUTH_INFO_REQUEST:
- log.debug("Received SSH_MSG_USERAUTH_INFO_REQUEST");
+ case SshConstants.SSH_MSG_USERAUTH_INFO_REQUEST: {
String name = buffer.getString();
String instruction = buffer.getString();
String language_tag = buffer.getString();
- log.info("Received {} {} {}", new Object[]{name, instruction, language_tag});
+ if (log.isDebugEnabled()) {
+ log.debug("next({}) Received SSH_MSG_USERAUTH_INFO_REQUEST - name={}, instruction={}, lang={}",
+ session, name, instruction, language_tag);
+ }
int num = buffer.getInt();
String[] prompt = new String[num];
boolean[] echo = new boolean[num];
@@ -93,17 +91,18 @@ public class UserAuthKeyboardInteractive extends AbstractUserAuth {
return Result.Failure;
}
- buffer = session.createBuffer(SSH_MSG_USERAUTH_INFO_RESPONSE);
+ buffer = session.createBuffer(SshConstants.SSH_MSG_USERAUTH_INFO_RESPONSE);
buffer.putInt(rep.length);
for (String r : rep) {
buffer.putString(r);
}
session.writePacket(buffer);
return Result.Continued;
- case SSH_MSG_USERAUTH_SUCCESS:
+ }
+ case SshConstants.SSH_MSG_USERAUTH_SUCCESS:
log.debug("Received SSH_MSG_USERAUTH_SUCCESS");
return Result.Success;
- case SSH_MSG_USERAUTH_FAILURE:
+ case SshConstants.SSH_MSG_USERAUTH_FAILURE:
{
String methods = buffer.getString();
boolean partial = buffer.getBoolean();