Re: [PATCHES] display and expression of the home directory in Win32

Started by Hiroshi Saitoalmost 20 years ago3 messages
#1Hiroshi Saito
saito@inetrt.skcapi.co.jp
1 attachment(s)

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
#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Hiroshi Saito (#1)

"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

#3Hiroshi Saito
saito@inetrt.skcapi.co.jp
In reply to: Hiroshi Saito (#1)

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