Fixups when displaying certain attachments
[gnus] / lisp / ntlm.el
index c9351e3..9ab83da 100644 (file)
@@ -1,6 +1,6 @@
 ;;; ntlm.el --- NTLM (NT LanManager) authentication support
 
-;; Copyright (C) 2001, 2007, 2008  Free Software Foundation, Inc.
+;; Copyright (C) 2001, 2007-2015 Free Software Foundation, Inc.
 
 ;; Author: Taro Kawagishi <tarok@transpulse.org>
 ;; Keywords: NTLM, SASL
@@ -27,9 +27,9 @@
 ;; This library is a direct translation of the Samba release 2.2.0
 ;; implementation of Windows NT and LanManager compatible password
 ;; encryption.
-;; 
+;;
 ;; Interface functions:
-;; 
+;;
 ;; ntlm-build-auth-request
 ;;   This will return a binary string, which should be used in the
 ;;   base64 encoded form and it is the caller's responsibility to encode
@@ -40,7 +40,7 @@
 ;;   (which will be a binary string) as the first argument and to
 ;;   encode the returned string with base64.  The second argument user
 ;;   should be given in user@domain format.
-;; 
+;;
 ;; ntlm-get-password-hashes
 ;;
 ;;
@@ -80,8 +80,8 @@ is not given."
        (request-msgType (concat (make-string 1 1) (make-string 3 0)))
                                        ;0x01 0x00 0x00 0x00
        (request-flags (concat (make-string 1 7) (make-string 1 178)
-                              (make-string 2 0)))
-                                       ;0x07 0xb2 0x00 0x00
+                              (make-string 1 8) (make-string 1 0)))
+                                       ;0x07 0xb2 0x08 0x00
        lu ld off-d off-u)
     (when (string-match "@" user)
       (unless domain
@@ -102,16 +102,54 @@ is not given."
            (md4-pack-int16 ld) ;domain field, count field
            (md4-pack-int16 ld) ;domain field, max count field
            (md4-pack-int32 (cons 0 off-d)) ;domain field, offset field
-           user                        ;bufer field
-           domain              ;bufer field
+           user                        ;buffer field
+           domain              ;buffer field
            )))
 
 (eval-when-compile
   (defmacro ntlm-string-as-unibyte (string)
     (if (fboundp 'string-as-unibyte)
        `(string-as-unibyte ,string)
+      string))
+  (defmacro ntlm-string-make-unibyte (string)
+    (if (fboundp 'string-make-unibyte)
+       `(string-make-unibyte ,string)
       string)))
 
+(eval-and-compile
+  (autoload 'sha1 "sha1")
+  (if (fboundp 'secure-hash)
+      (defalias 'ntlm-secure-hash 'secure-hash)
+    (defun ntlm-secure-hash (algorithm object &optional start end binary)
+      "Return the secure hash of OBJECT, a buffer or string.
+ALGORITHM is a symbol specifying the hash to use: md5, sha1.
+
+The two optional arguments START and END are positions specifying for
+which part of OBJECT to compute the hash.  If nil or omitted, uses the
+whole OBJECT.
+
+If BINARY is non-nil, returns a string in binary form."
+      (cond ((eq algorithm 'md5)
+            (if binary
+                (let* ((hex (md5 object start end))
+                       (len (length hex))
+                       (beg 0)
+                       rest)
+                  (while (< beg len)
+                    (push (ntlm-string-make-unibyte
+                           (char-to-string
+                            (string-to-number
+                             (substring hex beg (setq beg (+ beg 2)))
+                             16)))
+                          rest))
+                  (apply #'concat (nreverse rest)))
+              (md5 object start end)))
+           ((eq algorithm 'sha1)
+            (sha1 object start end binary))
+           (t
+            (error "(ntlm-secure-hash) Unsupported algorithm: %s"
+                   algorithm))))))
+
 (defun ntlm-build-auth-response (challenge user password-hashes)
   "Return the response string to a challenge string CHALLENGE given by
 the NTLM based server for the user USER and the password hash list
@@ -144,11 +182,35 @@ by PASSWORD-HASHES.  PASSWORD-HASHES should be a return value of
       (setq domain (substring user (1+ (match-beginning 0))))
       (setq user (substring user 0 (match-beginning 0))))
 
-    ;; generate response data
-    (setq lmRespData
-         (ntlm-smb-owf-encrypt (car password-hashes) challengeData))
-    (setq ntRespData
-         (ntlm-smb-owf-encrypt (cadr password-hashes) challengeData))
+    ;; check if "negotiate NTLM2 key" flag is set in type 2 message
+    (if (not (zerop (logand (aref flags 2) 8)))
+       (let (randomString
+             sessionHash)
+         ;; generate NTLM2 session response data
+         (setq randomString (ntlm-string-make-unibyte
+                             (concat
+                              (make-string 1 (random 256))
+                              (make-string 1 (random 256))
+                              (make-string 1 (random 256))
+                              (make-string 1 (random 256))
+                              (make-string 1 (random 256))
+                              (make-string 1 (random 256))
+                              (make-string 1 (random 256))
+                              (make-string 1 (random 256)))))
+         (setq sessionHash (ntlm-secure-hash
+                            'md5 (concat challengeData randomString)
+                            nil nil t))
+         (setq sessionHash (substring sessionHash 0 8))
+
+         (setq lmRespData (concat randomString (make-string 16 0)))
+         (setq ntRespData (ntlm-smb-owf-encrypt
+                           (cadr password-hashes) sessionHash)))
+      (progn
+       ;; generate response data
+       (setq lmRespData
+             (ntlm-smb-owf-encrypt (car password-hashes) challengeData))
+       (setq ntRespData
+             (ntlm-smb-owf-encrypt (cadr password-hashes) challengeData))))
 
     ;; get offsets to fields to pack the response struct in a string
     (setq lu (length user))
@@ -207,16 +269,16 @@ by PASSWORD-HASHES.  PASSWORD-HASHES should be a return value of
            ;; buffer field
            lmRespData                  ;lmResponse, 24 bytes
            ntRespData                  ;ntResponse, 24 bytes
-           (ntlm-ascii2unicode domain  ;unicode domain string, 2*ld bytes
+           (ntlm-ascii2unicode domain  ;Unicode domain string, 2*ld bytes
                                (length domain)) ;
-           (ntlm-ascii2unicode user    ;unicode user string, 2*lu bytes
+           (ntlm-ascii2unicode user    ;Unicode user string, 2*lu bytes
                                (length user)) ;
-           (ntlm-ascii2unicode user    ;unicode user string, 2*lu bytes
+           (ntlm-ascii2unicode user    ;Unicode user string, 2*lu bytes
                                (length user)) ;
            )))
 
 (defun ntlm-get-password-hashes (password)
-  "Return a pair of SMB hash and NT MD4 hash of the given password PASSWORD"
+  "Return a pair of SMB hash and NT MD4 hash of the given password PASSWORD."
   (list (ntlm-smb-passwd-hash password)
        (ntlm-md4hash password)))
 
@@ -440,7 +502,7 @@ length of STR is LEN."
 
 (defun ntlm-smb-dohash (in key forw)
   "Return the hash value for a string IN and a string KEY.
-Length of IN and KEY are 64.  FORW non nill means forward, nil means
+Length of IN and KEY are 64.  FORW non-nil means forward, nil means
 backward."
   (let (pk1                            ;string of length 56
        c                               ;string of length 28
@@ -526,7 +588,7 @@ into a Unicode string.  PASSWD is truncated to 128 bytes if longer."
     (setq len (length passwd))
     (if (> len 128)
        (setq len 128))
-    ;; Password must be converted to NT unicode
+    ;; Password must be converted to NT Unicode
     (setq wpwd (ntlm-ascii2unicode passwd len))
     ;; Calculate length in bytes
     (setq len (* len 2))
@@ -534,5 +596,4 @@ into a Unicode string.  PASSWD is truncated to 128 bytes if longer."
 
 (provide 'ntlm)
 
-;; arch-tag: 348ace18-f8e2-4176-8fe9-d9ab4e96f296
 ;;; ntlm.el ends here