]> diplodocus.org Git - nmh/commitdiff
A "credentials" mh-profile entry has been added. This allows
authorDavid Levine <levinedl@acm.org>
Sun, 14 Apr 2013 14:53:32 +0000 (09:53 -0500)
committerDavid Levine <levinedl@acm.org>
Sun, 14 Apr 2013 14:53:32 +0000 (09:53 -0500)
post(8), whom(1), send(1), inc(1), and msgchk(1) to (optionally)
honour the username in the .netrc file [Bug #23168].  And, it
allows specification of any valid filename in place of $HOME/.netrc.

18 files changed:
Makefile.am
config/config.c
docs/pending-release-notes
h/mh.h
h/prototypes.h
man/inc.man
man/mh-profile.man
man/msgchk.man
man/post.man
man/send.man
man/whom.man
mts/smtp/smtp.c
sbr/credentials.c [new file with mode: 0644]
sbr/ruserpass.c
test/inc/test-pop
uip/inc.c
uip/msgchk.c
uip/popsbr.c

index 470a763..78cce55 100644 (file)
@@ -518,8 +518,8 @@ sbr_libmh_a_SOURCES = sbr/addrsbr.c sbr/ambigsw.c sbr/atooi.c sbr/arglist.c \
                      sbr/context_find.c sbr/context_foil.c sbr/context_read.c \
                      sbr/context_replace.c sbr/context_save.c \
                      sbr/copy.c sbr/copyip.c sbr/cpydata.c \
-                     sbr/cpydgst.c sbr/crawl_folders.c sbr/discard.c \
-                     sbr/done.c sbr/dtimep.l sbr/dtime.c \
+                     sbr/cpydgst.c sbr/crawl_folders.c sbr/credentials.c \
+                     sbr/discard.c sbr/done.c sbr/dtimep.l sbr/dtime.c \
                      sbr/escape_addresses.c \
                      sbr/error.c sbr/ext_hook.c sbr/fdcompare.c \
                      sbr/folder_addmsg.c sbr/folder_delmsgs.c \
index 4024d30..151f7fc 100644 (file)
@@ -103,6 +103,9 @@ char *mh_defaults = nmhetcdir (/mh.profile);
 /* default name of user profile */
 char *mh_profile = ".mh_profile";
 
+/* name of credentials file, defaults to .netrc in either Path or $HOME. */
+char *credentials_file;
+
 /* name of current message "sequence" */
 char *current = "cur";
 
index 3b22581..e88165d 100644 (file)
@@ -120,3 +120,7 @@ BUG FIXES
 - Removed the artificial limit of 1000 messages at a time for rmmproc.
 - Fixed decoding of header fields when they contain a character that
   can't be converted.
+- post(8) -sasl now honours username in .netrc [Bug #23168].  whom(1),
+  send(1), inc(1), and msgchk(1) also benefit from this fix.  And, nmh
+  now supports specification of any valid filename in place of
+  $HOME/.netrc.
diff --git a/h/mh.h b/h/mh.h
index f5fd66b..354f3fa 100644 (file)
--- a/h/mh.h
+++ b/h/mh.h
@@ -357,6 +357,17 @@ typedef struct m_getfld_state *m_getfld_state_t;
 
 #define NMH_ATTACH_HEADER "Nmh-Attachment"  /* Default header for -attach */
 
+/*
+ * credentials management
+ */
+struct nmh_creds {
+    char *host;
+    char *user;
+    char *password;
+};
+
+typedef struct nmh_creds *nmh_creds_t;
+
 /*
  * miscellaneous macros
  */
@@ -405,6 +416,7 @@ extern char *catproc;
 extern char *components;
 extern char *context;
 extern char *current;
+extern char *credentials_file;
 extern char *defaultfolder;
 extern char *digestcomps;
 extern char *distcomps;
index 8fa3157..94be46a 100644 (file)
@@ -148,7 +148,7 @@ char *pwd (void);
 char *r1bindex(char *, int);
 void readconfig (struct node **, FILE *, char *, int);
 int refile (char **, char *);
-void ruserpass(char *, char **, char **);
+void ruserpass (char *, char **, char **);
 int remdir (char *);
 void scan_detect_mbox_style (FILE *);
 void scan_finished ();
@@ -228,3 +228,9 @@ int what_now (char *, int, int, char *, char *,
 int WhatNow(int, char **);
 int writeBase64aux(FILE *, FILE *);
 int writeBase64 (unsigned char *, size_t, unsigned char *);
+
+/*
+ * credentials management
+ */
+void init_credentials_file ();
+int nmh_get_credentials (char *, char *, int, nmh_creds_t);
index b534d1b..8d0a462 100644 (file)
@@ -1,4 +1,4 @@
-.TH INC %manext1% "February 16, 2013" "%nmhversion%"
+.TH INC %manext1% "April 14, 2013" "%nmhversion%"
 .\"
 .\" %nmhwarning%
 .\"
@@ -212,40 +212,11 @@ the environment variable.  The
 switch specifies the port name or number used to connect to the POP
 server.  If unspecified the default is \*(lqpop3\*(rq.
 .PP
-The default is for
-.B inc
-to assume that your account name on
-the POP server is the same as your current username.  To specify
-a different username, use the
+To specify a username for authentication with the POP server, use the
 .B \-user
 .I username
-switch.
-.PP
-When using POP, you will normally need to type the password for
-your account on the POP server, in order to retrieve your messages.
-It is possible to automate this process by creating a
-.RI \*(lq .netrc \*(rq
-file containing your login account information for this POP server.
-For each POP server, this file should have a line of the following
-form.  Replace the words
-.IR mypopserver ,
-.IR mylogin ,
-and
-.I mypassword
-with your own account information.
-.PP
-.RS 5
-.B machine
-.I mypopserver
-.B login
-.I mylogin
-.B password
-.I mypassword
-.RE
-.PP
-This
-.RI \*(lq .netrc \*(rq
-file should be owned and readable only by you.
+switch.  The credentials profile entry in the mh_profile(5) man page
+describes the ways to supply a username and password.
 .PP
 If passed the
 .B \-proxy
@@ -283,8 +254,9 @@ has been compiled with SASL support, the
 switch will enable
 the use of SASL authentication.  Depending on the SASL mechanism used, this
 may require an additional password prompt from the user (but the
-.RI \*(lq .netrc \*(rq
-file can be used to store this password).  The
+.I netrc
+file can be used to store this password, as described in the
+mh-profile(5) man page).  The
 .B \-saslmech
 switch can be used to select a particular SASL mechanism.
 .PP
@@ -332,6 +304,7 @@ To name sequences denoting unseen messages.
 .IR mhmail (1),
 .IR scan (1),
 .IR mh\-mail (5),
+.IR mh\-profile (5),
 .IR post (8),
 .IR rcvstore (1)
 .SH DEFAULTS
index a85522b..81d436a 100644 (file)
@@ -1,4 +1,4 @@
-.TH MH-PROFILE %manext5% "March 18, 2013" "%nmhversion%"
+.TH MH-PROFILE %manext5% "April 14, 2013" "%nmhversion%"
 .\"
 .\" %nmhwarning%
 .\"
@@ -374,6 +374,92 @@ puts in the \*(lqFrom:\*(rq header; do not include an address in the
 signature text.  The \*(lqLocal\-Mailbox\*(rq profile component
 supersedes all of this.  (profile, no default)
 .RE
+.PP
+.BR credentials :
+\&legacy
+.RS 5
+Indicates how the username and password credentials will be retrieved
+for access to external servers, such as those that provide SMTP or POP
+service.  The supported entry values are \*(lqlegacy\*(rq and
+.RI \*(lqfile: netrc \*(rq.
+With \*(lqlegacy\*(rq, or if there is no credentials entry, the
+username is the first of:
+.PP
+.RS 5
+1)
+.B \-user
+switch to
+.BR send ,
+.BR post ,
+.BR whom ,
+.BR inc ,
+or
+.B msgchk
+program
+.br
+2) the login name on the local machine
+.RE
+.PP
+The password for SMTP services is the first of:
+.PP
+.RS 5
+1) password value from matching entry in file named \*(lq.netrc\*(rq
+in the user's home directory
+.br
+2) password obtained by interactively prompting the user
+.RE
+.PP
+The password for POP service when the
+.B \-sasl
+switch is used with one of these programs is the login name on the
+local machine.
+.PP
+With a
+.RI \*(lqfile: netrc \*(rq
+.B credentials
+entry, the username is the first of:
+.PP
+.RS 5
+1)
+.B \-user
+switch to program
+.br
+2) login name from matching entry in
+.I netrc
+file
+.br
+3) value provided by user in response to interactive query
+.RE
+.PP
+Similarly, the password is provided either in the
+.I netrc
+file or interactively.
+.I netrc
+can be any valid filename, either absolute or relative to Path or
+$HOME.  The
+.I netrc
+file contains authentication information, for each server,
+using a line of the following form.  Replace the words
+.IR myserver ,
+.IR mylogin ,
+and
+.I mypassword
+with your own account information:
+.PP
+.RS 5
+.B machine
+.I myserver
+.B login
+.I mylogin
+.B password
+.I mypassword
+.RE
+.PP
+This
+.I netrc
+file must be owned and readable only by you.
+(profile, default: legacy)
+.RE
 .SS "Process Profile Entries"
 The following profile elements are used whenever an
 .B nmh
index cadf46c..80ea71b 100644 (file)
@@ -1,4 +1,4 @@
-.TH MSGCHK %manext1% "January 27, 2012" "%nmhversion%"
+.TH MSGCHK %manext1% "April 14, 2013" "%nmhversion%"
 .\"
 .\" %nmhwarning%
 .\"
@@ -87,38 +87,11 @@ switch is given,
 will query this POP service host as to the status of
 mail waiting.
 .PP
-The default is for
-.B msgchk
-to assume that your account name
-on the POP server is the same as your current username.  To specify
-a different username, use the `\-user\ username' switch.
-.PP
-When using POP, you will normally need to type the password for
-your account on the POP server, in order to retrieve your messages.
-It is possible to automate this process by creating a
-.RI \*(lq \&.netrc \*(rq
-file containing your login account information for this POP server.
-For each POP server, this file should have a line of the following
-form.  Replace the words
-.IR mypopserver ,
-.IR mylogin ,
-and
-.I mypassword
-with
-your own account information.
-.PP
-.RS 5
-machine
-.I mypopserver
-login
-.I mylogin
-password
-.I mypassword
-.RE
-.PP
-This
-.RI \*(lq \&.netrc \*(rq
-file should be owned and readable only by you.
+To specify a username for authentication with the POP server, use the
+.B \-user
+.I username
+switch.  The credentials profile entry in the mh_profile(5) man page
+describes the ways to supply a username and password.
 .PP
 For debugging purposes, there is also a switch
 .BR \-snoop ,
@@ -133,8 +106,9 @@ has been compiled with SASL support, the
 switch will enable
 the use of SASL authentication.  Depending on the SASL mechanism used, this
 may require an additional password prompt from the user (but the
-.RI \*(lq \&.netrc \*(rq
-file can be used to store this password).  The
+.I netrc
+file can be used to store this password, as described in the
+mh-profile(5) man page).  The
 .B \-saslmech
 switch can be used to select a particular SASL mechanism.
 .PP
@@ -162,7 +136,8 @@ switch.
 None
 .fi
 .SH "SEE ALSO"
-.IR inc (1)
+.IR inc (1),
+.IR mh\-mail (5)
 .SH DEFAULTS
 .nf
 .RB ` user "' defaults to the current user"
index 8b2c943..5e81173 100644 (file)
@@ -1,4 +1,4 @@
-.TH POST %manext8% "April 9, 2013" "%nmhversion%"
+.TH POST %manext8% "April 14, 2013" "%nmhversion%"
 .\"
 .\" %nmhwarning%
 .\"
@@ -204,14 +204,17 @@ switches will enable and disable
 the use of SASL authentication with the SMTP MTA.  Depending on the
 SASL mechanism used, this may require an additional password prompt from the
 user (but the
-.RI \*(lq \&.netrc \*(rq
-file can be used to store this password).
+.I netrc
+file can be used to store this password, as described in the
+mh-profile(5) man page).  The
 .B \-saslmech
 switch can be used to select a particular SASL mechanism,
 and the
 .B \-user
-switch can be used to select a authorization userid
-to provide to SASL other than the default.
+switch can be used to select a authorization userid to provide to SASL
+other than the default.  The credentials profile entry in the
+mh_profile(5) man page describes the ways to supply a username and
+password.
 .PP
 If SASL authentication is successful, 
 .BR nmh
@@ -266,6 +269,7 @@ consult the user's
 .IR send (1),
 .IR mh\-mail (5),
 .IR mh\-alias (5),
+.IR mh\-profile (5),
 .IR mh\-tailor (5)
 .PP
 .I "Standard for the Format of ARPA Internet Text Messages"
index fe528cb..ece0e5c 100644 (file)
@@ -1,7 +1,7 @@
 .\"
 .\" %nmhwarning%
 .\"
-.TH SEND %manext1% "April 9, 2013" "%nmhversion%"
+.TH SEND %manext1% "April 14, 2013" "%nmhversion%"
 .SH NAME
 send \- send a message
 .SH SYNOPSIS
@@ -395,14 +395,17 @@ switches will enable and disable
 the use of SASL authentication with the SMTP MTA.  Depending on the
 SASL mechanism used, this may require an additional password prompt from the
 user (but the
-.RI \*(lq \&.netrc \*(rq
-file can be used to store this password).
+.I netrc
+file can be used to store this password, as described in the
+mh-profile(5) man page).  The
 .B \-saslmech
 switch can be used to select a particular SASL mechanism,
 and the
 .B \-user
-switch can be used to select a authorization userid
-to provide to SASL other than the default.
+switch can be used to select a authorization userid to provide to SASL
+other than the default.  The credentials profile entry in the
+mh_profile(5) man page describes the ways to supply a username and
+password.
 .PP
 If SASL authentication is successful,
 .BR nmh
@@ -474,6 +477,7 @@ for more information.
 .IR repl (1),
 .IR whatnow (1),
 .IR mh\-alias (5),
+.IR mh\-profile (5),
 .IR mh\-tailor (5),
 .IR post (8)
 .SH DEFAULTS
index f11fc02..cccccd4 100644 (file)
@@ -1,4 +1,4 @@
-.TH WHOM %manext1% "April 9, 2013" "%nmhversion%"
+.TH WHOM %manext1% "April 14, 2013" "%nmhversion%"
 .\"
 .\" %nmhwarning%
 .\"
@@ -84,14 +84,17 @@ switch will enable
 the use of SASL authentication with the SMTP MTA.  Depending on the
 SASL mechanism used, this may require an additional password prompt from the
 user (but the
-.RI \*(lq \&.netrc \*(rq
-file can be used to store this password).
+.I netrc
+file can be used to store this password, as described in the
+mh-profile(5) man page).  The
 .B \-saslmech
 switch can be used to select a particular SASL mechanism,
 and the
 .B \-user
-switch can be used to select a authorization userid
-to provide to SASL other than the default.
+switch can be used to select a authorization userid to provide to SASL
+other than the default.  The credentials profile entry in the
+mh_profile(5) man page describes the ways to supply a username and
+password.
 .PP
 If SASL authentication is successful, 
 .BR nmh
@@ -145,6 +148,7 @@ for more information.
 .fi
 .SH "SEE ALSO"
 .IR mh\-alias (5),
+.IR mh\-profile (5),
 .IR post (8)
 .SH DEFAULTS
 .nf
index c973c91..8b17042 100644 (file)
@@ -99,7 +99,7 @@ static FILE *sm_wfp = NULL;
 static sasl_conn_t *conn = NULL;       /* SASL connection state */
 static int sasl_complete = 0;          /* Has authentication succeded? */
 static sasl_ssf_t sasl_ssf;            /* Our security strength factor */
-static char *sasl_pw_context[2];       /* Context to pass into sm_get_pass */
+static char *sasl_pw_context[3];       /* Context to pass into sm_get_pass */
 static int maxoutbuf;                  /* Maximum crypto output buffer */
 static char *sasl_outbuffer;           /* SASL output buffer for encryption */
 static int sasl_outbuflen;             /* Current length of data in outbuf */
@@ -109,10 +109,10 @@ static int sm_get_pass(sasl_conn_t *, void *, int, sasl_secret_t **);
 static sasl_callback_t callbacks[] = {
     { SASL_CB_USER, (sasl_callback_ft) sm_get_user, NULL },
 #define SM_SASL_N_CB_USER 0
-    { SASL_CB_PASS, (sasl_callback_ft) sm_get_pass, NULL },
-#define SM_SASL_N_CB_PASS 1
     { SASL_CB_AUTHNAME, (sasl_callback_ft) sm_get_user, NULL },
-#define SM_SASL_N_CB_AUTHNAME 2
+#define SM_SASL_N_CB_AUTHNAME 1
+    { SASL_CB_PASS, (sasl_callback_ft) sm_get_pass, NULL },
+#define SM_SASL_N_CB_PASS 2
     { SASL_CB_LIST_END, NULL, NULL },
 };
 
@@ -820,17 +820,12 @@ sm_auth_sasl(char *user, int saslssf, char *mechlist, char *inhost)
     sasl_security_properties_t secprops;
     sasl_ssf_t *ssf;
     int *outbufmax;
+    char *pass = NULL;
 
     /*
      * Initialize the callback contexts
      */
 
-    if (user == NULL)
-       user = getusername();
-
-    callbacks[SM_SASL_N_CB_USER].context = user;
-    callbacks[SM_SASL_N_CB_AUTHNAME].context = user;
-
     /*
      * This is a _bit_ of a hack ... but if the hostname wasn't supplied
      * to us on the command line, then call getpeername and do a
@@ -861,8 +856,12 @@ sm_auth_sasl(char *user, int saslssf, char *mechlist, char *inhost)
        strncpy(host, inhost, sizeof(host) - 1);
     }
 
+    callbacks[SM_SASL_N_CB_USER].context = user;
+    callbacks[SM_SASL_N_CB_AUTHNAME].context = user;
+
     sasl_pw_context[0] = host;
     sasl_pw_context[1] = user;
+    sasl_pw_context[2] = pass;
 
     callbacks[SM_SASL_N_CB_PASS].context = sasl_pw_context;
 
@@ -1072,7 +1071,6 @@ sm_get_pass(sasl_conn_t *conn, void *context, int id,
            sasl_secret_t **psecret)
 {
     char **pw_context = (char **) context;
-    char *pass = NULL;
     int len;
 
     NMH_UNUSED (conn);
@@ -1080,20 +1078,14 @@ sm_get_pass(sasl_conn_t *conn, void *context, int id,
     if (! psecret || id != SASL_CB_PASS)
        return SASL_BADPARAM;
 
-    ruserpass(pw_context[0], &(pw_context[1]), &pass);
-
-    len = strlen(pass);
-
-    *psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len);
+    len = strlen (pw_context[2]);
 
-    if (! *psecret) {
-       free(pass);
+    if (! (*psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len))) {
        return SASL_NOMEM;
     }
 
     (*psecret)->len = len;
-    strcpy((char *) (*psecret)->data, pass);
-/*    free(pass); */
+    strcpy((char *) (*psecret)->data, pw_context[2]);
 
     return SASL_OK;
 }
diff --git a/sbr/credentials.c b/sbr/credentials.c
new file mode 100644 (file)
index 0000000..9d4e41c
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * This code is Copyright (c) 2013, by the authors of nmh.  See the
+ * COPYRIGHT file in the root directory of the nmh distribution for
+ * complete copyright information.
+ */
+
+#include <h/mh.h>
+#include <h/utils.h>
+#include <h/mts.h>
+
+void
+init_credentials_file () {
+    if (credentials_file == NULL) {
+        char *cred_style = context_find ("credentials");
+
+        if (cred_style == NULL  ||  ! strcmp (cred_style, "legacy")) {
+            char *hdir = getenv ("HOME");
+
+            credentials_file = concat (hdir ? hdir : ".", "/.netrc", NULL);
+        } else if (! strncasecmp (cred_style, "file:", 5)) {
+            struct stat st;
+            char *filename = cred_style + 5;
+
+            while (*filename  &&  isspace ((int) *filename)) ++filename;
+
+            if (*filename == '/') {
+                credentials_file = filename;
+            } else {
+                credentials_file = m_maildir (filename);
+                if (stat (credentials_file, &st) != OK) {
+                    credentials_file =
+                        concat (mypath ? mypath : ".", "/", filename, NULL);
+                    if (stat (credentials_file, &st) != OK) {
+                        admonish (NULL, "unable to find credentials file %s",
+                                  filename);
+                    }
+                }
+            }
+        }
+    }
+}
+
+int
+nmh_get_credentials (char *host, char *user, int sasl, nmh_creds_t creds) {
+    char *cred_style = context_find ("credentials");
+
+    init_credentials_file ();
+    creds->host = host;
+
+    if (cred_style == NULL  ||  ! strcmp (cred_style, "legacy")) {
+        /* This is what inc.c and msgchk.c used to contain. */
+        if (user == NULL) {
+            creds->user = getusername ();
+        }
+        if (sasl) {
+            creds->password = getusername ();
+        } else {
+            ruserpass (host, &creds->user, &creds->password);
+        }
+    } else if (! strncasecmp (cred_style, "file:", 5)) {
+        /*
+         * Determine user using the first of:
+         * 1) -user switch
+         * 2) matching host entry with login in a credentials file
+         *    such as ~/.netrc
+         * 3) interactively request from user (as long as the
+         *    credentials file didn't have a "default" token)
+         */
+        creds->user = user;
+        ruserpass (host, &creds->user, &creds->password);
+    }
+
+    return OK;
+}
index d422f67..f5ef74a 100644 (file)
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Portions of this code are Copyright (c) 2013, by the authors of
+ * nmh.  See the COPYRIGHT file in the root directory of the nmh
+ * distribution for complete copyright information.
  */
 
 #include <h/mh.h>
 
 static FILE *cfile;
 
-#ifndef MAXHOSTNAMELEN
-# define MAXHOSTNAMELEN 64
-#endif
-
 #define        DEFAULT 1
 #define        LOGIN   2
 #define        PASSWD  3
@@ -62,78 +62,78 @@ static int token(void);
 void
 ruserpass(char *host, char **aname, char **apass)
 {
-    char *hdir, buf[BUFSIZ];
     int t, usedefault = 0;
     struct stat stb;
 
-    hdir = getenv("HOME");
-    if (hdir == NULL)
-       hdir = ".";
-    snprintf(buf, sizeof(buf), "%s/.netrc", hdir);
-    cfile = fopen(buf, "r");
+    init_credentials_file ();
+
+    cfile = fopen (credentials_file, "r");
     if (cfile == NULL) {
        if (errno != ENOENT)
-           perror(buf);
-       goto done;
-    }
-
-    while ((t = token())) {
-       switch(t) {
-       case DEFAULT:
-           usedefault = 1;
-           /* FALL THROUGH */
-
-       case MACH:
-           if (!usedefault) {
-               if (token() != ID)
+           perror (credentials_file);
+    } else {
+       while ((t = token())) {
+           switch(t) {
+           case DEFAULT:
+               usedefault = 1;
+               /* FALL THROUGH */
+
+           case MACH:
+               if (!usedefault) {
+                   if (token() != ID)
+                       continue;
+                   /*
+                    * Allow match either for user's host name.
+                    */
+                   if (strcasecmp(host, tokval) == 0)
+                       goto match;
                    continue;
-               /*
-                * Allow match either for user's host name.
-                */
-               if (strcasecmp(host, tokval) == 0)
-                   goto match;
-               continue;
-           }
-match:
-           while ((t = token()) && t != MACH && t != DEFAULT) {
-               switch(t) {
-               case LOGIN:
-                   if (token() && *aname == 0) {
-                       *aname = mh_xmalloc((size_t) strlen(tokval) + 1);
-                       strcpy(*aname, tokval);
-                   }
-                   break;
-               case PASSWD:
-                   if (fstat(fileno(cfile), &stb) >= 0 &&
-                       (stb.st_mode & 077) != 0) {
-                       /* We make this a fatal error to force the user to correct it */
-                       advise(NULL, "Error - ~/.netrc file must not be world or group readable.");
-                       adios(NULL, "Remove password or correct file permissions.");
-                   }
-                   if (token() && *apass == 0) {
-                       *apass = mh_xmalloc((size_t) strlen(tokval) + 1);
-                       strcpy(*apass, tokval);
+               }
+           match:
+               while ((t = token()) && t != MACH && t != DEFAULT) {
+                   switch(t) {
+                   case LOGIN:
+                       if (token() && *aname == 0) {
+                           *aname = mh_xmalloc((size_t) strlen(tokval) + 1);
+                           strcpy(*aname, tokval);
+                       }
+                       break;
+
+                   case PASSWD:
+                       if (fstat(fileno(cfile), &stb) >= 0 &&
+                           (stb.st_mode & 077) != 0) {
+                           /* We make this a fatal error to force the
+                              user to correct it. */
+                           advise(NULL, "Error - file %s must not be world or "
+                                  "group readable.", credentials_file);
+                           adios(NULL, "Remove password or correct file "
+                                 "permissions.");
+                       }
+                       if (token() && *apass == 0) {
+                           *apass = mh_xmalloc((size_t) strlen(tokval) + 1);
+                           strcpy(*apass, tokval);
+                       }
+                       break;
+
+                   case ACCOUNT:
+                       break;
+
+                   case MACDEF:
+                       fclose(cfile);
+                       return;
+
+                   default:
+                       fprintf(stderr,
+                               "Unknown keyword %s in credentials file %s\n",
+                               tokval, credentials_file);
+                       break;
                    }
-                   break;
-               case ACCOUNT:
-                   break;
-
-               case MACDEF:
-                   goto done_close;
-                   break;
-               default:
-                   fprintf(stderr, "Unknown .netrc keyword %s\n", tokval);
-                   break;
                }
+               return;
            }
-           goto done;
        }
     }
 
-done_close:
-    fclose(cfile);
-
-done:
     if (!*aname) {
        char tmp[80];
        char *myname;
index 7724ae3..2bb0bb4 100755 (executable)
@@ -73,6 +73,34 @@ run_test "inc -file $MH_TEST_DIR/inc.mbox -truncate" \
 
   11+ 12/17 No Such User       Hello<<Hey man, how's it going? . Hope you're do"
 
+check $testmessage `mhpath +inbox 11` 'keep first'
+rm -f "$MH_TEST_DIR/inc.mbox" "$MH_TEST_DIR/.inc.map" "$netrc"
+
+# check credentials: file
+# Redirect stdin so that inc doesn't wait on the user if it can't
+# read the netrc file, even though that shouldn't happen.
+TESTUSER=differenuser
+TESTPASS=differentpass
+
+netrc="${HOME}/.mhnetrc"
+echo "default login ${TESTUSER} password ${TESTPASS}" > "$netrc"
+chmod 600 "$netrc"
+echo "credentials: file:${netrc}" >>$MH
+
+pid=`"${MH_OBJ_DIR}/test/fakepop" "$testmessage" "$testport" \
+                       "$TESTUSER" "$TESTPASS"`
+
+touch "$MH_TEST_DIR/inc.mbox"
+run_test "inc -user ${TESTUSER} -host 127.0.0.1 -port $testport -width 65 \
+          -pack $MH_TEST_DIR/inc.mbox" \
+       "Incorporating new mail into (null)...
+
+   1  12/17 No Such User       Hello<<Hey man, how's it going? ." </dev/null
+run_test "inc -file $MH_TEST_DIR/inc.mbox -truncate -width 65" \
+       "Incorporating new mail into inbox...
+
+  11+ 12/17 No Such User       Hello<<Hey man, how's it going? ." </dev/null
+
 check $testmessage `mhpath +inbox 11`
 rm -f "$MH_TEST_DIR/inc.mbox" "$MH_TEST_DIR/.inc.map" "$netrc"
 
index f169fc7..e1c58cb 100644 (file)
--- a/uip/inc.c
+++ b/uip/inc.c
@@ -190,7 +190,6 @@ main (int argc, char **argv)
     char *maildir_copy = NULL; /* copy of mail directory because the static gets overwritten */
 
     int nmsgs, nbytes;
-    char *pass = NULL;
     char *MAILHOST_env_variable;
 
     done=inc_done;
@@ -391,18 +390,14 @@ main (int argc, char **argv)
      * a POP server?
      */
     if (inc_type == INC_POP) {
-       if (user == NULL)
-           user = getusername ();
-       if (sasl)
-           pass = getusername ();
-       else
-           ruserpass (host, &user, &pass);
+       struct nmh_creds creds = { 0, 0, 0 };
 
        /*
         * initialize POP connection
         */
-       if (pop_init (host, port, user, pass, proxy, snoop, sasl,
-                     saslmech) == NOTOK)
+       nmh_get_credentials (host, user, sasl, &creds);
+       if (pop_init (host, port, creds.user, creds.password, proxy, snoop,
+                     sasl, saslmech) == NOTOK)
            adios (NULL, "%s", response);
 
        /* Check if there are any messages */
index 6a0a12e..af280f5 100644 (file)
@@ -80,7 +80,7 @@ main (int argc, char **argv)
     int datesw = 1, notifysw = NT_ALL;
     int status = 0, sasl = 0;
     int snoop = 0, vecp = 0;
-    char *cp, *host = NULL, *port = NULL, *user, *proxy = NULL; 
+    char *cp, *host = NULL, *port = NULL, *user = NULL, *proxy = NULL;
     char buf[BUFSIZ], *saslmech = NULL; 
     char **argp, **arguments, *vec[MAXVEC];
     struct passwd *pw;
@@ -94,7 +94,6 @@ main (int argc, char **argv)
     context_read();
 
     mts_init (invo_name);
-    user = getusername();
 
     arguments = getarguments (invo_name, argc, argv, 1);
     argp = arguments;
@@ -151,7 +150,7 @@ main (int argc, char **argv)
                    if (vecp >= MAXVEC-1)
                        adios (NULL, "you can only check %d users at a time", MAXVEC-1);
                    else
-                       vec[vecp++] = cp;
+                       user = vec[vecp++] = cp;
                    continue;
 
                case SNOOPSW:
@@ -206,26 +205,26 @@ main (int argc, char **argv)
                                      snoop, sasl, saslmech);
        }
     } else {
-
-    if (vecp == 0) {
-       char *home;
-
-        /* Not sure this check makes sense... */
-       if (!geteuid() || NULL == (home = getenv("HOME"))) {
-           pw = getpwnam (user);
-           if (pw == NULL)
-               adios (NULL, "unable to get information about user");
-           home = pw->pw_dir;
-       }
-       status = checkmail (user, home, datesw, notifysw, 1);
-    } else {
-       for (vecp = 0; vec[vecp]; vecp++) {
-           if ((pw = getpwnam (vec[vecp])))
-               status += checkmail (pw->pw_name, pw->pw_dir, datesw, notifysw, 0);
-           else
-               advise (NULL, "no such user as %s", vec[vecp]);
+       if (user == NULL) user = getusername ();
+       if (vecp == 0) {
+           char *home;
+
+           /* Not sure this check makes sense... */
+           if (!geteuid() || NULL == (home = getenv("HOME"))) {
+               pw = getpwnam (user);
+               if (pw == NULL)
+                   adios (NULL, "unable to get information about user");
+               home = pw->pw_dir;
+           }
+           status = checkmail (user, home, datesw, notifysw, 1);
+       } else {
+           for (vecp = 0; vec[vecp]; vecp++) {
+               if ((pw = getpwnam (vec[vecp])))
+                   status += checkmail (pw->pw_name, pw->pw_dir, datesw, notifysw, 0);
+               else
+                   advise (NULL, "no such user as %s", vec[vecp]);
+           }
        }
-    }
     }          /* host == NULL */
 
     done (status);
@@ -327,19 +326,14 @@ remotemail (char *host, char *port, char *user, char *proxy, int notifysw,
            int personal, int snoop, int sasl, char *saslmech)
 {
     int nmsgs, nbytes, status;
-    char *pass = NULL;
-
-    if (user == NULL)
-       user = getusername ();
-    if (sasl)
-       pass = getusername ();
-    else
-       ruserpass (host, &user, &pass);
+    struct nmh_creds creds = { 0, 0, 0 };
 
     /* open the POP connection */
-    if (pop_init (host, port, user, pass, proxy, snoop, sasl, saslmech) == NOTOK
-           || pop_stat (&nmsgs, &nbytes) == NOTOK      /* check for messages  */
-           || pop_quit () == NOTOK) {                  /* quit POP connection */
+    nmh_get_credentials (host, user, sasl, &creds);
+    if (pop_init (host, port, creds.user, creds.password, proxy, snoop, sasl,
+                 saslmech) == NOTOK
+           || pop_stat (&nmsgs, &nbytes) == NOTOK     /* check for messages  */
+           || pop_quit () == NOTOK) {                 /* quit POP connection */
        advise (NULL, "%s", response);
        return 1;
     }
index fb66a93..bdd55c5 100644 (file)
@@ -46,6 +46,7 @@ static int sasl_get_user(void *, int, const char **, unsigned *);
 static int sasl_get_pass(sasl_conn_t *, void *, int, sasl_secret_t **);
 struct pass_context {
     char *user;
+    char *password;
     char *host;
 };
 
@@ -71,7 +72,7 @@ static int command(const char *, ...);
 static int multiline(void);
 
 #ifdef CYRUS_SASL
-static int pop_auth_sasl(char *, char *, char *);
+static int pop_auth_sasl(char *, char *, char *, char *);
 static int sasl_fgetc(FILE *);
 #endif /* CYRUS_SASL */
 
@@ -91,7 +92,7 @@ static int putline (char *, FILE *);
  */
 
 int
-pop_auth_sasl(char *user, char *host, char *mech)
+pop_auth_sasl(char *user, char *password, char *host, char *mech)
 {
     int result, status, sasl_capability = 0;
     unsigned int buflen, outlen;
@@ -159,6 +160,7 @@ pop_auth_sasl(char *user, char *host, char *mech)
     callbacks[POP_SASL_CB_N_USER].context = user;
     p_context.user = user;
     p_context.host = host;
+    p_context.password = password;
     callbacks[POP_SASL_CB_N_PASS].context = &p_context;
 
     result = sasl_client_init(callbacks);
@@ -351,7 +353,7 @@ static int
 sasl_get_pass(sasl_conn_t *conn, void *context, int id, sasl_secret_t **psecret)
 {
     struct pass_context *p_context = (struct pass_context *) context;
-    char *pass = NULL;
+    char *pass = p_context->password;
     int len;
 
     NMH_UNUSED (conn);
@@ -359,8 +361,6 @@ sasl_get_pass(sasl_conn_t *conn, void *context, int id, sasl_secret_t **psecret)
     if (! psecret || id != SASL_CB_PASS)
        return SASL_BADPARAM;
 
-    ruserpass(p_context->user, &(p_context->host), &pass);
-
     len = strlen(pass);
 
     *psecret = (sasl_secret_t *) mh_xmalloc(sizeof(sasl_secret_t) + len);
@@ -510,7 +510,7 @@ pop_init (char *host, char *port, char *user, char *pass, char *proxy,
            if (*response == '+') {
 #  ifdef CYRUS_SASL
                if (sasl) {
-                   if (pop_auth_sasl(user, host, mech) != NOTOK)
+                   if (pop_auth_sasl(user, pass, host, mech) != NOTOK)
                        return OK;
                } else
 #  endif /* CYRUS_SASL */