Index: /branches/rel_apv_10_7/usr/click/bin/backend/users.h
===================================================================
--- /branches/rel_apv_10_7/usr/click/bin/backend/users.h	(revision 38571)
+++ /branches/rel_apv_10_7/usr/click/bin/backend/users.h	(working copy)
@@ -95,6 +95,8 @@
 #define USER_FLAG_CHANGING_PW         0x00000008
 #define USER_FLAG_TWOFACTOR_AUTH      0x00000010
 
+#define MAX_CHANGE_PASSWD_RETRY			5
+
 enum {
 	USER_INIT,               /* Initial state */
 	USER_FIRST_TIME_LOGIN,   /* The user first time login */
@@ -122,6 +124,9 @@
 	int twofactor_random; /* Used for twofactor, do signature for this random */
 	uint32_t flags;
 	uint64_t expire_time;
+
+	int retry_times;      /* Used to record the number of failed password change attempts */
+	uint64_t unlock_time; /* Used to record the unlock time for failed password change attempts */
 } user_info_t;
 
 /* If change this struct, need to synchronously change the struct in user.h, auth2.c and login.c and usr/click/libpyauth/pyauth.c*/
Index: /branches/rel_apv_10_7/usr/click/bin/backend/users.c
===================================================================
--- /branches/rel_apv_10_7/usr/click/bin/backend/users.c	(revision 38571)
+++ /branches/rel_apv_10_7/usr/click/bin/backend/users.c	(working copy)
@@ -148,6 +148,7 @@
 static int ssh_enable_pubkey(const char *uname);
 
 static int get_passwd_interactive(char *user, char *newpass, char *group, int check);
+static int get_passwd_interactive_with_lock_mechanism(char *user, char *newpass, char *group, int check);
 static int create_userlogin_conf(user_info_t *p_user, int first_time_login);
 static int check_userlogin_conf_exist(char *user);
 static int delete_userlogin_conf(char *user);
@@ -169,6 +170,9 @@
 
 extern void changepwd_timeout_handle(int signo); 
 
+static int check_change_passwd_is_locked(user_info_t *user);
+static int update_change_passwd_status(user_info_t *user, int success);
+
 enum user_kind{
 	OTHER_USER = 0,
 	ARRAY_USER,
@@ -1928,6 +1932,57 @@
 	return 0;
 }
 
+static int
+check_change_passwd_is_locked(user_info_t *user) {
+	struct timeval tv;
+
+	if (user->retry_times < MAX_CHANGE_PASSWD_RETRY-1) {
+		return FALSE;
+	}
+
+	bzero(&tv, sizeof(tv));
+	gettimeofday(&tv, NULL);
+
+	if (user->unlock_time <= tv.tv_sec) {
+		return FALSE;
+	}
+
+	printf("The user \"%s\" has failed to change password in more than %d consecutive times and has been locked.\n"
+			"Please retry after %d seconds.\n", user->name, MAX_CHANGE_PASSWD_RETRY, user->unlock_time - tv.tv_sec);
+
+	return TRUE;
+}
+
+static int
+update_change_passwd_status(user_info_t *user, int success) {
+	struct timeval tv;
+
+	if (success) {
+		user->retry_times = 0;
+		user->unlock_time = 0;
+		return 0;
+	}
+
+	if (user->retry_times < MAX_CHANGE_PASSWD_RETRY) {
+		if (++(user->retry_times) == MAX_CHANGE_PASSWD_RETRY) {
+			bzero(&tv, sizeof(tv));
+			gettimeofday(&tv, NULL);
+			user->unlock_time = tv.tv_sec + LOCK_USER_TIME;
+			printf("The user \"%s\" has failed to change password in more than %d consecutive times and has been locked.\n"
+					"Please retry after %d seconds.\n", user->name, MAX_CHANGE_PASSWD_RETRY, LOCK_USER_TIME);
+			return -1;
+		}
+	} else {
+		user->retry_times = 1;
+		user->unlock_time = 0;
+	}	
+
+	printf("The user \"%s\" will be locked if it fails to change password in more than %d consecutive times.\n", 
+			user->name, MAX_CHANGE_PASSWD_RETRY - user->retry_times);
+
+	return -1;
+}
+
 int
 change_passwd(char *name, char *pass)
 {
@@ -1973,6 +2028,10 @@
 		}
 	}
 
+	if (check_change_passwd_is_locked(&(p->user[idx]))) {
+		return -1;
+	}
+
 	if (pass && 0 == strncmp(pass, ENCRYPTSTR, sizeof(ENCRYPTSTR)-1)) {
 		is_encpass = 1;
 	}
@@ -1982,7 +2041,7 @@
 			pass_len = strlen(pass);
 			if(pass_len > MAX_PASS_LEN_UI_ADDUSER) {
 				printf("Invalid password length, it must less than %d characters.\n", MAX_PASS_LEN_UI_ADDUSER);
-				return -1;
+				goto lock;
 			}
 		}
 
@@ -1995,25 +2054,29 @@
 			
 			if (pass_len == 0 && sess_state.ui_type == USER_TERMINAL) {
 				bzero(newpass, sizeof(newpass));
-				if (0 != get_passwd_interactive(name, newpass, NULL, 1))
+				if (0 != get_passwd_interactive_with_lock_mechanism(name, newpass, NULL, 1))
 					return -1;
 				pass = newpass;
 				if_check = 0;
 			} else if (pass_len < FORCE_MIN_PASS_LEN_UI_ADDUSER) {
 				printf("Invalid password! It must contain at least %d characters.\n", FORCE_MIN_PASS_LEN_UI_ADDUSER);
-				return -1;
+				goto lock;
 			}
 		} else if (0 == pass_len) {
 			printf("Password cannot be empty.\n");
-			return -1;
+			goto lock;
 		}
 	}
 	
 	if (change_passwd_local(name, pass, if_check) != 0) {
-		return -1;
+		goto lock;
 	}
 
