Index: /branches/rel_avx_2_7_2/src/backend/sys_cmd.c
===================================================================
--- /branches/rel_avx_2_7_2/src/backend/sys_cmd.c	(revision 8849)
+++ /branches/rel_avx_2_7_2/src/backend/sys_cmd.c	(working copy)
@@ -40,6 +40,7 @@
 #include <time.h>
 #include <unistd.h>
 #include <inttypes.h>
+#include <stdint.h>
 #include <poll.h>
 #include <sys/ioctl.h>
 #include <termios.h>
@@ -57,6 +58,9 @@
 #include <libxml/xpath.h>
 #include <libxml/xpathInternals.h>
 
+#include <openssl/aes.h>
+#include <openssl/evp.h>
+
 #include <feactl/avx_ul.h>
 #include <feactl/apv_feactl.h>
 #include <vtch/vtch.h>
@@ -7017,3 +7021,332 @@
 }
 
 #undef AVX_IF_DESC_CMD_LENGTH
+
+#define _AVX_EXAUTH_STR_LEN 64
+
+enum {
+    AVX_EXAUTH_OFF = 0,
+    AVX_EXAUTH_ON,
+};
+
+typedef struct {
+    uint8_t status;
+    char host[_AVX_EXAUTH_STR_LEN];
+    uint16_t port;
+    char secret[_AVX_EXAUTH_STR_LEN];
+} __avx_exauth_conf_t;
+
+static __avx_exauth_conf_t exauth_conf = {
+    .status = AVX_EXAUTH_OFF,
+    .host = "",
+    .port = 0,
+    .secret = "",
+};
+
+#define AVX_NSS_CONF "/etc/nsswitch.conf"
+
+/* The PAM stacks with
+ * RADIUS authentication enabled appear like the following:
+ *
+ *     <type> [success=done default=ignore] pam_radius_auth.so
+ *     <type> [success=done default=bad] pam_unix.so
+ *
+ * With this setting, PAM will run the following flow:
+ *     1. First check RADIUS users.
+ *         - If user is met in RADIUS, return to the application
+ *           (done by "success=done").
+ *         - If not, go to the next step (done by "default=ignore").
+ *     2. Check UNIX users.
+ *         - It user is met in UNIX, return to the application.
+ *         - If not, abort the whole PAM authentication
+ *           (done by "default=bad").
+ *
+ * As a counterpart, the PAM stacks with RADIUS authentication
+ * disabled appear like the following:
+ *
+ *     <type> [success=done default=bad] pam_unix.so
+ */
+
+#define AVX_AUTH_PAM "/etc/pam.d/array-common-auth.pam"
+#define AVX_ACCT_PAM "/etc/pam.d/array-common-acct.pam"
+#define _AVX_PAM_FIRST_PASS "[success=done default=ignore]"
+#define _AVX_PAM_LAST_PASS "[success=done default=bad]"
+#define _AVX_PAM_USE_RADIUS "pam_radius_auth.so"
+#define _AVX_PAM_USE_UNIX "pam_unix.so"
+
+#define _AVX_WRITE_PAM_CONF(conf, type, BODY)                                  \
+    do {                                                                       \
+        FILE *fp = fopen(conf, "w");                                           \
+        if (!fp) {                                                             \
+            printf("Cannot open %s PAM conf\n", type);                         \
+            return -1;                                                         \
+        }                                                                      \
+        BODY fclose(fp);                                                       \
+    } while (0)
+
+#define _AVX_WRITE_PASS(type, ctrl, mod)                                       \
+    fprintf(fp, "%s %s %s", type, ctrl, mod)
+
+#define _AVX_WRITE_LF fprintf(fp, "\n")
+
+int exauth_on() {
+	_AVX_WRITE_PAM_CONF(
+        AVX_AUTH_PAM, "auth",
+        _AVX_WRITE_PASS("auth", _AVX_PAM_FIRST_PASS, _AVX_PAM_USE_RADIUS);
+        _AVX_WRITE_LF;
+        _AVX_WRITE_PASS("auth", _AVX_PAM_LAST_PASS, _AVX_PAM_USE_UNIX););
+
+    _AVX_WRITE_PAM_CONF(
+        AVX_ACCT_PAM, "account",
+        _AVX_WRITE_PASS("account", _AVX_PAM_FIRST_PASS, _AVX_PAM_USE_RADIUS);
+        _AVX_WRITE_LF;
+        _AVX_WRITE_PASS("account", _AVX_PAM_LAST_PASS, _AVX_PAM_USE_UNIX););
+
+    /* Activate NSS of RADIUS users */
+    system("sed -i '/^passwd:/s/$/ ato/' " AVX_NSS_CONF);
+    system("sed -i '/^shadow:/s/$/ ato/' " AVX_NSS_CONF);
+
+    sleep(1);
+
+    exauth_conf.status = AVX_EXAUTH_ON;
+
+    return 0;
+}
+
+int exauth_off() {
+    _AVX_WRITE_PAM_CONF(
+        AVX_AUTH_PAM, "auth",
+        _AVX_WRITE_PASS("auth", _AVX_PAM_LAST_PASS, _AVX_PAM_USE_UNIX););
+
+    _AVX_WRITE_PAM_CONF(
+        AVX_ACCT_PAM, "account",
+        _AVX_WRITE_PASS("account", _AVX_PAM_LAST_PASS, _AVX_PAM_USE_UNIX););
+
+    /* Deactivate NSS of RADIUS user */
+    system("sed -i '/^passwd:/s/ ato//g' " AVX_NSS_CONF);
+    system("sed -i '/^shadow:/s/ ato//g' " AVX_NSS_CONF);
+
+    sleep(1);
+
+    exauth_conf.status = AVX_EXAUTH_OFF;
+
+    return 0;
+}
+
+#define _AVX_EXAUTH_ENCRYPT "ENCRYPTED"
+#define AVX_RADIUS_CONF "/etc/pam_radius.conf"
+#define _AVX_RADIUS_TIMEOUT 3
+#define _AVX_EXAUTH_SET_ATTR(h, p, s) \
+    do { \
+        strncpy(exauth_conf.host, h, _AVX_EXAUTH_STR_LEN); \
+        exauth_conf.port = p; \
+        strncpy(exauth_conf.secret, s, _AVX_EXAUTH_STR_LEN); \
+    } while(0)
+
+#define _AVX_AES_BLOCK_SZ 16
+#define _AVX_SECRET_LEN 129
+
+/***********************************************************************
+* This func is for changing server secret from plaintext to ciphertext
+* via AES128 encrypt and base64 encode
+*
+* This function is originated from APV rel_apv_10_7 branch revision 38549.
+*
+* secret_in: server secret in plaintext, max length is _AVX_SECRET_LEN
+* secret_out: server secret in ciphertext, this is looger than secret_in
+*             but shorter than 2 times of _AVX_SECRET_LEN
+*
+************************************************************************/
+
+static int
+encrypt_secret(const unsigned char *secret_in, unsigned char *secret_out)
+{
+        AES_KEY aes_key;
+        unsigned char key[_AVX_AES_BLOCK_SZ];
+        unsigned char iv[_AVX_AES_BLOCK_SZ];
+        unsigned char seed_key[11] = "ARRAYCLICK";
+        unsigned char seed_iv[12] = "ARRAYISBEST";
+        unsigned char temp[2 * _AVX_SECRET_LEN];
+        int len;
+        int i;
+
+        memcpy(temp, secret_in, _AVX_SECRET_LEN);
+        len = strlen((char *)temp) + 1;
+
+        if (len % _AVX_AES_BLOCK_SZ != 0) {
+			len = (len / _AVX_AES_BLOCK_SZ + 1) * _AVX_AES_BLOCK_SZ;
+        }
+
+        for (i = 0; i < _AVX_AES_BLOCK_SZ; i++) {
+                key[i] = seed_key[i % sizeof(seed_key)];
+        }
+
+        for (i = 0; i < _AVX_AES_BLOCK_SZ; i++) {
+                iv[i] = seed_iv[i % sizeof(seed_iv)];
+        }
+
+        if (AES_set_encrypt_key(key, 128, &aes_key) < 0) {
+                return -1;
+        }
+
+        AES_cbc_encrypt(secret_in, temp, len, &aes_key, iv, AES_ENCRYPT);
+
+        EVP_EncodeBlock(secret_out, temp, len);
+
+        return 0;
+}
+
+/***********************************************************************
+* This func is for changing server secret from ciphertext to plaintext
+* via base64 decode and AES128 decrypt
+*
+* This function is originated from APV rel_apv_10_7 branch revision 38549.
+*
+* secret_in: server secret in ciphertext, max length is 4/3 times of
+*            _AVX_SECRET_LEN
+* secret_out: server secret in plaintext, this is shorter than _AVX_SECRET_LEN
+*
+************************************************************************/
+
+static int
+decrypt_secret(const unsigned char *secret_in, unsigned char *secret_out)
+{
+        AES_KEY aes_key;
+        unsigned char key[_AVX_AES_BLOCK_SZ];
+        unsigned char iv[_AVX_AES_BLOCK_SZ];
+        unsigned char seed_key[11] = "ARRAYCLICK";
+        unsigned char seed_iv[12] = "ARRAYISBEST";
+        unsigned char temp[2 * _AVX_SECRET_LEN];
+        int len;
+        int i;
+
+        memcpy(temp, secret_in, 2 * _AVX_SECRET_LEN);
+        temp[2 * _AVX_SECRET_LEN - 1] = '\0';
+        len = strlen((char *)temp);
+
+		if (len > (_AVX_SECRET_LEN / 3 * 4)) {
+                return -1;
+        }
+
+        if (len < 24) {
+                /* encrypted secret is 16 Byte at least, after base64 it is 24 */
+                return -1;
+        }
+
+        len = EVP_DecodeBlock(temp, secret_in, len);
+
+        if (len == -1) {
+                return -1;
+        }
+
+        len -= len % _AVX_AES_BLOCK_SZ;
+
+        for (i = 0; i < _AVX_AES_BLOCK_SZ; i++) {
+                key[i] = seed_key[i % sizeof(seed_key)];
+        }
+
+        for (i = 0; i < _AVX_AES_BLOCK_SZ; i++) {
+                iv[i] = seed_iv[i % sizeof(seed_iv)];
+        }
+
+		if (AES_set_decrypt_key(key, 128, &aes_key) < 0) {
+                return -1;
+        }
+
+        AES_cbc_encrypt(temp, secret_out, len, &aes_key, iv, AES_DECRYPT);
+
+        return 0;
+}
+
+#undef _AVX_AES_BLOCK_SZ
+#undef _AVX_SECRET_LEN
+
+int set_radius_server(
+    char *host,
+    uint16_t port,
+    char *secret,
+    char *encrypt_flag
+) {
+    FILE *fp = fopen(AVX_RADIUS_CONF, "w");
+    if(!fp) {
+        printf("Cannot open RADIUS server config\n");
+        return -1;
+    }
+
+    fprintf(fp, "%s:%d %s %d", host, port, secret, _AVX_RADIUS_TIMEOUT);
+
+    fclose(fp);
+
+    sleep(1);
+
+    _AVX_EXAUTH_SET_ATTR(host, port, secret);
+
+    return 0;
+}
+
+int unset_radius_server() {
+    system("rm -rf " AVX_RADIUS_CONF);
+
+    sleep(1);
+
+    const char *EMPTY_STR = "";
+
+    _AVX_EXAUTH_SET_ATTR(EMPTY_STR, 0, EMPTY_STR);
+
+    return 0;
+}
+
+#define _AVX_EXAUTH_PREFIX "admin aaa"
+#define _AVX_EXAUTH_BUF_LEN 1024
+#define _AVX_EXAUTH_STAT _AVX_EXAUTH_PREFIX " %s\n"
+#define _AVX_EXAUTH_PROPS \
+    _AVX_EXAUTH_PREFIX " server es01 \"%s\" %d \"%s\"\n"
+
+char *write_exauth_conf(void) {
+    char *save_exauth;
+    save_exauth = (char *)malloc(sizeof(char) * _AVX_EXAUTH_BUF_LEN);
+    if(!save_exauth) {
+        printf("System error occurred.\n");
+        return NULL;
+    }
+    bzero(save_exauth, _AVX_EXAUTH_BUF_LEN);
+
+    int len = 0;
+    int ret;
+#define _(fmt, ...) \
+    ret = sprintf( \
+            save_exauth + len, \
+            fmt, \
+            __VA_ARGS__); \
+    len += ret;
+
+    _(_AVX_EXAUTH_STAT, exauth_conf.status == AVX_EXAUTH_OFF ? "off" : "on");
+    _(_AVX_EXAUTH_PROPS, exauth_conf.host, exauth_conf.port, exauth_conf.secret);
+#undef _
+
+    return save_exauth;
+}
+
+int show_exauth_all(void) {
+    /* Show status of external authentication */
+    printf(_AVX_EXAUTH_STAT, exauth_conf.status == AVX_EXAUTH_OFF
+        ? "off" : "on"
+    );
+
+    /* RADIUS server attributes */
+    if(strlen(exauth_conf.host) > 0) {
+        printf(_AVX_EXAUTH_PROPS,
+            exauth_conf.host,
+            exauth_conf.port,
+            "*****"
+        );
+    }
+
+    unsigned char e[2 * _AVX_SECRET_LEN];
+    encrypt_secret((unsigned char *)exauth_conf.secret, e);
+    printf("encrypt: %s\n", e);
+    decrypt_secret(e, e);
+    printf("decrypt: %s\n", e);
+
+    return 0;
+}
Index: /branches/rel_avx_2_7_2/src/backend/sys_tool.h
===================================================================
--- /branches/rel_avx_2_7_2/src/backend/sys_tool.h	(revision 8849)
+++ /branches/rel_avx_2_7_2/src/backend/sys_tool.h	(working copy)
@@ -72,6 +72,10 @@
 extern char* write_system_interactive(void);
 extern char* write_if_shutdown(void);
 extern char* write_if_description(void);
