dovecotpw.c revision 034ba60e28b45896b4a26548fe3a6d0be5f6dfa0
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen/* Copyright (C) 2004 Joshua Goodall */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "lib.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "array.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "password-scheme.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "randgen.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include "safe-memset.h"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include <ctype.h>
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include <fcntl.h>
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include <stdio.h>
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include <stdlib.h>
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#include <unistd.h>
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen#ifdef HAVE_LIBGEN_H
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen# include <libgen.h>
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#endif
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen#define DEFAULT_SCHEME "HMAC-MD5"
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic void __attr_noreturn__
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenusage(const char *s)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen fprintf(stderr,
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen "usage: %s [-l] [-p plaintext] [-s scheme] [-u user] [-V]\n", s);
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen " -l List known password schemes",
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen " -p plaintext New password",
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen " -s scheme Password scheme",
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen " -u user Username (if scheme uses it)",
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen " -V Internally verify the hash");
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen exit(1);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenint main(int argc, char *argv[])
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen{
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen const char *hash = NULL;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen const char *user = NULL;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen char *scheme = NULL;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen char *plaintext = NULL;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen int ch, lflag = 0, Vflag = 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen lib_init();
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen random_init();
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen password_schemes_init();
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen while ((ch = getopt(argc, argv, "lp:s:u:V")) != -1) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen switch (ch) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen case 'l':
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen lflag = 1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen break;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen case 'p':
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen plaintext = i_strdup(optarg);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen safe_memset(optarg, 0, strlen(optarg));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen break;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen case 's':
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen scheme = i_strdup(optarg);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen break;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen case 'u':
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen user = i_strdup(optarg);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen break;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen case 'V':
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen Vflag = 1;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen break;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen case '?':
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen default:
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen usage(basename(*argv));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (lflag) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen const struct password_scheme *const *schemes;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen unsigned int i, count;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen schemes = array_get(&password_schemes, &count);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen for (i = 0; i < count; i++)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen printf("%s ", schemes[i]->name);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen printf("\n");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen exit(0);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (argc != optind)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen usage(basename(*argv));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (scheme == NULL)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen scheme = i_strdup(DEFAULT_SCHEME);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen else {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen char *c;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen for (c = scheme; *c != '\0'; c++)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen *c = i_toupper(*c);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen while (plaintext == NULL) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen char *check;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen static int lives = 3;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen plaintext = i_strdup(getpass("Enter new password: "));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen check = i_strdup(getpass("Retype new password: "));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (strcmp(plaintext, check) != 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen fprintf(stderr, "Passwords don't match!\n");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (--lives == 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen exit(1);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen safe_memset(plaintext, 0, strlen(plaintext));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen safe_memset(check, 0, strlen(check));
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_free(plaintext);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_free(check);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen plaintext = NULL;
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (!password_generate_encoded(plaintext, user, scheme, &hash)) {
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen fprintf(stderr, "Unknown scheme: %s\n", scheme);
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen exit(1);
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen }
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen if (Vflag == 1) {
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen const unsigned char *raw_password;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen size_t size;
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen if (password_decode(hash, scheme, &raw_password, &size) <= 0) {
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen fprintf(stderr, "reverse decode check failed\n");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen exit(2);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (password_verify(plaintext, user, scheme,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen raw_password, size) != 1) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen fprintf(stderr,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "reverse password verification check failed\n");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen exit(2);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen }
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen printf("{%s}%s (verified)\n", scheme, hash);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen } else
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen printf("{%s}%s\n", scheme, hash);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return 0;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen}
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen