/*- * Copyright (c) 2005 Eirik A. Nygaard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include "psql.config.h" #include "psqladm.h" #define ACTION_ADD 1 #define ACTION_DELETE 2 #define ACTION_EDIT 3 #define ACTION_LIST 4 #define ACTION_CHPASS 5 PGconn *pgconn; void usage(void); int adduser(char *username, char *password, uid_t uid); int verify_owner(char *username, uid_t uid); void listusers(uid_t uid); int dropuser(char *username); void change_password(char *username, char *password); int main(int argc, char **argv) { uid_t uid; int action = 0, c; char *username = NULL, *password = NULL; char *newpassword = NULL; char _username[1024], _password[1024]; char _newpassword[1024]; char getpass1[1024]; char getpass2[1024]; while ((c = getopt(argc, argv, "Phadlu:p:")) != -1) { switch (c) { case 'h': usage(); exit(1); case 'a': action = ACTION_ADD; break; case 'd': action = ACTION_DELETE; break; case 'e': action = ACTION_EDIT; break; case 'l': action = ACTION_LIST; break; case 'u': username = optarg; break; case 'p': password = optarg; break; case 'P': action = ACTION_CHPASS; break; default: fprintf(stderr, "Unknown argument: '%c'\n", c); usage(); exit(1); } } argc -= optind; argv += optind; if (action == 0) { usage(); errx(1, "No action specified!"); } if (!username && argc > 0) { username = argv[0]; argc--; argv++; } if (!password && argc > 0) { password = argv[0]; argc--; argv++; } if (!username && (action == ACTION_ADD || action == ACTION_EDIT || action == ACTION_DELETE || action == ACTION_CHPASS)) { usage(); errx(1, "Specify username!"); } if (!password && action == ACTION_ADD) { getpassword("Password: ", "Repeast password: ", getpass1, sizeof(getpass1)); password = getpass1; } if (!newpassword && action == ACTION_CHPASS) { if (password) { newpassword = password; } else { getpassword("New password: ", "Repeast new password: ", getpass2, sizeof(getpass2)); newpassword = getpass2; } } /* verify input */ if (username && !verifystr(username, STR_TYPE_NAME)) errx(1, "Invalid username input"); if (password && !verifystr(password, STR_TYPE_PASSWORD)) errx(1, "Invalid password input"); if (newpassword && !verifystr(newpassword, STR_TYPE_PASSWORD)) errx(1, "Invalid new password input"); uid = get_cred(); pgconn = db_connect(PSQL_USER, PSQL_PASSWORD, PSQL_DBNAME, PSQL_HOST); if (username) { struct passwd *passwd; if (strlen(username) > 1000) errx(1, "Too long username"); PQescapeString(_username, username, MIN(strlen(username), sizeof(_username))); passwd = getpwuid(uid); if (passwd == NULL) err(1, "Unable to get login info"); if (!verify_startwith(username, passwd->pw_name)) errx(1, "Your dbuser must start with your username, and separate username from extrainfo with '_'"); } if (password) { if (strlen(password) > 1000) errx(1, "Too long password"); PQescapeString(_password, password, MIN(strlen(password), sizeof(_password))); } if (newpassword) { if (strlen(newpassword) > 1000) errx(1, "Too long newpassword"); PQescapeString(_newpassword, newpassword, MIN(strlen(newpassword), sizeof(_newpassword))); } switch (action) { case ACTION_ADD: printf("Adding user %s... \n", _username); if (adduser(_username, _password, uid) != 0) errx(1, "Unable to add new user"); break; case ACTION_DELETE: if (!verify_owner(_username, uid)) errx(1, "You are not the owner for that dbuser."); printf("Deleting user... \n"); dropuser(username); break; case ACTION_EDIT: if (!verify_owner(_username, uid)) errx(1, "You are not the owner for that dbuser."); printf("Editing user... nothing to do here, sorry!\n"); break; case ACTION_LIST: listusers(uid); break; case ACTION_CHPASS: printf("Changing password... \n"); change_password(_username, _newpassword); break; } return(0); } void usage(void) { fprintf(stderr, "psql-useradm [-h] [-a] [-d] [-l] [-P] [username] [password]\n"); fprintf(stderr, "\t-h: This help screen\n"); fprintf(stderr, "\t-a: Create a user\n"); fprintf(stderr, "\t-d: Drop a user\n"); /*fprintf(stderr, "\t-e: Edit you user [not functional]\n");*/ fprintf(stderr, "\t-l: List your database users\n"); fprintf(stderr, "\t-P: Change password\n"); } int adduser(char *username, char *password, uid_t uid) { char query[1024]; int nfields; PGresult *res; snprintf(query, sizeof(query), "SELECT uid FROM psqluseradm WHERE username = '%s'", username); res = PQexec(pgconn, query); if (PQresultStatus(res) != PGRES_TUPLES_OK) errx(1, "Could not execute query: '%s': %s", query, PQerrorMessage(pgconn)); nfields = PQntuples(res); if (nfields > 0) errx(1, "A database user with that name already exists"); snprintf(query, sizeof(query), "CREATE USER %s NOCREATEDB NOCREATEUSER ENCRYPTED PASSWORD '%s'", username, password); res = PQexec(pgconn, query); if (PQresultStatus(res) != PGRES_COMMAND_OK) errx(1, "unable to add db user: %s", PQerrorMessage(pgconn)); snprintf(query, sizeof(query), "INSERT INTO psqluseradm (uid, username) VALUES(%d, '%s')", uid, username); res = PQexec(pgconn, query); if (PQresultStatus(res) != PGRES_COMMAND_OK) errx(1, "unable to add info user: %s", PQerrorMessage(pgconn)); printf("done!\n"); return(0); } void listusers(uid_t uid) { char query[1024]; PGresult *res; int i, nfields; snprintf(query, sizeof(query), "SELECT username, ts FROM psqluseradm WHERE uid = %d", uid); res = PQexec(pgconn, query); if (PQresultStatus(res) != PGRES_TUPLES_OK) errx(1, "unable to list users: %s: %s", query, PQerrorMessage(pgconn)); nfields = PQnfields(res); printf("%-15s %-15s\n", "DBuser", "Created"); for (i = 0; i < PQntuples(res); i++) { /* XXX: Format timestamp... */ printf("%-15s %-15s\n", PQgetvalue(res, i, 0), PQgetvalue(res, i, 1)); } if (PQntuples(res) == 0) printf("You don't have any database users...\n"); } int dropuser(char *username) { char query[1024]; PGresult *res; snprintf(query, sizeof(query), "DROP USER %s", username); res = PQexec(pgconn, query); if (PQresultStatus(res) != PGRES_COMMAND_OK) errx(1, "unable to drop user: %s: %s", query, PQerrorMessage(pgconn)); snprintf(query, sizeof(query), "DELETE FROM psqluseradm WHERE username = '%s'", username); res = PQexec(pgconn, query); if (PQresultStatus(res) != PGRES_COMMAND_OK) errx(1, "unable to delete info user: %s: %s", query, PQerrorMessage(pgconn)); printf("done!\n"); return(0); } int verify_owner(char *username, uid_t uid) { char query[1024]; PGresult *res; snprintf(query, sizeof(query), "SELECT id FROM psqluseradm " \ "WHERE username = '%s' AND uid = %d", username, uid); res = PQexec(pgconn, query); if (PQresultStatus(res) != PGRES_TUPLES_OK) errx(1, "verify query failed: %s: %s", query, PQerrorMessage(pgconn)); if (PQntuples(res) > 0) return(1); return(0); } void change_password(char *username, char *password) { char query[1024]; PGresult *res; snprintf(query, sizeof(query), "ALTER USER %s PASSWORD '%s'", username, password); res = PQexec(pgconn, query); if (PQresultStatus(res) != PGRES_COMMAND_OK) errx(1, "unable to change password for user: %s", query); printf("done\n"); }