+extern char* write_exauth_conf(void);
+
+extern int show_exauth_all(void);
+
 extern int clear_nameserver(char *ip);
 extern int clear_iphost(void);
 extern int ui_clear_supportip(void);
Index: /branches/rel_avx_2_7_2/src/backend/sys_tool.c
===================================================================
--- /branches/rel_avx_2_7_2/src/backend/sys_tool.c	(revision 8849)
+++ /branches/rel_avx_2_7_2/src/backend/sys_tool.c	(working copy)
@@ -358,6 +358,11 @@
         CMD_NORMAL | CMD_ARRAYOS | CMD_GLOBAL,
         "#interface description"
     },
+    {
+        write_exauth_conf,
+        CMD_NORMAL | CMD_ARRAYOS | CMD_GLOBAL,
+        "#admin aaa configuration"
+    },
     /*last entry is empty*/
     {
         NULL,
Index: /branches/rel_avx_2_7_2/src/generator/commands.pm
===================================================================
--- /branches/rel_avx_2_7_2/src/generator/commands.pm	(revision 8849)
+++ /branches/rel_avx_2_7_2/src/generator/commands.pm	(working copy)
@@ -7239,6 +7239,151 @@
             optional => "NO",
         }, ],
     },
+    {
+        obj_type => "MENU",
+        name => "admin",
+        parent_menu => ".",
+        uniq_name => "root_admin",
+        cmd_attribute => "CMD_ARRAYOS|CMD_NORMAL",
+        user_level => "CLI_LEVEL_CONFIG",
+        help_string => "Administration configuration",
+    },
+    {
+        obj_type => "MENU",
+        name => "aaa",
+        parent_menu => "root_admin",
+        uniq_name => "root_admin_aaa",
+        cmd_attribute => "CMD_ARRAYOS|CMD_NORMAL",
+        user_level => "CLI_LEVEL_CONFIG",
+        help_string => "External authentication configuration",
+    },
+    {
+        obj_type => "MENU",
+        name => "server",
+        parent_menu => "root_admin_aaa",
+        uniq_name => "root_admin_server_aaa",
+        cmd_attribute => "CMD_ARRAYOS|CMD_NORMAL",
+        user_level => "CLI_LEVEL_CONFIG",
+        help_string => "External authentication server configuration",
+    },
+    {
+        obj_type => "ITEM",
+        name => "es01",
+        menu => "root_admin_server_aaa",
+        help_string => "Configure external RADIUS authentication server",
+        cmd_attribute => "CMD_ARRAYOS|CMD_NORMAL|CMD_GLOBAL|CMD_SPECIAL_LOG",
+        user_level => "CLI_LEVEL_CONFIG",
+        function_name => "set_radius_server",
+        function_args => [
+            {
+                type => "STRING",
+                help_string => "Host name or ip address",
+                optional => "NO",
+            },
+            {
+                type => "U16",
+                help_string => "Port",
+                optional => "NO",
+            },
+            {
+                type => "STRING",
+                help_string => "Secret",
+                optional => "YES",
+                default_value => "\"\"",
+            },
+            {
+                type => "STRING",
+                help_string => "",
+                optional => "YES",
+                default_value => "\"\"",
+            },
+        ],
+    },
+    {
+        obj_type => "MENU",
+        name => "admin",
+        parent_menu => "root_no",
+        uniq_name => "root_no_admin",
+        cmd_attribute => "CMD_ARRAYOS|CMD_NORMAL",
+        user_level => "CLI_LEVEL_CONFIG",
+        help_string => "Delete administration configurations",
+    },
+	{
+        obj_type => "MENU",
+        name => "aaa",
+        parent_menu => "root_no_admin",
+        uniq_name => "root_no_admin_aaa_server",
+        cmd_attribute => "CMD_ARRAYOS|CMD_NORMAL",
+        user_level => "CLI_LEVEL_ENABLE",
+        help_string => "Delete external authentication configurations",
+    },
+    {
+        obj_type => "MENU",
+        name => "server",
+        parent_menu => "root_no_admin_aaa_server",
+        uniq_name => "root_no_admin_aaa",
+        help_string => "Delete external authentication server",
+        cmd_attribute => "CMD_ARRAYOS|CMD_NORMAL|CMD_GLOBAL",
+        user_level => "CLI_LEVEL_CONFIG",
+    },
+	{
+        obj_type => "ITEM",
+        name => "es01",
+        menu => "root_no_admin_aaa",
+        help_string => "Delete external RADIUS authentication server",
+        cmd_attribute => "CMD_ARRAYOS|CMD_NORMAL|CMD_GLOBAL|CMD_SPECIAL_LOG",
+        user_level => "CLI_LEVEL_CONFIG",
+        function_name => "unset_radius_server",
+        function_args => [],
+    },
+    {
+        obj_type => "ITEM",
+        name => "on",
+        menu => "root_admin_aaa",
+        help_string => "Turn on external authentication",
+        cmd_attribute => "CMD_ARRAYOS|CMD_NORMAL|CMD_GLOBAL",
+        user_level => "CLI_LEVEL_CONFIG",
+        function_name => "exauth_on",
+        function_args => [],
+    },
+    {
+        obj_type => "ITEM",
+        name => "off",
+        menu => "root_admin_aaa",
+        help_string => "Turn off external authentication",
+        cmd_attribute => "CMD_ARRAYOS|CMD_NORMAL|CMD_GLOBAL",
+        user_level => "CLI_LEVEL_CONFIG",
+        function_name => "exauth_off",
+        function_args => [],
+    },
+    {
+        obj_type => "MENU",
+        name => "admin",
+        parent_menu => "root_show",
+        uniq_name => "root_show_admin",
+        cmd_attribute => "CMD_ARRAYOS|CMD_NORMAL",
+        user_level => "CLI_LEVEL_ENABLE",
+        help_string => "Display administration configurations",
+    },
+    {
+        obj_type => "MENU",
+        name => "aaa",
+        parent_menu => "root_show_admin",
+        uniq_name => "root_show_admin_aaa",
+        cmd_attribute => "CMD_ARRAYOS|CMD_NORMAL",
+        user_level => "CLI_LEVEL_ENABLE",
+        help_string => "Display external authentication configurations",
+    },
+    {
+        obj_type => "ITEM",
+        name => "all",
+        menu => "root_show_admin_aaa",
+        help_string => "Display all external authentication configurations",
+        cmd_attribute => "CMD_ARRAYOS|CMD_NORMAL|CMD_GLOBAL",
+        user_level => "CLI_LEVEL_ENABLE",
+        function_name => "show_exauth_all",
+        function_args => [],
+    },
 );
 
 # This method is required to expost the command table to the caller.
