diff options
| author | Glenn Morris | 2007-12-02 21:52:46 +0000 |
|---|---|---|
| committer | Glenn Morris | 2007-12-02 21:52:46 +0000 |
| commit | 369fc5a6265998ababe34519f48732ad7fb335fc (patch) | |
| tree | 1389515bdc4181f45b7727a387a09fe01246a199 | |
| parent | 323fc9ec1af6e911a86db428cc38cdcdc5c31c75 (diff) | |
| download | emacs-369fc5a6265998ababe34519f48732ad7fb335fc.tar.gz emacs-369fc5a6265998ababe34519f48732ad7fb335fc.zip | |
Move here from ../gnus.
| -rw-r--r-- | lisp/ChangeLog | 6 | ||||
| -rw-r--r-- | lisp/net/sasl-cram.el | 52 | ||||
| -rw-r--r-- | lisp/net/sasl-digest.el | 159 | ||||
| -rw-r--r-- | lisp/net/sasl-ntlm.el | 68 | ||||
| -rw-r--r-- | lisp/net/sasl.el | 273 |
5 files changed, 558 insertions, 0 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 9038d2b98dc..bec72ccb1f2 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -13,6 +13,9 @@ | |||
| 13 | 13 | ||
| 14 | 2007-12-02 Glenn Morris <rgm@gnu.org> | 14 | 2007-12-02 Glenn Morris <rgm@gnu.org> |
| 15 | 15 | ||
| 16 | * emacs-lisp/bytecomp.el (byte-compile-declare-function): Reverse | ||
| 17 | branches of if statement. | ||
| 18 | |||
| 16 | * emulation/viper-cmd.el (top-level): Don't require advice. | 19 | * emulation/viper-cmd.el (top-level): Don't require advice. |
| 17 | Don't load viper-util, viper-keym, viper-mous, viper-macs, | 20 | Don't load viper-util, viper-keym, viper-mous, viper-macs, |
| 18 | viper-ex when compiling. | 21 | viper-ex when compiling. |
| @@ -37,6 +40,9 @@ | |||
| 37 | * emulation/viper.el (top-level): Don't require ring. | 40 | * emulation/viper.el (top-level): Don't require ring. |
| 38 | Don't load viper-init, viper-cmd when compiling. | 41 | Don't load viper-init, viper-cmd when compiling. |
| 39 | 42 | ||
| 43 | * net/sasl-cram.el, net/sasl-digest.el, net/sasl-ntlm.el, net/sasl.el: | ||
| 44 | Move here from gnus/. | ||
| 45 | |||
| 40 | 2007-12-02 Karl Fogel <kfogel@red-bean.com> | 46 | 2007-12-02 Karl Fogel <kfogel@red-bean.com> |
| 41 | 47 | ||
| 42 | Offer option for saveplace to be quiet about loading and saving. | 48 | Offer option for saveplace to be quiet about loading and saving. |
diff --git a/lisp/net/sasl-cram.el b/lisp/net/sasl-cram.el new file mode 100644 index 00000000000..32f1e69f81f --- /dev/null +++ b/lisp/net/sasl-cram.el | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | ;;; sasl-cram.el --- CRAM-MD5 module for the SASL client framework | ||
| 2 | |||
| 3 | ;; Copyright (C) 2000, 2007 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: Daiki Ueno <ueno@unixuser.org> | ||
| 6 | ;; Kenichi OKADA <okada@opaopa.org> | ||
| 7 | ;; Keywords: SASL, CRAM-MD5 | ||
| 8 | |||
| 9 | ;; This file is part of GNU Emacs. | ||
| 10 | |||
| 11 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 12 | ;; it under the terms of the GNU General Public License as published by | ||
| 13 | ;; the Free Software Foundation; either version 3, or (at your option) | ||
| 14 | ;; any later version. | ||
| 15 | |||
| 16 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 19 | ;; GNU General Public License for more details. | ||
| 20 | |||
| 21 | ;; You should have received a copy of the GNU General Public License | ||
| 22 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 23 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 24 | ;; Boston, MA 02110-1301, USA. | ||
| 25 | |||
| 26 | ;;; Commentary: | ||
| 27 | |||
| 28 | (require 'sasl) | ||
| 29 | (require 'hmac-md5) | ||
| 30 | |||
| 31 | (defconst sasl-cram-md5-steps | ||
| 32 | '(ignore ;no initial response | ||
| 33 | sasl-cram-md5-response)) | ||
| 34 | |||
| 35 | (defun sasl-cram-md5-response (client step) | ||
| 36 | (let ((passphrase | ||
| 37 | (sasl-read-passphrase | ||
| 38 | (format "CRAM-MD5 passphrase for %s: " | ||
| 39 | (sasl-client-name client))))) | ||
| 40 | (unwind-protect | ||
| 41 | (concat (sasl-client-name client) " " | ||
| 42 | (encode-hex-string | ||
| 43 | (hmac-md5 (sasl-step-data step) passphrase))) | ||
| 44 | (fillarray passphrase 0)))) | ||
| 45 | |||
| 46 | (put 'sasl-cram 'sasl-mechanism | ||
| 47 | (sasl-make-mechanism "CRAM-MD5" sasl-cram-md5-steps)) | ||
| 48 | |||
| 49 | (provide 'sasl-cram) | ||
| 50 | |||
| 51 | ;;; arch-tag: 46cb281b-975a-4fe0-a39f-3018691b1b05 | ||
| 52 | ;;; sasl-cram.el ends here | ||
diff --git a/lisp/net/sasl-digest.el b/lisp/net/sasl-digest.el new file mode 100644 index 00000000000..6c544518e7f --- /dev/null +++ b/lisp/net/sasl-digest.el | |||
| @@ -0,0 +1,159 @@ | |||
| 1 | ;;; sasl-digest.el --- DIGEST-MD5 module for the SASL client framework | ||
| 2 | |||
| 3 | ;; Copyright (C) 2000, 2007 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: Daiki Ueno <ueno@unixuser.org> | ||
| 6 | ;; Kenichi OKADA <okada@opaopa.org> | ||
| 7 | ;; Keywords: SASL, DIGEST-MD5 | ||
| 8 | |||
| 9 | ;; This file is part of GNU Emacs. | ||
| 10 | |||
| 11 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 12 | ;; it under the terms of the GNU General Public License as published by | ||
| 13 | ;; the Free Software Foundation; either version 3, or (at your option) | ||
| 14 | ;; any later version. | ||
| 15 | |||
| 16 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 19 | ;; GNU General Public License for more details. | ||
| 20 | |||
| 21 | ;; You should have received a copy of the GNU General Public License | ||
| 22 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 23 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 24 | ;; Boston, MA 02110-1301, USA. | ||
| 25 | |||
| 26 | ;;; Commentary: | ||
| 27 | |||
| 28 | ;; This program is implemented from draft-leach-digest-sasl-05.txt. | ||
| 29 | ;; | ||
| 30 | ;; It is caller's responsibility to base64-decode challenges and | ||
| 31 | ;; base64-encode responses in IMAP4 AUTHENTICATE command. | ||
| 32 | ;; | ||
| 33 | ;; Passphrase should be longer than 16 bytes. (See RFC 2195) | ||
| 34 | |||
| 35 | ;;; Commentary: | ||
| 36 | |||
| 37 | (require 'sasl) | ||
| 38 | (require 'hmac-md5) | ||
| 39 | |||
| 40 | (defvar sasl-digest-md5-nonce-count 1) | ||
| 41 | (defvar sasl-digest-md5-unique-id-function | ||
| 42 | sasl-unique-id-function) | ||
| 43 | |||
| 44 | (defvar sasl-digest-md5-syntax-table | ||
| 45 | (let ((table (make-syntax-table))) | ||
| 46 | (modify-syntax-entry ?= "." table) | ||
| 47 | (modify-syntax-entry ?, "." table) | ||
| 48 | table) | ||
| 49 | "A syntax table for parsing digest-challenge attributes.") | ||
| 50 | |||
| 51 | (defconst sasl-digest-md5-steps | ||
| 52 | '(ignore ;no initial response | ||
| 53 | sasl-digest-md5-response | ||
| 54 | ignore)) ;"" | ||
| 55 | |||
| 56 | (defun sasl-digest-md5-parse-string (string) | ||
| 57 | "Parse STRING and return a property list. | ||
| 58 | The value is a cons cell of the form \(realm nonce qop-options stale maxbuf | ||
| 59 | charset algorithm cipher-opts auth-param)." | ||
| 60 | (with-temp-buffer | ||
| 61 | (set-syntax-table sasl-digest-md5-syntax-table) | ||
| 62 | (save-excursion | ||
| 63 | (insert string) | ||
| 64 | (goto-char (point-min)) | ||
| 65 | (insert "(") | ||
| 66 | (while (progn (forward-sexp) (not (eobp))) | ||
| 67 | (delete-char 1) | ||
| 68 | (insert " ")) | ||
| 69 | (insert ")") | ||
| 70 | (read (point-min-marker))))) | ||
| 71 | |||
| 72 | (defun sasl-digest-md5-digest-uri (serv-type host &optional serv-name) | ||
| 73 | (concat serv-type "/" host | ||
| 74 | (if (and serv-name | ||
| 75 | (not (string= host serv-name))) | ||
| 76 | (concat "/" serv-name)))) | ||
| 77 | |||
| 78 | (defun sasl-digest-md5-cnonce () | ||
| 79 | (let ((sasl-unique-id-function sasl-digest-md5-unique-id-function)) | ||
| 80 | (sasl-unique-id))) | ||
| 81 | |||
| 82 | (defun sasl-digest-md5-response-value (username | ||
| 83 | realm | ||
| 84 | nonce | ||
| 85 | cnonce | ||
| 86 | nonce-count | ||
| 87 | qop | ||
| 88 | digest-uri | ||
| 89 | authzid) | ||
| 90 | (let ((passphrase | ||
| 91 | (sasl-read-passphrase | ||
| 92 | (format "DIGEST-MD5 passphrase for %s: " | ||
| 93 | username)))) | ||
| 94 | (unwind-protect | ||
| 95 | (encode-hex-string | ||
| 96 | (md5-binary | ||
| 97 | (concat | ||
| 98 | (encode-hex-string | ||
| 99 | (md5-binary (concat (md5-binary | ||
| 100 | (concat username ":" realm ":" passphrase)) | ||
| 101 | ":" nonce ":" cnonce | ||
| 102 | (if authzid | ||
| 103 | (concat ":" authzid))))) | ||
| 104 | ":" nonce | ||
| 105 | ":" (format "%08x" nonce-count) ":" cnonce ":" qop ":" | ||
| 106 | (encode-hex-string | ||
| 107 | (md5-binary | ||
| 108 | (concat "AUTHENTICATE:" digest-uri | ||
| 109 | (if (member qop '("auth-int" "auth-conf")) | ||
| 110 | ":00000000000000000000000000000000"))))))) | ||
| 111 | (fillarray passphrase 0)))) | ||
| 112 | |||
| 113 | (defun sasl-digest-md5-response (client step) | ||
| 114 | (let* ((plist | ||
| 115 | (sasl-digest-md5-parse-string (sasl-step-data step))) | ||
| 116 | (realm | ||
| 117 | (or (sasl-client-property client 'realm) | ||
| 118 | (plist-get plist 'realm))) ;need to check | ||
| 119 | (nonce-count | ||
| 120 | (or (sasl-client-property client 'nonce-count) | ||
| 121 | sasl-digest-md5-nonce-count)) | ||
| 122 | (qop | ||
| 123 | (or (sasl-client-property client 'qop) | ||
| 124 | "auth")) | ||
| 125 | (digest-uri | ||
| 126 | (sasl-digest-md5-digest-uri | ||
| 127 | (sasl-client-service client)(sasl-client-server client))) | ||
| 128 | (cnonce | ||
| 129 | (or (sasl-client-property client 'cnonce) | ||
| 130 | (sasl-digest-md5-cnonce)))) | ||
| 131 | (sasl-client-set-property client 'nonce-count (1+ nonce-count)) | ||
| 132 | (unless (string= qop "auth") | ||
| 133 | (sasl-error (format "Unsupported \"qop-value\": %s" qop))) | ||
| 134 | (concat | ||
| 135 | "username=\"" (sasl-client-name client) "\"," | ||
| 136 | "realm=\"" realm "\"," | ||
| 137 | "nonce=\"" (plist-get plist 'nonce) "\"," | ||
| 138 | "cnonce=\"" cnonce "\"," | ||
| 139 | (format "nc=%08x," nonce-count) | ||
| 140 | "digest-uri=\"" digest-uri "\"," | ||
| 141 | "qop=" qop "," | ||
| 142 | "response=" | ||
| 143 | (sasl-digest-md5-response-value | ||
| 144 | (sasl-client-name client) | ||
| 145 | realm | ||
| 146 | (plist-get plist 'nonce) | ||
| 147 | cnonce | ||
| 148 | nonce-count | ||
| 149 | qop | ||
| 150 | digest-uri | ||
| 151 | (plist-get plist 'authzid))))) | ||
| 152 | |||
| 153 | (put 'sasl-digest 'sasl-mechanism | ||
| 154 | (sasl-make-mechanism "DIGEST-MD5" sasl-digest-md5-steps)) | ||
| 155 | |||
| 156 | (provide 'sasl-digest) | ||
| 157 | |||
| 158 | ;;; arch-tag: 786e02ed-1bc4-4b3c-bf34-96c27e31084d | ||
| 159 | ;;; sasl-digest.el ends here | ||
diff --git a/lisp/net/sasl-ntlm.el b/lisp/net/sasl-ntlm.el new file mode 100644 index 00000000000..cd8304db70a --- /dev/null +++ b/lisp/net/sasl-ntlm.el | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | ;;; sasl-ntlm.el --- NTLM (NT Lan Manager) module for the SASL client framework | ||
| 2 | |||
| 3 | ;; Copyright (C) 2000, 2007 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: Taro Kawagishi <tarok@transpulse.org> | ||
| 6 | ;; Keywords: SASL, NTLM | ||
| 7 | ;; Version: 1.00 | ||
| 8 | ;; Created: February 2001 | ||
| 9 | |||
| 10 | ;; This file is part of GNU Emacs. | ||
| 11 | |||
| 12 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 13 | ;; it under the terms of the GNU General Public License as published by | ||
| 14 | ;; the Free Software Foundation; either version 3, or (at your option) | ||
| 15 | ;; any later version. | ||
| 16 | |||
| 17 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 18 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | ;; GNU General Public License for more details. | ||
| 21 | |||
| 22 | ;; You should have received a copy of the GNU General Public License | ||
| 23 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 24 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 25 | ;; Boston, MA 02110-1301, USA. | ||
| 26 | |||
| 27 | ;;; Commentary: | ||
| 28 | |||
| 29 | ;; This is a SASL interface layer for NTLM authentication message | ||
| 30 | ;; generation by ntlm.el | ||
| 31 | |||
| 32 | ;;; Code: | ||
| 33 | |||
| 34 | (require 'sasl) | ||
| 35 | (require 'ntlm) | ||
| 36 | |||
| 37 | (defconst sasl-ntlm-steps | ||
| 38 | '(ignore ;nothing to do before making | ||
| 39 | sasl-ntlm-request ;authentication request | ||
| 40 | sasl-ntlm-response) ;response to challenge | ||
| 41 | "A list of functions to be called in sequnece for the NTLM | ||
| 42 | authentication steps. Ther are called by 'sasl-next-step.") | ||
| 43 | |||
| 44 | (defun sasl-ntlm-request (client step) | ||
| 45 | "SASL step function to generate a NTLM authentication request to the server. | ||
| 46 | Called from 'sasl-next-step. | ||
| 47 | CLIENT is a vector [mechanism user service server sasl-client-properties] | ||
| 48 | STEP is a vector [<previous step function> <result of previous step function>]" | ||
| 49 | (let ((user (sasl-client-name client))) | ||
| 50 | (ntlm-build-auth-request user))) | ||
| 51 | |||
| 52 | (defun sasl-ntlm-response (client step) | ||
| 53 | "SASL step function to generate a NTLM response against the server | ||
| 54 | challenge stored in the 2nd element of STEP. Called from 'sasl-next-step." | ||
| 55 | (let* ((user (sasl-client-name client)) | ||
| 56 | (passphrase | ||
| 57 | (sasl-read-passphrase (format "NTLM passphrase for %s: " user))) | ||
| 58 | (challenge (sasl-step-data step))) | ||
| 59 | (ntlm-build-auth-response challenge user | ||
| 60 | (ntlm-get-password-hashes passphrase)))) | ||
| 61 | |||
| 62 | (put 'sasl-ntlm 'sasl-mechanism | ||
| 63 | (sasl-make-mechanism "NTLM" sasl-ntlm-steps)) | ||
| 64 | |||
| 65 | (provide 'sasl-ntlm) | ||
| 66 | |||
| 67 | ;;; arch-tag: 1d9164c1-1df0-418f-b7ab-360157fd05dc | ||
| 68 | ;;; sasl-ntlm.el ends here | ||
diff --git a/lisp/net/sasl.el b/lisp/net/sasl.el new file mode 100644 index 00000000000..9118d288da4 --- /dev/null +++ b/lisp/net/sasl.el | |||
| @@ -0,0 +1,273 @@ | |||
| 1 | ;;; sasl.el --- SASL client framework | ||
| 2 | |||
| 3 | ;; Copyright (C) 2000, 2007 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: Daiki Ueno <ueno@unixuser.org> | ||
| 6 | ;; Keywords: SASL | ||
| 7 | |||
| 8 | ;; This file is part of GNU Emacs. | ||
| 9 | |||
| 10 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 11 | ;; it under the terms of the GNU General Public License as published by | ||
| 12 | ;; the Free Software Foundation; either version 3, or (at your option) | ||
| 13 | ;; any later version. | ||
| 14 | |||
| 15 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | ;; GNU General Public License for more details. | ||
| 19 | |||
| 20 | ;; You should have received a copy of the GNU General Public License | ||
| 21 | ;; along with GNU Emacs; see the file COPYING. If not, write to the | ||
| 22 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 23 | ;; Boston, MA 02110-1301, USA. | ||
| 24 | |||
| 25 | ;;; Commentary: | ||
| 26 | |||
| 27 | ;; This module provides common interface functions to share several | ||
| 28 | ;; SASL mechanism drivers. The toplevel is designed to be mostly | ||
| 29 | ;; compatible with [Java-SASL]. | ||
| 30 | ;; | ||
| 31 | ;; [SASL] J. Myers, "Simple Authentication and Security Layer (SASL)", | ||
| 32 | ;; RFC 2222, October 1997. | ||
| 33 | ;; | ||
| 34 | ;; [Java-SASL] R. Weltman & R. Lee, "The Java SASL Application Program | ||
| 35 | ;; Interface", draft-weltman-java-sasl-03.txt, March 2000. | ||
| 36 | |||
| 37 | ;;; Code: | ||
| 38 | |||
| 39 | (defvar sasl-mechanisms | ||
| 40 | '("CRAM-MD5" "DIGEST-MD5" "PLAIN" "LOGIN" "ANONYMOUS" | ||
| 41 | "NTLM" "SCRAM-MD5")) | ||
| 42 | |||
| 43 | (defvar sasl-mechanism-alist | ||
| 44 | '(("CRAM-MD5" sasl-cram) | ||
| 45 | ("DIGEST-MD5" sasl-digest) | ||
| 46 | ("PLAIN" sasl-plain) | ||
| 47 | ("LOGIN" sasl-login) | ||
| 48 | ("ANONYMOUS" sasl-anonymous) | ||
| 49 | ("NTLM" sasl-ntlm) | ||
| 50 | ("SCRAM-MD5" sasl-scram))) | ||
| 51 | |||
| 52 | (defvar sasl-unique-id-function #'sasl-unique-id-function) | ||
| 53 | |||
| 54 | (put 'sasl-error 'error-message "SASL error") | ||
| 55 | (put 'sasl-error 'error-conditions '(sasl-error error)) | ||
| 56 | |||
| 57 | (defun sasl-error (datum) | ||
| 58 | (signal 'sasl-error (list datum))) | ||
| 59 | |||
| 60 | ;;; @ SASL client | ||
| 61 | ;;; | ||
| 62 | |||
| 63 | (defun sasl-make-client (mechanism name service server) | ||
| 64 | "Return a newly allocated SASL client. | ||
| 65 | NAME is name of the authorization. SERVICE is name of the service desired. | ||
| 66 | SERVER is the fully qualified host name of the server to authenticate to." | ||
| 67 | (vector mechanism name service server (make-symbol "sasl-client-properties"))) | ||
| 68 | |||
| 69 | (defun sasl-client-mechanism (client) | ||
| 70 | "Return the authentication mechanism driver of CLIENT." | ||
| 71 | (aref client 0)) | ||
| 72 | |||
| 73 | (defun sasl-client-name (client) | ||
| 74 | "Return the authorization name of CLIENT, a string." | ||
| 75 | (aref client 1)) | ||
| 76 | |||
| 77 | (defun sasl-client-service (client) | ||
| 78 | "Return the service name of CLIENT, a string." | ||
| 79 | (aref client 2)) | ||
| 80 | |||
| 81 | (defun sasl-client-server (client) | ||
| 82 | "Return the server name of CLIENT, a string." | ||
| 83 | (aref client 3)) | ||
| 84 | |||
| 85 | (defun sasl-client-set-properties (client plist) | ||
| 86 | "Destructively set the properties of CLIENT. | ||
| 87 | The second argument PLIST is the new property list." | ||
| 88 | (setplist (aref client 4) plist)) | ||
| 89 | |||
| 90 | (defun sasl-client-set-property (client property value) | ||
| 91 | "Add the given property/value to CLIENT." | ||
| 92 | (put (aref client 4) property value)) | ||
| 93 | |||
| 94 | (defun sasl-client-property (client property) | ||
| 95 | "Return the value of the PROPERTY of CLIENT." | ||
| 96 | (get (aref client 4) property)) | ||
| 97 | |||
| 98 | (defun sasl-client-properties (client) | ||
| 99 | "Return the properties of CLIENT." | ||
| 100 | (symbol-plist (aref client 4))) | ||
| 101 | |||
| 102 | ;;; @ SASL mechanism | ||
| 103 | ;;; | ||
| 104 | |||
| 105 | (defun sasl-make-mechanism (name steps) | ||
| 106 | "Make an authentication mechanism. | ||
| 107 | NAME is a IANA registered SASL mechanism name. | ||
| 108 | STEPS is list of continuation function." | ||
| 109 | (vector name | ||
| 110 | (mapcar | ||
| 111 | (lambda (step) | ||
| 112 | (let ((symbol (make-symbol (symbol-name step)))) | ||
| 113 | (fset symbol (symbol-function step)) | ||
| 114 | symbol)) | ||
| 115 | steps))) | ||
| 116 | |||
| 117 | (defun sasl-mechanism-name (mechanism) | ||
| 118 | "Return name of MECHANISM, a string." | ||
| 119 | (aref mechanism 0)) | ||
| 120 | |||
| 121 | (defun sasl-mechanism-steps (mechanism) | ||
| 122 | "Return the authentication steps of MECHANISM, a list of functions." | ||
| 123 | (aref mechanism 1)) | ||
| 124 | |||
| 125 | (defun sasl-find-mechanism (mechanisms) | ||
| 126 | "Retrieve an apropriate mechanism object from MECHANISMS hints." | ||
| 127 | (let* ((sasl-mechanisms sasl-mechanisms) | ||
| 128 | (mechanism | ||
| 129 | (catch 'done | ||
| 130 | (while sasl-mechanisms | ||
| 131 | (if (member (car sasl-mechanisms) mechanisms) | ||
| 132 | (throw 'done (nth 1 (assoc (car sasl-mechanisms) | ||
| 133 | sasl-mechanism-alist)))) | ||
| 134 | (setq sasl-mechanisms (cdr sasl-mechanisms)))))) | ||
| 135 | (if mechanism | ||
| 136 | (require mechanism)) | ||
| 137 | (get mechanism 'sasl-mechanism))) | ||
| 138 | |||
| 139 | ;;; @ SASL authentication step | ||
| 140 | ;;; | ||
| 141 | |||
| 142 | (defun sasl-step-data (step) | ||
| 143 | "Return the data which STEP holds, a string." | ||
| 144 | (aref step 1)) | ||
| 145 | |||
| 146 | (defun sasl-step-set-data (step data) | ||
| 147 | "Store DATA string to STEP." | ||
| 148 | (aset step 1 data)) | ||
| 149 | |||
| 150 | (defun sasl-next-step (client step) | ||
| 151 | "Evaluate the challenge and prepare an appropriate next response. | ||
| 152 | The data type of the value and optional 2nd argument STEP is nil or | ||
| 153 | opaque authentication step which holds the reference to the next action | ||
| 154 | and the current challenge. At the first time STEP should be set to nil." | ||
| 155 | (let* ((steps | ||
| 156 | (sasl-mechanism-steps | ||
| 157 | (sasl-client-mechanism client))) | ||
| 158 | (function | ||
| 159 | (if (vectorp step) | ||
| 160 | (nth 1 (memq (aref step 0) steps)) | ||
| 161 | (car steps)))) | ||
| 162 | (if function | ||
| 163 | (vector function (funcall function client step))))) | ||
| 164 | |||
| 165 | (defvar sasl-read-passphrase nil) | ||
| 166 | (defun sasl-read-passphrase (prompt) | ||
| 167 | (if (not sasl-read-passphrase) | ||
| 168 | (if (functionp 'read-passwd) | ||
| 169 | (setq sasl-read-passphrase 'read-passwd) | ||
| 170 | (if (load "passwd" t) | ||
| 171 | (setq sasl-read-passphrase 'read-passwd) | ||
| 172 | (autoload 'ange-ftp-read-passwd "ange-ftp") | ||
| 173 | (setq sasl-read-passphrase 'ange-ftp-read-passwd)))) | ||
| 174 | (funcall sasl-read-passphrase prompt)) | ||
| 175 | |||
| 176 | (defun sasl-unique-id () | ||
| 177 | "Compute a data string which must be different each time. | ||
| 178 | It contain at least 64 bits of entropy." | ||
| 179 | (concat (funcall sasl-unique-id-function)(funcall sasl-unique-id-function))) | ||
| 180 | |||
| 181 | (defvar sasl-unique-id-char nil) | ||
| 182 | |||
| 183 | ;; stolen (and renamed) from message.el | ||
| 184 | (defun sasl-unique-id-function () | ||
| 185 | ;; Don't use microseconds from (current-time), they may be unsupported. | ||
| 186 | ;; Instead we use this randomly inited counter. | ||
| 187 | (setq sasl-unique-id-char | ||
| 188 | (% (1+ (or sasl-unique-id-char (logand (random t) (1- (lsh 1 20))))) | ||
| 189 | ;; (current-time) returns 16-bit ints, | ||
| 190 | ;; and 2^16*25 just fits into 4 digits i base 36. | ||
| 191 | (* 25 25))) | ||
| 192 | (let ((tm (current-time))) | ||
| 193 | (concat | ||
| 194 | (sasl-unique-id-number-base36 | ||
| 195 | (+ (car tm) | ||
| 196 | (lsh (% sasl-unique-id-char 25) 16)) 4) | ||
| 197 | (sasl-unique-id-number-base36 | ||
| 198 | (+ (nth 1 tm) | ||
| 199 | (lsh (/ sasl-unique-id-char 25) 16)) 4)))) | ||
| 200 | |||
| 201 | (defun sasl-unique-id-number-base36 (num len) | ||
| 202 | (if (if (< len 0) | ||
| 203 | (<= num 0) | ||
| 204 | (= len 0)) | ||
| 205 | "" | ||
| 206 | (concat (sasl-unique-id-number-base36 (/ num 36) (1- len)) | ||
| 207 | (char-to-string (aref "zyxwvutsrqponmlkjihgfedcba9876543210" | ||
| 208 | (% num 36)))))) | ||
| 209 | |||
| 210 | ;;; PLAIN (RFC2595 Section 6) | ||
| 211 | (defconst sasl-plain-steps | ||
| 212 | '(sasl-plain-response)) | ||
| 213 | |||
| 214 | (defun sasl-plain-response (client step) | ||
| 215 | (let ((passphrase | ||
| 216 | (sasl-read-passphrase | ||
| 217 | (format "PLAIN passphrase for %s: " (sasl-client-name client)))) | ||
| 218 | (authenticator-name | ||
| 219 | (sasl-client-property | ||
| 220 | client 'authenticator-name)) | ||
| 221 | (name (sasl-client-name client))) | ||
| 222 | (unwind-protect | ||
| 223 | (if (and authenticator-name | ||
| 224 | (not (string= authenticator-name name))) | ||
| 225 | (concat authenticator-name "\0" name "\0" passphrase) | ||
| 226 | (concat "\0" name "\0" passphrase)) | ||
| 227 | (fillarray passphrase 0)))) | ||
| 228 | |||
| 229 | (put 'sasl-plain 'sasl-mechanism | ||
| 230 | (sasl-make-mechanism "PLAIN" sasl-plain-steps)) | ||
| 231 | |||
| 232 | (provide 'sasl-plain) | ||
| 233 | |||
| 234 | ;;; LOGIN (No specification exists) | ||
| 235 | (defconst sasl-login-steps | ||
| 236 | '(ignore ;no initial response | ||
| 237 | sasl-login-response-1 | ||
| 238 | sasl-login-response-2)) | ||
| 239 | |||
| 240 | (defun sasl-login-response-1 (client step) | ||
| 241 | ;;; (unless (string-match "^Username:" (sasl-step-data step)) | ||
| 242 | ;;; (sasl-error (format "Unexpected response: %s" (sasl-step-data step)))) | ||
| 243 | (sasl-client-name client)) | ||
| 244 | |||
| 245 | (defun sasl-login-response-2 (client step) | ||
| 246 | ;;; (unless (string-match "^Password:" (sasl-step-data step)) | ||
| 247 | ;;; (sasl-error (format "Unexpected response: %s" (sasl-step-data step)))) | ||
| 248 | (sasl-read-passphrase | ||
| 249 | (format "LOGIN passphrase for %s: " (sasl-client-name client)))) | ||
| 250 | |||
| 251 | (put 'sasl-login 'sasl-mechanism | ||
| 252 | (sasl-make-mechanism "LOGIN" sasl-login-steps)) | ||
| 253 | |||
| 254 | (provide 'sasl-login) | ||
| 255 | |||
| 256 | ;;; ANONYMOUS (RFC2245) | ||
| 257 | (defconst sasl-anonymous-steps | ||
| 258 | '(ignore ;no initial response | ||
| 259 | sasl-anonymous-response)) | ||
| 260 | |||
| 261 | (defun sasl-anonymous-response (client step) | ||
| 262 | (or (sasl-client-property client 'trace) | ||
| 263 | (sasl-client-name client))) | ||
| 264 | |||
| 265 | (put 'sasl-anonymous 'sasl-mechanism | ||
| 266 | (sasl-make-mechanism "ANONYMOUS" sasl-anonymous-steps)) | ||
| 267 | |||
| 268 | (provide 'sasl-anonymous) | ||
| 269 | |||
| 270 | (provide 'sasl) | ||
| 271 | |||
| 272 | ;;; arch-tag: 8b3326fa-4978-4fda-93e2-cb2c6255f887 | ||
| 273 | ;;; sasl.el ends here | ||