~ubuntu-branches/ubuntu/maverick/evolution-data-server/maverick-proposed

« back to all changes in this revision

Viewing changes to servers/exchange/xntlm/xntlm.c

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2010-05-17 17:02:06 UTC
  • mfrom: (1.1.79 upstream) (1.6.12 experimental)
  • Revision ID: james.westby@ubuntu.com-20100517170206-4ufr52vwrhh26yh0
Tags: 2.30.1-1ubuntu1
* Merge from debian experimental. Remaining change:
  (LP: #42199, #229669, #173703, #360344, #508494)
  + debian/control:
    - add Vcs-Bzr tag
    - don't use libgnome
    - Use Breaks instead of Conflicts against evolution 2.25 and earlier.
  + debian/evolution-data-server.install,
    debian/patches/45_libcamel_providers_version.patch:
    - use the upstream versioning, not a Debian-specific one 
  + debian/libedata-book1.2-dev.install, debian/libebackend-1.2-dev.install,
    debian/libcamel1.2-dev.install, debian/libedataserverui1.2-dev.install:
    - install html documentation
  + debian/rules:
    - don't build documentation it's shipped with the tarball

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
 
 
3
 
/* Copyright (C) 2001-2004 Novell, Inc.
4
 
 *
5
 
 * This program is free software; you can redistribute it and/or
6
 
 * modify it under the terms of version 2 of the GNU Lesser General Public
7
 
 * License as published by the Free Software Foundation.
8
 
 *
9
 
 * This program is distributed in the hope that it will be useful,
10
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 
 * General Public License for more details.
13
 
 *
14
 
 * You should have received a copy of the GNU Lesser General Public
15
 
 * License along with this program; if not, write to the
16
 
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17
 
 * Boston, MA 02110-1301, USA.
18
 
 */
19
 
 
20
 
#ifdef HAVE_CONFIG_H
21
 
#include <config.h>
22
 
#endif
23
 
 
24
 
#include "xntlm.h"
25
 
#include "xntlm-des.h"
26
 
#include "xntlm-md4.h"
27
 
 
28
 
#include <ctype.h>
29
 
#include <string.h>
30
 
 
31
 
static guchar NTLM_NEGOTIATE_MESSAGE[] = {
32
 
         'N',  'T',  'L',  'M',  'S',  'S',  'P', 0x00,
33
 
        0x01, 0x00, 0x00, 0x00, 0x06, 0x82, 0x00, 0x00,
34
 
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
35
 
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36
 
        0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
37
 
        0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00
38
 
};
39
 
 
40
 
/**
41
 
 * xntlm_negotiate:
42
 
 *
43
 
 * Creates an NTLM Type 1 (Negotiate) message
44
 
 *
45
 
 * Return value: the message
46
 
 **/
47
 
GByteArray *
48
 
xntlm_negotiate (void)
49
 
{
50
 
        GByteArray *message;
51
 
 
52
 
        message = g_byte_array_new ();
53
 
        g_byte_array_append (message, NTLM_NEGOTIATE_MESSAGE,
54
 
                             sizeof (NTLM_NEGOTIATE_MESSAGE));
55
 
        return message;
56
 
}
57
 
 
58
 
#define GET_SHORTY(p) ((p)[0] + ((p)[1] << 8))
59
 
 
60
 
static gchar *
61
 
strip_dup (guchar *mem, gint len)
62
 
{
63
 
        gchar *buf = g_malloc (len / 2 + 1), *p = buf;
64
 
 
65
 
        while (len > 0) {
66
 
                *p = (gchar)*mem;
67
 
                p++;
68
 
                mem += 2;
69
 
                len -= 2;
70
 
        }
71
 
 
72
 
        *p = '\0';
73
 
        return buf;
74
 
}
75
 
 
76
 
#define NTLM_CHALLENGE_NONCE_POS       24
77
 
#define NTLM_CHALLENGE_NONCE_LEN        8
78
 
 
79
 
#define NTLM_CHALLENGE_DATA_OFFSET_POS 44
80
 
#define NTLM_CHALLENGE_DATA_LENGTH_POS 40
81
 
 
82
 
#define NTLM_CHALLENGE_DATA_NT_DOMAIN   2
83
 
#define NTLM_CHALLENGE_DATA_W2K_DOMAIN  4
84
 
 
85
 
#define NTLM_CHALLENGE_BASE_SIZE       48
86
 
 
87
 
/**
88
 
 * xntlm_parse_challenge:
89
 
 * @challenge: buffer containing an NTLM Type 2 (Challenge) message
90
 
 * @len: the length of @challenge
91
 
 * @nonce: return variable for the challenge nonce, or %NULL
92
 
 * @nt_domain: return variable for the server NT domain, or %NULL
93
 
 * @w2k_domain: return variable for the server W2k domain, or %NULL
94
 
 *
95
 
 * Attempts to parse the challenge in @challenge. If @nonce is
96
 
 * non-%NULL, the 8-byte nonce from @challenge will be returned in it.
97
 
 * Likewise, if @nt_domain and/or @w2k_domain are non-%NULL, the
98
 
 * server's domain names will be returned in them. The strings
99
 
 * returned must be freed with g_free().
100
 
 *
101
 
 * Return value: %TRUE if the challenge could be parsed,
102
 
 * %FALSE otherwise.
103
 
 **/
104
 
gboolean
105
 
xntlm_parse_challenge (gpointer challenge, gint len, gchar **nonce,
106
 
                       gchar **nt_domain, gchar **w2k_domain)
107
 
{
108
 
        guchar *chall = (guchar *)challenge;
109
 
        gint off, dlen, doff, type;
110
 
 
111
 
        if (len < NTLM_CHALLENGE_BASE_SIZE)
112
 
                return FALSE;
113
 
 
114
 
        off = GET_SHORTY (chall + NTLM_CHALLENGE_DATA_OFFSET_POS);
115
 
        dlen = GET_SHORTY (chall + NTLM_CHALLENGE_DATA_LENGTH_POS);
116
 
        if (len < off + dlen)
117
 
                return FALSE;
118
 
 
119
 
        if (nonce) {
120
 
                *nonce = g_memdup (chall + NTLM_CHALLENGE_NONCE_POS,
121
 
                                   NTLM_CHALLENGE_NONCE_LEN);
122
 
        }
123
 
 
124
 
        if (!nt_domain && !w2k_domain)
125
 
                return TRUE;
126
 
 
127
 
        while (off < len - 4) {
128
 
                type = GET_SHORTY (chall + off);
129
 
                dlen = GET_SHORTY (chall + off + 2);
130
 
                doff = off + 4;
131
 
                if (doff + dlen > len)
132
 
                        break;
133
 
 
134
 
                switch (type) {
135
 
                case NTLM_CHALLENGE_DATA_NT_DOMAIN:
136
 
                        if (nt_domain)
137
 
                                *nt_domain = strip_dup (chall + doff, dlen);
138
 
                        break;
139
 
                case NTLM_CHALLENGE_DATA_W2K_DOMAIN:
140
 
                        if (w2k_domain)
141
 
                                *w2k_domain = strip_dup (chall + doff, dlen);
142
 
                        break;
143
 
                }
144
 
 
145
 
                off = doff + dlen;
146
 
        }
147
 
 
148
 
        return TRUE;
149
 
}
150
 
 
151
 
static void
152
 
ntlm_set_string (GByteArray *ba, gint offset, const gchar *data, gint len)
153
 
{
154
 
        ba->data[offset    ] = ba->data[offset + 2] =  len       & 0xFF;
155
 
        ba->data[offset + 1] = ba->data[offset + 3] = (len >> 8) & 0xFF;
156
 
        ba->data[offset + 4] =  ba->len       & 0xFF;
157
 
        ba->data[offset + 5] = (ba->len >> 8) & 0xFF;
158
 
        g_byte_array_append (ba, (guint8 *) data, len);
159
 
}
160
 
 
161
 
static void ntlm_lanmanager_hash (const gchar *password, gchar hash[21]);
162
 
static void ntlm_nt_hash         (const gchar *password, gchar hash[21]);
163
 
static void ntlm_calc_response   (const guchar key[21],
164
 
                                  const guchar plaintext[8],
165
 
                                  guchar results[24]);
166
 
 
167
 
static guchar NTLM_RESPONSE_MESSAGE_HEADER[] = {
168
 
         'N',  'T',  'L',  'M',  'S',  'S',  'P', 0x00,
169
 
        0x03, 0x00, 0x00, 0x00, 0x02, 0x82, 0x00, 0x00
170
 
};
171
 
 
172
 
#define NTLM_RESPONSE_BASE_SIZE             64
173
 
#define NTLM_RESPONSE_LM_RESP_OFFSET        12
174
 
#define NTLM_RESPONSE_NT_RESP_OFFSET        20
175
 
#define NTLM_RESPONSE_DOMAIN_OFFSET         28
176
 
#define NTLM_RESPONSE_USER_OFFSET           36
177
 
#define NTLM_RESPONSE_WORKSTATION_OFFSET    44
178
 
 
179
 
/**
180
 
 * xntlm_authenticate:
181
 
 * @nonce: the nonce from an NTLM Type 2 (Challenge) message
182
 
 * @domain: the NT domain to authenticate against
183
 
 * @user: the name of the user in @domain
184
 
 * @password: @user's password
185
 
 * @workstation: the name of the local workstation authenticated
186
 
 * against, or %NULL.
187
 
 *
188
 
 * Generates an NTLM Type 3 (Authenticate) message from the given
189
 
 * data. @workstation is provided for completeness, but can basically
190
 
 * always be left %NULL.
191
 
 *
192
 
 * Return value: the NTLM Type 3 message
193
 
 **/
194
 
GByteArray *
195
 
xntlm_authenticate (const gchar *nonce, const gchar *domain,
196
 
                    const gchar *user, const gchar *password,
197
 
                    const gchar *workstation)
198
 
{
199
 
        GByteArray *message;
200
 
        guchar hash[21], lm_resp[24], nt_resp[24];
201
 
 
202
 
        if (!workstation)
203
 
                workstation = "";
204
 
 
205
 
        message = g_byte_array_new ();
206
 
 
207
 
        ntlm_lanmanager_hash (password, (gchar *) hash);
208
 
        ntlm_calc_response (hash, (guchar *) nonce, lm_resp);
209
 
        ntlm_nt_hash (password, (gchar *) hash);
210
 
        ntlm_calc_response (hash, (guchar *) nonce, nt_resp);
211
 
 
212
 
        g_byte_array_set_size (message, NTLM_RESPONSE_BASE_SIZE);
213
 
        memset (message->data, 0, NTLM_RESPONSE_BASE_SIZE);
214
 
        memcpy (message->data, NTLM_RESPONSE_MESSAGE_HEADER,
215
 
                sizeof (NTLM_RESPONSE_MESSAGE_HEADER));
216
 
 
217
 
        ntlm_set_string (message, NTLM_RESPONSE_DOMAIN_OFFSET,
218
 
                         domain, strlen (domain));
219
 
        ntlm_set_string (message, NTLM_RESPONSE_USER_OFFSET,
220
 
                         user, strlen (user));
221
 
        ntlm_set_string (message, NTLM_RESPONSE_WORKSTATION_OFFSET,
222
 
                         workstation, strlen (workstation));
223
 
        ntlm_set_string (message, NTLM_RESPONSE_LM_RESP_OFFSET,
224
 
                         (gchar *) lm_resp, sizeof (lm_resp));
225
 
        ntlm_set_string (message, NTLM_RESPONSE_NT_RESP_OFFSET,
226
 
                         (gchar *) nt_resp, sizeof (nt_resp));
227
 
 
228
 
        return message;
229
 
}
230
 
 
231
 
static void
232
 
setup_schedule (const guchar *key_56, XNTLM_DES_KS ks)
233
 
{
234
 
        guchar key[8];
235
 
        gint i, c, bit;
236
 
 
237
 
        key[0] = (key_56[0]);
238
 
        key[1] = (key_56[1] >> 1) | ((key_56[0] << 7) & 0xFF);
239
 
        key[2] = (key_56[2] >> 2) | ((key_56[1] << 6) & 0xFF);
240
 
        key[3] = (key_56[3] >> 3) | ((key_56[2] << 5) & 0xFF);
241
 
        key[4] = (key_56[4] >> 4) | ((key_56[3] << 4) & 0xFF);
242
 
        key[5] = (key_56[5] >> 5) | ((key_56[4] << 3) & 0xFF);
243
 
        key[6] = (key_56[6] >> 6) | ((key_56[5] << 2) & 0xFF);
244
 
        key[7] =                    ((key_56[6] << 1) & 0xFF);
245
 
 
246
 
        /* Fix parity */
247
 
        for (i = 0; i < 8; i++) {
248
 
                for (c = bit = 0; bit < 8; bit++)
249
 
                        if (key [i] & (1 << bit))
250
 
                                c++;
251
 
                if (!(c & 1))
252
 
                        key [i] ^= 0x01;
253
 
        }
254
 
 
255
 
        xntlm_deskey (ks, key, XNTLM_DES_ENCRYPT);
256
 
}
257
 
 
258
 
static guchar LM_PASSWORD_MAGIC[] = {
259
 
        0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25,
260
 
        0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25,
261
 
        0x00, 0x00, 0x00, 0x00, 0x00
262
 
};
263
 
 
264
 
static void
265
 
ntlm_lanmanager_hash (const gchar *password, gchar hash[21])
266
 
{
267
 
        guchar lm_password [15];
268
 
        XNTLM_DES_KS ks;
269
 
        guint i;
270
 
 
271
 
        for (i = 0; i < 14 && password [i]; i++)
272
 
                lm_password [i] = toupper ((guchar) password [i]);
273
 
 
274
 
        for (; i < sizeof (lm_password); i++)
275
 
                lm_password [i] = '\0';
276
 
 
277
 
        memcpy (hash, LM_PASSWORD_MAGIC, sizeof (LM_PASSWORD_MAGIC));
278
 
 
279
 
        setup_schedule (lm_password, ks);
280
 
        xntlm_des (ks, (guchar *) hash);
281
 
 
282
 
        setup_schedule (lm_password + 7, ks);
283
 
        xntlm_des (ks, (guchar *) hash + 8);
284
 
}
285
 
 
286
 
static void
287
 
ntlm_nt_hash (const gchar *password, gchar hash[21])
288
 
{
289
 
        guchar *buf, *p;
290
 
 
291
 
        p = buf = g_malloc (strlen (password) * 2);
292
 
 
293
 
        while (*password) {
294
 
                *p++ = *password++;
295
 
                *p++ = '\0';
296
 
        }
297
 
 
298
 
        xntlm_md4sum (buf, p - buf, (guchar *) hash);
299
 
        memset (hash + 16, 0, 5);
300
 
 
301
 
        g_free (buf);
302
 
}
303
 
 
304
 
static void
305
 
ntlm_calc_response (const guchar key[21], const guchar plaintext[8],
306
 
                    guchar results[24])
307
 
{
308
 
        XNTLM_DES_KS ks;
309
 
 
310
 
        memcpy (results, plaintext, 8);
311
 
        memcpy (results + 8, plaintext, 8);
312
 
        memcpy (results + 16, plaintext, 8);
313
 
 
314
 
        setup_schedule (key, ks);
315
 
        xntlm_des (ks, results);
316
 
 
317
 
        setup_schedule (key + 7, ks);
318
 
        xntlm_des (ks, results + 8);
319
 
 
320
 
        setup_schedule (key + 14, ks);
321
 
        xntlm_des (ks, results + 16);
322
 
}
323