1 ;;; ntlm.el --- NTLM (NT LanManager) authentication support
3 ;; Copyright (C) 2001, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
5 ;; Author: Taro Kawagishi <tarok@transpulse.org>
6 ;; Keywords: NTLM, SASL
8 ;; Created: February 2001
10 ;; This file is part of GNU Emacs.
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 of the License, or
15 ;; (at your option) any later version.
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.
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
27 ;; This library is a direct translation of the Samba release 2.2.0
28 ;; implementation of Windows NT and LanManager compatible password
31 ;; Interface functions:
33 ;; ntlm-build-auth-request
34 ;; This will return a binary string, which should be used in the
35 ;; base64 encoded form and it is the caller's responsibility to encode
36 ;; the returned string with base64.
38 ;; ntlm-build-auth-response
39 ;; It is the caller's responsibility to pass a base64 decoded string
40 ;; (which will be a binary string) as the first argument and to
41 ;; encode the returned string with base64. The second argument user
42 ;; should be given in user@domain format.
44 ;; ntlm-get-password-hashes
47 ;; NTLM authentication procedure example:
49 ;; 1. Open a network connection to the Exchange server at the IMAP port (143)
50 ;; 2. Receive an opening message such as:
51 ;; "* OK Microsoft Exchange IMAP4rev1 server version 5.5.2653.7 (XXXX) ready"
52 ;; 3. Ask for IMAP server capability by sending "NNN capability"
53 ;; 4. Receive a capability message such as:
54 ;; "* CAPABILITY IMAP4 IMAP4rev1 IDLE LITERAL+ LOGIN-REFERRALS MAILBOX-REFERRALS NAMESPACE AUTH=NTLM"
55 ;; 5. Ask for NTLM authentication by sending a string
56 ;; "NNN authenticate ntlm"
57 ;; 6. Receive continuation acknowledgment "+"
58 ;; 7. Send NTLM authentication request generated by 'ntlm-build-auth-request
59 ;; 8. Receive NTLM challenge string following acknowledgment "+"
60 ;; 9. Generate response to challenge by 'ntlm-build-auth-response
61 ;; (here two hash function values of the user password are encrypted)
62 ;; 10. Receive authentication completion message such as
63 ;; "NNN OK AUTHENTICATE NTLM completed."
70 ;;; NTLM authentication interface functions
72 (defun ntlm-build-auth-request (user &optional domain)
73 "Return the NTLM authentication request string for USER and DOMAIN.
74 USER is a string representing a user name to be authenticated and
75 DOMAIN is a NT domain. USER can include a NT domain part as in
76 user@domain where the string after @ is used as the domain if DOMAIN
79 (let ((request-ident (concat "NTLMSSP" (make-string 1 0)))
80 (request-msgType (concat (make-string 1 1) (make-string 3 0)))
82 (request-flags (concat (make-string 1 7) (make-string 1 178)
86 (when (string-match "@" user)
88 (setq domain (substring user (1+ (match-beginning 0)))))
89 (setq user (substring user 0 (match-beginning 0))))
90 ;; set fields offsets within the request struct
91 (setq lu (length user))
92 (setq ld (length domain))
93 (setq off-u 32) ;offset to the string 'user
94 (setq off-d (+ 32 lu)) ;offset to the string 'domain
95 ;; pack the request struct in a string
96 (concat request-ident ;8 bytes
97 request-msgType ;4 bytes
98 request-flags ;4 bytes
99 (md4-pack-int16 lu) ;user field, count field
100 (md4-pack-int16 lu) ;user field, max count field
101 (md4-pack-int32 (cons 0 off-u)) ;user field, offset field
102 (md4-pack-int16 ld) ;domain field, count field
103 (md4-pack-int16 ld) ;domain field, max count field
104 (md4-pack-int32 (cons 0 off-d)) ;domain field, offset field
110 (defmacro ntlm-string-as-unibyte (string)
111 (if (fboundp 'string-as-unibyte)
112 `(string-as-unibyte ,string)
115 (defun ntlm-build-auth-response (challenge user password-hashes)
116 "Return the response string to a challenge string CHALLENGE given by
117 the NTLM based server for the user USER and the password hash list
118 PASSWORD-HASHES. NTLM uses two hash values which are represented
119 by PASSWORD-HASHES. PASSWORD-HASHES should be a return value of
120 (list (ntlm-smb-passwd-hash password) (ntlm-md4hash password))"
121 (let* ((rchallenge (ntlm-string-as-unibyte challenge))
122 ;; get fields within challenge struct
123 ;;(ident (substring rchallenge 0 8)) ;ident, 8 bytes
124 ;;(msgType (substring rchallenge 8 12)) ;msgType, 4 bytes
125 (uDomain (substring rchallenge 12 20)) ;uDomain, 8 bytes
126 (flags (substring rchallenge 20 24)) ;flags, 4 bytes
127 (challengeData (substring rchallenge 24 32)) ;challengeData, 8 bytes
128 uDomain-len uDomain-offs
129 ;; response struct and its fields
130 lmRespData ;lmRespData, 24 bytes
131 ntRespData ;ntRespData, 24 bytes
132 domain ;ascii domain string
133 lu ld off-lm off-nt off-d off-u off-w off-s)
134 ;; extract domain string from challenge string
135 (setq uDomain-len (md4-unpack-int16 (substring uDomain 0 2)))
136 (setq uDomain-offs (md4-unpack-int32 (substring uDomain 4 8)))
138 (ntlm-unicode2ascii (substring challenge