Re: [PATCHES] display and expression of the home directory in Win32
Hi All.
I have thought this way and that since that time. Suggestion of Magnus-san
was considered and this was made.
I considered many things about the pgpass guide of libpq. In windows, even
the place of it was not clear. Furthermore, they are intricately concerned
with an environment variable again. Then, I thought that wanted to take into
consideration not only a position but its maintenance.
C:\Program Files\PostgreSQL\8.1\bin>pqpasswd.exe --help
pqpasswd installs a pgpass(libpq) connect a PostgreSQL database.
Usage:
pqpasswd [OPTION]... [DBNAME]
Options:
-l, --list show a list of installed pgpass
-r, --remove remove the my pgpass
-h, --host=HOSTNAME database server host or socket directory
-p, --port=PORT database server port
-d, --dbname=DBNAME database to connect as
-U, --username=USERNAME user name to connect as
--help show this help, then exit
--version output version information, then exit
Report bugs to <pgsql-bugs@postgresql.org>.
C:\Program Files\PostgreSQL\8.1\bin>pqpasswd.exe --list
C:\Documents and Settings\saito\Application Data/postgresql/pgpass.conf
hostname=localhost port=5432 dbname=* username=postgres password=**********
hostname=* port=5432 dbname=saito username=saito password=**********
hostname=localhost port=5432 dbname=* username=z-saito password=**********
The 2th line is used.
password change can be made as follows.
C:\Program Files\PostgreSQL\8.1\bin>pqpasswd.exe --dbname="*" --username="postgres"
New Password:
Retype New Password:
Succeeded in creation.
C:\Program Files\PostgreSQL\8.1\bin>pqpasswd.exe -l --dbname="*" --username="postgres"
C:\Documents and Settings\saito\Application Data/postgresql/pgpass.conf
hostname=localhost port=5432 dbname=* username=postgres password=**********
hostname=* port=5432 dbname=saito username=saito password=**********
hostname=localhost port=5432 dbname=* username=z-saito password=**********
The 1th line is used.
I want the password to be enciphered in the future. However, we fully have to take the past
property into consideration. Then, I want this to be equipped as first stage.
any suggestion.?
Regards,
Hiroshi Saito
Attachments:
scripts_pqpasswd_patchapplication/octet-stream; name=scripts_pqpasswd_patchDownload
--- src/bin/scripts/Makefile.orig Mon Jan 30 22:46:00 2006
+++ src/bin/scripts/Makefile Thu Feb 23 15:46:47 2006
@@ -14,7 +14,7 @@
top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
-PROGRAMS = createdb createlang createuser dropdb droplang dropuser clusterdb vacuumdb reindexdb
+PROGRAMS = createdb createlang createuser dropdb droplang dropuser clusterdb vacuumdb reindexdb pqpasswd
override CPPFLAGS := -DFRONTEND -I$(top_srcdir)/src/bin/pg_dump -I$(top_srcdir)/src/bin/psql -I$(libpq_srcdir) $(CPPFLAGS)
@@ -32,6 +32,7 @@
clusterdb: clusterdb.o common.o dumputils.o $(top_builddir)/src/backend/parser/keywords.o
vacuumdb: vacuumdb.o common.o
reindexdb: reindexdb.o common.o dumputils.o $(top_builddir)/src/backend/parser/keywords.o
+pqpasswd: pqpasswd.o common.o
dumputils.c: % : $(top_srcdir)/src/bin/pg_dump/%
rm -f $@ && $(LN_S) $< .
@@ -54,6 +55,7 @@
$(INSTALL_PROGRAM) clusterdb$(X) $(DESTDIR)$(bindir)/clusterdb$(X)
$(INSTALL_PROGRAM) vacuumdb$(X) $(DESTDIR)$(bindir)/vacuumdb$(X)
$(INSTALL_PROGRAM) reindexdb$(X) $(DESTDIR)$(bindir)/reindexdb$(X)
+ $(INSTALL_PROGRAM) pqpasswd$(X) $(DESTDIR)$(bindir)/pqpasswd$(X)
installdirs:
$(mkinstalldirs) $(DESTDIR)$(bindir)
--- src/bin/scripts/pqpasswd.c.orig Thu Feb 23 15:47:33 2006
+++ src/bin/scripts/pqpasswd.c Tue Feb 28 03:08:04 2006
@@ -0,0 +1,541 @@
+/*-------------------------------------------------------------------------
+ *
+ * pqpasswd
+ *
+ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL: pgsql/src/bin/scripts/pqpasswd.c,v 1.00 2006/01/16 02:11:21 h-saito Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres_fe.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+#include "common.h"
+
+#ifndef WIN32
+#define PGPASSFILE ".pgpass"
+#else
+#define PGPASSFILE "pgpass.conf"
+#endif
+
+char homedir[MAXPGPATH];
+char pgpassfile[MAXPGPATH];
+char *passfile_env;
+
+/* setting options */
+#define DefaultHost "localhost"
+char *hostname = NULL;
+char *port = NULL;
+char *dbname = NULL;
+char *username = NULL;
+char *password = NULL;
+
+/* pqGetHomeDirectory is libpgport and shared. */
+extern bool pqGetHomeDirectory(char *buf, int bufsize);
+
+static void help(const char *progname);
+
+/*
+ * this actually returns the user's home directory.
+ */
+static bool
+get_homedirectry(char *buf, int bufsize)
+{
+#ifdef WIN32
+ struct stat stat_buf;
+#endif
+ if (!pqGetHomeDirectory(buf, bufsize))
+ return false;
+#ifdef WIN32
+ /* If home directory */
+ if (stat(buf, &stat_buf) == -1)
+ CreateDirectory(buf, 0);
+#endif
+ return true;
+}
+
+/*
+ * String sequence interpretation.
+ */
+static char *
+get_pwdstringseq(char *buf)
+{
+ char *tbuf;
+ bool bslash = false;
+
+ if (buf == NULL)
+ return NULL;
+ tbuf = buf;
+ if (*tbuf == '*')
+ return tbuf + 2;
+ while (*tbuf != 0)
+ {
+ if (*tbuf == '\\' && !bslash)
+ {
+ tbuf++;
+ bslash = true;
+ }
+ if (*tbuf == ':' && !bslash)
+ return tbuf + 1;
+ bslash = false;
+ tbuf++;
+ }
+ return NULL;
+}
+
+/*
+ * Get a password from the password file. Return is the congruous positions.
+ * format is "hostname:port:database:username:password"
+ */
+static int
+get_passwordfile(bool listpgpass, char *hostname, char *port, char *dbname, char *username)
+{
+ FILE *fp;
+ struct stat stat_buf;
+ int result_position = 0;
+ int line_position = 0;
+ char buf[BUFSIZ];
+
+ /* If password file cannot be opened, ignore it. */
+ if (stat(pgpassfile, &stat_buf) == -1)
+ return result_position;
+
+#ifndef WIN32
+
+ if (!S_ISREG(stat_buf.st_mode))
+ {
+ fprintf(stderr, _("WARNING: password file \"%s\" is not a plain file\n"), pgpassfile);
+ free(pgpassfile);
+ return result_position;
+ }
+
+ /* If password file is insecure, alert the user and ignore it. */
+ if (stat_buf.st_mode & (S_IRWXG | S_IRWXO))
+ {
+ fprintf(stderr, _("WARNING: password file \"%s\" has world or group read access; permission should be u=rw (0600)\n"), pgpassfile);
+ return result_position;
+ }
+#endif
+
+ fp = fopen(pgpassfile, "r");
+ if (fp == NULL)
+ return result_position;
+
+ while (!feof(fp))
+ {
+ char *t,
+ *ret;
+ char result[BUFSIZ];
+ int len,
+ pos;
+ bool cond;
+ buf[0] = '\0';
+ fgets(buf, BUFSIZ - 1, fp);
+
+ t = ret = buf;
+
+ len = strlen(buf);
+ if (len == 0)
+ continue;
+
+ line_position++;
+ cond = TRUE;
+
+ /* Remove trailing newline */
+ if (buf[len - 1] == '\n')
+ buf[len - 1] = '\0';
+ pos = 0;
+ while((t = get_pwdstringseq(t)) != NULL)
+ {
+ strncpy(result,ret,t - ret -1);
+ result[t - ret -1] = '\0';
+ ret = t;
+
+ switch(pos){
+ case 0: if (listpgpass)
+ printf("hostname=%s ",result);
+ if ((strcmp(hostname, result)) &&
+ (strcmp(result, "*")))
+ cond = FALSE;
+ break;
+ case 1: if (listpgpass)
+ printf("port=%s ",result);
+ if ((strcmp(port, result)) &&
+ (strcmp(result, "*")))
+ cond = FALSE;
+ break;
+ case 2: if (listpgpass)
+ printf("dbname=%s ",result);
+ if ((strcmp(dbname, result)) &&
+ (strcmp(result, "*")))
+ cond = FALSE;
+ break;
+ case 3: if (listpgpass)
+ {
+ printf("username=%s ",result);
+ printf("password=**********\n");
+ }
+ if ((strcmp(username, result)) &&
+ (strcmp(result, "*")))
+ cond = FALSE;
+ // printf("password=%s\n",t);
+ break;
+ default:
+ break;
+ }
+ pos++;
+ continue;
+ }
+
+ if ( cond )
+ result_position = line_position;
+
+ }
+
+ fclose(fp);
+
+ return result_position;
+
+}
+
+/*
+ * Get the temporary file name.
+ */
+static char
+*get_temporaryfile()
+{
+ const char *tmpdir;
+#ifdef WIN32
+ char tmppath[MAXPGPATH];
+#endif
+ struct timeval curtime;
+ static char filename[MAXPGPATH];
+
+#ifdef WIN32
+ if ((tmpdir = getenv("TEMP")) == NULL)
+ {
+ GetTempPath(sizeof(tmppath), tmppath);
+ tmpdir = tmppath;
+ }
+#else
+ if ((tmpdir = getenv("TMPDIR")) == NULL)
+ {
+ if (getuid() == 0)
+ tmpdir = "/tmp";
+ else
+ tmpdir = "/var/tmp";
+ }
+#endif
+
+ gettimeofday(&curtime, NULL);
+
+ sprintf(filename, "%s/%08lx%05lx", tmpdir,
+ (unsigned long)curtime.tv_sec, (unsigned long)curtime.tv_usec);
+
+ return filename;
+
+}
+
+/*
+ * Orignal file move.
+ */
+static bool
+filemove(char *fromfile, char *tofile)
+{
+ char line[BUFSIZ];
+ FILE *fip,
+ *fop;
+
+ fip = fopen(fromfile, "r");
+ if (fip == NULL)
+ return FALSE;
+ fop = fopen(tofile, "w");
+ if (fop == NULL)
+ {
+ fclose(fip);
+ return FALSE;
+ }
+
+ while (fgets(line, sizeof(line), fip) != NULL)
+ {
+ fputs(line, fop);
+ }
+
+ fclose(fip);
+ fclose(fop);
+
+ unlink(fromfile);
+
+ return TRUE;
+}
+
+int
+main(int argc, char *argv[])
+{
+ static struct option long_options[] = {
+ {"list", no_argument, NULL, 'l'},
+ {"remove", no_argument, NULL, 'r'},
+ {"host", required_argument, NULL, 'h'},
+ {"port", required_argument, NULL, 'p'},
+ {"dbname", required_argument, NULL, 'd'},
+ {"username", required_argument, NULL, 'U'},
+ {NULL, 0, NULL, 0}
+ };
+
+ const char *progname;
+ int optindex;
+ int c;
+
+ bool listpgpass = false;
+ bool removepgpass = false;
+ int update_position = 0;
+ char *repassword = NULL;
+ FILE *fip,
+ *fop;
+ char *pwtempfile = NULL;
+
+ progname = get_progname(argv[0]);
+ set_pglocale_pgservice(argv[0], "pgscripts");
+
+ handle_help_version_opts(argc, argv, "pqpasswd", help);
+
+ while ((c = getopt_long(argc, argv, "lrh:p:U:d:", long_options, &optindex)) != -1)
+ {
+ switch (c)
+ {
+ case 'l':
+ listpgpass = true;
+ break;
+ case 'r':
+ removepgpass = true;
+ break;
+ case 'h':
+ hostname = optarg;
+ break;
+ case 'p':
+ port = optarg;
+ break;
+ case 'U':
+ username = optarg;
+ break;
+ case 'd':
+ dbname = optarg;
+ break;
+ default:
+ fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
+ exit(1);
+ }
+ }
+
+ if (argc - optind > 0)
+ {
+ if (listpgpass)
+ dbname = argv[optind++];
+ else
+ {
+ dbname = argv[optind++];
+ if (argc - optind > 0)
+ dbname = argv[optind++];
+ }
+ }
+
+ if (argc - optind > 0)
+ {
+ fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
+ progname, argv[optind]);
+ fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
+ exit(1);
+ }
+
+ /* get the environment */
+
+ if (hostname == NULL)
+ {
+ if (getenv("PGHOST"))
+ hostname = getenv("PGHOST");
+ else
+ hostname = DefaultHost;
+ }
+
+ if (port == NULL)
+ {
+ if (getenv("PGPORT"))
+ port = getenv("PGPORT");
+ else
+ port = DEF_PGPORT_STR;
+ }
+
+ if (dbname == NULL)
+ {
+ if (getenv("PGDATABASE"))
+ dbname = getenv("PGDATABASE");
+ else if (getenv("PGUSER"))
+ dbname = getenv("PGUSER");
+ else
+ dbname = (char *)get_user_name(progname);
+ }
+
+ if (username == NULL)
+ {
+ if (getenv("PGUSER"))
+ username = getenv("PGUSER");
+ else
+ username = (char *)get_user_name(progname);
+ }
+
+ if (password == NULL)
+ {
+ if (getenv("PGPASSWORD"))
+ password = getenv("PGPASSWORD");
+ }
+
+ if ((passfile_env = getenv("PGPASSFILE")) != NULL)
+ /* use the literal path from the environment, if set */
+ StrNCpy(pgpassfile, passfile_env, MAXPGPATH);
+ else
+ {
+
+ if (!get_homedirectry(homedir, sizeof(homedir)))
+ {
+ fprintf(stderr,_("Oops?,home directry access denied.\n"));
+ exit(1);
+ }
+ snprintf(pgpassfile, MAXPGPATH, "%s/%s", homedir, PGPASSFILE);
+ }
+
+ /*
+ * List option
+ */
+ if (listpgpass)
+ {
+ printf("%s\n", pgpassfile);
+ /* view pgpass */
+ printf(_("This %dth line is used.\n"),
+ get_passwordfile(listpgpass, hostname, port, dbname, username));
+ exit(0);
+ }
+ else
+ {
+ update_position =
+ get_passwordfile(listpgpass, hostname, port, dbname, username);
+ }
+
+ /*
+ * Remove option
+ */
+ if (removepgpass)
+ {
+ char *reply;
+
+ reply = simple_prompt("Do you want to remove pgpass? (y/n) ", 1, true);
+ if (check_yesno_response(reply) == 1)
+ {
+ unlink(pgpassfile);
+ printf(_("Succeeded.\n"));
+ exit(0);
+ }
+ else
+ {
+ printf(_("Canceled.\n"));
+ exit(1);
+ }
+ }
+
+ password = simple_prompt("New Password: ", 100, false);
+ repassword = simple_prompt("Retype New Password: ", 100, false);
+
+ if (strcmp(password, repassword))
+ {
+ fprintf(stderr,_("Passwords do not match!\n"));
+ exit(1);
+ }
+
+ /* write the temp directory password */
+ pwtempfile = get_temporaryfile();
+ fop = fopen(pwtempfile, "w");
+
+ if (fop == NULL)
+ {
+ fprintf(stderr,_("tempfile(%s) create error!\n"), pwtempfile);
+ exit(1);
+ }
+
+ fip = fopen(pgpassfile, "r");
+
+ if (fip != NULL)
+ {
+ int rec_count = 0;
+ while (!feof(fip))
+ {
+ char buf[BUFSIZ];
+ buf[0] = '\0';
+
+ fgets(buf, BUFSIZ - 1, fip);
+ if (strlen(buf)== 0)
+ break;
+ rec_count++;
+
+ if (update_position == rec_count)
+ fprintf(fop, "%s:%s:%s:%s:%s\n",
+ hostname, port, dbname, username, password);
+ else
+ fputs(buf, fop);
+ }
+
+ fclose(fip);
+ }
+
+ if (update_position == 0)
+ fprintf(fop, "%s:%s:%s:%s:%s\n",
+ hostname, port, dbname, username, password);
+
+ fclose(fop);
+
+ unlink(pgpassfile);
+
+#ifdef DEBUG
+ fprintf(stderr,"%s\n",pwtempfile);
+#endif
+ if (!filemove(pwtempfile, pgpassfile))
+ {
+ fprintf(stderr,_("pgpass work error keep the tempfile(%s)!\n"), pwtempfile);
+ exit(1);
+ }
+
+#ifndef WIN32
+ chmod(pgpassfile, 0600);
+#endif
+ if (getenv("PGPASSWORD"))
+ {
+ fprintf(stderr,_("Notice:You specify the password by the environment variable.\n"));
+ fprintf(stderr,_(" It may become the connection demand which is not meant.\n"));
+ fprintf(stderr,_(" Please check environment PGPASSWORD.\n"));
+ }
+
+ printf(_("Succeeded in creation.\n"));
+
+ exit(0);
+}
+
+static void
+help(const char *progname)
+{
+ printf(_("%s installs a pgpass(libpq) connect a PostgreSQL database.\n\n"), progname);
+ printf(_("Usage:\n"));
+ printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
+ printf(_("\nOptions:\n"));
+ printf(_(" -l, --list show a list of installed pgpass\n"));
+ printf(_(" -r, --remove remove the my pgpass\n"));
+ printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
+ printf(_(" -p, --port=PORT database server port\n"));
+ printf(_(" -d, --dbname=DBNAME database to connect as\n"));
+ printf(_(" -U, --username=USERNAME user name to connect as\n"));
+ printf(_(" --help show this help, then exit\n"));
+ printf(_(" --version output version information, then exit\n"));
+ printf(_("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
+}
--- src/interfaces/libpq/libpqddll.def.orig Tue Feb 28 03:08:24 2006
+++ src/interfaces/libpq/libpqddll.def Tue Feb 28 03:09:00 2006
@@ -127,3 +127,4 @@
lo_create @ 123
PQinitSSL @ 124
PQregisterThreadLock @ 125
+ pqGetHomeDirectory @ 126
--- src/interfaces/libpq/libpqdll.def.orig Tue Feb 28 03:08:24 2006
+++ src/interfaces/libpq/libpqdll.def Tue Feb 28 03:10:37 2006
@@ -127,3 +127,4 @@
lo_create @ 123
PQinitSSL @ 124
PQregisterThreadLock @ 125
+ pqGetHomeDirectory @ 126
"Hiroshi Saito" <saito@inetrt.skcapi.co.jp> writes:
C:\Program Files\PostgreSQL\8.1\bin>pqpasswd.exe --help
pqpasswd installs a pgpass(libpq) connect a PostgreSQL database.
I must be missing something. What exactly does this accomplish that
couldn't be done at least as flexibly with a simple text editor?
If the argument is "point-and-drool Windows users can't be expected to
use a text editor", I would think that the same argument applies to
a command-line program; you'd have to make a GUI application to make
it easier to use than Notepad or what-have-you.
regards, tom lane
Thank you for a quick response.
From: "Tom Lane"
C:\Program Files\PostgreSQL\8.1\bin>pqpasswd.exe --help
pqpasswd installs a pgpass(libpq) connect a PostgreSQL database.I must be missing something. What exactly does this accomplish that
couldn't be done at least as flexibly with a simple text editor?
Ah, It is involved with an environment variable, and a user has to operate it,
fully taking into consideration. While opening the text editor, someone may
be in your back....
If the argument is "point-and-drool Windows users can't be expected to
use a text editor", I would think that the same argument applies to
a command-line program; you'd have to make a GUI application to make
it easier to use than Notepad or what-have-you.
Um, pgAdminIII is performing it. As for it, the solution method is different
though regrettable....
As a very important thing, I am planning future encryption.
Regards,
Hiroshi Saito