Rewrite the NETRC library to something more general and much shorter,
along with up-to-date information. Get FTP and POP3 to use the new code.
This commit is contained in:
parent
2994678584
commit
c04d46910c
|
@ -1,136 +1,59 @@
|
||||||
\chapter{Reading netrc-files}\label{cha:netrc}
|
\chapter{Parsing Netrc Files}\label{cha:netrc}
|
||||||
%
|
%
|
||||||
\begin{description}
|
The \ex{netrc} structures provides procedures to parse authentication
|
||||||
\item[Used files:] netrc.scm
|
information contained in \ex{~/.netrc}.
|
||||||
\item[Name of the package:] netrc
|
|
||||||
\end{description}
|
|
||||||
%
|
|
||||||
\section{Overview}
|
|
||||||
This module provides procedures to parse authentication information
|
|
||||||
contained in \ex{~/.netrc}.
|
|
||||||
|
|
||||||
On Unix systems the \ex{~/.netrc} file (in the user's home directory)
|
On Unix systems the netrc file may contain information allowing
|
||||||
may contain information allowing automatic login to remote hosts. The
|
automatic login to remote hosts. The format of the file is defined in
|
||||||
format of the file is defined in the \ex{ftp}(1) manual page. Example
|
the \ex{ftp(1)} manual page. Example lines are
|
||||||
lines are
|
%
|
||||||
\begin{alltt}
|
\begin{verbatim}
|
||||||
machine ondine.cict.fr login marsden password secret
|
machine ondine.cict.fr login marsden password secret
|
||||||
default login anonymous password user@site%
|
default login anonymous password user@site
|
||||||
\end{alltt}
|
\end{verbatim}
|
||||||
|
%
|
||||||
The \ex{~/.netrc} file should be protected by appropriate permissions, and
|
The netrc file should be protected by appropriate permissions, and
|
||||||
(like \ex{/usr/bin/ftp}) this library will refuse to read the file if it is
|
(like \ex{/usr/bin/ftp}) this library will refuse to read the file if it is
|
||||||
badly protected. (unlike \ex{ftp} this library will always refuse
|
badly protected. (unlike \ex{ftp} this library will always refuse
|
||||||
to read the file -- \ex{ftp} refuses it only if the password is
|
to read the file----\ex{ftp} refuses it only if the password is
|
||||||
given for a non-default account). Appropriate permissions are set if
|
given for a non-default account). Appropriate permissions are set if
|
||||||
only the user has permissions on the file.
|
only the user has permissions on the file.
|
||||||
|
|
||||||
Note following restrictions and differences:
|
\defun{netrc-machine-entry}{host accept-default? [file-name]}{netrc-entry-or-\sharpf}
|
||||||
\begin{itemize}
|
|
||||||
\item The macdef statement (defining macros) is not supported.
|
|
||||||
\item The settings for one machine must be on a single line.
|
|
||||||
\item The is no error proof while reading the file.
|
|
||||||
\item Default need not be the last line of the netrc-file.
|
|
||||||
\end{itemize}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
\section{Entry points}
|
|
||||||
|
|
||||||
What you probably want, is to read out the default netrc-file. Do the
|
|
||||||
following:
|
|
||||||
\begin{alltt}
|
|
||||||
(let ((netrc-record (netrc:parse)))
|
|
||||||
(netrc:lookup netrc-record "name of the machine"))
|
|
||||||
\end{alltt}
|
|
||||||
|
|
||||||
and you will receive three values: \semvar{login-name},
|
|
||||||
\semvar{password} and \semvar{account-name}. If you only want the
|
|
||||||
login name or the password, use \ex{netrc:\ob{}lookup\=login} or
|
|
||||||
\ex{netrc:\ob{}lookup\=password}, resp.
|
|
||||||
|
|
||||||
You will get either the login / password for the specified machine, or
|
|
||||||
a default login / password if the machine is unknown.
|
|
||||||
|
|
||||||
|
|
||||||
\begin{defundesc}{user-mail-address}{}{string}
|
|
||||||
Calculate the user's email address, as per the Emacs function of the
|
|
||||||
same name. Will take into account the environment variable
|
|
||||||
\ex{REPLYTO}, if set. Otherwise the mail-address will look like
|
|
||||||
\ex{user@\ob{}hostname}.
|
|
||||||
\end{defundesc}
|
|
||||||
|
|
||||||
\defun{netrc:parse} {[filename] [fallback-password] [fallback-login]} {netrc-record}
|
|
||||||
\begin{defundescx}{netrc:try-parse} {filename fallback-password
|
|
||||||
fallback-login} {netrc-record}
|
|
||||||
|
|
||||||
\ex{netrc:parse} parses the netrc file and returns a \ex{netrc}
|
|
||||||
record, containing all necessary information for the following
|
|
||||||
procedures.
|
|
||||||
|
|
||||||
\semvar{filename} defaults to ``~/.netrc'',
|
|
||||||
\semvar{fallback-password} defaults to the result of the call to
|
|
||||||
\ex{user\=mail\=address} and \semvar{fallback-login} defaults to
|
|
||||||
``anonymous''. If the netrc file does not provide a default password
|
|
||||||
or a default login (stated by the ``default'' statement),
|
|
||||||
\semvar{fallback-password} and \semvar{fallback-login} will be used
|
|
||||||
as default password or login, respectively (thus,
|
|
||||||
\ex{user\=mail\=address} is only called if the netrc file does not
|
|
||||||
contain a default specification). If the netrc file does not exist,
|
|
||||||
a netrc-record filled with default values is returned. If the netrc
|
|
||||||
file does not have the correct permissions, a message is printed to
|
|
||||||
the current error port and a netrc-record filled with default values
|
|
||||||
is returned.
|
|
||||||
|
|
||||||
\ex{netrc:try-parse} does the same as \ex{netrc:\ob{}parse}, except
|
|
||||||
of the following: if there is no file called \semvar{filename}, the
|
|
||||||
according error will be raised and if the specified file does not
|
|
||||||
have the correct permissions set, a \ex{netrc\=refuse\=warning} will
|
|
||||||
be signalled. So, if you don't like the error handling and behavior
|
|
||||||
of \ex{netrc:\ob{}parse}, use \ex{netrc:\ob{}try\=parse} and catch
|
|
||||||
the signalled conditions. Note, that \ex{netrc:\ob{}parse} resolves
|
|
||||||
\semvar{filename} for you, \ex{netrc:\ob{}try-parse} does not -- you
|
|
||||||
have to do it on your own.
|
|
||||||
\end{defundescx}
|
|
||||||
|
|
||||||
\defun{netrc:lookup}{netrc-record machine [default?]} {string string string}
|
|
||||||
\defunx{netrc:lookup-password}{netrc-record machine [default?]}{string}
|
|
||||||
\defunx{netrc:lookup-login}{netrc-record machine [default?]}{string}
|
|
||||||
\begin{desc}
|
\begin{desc}
|
||||||
Return the login, password and / or account information for
|
This procedure looks for the entry related to given host in the
|
||||||
\semvar{machine} specified by \semvar{netrc-record}, respectively.
|
user's netrc file. The host is specified in \var{host}.
|
||||||
If \semvar{default?} is \sharpt, default values are returned if no
|
\var{Accept-default?} specifies whether \ex{netrc-machine-entry}
|
||||||
such \semvar{machine} is specified in the \semvar{netrc-record}.
|
should fall back to the default entry if there is no macht for
|
||||||
Otherwise [\sharpf\ \sharpf\ \sharpf] or \sharpf\ is returned,
|
\var{host} in the netrc file. If specified, \var{file-name}
|
||||||
respectively.
|
specifies an alternate file name for the netrc data. It defaults to
|
||||||
|
\ex{.netrc} in the current user's home directory.
|
||||||
|
|
||||||
|
\ex{Netrc-machine-entry} returns a netrc entry (see below) if it was
|
||||||
|
able to find the requested information; if not, it returns \sharpf.
|
||||||
|
|
||||||
|
If the netrc file had inappropriate permissions, \ex{netrc-machine-entry}
|
||||||
|
raises an error.
|
||||||
\end{desc}
|
\end{desc}
|
||||||
|
|
||||||
\defun{netrc:default-login}{netrc-record}{string}
|
\defun{netrc-entry?}{thing}{boolean}
|
||||||
\begin{defundescx}{netrc:default-password}{netrc-record}{string}
|
\defunx{netrc-entry-machine}{netrc-entry}{string}
|
||||||
Return the default values for the login or the password, respectively,
|
\defunx{netrc-entry-login}{netrc-entry}{string-or-\sharpf}
|
||||||
specified by \semvar{netrc-record}. If the netrc file did not
|
\defunx{netrc-entry-password}{netrc-entry}{string-or-\sharpf}
|
||||||
specify a default login, ``anonymous'' is returned by
|
\defunx{netrc-entry-account}{netrc-entry}{string-or-\sharpf}
|
||||||
\ex{netrc:\ob{}default\=login}. If the netrc file did not specify a
|
\begin{desc}
|
||||||
default password, the result of the call to \ex{user\=mail\=address}
|
\ex{Netrc-entry?} is the predicate for netrc entries. The other
|
||||||
is returned by \ex{netrc:\ob{}default\=password}.
|
procedures are selectors for netrc entries as returned by
|
||||||
\end{defundescx}
|
\ex{netrc-machine-entry}. They return \sharpf{} if the netrc file
|
||||||
|
didn't contain a binding for the corresponding field.
|
||||||
|
\end{desc}
|
||||||
|
|
||||||
\section{Related work}
|
\defun{netrc-macro-definitions}{[file-name]}{alist}
|
||||||
\begin{itemize}
|
\begin{desc}
|
||||||
\item Graham Barr has written a similar library for Perl, called
|
This returns the macro definitions from the netrc files, represented
|
||||||
\ex{Netrc.pm}.
|
as an alist mapping macro names---represented as strings---to
|
||||||
\item \ex{ange-ftp.el} (transparent remote file access for Emacs)
|
definitions---represented as lists of strings.
|
||||||
parses the user's netrc file.
|
\end{desc}
|
||||||
\end{itemize}
|
|
||||||
|
|
||||||
\section{Desirable things}
|
|
||||||
\begin{itemize}
|
|
||||||
\item Remove restrictions (as stated in `\emph{Overview}') and behave like
|
|
||||||
\ex{/usr/\ob{}bin/\ob{}ftp} behaves
|
|
||||||
\item perhaps: adding case-insensitivity (for host names)
|
|
||||||
\item perhaps: better record-disclosers for netrc-entry- and
|
|
||||||
netrc-records
|
|
||||||
\end{itemize}
|
|
||||||
|
|
||||||
%%% Local Variables:
|
%%% Local Variables:
|
||||||
%%% mode: latex
|
%%% mode: latex
|
||||||
|
|
|
@ -104,11 +104,11 @@
|
||||||
(cond
|
(cond
|
||||||
(netrc-record)
|
(netrc-record)
|
||||||
(else
|
(else
|
||||||
(set! netrc-record (netrc-parse))
|
(set! netrc-record
|
||||||
|
(netrc-machine-entry (ftp-connection-host-name connection) #t))
|
||||||
netrc-record)))))
|
netrc-record)))))
|
||||||
(let ((login (or login
|
(let ((login (or login
|
||||||
(netrc-lookup-login (get-netrc-record)
|
(netrc-entry-login (get-netrc-record)))))
|
||||||
(ftp-connection-host-name connection)))))
|
|
||||||
(let ((reply
|
(let ((reply
|
||||||
(ftp-send-command connection (build-command "USER" login)
|
(ftp-send-command connection (build-command "USER" login)
|
||||||
(lambda (code)
|
(lambda (code)
|
||||||
|
@ -120,9 +120,7 @@
|
||||||
(build-command
|
(build-command
|
||||||
"PASS"
|
"PASS"
|
||||||
(or password
|
(or password
|
||||||
(netrc-lookup-password (get-netrc-record)
|
(netrc-entry-password (get-netrc-record))))
|
||||||
(ftp-connection-host-name
|
|
||||||
connection))))
|
|
||||||
(exactly-code "230")))))))
|
(exactly-code "230")))))))
|
||||||
|
|
||||||
(define-enumerated-type ftp-type :ftp-type
|
(define-enumerated-type ftp-type :ftp-type
|
||||||
|
|
|
@ -2,393 +2,154 @@
|
||||||
|
|
||||||
;;; This file is part of the Scheme Untergrund Networking package.
|
;;; This file is part of the Scheme Untergrund Networking package.
|
||||||
|
|
||||||
;;; Copyright (c) 1998 by Eric Marsden
|
;;; Copyright (c) 2003 by Mike Sperber <sperber@informatik.uni-tuebingen.de>
|
||||||
;;; Copyright (c) 2002 by Andreas Bernauer.
|
|
||||||
;;; For copyright information, see the file COPYING which comes with
|
;;; For copyright information, see the file COPYING which comes with
|
||||||
;;; the distribution.
|
;;; the distribution.
|
||||||
|
|
||||||
;;; Overview =====================================================
|
(define (check-permissions file-name)
|
||||||
;;
|
(if (not (zero? (bitwise-and #b000111111 (file-mode file-name))))
|
||||||
;; On Unix systems the ~/.netrc file (in the user's home directory)
|
(error "Not parsing netrc file; dangerous permissions."
|
||||||
;; may contain information allowing automatic login to remote hosts.
|
file-name)))
|
||||||
;; The format of the file is defined in the ftp(1) manual page.
|
|
||||||
;; Example lines are
|
|
||||||
;;
|
|
||||||
;; machine ondine.cict.fr login marsden password secret
|
|
||||||
;; default login anonymous password user@site
|
|
||||||
;;
|
|
||||||
;; The ~/.netrc file should be protected by appropriate permissions,
|
|
||||||
;; and (like /usr/bin/ftp) this library will refuse to read the file if
|
|
||||||
;; it is badly protected. (unlike /usr/bin/ftp this library will always
|
|
||||||
;; refuse to read the file -- /usr/bin/ftp refuses it only if the password
|
|
||||||
;; is given for a non-default account). Appropriate permissions are set
|
|
||||||
;; if only the user has permissions on the file.
|
|
||||||
;;
|
|
||||||
;; Note following restrictions / differences:
|
|
||||||
;; * The macdef statement (defining macros) is not supported.
|
|
||||||
;; * The settings for one machine must be on a single line.
|
|
||||||
;; * The is no error proof while reading the file.
|
|
||||||
;; * default need not be the last line of the netrc-file
|
|
||||||
|
|
||||||
|
(define (netrc-file-name)
|
||||||
|
(string-append (file-name-as-directory (home-dir))
|
||||||
|
".netrc"))
|
||||||
|
|
||||||
|
(define (skip-whitespace port)
|
||||||
|
(let loop ()
|
||||||
|
(let ((char (peek-char port)))
|
||||||
|
(cond
|
||||||
|
((eof-object? char)
|
||||||
|
(values))
|
||||||
|
((char-set-contains? char-set:whitespace char)
|
||||||
|
(read-char port)
|
||||||
|
(loop))
|
||||||
|
(else (values))))))
|
||||||
|
|
||||||
;;; Entry points =======================================================
|
(define (skip-until-eol port)
|
||||||
;;
|
(let loop ()
|
||||||
;; What you probably want, is to read out the default netrc-file. Do the
|
(let ((char (peek-char port)))
|
||||||
;; following:
|
(cond
|
||||||
;;
|
((eof-object? char)
|
||||||
;; (let ((netrc-record (netrc-parse)))
|
(values))
|
||||||
;; (netrc-lookup netrc-record "name of the machine"))
|
((char=? #\newline char)
|
||||||
;;
|
(read-char port))
|
||||||
;; and you will receive three values: login-name, password and account-name.
|
(else
|
||||||
;; If you only want the login-name or the password, use netrc-lookup-login
|
(read-char port)
|
||||||
;; or netrc-lookup-password resp.
|
(loop))))))
|
||||||
;;
|
|
||||||
;; You will get either the login / password for the specified machine,
|
|
||||||
;; or a default login / password if the machine is unknown.
|
|
||||||
;;
|
|
||||||
;;
|
|
||||||
;; (user-mail-address) -> string
|
|
||||||
;; Calculate the user's email address, as per the Emacs function of
|
|
||||||
;; the same name. Will take into account the environment variable
|
|
||||||
;; REPLYTO, if set. Otherwise the mail-address will look like
|
|
||||||
;; user@hostname.
|
|
||||||
;;
|
|
||||||
;; (netrc-parse [filename [fallback-password [fallback-login]]])
|
|
||||||
;; -> netrc-record
|
|
||||||
;; * parses the netrc file and returns a netrc-record, containing all
|
|
||||||
;; necessary information for the following procedures.
|
|
||||||
;; * FILENAME defaults to "~/.netrc"
|
|
||||||
;; FALLBACK-PASSWORD defaults to the result of (user-mail-address)
|
|
||||||
;; FALLBACK-LOGIN defaults to "anonymous"
|
|
||||||
;; * if the netrc file does not provide a default password or a default
|
|
||||||
;; login (stated by the "default" statement), FALLBACK-PASSWORD and
|
|
||||||
;; FALLBACK-LOGIN will be used as default password or login, respectively.
|
|
||||||
;; (thus, user-mail-address is only called if the netrc file does not
|
|
||||||
;; contain a default specification)
|
|
||||||
;; * if the netrc file does not exist, a netrc-record filled with
|
|
||||||
;; default values is returned.
|
|
||||||
;; * if the netrc file does not have the correct permissions, a message is
|
|
||||||
;; printed to current error port and a netrc-record filled with default
|
|
||||||
;; values is returned.
|
|
||||||
;;
|
|
||||||
;; (netrc-try-parse filename fallback-password fallback-login) -> netrc-record
|
|
||||||
;; parses the netrc file and returns a netrc-record, containing all
|
|
||||||
;; necessary information for the following procedures.
|
|
||||||
;; if there is no file called FILENAME, the according error will be raised
|
|
||||||
;; if the specified file does not have the correct permissions set,
|
|
||||||
;; a netrc-refuse-warning will be signalled.
|
|
||||||
;; so if you don't like the error handling of netrc-parse, use
|
|
||||||
;; netrc-try-parse and catch the signalled conditions.
|
|
||||||
;;
|
|
||||||
;; (netrc-lookup netrc-record machine [default?]) -> string x string x string
|
|
||||||
;; Return the login,password,account information for MACHINE
|
|
||||||
;; specified by the netrc file.
|
|
||||||
;; If DEFAULT? is #t, default values are returned if no such
|
|
||||||
;; MACHINE is specified in the netrc file. Otherwise, #f,#f,#f
|
|
||||||
;; is returned
|
|
||||||
;;
|
|
||||||
;; (netrc-lookup-password netrc-record machine [default?]) -> string
|
|
||||||
;; Return the password information for MACHINE specified by the
|
|
||||||
;; netrc file.
|
|
||||||
;; If DEFAULT? is #t, the default password is returned if no such
|
|
||||||
;; MACHINE is specified. Otherwise, #f is returned.
|
|
||||||
;;
|
|
||||||
;; (netrc-lookup-login netrc-record machine [default?]) -> string
|
|
||||||
;; Return the login information for MACHINE specified by the
|
|
||||||
;; netrc file.
|
|
||||||
;; If DEFAULT? is #t, the default login is returned if no such
|
|
||||||
;; MACHINE is specified. Otherwise, #f is returned.
|
|
||||||
;;
|
|
||||||
;; (netrc-default-login netrc-record) -> string
|
|
||||||
;; Return the default login specified by the netrc file or "anonymous"
|
|
||||||
;;
|
|
||||||
;; (netrc-default-password netrc-record) -> string
|
|
||||||
;; Return the default password specified by the netrc file or
|
|
||||||
;; the mail-addres (result of (user-mail-address))
|
|
||||||
|
|
||||||
|
(define (read-lines-until-double-eol port)
|
||||||
|
(let loop ((reverse-lines '()))
|
||||||
|
(let ((line (read-line port)))
|
||||||
|
(if (or (eof-object? line)
|
||||||
|
(string=? "" line))
|
||||||
|
(reverse reverse-lines)
|
||||||
|
(loop (cons line reverse-lines))))))
|
||||||
|
|
||||||
|
(define (next-token port)
|
||||||
|
(skip-whitespace port)
|
||||||
|
(let loop ((reverse-chars '()))
|
||||||
|
|
||||||
;;; Related work ========================================================
|
(define (token)
|
||||||
;;
|
(if (null? reverse-chars)
|
||||||
;; * Graham Barr has written a similar library for Perl, called
|
#f
|
||||||
;; Netrc.pm
|
(list->string (reverse reverse-chars))))
|
||||||
;;
|
|
||||||
;; * EFS (transparent remote file access for Emacs) parses the
|
|
||||||
;; user's netrc file
|
|
||||||
|
|
||||||
|
(let ((char (peek-char port)))
|
||||||
|
(cond
|
||||||
|
((eof-object? char) (token))
|
||||||
|
((char-set-contains? char-set:whitespace char) (token))
|
||||||
|
(else
|
||||||
|
(loop (cons (read-char port) reverse-chars)))))))
|
||||||
|
|
||||||
;;; Desirable things =============================================
|
(define (next-field port)
|
||||||
;;
|
(let ((token (next-token port)))
|
||||||
;; * Remove restrictions (as stated in 'Overview') and behave like
|
(cond
|
||||||
;; /usr/bin/ftp behaves
|
((not token)
|
||||||
;; * perhaps: adding case-insensitivity (for host names)
|
(values #f #f))
|
||||||
;; * perhaps: better record-disclosers for netrc-entry- and netrc-records
|
((string=? "default" token)
|
||||||
|
(values token #f))
|
||||||
|
((string=? "macdef" token)
|
||||||
|
(let ((name (next-token port)))
|
||||||
|
(skip-until-eol port)
|
||||||
|
(values token
|
||||||
|
(cons name (read-lines-until-double-eol port)))))
|
||||||
|
(else
|
||||||
|
(values token (next-token port))))))
|
||||||
|
|
||||||
|
(define (skip-until-machine port machine accept-default?)
|
||||||
|
(let loop ()
|
||||||
|
(call-with-values
|
||||||
|
(lambda () (next-field port))
|
||||||
|
(lambda (tag value)
|
||||||
|
(cond
|
||||||
|
((not tag) #f)
|
||||||
|
((and accept-default? (string=? "default" tag))
|
||||||
|
#t)
|
||||||
|
((and (string=? tag "machine")
|
||||||
|
(string-ci=? machine value))
|
||||||
|
#t)
|
||||||
|
(else
|
||||||
|
(loop)))))))
|
||||||
|
|
||||||
; return the user's mail address, either specified by the environment
|
(define (next-macro-definition port)
|
||||||
; variable REPLYTO or "user@hostname".
|
(let loop ()
|
||||||
(define (user-mail-address)
|
(call-with-values
|
||||||
(or (getenv "REPLYTO")
|
(lambda () (next-field port))
|
||||||
(string-append (user-login-name) "@" (system-fqdn))))
|
(lambda (tag value)
|
||||||
|
(cond
|
||||||
|
((not tag) #f)
|
||||||
; looks up the desired machine in a netrc-record
|
((string=? "macdef" tag) value)
|
||||||
; if the machine is found in the entries-section
|
(else (loop)))))))
|
||||||
; following three values are returned: login, password and account
|
|
||||||
; if the machine is not found in the entries-section
|
|
||||||
; the behavior depends on lookup-default? which defaults to #t:
|
|
||||||
; if lookup-default? is #t
|
|
||||||
; following three values are returned: default-login default-password #f
|
|
||||||
; otherwise #f #f #f is returned.
|
|
||||||
(define (netrc-lookup netrc-record machine . lookup-default?)
|
|
||||||
(let-optionals lookup-default?
|
|
||||||
((lookup-default? #t))
|
|
||||||
(let ((record (find-record netrc-record machine)))
|
|
||||||
(if record
|
|
||||||
(values (netrc-entry-login record)
|
|
||||||
(netrc-entry-password record)
|
|
||||||
(netrc-entry-account record))
|
|
||||||
(if lookup-default?
|
|
||||||
(values (netrc-default-login netrc-record)
|
|
||||||
(netrc-default-password netrc-record)
|
|
||||||
#f)
|
|
||||||
(values #f #f #f))))))
|
|
||||||
|
|
||||||
; does the same as netrc-lookup, but returns only the password (or #f)
|
|
||||||
(define (netrc-lookup-password netrc-record machine . lookup-default?)
|
|
||||||
(let-optionals lookup-default?
|
|
||||||
((lookup-default? #t))
|
|
||||||
(let ((record (find-record netrc-record machine)))
|
|
||||||
(if record
|
|
||||||
(netrc-entry-password record)
|
|
||||||
(and lookup-default?
|
|
||||||
(netrc-default-password netrc-record))))))
|
|
||||||
|
|
||||||
; does the same as netrc-lookup, but returns only the login (or #f)
|
|
||||||
(define (netrc-lookup-login netrc-record machine . lookup-default?)
|
|
||||||
(let-optionals lookup-default?
|
|
||||||
((lookup-default? #t))
|
|
||||||
(let ((record (find-record netrc-record machine)))
|
|
||||||
(if record
|
|
||||||
(netrc-entry-login record)
|
|
||||||
(and lookup-default?
|
|
||||||
(netrc-default-login netrc-record))))))
|
|
||||||
|
|
||||||
; does the work for netrc-parse
|
|
||||||
; file-name has to be resolved
|
|
||||||
(define (netrc-try-parse file-name default-password default-login)
|
|
||||||
(netrc-check-permissions file-name)
|
|
||||||
(let ((fd (open-input-file file-name))
|
|
||||||
(netrc-record (make-netrc '() default-password default-login file-name)))
|
|
||||||
(for-each-line (parse-line netrc-record) fd)))
|
|
||||||
|
|
||||||
; parses the netrc-file
|
|
||||||
; expected arguments: filename default-password default-login
|
|
||||||
; filename: filename of the .netrc-file (defaults to ~/.netrc)
|
|
||||||
; default-password: default password for any not specified machine
|
|
||||||
; defaults to (user-mail-address)
|
|
||||||
; default password in netrc-file overwrites this setting
|
|
||||||
; default-login: default login name for any not specified machine
|
|
||||||
; defaults to "anonymous"
|
|
||||||
; default login in netrc-file overwrites this setting
|
|
||||||
; * (default-login is expected after default-password as users usually want
|
|
||||||
; to change the default-password (to something else than their mail-address)
|
|
||||||
; rather than the login-name)(define (netrc-parse . args)
|
|
||||||
; * if the given file does not exist or it has the wrong permissions,
|
|
||||||
; than a default netrc-record is returned
|
|
||||||
; * if you don't want expected errors to be captured, use netrc-try-parse;
|
|
||||||
; note that you have to resolve the file-name on your own
|
|
||||||
(define-condition-type 'netrc-refuse '(warning))
|
|
||||||
(define netrc-refuse? (condition-predicate 'netrc-refuse))
|
|
||||||
|
|
||||||
(define (netrc-parse . args)
|
|
||||||
(let-optionals
|
|
||||||
args ((file-name "~/.netrc")
|
|
||||||
(default-password #f) ; both ...
|
|
||||||
(default-login #f)) ; ... are set if netrc-file does
|
|
||||||
; not provide default-values
|
|
||||||
(let* ((file-name (resolve-file-name file-name))
|
|
||||||
(local-default-login (lambda () "anonymous"))
|
|
||||||
(local-default-password (lambda () (user-mail-address)))
|
|
||||||
(local-default-netrc-record
|
|
||||||
(lambda ()
|
|
||||||
(make-netrc '()
|
|
||||||
(or default-login (local-default-login))
|
|
||||||
(or default-password (local-default-password))
|
|
||||||
#f))))
|
|
||||||
; i know, this double-handler sucks; has anyone a better idea?
|
|
||||||
(call-with-current-continuation
|
|
||||||
(lambda (exit)
|
|
||||||
(with-handler
|
|
||||||
(lambda (error more)
|
|
||||||
(if (netrc-refuse? error)
|
|
||||||
(format (current-error-port)
|
|
||||||
"netrc- Warning: ~a~%"
|
|
||||||
(car (condition-stuff error)))
|
|
||||||
(format (current-error-port)
|
|
||||||
"netrc- Warning: Unexpected error encountered: ~s~%"
|
|
||||||
error))
|
|
||||||
(exit (local-default-netrc-record)))
|
|
||||||
(lambda ()
|
|
||||||
(with-errno-handler*
|
|
||||||
(lambda (errno packet)
|
|
||||||
(if (= errno errno/noent)
|
|
||||||
(format (current-error-port)
|
|
||||||
"netrc- Warning: no such file or directory: ~a~%"
|
|
||||||
file-name)
|
|
||||||
(format (current-error-port)
|
|
||||||
"netrc- Warning: Error accessing file ~s~%"
|
|
||||||
file-name))
|
|
||||||
(exit (local-default-netrc-record)))
|
|
||||||
(lambda ()
|
|
||||||
(let ((netrc-record
|
|
||||||
(netrc-try-parse file-name default-password default-login)))
|
|
||||||
; If we get a netrc-record, we return it after
|
|
||||||
; checking default login and default password settings.
|
|
||||||
; Otherwise, we return the default record with
|
|
||||||
; file-name stored.
|
|
||||||
; This is sub-optimal, as we may throw away badly
|
|
||||||
; structured .netrc-files silently. We need an error
|
|
||||||
; checking mechanism.
|
|
||||||
(if (netrc? netrc-record)
|
|
||||||
(begin
|
|
||||||
(if (eq? (netrc-default-login netrc-record) #f)
|
|
||||||
(set-netrc-default-login! netrc-record (local-default-login)))
|
|
||||||
(if (eq? (netrc-default-password netrc-record) #f)
|
|
||||||
(set-netrc-default-password! netrc-record (local-default-password)))
|
|
||||||
netrc-record)
|
|
||||||
(let ((default-netrc-record (local-default-netrc-record)))
|
|
||||||
(set-netrc-file-name! default-netrc-record file-name)
|
|
||||||
default-netrc-record))))))))))))
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
||||||
;; nothing exported below
|
|
||||||
;; except
|
|
||||||
;; netrc-default-password
|
|
||||||
;; netrc-default-login
|
|
||||||
|
|
||||||
(define-record-type netrc-entry :netrc-entry
|
(define-record-type netrc-entry :netrc-entry
|
||||||
(make-netrc-entry machine login password account)
|
(make-netrc-entry machine login password account)
|
||||||
netrc-entry?
|
netrc-entry?
|
||||||
(machine netrc-entry-machine)
|
(machine netrc-entry-machine set-netrc-entry-machine!)
|
||||||
(login netrc-entry-login)
|
(login netrc-entry-login set-netrc-entry-login!)
|
||||||
(password netrc-entry-password)
|
(password netrc-entry-password set-netrc-entry-password!)
|
||||||
(account netrc-entry-account))
|
(account netrc-entry-account set-netrc-entry-account!))
|
||||||
|
|
||||||
(define-record-type netrc :netrc
|
(define (netrc-machine-entry machine accept-default? . maybe-file-name)
|
||||||
(make-netrc entries default-login default-password file-name)
|
(let ((file-name (if (pair? maybe-file-name)
|
||||||
netrc?
|
(car maybe-file-name)
|
||||||
;; list of netrc-entrys
|
(netrc-file-name)))
|
||||||
(entries netrc-entries set-netrc-entries!)
|
(entry (make-netrc-entry machine #f #f #f)))
|
||||||
;; default-values (either library-default or netrc-file-default)
|
(check-permissions file-name)
|
||||||
(default-login netrc-default-login set-netrc-default-login!)
|
(call-with-input-file file-name
|
||||||
(default-password netrc-default-password set-netrc-default-password!)
|
(lambda (port)
|
||||||
(file-name netrc-file-name set-netrc-file-name!))
|
(if (not (skip-until-machine port machine accept-default?))
|
||||||
|
#f
|
||||||
|
(let loop ()
|
||||||
|
(call-with-values
|
||||||
|
(lambda () (next-field port))
|
||||||
|
(lambda (tag value)
|
||||||
|
(cond
|
||||||
|
((not tag) entry)
|
||||||
|
((or (string=? "default" tag)
|
||||||
|
(string=? "machine" tag))
|
||||||
|
entry)
|
||||||
|
((string=? "login" tag)
|
||||||
|
(set-netrc-entry-login! entry value)
|
||||||
|
(loop))
|
||||||
|
((string=? "password" tag)
|
||||||
|
(set-netrc-entry-password! entry value)
|
||||||
|
(loop))
|
||||||
|
((string=? "account" tag)
|
||||||
|
(set-netrc-entry-account! entry value)
|
||||||
|
(loop))
|
||||||
|
(else (loop)))))))))))
|
||||||
|
|
||||||
|
(define (netrc-macro-definitions . maybe-file-name)
|
||||||
(define-record-discloser :netrc-entry
|
(let ((file-name (if (pair? maybe-file-name)
|
||||||
(lambda (netrc-entry)
|
(car maybe-file-name)
|
||||||
(list 'netrc-entry))) ; perhaps something else later on
|
(netrc-file-name))))
|
||||||
|
(check-permissions file-name)
|
||||||
(define-record-discloser :netrc
|
(call-with-input-file file-name
|
||||||
(lambda (netrc)
|
(lambda (port)
|
||||||
(list 'netrc))) ; perhaps something else later on
|
(let loop ((reverse-alist '()))
|
||||||
|
(cond
|
||||||
; finds a record in the entries-list of a netrc-record
|
((next-macro-definition port)
|
||||||
; matching the given machine
|
=> (lambda (pair)
|
||||||
; returns the netrc-entry-record if found, otherwise #f
|
(loop (cons pair reverse-alist))))
|
||||||
(define (find-record netrc-record machine)
|
(else (reverse reverse-alist))))))))
|
||||||
(find-first (lambda (rec)
|
|
||||||
(and (equal? (netrc-entry-machine rec) machine)
|
|
||||||
rec))
|
|
||||||
(netrc-entries netrc-record)))
|
|
||||||
|
|
||||||
|
|
||||||
;; raise error if any permissions are set for group or others.
|
|
||||||
(define (netrc-check-permissions file-name)
|
|
||||||
(let ((perms (- (file-mode file-name) 32768)))
|
|
||||||
(if (positive? (bitwise-and #b000111111 perms))
|
|
||||||
(signal 'netrc-refuse
|
|
||||||
(format #f
|
|
||||||
"Not parsing ~s (netrc file); dangerous permissions."
|
|
||||||
file-name)))))
|
|
||||||
|
|
||||||
; tries to match target on line and returns the first group,
|
|
||||||
; or #f if there is no match
|
|
||||||
(define (try-match target line)
|
|
||||||
(let ((match (string-match target line)))
|
|
||||||
(and match
|
|
||||||
(match:substring match 1))))
|
|
||||||
|
|
||||||
; parses the default line of the netrc-file
|
|
||||||
(define (parse-default netrc-record line)
|
|
||||||
(let ((login (try-match "login[ \t]+([^ \t]+)" line))
|
|
||||||
(password (try-match "password[ \t]+([^ \t]+)" line)))
|
|
||||||
(if login
|
|
||||||
(set-netrc-default-login! netrc-record login))
|
|
||||||
(if password
|
|
||||||
(set-netrc-default-password! netrc-record password))
|
|
||||||
netrc-record))
|
|
||||||
|
|
||||||
; parses a line of the netrc-file
|
|
||||||
(define (parse-line netrc-record)
|
|
||||||
(lambda (line)
|
|
||||||
(cond ((string-match "default" line)
|
|
||||||
(parse-default netrc-record line))
|
|
||||||
(else
|
|
||||||
(let ((machine (try-match "machine[ \t]+([^ \t]+)" line))
|
|
||||||
(login (try-match "login[ \t]+([^ \t]+)" line))
|
|
||||||
(password (try-match "password[ \t]+([^ \t]+)" line))
|
|
||||||
(account (try-match "account[ \t]+([^ \t]+)" line)))
|
|
||||||
(if (or machine login password account)
|
|
||||||
(add netrc-record machine login password account)
|
|
||||||
netrc-record)))))) ; return record on empty / wrong lines
|
|
||||||
; (This is a workaround. we should give a warning on malicious .netrc
|
|
||||||
; files. As we do not have an error checking system installed yet, we
|
|
||||||
; skip these lines silently.)
|
|
||||||
|
|
||||||
; adds machine login password account stored in a netrc-entry-record
|
|
||||||
; to the entries-list of a netrc-record
|
|
||||||
(define (add netrc-record machine login password account)
|
|
||||||
(set-netrc-entries! netrc-record
|
|
||||||
(cons (make-netrc-entry machine login password account)
|
|
||||||
(netrc-entries netrc-record)))
|
|
||||||
netrc-record)
|
|
||||||
|
|
||||||
;; for testing
|
|
||||||
(define (netrc-dump netrc-record)
|
|
||||||
(format #t "~%--- Dumping ~s contents ---" (netrc-file-name netrc-record))
|
|
||||||
(for-each (lambda (rec)
|
|
||||||
(format #t "~% machine ~a login ~a password ~a account ~a"
|
|
||||||
(netrc-entry-machine rec)
|
|
||||||
(netrc-entry-login rec)
|
|
||||||
(netrc-entry-password rec)
|
|
||||||
(netrc-entry-account rec)))
|
|
||||||
(netrc-entries netrc-record))
|
|
||||||
(format #t "~% default login: ~s" (netrc-default-login netrc-record))
|
|
||||||
(format #t "~% default password: ~s" (netrc-default-password netrc-record))
|
|
||||||
(format #t "~%--- End of ~s contents ---~%" (netrc-file-name netrc-record)))
|
|
||||||
|
|
||||||
|
|
||||||
; runs proc for each line of fd (line is argument to proc)
|
|
||||||
; returns either nothing, if the fd had no line
|
|
||||||
; or the value returned by proc called on the last line
|
|
||||||
(define (for-each-line proc fd)
|
|
||||||
(let ((line (read-line fd)))
|
|
||||||
(if (not (eof-object? line))
|
|
||||||
(let loop ((last-result (proc line)))
|
|
||||||
(let ((line (read-line fd)))
|
|
||||||
(if (not (eof-object? line))
|
|
||||||
(loop (proc line))
|
|
||||||
last-result))))))
|
|
||||||
|
|
||||||
; finds first element in l for which pred doesn't return #f
|
|
||||||
; returns either #f (no such element found)
|
|
||||||
; or the result of the last call to pred
|
|
||||||
(define (find-first pred l)
|
|
||||||
(if (null? l) #f
|
|
||||||
(or (pred (car l))
|
|
||||||
(find-first pred (cdr l)))))
|
|
||||||
|
|
||||||
;; EOF
|
|
||||||
|
|
|
@ -91,16 +91,22 @@
|
||||||
(cond
|
(cond
|
||||||
(netrc-record)
|
(netrc-record)
|
||||||
(else
|
(else
|
||||||
(set! netrc-record (netrc-parse))
|
(set! netrc-record
|
||||||
|
(netrc-machine-entry (pop3-connection-host-name connection) #f))
|
||||||
netrc-record)))))
|
netrc-record)))))
|
||||||
(let ((login (or login
|
(let ((login (or login
|
||||||
(netrc-lookup-login (get-netrc-record)
|
(begin
|
||||||
(pop3-connection-host-name connection)
|
(if (or (not (get-netrc-record))
|
||||||
#f)))
|
(not (netrc-entry-login (get-netrc-record))))
|
||||||
|
(signal 'pop3-error
|
||||||
|
"no login record specified and no netrc entry"))
|
||||||
|
(netrc-entry-login (get-netrc-record)))))
|
||||||
(password (or password
|
(password (or password
|
||||||
(netrc-lookup-password (get-netrc-record)
|
(begin
|
||||||
(pop3-connection-host-name connection)
|
(if (not (netrc-entry-password (get-netrc-record)))
|
||||||
#f))))
|
(signal 'pop3-error
|
||||||
|
"no password record specified and no netrc entry"))
|
||||||
|
(netrc-entry-password (get-netrc-record))))))
|
||||||
(with-fatal-error-handler*
|
(with-fatal-error-handler*
|
||||||
(lambda (result punt)
|
(lambda (result punt)
|
||||||
(cond
|
(cond
|
||||||
|
|
|
@ -114,13 +114,13 @@
|
||||||
copy-ascii-port->port))
|
copy-ascii-port->port))
|
||||||
|
|
||||||
(define-interface netrc-interface
|
(define-interface netrc-interface
|
||||||
(export user-mail-address
|
(export netrc-machine-entry
|
||||||
netrc-lookup
|
netrc-entry?
|
||||||
netrc-lookup-password
|
netrc-entry-machine
|
||||||
netrc-lookup-login
|
netrc-entry-login
|
||||||
netrc-parse
|
netrc-entry-password
|
||||||
netrc-try-parse
|
netrc-entry-account
|
||||||
netrc-refuse?))
|
netrc-macro-definitions))
|
||||||
|
|
||||||
(define-interface pop3-interface
|
(define-interface pop3-interface
|
||||||
(export pop3-connect
|
(export pop3-connect
|
||||||
|
@ -434,9 +434,7 @@
|
||||||
(define-structure netrc netrc-interface
|
(define-structure netrc netrc-interface
|
||||||
(open scheme-with-scsh
|
(open scheme-with-scsh
|
||||||
define-record-types
|
define-record-types
|
||||||
conditions signals handle
|
srfi-14)
|
||||||
sunet-utilities
|
|
||||||
let-opt)
|
|
||||||
(files (lib netrc)))
|
(files (lib netrc)))
|
||||||
|
|
||||||
(define-structure pop3 pop3-interface
|
(define-structure pop3 pop3-interface
|
||||||
|
|
Loading…
Reference in New Issue