From 8ab4673bd580b24c56b074b8efe8348686301c1c Mon Sep 17 00:00:00 2001 From: eirikald Date: Tue, 13 Feb 2007 20:57:45 +0000 Subject: [PATCH] Initial import --- Makefile | 3 + README | 19 +++ TODO | 3 + psqldbadm/Makefile | 13 ++ psqldbadm/psql-dbadm.c | 323 +++++++++++++++++++++++++++++++++++++ psqluseradm/Makefile | 11 ++ psqluseradm/psql-useradm.c | 315 ++++++++++++++++++++++++++++++++++++ psqluseradm/psql.config.h | 4 + psqluseradm/psqladm.c | 117 ++++++++++++++ psqluseradm/psqladm.h | 43 +++++ tables.sql | 15 ++ 11 files changed, 866 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 TODO create mode 100644 psqldbadm/Makefile create mode 100644 psqldbadm/psql-dbadm.c create mode 100644 psqluseradm/Makefile create mode 100644 psqluseradm/psql-useradm.c create mode 100644 psqluseradm/psql.config.h create mode 100644 psqluseradm/psqladm.c create mode 100644 psqluseradm/psqladm.h create mode 100644 tables.sql diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e9c2b25 --- /dev/null +++ b/Makefile @@ -0,0 +1,3 @@ +SUBDIR= psqldbadm psqluseradm + +.include diff --git a/README b/README new file mode 100644 index 0000000..925ca01 --- /dev/null +++ b/README @@ -0,0 +1,19 @@ +PSQL-adm tools. + +Disallow usage and create as default settings for newly created databases, done +in template1: + REVOKE USAGE ON SCHEMA public FROM public; + REVOKE CREATE ON SCHEMA public FROM public; + +For every newly created database a schema with the same name as the specified +owner will be created, and the owner will have full authorization over it. + +Two databases are used to keep information related to whom owns a user or +database, their structure can be found in tables.sql. + +Database information is for now hardcoded into 'psqluseradm/psql.config.h', and +if you change that info you must recompile for them to take effect. + +The dbname and dbuser must start with the username of the caller. + + - Eirik Nygaard diff --git a/TODO b/TODO new file mode 100644 index 0000000..3bec6e6 --- /dev/null +++ b/TODO @@ -0,0 +1,3 @@ + * Add PQclear(res) all over the place + * Split out common parts from psql-[user|db]adm + * Learn english diff --git a/psqldbadm/Makefile b/psqldbadm/Makefile new file mode 100644 index 0000000..60cdbc3 --- /dev/null +++ b/psqldbadm/Makefile @@ -0,0 +1,13 @@ +.PATH: ${.CURDIR} ${.CURDIR}/../psqluseradm/ + +CFLAGS= -I/usr/local/include +LDFLAGS=-L/usr/local/lib -lpq + +PROG= psql-dbadm +SRCS= psql-dbadm.c psqladm.c + +NO_MAN= true + +WARNS?= 6 + +.include diff --git a/psqldbadm/psql-dbadm.c b/psqldbadm/psql-dbadm.c new file mode 100644 index 0000000..6eb9255 --- /dev/null +++ b/psqldbadm/psql-dbadm.c @@ -0,0 +1,323 @@ +/*- + * 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 "../psqluseradm/psql.config.h" +#include "../psqluseradm/psqladm.h" + +#define ACTION_ADD 1 +#define ACTION_DELETE 2 +#define ACTION_EDIT 3 +#define ACTION_LIST 4 + +PGconn *pgconn; + +void usage(void); +int createdatabase(char *dbname, char *owner, uid_t uid, char *encoding); +int verify_owner(char *dbname, uid_t uid); +void listdatabases(uid_t uid); +int dropdatabase(char *dbname); +char *first_dbuser(uid_t uid); +void create_schema(char *name, char *owner, PGconn *conn); + +int +main(int argc, char **argv) +{ + uid_t uid; + int action = 0, c; + char *dbname = NULL, *owner = NULL; + char _dbname[1024], _owner[1024]; + char *encoding, _encoding[1024]; + + while ((c = getopt(argc, argv, "hadlu:o:E:")) != -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': + dbname = optarg; + break; + case 'o': + owner = optarg; + break; + case 'E': + encoding = optarg; + break; + default: + fprintf(stderr, "Unknown argument: '%c'\n", c); + usage(); + exit(1); + } + } + argc -= optind; + argv += optind; + + if (!dbname && argc > 0) { + dbname = argv[0]; + argc--; + argv++; + } + if (!owner && argc > 0) { + owner = argv[0]; + argc--; + argv++; + } + + if (!dbname && + (action == ACTION_ADD || action == ACTION_EDIT || action == ACTION_DELETE)) { + usage(); + errx(1, "Specify dbname!"); + } + if (action == 0) { + usage(); + errx(1, "No action specified!"); + } + + uid = get_cred(); + pgconn = db_connect(PSQL_USER, PSQL_PASSWORD, PSQL_DBNAME, PSQL_HOST); + + /* verify input */ + if (dbname && !verifystr(dbname, STR_TYPE_NAME)) + errx(1, "Invalid dbname input"); + if (owner && !verifystr(owner, STR_TYPE_NAME)) + errx(1, "Invalid owner input"); + if (encoding && !verifystr(encoding, STR_TYPE_NAME)) + errx(1, "Invalid encoding input"); + + if (dbname) { + struct passwd *passwd; + if (strlen(dbname) > 1000) + errx(1, "Too long dbname"); + PQescapeString(_dbname, dbname, MIN(strlen(dbname), sizeof(_dbname))); + passwd = getpwuid(uid); + if (!passwd) + errx(1, "Unable to get login info"); + if (!verify_startwith(dbname, passwd->pw_name)) + errx(1, "Your database must start with your username"); + } + if (!owner) { + if ((owner = first_dbuser(uid)) == NULL) + errx(1, "You must create a database user first"); + printf("Defaulting to '%s' as dbowner!\n", owner); + } + if (encoding) { + PQescapeString(_encoding, encoding, MIN(strlen(encoding), sizeof(_encoding))); + encoding = _encoding; + } + if (strlen(owner) > 1000) + errx(1, "Too long owner name"); + PQescapeString(_owner , owner, MIN(strlen(owner), sizeof(_owner))); + + switch (action) { + case ACTION_ADD: + fprintf(stderr, "Creating database %s... ", _dbname); + if (createdatabase(_dbname, _owner, uid, encoding) != 0) + errx(1, "Unable to add new user"); + break; + case ACTION_DELETE: + if (!verify_owner(_dbname, uid)) + errx(1, "You are not the owner for that dbuser."); + fprintf(stderr, "Deleting user... "); + dropdatabase(dbname); + break; + case ACTION_EDIT: + if (!verify_owner(_dbname, uid)) + errx(1, "You are not the owner for that dbuser."); + fprintf(stderr, "Editing user... nothing to do here, sorry!\n"); + break; + case ACTION_LIST: + listdatabases(uid); + } + + return(0); +} + +void +usage(void) +{ + fprintf(stderr, "psql-dbadm [-h] [-a] [-d] [-l] [-E encoding] [dbname [owner]]\n"); + fprintf(stderr, "\t-h: This help screen\n"); + fprintf(stderr, "\t-a: Create a new database\n"); + fprintf(stderr, "\t-d: Drop a database\n"); + fprintf(stderr, "\t-l: List your databases\n"); + fprintf(stderr, "\t-E encoding: Specify encoding when you create a database\n"); +} + +int +createdatabase(char *dbname, char *owner, uid_t uid, char *encoding) +{ + char query[1024]; + int nfields; + PGresult *res; + PGconn *newpgconn; + + snprintf(query, sizeof(query), "SELECT id FROM psqldbadm WHERE dbname = '%s'", dbname); + 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 with that name already exists"); + snprintf(query, sizeof(query), "CREATE DATABASE %s OWNER = %s ", + dbname, owner); + if (encoding) { + char enc[1024]; + snprintf(enc, sizeof(enc), " ENCODING '%s'", encoding); + strncat(query, enc, sizeof(query) - strlen(query)); + } + res = PQexec(pgconn, query); + if (PQresultStatus(res) != PGRES_COMMAND_OK) + errx(1, "unable to add info db: %s", PQerrorMessage(pgconn)); + snprintf(query, sizeof(query), "INSERT INTO psqldbadm (uid, dbname, owner) " \ + "VALUES(%d, '%s', '%s')", + uid, dbname, owner); + res = PQexec(pgconn, query); + if (PQresultStatus(res) != PGRES_COMMAND_OK) + errx(1, "unable to add database: %s", PQerrorMessage(pgconn)); + snprintf(query, sizeof(query), "GRANT ALL ON DATABASE %s TO %s", dbname, owner); + res = PQexec(pgconn, query); + if (PQresultStatus(res) != PGRES_COMMAND_OK) + errx(1, "unable to grant owner access to database: %s", PQerrorMessage(pgconn)); + printf("done!\n"); + newpgconn = db_connect(PSQL_USER, PSQL_PASSWORD, (const char *)dbname, PSQL_HOST); + create_schema(owner, owner, newpgconn); + return(0); +} + +void +create_schema(char *name, char *owner, PGconn *conn) +{ + char query[1024]; + PGresult *res; + + snprintf(query, sizeof(query), "CREATE SCHEMA %s AUTHORIZATION %s", name, owner); + res = PQexec(conn, query); + if (PQresultStatus(res) != PGRES_COMMAND_OK) + errx(1, "unable to create user schema: %s", PQerrorMessage(conn)); +} + +void +listdatabases(uid_t uid) +{ + char query[1024]; + PGresult *res; + int i, nfields; + + snprintf(query, sizeof(query), "SELECT dbname, owner, ts FROM psqldbadm WHERE uid = %d", uid); + res = PQexec(pgconn, query); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + errx(1, "unable to list databases: %s: %s", query, PQerrorMessage(pgconn)); + nfields = PQnfields(res); + printf("%-15s %-15s %-15s\n", "DB", "DBowner", "Created"); + for (i = 0; i < PQntuples(res); i++) { + /* XXX: Format timestamp... */ + printf("%-15s %-15s %-15s\n", PQgetvalue(res, i, 0), PQgetvalue(res, i, 1), + PQgetvalue(res, i, 2)); + } + if (PQntuples(res) == 0) + printf("You don't have any databases...\n"); +} + +int +dropdatabase(char *dbname) +{ + char query[1024]; + PGresult *res; + + snprintf(query, sizeof(query), "DROP DATABASE %s", dbname); + res = PQexec(pgconn, query); + if (PQresultStatus(res) != PGRES_COMMAND_OK) + errx(1, "unable to drop database: %s: %s", query, PQerrorMessage(pgconn)); + snprintf(query, sizeof(query), "DELETE FROM psqldbadm WHERE dbname = '%s'", dbname); + res = PQexec(pgconn, query); + if (PQresultStatus(res) != PGRES_COMMAND_OK) + errx(1, "unable to delete info database: %s: %s", query, PQerrorMessage(pgconn)); + printf("done!\n"); + return(0); +} + +int +verify_owner(char *dbname, uid_t uid) +{ + char query[1024]; + PGresult *res; + + snprintf(query, sizeof(query), "SELECT id FROM psqldbadm " \ + "WHERE dbname = '%s' AND uid = %d", + dbname, 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); +} + + +char * +first_dbuser(uid_t uid) +{ + char query[1024]; + char *owner; + PGresult *res; + + snprintf(query, sizeof(query), "SELECT username FROM psqluseradm WHERE uid = %d LIMIT 1", uid); + res = PQexec(pgconn, query); + if (PQresultStatus(res) != PGRES_TUPLES_OK) + errx(1, "could not find first dbuser: %s: %s", query, PQerrorMessage(pgconn)); + if (PQntuples(res) == 0) + return(NULL); + owner = PQgetvalue(res, 0, 0); + return(owner); +} + diff --git a/psqluseradm/Makefile b/psqluseradm/Makefile new file mode 100644 index 0000000..cb492f7 --- /dev/null +++ b/psqluseradm/Makefile @@ -0,0 +1,11 @@ +CFLAGS= -I/usr/local/include +LDFLAGS=-L/usr/local/lib -lpq + +PROG= psql-useradm +SRCS= psql-useradm.c psqladm.c + +NO_MAN= true + +WARNS?= 6 + +.include diff --git a/psqluseradm/psql-useradm.c b/psqluseradm/psql-useradm.c new file mode 100644 index 0000000..5c2857e --- /dev/null +++ b/psqluseradm/psql-useradm.c @@ -0,0 +1,315 @@ +/*- + * 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"); +} diff --git a/psqluseradm/psql.config.h b/psqluseradm/psql.config.h new file mode 100644 index 0000000..affb656 --- /dev/null +++ b/psqluseradm/psql.config.h @@ -0,0 +1,4 @@ +#define PSQL_HOST "129.241.210.168" /* india, avoid ipv6 thingy */ +#define PSQL_USER "pgsql" +#define PSQL_DBNAME "psqladm" +#define PSQL_PASSWORD "somepass" diff --git a/psqluseradm/psqladm.c b/psqluseradm/psqladm.c new file mode 100644 index 0000000..d207314 --- /dev/null +++ b/psqluseradm/psqladm.c @@ -0,0 +1,117 @@ +/*- + * 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 "psql.config.h" +#include "psqladm.h" + +PGconn * +db_connect(const char *dbuser, const char *password, const char *dbname, const char *host) +{ + PGconn *conn; + char conninfo[1024]; + + snprintf(conninfo, sizeof(conninfo), + "dbname = '%s' host = '%s' user = '%s' password = '%s'", + dbname, host, dbuser, password); + conn = PQconnectdb(conninfo); + if (PQstatus(conn) != CONNECTION_OK) + errx(1, "Could not connect to database(%d): %s", PQstatus(conn), PQerrorMessage(conn)); + return(conn); +} + +int +verify_startwith(char *string, char *start) +{ + if (!strncmp(string, start, strlen(start))) { + if (strlen(string) == strlen(start)) + return(1); + if (string[strlen(start)] == '_') + return(1); + } + return(0); +} + +uid_t +get_cred(void) +{ + uid_t uid; + if ((int)(uid = getuid()) == -1) + err(1, "getuid"); + return(uid); +} + +void +getpassword(const char *prompt1, const char *prompt2, char *pass, size_t len) +{ + char pass1[1024]; + char pass2[1024]; + char *passwd; + + passwd = getpass(prompt1); + strlcpy(pass1, passwd, sizeof(pass1)); + passwd = getpass(prompt2); + strlcpy(pass2, passwd, sizeof(pass2)); + if (strcmp(pass1, pass2) != 0) { + errx(1, "Passwords doesn't match"); + } + strlcpy(pass, pass1, len); +} + +/* + * names does not contain spaces + * passwords does not contain spaces + * XXX: Add better checks later. + */ +int +verifystr(char *str, int type) +{ + unsigned int i; + + for (i = 0; i < strlen(str); i++) { + if (type == STR_TYPE_NAME) { + if (isspace((int)str[i])) + return(0); + } + if (type == STR_TYPE_PASSWORD) { + if (isspace((int)str[i])) + return(0); + } + } + + return(1); /* Bad Bad, default case should be non-verified */ +} diff --git a/psqluseradm/psqladm.h b/psqluseradm/psqladm.h new file mode 100644 index 0000000..00223a9 --- /dev/null +++ b/psqluseradm/psqladm.h @@ -0,0 +1,43 @@ +/*- + * 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. + */ + +#ifndef _PSQLADM_H_ +#define _PSQLADM_H_ + +#define STR_TYPE_NAME 1 +#define STR_TYPE_PASSWORD 2 + +int verify_startwith(char *string, char *start); +PGconn *db_connect(const char *dbuser, const char *password, const char *dbname, const char *host); +uid_t get_cred(void); +void getpassword(const char *prompt1, const char *prompt2, char *pass, size_t len); +int verifystr(char *str, int type); + +#endif /* _PSQLADM_H_ */ diff --git a/tables.sql b/tables.sql new file mode 100644 index 0000000..f18513d --- /dev/null +++ b/tables.sql @@ -0,0 +1,15 @@ +CREATE TABLE psqluseradm ( + id serial NOT NULL, + uid integer, + username character varying(128), + ts timestamp without time zone DEFAULT now() +); + +CREATE TABLE psqldbadm ( + id serial NOT NULL, + uid integer, + dbname character varying(128), + "owner" character varying(128), + ts timestamp without time zone DEFAULT now() +); +