patch: support for reading .netrc

Stephen Gildea <[email protected]> Thu, 23 Sep 2021 08:13:40 -0700
Newsgroups gmane.mail.getmail.user
Message-ID <52433.1632410020@pental>
I've just discovered getmail, and I'm excited because it looks like
just what I need.  I had been trying to using fetchmail, but getmail
is more flexible and has more features.  In particular, getmail can
use PEEK with IMAP, which fetchmail will not.

I quickly discovered that there is one thing getmail cannot do that
fetchmail and my other mail-reading programs do: getmail doesn't know
about my ~/.netrc file and instead expects me to copy my password into
a getmail-specific configuration file.

So I wrote the attached small patch.


This patch adds two new configuration options, "use_netrc" and "netrc_file".
When use_netrc = true, getmail will read a password (and possibly username)
from a user's .netrc file.  If that new option is omitted, there is no
change in behavior.  Setting netrc_file to a string naming a file path lets
the user select a netrc file other than ~/.netrc, the default.

The netrc file support uses Python's "netrc" module, available with its
current API since Python 2.3.


There are several reasons why I want this feature:

* More secure:

- Separate secret from shareable info.  This makes it less likely users
  will accidentally expose their passwords.  (You win, too: it is
  easier for people to attach their getmailrc file to a bug report if
  they don't have to remove their password first.)

- Easier integration with existing security tools.  These tools know to
  check that ~/.netrc is unreadable, but they do not necessarily know to
  check the permissions of ~/.getmail or ~/.getmail/getmailrc.

* Easier to deploy:

- My system's users already have .netrc files, and the remaining info
  is the same for all users, so everyone can start off with the same
  getmailrc file.  No customization of username or password is required.

- Easier user education.  I can share my getmailrc file, since it has no
  secrets.

- Easier password maintenance.  Users can continue to have their server
  passwords saved in only one place.  If getmail has a separate, unique
  place for its password, I fear that it will mysteriously fail when users
  update their password and forget they have a second file that needs
  updating.

* Enables new applications:

- We can write portable wrapper scripts for getmail that create new
  applications: display mailbox statistics, display a scan-line for each
  message, etc.  These scripts can create getmailrc configs on the fly,
  as long as they don't have to know any user-specific information.


The list of advantages is longer than the code.  I hope you like my patch.

 < Stephen

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
getmail-netrc.patch (text/x-diff, 5.4 KB)
--- getmail-5.15/getmail	2020-12-10 17:46:45.000000000 -0800
+++ getmail-5.15-netrc/getmail	2021-09-21 09:06:57.118764193 -0700
@@ -9,6 +9,7 @@
 import os.path
 import time
 import ConfigParser
+import netrc
 import poplib
 import imaplib
 import pprint
@@ -36,6 +37,7 @@
     'message_log_verbose',
     'message_log_syslog',
     'fingerprint',
+    'use_netrc',
 )
 options_int = (
     'delete_after',
@@ -47,6 +49,7 @@
 )
 options_str = (
     'message_log',
+    'netrc_file',
 )
 
 # Unix only
@@ -88,6 +91,8 @@
     'message_log_syslog' : False,
     'logfile' : None,
     'fingerprint' : False,
+    'use_netrc' : False,
+    'netrc_file' : None,
 }
 
 
@@ -620,6 +625,8 @@
                 'message_log_verbose' : defaults['message_log_verbose'],
                 'message_log_syslog' : defaults['message_log_syslog'],
                 'fingerprint' : defaults['fingerprint'],
+                'use_netrc' : defaults['use_netrc'],
+                'netrc_file' : defaults['netrc_file'],
             }
             # Python's ConfigParser .getboolean() couldn't handle booleans in
             # the defaults. Submitted a patch; they fixed it a different way.
@@ -694,6 +701,13 @@
                             % (config['message_log'], o)
                         )
 
