Merge remote-tracking branch 'asf/trunk' into kpasswd
diff --git a/kerb-admin-server/pom.xml b/kerb-admin-server/pom.xml
new file mode 100644
index 0000000..546f6da
--- /dev/null
+++ b/kerb-admin-server/pom.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed 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. See accompanying LICENSE file.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.kerby</groupId>
+    <artifactId>kerby-kerb</artifactId>
+    <version>1.0.0-RC3-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>kerb-admin-server</artifactId>
+
+  <name>Kerby-kerb Admin Server</name>
+  <description>Kerby-kerb Admin Server</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.kerby</groupId>
+      <artifactId>kerby-config</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.kerby</groupId>
+      <artifactId>kerb-identity</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.kerby</groupId>
+      <artifactId>kerb-util</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.kerby</groupId>
+      <artifactId>kerb-admin</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.kerby</groupId>
+      <artifactId>kerb-common</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/PasswdServerInit.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/PasswdServerInit.java
new file mode 100644
index 0000000..a80f253
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/PasswdServerInit.java
@@ -0,0 +1,71 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.server;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.PasswdServer;
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.PasswdServerConfig;
+import org.apache.kerby.util.OSUtil;
+
+import java.io.File;
+
+/**
+ * A running tool for password server.
+ * Allow both tcp and udp.
+ * tcp port: 464
+ * udp port: 464
+ */
+public class PasswdServerInit {
+    private static final String USAGE = (OSUtil.isWindows()
+        ? "Usage: bin\\kpasswdServer.cmd" : "Usage: sh bin/kpasswdServer.sh")
+        + " <conf-file>\n"
+        + "\tExample:\n"
+        + "\t\t"
+        + (OSUtil.isWindows()
+        ? "bin\\kpasswdServer.cmd" : "sh bin/kpasswdServer.sh")
+        + " conf\n";
+
+    public static void main(String[] args) throws Exception {
+
+        if (args.length != 1) {
+            System.err.println(USAGE);
+            System.exit(1);
+        }
+
+        String confDirPath = args[0];
+        PasswdServer passwdServer = new PasswdServer(new File(confDirPath));
+        PasswdServerConfig passwdServerConfig = passwdServer.getPasswdServerConfig();
+
+        passwdServer.setPasswdHost(passwdServerConfig.getPasswdHost());
+        passwdServer.setAllowTcp(true);
+        passwdServer.setAllowUdp(true); /**change password protocol allow both tcp and udp*/
+        passwdServer.setPasswdServerPort(passwdServerConfig.getPasswdPort());
+
+        try {
+            passwdServer.init();
+        } catch (KrbException e) {
+            System.err.println("Errors occurred when start admin server:  " + e.getMessage());
+            System.exit(2);
+        }
+        passwdServer.start();
+        System.out.println("Password server started!");
+    }
+}
+
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServer.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServer.java
new file mode 100644
index 0000000..f473c1d
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServer.java
@@ -0,0 +1,268 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.server.kpasswd;
+
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.impl.DefaultInternalPasswdServerImpl;
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.impl.InternalPasswdServer;
+import org.apache.kerby.kerberos.kerb.identity.backend.BackendConfig;
+import org.apache.kerby.kerberos.kerb.identity.backend.IdentityBackend;
+
+import java.io.File;
+
+/**
+ * The implemented Kerberos passwd passwd API.
+ */
+public class PasswdServer {
+    private final PasswdServerConfig passwdServerConfig;
+    private final BackendConfig backendConfig;
+    private final PasswdServerSetting passwdServerSetting;
+    private final KOptions startupOptions;
+
+    private InternalPasswdServer innerPasswdServer;
+
+    /**
+     * Constructor passing both passwdConfig and backendConfig.
+     * @param passwdConfig The passwd config
+     * @param backendConfig The backend config
+     * @throws KrbException e
+     */
+    public PasswdServer(PasswdServerConfig passwdConfig,
+                        BackendConfig backendConfig) throws KrbException {
+        this.passwdServerConfig = passwdConfig;
+        this.backendConfig = backendConfig;
+        startupOptions = new KOptions();
+        passwdServerSetting = new PasswdServerSetting(startupOptions,
+            passwdConfig, backendConfig);
+    }
+
+    /**
+     * Constructor given confDir where 'passwd.conf' and 'backend.conf' should be
+     * available.
+     * passwd.conf, that contains passwd passwd related items.
+     * backend.conf, that contains identity backend related items.
+     *
+     * @param confDir The conf dir
+     * @throws KrbException e
+     */
+    public PasswdServer(File confDir) throws KrbException {
+        PasswdServerConfig tmpPasswdServerConfig =
+            PasswdServerUtil.getPasswdServerConfig(confDir);
+        if (tmpPasswdServerConfig == null) {
+            tmpPasswdServerConfig = new PasswdServerConfig();
+        }
+        this.passwdServerConfig = tmpPasswdServerConfig;
+
+        BackendConfig tmpBackendConfig = PasswdServerUtil.getBackendConfig(confDir);
+        if (tmpBackendConfig == null) {
+            tmpBackendConfig = new BackendConfig();
+        }
+        tmpBackendConfig.setConfDir(confDir);
+        this.backendConfig = tmpBackendConfig;
+
+        startupOptions = new KOptions();
+        passwdServerSetting = new PasswdServerSetting(startupOptions,
+            passwdServerConfig, backendConfig);
+    }
+
+    /**
+     * Default constructor.
+     */
+    public PasswdServer() {
+        passwdServerConfig = new PasswdServerConfig();
+        backendConfig = new BackendConfig();
+        startupOptions = new KOptions();
+        passwdServerSetting = new PasswdServerSetting(startupOptions,
+            passwdServerConfig, backendConfig);
+    }
+
+    /**
+     * Set Passwd realm for ticket request
+     * @param realm The passwd realm
+     */
+    public void setPasswdServerRealm(String realm) {
+        startupOptions.add(PasswdServerOption.ADMIN_REALM, realm);
+    }
+
+    /**
+     * Set Passwd host.
+     * @param passwdHost The passwd host
+     */
+    public void setPasswdHost(String passwdHost) {
+        startupOptions.add(
+                PasswdServerOption.ADMIN_HOST,
+                passwdHost);
+    }
+
+    /**
+     * Set Passwd port.
+     * @param passwdPort The passwd port
+     */
+    public void setPasswdServerPort(int passwdPort) {
+        startupOptions.add(
+                PasswdServerOption.ADMIN_PORT,
+                passwdPort);
+    }
+
+    /**
+     * Set Passwd tcp port.
+     * @param passwdTcpPort The passwd tcp port
+     */
+    public void setPasswdTcpPort(int passwdTcpPort) {
+        startupOptions.add(
+                PasswdServerOption.ADMIN_TCP_PORT,
+                passwdTcpPort);
+    }
+
+    /**
+     * Set to allow UDP or not.
+     * @param allowUdp true if allow udp
+     */
+    public void setAllowUdp(boolean allowUdp) {
+        startupOptions.add(
+                PasswdServerOption.ALLOW_UDP,
+                allowUdp);
+    }
+
+    /**
+     * Set to allow TCP or not.
+     * @param allowTcp true if allow tcp
+     */
+    public void setAllowTcp(boolean allowTcp) {
+        startupOptions.add(
+                PasswdServerOption.ALLOW_TCP,
+                allowTcp);
+    }
+    /**
+     * Set Passwd udp port. Only makes sense when allowUdp is set.
+     * @param passwdUdpPort The passwd udp port
+     */
+    public void setPasswdUdpPort(int passwdUdpPort) {
+        startupOptions.add(
+                PasswdServerOption.ADMIN_UDP_PORT,
+                passwdUdpPort);
+    }
+
+    /**
+     * Set runtime folder.
+     * @param workDir The work dir
+     */
+    public void setWorkDir(File workDir) {
+        startupOptions.add(
+                PasswdServerOption.WORK_DIR,
+                workDir);
+    }
+
+    /**
+     * Allow to debug so have more logs.
+     */
+    public void enableDebug() {
+        startupOptions.add(
+                PasswdServerOption.ENABLE_DEBUG);
+    }
+
+    /**
+     * Allow to hook customized passwd implementation.
+     *
+     * @param innerPasswdServerImpl The inner passwd implementation
+     */
+    public void setInnerPasswdServerImpl(InternalPasswdServer innerPasswdServerImpl) {
+        startupOptions.add(
+                PasswdServerOption.INNER_ADMIN_IMPL,
+                innerPasswdServerImpl);
+    }
+
+    /**
+     * Get Passwd setting from startup options and configs.
+     * @return setting
+     */
+    public PasswdServerSetting getPasswdServerSetting() {
+        return passwdServerSetting;
+    }
+
+    /**
+     * Get the Passwd config.
+     * @return PasswdServerConfig
+     */
+    public PasswdServerConfig getPasswdServerConfig() {
+        return passwdServerConfig;
+    }
+
+    /**
+     * Get backend config.
+     *
+     * @return backend configuration
+     */
+    public BackendConfig getBackendConfig() {
+        return backendConfig;
+    }
+
+    /**
+     * Get identity service.
+     * @return IdentityService
+     */
+    public IdentityBackend getIdentityService() {
+        if (innerPasswdServer == null) {
+            throw new RuntimeException("Not init yet");
+        }
+        return innerPasswdServer.getIdentityBackend();
+    }
+
+    /**
+     * Initialize.
+     *
+     * @throws KrbException e.
+     */
+    public void init() throws KrbException {
+        if (startupOptions.contains(PasswdServerOption.INNER_ADMIN_IMPL)) {
+            innerPasswdServer = (InternalPasswdServer) startupOptions.getOptionValue(
+                PasswdServerOption.INNER_ADMIN_IMPL);
+        } else {
+            innerPasswdServer =
+                new DefaultInternalPasswdServerImpl(passwdServerSetting);
+        }
+
+        innerPasswdServer.init();
+    }
+
+    /**
+     * Start the Passwd passwd.
+     *
+     * @throws KrbException e.
+     */
+    public void start() throws KrbException {
+        if (innerPasswdServer == null) {
+            throw new RuntimeException("Not init yet");
+        }
+        innerPasswdServer.start();
+    }
+
+    /**
+     * Stop the Passwd passwd.
+     *
+     * @throws KrbException e.
+     */
+    public void stop() throws KrbException {
+        if (innerPasswdServer != null) {
+            innerPasswdServer.stop();
+        }
+    }
+}
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerConfig.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerConfig.java
new file mode 100644
index 0000000..4cb89f2
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerConfig.java
@@ -0,0 +1,94 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.server.kpasswd;
+
+
+import org.apache.kerby.kerberos.kerb.common.Krb5Conf;
+
+/**
+ * Kerb KDC side configuration API.
+ */
+public class PasswdServerConfig extends Krb5Conf {
+    private static final String KDCDEFAULT = "passwddefaults";
+
+    public boolean enableDebug() {
+        return getBoolean(PasswdServerConfigKey.KRB_DEBUG, true, KDCDEFAULT);
+    }
+
+    public String getPasswdServiceName() {
+        return getString(PasswdServerConfigKey.ADMIN_SERVICE_NAME, true, KDCDEFAULT);
+    }
+
+    public String getPasswdHost() {
+        return getString(PasswdServerConfigKey.ADMIN_HOST, true, KDCDEFAULT);
+    }
+
+    public int getPasswdPort() {
+        Integer passwdPort = getInt(PasswdServerConfigKey.ADMIN_PORT, true, KDCDEFAULT);
+        if (passwdPort != null && passwdPort > 0) {
+            return passwdPort.intValue();
+        }
+        return -1;
+    }
+
+    public int getPasswdTcpPort() {
+        Integer passwdTcpPort = getInt(PasswdServerConfigKey.ADMIN_TCP_PORT, true, KDCDEFAULT);
+        if (passwdTcpPort != null && passwdTcpPort > 0) {
+            return passwdTcpPort.intValue();
+        }
+        return getPasswdPort();
+    }
+
+    /**
+     * Is to allow TCP for KDC
+     * @return true to allow TCP, false otherwise
+     */
+    public Boolean allowTcp() {
+        return getBoolean(PasswdServerConfigKey.ADMIN_ALLOW_TCP, true, KDCDEFAULT)
+                || getInt(PasswdServerConfigKey.ADMIN_TCP_PORT, true, KDCDEFAULT) != null
+            || getInt(PasswdServerConfigKey.ADMIN_PORT, false, KDCDEFAULT) != null;
+    }
+
+    /**
+     * Is to allow UDP for KDC
+     * @return true to allow UDP, false otherwise
+     */
+    public Boolean allowUdp() {
+        return getBoolean(PasswdServerConfigKey.ADMIN_ALLOW_UDP, true, KDCDEFAULT)
+                || getInt(PasswdServerConfigKey.ADMIN_UDP_PORT, true, KDCDEFAULT) != null
+            || getInt(PasswdServerConfigKey.ADMIN_PORT, false, KDCDEFAULT) != null;
+    }
+
+    public int getPasswdUdpPort() {
+        Integer passwdUdpPort = getInt(PasswdServerConfigKey.ADMIN_UDP_PORT, true, KDCDEFAULT);
+        if (passwdUdpPort != null && passwdUdpPort > 0) {
+            return passwdUdpPort.intValue();
+        }
+        return getPasswdPort();
+    }
+
+    public String getPasswdRealm() {
+        return getString(PasswdServerConfigKey.ADMIN_REALM, true, KDCDEFAULT);
+    }
+
+    public String getPasswdDomain() {
+        return getString(PasswdServerConfigKey.ADMIN_DOMAIN, true, KDCDEFAULT);
+    }
+}
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerConfigKey.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerConfigKey.java
new file mode 100644
index 0000000..8f7651e
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerConfigKey.java
@@ -0,0 +1,56 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.server.kpasswd;
+
+import org.apache.kerby.config.ConfigKey;
+
+public enum PasswdServerConfigKey implements ConfigKey {
+    KRB_DEBUG(true),
+    ADMIN_SERVICE_NAME("Kpasswd-Server"),
+    KDC_IDENTITY_BACKEND,
+    ADMIN_HOST("127.0.0.1"),
+    ADMIN_PORT,
+    ADMIN_ALLOW_TCP(true),
+    ADMIN_ALLOW_UDP(true),
+    ADMIN_UDP_PORT,
+    ADMIN_TCP_PORT,
+    ADMIN_DOMAIN("example.com"),
+    ADMIN_REALM("EXAMPLE.COM");
+
+    private Object defaultValue;
+
+    PasswdServerConfigKey() {
+        this.defaultValue = null;
+    }
+
+    PasswdServerConfigKey(Object defaultValue) {
+        this.defaultValue = defaultValue;
+    }
+
+    @Override
+    public String getPropertyKey() {
+        return name().toLowerCase();
+    }
+
+    @Override
+    public Object getDefaultValue() {
+        return this.defaultValue;
+    }
+}
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerContext.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerContext.java
new file mode 100644
index 0000000..0d4bc7e
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerContext.java
@@ -0,0 +1,52 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.server.kpasswd;
+
+import org.apache.kerby.kerberos.kerb.identity.IdentityService;
+
+public class PasswdServerContext {
+    private final PasswdServerSetting passwdServerSetting;
+
+    private IdentityService identityService;
+
+    public PasswdServerContext(PasswdServerSetting passwdServerSetting) {
+        this.passwdServerSetting = passwdServerSetting;
+    }
+
+    public PasswdServerSetting getPasswdServerSetting() {
+        return passwdServerSetting;
+    }
+
+    public PasswdServerConfig getConfig() {
+        return passwdServerSetting.getPasswdServerConfig();
+    }
+
+    public void setIdentityService(IdentityService identityService) {
+        this.identityService = identityService;
+    }
+
+    public IdentityService getIdentityService() {
+        return identityService;
+    }
+
+    public String getPasswdRealm() {
+        return passwdServerSetting.getPasswdRealm();
+    }
+}
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerHandler.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerHandler.java
new file mode 100644
index 0000000..363ecdd
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerHandler.java
@@ -0,0 +1,65 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.server.kpasswd;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+
+/**
+ * KDC handler to process client requests. Currently only one realm is supported.
+ */
+public class PasswdServerHandler {
+    private static final Logger LOG = LoggerFactory.getLogger(PasswdServerHandler.class);
+    private final PasswdServerContext passwdServerContext;
+
+    /**
+     * Constructor with passwd context.
+     *
+     * @param passwdServerContext passwd passwd context
+     */
+    public PasswdServerHandler(PasswdServerContext passwdServerContext) {
+        this.passwdServerContext = passwdServerContext;
+        LOG.info("Passwd context realm:" + this.passwdServerContext.getPasswdRealm());
+    }
+
+    /**
+     * Process the client request message.
+     *
+     * @throws KrbException e
+     * @param receivedMessage The client request message
+     * @param remoteAddress Address from remote side
+     * @return The response message
+     */
+    public ByteBuffer handleMessage(ByteBuffer receivedMessage,
+                                    InetAddress remoteAddress) throws KrbException {
+        System.out.println("Password Server receive message: ");
+        System.out.println(new String(receivedMessage.array()));
+        String response = "Password server receive message.";
+        ByteBuffer responseMessage = ByteBuffer.allocate(response.length() + 4);
+        responseMessage.putInt(response.length());
+        responseMessage.put(response.getBytes());
+        responseMessage.flip();
+        return responseMessage;
+    }
+}
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerImpl.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerImpl.java
new file mode 100644
index 0000000..7cd7a8b
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerImpl.java
@@ -0,0 +1,250 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.server.kpasswd;
+
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.identity.backend.BackendConfig;
+import org.apache.kerby.kerberos.kerb.identity.backend.IdentityBackend;
+import org.apache.kerby.kerberos.kerb.server.KdcConfig;
+import org.apache.kerby.kerberos.kerb.server.KdcServerOption;
+import org.apache.kerby.kerberos.kerb.server.KdcSetting;
+import org.apache.kerby.kerberos.kerb.server.KdcUtil;
+import org.apache.kerby.kerberos.kerb.server.impl.DefaultInternalKdcServerImpl;
+import org.apache.kerby.kerberos.kerb.server.impl.InternalKdcServer;
+
+import java.io.File;
+
+/**
+ * The implemented Kerberos Server API.
+ */
+public class PasswdServerImpl {
+    private final KdcConfig passwdConfig;
+    private final BackendConfig backendConfig;
+    private final KdcSetting passwdSetting;
+    private final KOptions startupOptions;
+
+    private InternalKdcServer innerKdc;
+
+    /**
+     * Constructor passing both passwdConfig and backendConfig.
+     * @param passwdConfig The passwd config
+     * @param backendConfig The backend config
+     * @throws KrbException e
+     */
+    public PasswdServerImpl(KdcConfig passwdConfig,
+                           BackendConfig backendConfig) throws KrbException {
+        this.passwdConfig = passwdConfig;
+        this.backendConfig = backendConfig;
+        startupOptions = new KOptions();
+        passwdSetting = new KdcSetting(startupOptions, passwdConfig, backendConfig);
+    }
+
+    /**
+     * Constructor given confDir where 'passwd.conf' and 'backend.conf' should be
+     * available.
+     * passwd.conf, that contains passwd passwd related items.
+     * backend.conf, that contains identity backend related items.
+     *
+     * @param confDir The conf dir
+     * @throws KrbException e
+     */
+    public PasswdServerImpl(File confDir) throws KrbException {
+        KdcConfig tmpKdcConfig = KdcUtil.getKdcConfig(confDir);
+        if (tmpKdcConfig == null) {
+            tmpKdcConfig = new KdcConfig();
+        }
+        this.passwdConfig = tmpKdcConfig;
+
+        BackendConfig tmpBackendConfig = KdcUtil.getBackendConfig(confDir);
+        if (tmpBackendConfig == null) {
+            tmpBackendConfig = new BackendConfig();
+        }
+        tmpBackendConfig.setConfDir(confDir);
+        this.backendConfig = tmpBackendConfig;
+
+        startupOptions = new KOptions();
+        passwdSetting = new KdcSetting(startupOptions, passwdConfig, backendConfig);
+    }
+
+    /**
+     * Default constructor.
+     */
+    public PasswdServerImpl() {
+        passwdConfig = new KdcConfig();
+        backendConfig = new BackendConfig();
+        startupOptions = new KOptions();
+        passwdSetting = new KdcSetting(startupOptions, passwdConfig, backendConfig);
+    }
+
+    /**
+     * Set KDC realm for ticket request
+     * @param realm The passwd realm
+     */
+    public void setKdcRealm(String realm) {
+        startupOptions.add(KdcServerOption.KDC_REALM, realm);
+    }
+
+    /**
+     * Set KDC host.
+     * @param passwdHost The passwd host
+     */
+    public void setKdcHost(String passwdHost) {
+        startupOptions.add(KdcServerOption.KDC_HOST, passwdHost);
+    }
+
+    /**
+     * Set KDC port.
+     * @param passwdPort The passwd port
+     */
+    public void setKdcPort(int passwdPort) {
+        startupOptions.add(KdcServerOption.KDC_PORT, passwdPort);
+    }
+
+    /**
+     * Set KDC tcp port.
+     * @param passwdTcpPort The passwd tcp port
+     */
+    public void setKdcTcpPort(int passwdTcpPort) {
+        startupOptions.add(KdcServerOption.KDC_TCP_PORT, passwdTcpPort);
+    }
+
+    /**
+     * Set to allow UDP or not.
+     * @param allowUdp true if allow udp
+     */
+    public void setAllowUdp(boolean allowUdp) {
+        startupOptions.add(KdcServerOption.ALLOW_UDP, allowUdp);
+    }
+
+    /**
+     * Set to allow TCP or not.
+     * @param allowTcp true if allow tcp
+     */
+    public void setAllowTcp(boolean allowTcp) {
+        startupOptions.add(KdcServerOption.ALLOW_TCP, allowTcp);
+    }
+    /**
+     * Set KDC udp port. Only makes sense when allowUdp is set.
+     * @param passwdUdpPort The passwd udp port
+     */
+    public void setKdcUdpPort(int passwdUdpPort) {
+        startupOptions.add(KdcServerOption.KDC_UDP_PORT, passwdUdpPort);
+    }
+
+    /**
+     * Set runtime folder.
+     * @param workDir The work dir
+     */
+    public void setWorkDir(File workDir) {
+        startupOptions.add(KdcServerOption.WORK_DIR, workDir);
+    }
+
+    /**
+     * Allow to debug so have more logs.
+     */
+    public void enableDebug() {
+        startupOptions.add(KdcServerOption.ENABLE_DEBUG);
+    }
+
+    /**
+     * Allow to hook customized passwd implementation.
+     *
+     * @param innerKdcImpl The inner passwd implementation
+     */
+    public void setInnerKdcImpl(InternalKdcServer innerKdcImpl) {
+        startupOptions.add(KdcServerOption.INNER_KDC_IMPL, innerKdcImpl);
+    }
+
+    /**
+     * Get KDC setting from startup options and configs.
+     * @return setting
+     */
+    public KdcSetting getKdcSetting() {
+        return passwdSetting;
+    }
+
+    /**
+     * Get the KDC config.
+     * @return PasswdServerConfig
+     */
+    public KdcConfig getKdcConfig() {
+        return passwdConfig;
+    }
+
+    /**
+     * Get backend config.
+     *
+     * @return backend configuration
+     */
+    public BackendConfig getBackendConfig() {
+        return backendConfig;
+    }
+
+    /**
+     * Get identity service.
+     * @return IdentityService
+     */
+    public IdentityBackend getIdentityService() {
+        if (innerKdc == null) {
+            throw new RuntimeException("Not init yet");
+        }
+        return innerKdc.getIdentityBackend();
+    }
+
+    /**
+     * Initialize.
+     *
+     * @throws KrbException e.
+     */
+    public void init() throws KrbException {
+        if (startupOptions.contains(KdcServerOption.INNER_KDC_IMPL)) {
+            innerKdc = (InternalKdcServer) startupOptions.getOptionValue(
+                    KdcServerOption.INNER_KDC_IMPL);
+        } else {
+            innerKdc = new DefaultInternalKdcServerImpl(passwdSetting);
+        }
+
+        innerKdc.init();
+    }
+
+    /**
+     * Start the KDC passwd.
+     *
+     * @throws KrbException e.
+     */
+    public void start() throws KrbException {
+        if (innerKdc == null) {
+            throw new RuntimeException("Not init yet");
+        }
+        innerKdc.start();
+    }
+
+    /**
+     * Stop the KDC passwd.
+     *
+     * @throws KrbException e.
+     */
+    public void stop() throws KrbException {
+        if (innerKdc != null) {
+            innerKdc.stop();
+        }
+    }
+}
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerOption.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerOption.java
new file mode 100644
index 0000000..4594b14
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerOption.java
@@ -0,0 +1,52 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.server.kpasswd;
+
+import org.apache.kerby.KOption;
+import org.apache.kerby.KOptionInfo;
+import org.apache.kerby.KOptionType;
+
+/**
+ * KDC passwd startup options
+ */
+public enum PasswdServerOption implements KOption {
+    NONE(null),
+    INNER_ADMIN_IMPL(new KOptionInfo("inner KDC impl", "inner KDC impl", KOptionType.OBJ)),
+    ADMIN_REALM(new KOptionInfo("passwd realm", "passwd realm", KOptionType.STR)),
+    ADMIN_HOST(new KOptionInfo("passwd host", "passwd host", KOptionType.STR)),
+    ADMIN_PORT(new KOptionInfo("passwd port", "passwd port", KOptionType.INT)),
+    ALLOW_TCP(new KOptionInfo("allow tcp", "allow tcp", KOptionType.BOOL)),
+    ADMIN_TCP_PORT(new KOptionInfo("passwd tcp port", "passwd tcp port", KOptionType.INT)),
+    ALLOW_UDP(new KOptionInfo("allow udp", "allow udp", KOptionType.BOOL)),
+    ADMIN_UDP_PORT(new KOptionInfo("passwd udp port", "passwd udp port", KOptionType.INT)),
+    WORK_DIR(new KOptionInfo("work dir", "work dir", KOptionType.DIR)),
+    ENABLE_DEBUG(new KOptionInfo("enable debug", "enable debug", KOptionType.BOOL));
+
+    private final KOptionInfo optionInfo;
+
+    PasswdServerOption(KOptionInfo optionInfo) {
+        this.optionInfo = optionInfo;
+    }
+
+    @Override
+    public KOptionInfo getOptionInfo() {
+        return optionInfo;
+    }
+}
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerSetting.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerSetting.java
new file mode 100644
index 0000000..9316104
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerSetting.java
@@ -0,0 +1,188 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.server.kpasswd;
+
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.identity.backend.BackendConfig;
+
+/**
+ * Passwd Server setting that combines startup options and passwd config.
+ */
+public class PasswdServerSetting {
+    private final KOptions startupOptions;
+    private final PasswdServerConfig passwdServerConfig;
+    private final BackendConfig backendConfig;
+
+    /**
+     * PasswdServerSetting constructor
+     * @param startupOptions startup options
+     * @param config passwd configuration
+     * @param backendConfig backend configuration
+     */
+    public PasswdServerSetting(KOptions startupOptions,
+                              PasswdServerConfig config,
+                              BackendConfig backendConfig) {
+        this.startupOptions = startupOptions;
+        this.passwdServerConfig = config;
+        this.backendConfig = backendConfig;
+    }
+
+    public PasswdServerSetting(PasswdServerConfig passwdServerConfig,
+                              BackendConfig backendConfig) {
+        this(new KOptions(), passwdServerConfig, backendConfig);
+    }
+
+    /**
+     * Get the Passwd Server config.
+     * @return passwd configuration
+     */
+    public PasswdServerConfig getPasswdServerConfig() {
+        return passwdServerConfig;
+    }
+
+    /**
+     * Get the backend config.
+     * @return backend configuration
+     */
+    public BackendConfig getBackendConfig() {
+        return backendConfig;
+    }
+
+    public String getPasswdHost() {
+        String passwdHost = startupOptions.getStringOption(
+                PasswdServerOption.ADMIN_HOST);
+        if (passwdHost == null) {
+            passwdHost = passwdServerConfig.getPasswdHost();
+        }
+        return passwdHost;
+    }
+
+    /**
+     * Check passwd tcp setting and see if any bad.
+     * @return valid tcp port or -1 if not allowTcp
+     * @throws KrbException e
+     */
+    public int checkGetPasswdTcpPort() throws KrbException {
+        if (allowTcp()) {
+            int passwdPort = getPasswdTcpPort();
+            if (passwdPort < 1) {
+                throw new KrbException("Passwd Server tcp port isn't set or configured");
+            }
+            return passwdPort;
+        }
+        return -1;
+    }
+
+    /**
+     * Check passwd udp setting and see if any bad.
+     * @return valid udp port or -1 if not allowUdp
+     * @throws KrbException e
+     */
+    public int checkGetPasswdUdpPort() throws KrbException {
+        if (allowUdp()) {
+            int passwdPort = getPasswdUdpPort();
+            if (passwdPort < 1) {
+                throw new KrbException("Passwd Server udp port isn't set or configured");
+            }
+            return passwdPort;
+        }
+        return -1;
+    }
+
+    /**
+     * Get passwd tcp port
+     *
+     * @return passwd tcp port
+     */
+    public int getPasswdTcpPort() {
+        int tcpPort = startupOptions.getIntegerOption(PasswdServerOption.ADMIN_TCP_PORT);
+        if (tcpPort < 1) {
+            tcpPort = passwdServerConfig.getPasswdTcpPort();
+        }
+        if (tcpPort < 1) {
+            tcpPort = getPasswdPort();
+        }
+
+        return tcpPort;
+    }
+
+    /**
+     * Get passwd port
+     *
+     * @return passwd port
+     */
+    public int getPasswdPort() {
+        int passwdPort = startupOptions.getIntegerOption(PasswdServerOption.ADMIN_PORT);
+        if (passwdPort < 1) {
+            passwdPort = passwdServerConfig.getPasswdPort();
+        }
+        return passwdPort;
+    }
+
+    /**
+     * Get whether tcp protocol is allowed
+     * @return tcp protocol is allowed or not
+     */
+    public boolean allowTcp() {
+        Boolean allowTcp = startupOptions.getBooleanOption(
+                PasswdServerOption.ALLOW_TCP, passwdServerConfig.allowTcp());
+        return allowTcp;
+    }
+
+    /**
+     * Get whether udp protocol is allowed
+     * @return udp protocol is allowed or not
+     */
+    public boolean allowUdp() {
+        Boolean allowUdp = startupOptions.getBooleanOption(
+                PasswdServerOption.ALLOW_UDP, passwdServerConfig.allowUdp());
+        return allowUdp;
+    }
+
+    /**
+     * Get passwd udp port
+     *
+     * @return udp port
+     */
+    public int getPasswdUdpPort() {
+        int udpPort = startupOptions.getIntegerOption(PasswdServerOption.ADMIN_UDP_PORT);
+        if (udpPort < 1) {
+            udpPort = passwdServerConfig.getPasswdUdpPort();
+        }
+        if (udpPort < 1) {
+            udpPort = getPasswdPort();
+        }
+
+        return udpPort;
+    }
+
+    /**
+     * Get Passwd Server realm.
+     * @return Passwd Server realm
+     */
+    public String getPasswdRealm() {
+        String passwdRealm = startupOptions.getStringOption(PasswdServerOption.ADMIN_REALM);
+        if (passwdRealm == null || passwdRealm.isEmpty()) {
+            passwdRealm = passwdServerConfig.getPasswdRealm();
+        }
+        return passwdRealm;
+    }
+}
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerUtil.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerUtil.java
new file mode 100644
index 0000000..f45bafa
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/PasswdServerUtil.java
@@ -0,0 +1,142 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.server.kpasswd;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.identity.backend.BackendConfig;
+import org.apache.kerby.kerberos.kerb.identity.backend.IdentityBackend;
+import org.apache.kerby.kerberos.kerb.identity.backend.MemoryIdentityBackend;
+import org.apache.kerby.kerberos.kerb.transport.TransportPair;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
+/**
+ * KDC side utilities.
+ */
+public final class PasswdServerUtil {
+
+    private PasswdServerUtil() { }
+
+    /**
+     * Get passwd configuration
+     * @param confDir configuration directory
+     * @return passwd configuration
+     * @throws KrbException e.
+     */
+    public static PasswdServerConfig getPasswdServerConfig(File confDir) throws KrbException {
+        File passwdConfFile = new File(confDir, "kpasswdServer.conf");
+        if (passwdConfFile.exists()) {
+            PasswdServerConfig passwdServerConfig = new PasswdServerConfig();
+            try {
+                passwdServerConfig.addKrb5Config(passwdConfFile);
+            } catch (IOException e) {
+                throw new KrbException("Can not load the passwd configuration file "
+                        + passwdConfFile.getAbsolutePath());
+            }
+            return passwdServerConfig;
+        }
+
+        return null;
+    }
+
+    /**
+     * Get backend configuration
+     * @param confDir configuration directory
+     * @return backend configuration
+     * @throws KrbException e.
+     */
+    public static BackendConfig getBackendConfig(File confDir) throws KrbException {
+        File backendConfigFile = new File(confDir, "backend.conf");
+        if (backendConfigFile.exists()) {
+            BackendConfig backendConfig = new BackendConfig();
+            try {
+                backendConfig.addIniConfig(backendConfigFile);
+            } catch (IOException e) {
+                throw new KrbException("Can not load the backend configuration file "
+                        + backendConfigFile.getAbsolutePath());
+            }
+            return backendConfig;
+        }
+
+        return null;
+    }
+
+    /**
+     * Init the identity backend from backend configuration.
+     *
+     * @throws KrbException e.
+     * @param backendConfig backend configuration information
+     * @return backend
+     */
+    public static IdentityBackend getBackend(
+            BackendConfig backendConfig) throws KrbException {
+        String backendClassName = backendConfig.getString(
+                PasswdServerConfigKey.KDC_IDENTITY_BACKEND, true);
+        if (backendClassName == null) {
+            backendClassName = MemoryIdentityBackend.class.getCanonicalName();
+        }
+
+        Class<?> backendClass;
+        try {
+            backendClass = Class.forName(backendClassName);
+        } catch (ClassNotFoundException e) {
+            throw new KrbException("Failed to load backend class: "
+                    + backendClassName);
+        }
+
+        IdentityBackend backend;
+        try {
+            backend = (IdentityBackend) backendClass.newInstance();
+        } catch (InstantiationException | IllegalAccessException e) {
+            throw new KrbException("Failed to create backend: "
+                    + backendClassName);
+        }
+
+        backend.setConfig(backendConfig);
+        backend.initialize();
+        return backend;
+    }
+
+    /**
+     * Get KDC network transport addresses according to KDC setting.
+     * @param setting passwd setting
+     * @return UDP and TCP addresses pair
+     * @throws KrbException e
+     */
+    public static TransportPair getTransportPair(
+            PasswdServerSetting setting) throws KrbException {
+        TransportPair result = new TransportPair();
+
+        int tcpPort = setting.checkGetPasswdTcpPort();
+        if (tcpPort > 0) {
+            result.tcpAddress = new InetSocketAddress(
+                    setting.getPasswdHost(), tcpPort);
+        }
+        int udpPort = setting.checkGetPasswdUdpPort();
+        if (udpPort > 0) {
+            result.udpAddress = new InetSocketAddress(
+                    setting.getPasswdHost(), udpPort);
+        }
+
+        return result;
+    }
+}
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/AbstractInternalPasswdServer.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/AbstractInternalPasswdServer.java
new file mode 100644
index 0000000..0130f57
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/AbstractInternalPasswdServer.java
@@ -0,0 +1,116 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.server.kpasswd.impl;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.PasswdServerConfig;
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.PasswdServerSetting;
+import org.apache.kerby.kerberos.kerb.identity.CacheableIdentityService;
+import org.apache.kerby.kerberos.kerb.identity.IdentityService;
+import org.apache.kerby.kerberos.kerb.identity.backend.IdentityBackend;
+import org.apache.kerby.kerberos.kerb.identity.backend.BackendConfig;
+import org.apache.kerby.kerberos.kerb.identity.backend.MemoryIdentityBackend;
+import org.apache.kerby.kerberos.kerb.server.KdcUtil;
+
+/**
+ * Abstract Kpasswd passwd implementation.
+ */
+public class AbstractInternalPasswdServer implements InternalPasswdServer {
+    private boolean started;
+    private final PasswdServerConfig passwdConfig;
+    private final BackendConfig backendConfig;
+    private final PasswdServerSetting passwdSetting;
+    private IdentityBackend backend;
+    private IdentityService identityService;
+
+    public AbstractInternalPasswdServer(PasswdServerSetting passwdSetting) {
+        this.passwdSetting = passwdSetting;
+        this.passwdConfig = passwdSetting.getPasswdServerConfig();
+        this.backendConfig = passwdSetting.getBackendConfig();
+    }
+
+    @Override
+    public PasswdServerSetting getSetting() {
+        return passwdSetting;
+    }
+
+    public boolean isStarted() {
+        return started;
+    }
+
+    protected String getServiceName() {
+        return passwdConfig.getPasswdServiceName();
+    }
+
+    protected IdentityService getIdentityService() {
+        if (identityService == null) {
+            if (backend instanceof MemoryIdentityBackend) { // Already in memory
+                identityService = backend;
+            } else {
+                identityService = new CacheableIdentityService(
+                        backendConfig, backend);
+            }
+        }
+        return identityService;
+    }
+
+    @Override
+    public void init() throws KrbException {
+        backend = KdcUtil.getBackend(backendConfig);
+    }
+
+    @Override
+    public void start() throws KrbException {
+        try {
+            doStart();
+        } catch (Exception e) {
+            throw new KrbException("Failed to start " + getServiceName(), e);
+        }
+
+        started = true;
+    }
+
+    public boolean enableDebug() {
+        return passwdConfig.enableDebug();
+    }
+
+    @Override
+    public IdentityBackend getIdentityBackend() {
+        return backend;
+    }
+
+    protected void doStart() throws Exception {
+        backend.start();
+    }
+
+    public void stop() throws KrbException {
+        try {
+            doStop();
+        } catch (Exception e) {
+            throw new KrbException("Failed to stop " + getServiceName(), e);
+        }
+
+        started = false;
+    }
+
+    protected void doStop() throws Exception {
+        backend.stop();
+    }
+}
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/DefaultInternalPasswdServerImpl.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/DefaultInternalPasswdServerImpl.java
new file mode 100644
index 0000000..f50a25b
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/DefaultInternalPasswdServerImpl.java
@@ -0,0 +1,80 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.server.kpasswd.impl;
+
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.PasswdServerContext;
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.PasswdServerSetting;
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.PasswdServerUtil;
+import org.apache.kerby.kerberos.kerb.transport.KdcNetwork;
+import org.apache.kerby.kerberos.kerb.transport.TransportPair;
+import org.apache.kerby.kerberos.kerb.transport.KrbTransport;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * A default passwd passwd implementation.
+ */
+public class DefaultInternalPasswdServerImpl extends AbstractInternalPasswdServer {
+    private ExecutorService executor;
+    private PasswdServerContext passwdContext;
+    private KdcNetwork network;
+
+    public DefaultInternalPasswdServerImpl(PasswdServerSetting passwdSetting) {
+        super(passwdSetting);
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+
+        prepareHandler();
+
+        executor = Executors.newCachedThreadPool();
+
+        network = new KdcNetwork() {
+            @Override
+            protected void onNewTransport(KrbTransport transport) {
+                DefaultPasswdServerHandler passwdHandler =
+                    new DefaultPasswdServerHandler(passwdContext, transport);
+                executor.execute(passwdHandler);
+            }
+        };
+
+        network.init();
+        TransportPair tpair = PasswdServerUtil.getTransportPair(getSetting());
+        network.listen(tpair);
+        network.start();
+    }
+
+    private void prepareHandler() {
+        passwdContext = new PasswdServerContext(getSetting());
+        passwdContext.setIdentityService(getIdentityService());
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        super.doStop();
+
+        network.stop();
+
+        executor.shutdownNow();
+    }
+}
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/DefaultPasswdServerHandler.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/DefaultPasswdServerHandler.java
new file mode 100644
index 0000000..f9bd6ce
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/DefaultPasswdServerHandler.java
@@ -0,0 +1,72 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.server.kpasswd.impl;
+
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.PasswdServerContext;
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.PasswdServerHandler;
+import org.apache.kerby.kerberos.kerb.transport.KrbTransport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+
+public class DefaultPasswdServerHandler extends PasswdServerHandler implements Runnable {
+    private static Logger logger = LoggerFactory.getLogger(DefaultPasswdServerHandler.class);
+    private final KrbTransport transport;
+
+    public DefaultPasswdServerHandler(PasswdServerContext passwdServerContext, KrbTransport transport) {
+        super(passwdServerContext);
+        this.transport  = transport;
+    }
+
+    @Override
+    public void run() {
+        while (true) {
+            try {
+                ByteBuffer message = transport.receiveMessage();
+                if (message == null) {
+                    logger.debug("No valid request recved. Disconnect actively");
+                    transport.release();
+                    break;
+                }
+                handleMessage(message);
+            } catch (IOException e) {
+                transport.release();
+                logger.debug("Transport or decoding error occurred, "
+                        + "disconnecting abnormally", e);
+                break;
+            }
+        }
+    }
+
+    protected void handleMessage(ByteBuffer message) {
+        InetAddress clientAddress = transport.getRemoteAddress();
+
+        try {
+            ByteBuffer krbResponse = handleMessage(message, clientAddress);
+            transport.sendMessage(krbResponse);
+        } catch (Exception e) {
+            transport.release();
+            logger.error("Error occured while processing request:", e);
+        }
+    }
+}
\ No newline at end of file
diff --git a/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/InternalPasswdServer.java b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/InternalPasswdServer.java
new file mode 100644
index 0000000..c84ddbb
--- /dev/null
+++ b/kerb-admin-server/src/main/java/org/apache/kerby/kerberos/kerb/admin/server/kpasswd/impl/InternalPasswdServer.java
@@ -0,0 +1,60 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.server.kpasswd.impl;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.server.kpasswd.PasswdServerSetting;
+import org.apache.kerby.kerberos.kerb.identity.backend.IdentityBackend;
+
+/**
+ * An internal KDC passwd interface.
+ */
+public interface InternalPasswdServer {
+
+    /**
+     * Initialize.
+     * @throws KrbException e
+     */
+    void init() throws KrbException;
+
+    /**
+     * Start the KDC passwd.
+     * @throws KrbException e
+     */
+    void start() throws KrbException;
+
+    /**
+     * Stop the KDC passwd.
+     * @throws KrbException e
+     */
+    void stop() throws KrbException;
+
+    /**
+     * Get passwd passwd setting.
+     * @return setting
+     */
+    PasswdServerSetting getSetting();
+
+    /**
+     * Get identity backend.
+     * @return IdentityBackend
+     */
+    IdentityBackend getIdentityBackend();
+}
diff --git a/kerby-dist/kdc-dist/bin/kpasswdClient.cmd b/kerby-dist/kdc-dist/bin/kpasswdClient.cmd
new file mode 100644
index 0000000..0ecd815
--- /dev/null
+++ b/kerby-dist/kdc-dist/bin/kpasswdClient.cmd
@@ -0,0 +1,32 @@
+@echo off
+@rem  Licensed to the Apache Software Foundation (ASF) under one
+@rem  or more contributor license agreements.  See the NOTICE file
+@rem  distributed with this work for additional information
+@rem  regarding copyright ownership.  The ASF licenses this file
+@rem  to you under the Apache License, Version 2.0 (the
+@rem  "License"); you may not use this file except in compliance
+@rem  with the License.  You may obtain a copy of the License at
+@rem
+@rem    http://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem  Unless required by applicable law or agreed to in writing,
+@rem  software distributed under the License is distributed on an
+@rem  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@rem  KIND, either express or implied.  See the License for the
+@rem  specific language governing permissions and limitations
+@rem  under the License.
+@rem
+
+set DEBUG=
+set args=%*
+for %%a in (%*) do (
+  if -D == %%a (
+    set DEBUG=-Xdebug -Xrunjdwp:transport=dt_socket,address=8011,server=y,suspend=n
+    set args=%args:-D=%
+  )
+)
+
+java %DEBUG% ^
+-classpath target\lib\* ^
+-DKERBY_LOGFILE=kpasswdClient ^
+org.apache.kerby.kerberos.kerb.admin.PasswdClientTool %args%
\ No newline at end of file
diff --git a/kerby-dist/kdc-dist/bin/kpasswdClient.sh b/kerby-dist/kdc-dist/bin/kpasswdClient.sh
new file mode 100644
index 0000000..a59e3d6
--- /dev/null
+++ b/kerby-dist/kdc-dist/bin/kpasswdClient.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+
+# 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.
+
+DEBUG=
+args=
+for var in $*; do
+  if [ X"$var" = X"-D" ]; then
+    DEBUG="-Xdebug -Xrunjdwp:transport=dt_socket,address=8011,server=y,suspend=n"
+  else
+    args="$args $var"
+  fi
+done
+
+java $DEBUG \
+-classpath target/lib/*:. \
+-DKERBY_LOGFILE=kpasswdClient \
+org.apache.kerby.kerberos.kerb.admin.PasswdClientTool $args
\ No newline at end of file
diff --git a/kerby-dist/kdc-dist/bin/kpasswdServer.cmd b/kerby-dist/kdc-dist/bin/kpasswdServer.cmd
new file mode 100644
index 0000000..27e091a
--- /dev/null
+++ b/kerby-dist/kdc-dist/bin/kpasswdServer.cmd
@@ -0,0 +1,32 @@
+@echo off
+@rem  Licensed to the Apache Software Foundation (ASF) under one
+@rem  or more contributor license agreements.  See the NOTICE file
+@rem  distributed with this work for additional information
+@rem  regarding copyright ownership.  The ASF licenses this file
+@rem  to you under the Apache License, Version 2.0 (the
+@rem  "License"); you may not use this file except in compliance
+@rem  with the License.  You may obtain a copy of the License at
+@rem
+@rem    http://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem  Unless required by applicable law or agreed to in writing,
+@rem  software distributed under the License is distributed on an
+@rem  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@rem  KIND, either express or implied.  See the License for the
+@rem  specific language governing permissions and limitations
+@rem  under the License.
+@rem
+
+set DEBUG=
+set args=%*
+for %%a in (%*) do (
+  if -D == %%a (
+    set DEBUG=-Xdebug -Xrunjdwp:transport=dt_socket,address=8010,server=y,suspend=n
+    set args=%args:-D=%
+  )
+)
+
+java %DEBUG% ^
+-classpath target\lib\* ^
+-DKERBY_LOGFILE=kpasswdServer ^
+org.apache.kerby.kerberos.kerb.admin.server.PasswdServerInit %args%
diff --git a/kerby-dist/kdc-dist/bin/kpasswdServer.sh b/kerby-dist/kdc-dist/bin/kpasswdServer.sh
new file mode 100644
index 0000000..97feb41
--- /dev/null
+++ b/kerby-dist/kdc-dist/bin/kpasswdServer.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+
+# 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.
+
+DEBUG=
+args=
+for var in $*; do
+  if [ X"$var" = X"-D" ]; then
+    DEBUG="-Xdebug -Xrunjdwp:transport=dt_socket,address=8010,server=y,suspend=n"
+  else
+    args="$args $var"
+  fi
+done
+
+java $DEBUG \
+-classpath target/lib/*:. \
+-DKERBY_LOGFILE=kpasswdServer \
+org.apache.kerby.kerberos.kerb.admin.server.PasswdServerInit $args
\ No newline at end of file
diff --git a/kerby-dist/kdc-dist/conf/kpasswdClient.conf b/kerby-dist/kdc-dist/conf/kpasswdClient.conf
new file mode 100644
index 0000000..ea59d8b
--- /dev/null
+++ b/kerby-dist/kdc-dist/conf/kpasswdClient.conf
@@ -0,0 +1,20 @@
+#
+# 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.
+#
+[libdefaults]
+default_realm = TEST.COM
+admin_port = 65418
diff --git a/kerby-dist/kdc-dist/conf/kpasswdServer.conf b/kerby-dist/kdc-dist/conf/kpasswdServer.conf
new file mode 100644
index 0000000..ea59d8b
--- /dev/null
+++ b/kerby-dist/kdc-dist/conf/kpasswdServer.conf
@@ -0,0 +1,20 @@
+#
+# 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.
+#
+[libdefaults]
+default_realm = TEST.COM
+admin_port = 65418
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/PasswdClientTool.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/PasswdClientTool.java
new file mode 100644
index 0000000..cdceb2d
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/PasswdClientTool.java
@@ -0,0 +1,88 @@
+/**
+ *  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.kerby.kerberos.kerb.admin;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.PasswdClient;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.PasswdConfig;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.PasswdHandler;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.PasswdUtil;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.impl.DefaultPasswdHandler;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.request.PasswdRequest;
+import org.apache.kerby.kerberos.kerb.transport.KrbNetwork;
+import org.apache.kerby.kerberos.kerb.transport.KrbTransport;
+import org.apache.kerby.kerberos.kerb.transport.TransportPair;
+import org.apache.kerby.util.OSUtil;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * A running tool for password client.
+ */
+public class PasswdClientTool {
+    private static final String USAGE = (OSUtil.isWindows()
+        ? "Usage: bin\\kpasswdClient.cmd" : "Usage: sh bin/kpasswdClient.sh")
+        + " <conf-file>\n"
+        + "\tExample:\n"
+        + "\t\t"
+        + (OSUtil.isWindows()
+        ? "bin\\kpasswdClient.cmd" : "sh bin/kpasswdClient.sh")
+        + " conf\n";
+
+    private static final String LEGAL_COMMANDS = "Legal functions are remaining to construct...\n";
+
+    public static void main(String[] args) throws KrbException {
+
+        if (args.length != 1) {
+            System.err.println(USAGE);
+            System.exit(1);
+        }
+
+        String confDirPath = args[0];
+        PasswdClient passwdClient = new PasswdClient(new File(confDirPath));
+        PasswdConfig passwdConfig = passwdClient.getPasswdConfig();
+
+        passwdClient.setAdminRealm(passwdConfig.getAdminRealm());
+        passwdClient.setAllowTcp(true);
+        passwdClient.setAllowUdp(true);
+        passwdClient.setAdminTcpPort(passwdConfig.getAdminPort());
+        passwdClient.setAdminUdpPort(passwdConfig.getAdminPort());
+
+        passwdClient.init();
+        System.out.println("password client init successful!");
+        System.out.print(LEGAL_COMMANDS);
+
+        PasswdHandler passwdHandler = new DefaultPasswdHandler();
+        PasswdRequest passwdRequest = new PasswdRequest();
+
+        TransportPair tpair = PasswdUtil.getTransportPair(passwdClient.getSetting());
+        KrbNetwork network = new KrbNetwork();
+        network.setSocketTimeout(passwdClient.getSetting().getTimeout());
+        KrbTransport transport;
+        try {
+            transport = network.connect(tpair);
+        } catch (IOException e) {
+            throw new KrbException("Failed to create transport", e);
+        }
+        passwdRequest.setTransport(transport);
+        passwdHandler.handleRequest(passwdRequest);
+    }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdClient.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdClient.java
new file mode 100644
index 0000000..6861fa7
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdClient.java
@@ -0,0 +1,155 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.kpasswd;
+
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.impl.DefaultInternalPasswdClient;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.impl.InternalPasswdClient;
+
+import java.io.File;
+
+/**
+ * A Krb client API for applications to interact with KDC
+ */
+public class PasswdClient {
+
+    private final PasswdConfig passwdConfig;
+    private final KOptions commonOptions;
+    private final PasswdSetting passwdSetting;
+
+    private InternalPasswdClient innerClient;
+
+    /**
+     * Default constructor.
+     * @throws KrbException e
+     */
+    public PasswdClient() throws KrbException {
+        this.passwdConfig = PasswdUtil.getDefaultConfig();
+        this.commonOptions = new KOptions();
+        this.passwdSetting = new PasswdSetting(commonOptions, passwdConfig);
+    }
+
+    /**
+     * Construct with prepared PasswdConfig.
+     * @param passwdConfig The krb config
+     */
+    public PasswdClient(PasswdConfig passwdConfig) {
+        this.passwdConfig = passwdConfig;
+        this.commonOptions = new KOptions();
+        this.passwdSetting = new PasswdSetting(commonOptions, passwdConfig);
+    }
+
+    /**
+     * Constructor with conf dir
+     * @param confDir The conf dir
+     * @throws KrbException e
+     */
+    public PasswdClient(File confDir) throws KrbException {
+        this.commonOptions = new KOptions();
+        this.passwdConfig = PasswdUtil.getConfig(confDir);
+        this.passwdSetting = new PasswdSetting(commonOptions, passwdConfig);
+    }
+    
+    /**
+     * Set KDC realm for ticket request
+     * @param realm The realm
+     */
+    public void setAdminRealm(String realm) {
+        commonOptions.add(PasswdOption.ADMIN_REALM, realm);
+    }
+
+    /**
+     * Set Admin Server host.
+     * @param kdcHost The kdc host
+     */
+    public void setKdcHost(String kdcHost) {
+        commonOptions.add(PasswdOption.ADMIN_HOST, kdcHost);
+    }
+
+    /**
+     * Set Admin Server tcp port.
+     * @param kdcTcpPort The kdc tcp port
+     */
+    public void setAdminTcpPort(int kdcTcpPort) {
+        if (kdcTcpPort < 1) {
+            throw new IllegalArgumentException("Invalid port");
+        }
+        commonOptions.add(PasswdOption.ADMIN_TCP_PORT, kdcTcpPort);
+        setAllowTcp(true);
+    }
+
+    /**
+     * Set to allow UDP or not.
+     * @param allowUdp true if allow udp
+     */
+    public void setAllowUdp(boolean allowUdp) {
+        commonOptions.add(PasswdOption.ALLOW_UDP, allowUdp);
+    }
+
+    /**
+     * Set to allow TCP or not.
+     * @param allowTcp true if allow tcp
+     */
+    public void setAllowTcp(boolean allowTcp) {
+        commonOptions.add(PasswdOption.ALLOW_TCP, allowTcp);
+    }
+
+    /**
+     * Set Admin Server udp port. Only makes sense when allowUdp is set.
+     * @param adminUdpPort The kdc udp port
+     */
+    public void setAdminUdpPort(int adminUdpPort) {
+        if (adminUdpPort < 1) {
+            throw new IllegalArgumentException("Invalid port");
+        }
+        commonOptions.add(PasswdOption.ADMIN_UDP_PORT, adminUdpPort);
+        setAllowUdp(true);
+    }
+
+    /**
+     * Set time out for connection
+     * @param timeout in seconds
+     */
+    public void setTimeout(int timeout) {
+        commonOptions.add(PasswdOption.CONN_TIMEOUT, timeout);
+    }
+
+    /**
+     * Init the client.
+     * @throws KrbException e
+     */
+    public void init() throws KrbException {
+        innerClient = new DefaultInternalPasswdClient(passwdSetting);
+        innerClient.init();
+    }
+
+    /**
+     * Get krb client settings from options and configs.
+     * @return setting
+     */
+    public PasswdSetting getSetting() {
+        return passwdSetting;
+    }
+
+    public PasswdConfig getPasswdConfig() {
+        return passwdConfig;
+    }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdConfig.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdConfig.java
new file mode 100644
index 0000000..583ccf6
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdConfig.java
@@ -0,0 +1,120 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.kpasswd;
+
+import org.apache.kerby.kerberos.kerb.common.Krb5Conf;
+
+/**
+ * Kerb client side configuration API.
+ */
+public class PasswdConfig extends Krb5Conf {
+    private static final String LIBDEFAULT = "libdefaults";
+
+    public boolean enableDebug() {
+        return getBoolean(PasswdConfigKey.KRB_DEBUG, true, LIBDEFAULT);
+    }
+
+    /**
+     * Get KDC host name
+     *
+     * @return The kdc host
+     */
+    public String getAdminHost() {
+        return getString(
+            PasswdConfigKey.ADMIN_HOST, true, LIBDEFAULT);
+    }
+
+    /**
+     * Get KDC port, as both TCP and UDP ports
+     *
+     * @return The kdc host
+     */
+    public int getAdminPort() {
+        Integer kdcPort = getInt(PasswdConfigKey.ADMIN_PORT, true, LIBDEFAULT);
+        if (kdcPort != null) {
+            return kdcPort.intValue();
+        }
+        return -1;
+    }
+
+    /**
+     * Get KDC TCP port
+     *
+     * @return The kdc tcp port
+     */
+    public int getAdminTcpPort() {
+        Integer kdcPort = getInt(PasswdConfigKey.ADMIN_TCP_PORT, true, LIBDEFAULT);
+        if (kdcPort != null && kdcPort > 0) {
+            return kdcPort.intValue();
+        }
+        return getAdminPort();
+    }
+
+    /**
+     * Is to allow UDP for KDC
+     *
+     * @return true to allow UDP, false otherwise
+     */
+    public boolean allowUdp() {
+        return getBoolean(PasswdConfigKey.ADMIN_ALLOW_UDP, true, LIBDEFAULT)
+                || getInt(PasswdConfigKey.ADMIN_UDP_PORT, true, LIBDEFAULT) != null
+            || getInt(PasswdConfigKey.ADMIN_PORT, false, LIBDEFAULT) != null;
+    }
+
+    /**
+     * Is to allow TCP for KDC
+     *
+     * @return true to allow TCP, false otherwise
+     */
+    public boolean allowTcp() {
+        return getBoolean(PasswdConfigKey.ADMIN_ALLOW_TCP, true, LIBDEFAULT)
+                || getInt(PasswdConfigKey.ADMIN_TCP_PORT, true, LIBDEFAULT) != null
+            || getInt(PasswdConfigKey.ADMIN_PORT, false, LIBDEFAULT) != null;
+    }
+
+    /**
+     * Get KDC UDP port
+     *
+     * @return The kdc udp port
+     */
+    public int getAdminUdpPort() {
+        Integer kdcPort = getInt(PasswdConfigKey.ADMIN_UDP_PORT, true, LIBDEFAULT);
+        if (kdcPort != null && kdcPort > 0) {
+            return kdcPort.intValue();
+        }
+        return getAdminPort();
+    }
+
+    /**
+     * Get KDC realm.
+     * @return The kdc realm
+     */
+    public String getAdminRealm() {
+        String realm = getString(PasswdConfigKey.ADMIN_REALM, false, LIBDEFAULT);
+        if (realm == null) {
+            realm = getString(PasswdConfigKey.DEFAULT_REALM, false, LIBDEFAULT);
+            if (realm == null) {
+                realm = (String) PasswdConfigKey.ADMIN_REALM.getDefaultValue();
+            }
+        }
+
+        return realm;
+    }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdConfigKey.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdConfigKey.java
new file mode 100644
index 0000000..b963076
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdConfigKey.java
@@ -0,0 +1,55 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.kpasswd;
+
+import org.apache.kerby.config.ConfigKey;
+
+public enum PasswdConfigKey implements ConfigKey {
+    KRB_DEBUG(true),
+    ADMIN_HOST("localhost"),
+    ADMIN_PORT(null),
+    ADMIN_ALLOW_UDP(true),
+    ADMIN_ALLOW_TCP(true),
+    ADMIN_UDP_PORT(null),
+    ADMIN_TCP_PORT(null),
+    ADMIN_DOMAIN("example.com"),
+    DEFAULT_REALM(null),
+    ADMIN_REALM("EXAMPLE.COM");
+
+    private Object defaultValue;
+
+    PasswdConfigKey() {
+        this.defaultValue = null;
+    }
+
+    PasswdConfigKey(Object defaultValue) {
+        this.defaultValue = defaultValue;
+    }
+
+    @Override
+    public String getPropertyKey() {
+        return name().toLowerCase();
+    }
+
+    @Override
+    public Object getDefaultValue() {
+        return this.defaultValue;
+    }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdContext.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdContext.java
new file mode 100644
index 0000000..16837d9
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdContext.java
@@ -0,0 +1,49 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.kpasswd;
+
+public class PasswdContext {
+
+    private PasswdSetting passwdSetting;
+
+    /**
+     * Init with krbsetting.
+     * @param passwdSetting The krb setting
+     */
+    public void init(PasswdSetting passwdSetting) {
+        this.passwdSetting = passwdSetting;
+    }
+
+    /**
+     * Get krbsetting.
+     * @return The krb setting
+     */
+    public PasswdSetting getPasswdSetting() {
+        return passwdSetting;
+    }
+
+    /**
+     * Get krbconfig.
+     * @return The krb config
+     */
+    public PasswdConfig getConfig() {
+        return passwdSetting.getPasswdConfig();
+    }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdHandler.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdHandler.java
new file mode 100644
index 0000000..8f07bbc
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdHandler.java
@@ -0,0 +1,84 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.kpasswd;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.request.PasswdRequest;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public abstract class PasswdHandler {
+
+    /**
+     * Init with krbcontext.
+     *
+     * @param context The krbcontext
+     */
+    public void init(PasswdContext context) {
+
+    }
+
+    /**
+     * Handle the password server request.
+     *
+     * @param passwdRequest The password server request
+     * @throws KrbException e
+     */
+    public void handleRequest(PasswdRequest passwdRequest) throws KrbException {
+        passwdRequest.process();
+
+        String request = "Client request change password.";
+        ByteBuffer requestMessage = ByteBuffer.allocate(request.length() + 4);
+        requestMessage.putInt(request.length());
+        requestMessage.put(request.getBytes());
+        requestMessage.flip();
+
+        try {
+            sendMessage(passwdRequest, requestMessage);
+        } catch (IOException e) {
+            throw new KrbException("sending message failed", e);
+        }
+    }
+
+    /**
+     * Process the response message from kdc.
+     *
+     * @param passwdRequest The kpasswd request
+     * @param responseMessage The message from kdc
+     * @throws KrbException e
+     */
+    public void onResponseMessage(PasswdRequest passwdRequest,
+                                  ByteBuffer responseMessage) throws KrbException {
+        String message = new String(responseMessage.array());
+        System.out.println("client receive message: ");
+        System.out.println(message);
+    }
+
+    /**
+     * Send message to password server.
+     *
+     * @param passwdRequest The change password request
+     * @param requestMessage The request message to password server
+     * @throws IOException e
+     */
+    protected abstract void sendMessage(PasswdRequest passwdRequest,
+                                        ByteBuffer requestMessage) throws IOException;
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdOption.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdOption.java
new file mode 100644
index 0000000..228733b
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdOption.java
@@ -0,0 +1,102 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.kpasswd;
+
+import org.apache.kerby.KOption;
+import org.apache.kerby.KOptionInfo;
+import org.apache.kerby.KOptionType;
+
+/**
+ * This defines all the options that come across the client side.
+ */
+public enum PasswdOption implements KOption {
+    NONE(null),
+
+    ADMIN_REALM(new KOptionInfo("admin-realm", "kdc realm",
+        KOptionType.STR)),
+    ADMIN_HOST(new KOptionInfo("admin-host", "kdc host",
+        KOptionType.STR)),
+    ADMIN_TCP_PORT(new KOptionInfo("admin-tcp-port", "kdc tcp port",
+        KOptionType.INT)),
+    ALLOW_UDP(new KOptionInfo("allow-udp", "allow udp",
+        KOptionType.BOOL)),
+    ALLOW_TCP(new KOptionInfo("allow-tcp", "allow tcp",
+        KOptionType.BOOL)),
+    ADMIN_UDP_PORT(new KOptionInfo("admin-udp-port", "kdc udp port",
+        KOptionType.INT)),
+    CONN_TIMEOUT(new KOptionInfo("conn-timeout", "connection timeout",
+        KOptionType.INT)),
+
+    LIFE_TIME(new KOptionInfo("life-time", "life time",
+        KOptionType.INT)),
+    START_TIME(new KOptionInfo("start-time", "start time",
+        KOptionType.INT)),
+    RENEWABLE_TIME(new KOptionInfo("renewable_lifetime", "renewable lifetime",
+        KOptionType.INT)),
+    INCLUDE_ADDRESSES(new KOptionInfo("include_addresses",
+        "include addresses")),
+    AS_ENTERPRISE_PN(new KOptionInfo("as-enterprise-pn",
+        "client is enterprise principal name")),
+    CLIENT_PRINCIPAL(new KOptionInfo("client-principal", "Client principal",
+        KOptionType.STR)),
+
+    USE_PASSWD(new KOptionInfo("using-password", "using password")),
+    USER_PASSWD(new KOptionInfo("user-passwd", "User plain password")),
+
+    USE_KEYTAB(new KOptionInfo("use-keytab", "use keytab")),
+    USE_DFT_KEYTAB(new KOptionInfo("use-dft-keytab", "use default client keytab (with -k)")),
+    KEYTAB_FILE(new KOptionInfo("keytab-file", "filename of keytab to use",
+        KOptionType.FILE)),
+
+    KRB5_CACHE(new KOptionInfo("krb5-cache", "K5 cache name",
+        KOptionType.FILE)),
+    SERVICE_PRINCIPAL(new KOptionInfo("service-principal", "service principal",
+        KOptionType.STR)),
+    SERVER_PRINCIPAL(new KOptionInfo("admin-principal", "admin principal",
+        KOptionType.STR)),
+    ARMOR_CACHE(new KOptionInfo("armor-cache", "armor credential cache",
+        KOptionType.STR)),
+    USE_TGT(new KOptionInfo("use-tgt", "use tgt to get service ticket",
+        KOptionType.OBJ)),
+    CONF_DIR(new KOptionInfo("-conf", "conf dir", KOptionType.DIR));
+
+    private final KOptionInfo optionInfo;
+
+    PasswdOption(KOptionInfo optionInfo) {
+        this.optionInfo = optionInfo;
+    }
+
+    @Override
+    public KOptionInfo getOptionInfo() {
+        return optionInfo;
+    }
+
+    public static PasswdOption fromOptionName(String optionName) {
+        if (optionName != null) {
+            for (PasswdOption ko : values()) {
+                if (ko.optionInfo != null
+                    && ko.optionInfo.getName().equals(optionName)) {
+                    return ko;
+                }
+            }
+        }
+        return NONE;
+    }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdSetting.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdSetting.java
new file mode 100644
index 0000000..56aa030
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdSetting.java
@@ -0,0 +1,129 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.kpasswd;
+
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
+
+/**
+ * Admin client setting that combines common options and client config.
+ */
+public class PasswdSetting {
+    private final KOptions commonOptions;
+    private final PasswdConfig passwdConfig;
+
+    public PasswdSetting(KOptions commonOptions, PasswdConfig config) {
+        this.commonOptions = commonOptions;
+        this.passwdConfig = config;
+    }
+
+    public PasswdSetting(PasswdConfig config) {
+        this.commonOptions = new KOptions();
+        this.passwdConfig = config;
+    }
+
+    public PasswdConfig getPasswdConfig() {
+        return passwdConfig;
+    }
+
+    public String getKdcRealm() {
+        String kdcRealm = commonOptions.getStringOption(PasswdOption.ADMIN_REALM);
+        if (kdcRealm == null || kdcRealm.isEmpty()) {
+            kdcRealm = passwdConfig.getAdminRealm();
+        }
+        return kdcRealm;
+    }
+
+    public String getKdcHost() {
+        String kdcHost = commonOptions.getStringOption(PasswdOption.ADMIN_HOST);
+        if (kdcHost == null) {
+            return passwdConfig.getAdminHost();
+        }
+        return kdcHost;
+    }
+
+    /**
+     * Check kdc tcp setting and see if any bad.
+     * @return valid tcp port or -1 if not allowTcp
+     * @throws KrbException e
+     */
+    public int checkGetKdcTcpPort() throws KrbException {
+        if (allowTcp()) {
+            int kdcPort = getKdcTcpPort();
+            if (kdcPort < 1) {
+                throw new KrbException("KDC tcp port isn't set or configured");
+            }
+            return kdcPort;
+        }
+        return -1;
+    }
+
+    /**
+     * Check kdc udp setting and see if any bad.
+     * @return valid udp port or -1 if not allowUdp
+     * @throws KrbException e
+     */
+    public int checkGetKdcUdpPort() throws KrbException {
+        if (allowUdp()) {
+            int kdcPort = getKdcUdpPort();
+            if (kdcPort < 1) {
+                throw new KrbException("KDC udp port isn't set or configured");
+            }
+            return kdcPort;
+        }
+        return -1;
+    }
+
+    public int getKdcTcpPort() {
+        int tcpPort = commonOptions.getIntegerOption(PasswdOption.ADMIN_TCP_PORT);
+        if (tcpPort > 0) {
+            return tcpPort;
+        }
+        return passwdConfig.getAdminTcpPort();
+    }
+
+    public boolean allowUdp() {
+        Boolean allowUdp = commonOptions.getBooleanOption(
+                PasswdOption.ALLOW_UDP, passwdConfig.allowUdp());
+        return allowUdp;
+    }
+
+    public boolean allowTcp() {
+        Boolean allowTcp = commonOptions.getBooleanOption(
+                PasswdOption.ALLOW_TCP, passwdConfig.allowTcp());
+        return allowTcp;
+    }
+
+    public int getKdcUdpPort() {
+        int udpPort = commonOptions.getIntegerOption(PasswdOption.ADMIN_UDP_PORT);
+        if (udpPort > 0) {
+            return udpPort;
+        }
+        return passwdConfig.getAdminUdpPort();
+    }
+
+    public int getTimeout() {
+        int timeout = commonOptions.getIntegerOption(PasswdOption.CONN_TIMEOUT);
+        if (timeout > 0) {
+            return timeout;
+        }
+        return 1000; // by default
+    }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdUtil.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdUtil.java
new file mode 100644
index 0000000..8843b74
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/PasswdUtil.java
@@ -0,0 +1,127 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.kpasswd;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.transport.TransportPair;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.Map;
+
+public final class PasswdUtil {
+    private PasswdUtil() { }
+
+    private static final String KRB5_FILE_NAME = "kpasswdClient.conf";
+    private static final String KRB5_ENV_NAME = "KRB5_CONFIG";
+
+    /**
+     * Load krb5.conf from specified conf dir.
+     * @param confDir The conf dir
+     * @return PasswdConfig
+     * @throws KrbException e
+     */
+    public static PasswdConfig getConfig(File confDir) throws KrbException {
+        File confFile = new File(confDir, KRB5_FILE_NAME);
+        if (!confFile.exists()) {
+            throw new KrbException(KRB5_FILE_NAME + " not found");
+        }
+
+        if (confFile != null && confFile.exists()) {
+            PasswdConfig adminConfig = new PasswdConfig();
+            try {
+                adminConfig.addKrb5Config(confFile);
+                return adminConfig;
+            } catch (IOException e) {
+                throw new KrbException("Failed to load krb config "
+                        + confFile.getAbsolutePath());
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Load default krb5.conf
+     * @return The PasswdConfig
+     * @throws KrbException e
+     */
+    public static PasswdConfig getDefaultConfig() throws KrbException {
+        File confFile = null;
+        File confDir;
+        String tmpEnv;
+
+        try {
+            Map<String, String> mapEnv = System.getenv();
+            tmpEnv = mapEnv.get(KRB5_ENV_NAME);
+        } catch (SecurityException e) {
+            tmpEnv = null;
+        }
+        if (tmpEnv != null) {
+            confFile = new File(tmpEnv);
+            if (!confFile.exists()) {
+                throw new KrbException("krb5 conf not found. Invalid env "
+                        + KRB5_ENV_NAME);
+            }
+        } else {
+            confDir = new File("/etc/"); // for Linux. TODO: fix for Win etc.
+            if (confDir.exists()) {
+                confFile = new File(confDir, "krb5.conf");
+            }
+        }
+
+        PasswdConfig adminConfig = new PasswdConfig();
+        if (confFile != null && confFile.exists()) {
+            try {
+                adminConfig.addKrb5Config(confFile);
+            } catch (IOException e) {
+                throw new KrbException("Failed to load krb config "
+                        + confFile.getAbsolutePath());
+            }
+        }
+
+        return adminConfig;
+    }
+
+    /**
+     * Get KDC network transport addresses according to krb client setting.
+     * @param setting The krb setting
+     * @return UDP and TCP addresses pair
+     * @throws KrbException e
+     */
+    public static TransportPair getTransportPair(
+            PasswdSetting setting) throws KrbException {
+        TransportPair result = new TransportPair();
+
+        int tcpPort = setting.checkGetKdcTcpPort();
+        if (tcpPort > 0) {
+            result.tcpAddress = new InetSocketAddress(
+                    setting.getKdcHost(), tcpPort);
+        }
+        int udpPort = setting.checkGetKdcUdpPort();
+        if (udpPort > 0) {
+            result.udpAddress = new InetSocketAddress(
+                    setting.getKdcHost(), udpPort);
+        }
+
+        return result;
+    }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/impl/AbstractInternalPasswdClient.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/impl/AbstractInternalPasswdClient.java
new file mode 100644
index 0000000..675c93e
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/impl/AbstractInternalPasswdClient.java
@@ -0,0 +1,71 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.kpasswd.impl;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.PasswdSetting;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.PasswdContext;
+
+/**
+ * A krb client API for applications to interact with KDC
+ */
+public abstract class AbstractInternalPasswdClient
+                                    implements InternalPasswdClient {
+    private PasswdContext context;
+    private final PasswdSetting passwdSetting;
+
+    public AbstractInternalPasswdClient(PasswdSetting passwdSetting) {
+        this.passwdSetting = passwdSetting;
+    }
+
+    protected PasswdContext getContext() {
+        return context;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public PasswdSetting getSetting() {
+        return passwdSetting;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void init() throws KrbException {
+        context = new PasswdContext();
+        context.init(passwdSetting);
+    }
+
+    /**
+     * Fix principal name.
+     *
+     * @param principal The principal name
+     * @return The fixed principal
+     */
+    protected String fixPrincipal(String principal) {
+        if (!principal.contains("@")) {
+            principal += "@" + passwdSetting.getKdcRealm();
+        }
+        return principal;
+    }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/impl/DefaultInternalPasswdClient.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/impl/DefaultInternalPasswdClient.java
new file mode 100644
index 0000000..561de7c
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/impl/DefaultInternalPasswdClient.java
@@ -0,0 +1,64 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.kpasswd.impl;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.PasswdSetting;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.PasswdUtil;
+import org.apache.kerby.kerberos.kerb.transport.KrbNetwork;
+import org.apache.kerby.kerberos.kerb.transport.KrbTransport;
+import org.apache.kerby.kerberos.kerb.transport.TransportPair;
+
+import java.io.IOException;
+
+/**
+ * A default krb client implementation.
+ */
+public class DefaultInternalPasswdClient extends AbstractInternalPasswdClient {
+
+    private DefaultPasswdHandler passwdHandler;
+    private KrbTransport transport;
+
+    public DefaultInternalPasswdClient(PasswdSetting krbSetting) {
+        super(krbSetting);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void init() throws KrbException {
+        super.init();
+
+        this.passwdHandler = new DefaultPasswdHandler();
+        passwdHandler.init(getContext());
+
+        TransportPair tpair = PasswdUtil.getTransportPair(getSetting());
+        KrbNetwork network = new KrbNetwork();
+        network.setSocketTimeout(getSetting().getTimeout());
+        try {
+            transport = network.connect(tpair);
+        } catch (IOException e) {
+            throw new KrbException("Failed to create transport", e);
+        } finally {
+            transport.release();
+        }
+    }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/impl/DefaultPasswdHandler.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/impl/DefaultPasswdHandler.java
new file mode 100644
index 0000000..dc82983
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/impl/DefaultPasswdHandler.java
@@ -0,0 +1,61 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.kpasswd.impl;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.PasswdHandler;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.request.PasswdRequest;
+import org.apache.kerby.kerberos.kerb.transport.KrbTransport;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class DefaultPasswdHandler extends PasswdHandler {
+
+    /**
+     * Client handle request.
+     * Use super.handleRequest to send message,
+     * and use this.handleRequest to receive message.
+     */
+    @Override
+    public void handleRequest(PasswdRequest passwdRequest) throws KrbException {
+        /** super is used to send messsage*/
+        super.handleRequest(passwdRequest);
+
+        KrbTransport transport = passwdRequest.getTransport();
+        ByteBuffer receiveMessage = null;
+        try {
+            receiveMessage = transport.receiveMessage();
+        } catch (IOException e) {
+            throw new KrbException("Client receives response message failed.");
+        }
+        super.onResponseMessage(passwdRequest, receiveMessage);
+    }
+
+    /**
+     * Override super's sendMessage method.
+     */
+    @Override
+    protected void sendMessage(PasswdRequest passwdRequest,
+                               ByteBuffer requestMessage) throws IOException {
+        KrbTransport transport = passwdRequest.getTransport();
+        transport.sendMessage(requestMessage);
+    }
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/impl/InternalPasswdClient.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/impl/InternalPasswdClient.java
new file mode 100644
index 0000000..55f30c2
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/impl/InternalPasswdClient.java
@@ -0,0 +1,41 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.kpasswd.impl;
+
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.kpasswd.PasswdSetting;
+
+/**
+ * An internal krb client interface.
+ */
+public interface InternalPasswdClient {
+
+    /**
+     * Init with all the necessary options.
+     * @throws KrbException e
+     */
+    void init() throws KrbException;
+
+    /**
+     * Get krb client settings.
+     * @return setting
+     */
+    PasswdSetting getSetting();
+}
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/request/PasswdRequest.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/request/PasswdRequest.java
new file mode 100644
index 0000000..7f8868c
--- /dev/null
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kpasswd/request/PasswdRequest.java
@@ -0,0 +1,42 @@
+/**
+ *  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.kerby.kerberos.kerb.admin.kpasswd.request;
+
+import org.apache.kerby.kerberos.kerb.transport.KrbTransport;
+
+/**
+ * There is only one kind of password request,
+ * that is the change password request.
+ */
+public class PasswdRequest {
+    private KrbTransport transport;
+
+    public void setTransport(KrbTransport transport) {
+        this.transport = transport;
+    }
+
+    public KrbTransport getTransport() {
+        return transport;
+    }
+
+    public void process() {
+
+    }
+}
\ No newline at end of file