]> 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 470a763587bd8feca8ae57e2ace6b941fc5316e6..78cce559d46bf13ed64fb3472309c2fbe558f941 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/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 \
                      sbr/escape_addresses.c \
                      sbr/error.c sbr/ext_hook.c sbr/fdcompare.c \
                      sbr/folder_addmsg.c sbr/folder_delmsgs.c \
index 4024d305cbe9c86ac82203701d5be3dc3c9543c1..151f7fc296d106f3d10349a94590fc817d55d548 100644 (file)
@@ -103,6 +103,9 @@ char *mh_defaults = nmhetcdir (/mh.profile);
 /* default name of user profile */
 char *mh_profile = ".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";
 
 /* name of current message "sequence" */
 char *current = "cur";
 
index 3b225819effd22e41791d1cbcfcf32fc78237b5b..e88165decf7cdb7a097441cb3efb976cacc742b5 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.
 - 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 f5fd66be34d4931f47fa8880cc4ccf766cde8c64..354f3fa5ddd70a2a24d7b8dbb907f0bec2c097d6 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 */
 
 
 #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
  */
 /*
  * miscellaneous macros
  */
@@ -405,6 +416,7 @@ extern char *catproc;
 extern char *components;
 extern char *context;
 extern char *current;
 extern char *components;
 extern char *context;
 extern char *current;
+extern char *credentials_file;
 extern char *defaultfolder;
 extern char *digestcomps;
 extern char *distcomps;
 extern char *defaultfolder;
 extern char *digestcomps;
 extern char *distcomps;
index 8fa31576cff2abb1a24bd0f60fac14927e65306b..94be46afbabe258406e93a5ea80586b7e92a9161 100644 (file)
@@ -148,7 +148,7 @@ char *pwd (void);
 char *r1bindex(char *, int);
 void readconfig (struct node **, FILE *, char *, int);
 int refile (char **, char *);
 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 ();
 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 *);
 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 b534d1b12cfe8b5278f480e0653fb12e6ec0dd08..8d0a46269c45ff1d1ebb2323bac41df894603efd 100644 (file)
@@ -1,4 +1,4 @@
-.TH INC %manext1% "February 16, 2013" "%nmhversion%"
+.TH INC %manext1% "April 14, 2013" "%nmhversion%"
 .\"
 .\" %nmhwarning%
 .\"
 .\"
 .\" %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
 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
 .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
 .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
 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
 .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 mhmail (1),
 .IR scan (1),
 .IR mh\-mail (5),
+.IR mh\-profile (5),
 .IR post (8),
 .IR rcvstore (1)
 .SH DEFAULTS
 .IR post (8),
 .IR rcvstore (1)
 .SH DEFAULTS
index a85522b0009ebb520e4c40ef71c252c435a997ee..81d436a1dfab9b611c15970e18b68d996a11f6ad 100644 (file)
@@ -1,4 +1,4 @@
-.TH MH-PROFILE %manext5% "March 18, 2013" "%nmhversion%"
+.TH MH-PROFILE %manext5% "April 14, 2013" "%nmhversion%"
 .\"
 .\" %nmhwarning%
 .\"
 .\"
 .\" %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
 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
 .SS "Process Profile Entries"
 The following profile elements are used whenever an
 .B nmh
index cadf46ca4f8220853d19fb990a74a0b8b376eb7c..80ea71b198a37f15c8427a3200bd3f9ea6c26085 100644 (file)
@@ -1,4 +1,4 @@
-.TH MSGCHK %manext1% "January 27, 2012" "%nmhversion%"
+.TH MSGCHK %manext1% "April 14, 2013" "%nmhversion%"
 .\"
 .\" %nmhwarning%
 .\"
 .\"
 .\" %nmhwarning%
 .\"
@@ -87,38 +87,11 @@ switch is given,
 will query this POP service host as to the status of
 mail waiting.
 .PP
 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 ,
 .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
 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
 .B \-saslmech
 switch can be used to select a particular SASL mechanism.
 .PP