+	update_change_passwd_status(&(p->user[idx]), TRUE);
 	return update_user_conf(name, is_encpass);
+
+lock:
+	return update_change_passwd_status(&(p->user[idx]), FALSE);
 }
 
 int
@@ -3574,6 +3637,112 @@
 }
 
 static int
+get_passwd_interactive_with_lock_mechanism(char *user, char *newpass, char *group, int check)
+{
+	int len, pwd_ok = 0, idx = 0;
+	char *passwd;
+	user_conf_t *p;
+	user_info_t *user_info;
+
+	if ((p = user_conf_attach()) == NULL) {
+		return -1;
+	}
+
+	if ((idx = user_conf_lookup(user, p)) == -1) {
+		return -1;
+	}
+
+	user_info = &(p->user[idx]);
+
+	while (1) {
+		if (check_change_passwd_is_locked(user_info)) {
+			return -1;
+		}
+
+		if (!pwd_ok) {
+			printf("\nNew password:");
+			send_ctl_flag(STDIN_FILENO, (char)F_PASS);
+			fflush(stdout);
+			errno = 0;
+			passwd = getpass("");
+			if (passwd == NULL) {
+				printf("Error in reading the password\n");
+				goto lock;
+			} else if (ENOTTY == errno && (0 == strcmp(passwd, ""))) {
+				return -1;
+			}
+
+			len = strlen(passwd);
+			if (len < FORCE_MIN_PASS_LEN_UI_ADDUSER) {
+				printf("Invalid password! It must contain at least %d characters.\n", FORCE_MIN_PASS_LEN_UI_ADDUSER);
+				goto lock;
+			} else if (len > MAX_PASS_LEN_UI_ADDUSER) {
+				printf("Invalid password length, it must less than %d characters.\n", MAX_PASS_LEN_UI_ADDUSER);
+				goto lock;
+			}
+
+			if ((0 == strncmp(passwd, ENCRYPTSTR, sizeof(ENCRYPTSTR)-1)) && cli_interactive()) {
+				printf("Invalid password. It can not be an encrypted password.\n");
+				goto lock;
+			}
+
+			if (check) {
+				if (check_passwd(user, passwd) != 0) {
+					goto lock;
+				}
+			}
+			strncpy(newpass, passwd, len + 1);
+
+			/* get second password */
+			printf("Retype new password:");
+			send_ctl_flag(STDIN_FILENO, (char)F_PASS);
+			fflush(stdout);
+			passwd = getpass("");
+			if (passwd == NULL) {
+				printf("Error in reading the password\n");
+				goto lock;
+			}
+
+			if (strcmp(newpass, passwd) != 0) {
+				printf("Error: Passwords do not match\n");
+				goto lock;
+			}
+			pwd_ok = 1;
+			update_change_passwd_status(&(p->user[idx]), TRUE);
+		}
+
+		if (group) {
+			printf("Level ('enable', 'config' or 'api', direct enter is 'config'):");
+			fflush(stdout);
+			if (read(STDIN_FILENO, group, MAXNAMELEN) <= 0) {
+				printf("Error in reading the access level\n");
+				goto lock;
+			}
+			if (group[0] == '\n') {
+				strcpy(group, "config");
+			} else {
+				*(group + strlen(group) - 1) = '\0';
+			}
+			if (check) {
+				if (strcmp(group, CONFIG_GROUP) != 0 && 
+						strcmp(group, ENABLE_GROUP) != 0 &&
+						strcmp(group, SOAPAPI_GROUP) != 0) {
+					printf("Error: Unsupported access level\n");
+					goto lock;
+				}
+			}
+		}
+
+		break;
+
+lock:
+		update_change_passwd_status(user_info, FALSE);
+	}
+
+	return 0;
+}
+
+static int
 get_passwd_interactive(char *user, char *newpass, char *group, int check)
 {
 	int len, pwd_ok = 0;
Index: /branches/rel_apv_10_7/usr/click/lib/libexauth/auth_ext.c
===================================================================
--- /branches/rel_apv_10_7/usr/click/lib/libexauth/auth_ext.c	(revision 38571)
+++ /branches/rel_apv_10_7/usr/click/lib/libexauth/auth_ext.c	(working copy)
@@ -662,9 +662,9 @@
 	return ret_value;
 }
 
-#define MAXUSERS        100
-#define SEGMENTMAXUSERS 2048
-#define MAXNAMELEN      25
+#define MAXUSERS        100
+#define SEGMENTMAXUSERS 2048
+#define MAXNAMELEN      25
 #define UT_NAMESIZE     32
 #define USER_ITEM_NUM   (MAXUSERS+SEGMENTMAXUSERS)
 #if defined(__linux__)
@@ -691,6 +691,9 @@
 	int twofactor_random; /* Used for twofactor, do signature for this random */
 	uint32_t flags;
 	uint64_t expire_time;
+
+	int retry_times;      /* Used to record the number of failed password change attempts */
+	uint64_t unlock_time; /* Used to record the unlock time for failed password change attempts */
 } user_info_t;
 
 typedef struct _user_conf {
