/*
- * @(#) pg_passwd.c 1.8 09:13:16 97/07/02 Y. Ichikawa
+ * @(#) pg_passwd.c 1.8 09:13:16 97/07/02 Y. Ichikawa
*/
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include <ctype.h>
-#define issaltchar(c) (isalnum(c) || (c) == '.' || (c) == '/')
+#define issaltchar(c) (isalnum(c) || (c) == '.' || (c) == '/')
+
#include "postgres.h"
#ifdef HAVE_TERMIOS_H
#include <termios.h>
#ifdef HAVE_CRYPT_H
#include <crypt.h>
#else
-extern char *crypt(const char *, const char *);
+extern char *crypt(const char *, const char *);
#endif
-char *comname;
+
+char *comname;
void usage(FILE *stream);
void read_pwd_file(char *filename);
void write_pwd_file(char *filename, char *bkname);
int check_pwd(char key[9], char passwd[14]);
void prompt_for_username(char *username);
void prompt_for_password(char *prompt, char *password);
+
void usage(FILE *stream)
{
- fprintf(stream, "Usage: %s <password file>\n", comname);
+ fprintf(stream, "Usage: %s <password file>\n", comname);
}
+
typedef struct {
- char *uname;
- char *pwd;
- char *rest;
+ char *uname;
+ char *pwd;
+ char *rest;
} pg_pwd;
-#define MAXPWDS 1024
-pg_pwd pwds[MAXPWDS];
-int npwds = 0;
+
+#define MAXPWDS 1024
+
+pg_pwd pwds[MAXPWDS];
+int npwds = 0;
+
+
void read_pwd_file(char *filename)
{
- FILE *fp;
- static char line[512];
+ FILE *fp;
+ static char line[512];
static char ans[128];
- int i;
+ int i;
+
try_again:
fp = fopen(filename, "r");
if (fp == NULL) {
- if (errno == ENOENT) {
- printf("File \"%s\" does not exist. Create? (y/n): ", filename);
- fflush(stdout);
- fgets(ans, 128, stdin);
- switch (ans[0]) {
- case 'y': case 'Y':
- fp = fopen(filename, "w");
- if (fp == NULL) {
- perror(filename);
- exit(1);
- }
- fclose(fp);
- goto try_again;
- default:
- /* cannot continue */
- exit(1);
- }
- } else {
- perror(filename);
- exit(1);
- }
+ if (errno == ENOENT) {
+ printf("File \"%s\" does not exist. Create? (y/n): ", filename);
+ fflush(stdout);
+ fgets(ans, 128, stdin);
+ switch (ans[0]) {
+ case 'y': case 'Y':
+ fp = fopen(filename, "w");
+ if (fp == NULL) {
+ perror(filename);
+ exit(1);
+ }
+ fclose(fp);
+ goto try_again;
+ default:
+ /* cannot continue */
+ exit(1);
+ }
+ } else {
+ perror(filename);
+ exit(1);
+ }
}
+
/* read all the entries */
- for (npwds = 0; npwds < MAXPWDS && fgets(line, 512, fp) != NULL; ++npwds)
+ for (npwds = 0; npwds < MAXPWDS && fgets(line, 512, fp) != NULL; ++npwds) {
+ int l;
+ char *p, *q;
+ l = strlen(line);
+ if (line[l-1] == '\n')
+ line[l-1] = '\0';
+ else { /* too long */
+ fprintf(stderr, "%s: line %d: line too long.\n",
+ filename, npwds + 1);
+ exit(1);
+ }
+
+ /* get user name */
+ p = line;
+ if ((q = index(p, ':')) == NULL) {
+ fprintf(stderr, "%s: line %d: illegal format.\n",
+ filename, npwds + 1);
+ exit(1);
+ }
+ *(q++) = '\0';
+ if (strlen(p) == 0) {
+ fprintf(stderr, "%s: line %d: null user name.\n",
+ filename, npwds + 1);
+ exit(1);
+ }
+ pwds[npwds].uname = strdup(p);
+
+ /* check duplicate */
+ for (i = 0; i < npwds; ++i) {
+ if (strcmp(pwds[i].uname, pwds[npwds].uname) == 0) {
+ fprintf(stderr, "%s: duplicated entry.\n", pwds[npwds].uname);
+ exit(1);
+ }
+ }
+
+ /* get password field */
+ p = q;
+ q = index(p, ':');
+ /*
+ * --- don't care -----
+ if ((q = index(p, ':')) == NULL) {
+ fprintf(stderr, "%s: line %d: illegal format.\n",
+ filename, npwds + 1);
+ exit(1);
+ }
+ */
+
+ if (q != NULL) *(q++) = '\0';
+ if (strlen(p) != 13) {
+ fprintf(stderr, "WARNING: %s: line %d: illegal password length.\n",
+ filename, npwds + 1);
+ }
+ pwds[npwds].pwd = strdup(p);
+
+ /* rest of the line is treated as is */
+ if (q == NULL)
+ pwds[npwds].rest = NULL;
+ else
+ pwds[npwds].rest = strdup(q);
+ }
+
+ fclose(fp);
+}
+
+void write_pwd_file(char *filename, char *bkname)
+{
+ FILE* fp;
+ int i;
+
+ /* make the backup file */
+ link_again:
+ if (link(filename, bkname)) {
+ if (errno == EEXIST) {
+ unlink(bkname);
+ goto link_again;
+ }
+ perror(bkname);
+ exit(1);
+ }
+ if (unlink(filename)) {
+ perror(filename);
+ exit(1);
+ }
+
+ /* open file */
+ if ((fp = fopen(filename, "w")) == NULL) {
+ perror(filename);
+ exit(1);
+ }
+
+ /* write file */
+ for (i = 0; i < npwds; ++i) {
+ fprintf(fp, "%s:%s%s%s\n", pwds[i].uname, pwds[i].pwd,
+ pwds[i].rest ? ":" : "",
+ pwds[i].rest ? pwds[i].rest : "");
+ }
+
+ fclose(fp);
+}
+
+void encrypt_pwd(char key[9], char salt[3], char passwd[14])
+{
+ int n;
+
+ /* get encrypted password */
+ if (salt[0] == '\0') {
+ struct timeval tm;
+ gettimeofday(&tm, NULL);
+ srand(tm.tv_sec ? tm.tv_sec : 1);
+ do {
+ n = rand() % 256;
+ } while (! issaltchar(n));
+ salt[0] = n;
+ do {
+ n = rand() % 256;
+ } while (! issaltchar(n));
+ salt[1] = n;
+ salt[2] = '\0';
+ }
+ strcpy(passwd, crypt(key, salt));
+
+ /* show it */
+ /* fprintf(stderr, "key = %s, salt = %s, password = %s\n",
+ key, salt, passwd); */
+}
+
+int check_pwd(char key[9], char passwd[14])
+{
+ char shouldbe[14];
+ char salt[3];
+
+ salt[0] = passwd[0];
+ salt[1] = passwd[1];
+ salt[2] = '\0';
+ encrypt_pwd(key, salt, shouldbe);
+
+ return strncmp(shouldbe, passwd, 13) == 0 ? 1 : 0;
+}
+
+void prompt_for_username(char *username)
+{
+ int length;
+
+ printf("Username: ");
+ fgets(username, 9, stdin);
+ length = strlen(username);
+
+ /* skip rest of the line */
+ if (length > 0 && username[length-1] != '\n') {
+ static char buf[512];
+ do {
+ fgets(buf, 512, stdin);
+ } while (buf[strlen(buf)-1] != '\n');
+ }
+ if(length > 0 && username[length-1] == '\n') username[length-1] = '\0';
+}
+
+void prompt_for_password(char *prompt, char *password)
+{
+ int length;
+#ifdef HAVE_TERMIOS_H
+ struct termios t_orig, t;
+#endif
+
+ printf(prompt);
+#ifdef HAVE_TERMIOS_H
+ tcgetattr(0, &t);
+ t_orig = t;
+ t.c_lflag &= ~ECHO;
+ tcsetattr(0, TCSADRAIN, &t);
+#endif
+ fgets(password, 9, stdin);
+#ifdef HAVE_TERMIOS_H
+ tcsetattr(0, TCSADRAIN, &t_orig);
+#endif
+
+ length = strlen(password);
+ /* skip rest of the line */
+ if (length > 0 && password[length-1] != '\n') {
+ static char buf[512];
+ do {
+ fgets(buf, 512, stdin);
+ } while (buf[strlen(buf)-1] != '\n');
+ }
+ if(length > 0 && password[length-1] == '\n') password[length-1] = '\0';
+ printf("\n");
+}
+
+
+int main(int argc, char *argv[])
+{
+ static char bkname[512];
+ char username[9];
+ char salt[3];
+ char key[9], key2[9];
+ char e_passwd[14];
+ int i;
+
+ comname = argv[0];
+ if (argc != 2) {
+ usage(stderr);
+ exit(1);
+ }
+
+
+ /* open file */
+ read_pwd_file(argv[1]);
+
+ /* ask for the user name and the password */
+ prompt_for_username(username);
+ prompt_for_password("New password: ", key);
+ prompt_for_password("Re-enter new password: ", key2);
+ if (strncmp(key, key2, 8) != 0) {
+ fprintf(stderr, "Password mismatch.\n");
+ exit(1);
+ }
+ salt[0] = '\0';
+ encrypt_pwd(key, salt, e_passwd);
+
+ /* check password entry */
+ for (i = 0; i < npwds; ++i) {
+ if (strcmp(pwds[i].uname, username) == 0) { /* found */
+ pwds[i].pwd = strdup(e_passwd);
+ break;
+ }
+ }
+ if (i == npwds) { /* did not exist */
+ if (npwds == MAXPWDS) {
+ fprintf(stderr, "%s: cannot handle so may entries.\n", comname);
+ exit(1);
+ }
+ pwds[npwds].uname = strdup(username);
+ pwds[npwds].pwd = strdup(e_passwd);
+ pwds[npwds].rest = NULL;
+ ++npwds;
+ }
+
+ /* write back the file */
+ sprintf(bkname, "%s.bk", argv[1]);
+ write_pwd_file(argv[1], bkname);
+
+ return 0;
+}