"SfR Fresh" - the SfR Freeware/Shareware Archive

Member "gnus-5.10.10/lisp/canlock.el" of archive gnus-5.10.10.tar.gz:


As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) Lisp source code syntax highlighting with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
    1 ;;; canlock.el --- functions for Cancel-Lock feature
    2 
    3 ;; Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004,
    4 ;;   2005, 2006, 2007, 2008 Free Software Foundation, Inc.
    5 
    6 ;; Author: Katsumi Yamaoka <yamaoka@jpl.org>
    7 ;; Keywords: news, cancel-lock, hmac, sha1, rfc2104
    8 
    9 ;; This program is free software; you can redistribute it and/or modify
   10 ;; it under the terms of the GNU General Public License as published by
   11 ;; the Free Software Foundation; either version 3, or (at your option)
   12 ;; any later version.
   13 
   14 ;; This program is distributed in the hope that it will be useful,
   15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
   16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17 ;; GNU General Public License for more details.
   18 
   19 ;; You should have received a copy of the GNU General Public License
   20 ;; along with this program; see the file COPYING.  If not, write to the
   21 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   22 ;; Boston, MA 02110-1301, USA.
   23 
   24 ;;; Commentary:
   25 
   26 ;; Canlock is a library for generating and verifying Cancel-Lock and/or
   27 ;; Cancel-Key header in news articles.  This is used to protect articles
   28 ;; from rogue cancel, supersede or replace attacks.  The method is based
   29 ;; on draft-ietf-usefor-cancel-lock-01.txt which was released on November
   30 ;; 3rd 1998.  For instance, you can add Cancel-Lock (and possibly Cancel-
   31 ;; Key) header in a news article by using a hook which will be evaluated
   32 ;; just before sending an article as follows:
   33 ;;
   34 ;; (add-hook '*e**a*e-header-hook 'canlock-insert-header t)
   35 ;;
   36 ;; Verifying Cancel-Lock is mainly a function of news servers, however,
   37 ;; you can verify your own article using the command `canlock-verify' in
   38 ;; the (raw) article buffer.  You will be prompted for the password for
   39 ;; each time if the option `canlock-password' or `canlock-password-for-
   40 ;; verify' is nil.  Note that setting these options is a bit unsafe.
   41 
   42 ;;; Code:
   43 
   44 (eval-when-compile
   45   (require 'cl))
   46 
   47 (require 'sha1)
   48 
   49 (defvar mail-header-separator)
   50 
   51 (defgroup canlock nil
   52   "The Cancel-Lock feature."
   53   :group 'news)
   54 
   55 (defcustom canlock-password nil
   56   "Password to use when signing a Cancel-Lock or a Cancel-Key header."
   57   :type '(radio (const :format "Not specified " nil)
   58 		(string :tag "Password"))
   59   :group 'canlock)
   60 
   61 (defcustom canlock-password-for-verify canlock-password
   62   "Password to use when verifying a Cancel-Lock or a Cancel-Key header."
   63   :type '(radio (const :format "Not specified " nil)
   64 		(string :tag "Password"))
   65   :group 'canlock)
   66 
   67 (defcustom canlock-force-insert-header nil
   68   "If non-nil, insert a Cancel-Lock or a Cancel-Key header even if the
   69 buffer does not look like a news message."
   70   :type 'boolean
   71   :group 'canlock)
   72 
   73 (eval-when-compile
   74   (defmacro canlock-string-as-unibyte (string)
   75     "Return a unibyte string with the same individual bytes as STRING."
   76     (if (fboundp 'string-as-unibyte)
   77 	(list 'string-as-unibyte string)
   78       string)))
   79 
   80 (defun canlock-sha1 (message)
   81   "Make a SHA-1 digest of MESSAGE as a unibyte string of length 20 bytes."
   82   (let (sha1-maximum-internal-length)
   83     (sha1 message nil nil 'binary)))
   84 
   85 (defun canlock-make-cancel-key (message-id password)
   86   "Make a Cancel-Key header."
   87   (when (> (length password) 20)
   88     (setq password (canlock-sha1 password)))
   89   (setq password (concat password (make-string (- 64 (length password)) 0)))
   90   (let ((ipad (mapconcat (lambda (byte)
   91 			   (char-to-string (logxor 54 byte)))
   92 			 password ""))
   93 	(opad (mapconcat (lambda (byte)
   94 			   (char-to-string (logxor 92 byte)))
   95 			 password "")))
   96     (base64-encode-string
   97      (canlock-sha1
   98       (concat opad
   99 	      (canlock-sha1
  100 	       (concat ipad (canlock-string-as-unibyte message-id))))))))
  101 
  102 (defun canlock-narrow-to-header ()
  103   "Narrow the buffer to the head of the message."
  104   (let (case-fold-search)
  105     (narrow-to-region
  106      (goto-char (point-min))
  107      (goto-char (if (re-search-forward
  108 		     (format "^$\\|^%s$"
  109 			     (regexp-quote mail-header-separator))
  110 		     nil t)
  111 		    (match-beginning 0)
  112 		  (point-max))))))
  113 
  114 (defun canlock-delete-headers ()
  115   "Delete Cancel-Key or Cancel-Lock headers in the narrowed buffer."
  116   (let ((case-fold-search t))
  117     (goto-char (point-min))
  118     (while (re-search-forward "^Cancel-\\(Key\\|Lock\\):" nil t)
  119       (delete-region (match-beginning 0)
  120 		     (if (re-search-forward "^[^\t ]" nil t)
  121 			 (goto-char (match-beginning 0))
  122 		       (point-max))))))
  123 
  124 (defun canlock-fetch-fields (&optional key)
  125   "Return a list of the values of Cancel-Lock header.
  126 If KEY is non-nil, look for a Cancel-Key header instead.  The buffer
  127 is expected to be narrowed to just the headers of the message."
  128   (let ((field (mail-fetch-field (if key "Cancel-Key" "Cancel-Lock")))
  129 	fields rest
  130 	(case-fold-search t))
  131     (when field
  132       (setq fields (split-string field "[\t\n\r ,]+"))
  133       (while fields
  134 	(when (string-match "^sha1:" (setq field (pop fields)))
  135 	  (push (substring field 5) rest)))
  136       (nreverse rest))))
  137 
  138 (defun canlock-fetch-id-for-key ()
  139   "Return a Message-ID in Cancel, Supersedes or Replaces header.
  140 The buffer is expected to be narrowed to just the headers of the
  141 message."
  142   (or (let ((cancel (mail-fetch-field "Control")))
  143 	(and cancel
  144 	     (string-match "^cancel[\t ]+\\(<[^\t\n @<>]+@[^\t\n @<>]+>\\)"
  145 			   cancel)
  146 	     (match-string 1 cancel)))
  147       (mail-fetch-field "Supersedes")
  148       (mail-fetch-field "Replaces")))
  149 
  150 ;;;###autoload
  151 (defun canlock-insert-header (&optional id-for-key id-for-lock password)
  152   "Insert a Cancel-Key and/or a Cancel-Lock header if possible."
  153   (let (news control key-for-key key-for-lock)
  154     (save-excursion
  155       (save-restriction
  156 	(canlock-narrow-to-header)
  157 	(when (setq news (or canlock-force-insert-header
  158 			     (mail-fetch-field "Newsgroups")))
  159 	  (unless id-for-key
  160 	    (setq id-for-key (canlock-fetch-id-for-key)))
  161 	  (if (and (setq control (mail-fetch-field "Control"))
  162 		   (string-match "^cancel[\t ]+<[^\t\n @<>]+@[^\t\n @<>]+>"
  163 				 control))
  164 	      (setq id-for-lock nil)
  165 	    (unless id-for-lock
  166 	      (setq id-for-lock (mail-fetch-field "Message-ID"))))
  167 	  (canlock-delete-headers)
  168 	  (goto-char (point-max))))
  169       (when news
  170 	(if (not (or id-for-key id-for-lock))
  171 	    (message "There are no Message-ID(s)")
  172 	  (unless password
  173 	    (setq password (or canlock-password
  174 			       (read-passwd
  175 				"Password for Canlock: "))))
  176 	  (if (or (not (stringp password)) (zerop (length password)))
  177 	      (message "Password for Canlock is bad")
  178 	    (setq key-for-key (when id-for-key
  179 				(canlock-make-cancel-key
  180 				 id-for-key password))
  181 		  key-for-lock (when id-for-lock
  182 				 (canlock-make-cancel-key
  183 				  id-for-lock password)))
  184 	    (if (not (or key-for-key key-for-lock))
  185 		(message "Couldn't insert Canlock header")
  186 	      (when key-for-key
  187 		(insert "Cancel-Key: sha1:" key-for-key "\n"))
  188 	      (when key-for-lock
  189 		(insert "Cancel-Lock: sha1:"
  190 			(base64-encode-string (canlock-sha1 key-for-lock))
  191 			"\n")))))))))
  192 
  193 ;;;###autoload
  194 (defun canlock-verify (&optional buffer)
  195   "Verify Cancel-Lock or Cancel-Key in BUFFER.
  196 If BUFFER is nil, the current buffer is assumed.  Signal an error if
  197 it fails."
  198   (interactive)
  199   (let (keys locks errmsg id-for-key id-for-lock password
  200 	     key-for-key key-for-lock match)
  201     (save-excursion
  202       (when buffer
  203 	(set-buffer buffer))
  204       (save-restriction
  205 	(widen)
  206 	(canlock-narrow-to-header)
  207 	(setq keys (canlock-fetch-fields 'key)
  208 	      locks (canlock-fetch-fields))
  209 	(if (not (or keys locks))
  210 	    (setq errmsg
  211 		  "There are neither Cancel-Lock nor Cancel-Key headers")
  212 	  (setq id-for-key (canlock-fetch-id-for-key)
  213 		id-for-lock (mail-fetch-field "Message-ID"))
  214 	  (or id-for-key id-for-lock
  215 	      (setq errmsg "There are no Message-ID(s)")))))
  216     (if errmsg
  217 	(error "%s" errmsg)
  218       (setq password (or canlock-password-for-verify
  219 			 (read-passwd "Password for Canlock: ")))
  220       (if (or (not (stringp password)) (zerop (length password)))
  221 	  (error "Password for Canlock is bad")
  222 	(when keys
  223 	  (when id-for-key
  224 	    (setq key-for-key (canlock-make-cancel-key id-for-key password))
  225 	    (while (and keys (not match))
  226 	      (setq match (string-equal key-for-key (pop keys)))))
  227 	  (setq keys (if match "good" "bad")))
  228 	(setq match nil)
  229 	(when locks
  230 	  (when id-for-lock
  231 	    (setq key-for-lock
  232 		  (base64-encode-string
  233 		   (canlock-sha1 (canlock-make-cancel-key id-for-lock
  234 							  password))))
  235 	    (when (and locks (not match))
  236 	      (setq match (string-equal key-for-lock (pop locks)))))
  237 	  (setq locks (if match "good" "bad")))
  238 	(prog1
  239 	    (when (member "bad" (list keys locks))
  240 	      "bad")
  241 	  (cond ((and keys locks)
  242 		 (message "Cancel-Key is %s, Cancel-Lock is %s" keys locks))
  243 		(locks
  244 		 (message "Cancel-Lock is %s" locks))
  245 		(keys
  246 		 (message "Cancel-Key is %s" keys))))))))
  247 
  248 (provide 'canlock)
  249 
  250 ;;; arch-tag: 033c4f09-b9f1-459d-bd0d-254430283f78
  251 ;;; canlock.el ends here