diff --git a/server/core/adminusers.c b/server/core/adminusers.c index 5fcb3d221..9072202cc 100644 --- a/server/core/adminusers.c +++ b/server/core/adminusers.c @@ -18,6 +18,7 @@ #include #include #include +#include #define _XOPEN_SOURCE #include #include @@ -48,7 +49,15 @@ static int admin_init = 0; static char *ADMIN_ERR_NOMEM = "Out of memory"; static char *ADMIN_ERR_FILEOPEN = "Unable to create password file"; static char *ADMIN_ERR_DUPLICATE = "Duplicate username specified"; +static char *ADMIN_ERR_USERNOTFOUND = "User not found"; +static char *ADMIN_ERR_AUTHENTICATION = "Authentication failed"; static char *ADMIN_ERR_FILEAPPEND = "Unable to append to password file"; +static char *ADMIN_ERR_PWDFILEOPEN = "Failed to open password file"; +static char *ADMIN_ERR_TMPFILEOPEN = "Failed to open temporary password file"; +static char *ADMIN_ERR_PWDFILEACCESS = "Failed to access password file"; +static char *ADMIN_SUCCESS = NULL; + +static const int LINELEN=80; /** * Admin Users initialisation @@ -150,7 +159,7 @@ char fname[1024], *home, *cpasswd; skygw_log_write(NULL, LOGFILE_ERROR, "Unable to create password file %s.\n", fname); - return ADMIN_ERR_FILEOPEN; + return ADMIN_ERR_PWDFILEOPEN; } fclose(fp); } @@ -169,9 +178,145 @@ char fname[1024], *home, *cpasswd; } fprintf(fp, "%s:%s\n", uname, cpasswd); fclose(fp); - return NULL; + return ADMIN_SUCCESS; } + +/** + * Remove maxscale user from in-memory structure and from password file + * + * @param uname Name of the new user + * @param passwd Password for the new user + * @return NULL on success or an error string on failure + */ +char* admin_remove_user( + char* uname, + char* passwd) +{ + FILE* fp; + FILE* fp_tmp; + char fname[1024]; + char fname_tmp[1024]; + char* home; + char fusr[LINELEN]; + char fpwd[LINELEN]; + char line[LINELEN]; + fpos_t rpos; + + if (!admin_search_user(uname)) { + skygw_log_write(NULL, + LOGFILE_MESSAGE, + "Couldn't find user %s. Removing user failed", uname); + return ADMIN_ERR_USERNOTFOUND; + } + + if (admin_verify(uname, passwd) == 0) { + skygw_log_write(NULL, + LOGFILE_MESSAGE, + "Authentication failed, wrong user/password combination.\n" + "Removing user failed"); + return ADMIN_ERR_AUTHENTICATION; + } + + /** Remove user from in-memory structure */ + users_delete(users, uname); + + /** + * Open passwd file and remove user from the file. + */ + if ((home = getenv("MAXSCALE_HOME")) != NULL) { + sprintf(fname, "%s/etc/passwd", home); + sprintf(fname_tmp, "%s/etc/passwd_tmp", home); + } else { + sprintf(fname, "/usr/local/skysql/MaxScale/etc/passwd"); + sprintf(fname_tmp, "/usr/local/skysql/MaxScale/etc/passwd_tmp"); + } + /** + * Rewrite passwd file from memory. + */ + if ((fp = fopen(fname, "r")) == NULL) + { + int err = errno; + skygw_log_write(NULL, LOGFILE_ERROR, + "Unable to open password file %s : errno %d.\n" + "Removing user from file failed; it must be done manually.", + fname, + err); + return ADMIN_ERR_PWDFILEOPEN; + } + /** + * Open temporary passwd file. + */ + if ((fp_tmp = fopen(fname_tmp, "w")) == NULL) + { + int err = errno; + skygw_log_write(NULL, LOGFILE_ERROR, + "Unable to open tmp file %s : errno %d.\n" + "Removing user from passwd file failed; " + "it must be done manually.", + fname_tmp, + err); + fclose(fp); + return ADMIN_ERR_TMPFILEOPEN; + } + + /** + * Scan passwd and copy all but matching lines to temp file. + */ + if (fgetpos(fp, &rpos) != 0) { + int err = errno; + skygw_log_write(NULL, LOGFILE_ERROR, + "Unable to process passwd file %s : errno %d.\n" + "Removing user from file failed, and must be done manually.", + fname, + err); + return ADMIN_ERR_PWDFILEACCESS; + } + + while (fscanf(fp, "%[^:]:%s\n", fusr, fpwd) == 2) + { + /** + * Compare username what was found from passwd file. + * Unmatching lines are copied to tmp file. + */ + if (strncmp(uname, fusr, strlen(uname)+1) != 0) { + fsetpos(fp, &rpos); /** one step back */ + fgets(line, LINELEN, fp); + fputs(line, fp_tmp); + } + + if (fgetpos(fp, &rpos) != 0) { + int err = errno; + skygw_log_write(NULL, LOGFILE_ERROR, + "Unable to process passwd file %s : errno %d.\n" + "Removing user from file failed, and must be " + "done manually.", + fname, + err); + return ADMIN_ERR_PWDFILEACCESS; + } + } + fclose(fp); + /** + * Replace original passwd file with new. + */ + if (rename(fname_tmp, fname)) { + int err = errno; + skygw_log_write(NULL, LOGFILE_ERROR, + "Unable to rename new passwd file %s : errno %d.\n" + "Rename it to %s manually.", + fname_tmp, + err, + fname); + return ADMIN_ERR_PWDFILEACCESS; + } + + fclose(fp_tmp); + return ADMIN_SUCCESS; +} + + + /** * Check for existance of the user * @@ -179,7 +324,7 @@ char fname[1024], *home, *cpasswd; * @return Non-zero if the user exists */ int -admin_test_user(char *user) +admin_search_user(char *user) { initialise(); if (users == NULL) diff --git a/server/include/adminusers.h b/server/include/adminusers.h index 16c61c26d..380e9ee70 100644 --- a/server/include/adminusers.h +++ b/server/include/adminusers.h @@ -36,5 +36,7 @@ extern char *admin_add_user(char *, char *); extern int admin_test_user(char *); extern void dcb_PrintAdminUsers(DCB *dcb); +char* admin_remove_user(char* uname, char* passwd); + #endif diff --git a/server/modules/routing/debugcmd.c b/server/modules/routing/debugcmd.c index f1ebba0bb..183b075bb 100644 --- a/server/modules/routing/debugcmd.c +++ b/server/modules/routing/debugcmd.c @@ -81,7 +81,7 @@ static void telnetdShowUsers(DCB *); * The subcommands of the show command */ struct subcommand showoptions[] = { - { "dcbs", 0, dprintAllDCBs, "Show all descriptor control blocks (network connections)", + { "dcbs", 0, dprintAllDCBs, "Show all descriptor control blocks (network connections)", {0, 0, 0} }, { "dcb", 1, dprintDCB, "Show a single descriptor control block e.g. show dcb 0x493340", {ARG_TYPE_ADDRESS, 0, 0} }, @@ -191,6 +191,25 @@ struct subcommand addoptions[] = { {0, 0, 0} } }; + +static void telnetdRemoveUser(DCB *, char *, char *); +/** + * The subcommands of the remove command + */ +struct subcommand removeoptions[] = { + { + "user", + 2, + telnetdRemoveUser, + "Remove existing maxscale user. Example : remove user john johnpwd", + {ARG_TYPE_STRING, ARG_TYPE_STRING, 0} + }, + { + NULL, 0, NULL, NULL, {0, 0, 0} + } +}; + + /** * The debug command table */ @@ -200,6 +219,7 @@ static struct { } cmds[] = { { "add", addoptions }, { "clear", clearoptions }, + { "remove", removeoptions }, { "restart", restartoptions }, { "set", setoptions }, { "show", showoptions }, @@ -513,7 +533,7 @@ reload_config(DCB *dcb) } /** - * Add a new admin user + * Add a new maxscale admin user * * @param dcb The DCB for messages * @param user The user name @@ -524,7 +544,7 @@ telnetdAddUser(DCB *dcb, char *user, char *passwd) { char *err; - if (admin_test_user(user)) + if (admin_search_user(user)) { dcb_printf(dcb, "User %s already exists.\n", user); return; @@ -535,6 +555,39 @@ char *err; dcb_printf(dcb, "Failed to add new user. %s\n", err); } + +/** + * Remove a maxscale admin user + * + * @param dcb The DCB for messages + * @param user The user name + * @param passwd The Password of the user + */ +static void telnetdRemoveUser( + DCB* dcb, + char* user, + char* passwd) +{ + char* err; + + if (!admin_search_user(user)) + { + dcb_printf(dcb, "User %s doesn't exist.\n", user); + return; + } + + if ((err = admin_remove_user(user, passwd)) == NULL) + { + dcb_printf(dcb, "User %s has been successfully removed.\n", user); + } + else + { + dcb_printf(dcb, "Failed to remove user %s. %s\n", user, err); + } +} + + + /** * Print the adminsitration users *