+                # see if a netrc file is configured
+                netrc_object = None
+                if config['use_netrc']:
+                    netrc_object = netrc.netrc(
+                        config['netrc_file']
+                        and expand_user_vars(config['netrc_file']))
+
                 # Clear out the ConfigParser defaults before processing further
                 # sections
                 configparser._defaults = {}
@@ -721,6 +735,14 @@
                     else:
                         log.debug('    parameter %s="%s"\n' % (name, value))
                     retriever_args[name] = value
+                if netrc_object:
+                    # add username and password from netrc, as read above
+                    netrc_auth = netrc_object.authenticators(
+                        retriever_args['server'])
+                    if netrc_auth and netrc_auth[0]:
+                        retriever_args['username'] = netrc_auth[0]
+                    if netrc_auth and netrc_auth[2]:
+                        retriever_args['password'] = netrc_auth[2]
                 log.debug('    instantiating retriever %s with args %s\n'
                           % (retriever_type, format_params(retriever_args)))
                 try:
--- getmail-5.15/docs/configuration.html	2020-12-10 17:46:56.000000000 -0800
+++ getmail-5.15-netrc/docs/configuration.html	2021-09-21 08:54:56.521713927 -0700
@@ -531,7 +531,9 @@
     <li>
         username
         (<a href="#parameter-string">string</a>)
-        &mdash; username to provide when logging in to the mail server
+        &mdash; username to provide when logging in to the mail server.
+        If you enable <a href="#use_netrc">use_netrc</a>, the netrc file
+        can supply a username for each retriever.
     </li>
 </ul>
 <p>
@@ -555,6 +557,7 @@
             <li>by running an arbitrary command specified with the password_command parameter (see below)</li>
             <li>on Mac OS X only, from the OS X keychain</li>
             <li>on systems with Gnome keyring support, from the default Gnome keyring</li>
+            <li>if <a href="#use_netrc">use_netrc</a> option is True, from a .netrc file
             <li>if not found via any of the above methods, getmail will prompt for the password when run</li>
         </ol>
         To store your POP/IMAP account password into the Gnome keyring, ensure 
@@ -2366,6 +2369,28 @@
         getmail only retrieves messages it has not seen before.  Default: True.
     </li>
     <li>
+        <a name="use_netrc">use_netrc</a>
+        (<a href="#parameter-boolean">boolean</a>)
+        &mdash; if set, getmail will read a <span class="file">.netrc</span>
+        or <span class="file">.authinfo</span> file to set the
+        <span class="file">username</span> and/or
+        <span class="file">password</span> parameter for matching
+        retrievers.
+        A retriever matches if its <span class="file">server</span> parameter
+        matches a <span class="file">machine</span> entry in the netrc file.
+        The location of the .netrc file to read can be set with
+        the <a href="#netrc_file">netrc_file</a> option.  Default: False.
+    </li>
+    <li>
+        <a name="netrc_file">netrc_file</a>
+        (<a href="#parameter-boolean">string</a>)
+        &mdash; sets the file that <a href="#use_netrc">use_netrc</a> reads.
+        Has no effect unless <a href="#use_netrc">use_netrc</a> is True.
+        Default: unset, which means <a href="#use_netrc">use_netrc</a> will
+        read the default netrc file for your system,
+        typically <span class="file">~/.netrc</span>.
+    </li>
+    <li>
         delete
         (<a href="#parameter-boolean">boolean</a>)
         &mdash; if set, getmail will delete messages after retrieving and
--- getmail-5.15/docs/CHANGELOG	2020-12-10 17:46:45.000000000 -0800
+++ getmail-5.15-netrc/docs/CHANGELOG	2021-09-20 22:47:11.725093044 -0700
@@ -1,3 +1,8 @@
+Version next
+20 September 2021 or later
+    -add new use_netrc and netrc_file configuration options to support
+    reading secrets from a .netrc file.
+
 Version 5.15
 10 December 2020
     -documentation-only update.  No code changes.