[Pkg-wmaker-commits] [wmbiff] 01/77: interactive password prompting support for imap - leave password in the : format blank to use
Doug Torrance
dtorrance-guest at moszumanska.debian.org
Thu Aug 20 03:01:01 UTC 2015
This is an automated email from the git hooks/post-receive script.
dtorrance-guest pushed a commit to tag wmbiff_0_4_0
in repository wmbiff.
commit 12be48c3d92d25ff5459ca1ddc6a21ba38404271
Author: bluehal <bluehal>
Date: Thu Apr 4 08:51:50 2002 +0000
interactive password prompting support for imap - leave password in the : format blank to use
---
wmbiff/Client.h | 17 ++--
wmbiff/Imap4Client.c | 75 +++++++++++----
wmbiff/Makefile | 7 +-
wmbiff/Pop3Client.c | 8 +-
wmbiff/passwordMgr.c | 252 +++++++++++++++++++++++++++++++++++++++++++++++++
wmbiff/passwordMgr.h | 4 +
wmbiff/sample.wmbiffrc | 9 +-
wmbiff/test-make.sh | 25 +++++
8 files changed, 358 insertions(+), 39 deletions(-)
diff --git a/wmbiff/Client.h b/wmbiff/Client.h
index 231f7e2..f7f002d 100644
--- a/wmbiff/Client.h
+++ b/wmbiff/Client.h
@@ -1,4 +1,4 @@
-/* $Id: Client.h,v 1.12 2002/03/12 23:53:15 bluehal Exp $ */
+/* $Id: Client.h,v 1.13 2002/04/04 08:51:50 bluehal Exp $ */
/* Author : Scott Holden ( scotth at thezone.net )
Modified : Yong-iL Joh ( tolkien at mizi.com )
Modified : Jorge Garc�a ( Jorge.Garcia at uv.es )
@@ -57,16 +57,9 @@ typedef struct _mbox_t {
int serverPort;
int localPort;
char authList[100];
- } pop;
- struct {
- char password[32];
- char userName[32];
- char serverName[256];
- int serverPort;
- int localPort;
- char authList[100];
- unsigned int dossl:1;
- } imap;
+ unsigned int dossl:1, /* use tls. */
+ interactive_password:1; /* prompt the user if we can't login / password is empty */
+ } pop_imap;
} u;
FILE *(*open) (Pop3);
@@ -75,6 +68,8 @@ typedef struct _mbox_t {
time_t prevtime;
time_t prevfetch_time;
int loopinterval; /* loop interval for this mailbox */
+
+ const char *askpass; /* command to execute to get a password, if needed */
} mbox_t;
#define BUF_SIZE 1024
diff --git a/wmbiff/Imap4Client.c b/wmbiff/Imap4Client.c
index 4052d00..f6f42ec 100644
--- a/wmbiff/Imap4Client.c
+++ b/wmbiff/Imap4Client.c
@@ -13,6 +13,7 @@
#include "Client.h"
#include "charutil.h"
#include "tlsComm.h"
+#include "passwordMgr.h"
#include <sys/types.h>
#include <stdio.h>
@@ -24,7 +25,7 @@
#include <dmalloc.h>
#endif
-#define PCU (pc->u).imap
+#define PCU (pc->u).pop_imap
#ifdef __LCLINT__
void asprintf( /*@out@ */ char **out, char *fmt, ...);
@@ -42,6 +43,7 @@ static struct fdmap_struct {
/*@owned@ */ struct connection_state *cs;
} fdmap[FDMAP_SIZE];
+static void ask_user_for_password(Pop3 pc, int bFlushCache);
/* authentication callbacks */
#ifdef WITH_GCRYPT
@@ -75,8 +77,8 @@ static struct connection_state *state_for_pcu(Pop3 pc)
char *connection_id;
struct connection_state *retval = NULL;
int i;
- asprintf(&connection_id, "%s|%s|%s|%d", PCU.userName,
- PCU.password, PCU.serverName, PCU.serverPort);
+ asprintf(&connection_id, "%s|%s|%d", PCU.userName,
+ PCU.serverName, PCU.serverPort);
for (i = 0; i < FDMAP_SIZE; i++)
if (fdmap[i].user_password_server_port != NULL &&
(strcmp(connection_id,
@@ -96,8 +98,8 @@ static void bind_state_to_pcu(Pop3 pc,
if (scs == NULL) {
abort();
}
- asprintf(&connection_id, "%s|%s|%s|%d", PCU.userName,
- PCU.password, PCU.serverName, PCU.serverPort);
+ asprintf(&connection_id, "%s|%s|%d", PCU.userName,
+ PCU.serverName, PCU.serverPort);
for (i = 0; i < FDMAP_SIZE && fdmap[i].cs != NULL; i++);
if (i == FDMAP_SIZE) {
/* should never happen */
@@ -258,6 +260,8 @@ int imap_checkmail(Pop3 pc)
/* if it's not in the cache, try to open */
if (scs == NULL) {
+ IMAP_DM(pc, DEBUG_INFO, "Need new connection to %s@%s\n",
+ PCU.userName, PCU.serverName);
(void) pc->open(pc);
scs = state_for_pcu(pc);
}
@@ -290,7 +294,7 @@ int imap4Create(Pop3 pc, const char *const str)
struct re_registers regs;
int i, matchedchars;
const char *regexes[] = {
- ".*imaps?:([^: ]{1,32}):([^@]{1,32})@([^/: ]+)(/[^: ]+)?(:[0-9]+)? *",
+ ".*imaps?:([^: ]{1,32}):([^@]{0,32})@([^/: ]+)(/[^: ]+)?(:[0-9]+)? *",
".*imaps?:([^: ]{1,32}) ([^ ]{1,32}) ([^/: ]+)(/[^: ]+)?( [0-9]+)? *",
NULL
};
@@ -334,6 +338,8 @@ int imap4Create(Pop3 pc, const char *const str)
/* copy matches where they belong */
copy_substring(PCU.userName, regs.start[1], regs.end[1], str);
copy_substring(PCU.password, regs.start[2], regs.end[2], str);
+ if (PCU.password[0] == '\0')
+ PCU.interactive_password = 1;
copy_substring(PCU.serverName, regs.start[3], regs.end[3], str);
if (regs.start[4] != -1)
copy_substring(pc->path, regs.start[4] + 1, regs.end[4], str);
@@ -378,20 +384,31 @@ static int authenticate_plaintext(Pop3 pc,
goto plaintext_failed;
}
- /* login */
- tlscomm_printf(scs, "a001 LOGIN %s \"%s\"\r\n", PCU.userName,
- PCU.password);
- if (!tlscomm_expect(scs, "a001 ", buf, BUF_SIZE)) {
- IMAP_DM(pc, DEBUG_ERROR,
- "Did not get a response to the LOGIN command.\n");
- goto plaintext_failed;
- }
+ ask_user_for_password(pc, 0);
+ do {
+ /* login */
+ tlscomm_printf(scs, "a001 LOGIN %s \"%s\"\r\n", PCU.userName,
+ PCU.password);
+ if (!tlscomm_expect(scs, "a001 ", buf, BUF_SIZE)) {
+ IMAP_DM(pc, DEBUG_ERROR,
+ "Did not get a response to the LOGIN command.\n");
+ goto plaintext_failed;
+ }
+
+ if (buf[5] != 'O') {
+ IMAP_DM(pc, DEBUG_ERROR, "IMAP Login failed.\n");
+ /* if we're prompting the user, ask again, else fail */
+ if (PCU.interactive_password) {
+ PCU.password[0] = '\0';
+ ask_user_for_password(pc, 1); /* 1=overwrite the cache */
+ } else {
+ goto plaintext_failed;
+ }
+ } else {
+ return (1);
+ }
+ } while (1);
- if (buf[5] != 'O') {
- IMAP_DM(pc, DEBUG_ERROR, "IMAP Login failed.\n");
- goto plaintext_failed;
- }
- return (1);
plaintext_failed:
return (0);
}
@@ -420,6 +437,7 @@ static int authenticate_md5(Pop3 pc,
strcpy(buf, PCU.userName);
strcat(buf, " ");
+ ask_user_for_password(pc, 0);
gmh = gcry_md_open(GCRY_MD_MD5, GCRY_MD_FLAG_HMAC);
gcry_md_setkey(gmh, PCU.password, strlen(PCU.password));
gcry_md_write(gmh, (unsigned char *) buf2, strlen(buf2));
@@ -452,3 +470,22 @@ static int authenticate_md5(Pop3 pc,
return 0;
}
#endif
+
+static void ask_user_for_password(Pop3 pc, int bFlushCache)
+{
+ /* see if we already have a password, as provided in the config file, or
+ already requested from the user. */
+ if (PCU.interactive_password) {
+ if (strlen(PCU.password) == 0) {
+ /* we need to grab the password from the user. */
+ const char *password;
+ IMAP_DM(pc, DEBUG_INFO, "asking for password %d\n",
+ bFlushCache);
+ password =
+ passwordFor(PCU.userName, PCU.serverName, pc, bFlushCache);
+ if (password != NULL) {
+ strcpy(PCU.password, password);
+ }
+ }
+ }
+}
diff --git a/wmbiff/Makefile b/wmbiff/Makefile
index 4ef3c27..ea5f600 100644
--- a/wmbiff/Makefile
+++ b/wmbiff/Makefile
@@ -1,6 +1,6 @@
# Makefile for wmbiff
#
-# $Id: Makefile,v 1.28 2002/03/26 16:30:32 jordi Exp $
+# $Id: Makefile,v 1.29 2002/04/04 08:51:50 bluehal Exp $
# Disable gnutls crypto?
#WITHOUT_CRYPTO= 1
@@ -24,7 +24,7 @@ CFLAGS?= -O2 -Wall -Wpointer-arith
# Nothing below here should need to be changed
###########################################################
-WMBIFF_VERSION= "0.3.8"
+WMBIFF_VERSION= "0.4.0pre1"
EXTRAFLAGS= -DWMBIFF_VERSION='$(WMBIFF_VERSION)'
# Default linux owners
@@ -74,7 +74,7 @@ INSTALL_FILE?= $(INSTALL) -p -o $(INSTALL_USER) -g $(INSTALL_GROUP) -m 644
OBJS = wmbiff.o socket.o \
Pop3Client.o LicqClient.o mboxClient.o \
maildirClient.o Imap4Client.o tlsComm.o \
- ShellClient.o \
+ ShellClient.o passwordMgr.o\
../wmgeneral/wmgeneral.o \
../wmgeneral/misc.o \
../wmgeneral/list.o \
@@ -84,6 +84,7 @@ all: wmbiff
Imap4Client.o: Imap4Client.c Client.h Makefile
Pop3Client.o: Pop3Client.c Client.h Makefile
+passwordMgr.o: passwordMgr.c passwordMgr.h Client.h Makefile
wmbiff.o: wmbiff-master.xpm wmbiff.c Client.h
.c.o:
diff --git a/wmbiff/Pop3Client.c b/wmbiff/Pop3Client.c
index 0508c82..edab0dd 100644
--- a/wmbiff/Pop3Client.c
+++ b/wmbiff/Pop3Client.c
@@ -1,4 +1,4 @@
-/* $Id: Pop3Client.c,v 1.9 2002/03/12 23:53:15 bluehal Exp $ */
+/* $Id: Pop3Client.c,v 1.10 2002/04/04 08:51:50 bluehal Exp $ */
/* Author : Scott Holden ( scotth at thezone.net )
Modified : Yong-iL Joh ( tolkien at mizi.com )
Modified : Jorge Garc�a ( Jorge.Garcia at uv.es )
@@ -18,7 +18,7 @@
#include <dmalloc.h>
#endif
-#define PCU (pc->u).pop
+#define PCU (pc->u).pop_imap
#define POP_DM(pc, lvl, args...) DM(pc, lvl, "pop3: " args)
#ifdef WITH_GCRYPT
@@ -162,7 +162,7 @@ int pop3Create(Pop3 pc, const char *str)
*/
const char *regexes[] = {
"pop3:([^: ]{1,32}) ([^ ]{1,32}) ([^: ]+)( [0-9]+)? *",
- "pop3:([^: ]{1,32}):([^@]{1,32})@([^: ]+)(:[0-9]+)? *",
+ "pop3:([^: ]{1,32}):([^@]{0,32})@([^: ]+)(:[0-9]+)? *",
NULL
};
@@ -276,8 +276,6 @@ static FILE *authenticate_apop(Pop3 pc, FILE * fp, char *apop_str)
/* server doesn't support apop. */
return (NULL);
}
- POP_DM(pc, DEBUG_INFO, "APOP challenge: %s\n", apop_str);
- strcat(apop_str, PCU.password);
gmh = gcry_md_open(GCRY_MD_MD5, 0);
gcry_md_write(gmh, (unsigned char *) apop_str, strlen(apop_str));
diff --git a/wmbiff/passwordMgr.c b/wmbiff/passwordMgr.c
new file mode 100644
index 0000000..d4c8357
--- /dev/null
+++ b/wmbiff/passwordMgr.c
@@ -0,0 +1,252 @@
+/* passwordMgr.c
+ * Author: Neil Spring
+ */
+/* this module implements a password cache: the goal is to
+ allow multiple wmbiff mailboxes that are otherwise
+ independent get all their passwords while only asking the
+ user for an account's password once. */
+/* NOTE: it will fail if a user has different passwords for
+ pop vs. imap on the same server; this seems too far
+ fetched to be worth complexity */
+
+/* NOTE: it verifies that the askpass program, which, if
+ given with a full path, must be owned either by the user
+ or by root. There may be decent reasons not to do
+ this. */
+
+/* Intended properties: 1) exit()s if the user presses
+ cancel from askpass - this is detected by no output from
+ askpass. 2) allows the caller to remove a cached entry
+ if it turns out to be wrong, and prompt the user
+ again. This might be poor if the askpass program is
+ replaced with something non-interactive. */
+
+#include "passwordMgr.h"
+#include "Client.h"
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+typedef struct password_binding_struct {
+ struct password_binding_struct *next;
+ char user[32];
+ char server[255];
+ char password[32];
+} *password_binding;
+
+password_binding pass_list = NULL;
+
+/* verifies that askpass_fname, if it has no spaces, exists as
+ a file, is owned by the user or by root, and is not world
+ writeable. This is just a sanity check, and is not intended
+ to ensure the integrity of the password-asking program. */
+static int permissions_ok(Pop3 pc, const char *askpass_fname)
+{
+ struct stat st;
+ if (index(askpass_fname, ' ')) {
+ DM(pc, DEBUG_ERROR,
+ "askpass has a space in it; not verifying ownership/permissions on '%s'\n",
+ askpass_fname);
+ return (1);
+ }
+ if (stat(askpass_fname, &st)) {
+ DM(pc, DEBUG_ERROR, "Can't stat askpass program: '%s'\n",
+ askpass_fname);
+ DM(pc, DEBUG_ERROR, "For your own good, use a full pathname.\n");
+ return (0);
+ }
+ if (st.st_uid != 0 && st.st_uid != getuid()) {
+ DM(pc, DEBUG_ERROR,
+ "askpass program isn't owned by you or root: '%s'\n",
+ askpass_fname);
+ return (0);
+ }
+ if (st.st_mode & S_IWOTH) {
+ DM(pc, DEBUG_ERROR,
+ "askpass program is world writable: '%s'\n", askpass_fname);
+ return (0);
+ }
+ return (1);
+}
+
+const char *passwordFor(const char *username,
+ const char *servername, Pop3 pc, int bFlushCache)
+{
+
+ password_binding p;
+
+ /* find the binding */
+ for (p = pass_list;
+ p != NULL
+ && (strcmp(username, p->user) != 0 ||
+ strcmp(servername, p->server) != 0); p = p->next);
+
+ /* if so, return the password */
+ if (p != NULL) {
+ if (p->password[0] != '\0') {
+ if (bFlushCache == 0)
+ return (p->password);
+ /* else fall through, overwrite */
+ } else if (pc) {
+ /* if we've asked, but received nothing, disable this box */
+ pc->open = NULL;
+ pc->checkMail = NULL;
+ return (NULL);
+ }
+ } else {
+ p = (password_binding)
+ malloc(sizeof(struct password_binding_struct));
+ }
+
+ /* else, try to get it. */
+ if (pc->askpass != NULL) {
+ /* check that the executed file is a good one. */
+ if (permissions_ok(pc, pc->askpass)) {
+ char buf[255];
+ FILE *fp;
+ int l;
+ int exit_status;
+ strcpy(p->user, username);
+ strcpy(p->server, servername);
+ sprintf(buf, "%s 'password for wmbiff: %s@%s'",
+ pc->askpass, username, servername);
+
+ DM(pc, DEBUG_INFO, "passmgr: invoking %s\n", buf);
+ fp = popen(buf, "r");
+
+ if (fgets(p->password, 32, fp) == NULL) {
+ /* this likely means that the user cancelled, and doesn't
+ want us to keep asking about the password. */
+ DM(pc, DEBUG_ERROR,
+ "passmgr: fgets password failed, exiting\n");
+ DM(pc, DEBUG_ERROR,
+ "passmgr: (it looks like you pressed 'cancel')\n");
+ /* this seems like the sanest thing to do, for now */
+ exit(EXIT_FAILURE);
+ }
+
+ exit_status = pclose(fp);
+ if (exit_status != 0) {
+ if (exit_status == -1) {
+ /* an expected case with the signal handler */
+ DM(pc, DEBUG_INFO,
+ "passmgr: pclose from '%s' failed: %s\n", buf,
+ strerror(errno));
+ } else {
+ DM(pc, DEBUG_ERROR,
+ "passmgr: '%s' returne non-zero exit status %d\n",
+ buf, exit_status);
+ }
+ }
+
+ /* chomp; */
+ l = strlen(p->password) - 1;
+ if (p->password[l] == '\n')
+ p->password[l] = '\0';
+ p->next = pass_list;
+ pass_list = p;
+ return (p->password);
+ }
+ }
+
+ return (NULL);
+}
+
+#ifdef TEST_PASS_MGR
+int main(int argc, char *argv[])
+{
+ const char *b;
+ mbox_t m;
+
+ /* sh is almost certainly conforming; owned by root, etc. */
+ if (!permissions_ok(NULL, "/bin/sh")) {
+ printf("FAILURE: permission checker failed on /bin/sh.");
+ exit(EXIT_FAILURE);
+ }
+ /* tmp is definitely bad; and better be og+w */
+ if (permissions_ok(NULL, "/tmp")) {
+ printf("FAILURE: permission checker failed on /tmp.");
+ exit(EXIT_FAILURE);
+ }
+ /* TODO: also find some user-owned binary that shouldn't be g+w */
+ printf("SUCCESS: permission checker sanity check went well.\n");
+
+ /* *** */
+ m.askpass = "echo xlnt; #";
+
+ b = passwordFor("bill", "ted", &m, 0);
+ if (strcmp(b, "xlnt") != 0) {
+ printf("FAILURE: expected 'xlnt' got '%s'\n", b);
+ exit(EXIT_FAILURE);
+ }
+ printf("SUCCESS: expected 'xlnt' got '%s'\n", b);
+
+ /* *** */
+ m.askpass = "should be cached";
+ b = passwordFor("bill", "ted", &m, 0);
+ if (strcmp(b, "xlnt") != 0) {
+ printf("FAILURE: expected 'xlnt' got '%s'\n", b);
+ exit(EXIT_FAILURE);
+ }
+
+ printf("SUCCESS: cached 'xlnt' correctly\n");
+
+ /* *** */
+ m.askpass = "echo abcdefghi1abcdefghi2abcdefghi3a; #";
+
+ b = passwordFor("abbot", "costello", &m, 0);
+ if (strcmp(b, "abcdefghi1abcdefghi2abcdefghi3a") != 0) {
+ printf
+ ("FAILURE: expected 'abcdefghi1abcdefghi2abcdefghi3a' got '%s'\n",
+ b);
+ exit(EXIT_FAILURE);
+ }
+ printf
+ ("SUCCESS: expected 'abcdefghi1abcdefghi2abcdefghi3ab' got '%s'\n",
+ b);
+
+ /* try overflowing the buffer */
+ m.askpass = "echo abcdefghi1abcdefghi2abcdefghi3ab; #";
+ b = passwordFor("laverne", "shirley", &m, 0);
+ /* should come back truncated to fill the buffer */
+ if (strcmp(b, "abcdefghi1abcdefghi2abcdefghi3a") != 0) {
+ printf
+ ("FAILURE: expected 'abcdefghi1abcdefghi2abcdefghi3a' got '%s'\n",
+ b);
+ exit(EXIT_FAILURE);
+ }
+ printf
+ ("SUCCESS: expected 'abcdefghi1abcdefghi2abcdefghi3ab' got '%s'\n",
+ b);
+
+ /* make sure we still have the old one */
+ b = passwordFor("bill", "ted", &m, 0);
+ if (strcmp(b, "xlnt") != 0) {
+ printf("FAILURE: expected 'xlnt' got '%s'\n", b);
+ exit(EXIT_FAILURE);
+ }
+ printf("SUCCESS: expected 'xlnt' got '%s'\n", b);
+
+ /* what it's like if ssh-askpass is cancelled - should drop the mailbox */
+ m.askpass = "echo -n ; #";
+ b = passwordFor("abort", "me", &m, 0);
+ if (strcmp(b, "") != 0) {
+ printf("FAILURE: expected '' got '%s'\n", b);
+ exit(EXIT_FAILURE);
+ }
+ printf("SUCCESS: expected '' got '%s'\n", b);
+
+ /* what it's like if ssh-askpass is ok'd with an empty password. */
+ m.askpass = "echo ; #";
+ b = passwordFor("try", "again", &m, 0);
+ if (strcmp(b, "") != 0) {
+ printf("FAILURE: expected '' got '%s'\n", b);
+ exit(EXIT_FAILURE);
+ }
+ printf("SUCCESS: expected '' got '%s'\n", b);
+
+ exit(EXIT_SUCCESS);
+}
+#endif
diff --git a/wmbiff/passwordMgr.h b/wmbiff/passwordMgr.h
new file mode 100644
index 0000000..11d0621
--- /dev/null
+++ b/wmbiff/passwordMgr.h
@@ -0,0 +1,4 @@
+#include "Client.h"
+
+const char *passwordFor(const char *username,
+ const char *servername, Pop3 pc, int bFlushCache);
diff --git a/wmbiff/sample.wmbiffrc b/wmbiff/sample.wmbiffrc
index 660456b..c59cd82 100644
--- a/wmbiff/sample.wmbiffrc
+++ b/wmbiff/sample.wmbiffrc
@@ -1,10 +1,17 @@
-# $Id: sample.wmbiffrc,v 1.8 2002/03/06 07:15:08 bluehal Exp $
+# $Id: sample.wmbiffrc,v 1.9 2002/04/04 08:51:50 bluehal Exp $
#
# See wmbiffrc(5) for more info.
#
# Global interval -- seconds between check mailboxes
interval=60
+# Global askpass -- choose a password acting program
+# that behaves like ssh-askpass
+# the commented version below is likely to work on RedHat
+# systems; wmbiff's default is likely to work on Debian
+# systems with ssh-askpass installed.
+#askpass = /usr/libexec/openssh/x11-ssh-askpass
+
### First string ###
# Label, that will be displayed
diff --git a/wmbiff/test-make.sh b/wmbiff/test-make.sh
new file mode 100755
index 0000000..6ab3686
--- /dev/null
+++ b/wmbiff/test-make.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+# a short script to make sure that wmbiff builds under various
+# options. this is not necessary for normal users, and is
+# intended as a last-minute sanity check before a release.
+echo NO-CRYPTO BUILD
+make clean
+WITHOUT_CRYPTO=1 make
+
+echo NORMAL BUILD
+make clean
+make
+
+echo DEBUG BUILD
+make clean
+DEBUG=1 make
+
+# doesn't really work on non -bsd
+if test `uname` != 'Linux'; then
+ echo LIKE BSD
+ make clean
+ EXT_GNU_REGEX_LIB=1 make
+fi
+
+# like I said... before a release.
+make clean
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-wmaker/wmbiff.git
More information about the Pkg-wmaker-commits
mailing list