@@ -162,7 +136,8 @@ switch.
 None
 .fi
 .SH "SEE ALSO"
 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"
 .SH DEFAULTS
 .nf
 .RB ` user "' defaults to the current user"
index 8b2c943522b69bec5adbc83ce8693fe266360157..5e811739240a7d0d579628087188d05d098e4329 100644 (file)
@@ -1,4 +1,4 @@
-.TH POST %manext8% "April 9, 2013" "%nmhversion%"
+.TH POST %manext8% "April 14, 2013" "%nmhversion%"
 .\"
 .\" %nmhwarning%
 .\"
 .\"
 .\" %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
 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
 .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
 .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 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"
 .IR mh\-tailor (5)
 .PP
 .I "Standard for the Format of ARPA Internet Text Messages"
index fe528cb7d1b494b7a82226adf07ab9560133f3d8..ece0e5c8910144efbad28cfde0582990714aa617 100644 (file)
@@ -1,7 +1,7 @@
 .\"
 .\" %nmhwarning%
 .\"
 .\"
 .\" %nmhwarning%
 .\"
-.TH SEND %manext1% "April 9, 2013" "%nmhversion%"
+.TH SEND %manext1% "April 14, 2013" "%nmhversion%"
 .SH NAME
 send \- send a message
 .SH SYNOPSIS
 .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
 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
 .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
 .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 repl (1),
 .IR whatnow (1),
 .IR mh\-alias (5),
+.IR mh\-profile (5),
 .IR mh\-tailor (5),
 .IR post (8)
 .SH DEFAULTS
 .IR mh\-tailor (5),
 .IR post (8)
 .SH DEFAULTS
index f11fc02490b38cb13a578c256768a8aa5168000a..cccccd4cb8115378e23a15b5a30e8a4af83a8f0b 100644 (file)
@@ -1,4 +1,4 @@
-.TH WHOM %manext1% "April 9, 2013" "%nmhversion%"
+.TH WHOM %manext1% "April 14, 2013" "%nmhversion%"
 .\"
 .\" %nmhwarning%
 .\"
 .\"
 .\" %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
 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
 .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
 .PP
 If SASL authentication is successful, 
 .BR nmh
@@ -145,6 +148,7 @@ for more information.
 .fi
 .SH "SEE ALSO"
 .IR mh\-alias (5),
 .fi
 .SH "SEE ALSO"
 .IR mh\-alias (5),
+.IR mh\-profile (5),
 .IR post (8)
 .SH DEFAULTS
 .nf
 .IR post (8)
 .SH DEFAULTS
 .nf
index c973c9191500d417c425aa9f4f0660f273de1445..8b17042c78c13ae59ec07721526256b1b65be137 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 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 */
 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
 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 },
     { 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 },
 };
 
     { 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;
     sasl_security_properties_t secprops;
     sasl_ssf_t *ssf;
     int *outbufmax;
+    char *pass = NULL;
 
     /*
      * Initialize the callback contexts
      */
 
 
     /*
      * 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
     /*
      * 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);
     }
 
        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[0] = host;
     sasl_pw_context[1] = user;
+    sasl_pw_context[2] = pass;
 
     callbacks[SM_SASL_N_CB_PASS].context = sasl_pw_context;
 
 
     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;
            sasl_secret_t **psecret)
 {
     char **pw_context = (char **) context;
-    char *pass = NULL;
     int len;
 
     NMH_UNUSED (conn);
     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;
 
     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;
        return SASL_NOMEM;
     }
 
     (*psecret)->len = len;
-    strcpy((char *) (*psecret)->data, pass);
-/*    free(pass); */
+    strcpy((char *) (*psecret)->data, pw_context[2]);
 
     return SASL_OK;
 }
 
     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 d422f67d31d2a042d0339a2ace1ebeafd22deab6..f5ef74a418187eba33e72b681cb332f2113ececd 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.
  * 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>
  */
 
 #include <h/mh.h>
 
 static FILE *cfile;
 
 
 static FILE *cfile;
 
-#ifndef MAXHOSTNAMELEN
-# define MAXHOSTNAMELEN 64
-#endif
-
 #define        DEFAULT 1
 #define        LOGIN   2
 #define        PASSWD  3
 #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)
 {
 void
 ruserpass(char *host, char **aname, char **apass)
 {
-    char *hdir, buf[BUFSIZ];
     int t, usedefault = 0;
     struct stat stb;
 
     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)
     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;
                    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;
     if (!*aname) {
        char tmp[80];
        char *myname;
index 7724ae3c5cab06f030e491decde028564e0c73ca..2bb0bb4d40a3493c8d7e8ae054b7199320472b55 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"
 
 
   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"
 
 check $testmessage `mhpath +inbox 11`
 rm -f "$MH_TEST_DIR/inc.mbox" "$MH_TEST_DIR/.inc.map" "$netrc"
 
index f169fc7d81db995cf9f09c66dcfee8f90e5aa468..e1c58cb1e68217ea0774236d658f3697352df638 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 *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;
     char *MAILHOST_env_variable;
 
     done=inc_done;
@@ -391,18 +390,14 @@ main (int argc, char **argv)
      * a POP server?
      */
     if (inc_type == INC_POP) {
      * 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
         */
 
        /*
         * 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 */
            adios (NULL, "%s", response);
 
        /* Check if there are any messages */
index 6a0a12e7940f7b094ff790bcc7e42ff0306093b8..af280f595bc92a49ecb39812c95409f8b291d3f0 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;
     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;
     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);
     context_read();
 
     mts_init (invo_name);
-    user = getusername();
 
     arguments = getarguments (invo_name, argc, argv, 1);
     argp = arguments;
 
     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
                    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:
                    continue;
 
                case SNOOPSW:
@@ -206,26 +205,26 @@ main (int argc, char **argv)
                                      snoop, sasl, saslmech);
        }
     } else {
                                      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);
     }          /* 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;
            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 */
 
     /* 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;
     }
        advise (NULL, "%s", response);
        return 1;
     }
index fb66a93b6336b0c8921b43e456fca5ac48d75686..bdd55c58c90f4f35bb10aca683604de57a64ec53 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;
 static int sasl_get_pass(sasl_conn_t *, void *, int, sasl_secret_t **);
 struct pass_context {
     char *user;
+    char *password;
     char *host;
 };
 
     char *host;
 };
 
@@ -71,7 +72,7 @@ static int command(const char *, ...);
 static int multiline(void);
 
 #ifdef CYRUS_SASL
 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 */
 
 static int sasl_fgetc(FILE *);
 #endif /* CYRUS_SASL */
 
@@ -91,7 +92,7 @@ static int putline (char *, FILE *);
  */
 
 int
  */
 
 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;
 {
     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;
     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);
     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;
 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);
     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;
 
     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);
     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 (*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 */
                        return OK;
                } else
 #  endif /* CYRUS_SASL */