aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2018-10-08 20:59:59 -0400
committerStefan Monnier2018-10-08 20:59:59 -0400
commitfc6004e61760d3bd3e27b593c318e634a221652c (patch)
treef0d97c62b0588b56947ce929af847eeb8a0af554
parent763721613bd478396dec11c8ccf145927ae70a48 (diff)
downloademacs-fc6004e61760d3bd3e27b593c318e634a221652c.tar.gz
emacs-fc6004e61760d3bd3e27b593c318e634a221652c.zip
* lisp/net/ntlm.el: Use lexical-binding
(ntlm-string-as-unibyte): Remove. (ntlm-build-auth-response): Use encode-coding-string instead. (ntlm-build-auth-request, ntlm-build-auth-response, ntlm-ascii2unicode) (ntlm-smb-owf-encrypt, ntlm-smb-hash, ntlm-smb-dohash, ntlm-md4hash): Use fewer setq more Lisp-style.
-rw-r--r--lisp/net/ntlm.el168
1 files changed, 79 insertions, 89 deletions
diff --git a/lisp/net/ntlm.el b/lisp/net/ntlm.el
index 7a68c68ab61..142c37510ec 100644
--- a/lisp/net/ntlm.el
+++ b/lisp/net/ntlm.el
@@ -1,4 +1,4 @@
1;;; ntlm.el --- NTLM (NT LanManager) authentication support 1;;; ntlm.el --- NTLM (NT LanManager) authentication support -*- lexical-binding:t -*-
2 2
3;; Copyright (C) 2001, 2007-2018 Free Software Foundation, Inc. 3;; Copyright (C) 2001, 2007-2018 Free Software Foundation, Inc.
4 4
@@ -106,7 +106,7 @@ is not given."
106 (request-flags (concat (make-string 1 7) (make-string 1 130) 106 (request-flags (concat (make-string 1 7) (make-string 1 130)
107 (make-string 1 8) (make-string 1 0))) 107 (make-string 1 8) (make-string 1 0)))
108 ;0x07 0x82 0x08 0x00 108 ;0x07 0x82 0x08 0x00
109 lu ld off-d off-u) 109 )
110 (when (and user (string-match "@" user)) 110 (when (and user (string-match "@" user))
111 (unless domain 111 (unless domain
112 (setq domain (substring user (1+ (match-beginning 0))))) 112 (setq domain (substring user (1+ (match-beginning 0)))))
@@ -115,10 +115,10 @@ is not given."
115 ;; set "negotiate domain supplied" bit 115 ;; set "negotiate domain supplied" bit
116 (aset request-flags 1 (logior (aref request-flags 1) ?\x10))) 116 (aset request-flags 1 (logior (aref request-flags 1) ?\x10)))
117 ;; set fields offsets within the request struct 117 ;; set fields offsets within the request struct
118 (setq lu (length user)) 118 (let* ((lu (length user))
119 (setq ld (length domain)) 119 (ld (length domain))
120 (setq off-u 32) ;offset to the string 'user 120 (off-u 32) ;offset to the string 'user
121 (setq off-d (+ 32 lu)) ;offset to the string 'domain 121 (off-d (+ 32 lu))) ;offset to the string 'domain
122 ;; pack the request struct in a string 122 ;; pack the request struct in a string
123 (concat request-ident ;8 bytes 123 (concat request-ident ;8 bytes
124 request-msgType ;4 bytes 124 request-msgType ;4 bytes
@@ -131,24 +131,20 @@ is not given."
131 (md4-pack-int32 (cons 0 off-d)) ;domain field, offset field 131 (md4-pack-int32 (cons 0 off-d)) ;domain field, offset field
132 user ;buffer field 132 user ;buffer field
133 domain ;buffer field 133 domain ;buffer field
134 ))) 134 ))))
135
136(eval-when-compile
137 (defmacro ntlm-string-as-unibyte (string)
138 (if (fboundp 'string-as-unibyte)
139 `(string-as-unibyte ,string)
140 string)))
141 135
142(defun ntlm-compute-timestamp () 136(defun ntlm-compute-timestamp ()
143 "Compute an NTLMv2 timestamp. 137 "Compute an NTLMv2 timestamp.
144Return a unibyte string representing the number of tenths of a 138Return a unibyte string representing the number of tenths of a
145microsecond since January 1, 1601 as a 64-bit little-endian 139microsecond since January 1, 1601 as a 64-bit little-endian
146signed integer." 140signed integer."
141 ;; FIXME: This can likely be significantly simplified using the new
142 ;; bignums support!
147 (let* ((s-to-tenths-of-us "mul(add(lsh($1,16),$2),10000000)") 143 (let* ((s-to-tenths-of-us "mul(add(lsh($1,16),$2),10000000)")
148 (us-to-tenths-of-us "mul($3,10)") 144 (us-to-tenths-of-us "mul($3,10)")
149 (ps-to-tenths-of-us "idiv($4,100000)") 145 (ps-to-tenths-of-us "idiv($4,100000)")
150 (tenths-of-us-since-jan-1-1601 146 (tenths-of-us-since-jan-1-1601
151 (apply 'calc-eval (concat "add(add(add(" 147 (apply #'calc-eval (concat "add(add(add("
152 s-to-tenths-of-us "," 148 s-to-tenths-of-us ","
153 us-to-tenths-of-us ")," 149 us-to-tenths-of-us "),"
154 ps-to-tenths-of-us ")," 150 ps-to-tenths-of-us "),"
@@ -157,12 +153,12 @@ signed integer."
157 "116444736000000000)") 153 "116444736000000000)")
158 'rawnum (encode-time nil 'list))) 154 'rawnum (encode-time nil 'list)))
159 result-bytes) 155 result-bytes)
160 (dotimes (byte 8) 156 (dotimes (_byte 8)
161 (push (calc-eval "and($1,16#FF)" 'rawnum tenths-of-us-since-jan-1-1601) 157 (push (calc-eval "and($1,16#FF)" 'rawnum tenths-of-us-since-jan-1-1601)
162 result-bytes) 158 result-bytes)
163 (setq tenths-of-us-since-jan-1-1601 159 (setq tenths-of-us-since-jan-1-1601
164 (calc-eval "rsh($1,8,64)" 'rawnum tenths-of-us-since-jan-1-1601))) 160 (calc-eval "rsh($1,8,64)" 'rawnum tenths-of-us-since-jan-1-1601)))
165 (apply 'unibyte-string (nreverse result-bytes)))) 161 (apply #'unibyte-string (nreverse result-bytes))))
166 162
167(defun ntlm-generate-nonce () 163(defun ntlm-generate-nonce ()
168 "Generate a random nonce, not to be used more than once. 164 "Generate a random nonce, not to be used more than once.
@@ -177,7 +173,13 @@ the NTLM based server for the user USER and the password hash list
177PASSWORD-HASHES. NTLM uses two hash values which are represented 173PASSWORD-HASHES. NTLM uses two hash values which are represented
178by PASSWORD-HASHES. PASSWORD-HASHES should be a return value of 174by PASSWORD-HASHES. PASSWORD-HASHES should be a return value of
179 (list (ntlm-smb-passwd-hash password) (ntlm-md4hash password))" 175 (list (ntlm-smb-passwd-hash password) (ntlm-md4hash password))"
180 (let* ((rchallenge (ntlm-string-as-unibyte challenge)) 176 (let* ((rchallenge (if (multibyte-string-p challenge)
177 (progn
178 ;; FIXME: Maybe it would be better to
179 ;; signal an error.
180 (message "Incorrect challenge string type in ntlm-build-auth-response")
181 (encode-coding-string challenge 'binary))
182 challenge))
181 ;; get fields within challenge struct 183 ;; get fields within challenge struct
182 ;;(ident (substring rchallenge 0 8)) ;ident, 8 bytes 184 ;;(ident (substring rchallenge 0 8)) ;ident, 8 bytes
183 ;;(msgType (substring rchallenge 8 12)) ;msgType, 4 bytes 185 ;;(msgType (substring rchallenge 8 12)) ;msgType, 4 bytes
@@ -188,20 +190,16 @@ by PASSWORD-HASHES. PASSWORD-HASHES should be a return value of
188 ;0x07 0x82 0x08 0x00 190 ;0x07 0x82 0x08 0x00
189 (flags (substring rchallenge 20 24)) ;flags, 4 bytes 191 (flags (substring rchallenge 20 24)) ;flags, 4 bytes
190 (challengeData (substring rchallenge 24 32)) ;challengeData, 8 bytes 192 (challengeData (substring rchallenge 24 32)) ;challengeData, 8 bytes
191 uDomain-len uDomain-offs 193 ;; Extract domain string from challenge string.
192 ;; response struct and its fields 194 ;;(uDomain-len (md4-unpack-int16 (substring uDomain 0 2)))
195 (uDomain-offs (md4-unpack-int32 (substring uDomain 4 8)))
196 ;; Response struct and its fields.
193 lmRespData ;lmRespData, 24 bytes 197 lmRespData ;lmRespData, 24 bytes
194 ntRespData ;ntRespData, variable length 198 ntRespData ;ntRespData, variable length
195 domain ;ascii domain string 199 ;; Match Mozilla behavior, which is to send an empty domain string
196 workstation ;ascii workstation string 200 (domain "") ;ascii domain string
197 ll ln lu ld lw off-lm off-nt off-u off-d off-w) 201 ;; Match Mozilla behavior, which is to send "WORKSTATION".
198 ;; extract domain string from challenge string 202 (workstation "WORKSTATION")) ;ascii workstation string
199 (setq uDomain-len (md4-unpack-int16 (substring uDomain 0 2)))
200 (setq uDomain-offs (md4-unpack-int32 (substring uDomain 4 8)))
201 ;; match Mozilla behavior, which is to send an empty domain string
202 (setq domain "")
203 ;; match Mozilla behavior, which is to send "WORKSTATION"
204 (setq workstation "WORKSTATION")
205 ;; overwrite domain in case user is given in <user>@<domain> format 203 ;; overwrite domain in case user is given in <user>@<domain> format
206 (when (string-match "@" user) 204 (when (string-match "@" user)
207 (setq domain (substring user (1+ (match-beginning 0)))) 205 (setq domain (substring user (1+ (match-beginning 0))))
@@ -260,13 +258,11 @@ by PASSWORD-HASHES. PASSWORD-HASHES should be a return value of
260 ;; so just treat it the same as levels 0 and 1 258 ;; so just treat it the same as levels 0 and 1
261 ;; check if "negotiate NTLM2 key" flag is set in type 2 message 259 ;; check if "negotiate NTLM2 key" flag is set in type 2 message
262 (if (not (zerop (logand (aref flags 2) 8))) 260 (if (not (zerop (logand (aref flags 2) 8)))
263 (let (randomString 261 ;; generate NTLM2 session response data
264 sessionHash) 262 (let* ((randomString (ntlm-generate-nonce))
265 ;; generate NTLM2 session response data 263 (sessionHash (secure-hash 'md5
266 (setq randomString (ntlm-generate-nonce))
267 (setq sessionHash (secure-hash 'md5
268 (concat challengeData randomString) 264 (concat challengeData randomString)
269 nil nil t)) 265 nil nil t)))
270 (setq sessionHash (substring sessionHash 0 8)) 266 (setq sessionHash (substring sessionHash 0 8))
271 (setq lmRespData (concat randomString (make-string 16 0))) 267 (setq lmRespData (concat randomString (make-string 16 0)))
272 (setq ntRespData (ntlm-smb-owf-encrypt 268 (setq ntRespData (ntlm-smb-owf-encrypt
@@ -278,16 +274,16 @@ by PASSWORD-HASHES. PASSWORD-HASHES should be a return value of
278 (ntlm-smb-owf-encrypt (cadr password-hashes) challengeData)))) 274 (ntlm-smb-owf-encrypt (cadr password-hashes) challengeData))))
279 275
280 ;; get offsets to fields to pack the response struct in a string 276 ;; get offsets to fields to pack the response struct in a string
281 (setq ll (length lmRespData)) 277 (let* ((ll (length lmRespData))
282 (setq ln (length ntRespData)) 278 (ln (length ntRespData))
283 (setq lu (length user)) 279 (lu (length user))
284 (setq ld (length domain)) 280 (ld (length domain))
285 (setq lw (length workstation)) 281 (lw (length workstation))
286 (setq off-u 64) ;offset to string 'uUser 282 (off-u 64) ;offset to string 'uUser
287 (setq off-d (+ off-u (* 2 lu))) ;offset to string 'uDomain 283 (off-d (+ off-u (* 2 lu))) ;offset to string 'uDomain
288 (setq off-w (+ off-d (* 2 ld))) ;offset to string 'uWks 284 (off-w (+ off-d (* 2 ld))) ;offset to string 'uWks
289 (setq off-lm (+ off-w (* 2 lw))) ;offset to string 'lmResponse 285 (off-lm (+ off-w (* 2 lw))) ;offset to string 'lmResponse
290 (setq off-nt (+ off-lm ll)) ;offset to string 'ntResponse 286 (off-nt (+ off-lm ll))) ;offset to string 'ntResponse
291 ;; pack the response struct in a string 287 ;; pack the response struct in a string
292 (concat "NTLMSSP\0" ;response ident field, 8 bytes 288 (concat "NTLMSSP\0" ;response ident field, 8 bytes
293 (md4-pack-int32 '(0 . 3)) ;response msgType field, 4 bytes 289 (md4-pack-int32 '(0 . 3)) ;response msgType field, 4 bytes
@@ -341,7 +337,7 @@ by PASSWORD-HASHES. PASSWORD-HASHES should be a return value of
341 (ntlm-ascii2unicode workstation lw) ;Unicode workstation, 2*lw bytes 337 (ntlm-ascii2unicode workstation lw) ;Unicode workstation, 2*lw bytes
342 lmRespData ;lmResponse, 24 bytes 338 lmRespData ;lmResponse, 24 bytes
343 ntRespData ;ntResponse, ln bytes 339 ntRespData ;ntResponse, ln bytes
344 ))) 340 ))))
345 341
346(defun ntlm-get-password-hashes (password) 342(defun ntlm-get-password-hashes (password)
347 "Return a pair of SMB hash and NT MD4 hash of the given password PASSWORD." 343 "Return a pair of SMB hash and NT MD4 hash of the given password PASSWORD."
@@ -351,7 +347,10 @@ by PASSWORD-HASHES. PASSWORD-HASHES should be a return value of
351(defun ntlm-ascii2unicode (str len) 347(defun ntlm-ascii2unicode (str len)
352 "Convert an ASCII string into a NT Unicode string, which is 348 "Convert an ASCII string into a NT Unicode string, which is
353little-endian utf16." 349little-endian utf16."
354 (let ((utf (make-string (* 2 len) 0)) (i 0) val) 350 ;; FIXME: Can't we use encode-coding-string with a `utf-16le' coding system?
351 (let ((utf (make-string (* 2 len) 0))
352 (i 0)
353 val)
355 (while (and (< i len) 354 (while (and (< i len)
356 (not (zerop (setq val (aref str i))))) 355 (not (zerop (setq val (aref str i)))))
357 (aset utf (* 2 i) val) 356 (aset utf (* 2 i) val)
@@ -380,9 +379,9 @@ string PASSWD. PASSWD is truncated to 14 bytes if longer."
380 "Return the response string of 24 bytes long for the given password 379 "Return the response string of 24 bytes long for the given password
381string PASSWD based on the DES encryption. PASSWD is of at most 14 380string PASSWD based on the DES encryption. PASSWD is of at most 14
382bytes long and the challenge string C8 of 8 bytes long." 381bytes long and the challenge string C8 of 8 bytes long."
383 (let ((len (min (length passwd) 16)) p22) 382 (let* ((len (min (length passwd) 16))
384 (setq p22 (concat (substring passwd 0 len) ;fill top 16 bytes with passwd 383 (p22 (concat (substring passwd 0 len) ;Fill top 16 bytes with passwd.
385 (make-string (- 22 len) 0))) 384 (make-string (- 22 len) 0))))
386 (ntlm-smb-des-e-p24 p22 c8))) 385 (ntlm-smb-des-e-p24 p22 c8)))
387 386
388(defun ntlm-smb-des-e-p24 (p22 c8) 387(defun ntlm-smb-des-e-p24 (p22 c8)
@@ -404,26 +403,26 @@ string C8."
404 "Return the hash string of length 8 for a string IN of length 8 and 403 "Return the hash string of length 8 for a string IN of length 8 and
405a string KEY of length 8. FORW is t or nil." 404a string KEY of length 8. FORW is t or nil."
406 (let ((out (make-string 8 0)) 405 (let ((out (make-string 8 0))
407 outb ;string of length 64
408 (inb (make-string 64 0)) 406 (inb (make-string 64 0))
409 (keyb (make-string 64 0)) 407 (keyb (make-string 64 0))
410 (key2 (ntlm-smb-str-to-key key)) 408 (key2 (ntlm-smb-str-to-key key))
411 (i 0) aa) 409 (i 0))
412 (while (< i 64) 410 (while (< i 64)
413 (unless (zerop (logand (aref in (/ i 8)) (ash 1 (- 7 (% i 8))))) 411 (unless (zerop (logand (aref in (/ i 8)) (ash 1 (- 7 (% i 8)))))
414 (aset inb i 1)) 412 (aset inb i 1))
415 (unless (zerop (logand (aref key2 (/ i 8)) (ash 1 (- 7 (% i 8))))) 413 (unless (zerop (logand (aref key2 (/ i 8)) (ash 1 (- 7 (% i 8)))))
416 (aset keyb i 1)) 414 (aset keyb i 1))
417 (setq i (1+ i))) 415 (setq i (1+ i)))
418 (setq outb (ntlm-smb-dohash inb keyb forw)) 416 (let ((outb (ntlm-smb-dohash inb keyb forw))
419 (setq i 0) 417 aa)
420 (while (< i 64) 418 (setq i 0)
421 (unless (zerop (aref outb i)) 419 (while (< i 64)
422 (setq aa (aref out (/ i 8))) 420 (unless (zerop (aref outb i))
423 (aset out (/ i 8) 421 (setq aa (aref out (/ i 8)))
424 (logior aa (ash 1 (- 7 (% i 8)))))) 422 (aset out (/ i 8)
425 (setq i (1+ i))) 423 (logior aa (ash 1 (- 7 (% i 8))))))
426 out)) 424 (setq i (1+ i)))
425 out)))
427 426
428(defun ntlm-smb-str-to-key (str) 427(defun ntlm-smb-str-to-key (str)
429 "Return a string of length 8 for the given string STR of length 7." 428 "Return a string of length 8 for the given string STR of length 7."
@@ -570,27 +569,22 @@ length of STR is LEN."
570 "Return the hash value for a string IN and a string KEY. 569 "Return the hash value for a string IN and a string KEY.
571Length of IN and KEY are 64. FORW non-nil means forward, nil means 570Length of IN and KEY are 64. FORW non-nil means forward, nil means
572backward." 571backward."
573 (let (pk1 ;string of length 56 572 (let* ((pk1 (ntlm-string-permute key ntlm-smb-perm1 56)) ;string of length 56
574 c ;string of length 28 573 (c (substring pk1 0 28)) ;string of length 28
575 d ;string of length 28 574 (d (substring pk1 28 56)) ;string of length 28
576 cd ;string of length 56 575 cd ;string of length 56
577 (ki (make-vector 16 0)) ;vector of string of length 48 576 (ki (make-vector 16 0)) ;vector of string of length 48
578 pd1 ;string of length 64 577 pd1 ;string of length 64
579 l ;string of length 32 578 l ;string of length 32
580 r ;string of length 32 579 r ;string of length 32
581 rl ;string of length 64 580 rl ;string of length 64
582 (i 0) (j 0) (k 0)) 581 (i 0) (j 0) (k 0))
583 (setq pk1 (ntlm-string-permute key ntlm-smb-perm1 56)) 582
584 (setq c (substring pk1 0 28)) 583 (dotimes (i 16)
585 (setq d (substring pk1 28 56))
586
587 (setq i 0)
588 (while (< i 16)
589 (setq c (ntlm-string-lshift c (aref ntlm-smb-sc i) 28)) 584 (setq c (ntlm-string-lshift c (aref ntlm-smb-sc i) 28))
590 (setq d (ntlm-string-lshift d (aref ntlm-smb-sc i) 28)) 585 (setq d (ntlm-string-lshift d (aref ntlm-smb-sc i) 28))
591 (setq cd (concat (substring c 0 28) (substring d 0 28))) 586 (setq cd (concat (substring c 0 28) (substring d 0 28)))
592 (aset ki i (ntlm-string-permute cd ntlm-smb-perm2 48)) 587 (aset ki i (ntlm-string-permute cd ntlm-smb-perm2 48)))
593 (setq i (1+ i)))
594 588
595 (setq pd1 (ntlm-string-permute in ntlm-smb-perm3 64)) 589 (setq pd1 (ntlm-string-permute in ntlm-smb-perm3 64))
596 590
@@ -649,16 +643,12 @@ backward."
649(defun ntlm-md4hash (passwd) 643(defun ntlm-md4hash (passwd)
650 "Return the 16 bytes MD4 hash of a string PASSWD after converting it 644 "Return the 16 bytes MD4 hash of a string PASSWD after converting it
651into a Unicode string. PASSWD is truncated to 128 bytes if longer." 645into a Unicode string. PASSWD is truncated to 128 bytes if longer."
652 (let (len wpwd) 646 (let* ((len (min (length passwd) 128)) ;Pwd can't be > than 128 characters.
653 ;; Password cannot be longer than 128 characters 647 ;; Password must be converted to NT Unicode.
654 (setq len (length passwd)) 648 (wpwd (ntlm-ascii2unicode passwd len)))
655 (if (> len 128) 649 (md4 wpwd
656 (setq len 128)) 650 ;; Calculate length in bytes.
657 ;; Password must be converted to NT Unicode 651 (* len 2))))
658 (setq wpwd (ntlm-ascii2unicode passwd len))
659 ;; Calculate length in bytes
660 (setq len (* len 2))
661 (md4 wpwd len)))
662 652
663(provide 'ntlm) 653(provide 'ntlm)
664 654