Sync from SUSE:SLFO:Main fetchmail revision 167eafefba1b0c2f31793088483240b6
This commit is contained in:
commit
3e80a7d031
23
.gitattributes
vendored
Normal file
23
.gitattributes
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
## Default LFS
|
||||
*.7z filter=lfs diff=lfs merge=lfs -text
|
||||
*.bsp filter=lfs diff=lfs merge=lfs -text
|
||||
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
||||
*.gem filter=lfs diff=lfs merge=lfs -text
|
||||
*.gz filter=lfs diff=lfs merge=lfs -text
|
||||
*.jar filter=lfs diff=lfs merge=lfs -text
|
||||
*.lz filter=lfs diff=lfs merge=lfs -text
|
||||
*.lzma filter=lfs diff=lfs merge=lfs -text
|
||||
*.obscpio filter=lfs diff=lfs merge=lfs -text
|
||||
*.oxt filter=lfs diff=lfs merge=lfs -text
|
||||
*.pdf filter=lfs diff=lfs merge=lfs -text
|
||||
*.png filter=lfs diff=lfs merge=lfs -text
|
||||
*.rpm filter=lfs diff=lfs merge=lfs -text
|
||||
*.tbz filter=lfs diff=lfs merge=lfs -text
|
||||
*.tbz2 filter=lfs diff=lfs merge=lfs -text
|
||||
*.tgz filter=lfs diff=lfs merge=lfs -text
|
||||
*.ttf filter=lfs diff=lfs merge=lfs -text
|
||||
*.txz filter=lfs diff=lfs merge=lfs -text
|
||||
*.whl filter=lfs diff=lfs merge=lfs -text
|
||||
*.xz filter=lfs diff=lfs merge=lfs -text
|
||||
*.zip filter=lfs diff=lfs merge=lfs -text
|
||||
*.zst filter=lfs diff=lfs merge=lfs -text
|
41
fetchmail-6.3.8-smtp_errors.patch
Normal file
41
fetchmail-6.3.8-smtp_errors.patch
Normal file
@ -0,0 +1,41 @@
|
||||
# Patches fetchmail's behaviour for SMTP servers which:
|
||||
# 1) insist on using TLS - we do not want messages which cannot
|
||||
# be sent due to server negotiation problems lost - rather we
|
||||
# keep them on the mailserver. As users should realize rather
|
||||
# quickly that something went wrong, the overhead shouldn't
|
||||
# be considered that important.
|
||||
# 2) use the 501 error code to mark spam - in such a case
|
||||
# the 'antispam' option should be used
|
||||
Index: fetchmail-6.5.1/sink.c
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/sink.c
|
||||
+++ fetchmail-6.5.1/sink.c
|
||||
@@ -526,6 +526,19 @@ static int handle_smtp_report(struct que
|
||||
free(responses[0]);
|
||||
return(PS_TRANSIENT);
|
||||
|
||||
+ case 501: /* Syntax error in parameters or arguments */
|
||||
+ /*
|
||||
+ * Some SMTP servers use this error code to refuse spam, however
|
||||
+ * as we don't want to delete message if e.g. the address is (possibly
|
||||
+ * by mistake) malformed, user has to use the 'antispam' option to
|
||||
+ * treat this as spam symptom
|
||||
+ */
|
||||
+ free(responses[0]);
|
||||
+ if (outlevel > O_SILENT)
|
||||
+ report_complete(stdout,
|
||||
+ GT_(" SMTP 501 error - if the server uses this code to report spam, include '501' in the 'antispam' option .\n"));
|
||||
+ return(PS_TRANSIENT);
|
||||
+
|
||||
default:
|
||||
/* bounce non-transient errors back to the sender */
|
||||
if (smtperr >= 500 && smtperr <= 599)
|
||||
@@ -591,7 +604,7 @@ static int handle_smtp_report_without_bo
|
||||
case 553: /* invalid sending domain */
|
||||
return(PS_REFUSED);
|
||||
|
||||
- default:
|
||||
+ default:
|
||||
/* bounce non-transient errors back to the sender */
|
||||
if (smtperr >= 500 && smtperr <= 599)
|
||||
return(PS_SUCCESS);
|
BIN
fetchmail-6.5.1.tar.xz
(Stored with Git LFS)
Normal file
BIN
fetchmail-6.5.1.tar.xz
(Stored with Git LFS)
Normal file
Binary file not shown.
16
fetchmail-6.5.1.tar.xz.asc
Normal file
16
fetchmail-6.5.1.tar.xz.asc
Normal file
@ -0,0 +1,16 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQIzBAABCgAdFiEE3EplW9mTzUhx+oIQ5BKxVu/zhVoFAmcz6JcACgkQ5BKxVu/z
|
||||
hVptQA//c7mklRvCJmSIhF91w0XntT5aOoWL19zLLZXBXgU+3YXmhu8sUufaZtVF
|
||||
ORJpJPvxEuK3g3Ja9rS4q959pM1rTDZ15GvpnF9oXUi62xLEEGzMweU8PIIMu7Ov
|
||||
AV6kJMJ0jmVEBwRhVnYn18+QgiB33hy6CiHbzKXQafElbSbR+7Cg7C4tPpv2hlfh
|
||||
BslV/zZIGwDfi6GrlZqfPyd/r8258fhsmUQa/y/HTYm9QCc1DKXfSPzqpb1yZMLe
|
||||
omOw0IMduE2xn2QsWz2CgdeNO7QPH6qFoM9SJTh3xtI4f7xVb6tLW4vvVpOQb85E
|
||||
LIUg+NWoqBmLBx2wkLttSld9kDJZFTVksZEa7XcvJGY62tIeLAn/0Y1Ytg6Xpm9H
|
||||
oihaNZ7vhsB6iwNWOuHxXtJOpvkMfEDmtSQDoT3ier+HA8/+ofiLUrctZ30uh0da
|
||||
R/AjFDwFD53lbdWmfMpL+ZUHcctSg+3MDaL2AF2eOkxlDf0+zESffncxLLUXnhgR
|
||||
5eSpxg/CclShPY1kkq6D3UTznwLu4UxsjL2YmQS0jefE4VrJOBFxpExMs2z/tMKn
|
||||
yRV8JnDWTAHtw1FmynXz0YClXVHSKlf2h4vTUf92hapwvcz2ExhjkLDFiMMi+/jX
|
||||
+Qlb4iYVUdg5rqvTCTgWoHC4nArbcSSlYrxSQZpjSzUzyJzsSX8=
|
||||
=fYQt
|
||||
-----END PGP SIGNATURE-----
|
@ -0,0 +1,48 @@
|
||||
From: Matthew Ogilvie <mmogilvi+fml@zoho.com>
|
||||
Date: Sat, 3 Jun 2017 17:57:22 -0600
|
||||
Subject: FAQ: list gmail options including oauthbearer and app password
|
||||
Git-repo: https://gitlab.com/fetchmail/fetchmail.git
|
||||
Git-commit: dbeee6a0c0fc5392953f38d6f0dcffdeeb8ae141
|
||||
|
||||
---
|
||||
fetchmail-FAQ.html | 24 +++++++++++++++++++++---
|
||||
1 file changed, 21 insertions(+), 3 deletions(-)
|
||||
|
||||
Index: fetchmail-6.5.1/fetchmail-FAQ.html
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/fetchmail-FAQ.html
|
||||
+++ fetchmail-6.5.1/fetchmail-FAQ.html
|
||||
@@ -1956,12 +1956,28 @@ authentication schemes based on OAuth 2.
|
||||
users to jump through quite a few hoops, and use web browsers for
|
||||
signing in, and software vendors to hand in their software for
|
||||
sometimes paid reviews. Such is not going to happen for fetchmail.
|
||||
+
|
||||
+If this hinders access to your account through fetchmail, you have some
|
||||
+options:</p>
|
||||
+<ul>
|
||||
+ <li>You can generate and use an
|
||||
+ <a href="https://support.google.com/accounts/answer/185833">App Password</a>.
|
||||
+ This is probably best unless you are on a "G-Suite" account and the
|
||||
+ administrator has disabled this option.</li>
|
||||
+ <li>You can use separate tools to generate and renew oauth2 access
|
||||
+ tokens. Then configure fetchmail to use "auth oauthbearer" and use
|
||||
+ a current access token as the password. See comments and --help in
|
||||
+ contrib/fetchmail-oauth2.py from the fetchmail source tree
|
||||
+ for more information. This is derived from Google's
|
||||
+ <a href="https://github.com/google/gmail-oauth2-tools/wiki/OAuth2DotPyRunThrough">OAuth2DotPyRunThrough</a>,
|
||||
+ associated code, RFC-7628, and RFC-6750.</li>
|
||||
+ <li>You may turn on access for "less secure apps" at
|
||||
+ <a href="https://www.google.com/settings/security/lesssecureapps">https://www.google.com/settings/security/lesssecureapps</a>,
|
||||
+ or see <a href="https://support.google.com/accounts/answer/6010255">https://support.google.com/accounts/answer/6010255</a>.
|
||||
+ But G-suite administrators are more likely to have disabled
|
||||
+ this option than "App Password"s.</li>
|
||||
+</ul>
|
||||
|
||||
-If this hinders access to your account through fetchmail, you may
|
||||
-need to turn on access for "less secure apps", or create an application or service specific password.
|
||||
-
|
||||
-For Google, this - at some point in time - used to live at <a
|
||||
- href="https://myaccount.google.com/lesssecureapps">https://myaccount.google.com/lesssecureapps</a>.<br/>
|
||||
It is disputable whether an application that does not include web
|
||||
browsing capabilities or heavy-weight libraries is "less secure" as
|
||||
Google claims.</p>
|
@ -0,0 +1,616 @@
|
||||
From: Matthew Ogilvie <mmogilvi+fml@zoho.com>
|
||||
Date: Thu, 1 Jun 2017 00:09:02 -0600
|
||||
Subject: add contrib/fetchnmail-oauth2.py token acquisition utility
|
||||
Git-repo: https://gitlab.com/fetchmail/fetchmail.git
|
||||
Git-commit: c82625858682eb2396b6a49da79e403c6f2b018b
|
||||
|
||||
---
|
||||
contrib/README | 6
|
||||
contrib/fetchmail-oauth2.py | 567 ++++++++++++++++++++++++++++++++++++++++++++
|
||||
fetchmail.man | 3
|
||||
3 files changed, 575 insertions(+), 1 deletion(-)
|
||||
create mode 100755 contrib/fetchmail-oauth2.py
|
||||
|
||||
Index: fetchmail-6.5.1/contrib/README
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/contrib/README
|
||||
+++ fetchmail-6.5.1/contrib/README
|
||||
@@ -181,6 +181,12 @@ sendmail 8.11.0 with multidrop.
|
||||
|
||||
Watchdog script to check whether fetchmail is working in daemon mode.
|
||||
|
||||
+### fetchmail-oauth2.py
|
||||
+
|
||||
+Script to obtain oauth2 access tokens that "fetchmail --auth oauthbearer"
|
||||
+expects in place of the password. See --help and comments in the
|
||||
+script, as well as fetchmail --auth documentation.
|
||||
+
|
||||
### mold-remover.py
|
||||
|
||||
A short python script to remove old read mail from a pop3 mailserver.
|
||||
Index: fetchmail-6.5.1/contrib/fetchmail-oauth2.py
|
||||
===================================================================
|
||||
--- /dev/null
|
||||
+++ fetchmail-6.5.1/contrib/fetchmail-oauth2.py
|
||||
@@ -0,0 +1,567 @@
|
||||
+#!/usr/bin/python
|
||||
+#
|
||||
+# Updates: Copyright 2017 Matthew Ogilvie (mogilvie+fml at zoho.com)
|
||||
+# - Started with https://github.com/google/gmail-oauth2-tools.git
|
||||
+# commit 45c39795044c604ed126205806191a8473c0f671 dated
|
||||
+# 2015-06-09.
|
||||
+# - Add file interaction (--refresh, --auto_refresh,
|
||||
+# --obtain_refresh_token_file and related options).
|
||||
+# - Support both python 2 and 3.
|
||||
+# - Keeping the same license (below).
|
||||
+#
|
||||
+# Copyright 2012 Google Inc.
|
||||
+#
|
||||
+# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
+# you may not use this file except in compliance with the License.
|
||||
+# You may obtain a copy of the License at
|
||||
+#
|
||||
+ # http://www.apache.org/licenses/LICENSE-2.0
|
||||
+#
|
||||
+# Unless required by applicable law or agreed to in writing, software
|
||||
+# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
+# See the License for the specific language governing permissions and
|
||||
+# limitations under the License.
|
||||
+
|
||||
+###############
|
||||
+# POSSIBLE IMPROVEMENTS:
|
||||
+#
|
||||
+# FUTURE: Explicitly track expiration time of access tokens,
|
||||
+# and base --auto_refresh on actual expiration time instead of
|
||||
+# simple age.
|
||||
+# FUTURE: Add a mode that can print the access token by itself to
|
||||
+# stdout, presumably piped into fetchmail or similar (either both
|
||||
+# launched by a wrapper script, this launches fetchmail, or fetchmail
|
||||
+# launches this).
|
||||
+# FUTURE: Mix old and new interfaces (or get rid of old interface):
|
||||
+# Support using a config file to supply some of the details
|
||||
+# for the original google modes of operation (--generate_oauth2_token,
|
||||
+# --generate_oauth2_string, --refresh_token, and --test_*).
|
||||
+# Also support providing sensative data on the command line instead
|
||||
+# of files for the new modes of operation, despite the lack
|
||||
+# of security (process listings, .bash_history files, etc).
|
||||
+# FUTURE: Revise model for how to set permissions on updated files?
|
||||
+# Preserve existing? Somehow allow setting UID/GID? Warn if files
|
||||
+# are accessible by anyone but the current user?
|
||||
+
|
||||
+"""Performs client tasks for testing IMAP OAuth2 authentication.
|
||||
+
|
||||
+This documentation and examples is for gmail. For other providers,
|
||||
+you will likely need to track down appropriate non-default settings
|
||||
+for auth_url, token_url, and scope.
|
||||
+
|
||||
+To use this script, you'll need to have registered with Google as an OAuth
|
||||
+application and obtained an OAuth client ID and client secret.
|
||||
+See https://developers.google.com/identity/protocols/OAuth2 and
|
||||
+https://developers.google.com/identity/sign-in/web/devconsole-project
|
||||
+for instructions on registering and for documentation of the APIs
|
||||
+invoked by this code.
|
||||
+
|
||||
+This script has 2 main modes of operation.
|
||||
+
|
||||
+1. The first mode is used to generate and authorize an OAuth2 token, the
|
||||
+first step in logging in via OAuth2.
|
||||
+
|
||||
+First, after registering your "application" (above) you should setup a
|
||||
+configuration file. Use a text editor to do the command-line equivalent of:
|
||||
+
|
||||
+ sed 's/^ *//' > /path/to/oauth2Config.properties << EOF
|
||||
+ client_id=1038[...].apps.googleusercontent.com
|
||||
+ client_secret=VWFn8LIKAMC-MsjBMhJeOplZ
|
||||
+ refresh_token_file=/home/path/to/refresh_token_file
|
||||
+ access_token_file=/home/path/to/access_token_file
|
||||
+EOF
|
||||
+
|
||||
+ chmod 600 /path/to/oauth2Config.properties
|
||||
+
|
||||
+Then run the following, and repeat any time the refresh token stops
|
||||
+working, such as when you change your password. This is interactive
|
||||
+and requires a web browser to complete:
|
||||
+
|
||||
+ oauth2 -c /path/to/oauth2Config.properties --obtain_refresh_token_file
|
||||
+
|
||||
+The script will converse with Google and generate an oauth request
|
||||
+token, then present you with a URL you should visit in your browser to
|
||||
+authorize the token. Once you get the verification code from the Google
|
||||
+website, enter it into the script, which will then save access and referesh
|
||||
+tokens to the corresponding files for later use.
|
||||
+
|
||||
+Also, you'll usually need to configure fetchmail by
|
||||
+including a section like the following in your .fetchmailrc:
|
||||
+
|
||||
+ poll imap.gmail.com protocol imap
|
||||
+ auth oauthbearer username "USER@gmail.com"
|
||||
+ passwordfile "/home/path/to/access_token_file"
|
||||
+ is LOCALUSER here sslmode wrapped sslcertck
|
||||
+
|
||||
+Alternative for debugging: You can also use the original google
|
||||
+script interface to obtain these tokens without involving files:
|
||||
+
|
||||
+ oauth2 \
|
||||
+ --client_id=1038[...].apps.googleusercontent.com \
|
||||
+ --client_secret=VWFn8LIKAMC-MsjBMhJeOplZ \
|
||||
+ --generate_oauth2_token
|
||||
+
|
||||
+
|
||||
+-----
|
||||
+2. The script will generate new access tokens using a refresh token.
|
||||
+
|
||||
+This uses the same config file setup above.
|
||||
+
|
||||
+ oauth2 -c /path/to/oauth2Config.properties --auto_refresh
|
||||
+ # Or force refresh by using --refresh instead of --auto_refresh.
|
||||
+
|
||||
+ fetchmail -s # or other tools configured to use the access_token_file
|
||||
+ # And/or call something to update outgoing MTA relay configuration,
|
||||
+ # if necessary.
|
||||
+
|
||||
+You may put this sequence in a short shell script,
|
||||
+and configure cron to call it a few times per hour.
|
||||
+
|
||||
+Alternative for debugging: You can also use the original google
|
||||
+script interface to refresh the token without involving files:
|
||||
+
|
||||
+ oauth2 \
|
||||
+ --client_id=1038[...].apps.googleusercontent.com \
|
||||
+ --client_secret=VWFn8LIKAMC-MsjBMhJeOplZ \
|
||||
+ --refresh_token=1/Yzm6MRy4q1xi7Dx2DuWXNgT6s37OrP_DW_IoyTum4YA
|
||||
+
|
||||
+-----
|
||||
+Google's non-file script interface also supports a few other
|
||||
+testing modes; see --help.
|
||||
+"""
|
||||
+
|
||||
+from __future__ import print_function
|
||||
+import base64
|
||||
+import imaplib
|
||||
+import json
|
||||
+from optparse import OptionParser
|
||||
+import smtplib
|
||||
+import sys
|
||||
+import os
|
||||
+import time
|
||||
+
|
||||
+try:
|
||||
+ import urllib.request as urlopen
|
||||
+ import urllib.parse as urlparse
|
||||
+except ImportError:
|
||||
+ import urllib as urlopen
|
||||
+ import urllib as urlparse
|
||||
+
|
||||
+try: input = raw_input
|
||||
+except NameError: pass
|
||||
+
|
||||
+
|
||||
+def SetupOptionParser():
|
||||
+ # Usage message is the module's docstring.
|
||||
+ parser = OptionParser(usage=__doc__)
|
||||
+ parser.add_option('-c', '--config_file',
|
||||
+ default=None,
|
||||
+ help='Configuration file for --refresh '
|
||||
+ 'and --obtain_refresh_token_file.\n'
|
||||
+ 'The file should contain 4 (or more) settings, '
|
||||
+ 'one per line, or they can also be overridden '
|
||||
+ 'by the equivalent options:\n'
|
||||
+ ' client_id=...\n'
|
||||
+ ' client_secret=...\n'
|
||||
+ ' refresh_token_file=/path/to/...\n'
|
||||
+ ' access_token_file=/path/to/...\n'
|
||||
+ ' Also max_age_sec, scope, umask, auth_url, and'
|
||||
+ ' token_url have reasonable defaults for google.')
|
||||
+ parser.add_option('--auto_refresh',
|
||||
+ action='store_const',
|
||||
+ default=None,
|
||||
+ const=1,
|
||||
+ dest='refresh',
|
||||
+ help='Automatically refresh access_token_file, '
|
||||
+ 'if older than max_age_sec from '
|
||||
+ 'required -c /file/ info.');
|
||||
+ parser.add_option('--refresh',
|
||||
+ action='store_const',
|
||||
+ const=2,
|
||||
+ dest='refresh',
|
||||
+ help='Refresh access_token_file '
|
||||
+ 'unconditionally. Requires -c /file/ info.');
|
||||
+ parser.add_option('--obtain_refresh_token_file',
|
||||
+ action='store_true',
|
||||
+ dest='obtain_refresh_token_file',
|
||||
+ default=None,
|
||||
+ help='Update refresh token in file. This is '
|
||||
+ 'interactive, and requires '
|
||||
+ 'a web browser. Also requires -c /file/ info. '
|
||||
+ 'This also saves an initial access_token_file.');
|
||||
+ parser.add_option('--client_id',
|
||||
+ default=None,
|
||||
+ help='Client ID of the application that is authenticating. '
|
||||
+ 'See OAuth2 documentation for details.')
|
||||
+ parser.add_option('--client_secret',
|
||||
+ default=None,
|
||||
+ help='Client secret of the application that is '
|
||||
+ 'authenticating. See OAuth2 documentation for '
|
||||
+ 'details.')
|
||||
+ parser.add_option('--access_token_file',
|
||||
+ default=None,
|
||||
+ help='File name containing OAuth2 access token')
|
||||
+ parser.add_option('--refresh_token_file',
|
||||
+ default=None,
|
||||
+ help='File name containing OAuth2 refresh token')
|
||||
+ parser.add_option('--max_age_sec',
|
||||
+ default=None, # manual default 3000
|
||||
+ help='default max file age for --auto_refresh. '
|
||||
+ 'Defaults to 3000 (10 minutes short of '
|
||||
+ 'normal 3600 sec token expiration).')
|
||||
+ parser.add_option('--umask',
|
||||
+ default=None, # manual default 0077
|
||||
+ help='default umask for --auto_refresh and '
|
||||
+ '--obtain_refresh_token_file. Defaults to 0077.')
|
||||
+ parser.add_option('--scope',
|
||||
+ default=None, # manual default='https://mail.google.com/'
|
||||
+ help='scope for the access token. Multiple scopes can be '
|
||||
+ 'listed separated by spaces with the whole argument '
|
||||
+ 'quoted. Defaults to https://mail.google.com/')
|
||||
+ parser.add_option('--auth_url',
|
||||
+ default=None, # manual default...
|
||||
+ help='Permission URL for --obtain_refresh_token_file. '
|
||||
+ 'Defaults to https://accounts.google.com/o/oauth2/auth.')
|
||||
+ parser.add_option('--token_url',
|
||||
+ default=None, # manual default...
|
||||
+ help='Token URL for --obtain_refresh_token_file,'
|
||||
+ ' and --refresh. '
|
||||
+ 'Defaults to https://accounts.google.com/o/oauth2/token.')
|
||||
+ parser.add_option('--generate_oauth2_token',
|
||||
+ action='store_true',
|
||||
+ dest='generate_oauth2_token',
|
||||
+ help='(OLD/testing) generates an OAuth2 token for testing.'
|
||||
+ ' Ignores all files.')
|
||||
+ parser.add_option('--refresh_token',
|
||||
+ default=None,
|
||||
+ help='(OLD/testing) Generate a new access token using'
|
||||
+ ' this OAuth2 refresh token. Ignores all files.')
|
||||
+ parser.add_option('--user',
|
||||
+ default=None,
|
||||
+ help='(OLD/testing) email address of user whose account'
|
||||
+ ' is being accessed')
|
||||
+ parser.add_option('--access_token',
|
||||
+ default=None,
|
||||
+ help='(OLD/testing) OAuth2 access token.')
|
||||
+ parser.add_option('--generate_oauth2_string',
|
||||
+ action='store_true',
|
||||
+ dest='generate_oauth2_string',
|
||||
+ help='(OLD/testing) generates an initial client response'
|
||||
+ ' string for OAuth2. Ignores all files.')
|
||||
+ parser.add_option('--test_imap_authentication',
|
||||
+ action='store_true',
|
||||
+ dest='test_imap_authentication',
|
||||
+ help='(OLD/testing) attempts to authenticate to IMAP. '
|
||||
+ 'Ignores all files.')
|
||||
+ parser.add_option('--test_smtp_authentication',
|
||||
+ action='store_true',
|
||||
+ dest='test_smtp_authentication',
|
||||
+ help='(OLD/testing) attempts to authenticate to SMTP. '
|
||||
+ 'Ignores all files.')
|
||||
+ return parser
|
||||
+
|
||||
+
|
||||
+# Hardcoded dummy redirect URI for non-web apps.
|
||||
+REDIRECT_URI = 'urn:ietf:wg:oauth:2.0:oob'
|
||||
+
|
||||
+
|
||||
+def UrlEscape(text):
|
||||
+ # See OAUTH 5.1 for a definition of which characters need to be escaped.
|
||||
+ return urlparse.quote(text, safe='~-._')
|
||||
+
|
||||
+
|
||||
+def UrlUnescape(text):
|
||||
+ # See OAUTH 5.1 for a definition of which characters need to be escaped.
|
||||
+ return urlparse.unquote(text)
|
||||
+
|
||||
+
|
||||
+def FormatUrlParams(params):
|
||||
+ """Formats parameters into a URL query string.
|
||||
+
|
||||
+ Args:
|
||||
+ params: A key-value map.
|
||||
+
|
||||
+ Returns:
|
||||
+ A URL query string version of the given parameters.
|
||||
+ """
|
||||
+ param_fragments = []
|
||||
+ for param in sorted(params.items(), key=lambda x: x[0]):
|
||||
+ param_fragments.append('%s=%s' % (param[0], UrlEscape(param[1])))
|
||||
+ return '&'.join(param_fragments)
|
||||
+
|
||||
+
|
||||
+def GeneratePermissionUrl(client_id, scope, auth_url):
|
||||
+ """Generates the URL for authorizing access.
|
||||
+
|
||||
+ This uses the "OAuth2 for Installed Applications" flow described at
|
||||
+ https://developers.google.com/accounts/docs/OAuth2InstalledApp
|
||||
+
|
||||
+ Args:
|
||||
+ client_id: Client ID obtained by registering your app.
|
||||
+ scope: scope for access token, e.g. 'https://mail.google.com'
|
||||
+ Returns:
|
||||
+ A URL that the user should visit in their browser.
|
||||
+ """
|
||||
+ if not scope:
|
||||
+ scope = 'https://mail.google.com/'
|
||||
+ if not auth_url:
|
||||
+ auth_url = 'https://accounts.google.com/o/oauth2/auth'
|
||||
+ params = {}
|
||||
+ params['client_id'] = client_id
|
||||
+ params['redirect_uri'] = REDIRECT_URI
|
||||
+ params['scope'] = scope
|
||||
+ params['response_type'] = 'code'
|
||||
+ return '%s?%s' % (auth_url, FormatUrlParams(params))
|
||||
+
|
||||
+
|
||||
+def AuthorizeTokens(client_id, client_secret, authorization_code, token_url):
|
||||
+ """Obtains OAuth access token and refresh token.
|
||||
+
|
||||
+ This uses the application portion of the "OAuth2 for Installed Applications"
|
||||
+ flow at https://developers.google.com/accounts/docs/OAuth2InstalledApp#handlingtheresponse
|
||||
+
|
||||
+ Args:
|
||||
+ client_id: Client ID obtained by registering your app.
|
||||
+ client_secret: Client secret obtained by registering your app.
|
||||
+ authorization_code: code generated by Google Accounts after user grants
|
||||
+ permission.
|
||||
+ Returns:
|
||||
+ The decoded response from the Google Accounts server, as a dict. Expected
|
||||
+ fields include 'access_token', 'expires_in', and 'refresh_token'.
|
||||
+ """
|
||||
+ params = {}
|
||||
+ params['client_id'] = client_id
|
||||
+ params['client_secret'] = client_secret
|
||||
+ params['code'] = authorization_code
|
||||
+ params['redirect_uri'] = REDIRECT_URI
|
||||
+ params['grant_type'] = 'authorization_code'
|
||||
+ if not token_url:
|
||||
+ token_url = 'https://accounts.google.com/o/oauth2/token'
|
||||
+
|
||||
+ response = urlopen.urlopen(token_url,
|
||||
+ urlparse.urlencode(params).encode('ascii')).read()
|
||||
+ return json.loads(response.decode("utf-8"))
|
||||
+
|
||||
+
|
||||
+def RefreshToken(client_id, client_secret, refresh_token, token_url):
|
||||
+ """Obtains a new token given a refresh token.
|
||||
+
|
||||
+ See https://developers.google.com/accounts/docs/OAuth2InstalledApp#refresh
|
||||
+
|
||||
+ Args:
|
||||
+ client_id: Client ID obtained by registering your app.
|
||||
+ client_secret: Client secret obtained by registering your app.
|
||||
+ refresh_token: A previously-obtained refresh token.
|
||||
+ Returns:
|
||||
+ The decoded response from the Google Accounts server, as a dict. Expected
|
||||
+ fields include 'access_token', 'expires_in', and 'refresh_token'.
|
||||
+ """
|
||||
+ params = {}
|
||||
+ params['client_id'] = client_id
|
||||
+ params['client_secret'] = client_secret
|
||||
+ params['refresh_token'] = refresh_token
|
||||
+ params['grant_type'] = 'refresh_token'
|
||||
+ if not token_url:
|
||||
+ token_url = 'https://accounts.google.com/o/oauth2/token'
|
||||
+
|
||||
+ response = urlopen.urlopen(token_url,
|
||||
+ urlparse.urlencode(params).encode('ascii')).read()
|
||||
+ return json.loads(response.decode("utf-8"))
|
||||
+
|
||||
+
|
||||
+def GenerateOAuth2String(username, access_token, base64_encode=True):
|
||||
+ """Generates an IMAP OAuth2 authentication string.
|
||||
+
|
||||
+ See https://developers.google.com/google-apps/gmail/oauth2_overview
|
||||
+
|
||||
+ Args:
|
||||
+ username: the username (email address) of the account to authenticate
|
||||
+ access_token: An OAuth2 access token.
|
||||
+ base64_encode: Whether to base64-encode the output.
|
||||
+
|
||||
+ Returns:
|
||||
+ The SASL argument for the OAuth2 mechanism.
|
||||
+ """
|
||||
+ auth_string = 'user=%s\1auth=Bearer %s\1\1' % (username, access_token)
|
||||
+ if base64_encode:
|
||||
+ auth_string = base64.b64encode(auth_string)
|
||||
+ return auth_string
|
||||
+
|
||||
+
|
||||
+def TestImapAuthentication(user, auth_string):
|
||||
+ """Authenticates to IMAP with the given auth_string.
|
||||
+
|
||||
+ Prints a debug trace of the attempted IMAP connection.
|
||||
+
|
||||
+ Args:
|
||||
+ user: The Gmail username (full email address)
|
||||
+ auth_string: A valid OAuth2 string, as returned by GenerateOAuth2String.
|
||||
+ Must not be base64-encoded, since imaplib does its own base64-encoding.
|
||||
+ """
|
||||
+ print()
|
||||
+ imap_conn = imaplib.IMAP4_SSL('imap.gmail.com')
|
||||
+ imap_conn.debug = 4
|
||||
+ imap_conn.authenticate('XOAUTH2', lambda x: auth_string)
|
||||
+ imap_conn.select('INBOX')
|
||||
+
|
||||
+
|
||||
+def TestSmtpAuthentication(user, auth_string):
|
||||
+ """Authenticates to SMTP with the given auth_string.
|
||||
+
|
||||
+ Args:
|
||||
+ user: The Gmail username (full email address)
|
||||
+ auth_string: A valid OAuth2 string, not base64-encoded, as returned by
|
||||
+ GenerateOAuth2String.
|
||||
+ """
|
||||
+ print()
|
||||
+ smtp_conn = smtplib.SMTP('smtp.gmail.com', 587)
|
||||
+ smtp_conn.set_debuglevel(True)
|
||||
+ smtp_conn.ehlo('test')
|
||||
+ smtp_conn.starttls()
|
||||
+ smtp_conn.docmd('AUTH', 'XOAUTH2 ' + base64.b64encode(auth_string))
|
||||
+
|
||||
+
|
||||
+def RequireOptions(options, *args):
|
||||
+ missing = [arg for arg in args if getattr(options, arg) is None]
|
||||
+ if missing:
|
||||
+ print('Missing options: %s' % ' '.join(missing))
|
||||
+ sys.exit(-1)
|
||||
+
|
||||
+def parseConfigFile(options):
|
||||
+ if options.config_file:
|
||||
+ cfg = dict(line.strip().split('=',1) for line in open(options.config_file))
|
||||
+ else:
|
||||
+ cfg = { }
|
||||
+ # defaults:
|
||||
+ if not 'scope' in cfg:
|
||||
+ cfg['scope'] = 'https://mail.google.com/'
|
||||
+ if not 'max_age_sec' in cfg:
|
||||
+ cfg['max_age_sec'] = '3000'
|
||||
+ if not 'umask' in cfg:
|
||||
+ cfg['umask'] = '0077'
|
||||
+ if not 'auth_url' in cfg:
|
||||
+ cfg['auth_url'] = 'https://accounts.google.com/o/oauth2/auth'
|
||||
+ if not 'token_url' in cfg:
|
||||
+ cfg['token_url'] = 'https://accounts.google.com/o/oauth2/token'
|
||||
+ # overrides (from command line):
|
||||
+ for arg in [ 'scope', 'client_id', 'client_secret', 'umask',
|
||||
+ 'max_age_sec', 'access_token_file', 'refresh_token_file',
|
||||
+ 'auth_url', 'token_url' ]:
|
||||
+ if getattr(options,arg):
|
||||
+ cfg[arg] = getattr(options,arg)
|
||||
+ return cfg
|
||||
+
|
||||
+def requireConfig(cfg, *args):
|
||||
+ missing = [arg for arg in args if not arg in cfg]
|
||||
+ if missing:
|
||||
+ print('Missing options: %s' % ' '.join(missing))
|
||||
+ sys.exit(-1)
|
||||
+
|
||||
+
|
||||
+def main(argv):
|
||||
+ options_parser = SetupOptionParser()
|
||||
+ (options, args) = options_parser.parse_args()
|
||||
+ if options.refresh:
|
||||
+ cfg = parseConfigFile(options)
|
||||
+ requireConfig(cfg, 'refresh_token_file', 'access_token_file',
|
||||
+ 'client_id', 'client_secret', 'umask')
|
||||
+ st = os.stat(cfg['access_token_file'])
|
||||
+ if options.refresh < 2:
|
||||
+ requireConfig(cfg, 'max_age_sec')
|
||||
+ if time.time()-st.st_mtime < int(cfg['max_age_sec']):
|
||||
+ return
|
||||
+ with open(cfg['refresh_token_file'],"r") as f:
|
||||
+ reftok = f.readline().rstrip()
|
||||
+ if len(reftok) == 0:
|
||||
+ print('refresh token is empty')
|
||||
+ sys.exit(-1)
|
||||
+ response = RefreshToken(cfg['client_id'],cfg['client_secret'],reftok,
|
||||
+ cfg['token_url'])
|
||||
+ newTok = response['access_token']
|
||||
+ if len(newTok) == 0:
|
||||
+ print('failed to obtain access token: it is empty')
|
||||
+ sys.exit(-1)
|
||||
+ savedUmask = os.umask(int(cfg['umask'],8))
|
||||
+ try:
|
||||
+ with open(cfg['access_token_file']+".tmp","w") as f:
|
||||
+ f.write(newTok)
|
||||
+ f.write('\n')
|
||||
+ os.rename(cfg['access_token_file']+".tmp",cfg['access_token_file'])
|
||||
+ finally:
|
||||
+ os.umask(savedUmask)
|
||||
+ elif options.obtain_refresh_token_file:
|
||||
+ cfg = parseConfigFile(options)
|
||||
+ requireConfig(cfg, 'refresh_token_file', 'access_token_file',
|
||||
+ 'client_id', 'client_secret', 'umask')
|
||||
+ print('To authorize token, visit this url and follow the directions:')
|
||||
+ print(' %s' % GeneratePermissionUrl(cfg['client_id'], cfg['scope'],
|
||||
+ cfg['auth_url']))
|
||||
+ authorization_code = input('Enter verification code: ')
|
||||
+ response = AuthorizeTokens(cfg['client_id'], cfg['client_secret'],
|
||||
+ authorization_code, cfg['token_url'])
|
||||
+ newRefTok = response['refresh_token']
|
||||
+ if len(newRefTok) == 0:
|
||||
+ print('failed to obtain refresh token: it is empty')
|
||||
+ sys.exit(-1)
|
||||
+ newTok = response['access_token']
|
||||
+ if len(newTok) == 0:
|
||||
+ print('failed to obtain corresponding access token: it is empty')
|
||||
+ sys.exit(-1)
|
||||
+ savedUmask = os.umask(int(cfg['umask'],8))
|
||||
+ try:
|
||||
+ with open(cfg['refresh_token_file']+".tmp","w") as f:
|
||||
+ f.write(newRefTok)
|
||||
+ f.write('\n')
|
||||
+ os.rename(cfg['refresh_token_file']+".tmp",cfg['refresh_token_file'])
|
||||
+ with open(cfg['access_token_file']+".tmp","w") as f:
|
||||
+ f.write(newTok)
|
||||
+ f.write('\n')
|
||||
+ print("Refresh token saved to '%s'" % cfg['refresh_token_file'])
|
||||
+ print("Initial access token saved to '%s'" % cfg['access_token_file'])
|
||||
+ print('Access Token Expiration Seconds: %s' % response['expires_in'])
|
||||
+ os.rename(cfg['access_token_file']+".tmp",cfg['access_token_file'])
|
||||
+ finally:
|
||||
+ os.umask(savedUmask)
|
||||
+
|
||||
+ ##### (OLD/testing options)
|
||||
+
|
||||
+ elif options.refresh_token:
|
||||
+ RequireOptions(options, 'client_id', 'client_secret')
|
||||
+ response = RefreshToken(options.client_id, options.client_secret,
|
||||
+ options.refresh_token, options.token_url)
|
||||
+ print('Access Token: %s' % response['access_token'])
|
||||
+ print('Access Token Expiration Seconds: %s' % response['expires_in'])
|
||||
+ elif options.generate_oauth2_string:
|
||||
+ RequireOptions(options, 'user', 'access_token')
|
||||
+ print ('OAuth2 argument:\n' +
|
||||
+ GenerateOAuth2String(options.user, options.access_token))
|
||||
+ elif options.generate_oauth2_token:
|
||||
+ RequireOptions(options, 'client_id', 'client_secret')
|
||||
+ print('To authorize token, visit this url and follow the directions:')
|
||||
+ print(' %s' % GeneratePermissionUrl(options.client_id, options.scope,
|
||||
+ options.auth_url))
|
||||
+ authorization_code = input('Enter verification code: ')
|
||||
+ response = AuthorizeTokens(options.client_id, options.client_secret,
|
||||
+ authorization_code, options.token_url)
|
||||
+ print('Refresh Token: %s' % response['refresh_token'])
|
||||
+ print('Access Token: %s' % response['access_token'])
|
||||
+ print('Access Token Expiration Seconds: %s' % response['expires_in'])
|
||||
+ elif options.test_imap_authentication:
|
||||
+ RequireOptions(options, 'user', 'access_token')
|
||||
+ TestImapAuthentication(options.user,
|
||||
+ GenerateOAuth2String(options.user, options.access_token,
|
||||
+ base64_encode=False))
|
||||
+ elif options.test_smtp_authentication:
|
||||
+ RequireOptions(options, 'user', 'access_token')
|
||||
+ TestSmtpAuthentication(options.user,
|
||||
+ GenerateOAuth2String(options.user, options.access_token,
|
||||
+ base64_encode=False))
|
||||
+ else:
|
||||
+ options_parser.print_help()
|
||||
+ print('Nothing to do, exiting.')
|
||||
+ return
|
||||
+
|
||||
+
|
||||
+if __name__ == '__main__':
|
||||
+ main(sys.argv)
|
||||
Index: fetchmail-6.5.1/fetchmail.man
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/fetchmail.man
|
||||
+++ fetchmail-6.5.1/fetchmail.man
|
||||
@@ -1181,7 +1181,8 @@ External tools are necessary to obtain
|
||||
such tokens. Access tokens often expire fairly quickly (e.g. 1 hour),
|
||||
and new ones need to be generated from renewal tokens, so the
|
||||
"passwordfile", "passwordfd", or "pwmd_*" options may be useful. See the
|
||||
-oauth2.py script from
|
||||
+contrib/fetchmail-oauth2.py script from the fetchmail source code, which
|
||||
+was derived from code associated with
|
||||
.URL https://github.com/google/gmail-oauth2-tools/wiki/OAuth2DotPyRunThrough "Google's Oauth2 Run Through" ,
|
||||
and other oauth2 documentation. For services like gmail, an "App Password"
|
||||
is probably preferable if available, because it has roughly the same
|
300
fetchmail-add-imap-oauthbearer-support.patch
Normal file
300
fetchmail-add-imap-oauthbearer-support.patch
Normal file
@ -0,0 +1,300 @@
|
||||
From: Matthew Ogilvie <mmogilvi+fml@zoho.com>
|
||||
Date: Sat, 27 May 2017 15:32:28 -0600
|
||||
Subject: add imap oauthbearer support
|
||||
Git-repo: https://gitlab.com/fetchmail/fetchmail.git
|
||||
Git-commit: 5c44df6df70b90f06d3204c6fbdd1ff19e990ca0
|
||||
|
||||
This expects an oauth2 access token in place of password.
|
||||
When configured, it will also fall back on trying xoauth2.
|
||||
---
|
||||
conf.c | 2 +
|
||||
fetchmail.c | 3 +
|
||||
fetchmail.h | 2 +
|
||||
fetchmail.man | 26 +++++++++++--
|
||||
fetchmailconf.py | 2 -
|
||||
imap.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
options.c | 2 +
|
||||
rcfile_l.l | 1
|
||||
8 files changed, 137 insertions(+), 5 deletions(-)
|
||||
|
||||
Index: fetchmail-6.5.1/conf.c
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/conf.c
|
||||
+++ fetchmail-6.5.1/conf.c
|
||||
@@ -284,6 +284,8 @@ void dump_config(struct runctl *runp, st
|
||||
stringdump("auth", "otp");
|
||||
else if (ctl->server.authenticate == A_MSN)
|
||||
stringdump("auth", "msn");
|
||||
+ else if (ctl->server.authenticate == A_OAUTHBEARER)
|
||||
+ stringdump("auth", "oauthbearer");
|
||||
|
||||
#ifdef HAVE_RES_SEARCH
|
||||
booldump("dns", ctl->server.dns);
|
||||
Index: fetchmail-6.5.1/fetchmail.c
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/fetchmail.c
|
||||
+++ fetchmail-6.5.1/fetchmail.c
|
||||
@@ -1804,6 +1804,9 @@ static void dump_params (struct runctl *
|
||||
case A_IMPLICIT:
|
||||
printf(GT_(" End-to-end encryption assumed.\n"));
|
||||
break;
|
||||
+ case A_OAUTHBEARER:
|
||||
+ printf(GT_(" OAUTHBEARER will be forced; expecting password to really be OAUTH2 authentication token\n"));
|
||||
+ break;
|
||||
}
|
||||
if (ctl->server.principal != (char *) NULL)
|
||||
printf(GT_(" Mail service principal is: %s\n"), ctl->server.principal);
|
||||
Index: fetchmail-6.5.1/fetchmail.h
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/fetchmail.h
|
||||
+++ fetchmail-6.5.1/fetchmail.h
|
||||
@@ -64,6 +64,7 @@ struct addrinfo;
|
||||
#define A_IMPLICIT 8 /* authentication at session level */
|
||||
#define A_MSN 9 /* same as NTLM with keyword MSN */
|
||||
#define A_EXTERNAL 10 /* external authentication (client cert) */
|
||||
+#define A_OAUTHBEARER 11 /** oauth2 access token (not password) */
|
||||
|
||||
/* some protocols or authentication types (KERBEROS, GSSAPI, SSH) don't
|
||||
* require a password */
|
||||
@@ -99,6 +100,7 @@ struct addrinfo;
|
||||
#define MSGBUFSIZE 8192
|
||||
|
||||
#define NAMELEN 64 /* max username length */
|
||||
+/* oauth2 access tokens seem to be about 130 characters; make this longer: */
|
||||
#define PASSWORDLEN 256 /* max password length */
|
||||
#define DIGESTLEN 33 /* length of MD5 digest */
|
||||
|
||||
Index: fetchmail-6.5.1/fetchmail.man
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/fetchmail.man
|
||||
+++ fetchmail-6.5.1/fetchmail.man
|
||||
@@ -1113,8 +1113,8 @@ AUTHENTICATION below for details). The
|
||||
\&\fBpassword\fP, \fBkerberos_v5\fP, \fBkerberos\fP (or, for
|
||||
excruciating exactness, \fBkerberos_v4\fP), \fBgssapi\fP,
|
||||
\fBcram\-md5\fP, \fBotp\fP, \fBntlm\fP, \fBmsn\fP (only for POP3),
|
||||
-\fBexternal\fP (only IMAP) and \fBimplicit\fP (\fBssh\fP is understood
|
||||
-as alias for \fBimplicit\fP).
|
||||
+\fBexternal\fP (only IMAP), \fBimplicit\fP (\fBssh\fP is understood
|
||||
+as alias for \fBimplicit\fP) and \fBoauthbearer\fP (only IMAP).
|
||||
When \fBany\fP (the default) is specified, fetchmail tries
|
||||
first methods that do not require a password (EXTERNAL, GSSAPI, KERBEROS\ IV,
|
||||
KERBEROS\ 5); then it looks for methods that mask your password
|
||||
@@ -1139,8 +1139,24 @@ authentication. This option does not wo
|
||||
in line with RFC-2743 and IANA registrations, see
|
||||
.UR https://www.iana.org/assignments/gssapi-service-names/
|
||||
Generic Security Service Application Program Interface (GSSAPI)/Kerberos/Simple
|
||||
-Authentication and Security Layer (SASL) Service Names
|
||||
-.UE .
|
||||
+Authentication and Security Layer (SASL) Service Names .
|
||||
+.sp
|
||||
+\fBoauthbearer\fP expects the supplied password to be an oauth2 authentication
|
||||
+token instead of a password, as used by services like gmail.
|
||||
+See RFC 7628 and RFC 6750. The \fBoauthbearer\fP
|
||||
+setting also allows the non-standard "xoauth2" SASL scheme (using
|
||||
+the same token) if the server only claims to support "xoauth2".
|
||||
+External tools are necessary to obtain
|
||||
+such tokens. Access tokens often expire fairly quickly (e.g. 1 hour),
|
||||
+and new ones need to be generated from renewal tokens. See the
|
||||
+oauth2.py script from
|
||||
+.URL https://github.com/google/gmail-oauth2-tools/wiki/OAuth2DotPyRunThrough "Google's Oauth2 Run Through" ,
|
||||
+and other oauth2 documentation. For services like gmail, an "App Password"
|
||||
+is probably preferable if available, because it has roughly the same
|
||||
+security risks, and is a whole lot simpler to get working. "App Password"
|
||||
+and oauthbearer both need to protect secrets on the client machine (files) and
|
||||
+over the network (SSL/TLS). But "App Password" is
|
||||
+sometimes completely disabled by business "G-suite" administrators.
|
||||
.SS Miscellaneous Options
|
||||
.TP
|
||||
.B \-f <pathname> | \-\-fetchmailrc <pathname>
|
||||
@@ -2475,7 +2491,9 @@ Legal protocol identifiers for use with
|
||||
.PP
|
||||
Legal authentication types are 'any', 'password', 'kerberos',
|
||||
\&'kerberos_v4', 'kerberos_v5' and 'gssapi', 'cram\-md5', 'otp', 'msn'
|
||||
-(only for POP3), 'ntlm', 'implicit', 'external' (only IMAP).
|
||||
+(only for POP3), 'ntlm', 'implicit', 'external' (only IMAP),
|
||||
+'oauthbearer' (only for IMAP; requires authentication token in
|
||||
+place of password).
|
||||
The 'password' type specifies
|
||||
authentication by normal transmission of a password (the password may be
|
||||
plain text or subject to protocol-specific encryption as in CRAM-MD5);
|
||||
Index: fetchmail-6.5.1/fetchmailconf.py
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/fetchmailconf.py
|
||||
+++ fetchmail-6.5.1/fetchmailconf.py
|
||||
@@ -499,7 +499,7 @@ defaultports = {"auto":None,
|
||||
"ODMR":"odmr"}
|
||||
|
||||
authlist = ("any", "password", "gssapi", "kerberos", "implicit", "otp",
|
||||
- "msn", "ntlm")
|
||||
+ "msn", "ntlm", "oauthbearer")
|
||||
|
||||
listboxhelp = {
|
||||
'title' : 'List Selection Help',
|
||||
Index: fetchmail-6.5.1/imap.c
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/imap.c
|
||||
+++ fetchmail-6.5.1/imap.c
|
||||
@@ -24,6 +24,10 @@
|
||||
#define IMAP4 0 /* IMAP4 rev 0, RFC1730 */
|
||||
#define IMAP4rev1 1 /* IMAP4 rev 1, RFC2060 */
|
||||
|
||||
+/* imap_plus_cont_context values */
|
||||
+#define IPLUS_NONE 0
|
||||
+#define IPLUS_OAUTHBEARER 1 /* oauthbearer (for more error info) */
|
||||
+
|
||||
/* global variables: please reinitialize them explicitly for proper
|
||||
* working in daemon mode */
|
||||
|
||||
@@ -49,6 +53,8 @@ static void clear_sessiondata(void) {
|
||||
* a const initializer */
|
||||
const char *const capa_begin = " [CAPABILITY "; const unsigned capa_len = 13;
|
||||
|
||||
+static int plus_cont_context = IPLUS_NONE;
|
||||
+
|
||||
/* mailbox variables initialized in imap_getrange() */
|
||||
static int count = 0, oldcount = 0, recentcount = 0, unseen = 0, deletions = 0;
|
||||
static unsigned int startcount = 1;
|
||||
@@ -262,6 +268,21 @@ static int imap_response(int sock, char
|
||||
if (ok != PS_SUCCESS)
|
||||
return(ok);
|
||||
|
||||
+ if (buf[0] == '+' && buf[1] == ' ') {
|
||||
+ if (plus_cont_context == IPLUS_OAUTHBEARER) {
|
||||
+ /* future: Consider decoding the base64-encoded JSON
|
||||
+ * error response info and logging it. But for now,
|
||||
+ * ignore continuation data, send the expected blank
|
||||
+ * line, and assume that the next response will be
|
||||
+ * a tagged "NO" as documented.
|
||||
+ */
|
||||
+ SockWrite(sock, "\r\n", 2);
|
||||
+ if (outlevel >= O_MONITOR)
|
||||
+ report(stdout, "IMAP> \n");
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/* all tokens in responses are caseblind */
|
||||
for (cp = buf; *cp; cp++)
|
||||
if (islower((unsigned char)*cp))
|
||||
@@ -394,6 +415,69 @@ static int do_imap_ntlm(int sock, struct
|
||||
}
|
||||
#endif /* NTLM */
|
||||
|
||||
+static int do_imap_oauthbearer(int sock, struct query *ctl,flag xoauth2)
|
||||
+{
|
||||
+ /* Implements relevant parts of RFC-7628, RFC-6750, and
|
||||
+ * https://developers.google.com/gmail/imap/xoauth2-protocol
|
||||
+ *
|
||||
+ * This assumes something external manages obtaining an up-to-date
|
||||
+ * authentication/bearer token and arranging for it to be in
|
||||
+ * ctl->password. This may involve renewing it ahead of time if
|
||||
+ * necessary using a renewal token that fetchmail knows nothing about.
|
||||
+ * See:
|
||||
+ * https://github.com/google/gmail-oauth2-tools/wiki/OAuth2DotPyRunThrough
|
||||
+ */
|
||||
+ const char *name;
|
||||
+ char *oauth2str;
|
||||
+ int oauth2len;
|
||||
+ int saved_suppress_tags = suppress_tags;
|
||||
+
|
||||
+ char *oauth2b64;
|
||||
+
|
||||
+ int ok;
|
||||
+
|
||||
+ oauth2len = strlen(ctl->remotename) + strlen(ctl->password) + 32;
|
||||
+ oauth2str = (char *)xmalloc(oauth2len);
|
||||
+ if (xoauth2)
|
||||
+ {
|
||||
+ snprintf(oauth2str, oauth2len,
|
||||
+ "user=%s\1auth=Bearer %s\1\1",
|
||||
+ ctl->remotename,
|
||||
+ ctl->password);
|
||||
+ name = "XOAUTH2";
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ snprintf(oauth2str, oauth2len,
|
||||
+ "n,a=%s,\1auth=Bearer %s\1\1",
|
||||
+ ctl->remotename,
|
||||
+ ctl->password);
|
||||
+ name = "OAUTHBEARER";
|
||||
+ }
|
||||
+
|
||||
+ oauth2b64 = (char *)xmalloc(2*strlen(oauth2str)+8);
|
||||
+ to64frombits(oauth2b64, oauth2str, strlen(oauth2str));
|
||||
+
|
||||
+ memset(oauth2str, 0x55, strlen(oauth2str));
|
||||
+ free(oauth2str);
|
||||
+
|
||||
+ /* Protect the access token like a password in logs, despite the
|
||||
+ * usually-short expiration time and base64 encoding:
|
||||
+ */
|
||||
+ strlcpy(shroud, oauth2b64, sizeof(shroud));
|
||||
+
|
||||
+ plus_cont_context = IPLUS_OAUTHBEARER;
|
||||
+ ok = gen_transact(sock, "AUTHENTICATE %s %s", name, oauth2b64);
|
||||
+ plus_cont_context = IPLUS_NONE;
|
||||
+
|
||||
+ memset(shroud, 0x55, sizeof(shroud));
|
||||
+ shroud[0] = '\0';
|
||||
+ memset(oauth2b64, 0x55, strlen(oauth2b64));
|
||||
+ free(oauth2b64);
|
||||
+
|
||||
+ return ok;
|
||||
+}
|
||||
+
|
||||
static void imap_canonicalize(char *result, char *raw, size_t maxlen)
|
||||
/* encode an IMAP password as per RFC1730's quoting conventions */
|
||||
{
|
||||
@@ -584,6 +668,26 @@ static int imap_getauth(int sock, struct
|
||||
for future maintenance */
|
||||
(void)ok;
|
||||
|
||||
+ if (ctl->server.authenticate == A_OAUTHBEARER)
|
||||
+ {
|
||||
+ /* Fetchmail's oauthbearer and xoauth2 support expects the "password"
|
||||
+ * to actually be an oauth2 authentication token, so only
|
||||
+ * try these options if specifically enabled.
|
||||
+ * (Generating a token using the complex https-based oauth2
|
||||
+ * protocol is left as an exercise for the user.)
|
||||
+ */
|
||||
+ if (strstr(capabilities, "AUTH=OAUTHBEARER") ||
|
||||
+ !strstr(capabilities, "AUTH=XOAUTH2"))
|
||||
+ {
|
||||
+ ok = do_imap_oauthbearer(sock, ctl, FALSE); /* OAUTHBEARER */
|
||||
+ }
|
||||
+ if (ok && strstr(capabilities, "AUTH=XOAUTH2"))
|
||||
+ {
|
||||
+ ok = do_imap_oauthbearer(sock, ctl, TRUE); /* XOAUTH2 */
|
||||
+ }
|
||||
+ return ok;
|
||||
+ }
|
||||
+
|
||||
/* Yahoo hack - we'll just try ID if it was offered by the server,
|
||||
* and IGNORE errors. */
|
||||
{
|
||||
Index: fetchmail-6.5.1/options.c
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/options.c
|
||||
+++ fetchmail-6.5.1/options.c
|
||||
@@ -395,6 +395,8 @@ int parsecmdline (int argc /** argument
|
||||
ctl->server.authenticate = A_ANY;
|
||||
else if (strcmp(optarg, "msn") == 0)
|
||||
ctl->server.authenticate = A_MSN;
|
||||
+ else if (strcmp(optarg, "oauthbearer") == 0)
|
||||
+ ctl->server.authenticate = A_OAUTHBEARER;
|
||||
else {
|
||||
fprintf(stderr,GT_("Invalid authentication `%s' specified.\n"), optarg);
|
||||
errflag++;
|
||||
Index: fetchmail-6.5.1/rcfile_l.l
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/rcfile_l.l
|
||||
+++ fetchmail-6.5.1/rcfile_l.l
|
||||
@@ -103,6 +103,7 @@ cram(-md5)? { SETSTATE(0); yylval.proto
|
||||
msn { SETSTATE(0); yylval.proto = A_MSN; return AUTHTYPE;}
|
||||
ntlm { SETSTATE(0); yylval.proto = A_NTLM; return AUTHTYPE;}
|
||||
<AUTH>password { SETSTATE(0); yylval.proto = A_PASSWORD; return AUTHTYPE;}
|
||||
+oauthbearer { SETSTATE(0); yylval.proto = A_OAUTHBEARER; return AUTHTYPE;}
|
||||
timeout { return TIMEOUT;}
|
||||
idletimeout { return IDLETIMEOUT;}
|
||||
envelope { return ENVELOPE; }
|
314
fetchmail-add-passwordfile-and-passwordfd-options.patch
Normal file
314
fetchmail-add-passwordfile-and-passwordfd-options.patch
Normal file
@ -0,0 +1,314 @@
|
||||
From: Matthew Ogilvie <mmogilvi+fml@zoho.com>
|
||||
Date: Sun, 28 May 2017 00:01:02 -0600
|
||||
Subject: add passwordfile and passwordfd options
|
||||
Git-repo: https://gitlab.com/fetchmail/fetchmail.git
|
||||
Git-commit: cdd7182f65734c97723ba5f282040e08d830e650
|
||||
|
||||
---
|
||||
fetchmail.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
|
||||
fetchmail.h | 2 +
|
||||
fetchmail.man | 40 +++++++++++++++++++++++++++-
|
||||
options.c | 16 +++++++++++
|
||||
rcfile_l.l | 2 +
|
||||
rcfile_y.y | 6 ++++
|
||||
6 files changed, 145 insertions(+), 3 deletions(-)
|
||||
|
||||
Index: fetchmail-6.5.1/fetchmail.c
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/fetchmail.c
|
||||
+++ fetchmail-6.5.1/fetchmail.c
|
||||
@@ -471,7 +471,7 @@ int main(int argc, char **argv)
|
||||
/* Server won't care what the password is, but there
|
||||
must be some non-null string here. */
|
||||
ctl->password = ctl->remotename;
|
||||
- else
|
||||
+ else if (!ctl->passwordfile && ctl->passwordfd==-1)
|
||||
{
|
||||
const netrc_entry *p;
|
||||
|
||||
@@ -649,8 +649,81 @@ int main(int argc, char **argv)
|
||||
if (ctl->active && !(implicitmode && ctl->server.skip)
|
||||
&& !NO_PASSWORD(ctl) && !ctl->password)
|
||||
{
|
||||
- if (!isatty(0))
|
||||
+ if (ctl->passwordfd != -1)
|
||||
{
|
||||
+ char msg[PASSWORDLEN+1];
|
||||
+ char *mi;
|
||||
+
|
||||
+ /* Read one character at a time to avoid reading too
|
||||
+ * much if more than one password sent in through this FD
|
||||
+ * (although that would be a questionable practice).
|
||||
+ */
|
||||
+ for (mi = msg; mi<msg+sizeof(msg)-1; ++mi) {
|
||||
+ int res = read(ctl->passwordfd, mi, 1);
|
||||
+ if(res == -1) {
|
||||
+ int saveErrno = errno;
|
||||
+ fprintf(stderr,
|
||||
+ GT_("fetchmail: unable to read password from fd=%d: %s\n"),
|
||||
+ ctl->passwordfd,
|
||||
+ strerror(saveErrno));
|
||||
+ memset(msg, 0x55, mi-msg);
|
||||
+ return PS_AUTHFAIL;
|
||||
+ }
|
||||
+ if (res == 0 || *mi == '\n')
|
||||
+ break;
|
||||
+ }
|
||||
+ *mi = '\0';
|
||||
+ if (mi == msg) {
|
||||
+ fprintf(stderr,
|
||||
+ GT_("fetchmail: empty password read from fd=%d\n"),
|
||||
+ ctl->passwordfd);
|
||||
+ return PS_AUTHFAIL;
|
||||
+ }
|
||||
+
|
||||
+ ctl->password = xstrdup(msg);
|
||||
+ memset(msg, 0x55, mi-msg);
|
||||
+ } else if (ctl->passwordfile) {
|
||||
+ int fd = open(ctl->passwordfile, O_RDONLY);
|
||||
+ char msg[PASSWORDLEN+1];
|
||||
+ char *newline;
|
||||
+ int res;
|
||||
+
|
||||
+ if (fd == -1) {
|
||||
+ int saveErrno = errno;
|
||||
+ fprintf(stderr,
|
||||
+ GT_("fetchmail: unable to open %s: %s\n"),
|
||||
+ ctl->passwordfile,
|
||||
+ strerror(saveErrno));
|
||||
+ return PS_AUTHFAIL;
|
||||
+ }
|
||||
+
|
||||
+ res = read(fd, msg, sizeof(msg)-1);
|
||||
+ if (res == -1 || close(fd) == -1) {
|
||||
+ int saveErrno = errno;
|
||||
+ fprintf(stderr,
|
||||
+ GT_("fetchmail: error reading %s: %s\n"),
|
||||
+ ctl->passwordfile,
|
||||
+ strerror(saveErrno));
|
||||
+ return PS_AUTHFAIL;
|
||||
+ }
|
||||
+ msg[res] = '\0';
|
||||
+
|
||||
+ newline = memchr(msg, '\n', res);
|
||||
+ if (newline != NULL) {
|
||||
+ *newline = '\0';
|
||||
+ }
|
||||
+
|
||||
+ if (strlen(msg) == 0) {
|
||||
+ fprintf(stderr,
|
||||
+ GT_("fetchmail: empty password read from %s\n"),
|
||||
+ ctl->passwordfile);
|
||||
+ memset(msg, 0x55, res);
|
||||
+ return PS_AUTHFAIL;
|
||||
+ }
|
||||
+
|
||||
+ ctl->password = xstrdup(msg);
|
||||
+ memset(msg, 0x55, res);
|
||||
+ } else if (!isatty(0)) {
|
||||
fprintf(stderr,
|
||||
GT_("fetchmail: can't find a password for %s@%s.\n"),
|
||||
ctl->remotename, ctl->server.pollname);
|
||||
@@ -1046,6 +1119,10 @@ static void optmerge(struct query *h2, s
|
||||
FLAG_MERGE(wildcard);
|
||||
STRING_MERGE(remotename);
|
||||
STRING_MERGE(password);
|
||||
+ FLAG_MERGE(passwordfile);
|
||||
+ if (force ? h1->passwordfd!=-1 : h2->passwordfd==-1) {
|
||||
+ h2->passwordfd = h1->passwordfd;
|
||||
+ }
|
||||
STRING_MERGE(mda);
|
||||
STRING_MERGE(bsmtp);
|
||||
FLAG_MERGE(listener);
|
||||
@@ -1112,6 +1189,7 @@ static int load_params(int argc, char **
|
||||
def_opts.smtp_socket = -1;
|
||||
def_opts.smtpaddress = (char *)0;
|
||||
def_opts.smtpname = (char *)0;
|
||||
+ def_opts.passwordfd = -1;
|
||||
def_opts.server.protocol = P_AUTO;
|
||||
def_opts.server.timeout = CLIENT_TIMEOUT;
|
||||
def_opts.server.idle_timeout = CLIENT_IDLE_TIMEOUT;
|
||||
Index: fetchmail-6.5.1/fetchmail.h
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/fetchmail.h
|
||||
+++ fetchmail-6.5.1/fetchmail.h
|
||||
@@ -312,6 +312,8 @@ struct query
|
||||
int wildcard; /* should unmatched names be passed through */
|
||||
char *remotename; /* remote login name to use */
|
||||
char *password; /* remote password to use */
|
||||
+ char *passwordfile; /* filename; first line contains password */
|
||||
+ int passwordfd; /* fileno that password will be piped into */
|
||||
struct idlist *mailboxes; /* list of mailboxes to check */
|
||||
|
||||
/* per-forwarding-target data */
|
||||
Index: fetchmail-6.5.1/fetchmail.man
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/fetchmail.man
|
||||
+++ fetchmail-6.5.1/fetchmail.man
|
||||
@@ -1056,6 +1056,37 @@ The default is your login name on the cl
|
||||
\fBfetchmail\fP.
|
||||
See USER AUTHENTICATION below for a complete description.
|
||||
.TP
|
||||
+.B \-\-passwordfile <filename>
|
||||
+(Keyword: passwordfile)
|
||||
+.br
|
||||
+Specifies a file name from which to read the first line to use as the password.
|
||||
+Useful if something changes the password/token often without regenerating a
|
||||
+long fetchmailrc file, such as with typical xoauth2 authentication tokens.
|
||||
+Protect the file with appropriate permissions to avoid leaking your password.
|
||||
+Fetchmail might not re-read the file in daemon mode (-d) unless the
|
||||
+fetchmailrc file also changes, so it might make sense to run it in
|
||||
+non-daemon mode from some other background process (cron and/or whatever
|
||||
+updates the password).
|
||||
+.TP
|
||||
+.B \-\-passwordfd <integer>
|
||||
+(Keyword: passwordfd)
|
||||
+.br
|
||||
+Specifies a file descriptor number inherited from the calling process,
|
||||
+from which fetchmail should read one line to use as the password.
|
||||
+The descriptor will usually be the receiving end of a pipe (equivalent
|
||||
+to "something | fetchmail \-\-passwordfd 5 5<\&0"),
|
||||
+although it could also be a redirected input file
|
||||
+(equivalent to "fetchmail \-\-passwordfd 5 5</path/to/file").
|
||||
+Useful if something wants to manage password ownership more securely
|
||||
+than files, or if the password/token changes often,
|
||||
+such as with typical xoauth2 authentication tokens. Normal interactive
|
||||
+mode passwords requires that standard input is a terminal and disables
|
||||
+echo, but passwordfd does not care. Do not do something
|
||||
+like "echo 'password' | fetchmail ...", since echo's arguments are
|
||||
+likely to (briefly) be publicly visible in process listings.
|
||||
+This probably doesn't interact well with deamon mode: when will it
|
||||
+re-read a new password?
|
||||
+.TP
|
||||
.B \-I <specification> | \-\-interface <specification>
|
||||
(Keyword: interface)
|
||||
.br
|
||||
@@ -1148,7 +1179,8 @@ setting also allows the non-standard "xo
|
||||
the same token) if the server only claims to support "xoauth2".
|
||||
External tools are necessary to obtain
|
||||
such tokens. Access tokens often expire fairly quickly (e.g. 1 hour),
|
||||
-and new ones need to be generated from renewal tokens. See the
|
||||
+and new ones need to be generated from renewal tokens, so the
|
||||
+"passwordfile", "passwordfd", or "pwmd_*" options may be useful. See the
|
||||
oauth2.py script from
|
||||
.URL https://github.com/google/gmail-oauth2-tools/wiki/OAuth2DotPyRunThrough "Google's Oauth2 Run Through" ,
|
||||
and other oauth2 documentation. For services like gmail, an "App Password"
|
||||
@@ -2100,6 +2132,12 @@ T}
|
||||
pass[word] \& \& T{
|
||||
Specify remote account password
|
||||
T}
|
||||
+passwordfile \-\-... \& T{
|
||||
+File name with password in first line.
|
||||
+T}
|
||||
+passwordfd \-\-... \& T{
|
||||
+Inherited file descriptor from which to read one line for the password.
|
||||
+T}
|
||||
ssl \& \& T{
|
||||
Connect to server over the specified base protocol using SSL encryption
|
||||
T}
|
||||
Index: fetchmail-6.5.1/options.c
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/options.c
|
||||
+++ fetchmail-6.5.1/options.c
|
||||
@@ -29,6 +29,8 @@ enum {
|
||||
LA_POSTMASTER,
|
||||
LA_NOBOUNCE,
|
||||
LA_AUTH,
|
||||
+ LA_PASSWORDFILE,
|
||||
+ LA_PASSWORDFD,
|
||||
LA_FETCHDOMAINS,
|
||||
LA_BSMTP,
|
||||
LA_LMTP,
|
||||
@@ -98,6 +100,8 @@ static const struct option longoptions[]
|
||||
{"port", required_argument, (int *) 0, 'P' },
|
||||
{"service", required_argument, (int *) 0, 'P' },
|
||||
{"auth", required_argument, (int *) 0, LA_AUTH},
|
||||
+ {"passwordfile", required_argument, (int *) 0, LA_PASSWORDFILE },
|
||||
+ {"passwordfd", required_argument, (int *) 0, LA_PASSWORDFD },
|
||||
{"timeout", required_argument, (int *) 0, 't' },
|
||||
{"envelope", required_argument, (int *) 0, 'E' },
|
||||
{"qvirtual", required_argument, (int *) 0, 'Q' },
|
||||
@@ -231,6 +235,7 @@ int parsecmdline (int argc /** argument
|
||||
|
||||
memset(ctl, '\0', sizeof(struct query)); /* start clean */
|
||||
ctl->smtp_socket = -1;
|
||||
+ ctl->passwordfd = -1;
|
||||
|
||||
while (!errflag &&
|
||||
(c = getopt_long(argc,argv,shortoptions,
|
||||
@@ -402,6 +407,17 @@ int parsecmdline (int argc /** argument
|
||||
errflag++;
|
||||
}
|
||||
break;
|
||||
+ case LA_PASSWORDFILE:
|
||||
+ ctl->passwordfile = optarg;
|
||||
+ break;
|
||||
+ case LA_PASSWORDFD:
|
||||
+ ctl->passwordfd = xatoi(optarg, &errflag);
|
||||
+ if (ctl->passwordfd < 0) {
|
||||
+ fprintf(stderr,GT_("Invalid file descriptor %d\n"),
|
||||
+ ctl->passwordfd);
|
||||
+ errflag++;
|
||||
+ }
|
||||
+ break;
|
||||
case 't':
|
||||
ctl->server.timeout = xatoi(optarg, &errflag);
|
||||
if (ctl->server.timeout == 0)
|
||||
Index: fetchmail-6.5.1/rcfile_l.l
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/rcfile_l.l
|
||||
+++ fetchmail-6.5.1/rcfile_l.l
|
||||
@@ -116,6 +116,8 @@ accept { return ACCEPT; }
|
||||
reject { return REJECT_; }
|
||||
|
||||
user(name)? {SETSTATE(NAME); return USERNAME; }
|
||||
+passwordfile { return PASSWORDFILE; }
|
||||
+passwordfd { return PASSWORDFD; }
|
||||
<INITIAL,NAME>pass(word)? {SETSTATE(NAME); return PASSWORD; }
|
||||
folder(s)? { return FOLDER; }
|
||||
smtp(host)? { return SMTPHOST; }
|
||||
Index: fetchmail-6.5.1/rcfile_y.y
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/rcfile_y.y
|
||||
+++ fetchmail-6.5.1/rcfile_y.y
|
||||
@@ -62,6 +62,7 @@ void yyerror (const char *s)
|
||||
%token DEFAULTS POLL SKIP VIA AKA LOCALDOMAINS PROTOCOL
|
||||
%token AUTHENTICATE TIMEOUT IDLETIMEOUT KPOP SDPS ENVELOPE QVIRTUAL
|
||||
%token USERNAME PASSWORD FOLDER SMTPHOST FETCHDOMAINS MDA BSMTP LMTP
|
||||
+%token PASSWORDFILE PASSWORDFD
|
||||
%token SMTPADDRESS SMTPNAME SPAMRESPONSE PRECONNECT POSTCONNECT LIMIT WARNINGS
|
||||
%token INTERFACE MONITOR PLUGIN PLUGOUT
|
||||
%token IS HERE THERE TO MAP
|
||||
@@ -314,6 +315,8 @@ user_option : TO mapping_list HERE
|
||||
|
||||
| IS STRING THERE {current.remotename = $2;}
|
||||
| PASSWORD STRING {current.password = $2;}
|
||||
+ | PASSWORDFILE STRING {current.passwordfile = $2;}
|
||||
+ | PASSWORDFD NUMBER {current.passwordfd = NUM_VALUE_IN($2);}
|
||||
| FOLDER folder_list
|
||||
| SMTPHOST smtp_list
|
||||
| FETCHDOMAINS fetch_list
|
||||
@@ -495,6 +498,7 @@ static void reset_server(const char *nam
|
||||
trailer = FALSE;
|
||||
memset(¤t,'\0',sizeof(current));
|
||||
current.smtp_socket = -1;
|
||||
+ current.passwordfd = -1;
|
||||
current.server.pollname = xstrdup(name);
|
||||
current.server.skip = skip;
|
||||
}
|
||||
@@ -515,6 +519,7 @@ static void user_reset(void)
|
||||
|
||||
memset(¤t, '\0', sizeof(current));
|
||||
current.smtp_socket = -1;
|
||||
+ current.passwordfd = -1;
|
||||
|
||||
current.server = save;
|
||||
}
|
||||
@@ -535,6 +540,7 @@ struct query *hostalloc(struct query *in
|
||||
{
|
||||
memset(node, '\0', sizeof(struct query));
|
||||
node->smtp_socket = -1;
|
||||
+ node->passwordfd = -1;
|
||||
}
|
||||
|
||||
/* append to end of list */
|
41
fetchmail-add-query_to64_outsize-utility-function.patch
Normal file
41
fetchmail-add-query_to64_outsize-utility-function.patch
Normal file
@ -0,0 +1,41 @@
|
||||
From: Matthew Ogilvie <mmogilvi+fml@zoho.com>
|
||||
Date: Fri, 21 Dec 2018 09:00:46 -0700
|
||||
Subject: add query_to64_outsize() utility function
|
||||
Git-repo: https://gitlab.com/fetchmail/fetchmail.git
|
||||
Git-commit: cc6e146d516140df800da68976eb7c0aa1cef7c0
|
||||
|
||||
---
|
||||
base64.c | 7 +++++++
|
||||
fetchmail.h | 1 +
|
||||
2 files changed, 8 insertions(+)
|
||||
|
||||
Index: fetchmail-6.5.1/base64.c
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/base64.c
|
||||
+++ fetchmail-6.5.1/base64.c
|
||||
@@ -66,6 +66,13 @@ fail:
|
||||
return rc;
|
||||
}
|
||||
|
||||
+size_t query_to64_outsize(size_t inlen)
|
||||
+/* Returns how much space needs to be allocated to receive the output from
|
||||
+ * to64frombits(), including the '\0' terminator. */
|
||||
+{
|
||||
+ return ((inlen+2)/3)*4+1;
|
||||
+}
|
||||
+
|
||||
int from64tobits(void *out_, const char *in, int maxlen)
|
||||
/* base 64 to raw bytes in quasi-big-endian order, returning count of bytes */
|
||||
/* maxlen limits output buffer size, set to zero to ignore */
|
||||
Index: fetchmail-6.5.1/fetchmail.h
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/fetchmail.h
|
||||
+++ fetchmail-6.5.1/fetchmail.h
|
||||
@@ -611,6 +611,7 @@ int prc_filecheck(const char *, const fl
|
||||
/* base64.c */
|
||||
unsigned len64frombits(unsigned inlen); /** calculate length needed to encode inlen octets. warnings: 1. caller needs to add 1 for a trailing \0 byte himself. 2. returns 0 for inlen 0! */
|
||||
int to64frombits(char *, const void *, int inlen, size_t outlen);
|
||||
+size_t query_to64_outsize(size_t inlen);
|
||||
int from64tobits(void *, const char *, int mxoutlen);
|
||||
|
||||
/* unmime.c */
|
160
fetchmail-add-readme-oauth2-issue-27.patch
Normal file
160
fetchmail-add-readme-oauth2-issue-27.patch
Normal file
@ -0,0 +1,160 @@
|
||||
From: William Bader <william@newspapersystems.com>
|
||||
Date: Sun, 31 Jan 2021 06:42:46 +0000
|
||||
Subject: Add README.OAUTH2 issue #27
|
||||
Git-repo: https://gitlab.com/fetchmail/fetchmail.git
|
||||
Git-commit: d52ba9652c9207358e0b9acc11403688f6f16b9e
|
||||
|
||||
---
|
||||
README.OAUTH2 | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 147 insertions(+)
|
||||
|
||||
--- /dev/null
|
||||
+++ b/README.OAUTH2
|
||||
@@ -0,0 +1,147 @@
|
||||
+OAUTH2 support for gmail
|
||||
+========================
|
||||
+
|
||||
+Preface
|
||||
+-------
|
||||
+
|
||||
+fetchmail 7 adds support for OAuth2.
|
||||
+You create a project in google that requests gmail access to request an OAuth2 client id and client secret.
|
||||
+Then you use the contributed fetchmail-oauth2.py to request a refresh token for gmail access to your gmail account.
|
||||
+Then you use the fetchmail-oauth2.py again to request temporary access tokens that fetchmail uses like a password.
|
||||
+
|
||||
+Create a Google project and request an OAuth2 client id and client secret
|
||||
+-------------------------------------------------------------------------
|
||||
+
|
||||
+* Open the Google API Dashboard: https://console.developers.google.com/apis/dashboard
|
||||
+* The first time that you enter the page, you will have to select your country and agree to terms of service.
|
||||
+* You should see a title bar with "Google APIs" and a menu down the left with "Dashboard, Library,
|
||||
+ Credentials, OAuth consent screen, Domain verification, Page usage agreements".
|
||||
+* Click to create a new project, possibly on a pull-down arrow to the right of "Google APIs" on the title bar.
|
||||
+* Click on "NEW PROJECT".
|
||||
+ + Enter a project name like "fetchmail".
|
||||
+ + You can leave "Location" as "No organization" for personal email.
|
||||
+ + If you are a G Suite administrator, you might be able to enter your G Suite organization.
|
||||
+ + When you enter the project name, you will get a message like "Project ID: fetchmail-123456. It cannot be changed later."
|
||||
+ + Make a note of the full project name.
|
||||
+ + Click on "CREATE".
|
||||
+ + Google will take a few seconds to create the project.
|
||||
+* Switch to the new project, either from "SELECT PROJECT" in the notification window or on the title bar pulldown after "Google APIs".
|
||||
+* Click on "Credentials" on the menu at the left.
|
||||
+* Click on "+ CREATE CREDENTIALS" at the top of the window.
|
||||
+* Select "OAuth client ID" from the list of credential types.
|
||||
+* Click on "CONFIGURE CONSENT SCREEN" at the right.
|
||||
+ + Select "External" from the list of user types. "Internal" is for organizations with G Suite.
|
||||
+ + Click "CREATE".
|
||||
+* Fill out the app registration form.
|
||||
+ + "App name" can be the full project name, like "fetchmail-123456". It has to be unique.
|
||||
+ + "User support email" can be your gmail email.
|
||||
+ + "App logo" can be empty. I used /usr/share/icons/Adwaita/256x256/legacy/emblem-mail.png
|
||||
+ + "Application home page" can be empty.
|
||||
+ + "Application privacy policy link" can be empty.
|
||||
+ + "Application terms of service link" can be empty.
|
||||
+ + "Authorized domain" can be empty.
|
||||
+ + "Developer contact email address" can be your gmail email.
|
||||
+ + Click "SAVE AND CONTINUE".
|
||||
+ + Click "ADD OR REMOVE SCOPES" on the "Edit app registration" screen.
|
||||
+ + Click on "Google API Library". This opens a new tab.
|
||||
+ + Filter for "Email" and click on "Gmail API".
|
||||
+ + Click on "ENABLE".
|
||||
+ + Return to the "Edit app registration" tab and refresh.
|
||||
+ + Click "ADD OR REMOVE SCOPES" on the "Edit app registration" screen.
|
||||
+ + I think that the scope ".../auth/gmail.modify" to "View and modify but not delete your email" is sufficient.
|
||||
+ + Click on "SAVE AND CONTINUE". This opens the "Test Users" window.
|
||||
+ + Click on "+ ADD USERS".
|
||||
+ + Enter you gmail address and click on "ADD".
|
||||
+ + Click on "SAVE AND CONTINUE".
|
||||
+ + This opens a "Summary" page.
|
||||
+ + If you need to change something, click on "OAuth consent screen" on the menu at the left and then "EDIT APP" to step through the screens again.
|
||||
+* Click on "Credentials" on the menu at the left to create client credentials.
|
||||
+ + Click on "+ CREATE CREDENTIALS" at the top of the window.
|
||||
+ + Select "OAuth client ID" from the list of credential types.
|
||||
+ + Select "Desktop app" from the list of "Application types".
|
||||
+ + "Name" can be "DesktopClient1" or whatever the screen suggests.
|
||||
+ + Click on "CREATE".
|
||||
+ + It will show a window with "Your Client ID" and "Your Client Secret". Copy them somewhere safe.
|
||||
+
|
||||
+Download and build fetchmail 7
|
||||
+------------------------------
|
||||
+```
|
||||
+git clone https://gitlab.com/fetchmail/fetchmail.git
|
||||
+cd fetchmail
|
||||
+git checkout -t origin/next
|
||||
+./autogen.sh
|
||||
+./configure
|
||||
+make
|
||||
+make check
|
||||
+sudo make install
|
||||
+```
|
||||
+
|
||||
+Configure fetchmail-oauth2.py
|
||||
+-----------------------------
|
||||
+* Create a file, for example /home/yourname/.fetchmail-oauth2
|
||||
+```
|
||||
+client_id=YOUR-CLIENT-ID
|
||||
+client_secret=YOUR-CLIENT-SECRET
|
||||
+refresh_token_file=/home/yourname/.fetchmail-refresh
|
||||
+access_token_file=/home/yourname/.fetchmail-token
|
||||
+max_age_sec=3000
|
||||
+```
|
||||
+* Replace YOUR-CLIENT-ID and YOUR-CLIENT-SECRET with the keys for "Your Client ID" and "Your Client Secret" from the previous step.
|
||||
+* The refresh and token files do not need to exist, but they have to be valid paths.
|
||||
+* Run `contrib/fetchmail-oauth2.py -c /home/yourname/.fetchmail-oauth2 --obtain_refresh_token_file`
|
||||
+ + The script will give you a URL.
|
||||
+ + Paste the URL into a web browser.
|
||||
+ + URL should open a google authentication page.
|
||||
+ + Select the email account.
|
||||
+ + Google will warn that the app isn't verified. Click on "Continue".
|
||||
+ + Google will warn that "fetchmail-123456 wants to access your Google Account `your.name@gmail.com`".
|
||||
+ + Click on "Allow".
|
||||
+ + The page will display the sign in key.
|
||||
+ + Paste the key into the script.
|
||||
+ + The script will report:
|
||||
+```
|
||||
+Refresh token saved to '/home/yourname/.fetchmail-refresh'
|
||||
+Initial access token saved to '/home/yourname/.fetchmail-token'
|
||||
+Access Token Expiration Seconds: 3599
|
||||
+```
|
||||
+ + Hopefully you will not need to do this again for months or years.
|
||||
+* Run `chmod 0600` on all of the files .fetchmail-oauth2 .fetchmail-refresh .fetchmail-token
|
||||
+
|
||||
+Configure fetchmail
|
||||
+---------------------
|
||||
+* Create an entry in your `.fetchmailrc`
|
||||
+```
|
||||
+poll imap.gmail.com protocol imap
|
||||
+ auth oauthbearer username "your.name@gmail.com"
|
||||
+ passwordfile "/home/yourname/.fetchmail-token"
|
||||
+ is yourname here
|
||||
+ fetchlimit 10 folder "Download"
|
||||
+ keep
|
||||
+ sslmode wrapped sslcertck
|
||||
+```
|
||||
+* Run `chmod 0400` on your `.fetchmailrc`
|
||||
+* The optional "fetchlimit #" limits the number of emails if you are testing.
|
||||
+* The optional "folder name" sets the folder to check.
|
||||
+* I made gmail filters that add a "Download" label to important emails.
|
||||
+* Fetchmail downloads unread emails. You can go into gmail and mark a few emails unread for testing.
|
||||
+* Try running fetchmail once at a command line.
|
||||
+
|
||||
+Script fetchmail
|
||||
+----------------
|
||||
+* Each access token expires after an hour.
|
||||
+* If you run fetchmail from cron, you should run `fetchmail-oauth2.py -c /home/yourname/.fetchmail-oauth2 --auto_refresh ; fetchmail`
|
||||
+* For example, `*/2 * * * * (fetchmail-oauth2.py -c /home/yourname/.fetchmail-oauth2 --auto_refresh ; fetchmail) > /home/yourname/fetchmail.log 2>&1`
|
||||
+* The `--auto_refresh` option checks the age of the key against the `max_age_sec` and renews it if necessary.
|
||||
+* `max_age_sec=3000` in `.fetchmail-oauth2` renews the key after 50 minutes, which should give a safe margin.
|
||||
+
|
||||
+Further reading
|
||||
+---------------
|
||||
+* Instructions by the author of OAuth2 support for Fetchmail and Postfix
|
||||
+ + Setting Up OAUTH2 Support for Fetchmail and Postfix http://mmogilvi.users.sourceforge.net/software/oauthbearer.html
|
||||
+ + Run `fetchmail-oauth2.py --help | less`
|
||||
+* Documents from Google
|
||||
+ + Using OAuth 2.0 to Access Google APIs https://developers.google.com/identity/protocols/oauth2
|
||||
+ + Integrating Google Sign-In into your web app https://developers.google.com/identity/sign-in/web/devconsole-project
|
||||
+* Google links
|
||||
+ + Google API Dashboard: https://console.developers.google.com/apis/dashboard
|
||||
+ + Google Cloud Resource Manager: https://console.developers.google.com/cloud-resource-manager
|
23
fetchmail-bump-max-passwordlen-to-1bytes.patch
Normal file
23
fetchmail-bump-max-passwordlen-to-1bytes.patch
Normal file
@ -0,0 +1,23 @@
|
||||
From: Matthias Andree <matthias.andree@gmx.de>
|
||||
Date: Sat, 24 Apr 2021 15:12:01 +0200
|
||||
Subject: Bump max. passwordlen to 10000 bytes.
|
||||
Git-repo: https://gitlab.com/fetchmail/fetchmail.git
|
||||
Git-commit: 919fd787540c4a3fa4694566edce406df1e42001
|
||||
|
||||
---
|
||||
fetchmail.h | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
Index: fetchmail-6.5.1/fetchmail.h
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/fetchmail.h
|
||||
+++ fetchmail-6.5.1/fetchmail.h
|
||||
@@ -101,7 +101,7 @@ struct addrinfo;
|
||||
|
||||
#define NAMELEN 64 /* max username length */
|
||||
/* oauth2 access tokens seem to be about 130 characters; make this longer: */
|
||||
-#define PASSWORDLEN 4096 /* max password length; oauth2 tokens have no maximum length */
|
||||
+#define PASSWORDLEN 10000 /* max password length; oauth2 tokens have no maximum length */
|
||||
#define DIGESTLEN 33 /* length of MD5 digest */
|
||||
|
||||
/* exit code values */
|
29
fetchmail-chase-and-integrate-interface-change.patch
Normal file
29
fetchmail-chase-and-integrate-interface-change.patch
Normal file
@ -0,0 +1,29 @@
|
||||
From: Matthias Andree <matthias.andree@gmx.de>
|
||||
Date: Sun, 25 Nov 2018 12:09:07 +0100
|
||||
Subject: Chase and integrate interface change.
|
||||
Git-repo: https://gitlab.com/fetchmail/fetchmail.git
|
||||
Git-commit: d52b7b6859d46134b46e6de9b408739b18745d47
|
||||
|
||||
---
|
||||
oauth2.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/oauth2.c
|
||||
+++ b/oauth2.c
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "oauth2.h"
|
||||
|
||||
#include <stdio.h>
|
||||
+#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
char *get_oauth2_string(struct query *ctl,flag xoauth2)
|
||||
@@ -52,7 +53,7 @@ char *get_oauth2_string(struct query *ct
|
||||
}
|
||||
|
||||
oauth2b64 = (char *)xmalloc(2*strlen(oauth2str)+8);
|
||||
- to64frombits(oauth2b64, oauth2str, strlen(oauth2str));
|
||||
+ to64frombits(oauth2b64, oauth2str, strlen(oauth2str), oauth2len);
|
||||
|
||||
memset(oauth2str, 0x55, strlen(oauth2str));
|
||||
free(oauth2str);
|
45
fetchmail-give-each-ctl-it-s-own-copy-of-password.patch
Normal file
45
fetchmail-give-each-ctl-it-s-own-copy-of-password.patch
Normal file
@ -0,0 +1,45 @@
|
||||
From: Matthew Ogilvie <mmogilvi+fml@zoho.com>
|
||||
Date: Fri, 9 Jun 2017 19:31:17 -0600
|
||||
Subject: give each ctl it's own copy of password
|
||||
Git-repo: https://gitlab.com/fetchmail/fetchmail.git
|
||||
Git-commit: 469b0a212e7f047ab16ef46a9158df5fb373e8c2
|
||||
|
||||
pwdb_* and passwordfile options may free and re-allocate password
|
||||
for each poll operation. Giving each context it's own copy of
|
||||
the password should prevent accessing freed memory in another copy.
|
||||
|
||||
I haven't tested pwmd, but these seem like obvious fixes.
|
||||
---
|
||||
fetchmail.c | 12 ++++++++++--
|
||||
1 file changed, 10 insertions(+), 2 deletions(-)
|
||||
|
||||
Index: fetchmail-6.5.1/fetchmail.c
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/fetchmail.c
|
||||
+++ fetchmail-6.5.1/fetchmail.c
|
||||
@@ -470,7 +470,7 @@ int main(int argc, char **argv)
|
||||
if (NO_PASSWORD(ctl))
|
||||
/* Server won't care what the password is, but there
|
||||
must be some non-null string here. */
|
||||
- ctl->password = ctl->remotename;
|
||||
+ ctl->password = xstrdup(ctl->remotename);
|
||||
else if (!ctl->passwordfile && ctl->passwordfd==-1)
|
||||
{
|
||||
const netrc_entry *p;
|
||||
@@ -1118,7 +1118,15 @@ static void optmerge(struct query *h2, s
|
||||
|
||||
FLAG_MERGE(wildcard);
|
||||
STRING_MERGE(remotename);
|
||||
- STRING_MERGE(password);
|
||||
+ if (force ? !!h1->password : !h2->password) {
|
||||
+ if (h2->password) {
|
||||
+ memset(h2->password, 0x55, strlen(h2->password));
|
||||
+ xfree(h2->password);
|
||||
+ }
|
||||
+ if (h1->password) {
|
||||
+ h2->password = xstrdup(h1->password);
|
||||
+ }
|
||||
+ }
|
||||
FLAG_MERGE(passwordfile);
|
||||
if (force ? h1->passwordfd!=-1 : h2->passwordfd==-1) {
|
||||
h2->passwordfd = h1->passwordfd;
|
@ -0,0 +1,32 @@
|
||||
From: =?utf-8?q?Martin_Sj=C3=B6lund_=3Cmartin=40sjoelund=2Ese=3E?=
|
||||
Date: Thu, 17 Dec 2020 09:09:44 +0100
|
||||
Subject: Increase max password length to handle oauth tokens
|
||||
Git-repo: https://gitlab.com/fetchmail/fetchmail.git
|
||||
Git-commit: 6e877b5d92527ad501aaef46e37704b51db316fb
|
||||
|
||||
The maximum length of oauth2 access tokens is unbounded.
|
||||
* Google uses 2048 byte access tokens and "Google reserves the right
|
||||
to change token size within these limits, and your application
|
||||
must support variable token sizes accordingly."
|
||||
* My Office365 access token is 2108 bytes long.
|
||||
* Intuit says you must support 4096 byte access tokens.
|
||||
|
||||
This simply patches the hard-coded limit to 4096 bytes, but it might
|
||||
not be sufficient.
|
||||
---
|
||||
fetchmail.h | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
Index: fetchmail-6.5.1/fetchmail.h
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/fetchmail.h
|
||||
+++ fetchmail-6.5.1/fetchmail.h
|
||||
@@ -101,7 +101,7 @@ struct addrinfo;
|
||||
|
||||
#define NAMELEN 64 /* max username length */
|
||||
/* oauth2 access tokens seem to be about 130 characters; make this longer: */
|
||||
-#define PASSWORDLEN 256 /* max password length */
|
||||
+#define PASSWORDLEN 4096 /* max password length; oauth2 tokens have no maximum length */
|
||||
#define DIGESTLEN 33 /* length of MD5 digest */
|
||||
|
||||
/* exit code values */
|
@ -0,0 +1,35 @@
|
||||
From: Matthew Ogilvie <mmogilvi+fml@zoho.com>
|
||||
Date: Fri, 21 Dec 2018 09:01:40 -0700
|
||||
Subject: oauth2.c: calculate and pass in correct buffer size to to64frombits()
|
||||
Git-repo: https://gitlab.com/fetchmail/fetchmail.git
|
||||
Git-commit: 914ee333c73baa3c58d1e819ff4d66052e663335
|
||||
|
||||
Also allocate the actual needed size instead of an excessively large
|
||||
approximate size.
|
||||
|
||||
---
|
||||
oauth2.c | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/oauth2.c
|
||||
+++ b/oauth2.c
|
||||
@@ -34,6 +34,7 @@ char *get_oauth2_string(struct query *ct
|
||||
int oauth2len;
|
||||
|
||||
char *oauth2b64;
|
||||
+ size_t oauth2b64alloc;
|
||||
|
||||
oauth2len = strlen(ctl->remotename) + strlen(ctl->password) + 32;
|
||||
oauth2str = (char *)xmalloc(oauth2len);
|
||||
@@ -52,8 +53,9 @@ char *get_oauth2_string(struct query *ct
|
||||
ctl->password);
|
||||
}
|
||||
|
||||
- oauth2b64 = (char *)xmalloc(2*strlen(oauth2str)+8);
|
||||
- to64frombits(oauth2b64, oauth2str, strlen(oauth2str), oauth2len);
|
||||
+ oauth2b64alloc = query_to64_outsize(strlen(oauth2str));
|
||||
+ oauth2b64 = (char *)xmalloc(oauth2b64alloc);
|
||||
+ to64frombits(oauth2b64, oauth2str, strlen(oauth2str), oauth2b64alloc);
|
||||
|
||||
memset(oauth2str, 0x55, strlen(oauth2str));
|
||||
free(oauth2str);
|
172
fetchmail-re-read-passwordfile-on-every-poll.patch
Normal file
172
fetchmail-re-read-passwordfile-on-every-poll.patch
Normal file
@ -0,0 +1,172 @@
|
||||
From: Matthew Ogilvie <mmogilvi+fml@zoho.com>
|
||||
Date: Fri, 9 Jun 2017 18:20:40 -0600
|
||||
Subject: re-read passwordfile on every poll
|
||||
Git-repo: https://gitlab.com/fetchmail/fetchmail.git
|
||||
Git-commit: c2b96715bb39b9cfd1c751eae6b0111bed9c8581
|
||||
|
||||
---
|
||||
fetchmail.c | 100 ++++++++++++++++++++++++++++++++++++++--------------------
|
||||
fetchmail.man | 9 +----
|
||||
2 files changed, 69 insertions(+), 40 deletions(-)
|
||||
|
||||
Index: fetchmail-6.5.1/fetchmail.c
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/fetchmail.c
|
||||
+++ fetchmail-6.5.1/fetchmail.c
|
||||
@@ -681,48 +681,19 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
ctl->password = xstrdup(msg);
|
||||
+ ctl->passwordfile = NULL;
|
||||
memset(msg, 0x55, mi-msg);
|
||||
} else if (ctl->passwordfile) {
|
||||
- int fd = open(ctl->passwordfile, O_RDONLY);
|
||||
- char msg[PASSWORDLEN+1];
|
||||
- char *newline;
|
||||
- int res;
|
||||
-
|
||||
- if (fd == -1) {
|
||||
+ if (access(ctl->passwordfile, R_OK) != 0) {
|
||||
int saveErrno = errno;
|
||||
fprintf(stderr,
|
||||
- GT_("fetchmail: unable to open %s: %s\n"),
|
||||
+ GT_("fetchmail: unable to access %s: %s\n"),
|
||||
ctl->passwordfile,
|
||||
strerror(saveErrno));
|
||||
return PS_AUTHFAIL;
|
||||
}
|
||||
-
|
||||
- res = read(fd, msg, sizeof(msg)-1);
|
||||
- if (res == -1 || close(fd) == -1) {
|
||||
- int saveErrno = errno;
|
||||
- fprintf(stderr,
|
||||
- GT_("fetchmail: error reading %s: %s\n"),
|
||||
- ctl->passwordfile,
|
||||
- strerror(saveErrno));
|
||||
- return PS_AUTHFAIL;
|
||||
- }
|
||||
- msg[res] = '\0';
|
||||
-
|
||||
- newline = memchr(msg, '\n', res);
|
||||
- if (newline != NULL) {
|
||||
- *newline = '\0';
|
||||
- }
|
||||
-
|
||||
- if (strlen(msg) == 0) {
|
||||
- fprintf(stderr,
|
||||
- GT_("fetchmail: empty password read from %s\n"),
|
||||
- ctl->passwordfile);
|
||||
- memset(msg, 0x55, res);
|
||||
- return PS_AUTHFAIL;
|
||||
- }
|
||||
-
|
||||
- ctl->password = xstrdup(msg);
|
||||
- memset(msg, 0x55, res);
|
||||
+ ctl->password = xstrdup("dummy");
|
||||
+ /* file will be read/re-read on each poll interval below */
|
||||
} else if (!isatty(0)) {
|
||||
fprintf(stderr,
|
||||
GT_("fetchmail: can't find a password for %s@%s.\n"),
|
||||
@@ -739,6 +710,8 @@ int main(int argc, char **argv)
|
||||
ctl->password = xstrdup((char *)fm_getpassword(tmpbuf));
|
||||
free(tmpbuf);
|
||||
}
|
||||
+ } else {
|
||||
+ ctl->passwordfile = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -938,6 +911,65 @@ int main(int argc, char **argv)
|
||||
|
||||
dofastuidl = 0; /* this is reset in the driver if required */
|
||||
|
||||
+ if (ctl->passwordfile) {
|
||||
+ int fd = open(ctl->passwordfile, O_RDONLY);
|
||||
+ char msg[PASSWORDLEN+1];
|
||||
+ char *newline;
|
||||
+ int res;
|
||||
+
|
||||
+ if (fd == -1) {
|
||||
+ int saveErrno = errno;
|
||||
+ report(stderr,
|
||||
+ GT_("fetchmail: unable to open %s: %s\n"),
|
||||
+ ctl->passwordfile,
|
||||
+ strerror(saveErrno));
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ res = read(fd, msg, sizeof(msg)-1);
|
||||
+ close(fd);
|
||||
+ if (res == -1) {
|
||||
+ int saveErrno = errno;
|
||||
+ report(stderr,
|
||||
+ GT_("fetchmail: error reading %s: %s\n"),
|
||||
+ ctl->passwordfile,
|
||||
+ strerror(saveErrno));
|
||||
+ continue;
|
||||
+ }
|
||||
+ msg[res] = '\0';
|
||||
+
|
||||
+ newline = memchr(msg, '\n', res);
|
||||
+ if (newline != NULL) {
|
||||
+ *newline = '\0';
|
||||
+ }
|
||||
+
|
||||
+ if (strlen(msg) == 0) {
|
||||
+ report(stderr,
|
||||
+ GT_("fetchmail: empty password read from %s\n"),
|
||||
+ ctl->passwordfile);
|
||||
+ memset(msg, 0x55, res);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ if (ctl->password) {
|
||||
+ memset(ctl->password, 0x55, strlen(ctl->password));
|
||||
+ xfree(ctl->password);
|
||||
+ }
|
||||
+ ctl->password = xstrdup(msg);
|
||||
+ memset(msg, 0x55, res);
|
||||
+ }
|
||||
+
|
||||
+ if (!ctl->password) {
|
||||
+ /* This shouldn't be reachable (all cases caught
|
||||
+ * earlier), but keep it for safety since there
|
||||
+ * are many cases.
|
||||
+ */
|
||||
+ report(stderr,
|
||||
+ GT_("password is unexpectedly NULL querying %s\n"),
|
||||
+ ctl->server.pollname);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
querystatus = query_host(ctl);
|
||||
|
||||
if (NUM_NONZERO(ctl->fastuidl))
|
||||
Index: fetchmail-6.5.1/fetchmail.man
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/fetchmail.man
|
||||
+++ fetchmail-6.5.1/fetchmail.man
|
||||
@@ -1061,12 +1061,9 @@ See USER AUTHENTICATION below for a comp
|
||||
.br
|
||||
Specifies a file name from which to read the first line to use as the password.
|
||||
Useful if something changes the password/token often without regenerating a
|
||||
-long fetchmailrc file, such as with typical xoauth2 authentication tokens.
|
||||
+long fetchmailrc file, such as with typical oauth2 authentication tokens.
|
||||
Protect the file with appropriate permissions to avoid leaking your password.
|
||||
-Fetchmail might not re-read the file in daemon mode (-d) unless the
|
||||
-fetchmailrc file also changes, so it might make sense to run it in
|
||||
-non-daemon mode from some other background process (cron and/or whatever
|
||||
-updates the password).
|
||||
+Fetchmail will re-read the file for each poll when in daemon mode.
|
||||
.TP
|
||||
.B \-\-passwordfd <integer>
|
||||
(Keyword: passwordfd)
|
||||
@@ -1079,7 +1076,7 @@ although it could also be a redirected i
|
||||
(equivalent to "fetchmail \-\-passwordfd 5 5</path/to/file").
|
||||
Useful if something wants to manage password ownership more securely
|
||||
than files, or if the password/token changes often,
|
||||
-such as with typical xoauth2 authentication tokens. Normal interactive
|
||||
+such as with typical oauth2 authentication tokens. Normal interactive
|
||||
mode passwords requires that standard input is a terminal and disables
|
||||
echo, but passwordfd does not care. Do not do something
|
||||
like "echo 'password' | fetchmail ...", since echo's arguments are
|
423
fetchmail-support-oauthbearer-xoauth2-with-pop3.patch
Normal file
423
fetchmail-support-oauthbearer-xoauth2-with-pop3.patch
Normal file
@ -0,0 +1,423 @@
|
||||
From: Matthew Ogilvie <mmogilvi+fml@zoho.com>
|
||||
Date: Fri, 30 Jun 2017 02:35:12 -0600
|
||||
Subject: support oauthbearer/xoauth2 with pop3
|
||||
Git-repo: https://gitlab.com/fetchmail/fetchmail.git
|
||||
Git-commit: 7b5c56f0fa3acb4c5589a4747c1921a311d8a464
|
||||
|
||||
(Also factor out some common imap/pop3 oauth2 code.)
|
||||
---
|
||||
Makefile.am | 2
|
||||
fetchmail.man | 5 --
|
||||
imap.c | 53 +++--------------------
|
||||
oauth2.c | 61 +++++++++++++++++++++++++++
|
||||
oauth2.h | 6 ++
|
||||
pop3.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
|
||||
6 files changed, 202 insertions(+), 55 deletions(-)
|
||||
create mode 100644 oauth2.c
|
||||
create mode 100644 oauth2.h
|
||||
|
||||
Index: fetchmail-6.5.1/Makefile.am
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/Makefile.am
|
||||
+++ fetchmail-6.5.1/Makefile.am
|
||||
@@ -63,7 +63,7 @@ fetchmail_SOURCES= fetchmail.h getopt.h
|
||||
fetchmail.c env.c idle.c options.c daemon.c \
|
||||
driver.c transact.c sink.c smtp.c \
|
||||
idlist.c uid.c mxget.c md5ify.c cram.c gssapi.c \
|
||||
- opie.c interface.c netrc.c \
|
||||
+ oauth2.c opie.c interface.c netrc.c \
|
||||
unmime.c conf.c checkalias.c uid_db.h uid_db.c\
|
||||
lock.h lock.c \
|
||||
rcfile_l.l rcfile_y.y \
|
||||
Index: fetchmail-6.5.1/fetchmail.man
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/fetchmail.man
|
||||
+++ fetchmail-6.5.1/fetchmail.man
|
||||
@@ -1114,7 +1114,7 @@ AUTHENTICATION below for details). The
|
||||
excruciating exactness, \fBkerberos_v4\fP), \fBgssapi\fP,
|
||||
\fBcram\-md5\fP, \fBotp\fP, \fBntlm\fP, \fBmsn\fP (only for POP3),
|
||||
\fBexternal\fP (only IMAP), \fBimplicit\fP (\fBssh\fP is understood
|
||||
-as alias for \fBimplicit\fP) and \fBoauthbearer\fP (only IMAP).
|
||||
+as alias for \fBimplicit\fP) and \fBoauthbearer\fP (requires token).
|
||||
When \fBany\fP (the default) is specified, fetchmail tries
|
||||
first methods that do not require a password (EXTERNAL, GSSAPI, KERBEROS\ IV,
|
||||
KERBEROS\ 5); then it looks for methods that mask your password
|
||||
@@ -2492,8 +2492,7 @@ Legal protocol identifiers for use with
|
||||
Legal authentication types are 'any', 'password', 'kerberos',
|
||||
\&'kerberos_v4', 'kerberos_v5' and 'gssapi', 'cram\-md5', 'otp', 'msn'
|
||||
(only for POP3), 'ntlm', 'implicit', 'external' (only IMAP),
|
||||
-'oauthbearer' (only for IMAP; requires authentication token in
|
||||
-place of password).
|
||||
+'oauthbearer' (requires authentication token in place of password).
|
||||
The 'password' type specifies
|
||||
authentication by normal transmission of a password (the password may be
|
||||
plain text or subject to protocol-specific encryption as in CRAM-MD5);
|
||||
Index: fetchmail-6.5.1/imap.c
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/imap.c
|
||||
+++ fetchmail-6.5.1/imap.c
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
+#include "oauth2.h"
|
||||
#include "socket.h"
|
||||
|
||||
#include "i18n.h"
|
||||
@@ -417,63 +418,23 @@ static int do_imap_ntlm(int sock, struct
|
||||
|
||||
static int do_imap_oauthbearer(int sock, struct query *ctl,flag xoauth2)
|
||||
{
|
||||
- /* Implements relevant parts of RFC-7628, RFC-6750, and
|
||||
- * https://developers.google.com/gmail/imap/xoauth2-protocol
|
||||
- *
|
||||
- * This assumes something external manages obtaining an up-to-date
|
||||
- * authentication/bearer token and arranging for it to be in
|
||||
- * ctl->password. This may involve renewing it ahead of time if
|
||||
- * necessary using a renewal token that fetchmail knows nothing about.
|
||||
- * See:
|
||||
- * https://github.com/google/gmail-oauth2-tools/wiki/OAuth2DotPyRunThrough
|
||||
- */
|
||||
- const char *name;
|
||||
- char *oauth2str;
|
||||
- int oauth2len;
|
||||
- int saved_suppress_tags = suppress_tags;
|
||||
-
|
||||
- char *oauth2b64;
|
||||
-
|
||||
+ char *oauth2str = get_oauth2_string(ctl, xoauth2);
|
||||
+ const char *name = xoauth2 ? "XOAUTH2" : "OAUTHBEARER";
|
||||
int ok;
|
||||
|
||||
- oauth2len = strlen(ctl->remotename) + strlen(ctl->password) + 32;
|
||||
- oauth2str = (char *)xmalloc(oauth2len);
|
||||
- if (xoauth2)
|
||||
- {
|
||||
- snprintf(oauth2str, oauth2len,
|
||||
- "user=%s\1auth=Bearer %s\1\1",
|
||||
- ctl->remotename,
|
||||
- ctl->password);
|
||||
- name = "XOAUTH2";
|
||||
- }
|
||||
- else
|
||||
- {
|
||||
- snprintf(oauth2str, oauth2len,
|
||||
- "n,a=%s,\1auth=Bearer %s\1\1",
|
||||
- ctl->remotename,
|
||||
- ctl->password);
|
||||
- name = "OAUTHBEARER";
|
||||
- }
|
||||
-
|
||||
- oauth2b64 = (char *)xmalloc(2*strlen(oauth2str)+8);
|
||||
- to64frombits(oauth2b64, oauth2str, strlen(oauth2str));
|
||||
-
|
||||
- memset(oauth2str, 0x55, strlen(oauth2str));
|
||||
- free(oauth2str);
|
||||
-
|
||||
/* Protect the access token like a password in logs, despite the
|
||||
* usually-short expiration time and base64 encoding:
|
||||
*/
|
||||
- strlcpy(shroud, oauth2b64, sizeof(shroud));
|
||||
+ strlcpy(shroud, oauth2str, sizeof(shroud));
|
||||
|
||||
plus_cont_context = IPLUS_OAUTHBEARER;
|
||||
- ok = gen_transact(sock, "AUTHENTICATE %s %s", name, oauth2b64);
|
||||
+ ok = gen_transact(sock, "AUTHENTICATE %s %s", name, oauth2str);
|
||||
plus_cont_context = IPLUS_NONE;
|
||||
|
||||
memset(shroud, 0x55, sizeof(shroud));
|
||||
shroud[0] = '\0';
|
||||
- memset(oauth2b64, 0x55, strlen(oauth2b64));
|
||||
- free(oauth2b64);
|
||||
+ memset(oauth2str, 0x55, strlen(oauth2str));
|
||||
+ free(oauth2str);
|
||||
|
||||
return ok;
|
||||
}
|
||||
Index: fetchmail-6.5.1/oauth2.c
|
||||
===================================================================
|
||||
--- /dev/null
|
||||
+++ fetchmail-6.5.1/oauth2.c
|
||||
@@ -0,0 +1,61 @@
|
||||
+/*
|
||||
+ * oauth2.c -- oauthbearer and xoauth2 support
|
||||
+ *
|
||||
+ * Copyright 2017 by Matthew Ogilvie
|
||||
+ * For license terms, see the file COPYING in this directory.
|
||||
+ */
|
||||
+
|
||||
+#include "config.h"
|
||||
+#include "fetchmail.h"
|
||||
+#include "oauth2.h"
|
||||
+
|
||||
+#include <stdio.h>
|
||||
+#include <string.h>
|
||||
+
|
||||
+char *get_oauth2_string(struct query *ctl,flag xoauth2)
|
||||
+{
|
||||
+ /* Implements the bearer token string based for a
|
||||
+ * combination of RFC-7628 (ouath sasl, with
|
||||
+ * examples for imap only), RFC-6750 (oauth2), and
|
||||
+ * RFC-5034 (pop sasl), as implemented by gmail and others.
|
||||
+ *
|
||||
+ * Also supports xoauth2, which is just a couple of minor variariations.
|
||||
+ * https://developers.google.com/gmail/imap/xoauth2-protocol
|
||||
+ *
|
||||
+ * This assumes something external manages obtaining an up-to-date
|
||||
+ * authentication/bearer token and arranging for it to be in
|
||||
+ * ctl->password. This may involve renewing it ahead of time if
|
||||
+ * necessary using a renewal token that fetchmail knows nothing about.
|
||||
+ * See:
|
||||
+ * https://github.com/google/gmail-oauth2-tools/wiki/OAuth2DotPyRunThrough
|
||||
+ */
|
||||
+ char *oauth2str;
|
||||
+ int oauth2len;
|
||||
+
|
||||
+ char *oauth2b64;
|
||||
+
|
||||
+ oauth2len = strlen(ctl->remotename) + strlen(ctl->password) + 32;
|
||||
+ oauth2str = (char *)xmalloc(oauth2len);
|
||||
+ if (xoauth2)
|
||||
+ {
|
||||
+ snprintf(oauth2str, oauth2len,
|
||||
+ "user=%s\1auth=Bearer %s\1\1",
|
||||
+ ctl->remotename,
|
||||
+ ctl->password);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ snprintf(oauth2str, oauth2len,
|
||||
+ "n,a=%s,\1auth=Bearer %s\1\1",
|
||||
+ ctl->remotename,
|
||||
+ ctl->password);
|
||||
+ }
|
||||
+
|
||||
+ oauth2b64 = (char *)xmalloc(2*strlen(oauth2str)+8);
|
||||
+ to64frombits(oauth2b64, oauth2str, strlen(oauth2str));
|
||||
+
|
||||
+ memset(oauth2str, 0x55, strlen(oauth2str));
|
||||
+ free(oauth2str);
|
||||
+
|
||||
+ return oauth2b64;
|
||||
+}
|
||||
Index: fetchmail-6.5.1/oauth2.h
|
||||
===================================================================
|
||||
--- /dev/null
|
||||
+++ fetchmail-6.5.1/oauth2.h
|
||||
@@ -0,0 +1,6 @@
|
||||
+#ifndef OAUTH2_H
|
||||
+#define OAUTH2_H
|
||||
+
|
||||
+char *get_oauth2_string(struct query *ctl,flag xoauth2);
|
||||
+
|
||||
+#endif /*OAUTH2_H*/
|
||||
Index: fetchmail-6.5.1/pop3.c
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/pop3.c
|
||||
+++ fetchmail-6.5.1/pop3.c
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
+#include "oauth2.h"
|
||||
#include "socket.h"
|
||||
#include "i18n.h"
|
||||
#include "uid_db.h"
|
||||
@@ -49,6 +50,10 @@ static flag has_cram = FALSE;
|
||||
static flag has_otp = FALSE;
|
||||
static flag has_ntlm = FALSE;
|
||||
static flag has_stls = FALSE;
|
||||
+static flag has_oauthbearer = FALSE;
|
||||
+static flag has_xoauth2 = FALSE;
|
||||
+
|
||||
+static const char *next_sasl_resp = NULL;
|
||||
|
||||
static void clear_sessiondata(void) {
|
||||
/* must match defaults above */
|
||||
@@ -132,12 +137,65 @@ static int pop3_ok (int sock, char *argb
|
||||
char buf [POPBUFSIZE+1];
|
||||
char *bufp;
|
||||
|
||||
- if ((ok = gen_recv(sock, buf, sizeof(buf))) == 0)
|
||||
+ while ((ok = gen_recv(sock, buf, sizeof(buf))) == 0)
|
||||
{ bufp = buf;
|
||||
- if (*bufp == '+' || *bufp == '-')
|
||||
- bufp++;
|
||||
- else
|
||||
+ if (*bufp == '+')
|
||||
+ {
|
||||
+ bufp++;
|
||||
+ if (*bufp == ' ' && next_sasl_resp != NULL)
|
||||
+ {
|
||||
+ /* Currently only used for OAUTHBEARER/XOAUTH2, and only
|
||||
+ * rarely even then.
|
||||
+ *
|
||||
+ * This is the only case where the top while() actually
|
||||
+ * loops.
|
||||
+ *
|
||||
+ * For OAUTHBEARER, data aftetr '+ ' is probably
|
||||
+ * base64-encoded JSON with some HTTP-related error details.
|
||||
+ */
|
||||
+ if (*next_sasl_resp != '\0')
|
||||
+ SockWrite(sock, next_sasl_resp, strlen(next_sasl_resp));
|
||||
+ SockWrite(sock, "\r\n", 2);
|
||||
+ if (outlevel >= O_MONITOR)
|
||||
+ {
|
||||
+ const char *found;
|
||||
+ if (shroud[0] && (found = strstr(next_sasl_resp, shroud)))
|
||||
+ {
|
||||
+ /* enshroud() without copies, and avoid
|
||||
+ * confusing with a genuine "*" (cancel).
|
||||
+ */
|
||||
+ report(stdout, "POP3> %.*s[SHROUDED]%s\n",
|
||||
+ (int)(found-next_sasl_resp), next_sasl_resp,
|
||||
+ found+strlen(shroud));
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ report(stdout, "POP3> %s\n", next_sasl_resp);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (*next_sasl_resp == '\0' || *next_sasl_resp == '*')
|
||||
+ {
|
||||
+ /* No more responses expected, cancel AUTH command if
|
||||
+ * more responses requested.
|
||||
+ */
|
||||
+ next_sasl_resp = "*";
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ next_sasl_resp = "";
|
||||
+ }
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+ else if (*bufp == '-')
|
||||
+ {
|
||||
+ bufp++;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
return(PS_PROTOCOL);
|
||||
+ }
|
||||
|
||||
while (isalpha((unsigned char)*bufp))
|
||||
bufp++;
|
||||
@@ -206,6 +264,8 @@ static int pop3_ok (int sock, char *argb
|
||||
#endif
|
||||
if (argbuf != NULL)
|
||||
strcpy(argbuf,bufp);
|
||||
+
|
||||
+ break;
|
||||
}
|
||||
|
||||
return(ok);
|
||||
@@ -234,11 +294,13 @@ static int capa_probe(int sock)
|
||||
#ifdef NTLM_ENABLE
|
||||
has_ntlm = FALSE;
|
||||
#endif /* NTLM_ENABLE */
|
||||
+ has_oauthbearer = FALSE;
|
||||
+ has_xoauth2 = FALSE;
|
||||
|
||||
ok = gen_transact(sock, "CAPA");
|
||||
if (ok == PS_SUCCESS)
|
||||
{
|
||||
- char buffer[64];
|
||||
+ char buffer[128];
|
||||
char *cp;
|
||||
|
||||
/* determine what authentication methods we have available */
|
||||
@@ -253,6 +315,10 @@ static int capa_probe(int sock)
|
||||
if (strstr(buffer, "STLS"))
|
||||
has_stls = TRUE;
|
||||
#endif /* SSL_ENABLE */
|
||||
+static flag has_oauthbearer = FALSE;
|
||||
+static flag has_xoauth2 = FALSE;
|
||||
+
|
||||
+static const char *next_sasl_resp = NULL;
|
||||
|
||||
#if defined(GSSAPI)
|
||||
if (strstr(buffer, "GSSAPI"))
|
||||
@@ -276,6 +342,12 @@ static int capa_probe(int sock)
|
||||
|
||||
if (strstr(buffer, "CRAM-MD5"))
|
||||
has_cram = TRUE;
|
||||
+
|
||||
+ if (strstr(buffer, "OAUTHBEARER"))
|
||||
+ has_oauthbearer = TRUE;
|
||||
+
|
||||
+ if (strstr(buffer, "XOAUTH2"))
|
||||
+ has_xoauth2 = TRUE;
|
||||
}
|
||||
}
|
||||
done_capa = TRUE;
|
||||
@@ -292,6 +364,40 @@ static void set_peek_capable(struct quer
|
||||
peek_capable = !ctl->fetchall && (!ctl->keep || ctl->server.uidl);
|
||||
}
|
||||
|
||||
+static int do_oauthbearer(int sock, struct query *ctl, flag xoauth2)
|
||||
+{
|
||||
+ char *oauth2str = get_oauth2_string(ctl, xoauth2);
|
||||
+ const char *name = xoauth2 ? "XOAUTH2" : "OAUTHBEARER";
|
||||
+ int ok;
|
||||
+
|
||||
+ /* Protect the access token like a password in logs, despite the
|
||||
+ * usually-short expiration time and base64 encoding:
|
||||
+ */
|
||||
+ strlcpy(shroud, oauth2str, sizeof(shroud));
|
||||
+
|
||||
+ if (4+1+1+2+strlen(name)+strlen(oauth2str) <= 255)
|
||||
+ {
|
||||
+ next_sasl_resp = "";
|
||||
+ ok = gen_transact(sock, "AUTH %s %s", name, oauth2str);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ /* Too long to use "initial client response" (RFC-5034 section 4,
|
||||
+ * referencing RFC-4422 section 4).
|
||||
+ */
|
||||
+ next_sasl_resp = oauth2str;
|
||||
+ ok = gen_transact(sock, "AUTH %s", name);
|
||||
+ }
|
||||
+ next_sasl_resp = NULL;
|
||||
+
|
||||
+ memset(shroud, 0x55, sizeof(shroud));
|
||||
+ shroud[0] = '\0';
|
||||
+ memset(oauth2str, 0x55, strlen(oauth2str));
|
||||
+ free(oauth2str);
|
||||
+
|
||||
+ return ok;
|
||||
+}
|
||||
+
|
||||
static int pop3_getauth(int sock, struct query *ctl, char *greeting)
|
||||
/* apply for connection authorization */
|
||||
{
|
||||
@@ -371,6 +477,7 @@ static int pop3_getauth(int sock, struct
|
||||
(ctl->server.authenticate == A_KERBEROS_V5) ||
|
||||
(ctl->server.authenticate == A_OTP) ||
|
||||
(ctl->server.authenticate == A_CRAM_MD5) ||
|
||||
+ (ctl->server.authenticate == A_OAUTHBEARER) ||
|
||||
maybe_starttls(ctl))
|
||||
{
|
||||
if ((ok = capa_probe(sock)) != PS_SUCCESS)
|
||||
@@ -520,6 +627,19 @@ static int pop3_getauth(int sock, struct
|
||||
/*
|
||||
* OK, we have an authentication type now.
|
||||
*/
|
||||
+ if (ctl->server.authenticate == A_OAUTHBEARER)
|
||||
+ {
|
||||
+ if (has_oauthbearer || !has_xoauth2)
|
||||
+ {
|
||||
+ ok = do_oauthbearer(sock, ctl, FALSE); /* OAUTHBEARER */
|
||||
+ }
|
||||
+ if (ok != PS_SUCCESS && has_xoauth2)
|
||||
+ {
|
||||
+ ok = do_oauthbearer(sock, ctl, TRUE); /* XOAUTH2 */
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
#if defined(KERBEROS_V4)
|
||||
/*
|
||||
* Servers doing KPOP have to go through a dummy login sequence
|
1787
fetchmail.changes
Normal file
1787
fetchmail.changes
Normal file
File diff suppressed because it is too large
Load Diff
29
fetchmail.exec
Normal file
29
fetchmail.exec
Normal file
@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
# fetchmail-systemd-exec: sysconfig helper script for systemd
|
||||
|
||||
die() {
|
||||
echo "$@" 1>&2
|
||||
exit 5 # closest thing among fetchmail's exit codes
|
||||
}
|
||||
|
||||
echo "$FETCHMAIL_POLLING_INTERVAL" | grep -Eq '^[0-9]+$' \
|
||||
|| die 'invalid $FETCHMAIL_POLLING_INTERVAL setting'
|
||||
[ -r "$FETCHMAIL_RC_PATH" ] \
|
||||
|| die '$FETCHMAIL_RC_PATH does not exist or cannot be read'
|
||||
|
||||
OPTS="-d $FETCHMAIL_POLLING_INTERVAL"
|
||||
[ "$FETCHMAIL_FETCHALL" = "yes" ] && OPTS="$OPTS -a"
|
||||
[ "$FETCHMAIL_SILENT" = "yes" ] && OPTS="$OPTS -s"
|
||||
[ "`whoami`" = "fetchmail" -a -z "$FETCHMAILHOME" ] && \
|
||||
export FETCHMAILHOME=/var/lib/fetchmail
|
||||
|
||||
if [ ! -z "$FETCHMAIL_DEFAULT_LOGFILE" ] ; then
|
||||
if [ "$FETCHMAIL_DEFAULT_LOGFILE" = "syslog" ]; then
|
||||
OPTS="$OPTS --syslog"
|
||||
else
|
||||
OPTS="$OPTS -L $FETCHMAIL_DEFAULT_LOGFILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
exec /usr/bin/fetchmail $OPTS $FETCHMAIL_EXPERT_OPTIONS \
|
||||
-f $FETCHMAIL_RC_PATH
|
71
fetchmail.keyring
Normal file
71
fetchmail.keyring
Normal file
@ -0,0 +1,71 @@
|
||||
pub rsa4096 2015-09-09 [SC] [expires: 2020-12-23]
|
||||
DC4A655BD993CD4871FA8210E412B156EFF3855A
|
||||
uid [ unknown] Matthias Andree <matthias.andree@gmx.de>
|
||||
uid [ unknown] Matthias Andree <mandree@FreeBSD.org>
|
||||
sub rsa4096 2015-09-09 [E] [expires: 2020-12-23]
|
||||
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mQINBFXwq5cBEADQxc9JeK4yqt1BX5tOMfzyIfEyBWXix0xqeAA/HQ2wd31NFcGF
|
||||
EbAevDsGoO7UcYQji1Gj/TggmclV37SHPDE++bU7O6Wur57FfTsVCmS6XjHj/n2q
|
||||
XgxrWtU7Fv9YOBz/wNge3sGAh2xbwh5dTt+Ew6TbuMbwXNonb4WUCo6yFMrDd2vg
|
||||
9RqcVSDpdLFO0JI9hNGLQDtHP2TbBfGj8V5qz9NFiGzRxmmFhMzqOSDCEs9uanr3
|
||||
TCLq7yZFTyAmXDCZuyFhxGwHDo6jB+9LbIprA/oH0uFol899hiIrZRm7kIAYsOSv
|
||||
p84x0XBFvSMoDY4ZA4Ucv3xk+aDqob0V5F4+W3Vg7bdlpbAuwov944Zawbm/sBGc
|
||||
tNbfNeWjc+L7F43PbghzCfk6aLH0LwH3lNiu76F57lJqfTCnkBd0V0dUZ0/AJFsk
|
||||
Zu+aO/dCVkbfjotXDqsh55kBrSMsRX/rqt2d43q6o9AyWu5aMqLAG2ZN19qLu/a1
|
||||
vzbMEfRaimlFSo9LMY1jf5TcUc7mNlPDhm8c6o+Ivx/D0tSQ4V+3SqbroYgHo1A4
|
||||
Qyiau4sEP2YFtKbdRdpaN7WsdfdaZmrd9xa5lvp/gQZEdpLPzL0aBDEeUzaL/nee
|
||||
/EDQUbPuSYJCmDNyqxs/Y4j0ZGQmIPT1CY34AvdjIcLuT/BG1JZaIlKQ9QARAQAB
|
||||
tCVNYXR0aGlhcyBBbmRyZWUgPG1hbmRyZWVARnJlZUJTRC5vcmc+iQJUBBMBCgA+
|
||||
AhsDBQsJCAcDBRUKCQgLBRYCAwEAAh4BAheAFiEE3EplW9mTzUhx+oIQ5BKxVu/z
|
||||
hVoFAl4CEFEFCQnymDoACgkQ5BKxVu/zhVo/1g//WEhWloFEhIEY52aiexsPRKan
|
||||
WNcB0gUc15cT4hviWsyibYQFFJoRhc65fW739K0AbA1wjZha4jPLTwLtcFOSiIYT
|
||||
ia4VDXg9zabe48SiGso2iNGaTmNj/ZIr6F8WplaylJvyuvZPSA71c7uzbkJMWYpE
|
||||
PwFVYM/6g6ZYE/gy8PlYOQ+4cZzqxCHXwa2CHeCWmx4uFY2ntLY92BRxJIcMZPzB
|
||||
VKq+MtXSdaZjkDAz+Oj1PJnZ1lo04+RSKtdMyiNBgv+Js3s6eX2DSfXLuTN1yeR5
|
||||
PhlBNp8UbmBiV8gmVM1BDY4ga9JrY4nyPrbs5oPdaoXs1AV/HC82kBgkfA/PAWzs
|
||||
4yGEU/XQNUQbrCNHUdIY6nDnjdZfIpCVXnemk5oOPfV1lJfz+FgLYxfNnooYczbt
|
||||
/qwqElPSiTBL97Q5zbuX3Z3IllgT8HkhInMx5WofRjdu4valUI4yuSSfxmCXIXtz
|
||||
5iNedYhitg84J53hqFV6i9ctzbLbMYWaATUCEAHn9yLgwCluRyd3Wgmfde7zAXQh
|
||||
nxs65L9WzpNk0TnhDT6yJ3DzG/ycl0655wL6LGXgwWWDu0L60HNva8fJ83GqYpSf
|
||||
DVEzgj3cKBt2uWfwoZ/HvFQNzT4Bwh+WtkU602MUd+6hcEOde4+WfwPuoBdMjiea
|
||||
HJ7bMxKFtexpZvtsqzq0KE1hdHRoaWFzIEFuZHJlZSA8bWF0dGhpYXMuYW5kcmVl
|
||||
QGdteC5kZT6JAlQEEwEKAD4CGwMFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AWIQTc
|
||||
SmVb2ZPNSHH6ghDkErFW7/OFWgUCXgIQUQUJCfKYOgAKCRDkErFW7/OFWrlcD/9T
|
||||
FaFcPIQvOCHMkX+qHbLM1DLJbxQsEyx2hkXBDsN5Q2vqL14GvsG8ArFyWrrDTre2
|
||||
fr6j3xY27C2QhJ+JxKv3+ln+hv45zNSU1E2lld3HXmtBBGnDhcjekZZF0b/Hmr7Y
|
||||
unSL87Vp/Wq5dLslUH83Ycg2NQbpg7LpjdB7gnZlGS8cK17rTiSxhVIrPpUp0heS
|
||||
VVUmo2VQXtSMCspdmbY/uZfYjco9tLBfeHuC+N9E4gV2zPSmzGjzutQmt3UZCL2W
|
||||
MEy8SC0ljKb8FXF37/deEgSYtX5lB8MjHGUuKiVP22MyVAFRfZIOvkeYuCPXs876
|
||||
JKYA8ShsE+MNdYzcwgIWIAmS8RZOJ0Wgr4wW+gdz/3ALaQtsTRGSUOBtZ3Ewl3gR
|
||||
rWiFnKvBKaV48+qBpFMtfCBfOmrWS4W7wldAxBoy3lkhXUAGRIZlrE8eJFgYZPg6
|
||||
CLOh/iGaI7WADP63ZaoiLXfY3WWV5gR6wxGMsfdI4F4ccJx4Lyyhg6IG6aaRGO05
|
||||
jvIdVIWimFc0UVcGh10HBLnMNZwaQBf9CO56cJWRtlK5UibTXCYQWw4Ct1gZGgjR
|
||||
IZC3qrfrQj1nl6N5lN3bEKeGpRTF1CFspW6ZkJHRii5JdbjRmcu5wWVGEnVkporU
|
||||
H/6+eN3h7IHFupCij0tqLh+maK8Ch19etVhBobb5uLkCDQRV8KuXARAA1ybtHKfQ
|
||||
7yVepuWbvnoZpuaoxM6yCKSrrm/MVnxuxk5R9mDVtBGQMbqDPDyZWqkDFKdtkJO6
|
||||
kS/WZH6u3EtW6Ouz4s4MAEHJ3Bi//8CPhTb/KqhgaSjcJ/TM3wZRLlq63Po/ZeAh
|
||||
RJwCk6r48bL+GznEpbYa5ecANu6Smp1LB4FoLnMJOJQHdUOlk265ccQEgwbvjpjG
|
||||
Kwns3CBcUBnZzJu6klAsLchMehNAil4F+R0tkCrVdf6Ty0rCJIgRm9of/mr/Mxa9
|
||||
s1IQVccZqj8Xe34lmrhllVGAzSOfbtl9mtIjSwYkUE/mN/6eLBCAV7/g92iJ1Fh0
|
||||
NP1YAxWhJXPzmY9pbv8t9FHe+7SH2k0gT+i0LZnG+U91c7SeDrfftEb8OVSIwJIr
|
||||
PiTuygGep+UyFvu75CAvtOKrjjJrDuX+f9V6NDRaMywQq5/GTefBmEdhKAcetDzI
|
||||
wxVNTLLyCu0g4Q923+AthZ1dh9kAqdBeEx/hoVWm4uxRsudFVnKiOOEDCPyB+KeF
|
||||
qrfxXPHXlRgvGAvH+jnCuhwWrfYkH0gPC5YV90bZ1G5eAwZcOAvhHH2Uo8+Oa+GN
|
||||
2ofZdO2fpayF8FHcqahgNYb4XjKGiTWxZTUb8WB2NFGHnmGvP9rYaAQ/JkSbKUrq
|
||||
2kHV+uJiaQYWQK/Y7pSSonKsk4FESmbpTUsAEQEAAYkCPAQYAQoAJgIbDBYhBNxK
|
||||
ZVvZk81IcfqCEOQSsVbv84VaBQJeAhCMBQkJ8ph1AAoJEOQSsVbv84VajsgP/iso
|
||||
w15UNuy2nZuHJwD3tj/vHv/iXaPg8OVcrP6BCf5TA+N7QDYbW9A/QwHRHsaYQ3y6
|
||||
gpCUN6oobMJJSFDI/I40TowZ2TtEaPuVNzAe+H8Qe0BKiVkp8N0v7LzwB7AdmgpR
|
||||
hzdvvDJfEgk2AR4WtRc9b+sykWTBguGHA1/96ji84L4ef5VWkotB0B2em9RlRmQ8
|
||||
ScyB0JdjTXL5Ddkumtgeu3ltLrZTPlMrstf4XmlAYI6u+Jsn9Q+hgD1zmcwY5Mox
|
||||
GrSZgFoA9izdrDSk3QzLjN4bzLAJ9GIlSA/FtJ0rMDkCFCzPb6DCJTCBFE5lRUXf
|
||||
J8wnTygpvvhomWuiTH5ahcCeJ0JWxspjI/wKikWtdCGTME1KjudM73XceiRwHSCJ
|
||||
kGtoGFXcPE/CtsYsztLfb5icWzMG5zPAGZLEweNfyjVzyuYmAfvOCaQRcwRQqgzK
|
||||
587CVTUqxySqmk3VH1PtsfauUgvP/uvamVC2SE8djnqxXI3VrixbTMcNCAQVOSEU
|
||||
e5kEWx/u3BE23c6dYmZGq1TSGtIbseQZ0FemUQ3wEDtIg06z5lnsw0SfO5O9Ut2/
|
||||
Zb6acmXOCQJ7AqCBs8fn/4qqizH+cgNz63sPPheOYUROzEaNU+uPdgcpU2UZ9iDe
|
||||
LIJMO3QLkDsZDVhwATsHfyFKQN3TKHGJukMSQ4Lf
|
||||
=0adh
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
12
fetchmail.logrotate
Normal file
12
fetchmail.logrotate
Normal file
@ -0,0 +1,12 @@
|
||||
/var/log/fetchmail {
|
||||
compress
|
||||
dateext
|
||||
maxage 365
|
||||
rotate 99
|
||||
size=+1024k
|
||||
notifempty
|
||||
missingok
|
||||
copytruncate
|
||||
create 0600 fetchmail root
|
||||
}
|
||||
|
23
fetchmail.service
Normal file
23
fetchmail.service
Normal file
@ -0,0 +1,23 @@
|
||||
[Unit]
|
||||
Description=A remote-mail retrieval utility
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
# added automatically, for details please see
|
||||
# https://en.opensuse.org/openSUSE:Security_Features#Systemd_hardening_effort
|
||||
PrivateDevices=true
|
||||
ProtectHostname=true
|
||||
ProtectClock=true
|
||||
ProtectKernelTunables=true
|
||||
ProtectKernelModules=true
|
||||
ProtectKernelLogs=true
|
||||
ProtectControlGroups=true
|
||||
RestrictRealtime=true
|
||||
# end of automatic additions
|
||||
EnvironmentFile=-/etc/sysconfig/fetchmail
|
||||
User=fetchmail
|
||||
ExecStart=@LIBEXECDIR@/fetchmail-systemd-exec
|
||||
RestartSec=1
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
210
fetchmail.spec
Normal file
210
fetchmail.spec
Normal file
@ -0,0 +1,210 @@
|
||||
#
|
||||
# spec file for package fetchmail
|
||||
#
|
||||
# Copyright (c) 2024 SUSE LLC
|
||||
#
|
||||
# All modifications and additions to the file contributed by third parties
|
||||
# remain the property of their copyright owners, unless otherwise agreed
|
||||
# upon. The license for this file, and modifications and additions to the
|
||||
# file, is the same license as for the pristine package itself (unless the
|
||||
# license for the pristine package is not an Open Source License, in which
|
||||
# case the license is the MIT License). An "Open Source License" is a
|
||||
# license that conforms to the Open Source Definition (Version 1.9)
|
||||
# published by the Open Source Initiative.
|
||||
|
||||
# Please submit bugfixes or comments via https://bugs.opensuse.org/
|
||||
#
|
||||
|
||||
|
||||
#Compat macro for new _fillupdir macro introduced in Nov 2017
|
||||
%if ! %{defined _fillupdir}
|
||||
%define _fillupdir %{_localstatedir}/adm/fillup-templates
|
||||
%endif
|
||||
Name: fetchmail
|
||||
Version: 6.5.1
|
||||
Release: 0
|
||||
Summary: Full-Featured POP and IMAP Mail Retrieval Daemon
|
||||
License: GPL-2.0-or-later
|
||||
URL: https://www.fetchmail.info/
|
||||
Source0: https://sourceforge.net/projects/%{name}/files/branch_6.5/%{name}-%{version}.tar.xz
|
||||
Source1: https://sourceforge.net/projects/%{name}/files/branch_6.5/%{name}-%{version}.tar.xz.asc
|
||||
Source2: %{name}.logrotate
|
||||
Source3: sysconfig.%{name}
|
||||
Source5: %{name}.keyring
|
||||
Source6: %{name}.service
|
||||
Source7: %{name}.tmpfiles
|
||||
Source8: %{name}.exec
|
||||
Source9: %{name}.sysusers
|
||||
Patch0: fetchmail-6.3.8-smtp_errors.patch
|
||||
Patch1: fetchmail-add-imap-oauthbearer-support.patch
|
||||
Patch2: fetchmail-support-oauthbearer-xoauth2-with-pop3.patch
|
||||
Patch3: fetchmail-add-passwordfile-and-passwordfd-options.patch
|
||||
Patch4: fetchmail-add-contrib-fetchnmail-oauth2.py-token-acquisition-u.patch
|
||||
Patch5: fetchmail-FAQ-list-gmail-options-including-oauthbearer-and-app.patch
|
||||
Patch6: fetchmail-give-each-ctl-it-s-own-copy-of-password.patch
|
||||
Patch7: fetchmail-re-read-passwordfile-on-every-poll.patch
|
||||
Patch8: fetchmail-add-query_to64_outsize-utility-function.patch
|
||||
Patch9: fetchmail-chase-and-integrate-interface-change.patch
|
||||
Patch10: fetchmail-oauth2-c-calculate-and-pass-in-correct-buffer-size-to-to64frombits.patch
|
||||
Patch11: fetchmail-increase-max-password-length-to-handle-oauth-tokens.patch
|
||||
Patch12: fetchmail-bump-max-passwordlen-to-1bytes.patch
|
||||
Patch13: fetchmail-add-readme-oauth2-issue-27.patch
|
||||
Patch14: fetchmailconf-no-more-future.patch
|
||||
BuildRequires: automake
|
||||
BuildRequires: bison
|
||||
BuildRequires: fdupes
|
||||
BuildRequires: flex
|
||||
BuildRequires: krb5-devel
|
||||
BuildRequires: openssl-devel
|
||||
BuildRequires: postfix
|
||||
BuildRequires: procmail
|
||||
BuildRequires: python3-base
|
||||
BuildRequires: shadow
|
||||
BuildRequires: systemd-rpm-macros
|
||||
BuildRequires: sysuser-shadow
|
||||
BuildRequires: sysuser-tools
|
||||
BuildRequires: xz
|
||||
Requires: logrotate
|
||||
Requires(pre): %fillup_prereq
|
||||
Suggests: smtp_daemon
|
||||
%sysusers_requires
|
||||
|
||||
%description
|
||||
Fetchmail is a robust and well-documented remote mail retrieval and
|
||||
forwarding utility intended to be used over on-demand TCP/IP links
|
||||
(such as SLIP or PPP connections).
|
||||
|
||||
Fetchmail retrieves mail from remote mail servers and forwards it to
|
||||
your local machine's delivery system, so it can be read by normal mail
|
||||
user agents, such as mutt, elm, pine, (x)emacs/gnus, or mailx.
|
||||
|
||||
fetchmailconf, an interactive GUI configurator suitable for end-users,
|
||||
is included in the fetchmailconf package.
|
||||
|
||||
%package -n fetchmailconf
|
||||
Summary: Fetchmail Configuration Utility
|
||||
Requires: %{name} = %{version}
|
||||
Requires: python3 >= 3.7
|
||||
Requires: python3-tk
|
||||
|
||||
%description -n fetchmailconf
|
||||
A GUI configuration utility for generating fetchmail configuration
|
||||
files (.fetchmailrc).
|
||||
|
||||
%prep
|
||||
%autosetup -p1
|
||||
cp -a %{SOURCE2} %{SOURCE3} .
|
||||
|
||||
ACLOCAL="aclocal -I m4 -I m4-local" autoreconf -fvi
|
||||
|
||||
%build
|
||||
export CFLAGS="%{optflags} -fPIE"
|
||||
%configure \
|
||||
--enable-POP2 \
|
||||
--enable-RPA \
|
||||
--enable-NTLM \
|
||||
--enable-SDPS \
|
||||
--with-kerberos5 \
|
||||
--with-gssapi \
|
||||
--with-ssl=%{_prefix} \
|
||||
--with-python=%{bindir}/python3
|
||||
%make_build LDFLAGS="-pie"
|
||||
%sysusers_generate_pre %{SOURCE9} fetchmail
|
||||
|
||||
%install
|
||||
%make_install
|
||||
ln -sf fetchmail.1.gz %{buildroot}%{_mandir}/man1/fetchmailconf.1.gz
|
||||
%if 0%{?suse_version} > 1500
|
||||
mkdir -p %{buildroot}%{_sysconfdir}
|
||||
mkdir -p %{buildroot}%{_distconfdir}/logrotate.d
|
||||
cp fetchmail.logrotate %{buildroot}%{_distconfdir}/logrotate.d/fetchmail
|
||||
%else
|
||||
mkdir -p %{buildroot}%{_sysconfdir}/logrotate.d
|
||||
cp fetchmail.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/fetchmail
|
||||
%endif
|
||||
mkdir -p %{buildroot}/sbin
|
||||
mkdir -p %{buildroot}%{_unitdir}
|
||||
mkdir -p %{buildroot}%{_tmpfilesdir}
|
||||
mkdir -p %{buildroot}%{_sysusersdir}
|
||||
sed -e 's-@LIBEXECDIR@-%{_libexecdir}-g' -i %{SOURCE6}
|
||||
install -m 0644 %{SOURCE6} %{buildroot}%{_unitdir}/%{name}.service
|
||||
install -m 0644 %{SOURCE7} %{buildroot}%{_tmpfilesdir}/%{name}.conf
|
||||
install -m 0644 %{SOURCE9} %{buildroot}%{_sysusersdir}/%{name}.conf
|
||||
mkdir -p %{buildroot}%{_libexecdir}
|
||||
install -m 0755 %{SOURCE8} %{buildroot}%{_libexecdir}/%{name}-systemd-exec
|
||||
mkdir -p %{buildroot}%{_sbindir}
|
||||
ln -s service %{buildroot}%{_sbindir}/rc%{name}
|
||||
touch %{buildroot}%{_sysconfdir}/fetchmailrc
|
||||
mkdir -p %{buildroot}%{_fillupdir}
|
||||
cp sysconfig.%{name} %{buildroot}%{_fillupdir}
|
||||
mkdir -p %{buildroot}%{_localstatedir}/log
|
||||
touch %{buildroot}%{_localstatedir}/log/fetchmail
|
||||
mkdir -p %{buildroot}%{_localstatedir}/lib/fetchmail
|
||||
# Deduplicate Python files
|
||||
%fdupes %{buildroot}%{python3_sitelib}
|
||||
# we don't need this, it's aimed at fetchmail developers
|
||||
# and rpmlint is complaining that we have a binary in /usr/share
|
||||
rm -r contrib/gai*
|
||||
%find_lang %{name}
|
||||
|
||||
%pre -f fetchmail.pre
|
||||
%service_add_pre %{name}.service
|
||||
%if 0%{?suse_version} > 1500
|
||||
# Prepare for migration to /usr/etc; save any old .rpmsave
|
||||
for i in logrotate.d/fetchmail ; do
|
||||
test -f %{_sysconfdir}/${i}.rpmsave && mv -v %{_sysconfdir}/${i}.rpmsave %{_sysconfdir}/${i}.rpmsave.old ||:
|
||||
done
|
||||
%endif
|
||||
|
||||
%post
|
||||
%fillup_only
|
||||
%tmpfiles_create %{name}.conf
|
||||
%service_add_post %{name}.service
|
||||
|
||||
%if 0%{?suse_version} > 1500
|
||||
%posttrans
|
||||
# Migration to /usr/etc, restore just created .rpmsave
|
||||
for i in logrotate.d/fetchmail ; do
|
||||
test -f %{_sysconfdir}/${i}.rpmsave && mv -v %{_sysconfdir}/${i}.rpmsave %{_sysconfdir}/${i} ||:
|
||||
done
|
||||
%endif
|
||||
|
||||
%preun
|
||||
%service_del_preun %{name}.service
|
||||
|
||||
%postun
|
||||
%service_del_postun %{name}.service
|
||||
|
||||
%check
|
||||
%make_build check
|
||||
|
||||
%files -f %{name}.lang
|
||||
%license COPYING
|
||||
%doc FAQ FEATURES NEWS NOTES OLDNEWS README README.NTLM README.OAUTH2 README.SSL README.SSL-SERVER TODO contrib *.html *.txt *.pdf
|
||||
%{_bindir}/fetchmail
|
||||
%dir %attr(0700, fetchmail, fetchmail) %{_localstatedir}/lib/fetchmail
|
||||
%ghost %attr(0600, fetchmail, root) %{_localstatedir}/log/fetchmail
|
||||
%{_mandir}/man1/fetchmail.1%{?ext_man}
|
||||
%ghost %config(noreplace) %attr(0600, fetchmail, root) %{_sysconfdir}/fetchmailrc
|
||||
%if 0%{?suse_version} > 1500
|
||||
%{_distconfdir}/logrotate.d/fetchmail
|
||||
%else
|
||||
%config(noreplace) %{_sysconfdir}/logrotate.d/fetchmail
|
||||
%endif
|
||||
%{_unitdir}/%{name}.service
|
||||
%{_sbindir}/rc%{name}
|
||||
%{_libexecdir}/%{name}-systemd-exec
|
||||
%{_tmpfilesdir}/%{name}.conf
|
||||
%{_sysusersdir}/%{name}.conf
|
||||
%{_fillupdir}/sysconfig.%{name}
|
||||
|
||||
%files -n fetchmailconf
|
||||
%{_bindir}/fetchmailconf
|
||||
%{_mandir}/man1/fetchmailconf.1%{?ext_man}
|
||||
|
||||
%if 0%{suse_version} > 1500
|
||||
%{python3_sitelib}/fetchmailconf.*
|
||||
%{python3_sitelib}/__pycache__/fetchmailconf*
|
||||
%endif
|
||||
|
||||
%changelog
|
11
fetchmail.sysusers
Normal file
11
fetchmail.sysusers
Normal file
@ -0,0 +1,11 @@
|
||||
# Type Name ID GECOS [HOME]
|
||||
|
||||
# during upgrade from previous versions, the group may
|
||||
# have been deleted but the user still be present. Therefore
|
||||
# we have to be sure to recreate the group, as adding only
|
||||
# the user (if already present) won't create it
|
||||
g fetchmail -
|
||||
|
||||
u fetchmail - "mail retrieval daemon" /var/lib/fetchmail
|
||||
m fetchmail fetchmail
|
||||
|
2
fetchmail.tmpfiles
Normal file
2
fetchmail.tmpfiles
Normal file
@ -0,0 +1,2 @@
|
||||
d /run/fetchmail 700 fetchmail fetchmail
|
||||
f /var/log/fetchmail 600 fetchmail root
|
13
fetchmailconf-no-more-future.patch
Normal file
13
fetchmailconf-no-more-future.patch
Normal file
@ -0,0 +1,13 @@
|
||||
Index: fetchmail-6.5.1/fetchmailconf.py
|
||||
===================================================================
|
||||
--- fetchmail-6.5.1.orig/fetchmailconf.py
|
||||
+++ fetchmail-6.5.1/fetchmailconf.py
|
||||
@@ -3,7 +3,7 @@
|
||||
# A GUI configurator for generating fetchmail configuration files.
|
||||
# by Eric S. Raymond, <esr@snark.thyrsus.com>,
|
||||
# Matthias Andree <matthias.andree@gmx.de>
|
||||
-# Requires Python with Tkinter, and the following OS-dependent services:
|
||||
+# Requires Python 3.7+ with Tkinter, and the following OS-dependent services:
|
||||
# posix, posixpath, socket
|
||||
|
||||
# WARNING: this needs to be updated for fetchmail 6.4's SSL options,
|
53
sysconfig.fetchmail
Normal file
53
sysconfig.fetchmail
Normal file
@ -0,0 +1,53 @@
|
||||
## Path: Network/Mail/Fetchmail
|
||||
## Description: Fetchmail init script options
|
||||
## ServiceRestart: fetchmail
|
||||
## Type: integer
|
||||
## Default: 600
|
||||
#
|
||||
# Polling interval in seconds for daemon mode. Mails are regularly
|
||||
# fetched in this interval.
|
||||
#
|
||||
FETCHMAIL_POLLING_INTERVAL="600"
|
||||
|
||||
## Type: yesno
|
||||
## Default: yes
|
||||
#
|
||||
# The default is to retrieve all messages on server. If you want to
|
||||
# retrieve only new messages and keep old (seen) messages, disable
|
||||
# this option.
|
||||
#
|
||||
FETCHMAIL_FETCHALL="yes"
|
||||
|
||||
## Type: yesno
|
||||
## Default: no
|
||||
#
|
||||
# Fetchmail logs by default all retrieved or kept messages. If you do
|
||||
# not want to log every single message fetchmail downloads or keeps on
|
||||
# the server every time it polls, enable this option.
|
||||
#
|
||||
FETCHMAIL_SILENT="no"
|
||||
|
||||
## Type: string
|
||||
## Default: "/var/log/fetchmail"
|
||||
## Options: "/path/to/file", "syslog", ""
|
||||
#
|
||||
# This option allows to redirect status messages in daemon mode to the
|
||||
# specified log file or syslog(3) system if available. If empty, omits
|
||||
# any logging options.
|
||||
#
|
||||
FETCHMAIL_DEFAULT_LOGFILE="/var/log/fetchmail"
|
||||
|
||||
## Type: string
|
||||
## Default: ""
|
||||
#
|
||||
# Any additional fetchmail options. See fetchmail(1) manual page for
|
||||
# more information.
|
||||
#
|
||||
FETCHMAIL_EXPERT_OPTIONS=""
|
||||
|
||||
## Type: string
|
||||
## Default: "/etc/fetchmailrc"
|
||||
#
|
||||
# Use to override default location of fetchmailrc.
|
||||
#
|
||||
FETCHMAIL_RC_PATH="/etc/fetchmailrc"
|
Loading…
x
Reference in New Issue
Block a user