diff options
| author | Thomas Fitzsimmons | 2016-10-01 23:30:07 -0400 |
|---|---|---|
| committer | Thomas Fitzsimmons | 2016-10-05 20:18:17 -0400 |
| commit | 680e3986adaf1742a6a69ef2eb43a874ca6d5984 (patch) | |
| tree | 371df1b61dfdd21bbd45df065e91a73fe03e9476 | |
| parent | 9adfb021df482c6aa94a043f07acf1e8eb695bf2 (diff) | |
| download | emacs-680e3986adaf1742a6a69ef2eb43a874ca6d5984.tar.gz emacs-680e3986adaf1742a6a69ef2eb43a874ca6d5984.zip | |
lisp/net/ntlm.el: Match Mozilla Type 1 and 3 message behavior
* lisp/net/ntlm.el (ntlm-build-auth-request): Only set
"negotiate domain supplied" bit when a domain is supplied. Do
not set "negotiate workstation supplied" bit.
(ntlm-build-auth-response): Set domain to empty string by
default. Set workstation name to "WORKSTATION". Set flags to
logical and of Type 1 and Type 2 message flags. Remove four
trailing 0 bytes. Always set LM response. Hard-code domain
offset. Reorder buffer fields.
| -rw-r--r-- | lisp/net/ntlm.el | 86 |
1 files changed, 50 insertions, 36 deletions
diff --git a/lisp/net/ntlm.el b/lisp/net/ntlm.el index d96f3b1ebea..89f09b07448 100644 --- a/lisp/net/ntlm.el +++ b/lisp/net/ntlm.el | |||
| @@ -101,14 +101,17 @@ is not given." | |||
| 101 | (let ((request-ident (concat "NTLMSSP" (make-string 1 0))) | 101 | (let ((request-ident (concat "NTLMSSP" (make-string 1 0))) |
| 102 | (request-msgType (concat (make-string 1 1) (make-string 3 0))) | 102 | (request-msgType (concat (make-string 1 1) (make-string 3 0))) |
| 103 | ;0x01 0x00 0x00 0x00 | 103 | ;0x01 0x00 0x00 0x00 |
| 104 | (request-flags (concat (make-string 1 7) (make-string 1 178) | 104 | (request-flags (concat (make-string 1 7) (make-string 1 130) |
| 105 | (make-string 1 8) (make-string 1 0))) | 105 | (make-string 1 8) (make-string 1 0))) |
| 106 | ;0x07 0xb2 0x08 0x00 | 106 | ;0x07 0x82 0x08 0x00 |
| 107 | lu ld off-d off-u) | 107 | lu ld off-d off-u) |
| 108 | (when (string-match "@" user) | 108 | (when (and user (string-match "@" user)) |
| 109 | (unless domain | 109 | (unless domain |
| 110 | (setq domain (substring user (1+ (match-beginning 0))))) | 110 | (setq domain (substring user (1+ (match-beginning 0))))) |
| 111 | (setq user (substring user 0 (match-beginning 0)))) | 111 | (setq user (substring user 0 (match-beginning 0)))) |
| 112 | (when (and (stringp domain) (> (length domain) 0)) | ||
| 113 | ;; set "negotiate domain supplied" bit | ||
| 114 | (aset request-flags 1 (logior (aref request-flags 1) ?\x10))) | ||
| 112 | ;; set fields offsets within the request struct | 115 | ;; set fields offsets within the request struct |
| 113 | (setq lu (length user)) | 116 | (setq lu (length user)) |
| 114 | (setq ld (length domain)) | 117 | (setq ld (length domain)) |
| @@ -178,6 +181,10 @@ by PASSWORD-HASHES. PASSWORD-HASHES should be a return value of | |||
| 178 | ;;(ident (substring rchallenge 0 8)) ;ident, 8 bytes | 181 | ;;(ident (substring rchallenge 0 8)) ;ident, 8 bytes |
| 179 | ;;(msgType (substring rchallenge 8 12)) ;msgType, 4 bytes | 182 | ;;(msgType (substring rchallenge 8 12)) ;msgType, 4 bytes |
| 180 | (uDomain (substring rchallenge 12 20)) ;uDomain, 8 bytes | 183 | (uDomain (substring rchallenge 12 20)) ;uDomain, 8 bytes |
| 184 | ;; match default setting in `ntlm-build-auth-request' | ||
| 185 | (request-flags (concat (make-string 1 7) (make-string 1 130) | ||
| 186 | (make-string 1 8) (make-string 1 0))) | ||
| 187 | ;0x07 0x82 0x08 0x00 | ||
| 181 | (flags (substring rchallenge 20 24)) ;flags, 4 bytes | 188 | (flags (substring rchallenge 20 24)) ;flags, 4 bytes |
| 182 | (challengeData (substring rchallenge 24 32)) ;challengeData, 8 bytes | 189 | (challengeData (substring rchallenge 24 32)) ;challengeData, 8 bytes |
| 183 | uDomain-len uDomain-offs | 190 | uDomain-len uDomain-offs |
| @@ -185,19 +192,28 @@ by PASSWORD-HASHES. PASSWORD-HASHES should be a return value of | |||
| 185 | lmRespData ;lmRespData, 24 bytes | 192 | lmRespData ;lmRespData, 24 bytes |
| 186 | ntRespData ;ntRespData, variable length | 193 | ntRespData ;ntRespData, variable length |
| 187 | domain ;ascii domain string | 194 | domain ;ascii domain string |
| 188 | lu ld ln off-lm off-nt off-d off-u off-w off-s) | 195 | workstation ;ascii workstation string |
| 196 | ll ln lu ld lw off-lm off-nt off-u off-d off-w) | ||
| 189 | ;; extract domain string from challenge string | 197 | ;; extract domain string from challenge string |
| 190 | (setq uDomain-len (md4-unpack-int16 (substring uDomain 0 2))) | 198 | (setq uDomain-len (md4-unpack-int16 (substring uDomain 0 2))) |
| 191 | (setq uDomain-offs (md4-unpack-int32 (substring uDomain 4 8))) | 199 | (setq uDomain-offs (md4-unpack-int32 (substring uDomain 4 8))) |
| 192 | (setq domain | 200 | ;; match Mozilla behavior, which is to send an empty domain string |
| 193 | (ntlm-unicode2ascii (substring challenge | 201 | (setq domain "") |
| 194 | (cdr uDomain-offs) | 202 | ;; match Mozilla behavior, which is to send "WORKSTATION" |
| 195 | (+ (cdr uDomain-offs) uDomain-len)) | 203 | (setq workstation "WORKSTATION") |
| 196 | (/ uDomain-len 2))) | ||
| 197 | ;; overwrite domain in case user is given in <user>@<domain> format | 204 | ;; overwrite domain in case user is given in <user>@<domain> format |
| 198 | (when (string-match "@" user) | 205 | (when (string-match "@" user) |
| 199 | (setq domain (substring user (1+ (match-beginning 0)))) | 206 | (setq domain (substring user (1+ (match-beginning 0)))) |
| 200 | (setq user (substring user 0 (match-beginning 0)))) | 207 | (setq user (substring user 0 (match-beginning 0)))) |
| 208 | (when (and (stringp domain) (> (length domain) 0)) | ||
| 209 | ;; set "negotiate domain supplied" bit, since presumably domain | ||
| 210 | ;; was also set in `ntlm-build-auth-request' | ||
| 211 | (aset request-flags 1 (logior (aref request-flags 1) ?\x10))) | ||
| 212 | ;; match Mozilla behavior, which is to send the logical and of the | ||
| 213 | ;; type 1 and type 2 flags | ||
| 214 | (dotimes (index 4) | ||
| 215 | (aset flags index (logand (aref flags index) | ||
| 216 | (aref request-flags index)))) | ||
| 201 | 217 | ||
| 202 | (unless (and (integerp ntlm-compatibility-level) | 218 | (unless (and (integerp ntlm-compatibility-level) |
| 203 | (>= ntlm-compatibility-level 0) | 219 | (>= ntlm-compatibility-level 0) |
| @@ -228,17 +244,15 @@ by PASSWORD-HASHES. PASSWORD-HASHES should be a return value of | |||
| 228 | (ntlm-compute-timestamp) ; timestamp | 244 | (ntlm-compute-timestamp) ; timestamp |
| 229 | nonce ; client nonce | 245 | nonce ; client nonce |
| 230 | (make-string 4 0) ; unknown | 246 | (make-string 4 0) ; unknown |
| 231 | targetInfo ; target info | 247 | targetInfo)) ; target info |
| 232 | (make-string 4 0))) ; unknown | ||
| 233 | ;; for reference: LMv2 interim calculation | 248 | ;; for reference: LMv2 interim calculation |
| 234 | ;; (lm-interim (hmac-md5 (concat challengeData nonce) | 249 | (lm-interim (hmac-md5 (concat challengeData nonce) |
| 235 | ;; ntlmv2-hash)) | 250 | ntlmv2-hash)) |
| 236 | (nt-interim (hmac-md5 (concat challengeData blob) | 251 | (nt-interim (hmac-md5 (concat challengeData blob) |
| 237 | ntlmv2-hash))) | 252 | ntlmv2-hash))) |
| 238 | ;; for reference: LMv2 field, but match other clients that | 253 | ;; for reference: LMv2 field, but match other clients that |
| 239 | ;; send all zeros | 254 | ;; send all zeros |
| 240 | ;; (setq lmRespData (concat lm-interim nonce)) | 255 | (setq lmRespData (concat lm-interim nonce)) |
| 241 | (setq lmRespData (make-string 24 0)) | ||
| 242 | (setq ntRespData (concat nt-interim blob)))) | 256 | (setq ntRespData (concat nt-interim blob)))) |
| 243 | ;; compatibility level is 2, 1 or 0 | 257 | ;; compatibility level is 2, 1 or 0 |
| 244 | ;; level 2 should be treated specially but it's not clear how, | 258 | ;; level 2 should be treated specially but it's not clear how, |
| @@ -263,23 +277,24 @@ by PASSWORD-HASHES. PASSWORD-HASHES should be a return value of | |||
| 263 | (ntlm-smb-owf-encrypt (cadr password-hashes) challengeData)))) | 277 | (ntlm-smb-owf-encrypt (cadr password-hashes) challengeData)))) |
| 264 | 278 | ||
| 265 | ;; get offsets to fields to pack the response struct in a string | 279 | ;; get offsets to fields to pack the response struct in a string |
| 280 | (setq ll (length lmRespData)) | ||
| 281 | (setq ln (length ntRespData)) | ||
| 266 | (setq lu (length user)) | 282 | (setq lu (length user)) |
| 267 | (setq ld (length domain)) | 283 | (setq ld (length domain)) |
| 268 | (setq ln (length ntRespData)) | 284 | (setq lw (length workstation)) |
| 269 | (setq off-lm 64) ;offset to string 'lmResponse | 285 | (setq off-u 64) ;offset to string 'uUser |
| 270 | (setq off-nt (+ 64 24)) ;offset to string 'ntResponse | 286 | (setq off-d (+ off-u (* 2 lu))) ;offset to string 'uDomain |
| 271 | (setq off-d (+ 64 24 ln)) ;offset to string 'uDomain | 287 | (setq off-w (+ off-d (* 2 ld))) ;offset to string 'uWks |
| 272 | (setq off-u (+ 64 24 ln (* 2 ld))) ;offset to string 'uUser | 288 | (setq off-lm (+ off-w (* 2 lw))) ;offset to string 'lmResponse |
| 273 | (setq off-w (+ 64 24 ln (* 2 (+ ld lu)))) ;offset to string 'uWks | 289 | (setq off-nt (+ off-lm ll)) ;offset to string 'ntResponse |
| 274 | (setq off-s (+ 64 24 ln (* 2 (+ ld lu lu)))) ;offset to string 'sessionKey | ||
| 275 | ;; pack the response struct in a string | 290 | ;; pack the response struct in a string |
| 276 | (concat "NTLMSSP\0" ;response ident field, 8 bytes | 291 | (concat "NTLMSSP\0" ;response ident field, 8 bytes |
| 277 | (md4-pack-int32 '(0 . 3)) ;response msgType field, 4 bytes | 292 | (md4-pack-int32 '(0 . 3)) ;response msgType field, 4 bytes |
| 278 | 293 | ||
| 279 | ;; lmResponse field, 8 bytes | 294 | ;; lmResponse field, 8 bytes |
| 280 | ;;AddBytes(response,lmResponse,lmRespData,24); | 295 | ;;AddBytes(response,lmResponse,lmRespData,24); |
| 281 | (md4-pack-int16 24) ;len field | 296 | (md4-pack-int16 ll) ;len field |
| 282 | (md4-pack-int16 24) ;maxlen field | 297 | (md4-pack-int16 ll) ;maxlen field |
| 283 | (md4-pack-int32 (cons 0 off-lm)) ;field offset | 298 | (md4-pack-int32 (cons 0 off-lm)) ;field offset |
| 284 | 299 | ||
| 285 | ;; ntResponse field, 8 bytes | 300 | ;; ntResponse field, 8 bytes |
| @@ -293,7 +308,9 @@ by PASSWORD-HASHES. PASSWORD-HASHES should be a return value of | |||
| 293 | ;;AddBytes(response, uDomain, udomain, 2*ld); | 308 | ;;AddBytes(response, uDomain, udomain, 2*ld); |
| 294 | (md4-pack-int16 (* 2 ld)) ;len field | 309 | (md4-pack-int16 (* 2 ld)) ;len field |
| 295 | (md4-pack-int16 (* 2 ld)) ;maxlen field | 310 | (md4-pack-int16 (* 2 ld)) ;maxlen field |
| 296 | (md4-pack-int32 (cons 0 off-d)) ;field offset | 311 | ;; match Mozilla behavior, which is to hard-code the |
| 312 | ;; domain offset to 64 | ||
| 313 | (md4-pack-int32 (cons 0 64)) ;field offset | ||
| 297 | 314 | ||
| 298 | ;; uUser field, 8 bytes | 315 | ;; uUser field, 8 bytes |
| 299 | ;;AddUnicodeString(response,uUser,u); | 316 | ;;AddUnicodeString(response,uUser,u); |
| @@ -304,28 +321,25 @@ by PASSWORD-HASHES. PASSWORD-HASHES should be a return value of | |||
| 304 | 321 | ||
| 305 | ;; uWks field, 8 bytes | 322 | ;; uWks field, 8 bytes |
| 306 | ;;AddUnicodeString(response,uWks,u); | 323 | ;;AddUnicodeString(response,uWks,u); |
| 307 | (md4-pack-int16 (* 2 lu)) ;len field | 324 | (md4-pack-int16 (* 2 lw)) ;len field |
| 308 | (md4-pack-int16 (* 2 lu)) ;maxlen field | 325 | (md4-pack-int16 (* 2 lw)) ;maxlen field |
| 309 | (md4-pack-int32 (cons 0 off-w)) ;field offset | 326 | (md4-pack-int32 (cons 0 off-w)) ;field offset |
| 310 | 327 | ||
| 311 | ;; sessionKey field, 8 bytes | 328 | ;; sessionKey field, blank, 8 bytes |
| 312 | ;;AddString(response,sessionKey,NULL); | 329 | ;;AddString(response,sessionKey,NULL); |
| 313 | (md4-pack-int16 0) ;len field | 330 | (md4-pack-int16 0) ;len field |
| 314 | (md4-pack-int16 0) ;maxlen field | 331 | (md4-pack-int16 0) ;maxlen field |
| 315 | (md4-pack-int32 (cons 0 (- off-s off-lm))) ;field offset | 332 | (md4-pack-int32 (cons 0 0)) ;field offset |
| 316 | 333 | ||
| 317 | ;; flags field, 4 bytes | 334 | ;; flags field, 4 bytes |
| 318 | flags ; | 335 | flags ; |
| 319 | 336 | ||
| 320 | ;; buffer field | 337 | ;; buffer field |
| 338 | (ntlm-ascii2unicode user lu) ;Unicode user, 2*lu bytes | ||
| 339 | (ntlm-ascii2unicode domain ld) ;Unicode domain, 2*ld bytes | ||
| 340 | (ntlm-ascii2unicode workstation lw) ;Unicode workstation, 2*lw bytes | ||
| 321 | lmRespData ;lmResponse, 24 bytes | 341 | lmRespData ;lmResponse, 24 bytes |
| 322 | ntRespData ;ntResponse, 24 bytes | 342 | ntRespData ;ntResponse, ln bytes |
| 323 | (ntlm-ascii2unicode domain ;Unicode domain string, 2*ld bytes | ||
| 324 | (length domain)) ; | ||
| 325 | (ntlm-ascii2unicode user ;Unicode user string, 2*lu bytes | ||
| 326 | (length user)) ; | ||
| 327 | (ntlm-ascii2unicode user ;Unicode user string, 2*lu bytes | ||
| 328 | (length user)) ; | ||
| 329 | ))) | 343 | ))) |
| 330 | 344 | ||
| 331 | (defun ntlm-get-password-hashes (password) | 345 | (defun ntlm-get-password-hashes (password) |