summaryrefslogtreecommitdiffstats
path: root/src/pam-dotfile-gen.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pam-dotfile-gen.c')
-rw-r--r--src/pam-dotfile-gen.c280
1 files changed, 280 insertions, 0 deletions
diff --git a/src/pam-dotfile-gen.c b/src/pam-dotfile-gen.c
new file mode 100644
index 0000000..0d10ec3
--- /dev/null
+++ b/src/pam-dotfile-gen.c
@@ -0,0 +1,280 @@
+/***
+ This file is part of pam_dotfile.
+
+ pam_dotfile is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ pam_dotfile is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with pam_dotfile; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA
+***/
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include <string.h>
+#include <termios.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "md5.h"
+#include "md5util.h"
+
+#ifdef COMPAT05
+int compat = 0;
+#endif
+
+static void _random(char *r, int l) {
+ FILE *f;
+ int b = 0;
+
+ if ((f = fopen("/dev/urandom", "r"))) {
+ if (fread(r, l, 1, f) == 1)
+ b = 1;
+ fclose(f);
+ }
+
+ if (!b) {
+ int i;
+ fprintf(stderr, "WARNING: Could not read /dev/urandom, generating pseudo randomness.\n");
+
+ for (i = 0; i < l; i++)
+ r[i] = (unsigned char) rand() & 0xFF;
+ }
+}
+
+static void _md5_gen(const char *password, FILE *f) {
+ static unsigned char salt[16];
+ static char saltc[33];
+ static unsigned char digest[16];
+ static char digestc[33];
+ md5_state_t t;
+
+ _random(salt, 16);
+
+ fhex(salt, 16, saltc);
+ saltc[32] = 0;
+
+ md5_init(&t);
+ md5_append(&t, saltc, 32);
+ md5_append(&t, password, strlen(password));
+ md5_finish(&t, digest);
+
+#ifdef COMPAT05
+ if (compat)
+ fhex_broken_md5(digest, digestc);
+ else
+#endif
+ fhex_md5(digest, digestc);
+ digestc[32] = 0;
+
+#ifdef COMPAT05
+ fprintf(f, "%s%s%s\n", compat ? "" : "+", saltc, digestc);
+#else
+ fprintf(f, "+%s%s\n", saltc, digestc);
+#endif
+}
+
+void usage(char *argv0) {
+ char *p;
+
+ if ((p = strrchr(argv0, '/')))
+ p++;
+ else
+ p = argv0;
+
+#ifdef COMPAT05
+ printf("%s [-C] [-a <service>] | -h\n"
+#else
+ printf("%s [-a <service>] | -h\n"
+#endif
+ " -a <service> Add a password for the specified service\n"
+ " -h Show this help\n"
+#ifdef COMPAT05
+ " -C Enable compatibility with pam_dotfile <= 0.5\n"
+#endif
+ , p);
+}
+
+char *chomp(char *p) {
+ char *e;
+
+ while ((e = strchr(p, '\n')))
+ *e = 0;
+
+ return p;
+}
+
+int set_echo(int fd, int b) {
+ static struct termios saved;
+
+ if (!b) {
+ static struct termios t;
+
+ if (tcgetattr(fd, &saved) < 0) {
+ fprintf(stderr, "tcgetattr(): %s\n", strerror(errno));
+ return -1;
+ }
+
+ t = saved;
+ t.c_lflag &= ~ECHO;
+
+ if (tcsetattr(fd, TCSANOW, &t) < 0) {
+ fprintf(stderr, "tcsetattr(): %s\n", strerror(errno));
+ return -1;
+ }
+
+ } else {
+ if (tcsetattr(fd, TCSANOW, &saved) < 0) {
+ fprintf(stderr, "tcsetattr(): %s\n", strerror(errno));
+ return -1;
+ }
+ }
+
+
+ return 0;
+}
+
+int add_password(char *p) {
+ FILE *f = NULL;
+ static char fn[PATH_MAX];
+ static char password1[128], password2[128];
+ int r = -1;
+ int e = 0;
+ mode_t m;
+
+ if (isatty(STDIN_FILENO)) {
+ if (set_echo(STDIN_FILENO, 0) < 0)
+ goto finish;
+
+ e = 1;
+ }
+
+ snprintf(fn, sizeof(fn), "%s/.pam-%s", getenv("HOME"), p);
+
+ m = umask(0077);
+ if (!(f = fopen(fn, "a"))) {
+ umask(m);
+ fprintf(stderr, "Could not open file <%s> for writing: %s\n", fn, strerror(errno));
+ goto finish;
+ }
+ umask(m);
+
+ if (isatty(STDIN_FILENO)) {
+ fputs("Password:", stdout);
+ fflush(stdout);
+ }
+
+ if (!fgets(password1, sizeof(password1), stdin)) {
+ fprintf(stderr, "Failure reading password\n");
+ goto finish;
+ }
+
+ if (isatty(STDIN_FILENO)) {
+ fputs("\nPlease repeat; password:", stdout);
+ fflush(stdout);
+ }
+
+ if (!fgets(password2, sizeof(password2), stdin)) {
+ fprintf(stderr, "Failure reading password\n");
+ goto finish;
+ }
+
+ if (isatty(STDIN_FILENO)) {
+ fputs("\n", stdout);
+ fflush(stdout);
+ }
+
+ chomp(password1);
+ chomp(password2);
+
+ if (strcmp(password1, password2)) {
+ fprintf(stderr, "ERROR: Passwords do not match!\n");
+ goto finish;
+ }
+
+ _md5_gen(password1, f);
+
+ fprintf(stderr, "Password added.\n");
+
+ r = 0;
+
+finish:
+ if (e)
+ set_echo(STDIN_FILENO, 1);
+
+ if (f) {
+ fclose(f);
+ chmod(fn, 0600);
+ }
+
+ return 0;
+}
+
+int main(int argc, char*argv[]) {
+ int c;
+#ifdef COMPAT05
+ const char* argspec = "a:hC";
+#else
+ const char* argspec = "a:h";
+#endif
+ char *addp = 0;
+
+ srand(time(NULL)*getpid());
+
+
+ while ((c = getopt(argc, argv, argspec)) > 0) {
+
+ switch (c) {
+ case 'a' :
+ addp = optarg;
+ break;
+
+#ifdef COMPAT05
+ case 'C':
+ compat = 1;
+ break;
+#endif
+
+ default:
+ usage(argv[0]);
+ return 1;
+ }
+ }
+
+
+ if (addp)
+ return add_password(addp) < 0 ? 1 : 0;
+
+ for(;;) {
+ int n;
+ static char ln[256];
+
+ if (!fgets(ln, sizeof(ln), stdin))
+ break;
+
+ if (ln[0] == 0 || ln[0] == '\n' || ln[0] == '#') {
+ fputs(ln, stdout);
+ continue;
+ }
+
+ if (ln[(n = strlen(ln))-1] == '\n')
+ ln[n-1] = 0;
+
+ _md5_gen(ln, stdout);
+ }
+
+ return 0;
+}