"Fossies" - the Fresh Open Source Software Archive 
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /*
2 * $Id: ntlmssp.inc.c,v 1.2.4.1 2003/02/23 15:56:26 casz Exp $
3 *
4 */
5
6 #define MAX_HOSTLEN 32
7 #define MAX_DOMLEN 32
8 #define MAX_USERLEN 32
9 #define RESP_LEN 24
10 #define NONCE_LEN 8
11
12 /* fhz, 01-10-15 : borrowed from samba code */
13 /* NTLMSSP negotiation flags */
14 #define NTLMSSP_NEGOTIATE_UNICODE 0x00000001
15 #define NTLMSSP_NEGOTIATE_OEM 0x00000002
16 #define NTLMSSP_REQUEST_TARGET 0x00000004
17 #define NTLMSSP_NEGOTIATE_SIGN 0x00000010
18 #define NTLMSSP_NEGOTIATE_SEAL 0x00000020
19 #define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080
20 #define NTLMSSP_NEGOTIATE_NTLM 0x00000200
21 #define NTLMSSP_NEGOTIATE_00001000 0x00001000
22 #define NTLMSSP_NEGOTIATE_00002000 0x00002000
23 #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000
24 #define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000
25 #define NTLMSSP_TARGET_TYPE_SERVER 0x00020000
26 #define NTLMSSP_NEGOTIATE_NTLM2 0x00080000
27 #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000
28 #define NTLMSSP_NEGOTIATE_128 0x20000000
29 #define NTLMSSP_NEGOTIATE_KEY_EXCH 0x40000000
30
31 #define SMBD_NTLMSSP_NEG_FLAGS 0x000082b1
32 #define NTLM_NTLMSSP_NEG_FLAGS 0x00008206
33 /* 8201 8207 */
34
35 #define LEN_NTLMSSP_FLAGS 4
36 #define OFFSET_MSG1_NTLMSSP_FLAGS 12
37
38 struct ntlm_msg1 {
39 unsigned char protocol[8];
40 unsigned char type; /* 1 */
41 unsigned char zero1[3];
42 unsigned char flags[2];
43 unsigned char zero2[2];
44
45 unsigned char dom_len[4];
46 unsigned char dom_off[4];
47
48 unsigned char host_len[4];
49 unsigned char host_off[4];
50
51 #if 0
52 unsigned char data[0];
53 #endif
54 } __attribute__((packed));
55
56 struct ntlm_msg2 {
57 unsigned char protocol[8];
58 unsigned char type; /* 2 */
59 unsigned char zero1[7];
60 unsigned char msg_len[4];
61 unsigned char flags[2];
62 unsigned char zero2[2];
63
64 unsigned char nonce[8];
65 unsigned char zero3[8];
66 } __attribute__((packed));
67
68 struct ntlm_msg3 {
69 unsigned char protocol[8];
70 unsigned char type; /* 3 */
71 unsigned char zero1[3];
72
73 unsigned char lm_len[4];
74 unsigned char lm_off[4];
75
76 unsigned char nt_len[4];
77 unsigned char nt_off[4];
78
79 unsigned char dom_len[4];
80 unsigned char dom_off[4];
81
82 unsigned char user_len[4];
83 unsigned char user_off[4];
84
85 unsigned char host_len[4];
86 unsigned char host_off[4];
87
88 unsigned char msg_len[4]; /* Win9x: data begins here! */
89
90 #if 0
91 unsigned char data[0];
92 #endif
93 } __attribute__((packed));
94
95 struct ntlm_msg2_win9x {
96 unsigned char protocol[8];
97 unsigned char type; /* 2 */
98 unsigned char zero1[3];
99 unsigned char dom_len1[2];
100 unsigned char dom_len2[2];
101 unsigned char dom_off[4];
102 unsigned char flags[2];
103 unsigned char zero2[2];
104
105 unsigned char nonce[8];
106 unsigned char zero3[8];
107 unsigned char zero4[4];
108 unsigned char msg_len[4];
109 unsigned char dom[MAX_DOMLEN];
110 } __attribute__((packed));
111
112 /* size without dom[] : */
113 #define NTLM_MSG2_WIN9X_FIXED_SIZE (sizeof(struct ntlm_msg2_win9x)-MAX_DOMLEN)
114
115
116 typedef struct ntlmssp_info {
117 int msg_type;
118 unsigned char user[MAX_USERLEN + 1];
119 unsigned char host[MAX_HOSTLEN + 1];
120 unsigned char domain[MAX_DOMLEN + 1];
121 unsigned char lm[RESP_LEN];
122 unsigned char nt[RESP_LEN];
123 } ntlmssp_info_rec;
124
125 #define little_endian_word(x) x[0] + (((unsigned)x[1]) << 8)
126 /* fhz 02-02-09: typecasting is needed for a generic use */
127 #define set_little_endian_word(x,y) (*((char *)x))=(y&0xff);*(((char*)x)+1)=((y>>8)&0xff)
128
129 static int
130 ntlm_msg_type(unsigned char *raw_msg, unsigned msglen)
131 {
132 struct ntlm_msg1 *msg = (struct ntlm_msg1 *) raw_msg;
133
134 if (msglen < 9)
135 return -1;
136 if (strncmp(msg->protocol, "NTLMSSP", 8))
137 return -1;
138 return msg->type;
139 }
140
141 static int
142 ntlm_extract_mem(request_rec * r, unsigned char *dst,
143 unsigned char *src, unsigned srclen,
144 unsigned char *off, unsigned char *len,
145 unsigned max)
146 {
147 unsigned o = little_endian_word(off);
148 unsigned l = little_endian_word(len);
149 if (l > max)
150 return -1;
151 if (o >= srclen)
152 return -1;
153 if (o + l > srclen)
154 return -1;
155 src += o;
156 while (l-- > 0)
157 *dst++ = *src++;
158 return 0;
159 }
160
161 static int
162 ntlm_extract_string(request_rec * r, unsigned char *dst,
163 unsigned char *src, unsigned srclen,
164 unsigned char *off, unsigned char *len,
165 unsigned max)
166 {
167 unsigned o = little_endian_word(off);
168 unsigned l = little_endian_word(len);
169 if (l > max)
170 return -1;
171 if (o >= srclen)
172 return -1;
173 if (o + l > srclen)
174 return -1;
175 src += o;
176 while (l-- > 0) {
177 /* +csz 2003/02/20 - En algunos casos vienen \0 entremedio */
178 if ( *src != '\0' ) {
179 *dst = *src;
180 dst++;
181 }
182 src++;
183 }
184 *dst = 0;
185 return 0;
186 }
187
188 static int
189 ntlm_put_in_unicode(unsigned char *dst,
190 unsigned char *src, unsigned srclen, unsigned max)
191 {
192 unsigned l = srclen*2;
193 if (l > max)
194 l=max; /* fhz: bad very bad */
195 while (l > 0) {
196 /* ASCII to unicode*/
197 *dst++ = *src++;
198 *dst++=0;
199 l -=2;
200 }
201 return 0;
202
203
204
205 }
206
207 static int
208 ntlm_extract_unicode(request_rec * r, unsigned char *dst,
209 unsigned char *src, unsigned srclen,
210 unsigned char *off, unsigned char *len,
211 unsigned max)
212 {
213 unsigned o = little_endian_word(off);
214 unsigned l = little_endian_word(len) / 2; /* Unicode! */
215 if (l > max)
216 return -1;
217 if (o >= srclen)
218 return -1;
219 if (o + l > srclen)
220 return -1;
221 src += o;
222 while (l > 0) {
223 /* Unicode to ASCII */
224 *dst++ = *src;
225 src += 2;
226 l -= 2;
227 }
228 *dst = 0;
229 return 0;
230 }
231
232 static int
233 ntlm_msg1_getntlmssp_flags(request_rec * r, unsigned char *raw_msg,
234 unsigned char *ntlmssp_flags)
235 {
236 struct ntlm_msg1 *msg = (struct ntlm_msg1 *) raw_msg;
237 *ntlmssp_flags=little_endian_word(msg->flags);
238 return 0;
239 }
240
241 static int
242 ntlm_msg1_gethostname(request_rec * r, unsigned char *raw_msg,
243 unsigned msglen, unsigned char *hostname)
244 {
245 struct ntlm_msg1 *msg = (struct ntlm_msg1 *) raw_msg;
246 if (ntlm_extract_string(r, hostname, (char *) msg, msglen,
247 msg->host_off, msg->host_len, MAX_HOSTLEN))
248 return 1;
249 return 0;
250 }
251
252 static int
253 ntlm_msg1_getdomainname(request_rec * r, unsigned char *raw_msg,
254 unsigned msglen, unsigned char *domainname)
255 {
256 struct ntlm_msg1 *msg = (struct ntlm_msg1 *) raw_msg;
257 if (ntlm_extract_string(r, domainname, (char *) msg,
258 msglen, msg->dom_off, msg->dom_len, MAX_DOMLEN))
259 return 2;
260 return 0;
261 }
262
263 static int
264 ntlm_msg3_getlm(request_rec * r, unsigned char *raw_msg, unsigned msglen,
265 unsigned char *lm)
266 {
267 struct ntlm_msg3 *msg = (struct ntlm_msg3 *) raw_msg;
268 if (ntlm_extract_mem(r, lm, (char *) msg, msglen, msg->lm_off,
269 msg->lm_len, RESP_LEN))
270 return 4;
271 return 0;
272 }
273
274 static int
275 ntlm_msg3_getnt(request_rec * r, unsigned char *raw_msg, unsigned msglen,
276 unsigned char *nt)
277 {
278 struct ntlm_msg3 *msg = (struct ntlm_msg3 *) raw_msg;
279 if (ntlm_extract_mem(r, nt, (char *) msg, msglen, msg->nt_off,
280 msg->nt_len, RESP_LEN))
281 /* Win9x: we can't extract nt ... so we use lm... */
282 if (ntlm_extract_mem(r, nt, (char *) msg, msglen, msg->lm_off,
283 msg->lm_len, RESP_LEN))
284 return 8;
285 return 0;
286 }
287
288 static int
289 ntlm_msg3_getusername(request_rec * r, unsigned char *raw_msg,
290 unsigned msglen, unsigned char *username,
291 unsigned ntlmssp_flags)
292 {
293 struct ntlm_msg3 *msg = (struct ntlm_msg3 *) raw_msg;
294 int c;
295 if (ntlmssp_flags & NTLMSSP_NEGOTIATE_UNICODE) {
296 if (ntlm_extract_unicode(r, username, (char *) msg, msglen,
297 msg->user_off, msg->user_len, MAX_USERLEN))
298 return 16;
299 }
300 else { /* ascii */
301 if (ntlm_extract_string(r, username, (char *) msg, msglen,
302 msg->user_off, msg->user_len, MAX_USERLEN))
303 return 16;
304 else {
305 /* Win9x client leave username in uppercase...fix it: */
306 while (*username!=(unsigned char)NULL) {
307 c=tolower((int)*username);
308 *username=(unsigned char)c;
309 username++;
310 }
311 }
312 }
313 return 0;
314 }
315
316 static int
317 ntlm_msg3_gethostname(request_rec * r, unsigned char *raw_msg, unsigned msglen,
318 unsigned char *hostname,unsigned ntlmssp_flags)
319 {
320 struct ntlm_msg3 *msg = (struct ntlm_msg3 *) raw_msg;
321 if (ntlmssp_flags & NTLMSSP_NEGOTIATE_UNICODE) {
322 if (ntlm_extract_unicode(r, hostname, (char *) msg, msglen,
323 msg->host_off, msg->host_len, MAX_HOSTLEN))
324 return 0; /* this one FAILS, but since the value is not used,
325 * we just pretend it was ok. */
326 }
327 else { /* ascii */
328 if (ntlm_extract_string(r, hostname, (char *) msg, msglen,
329 msg->host_off, msg->host_len, MAX_HOSTLEN))
330 return 0; /* this one FAILS, but since the value is not used,
331 * we just pretend it was ok. */
332 }
333 return 0;
334 }
335
336 static int
337 ntlm_msg3_getdomainname(request_rec * r, unsigned char *raw_msg,
338 unsigned msglen, unsigned char *domainname,
339 unsigned ntlmssp_flags)
340 {
341 struct ntlm_msg3 *msg = (struct ntlm_msg3 *) raw_msg;
342 if (ntlmssp_flags & NTLMSSP_NEGOTIATE_UNICODE) {
343 if (ntlm_extract_unicode(r, domainname, (char *) msg, msglen,
344 msg->dom_off, msg->dom_len, MAX_DOMLEN))
345 return 64;
346 }
347 else { /* asii */
348 if (ntlm_extract_string(r, domainname, (char *) msg, msglen,
349 msg->dom_off, msg->dom_len, MAX_DOMLEN))
350 return 64;
351 }
352 return 0;
353 }
354
355 static int
356 ntlm_decode_msg(request_rec * r, struct ntlmssp_info *info,
357 unsigned char *raw_msg, unsigned msglen,
358 unsigned *ntlmssp_flags)
359 {
360 switch (info->msg_type = ntlm_msg_type(raw_msg, msglen)) {
361 case 1:
362 return ntlm_msg1_getntlmssp_flags(r,raw_msg,(unsigned char*)ntlmssp_flags)
363 + ntlm_msg1_gethostname(r, raw_msg, msglen, info->host)
364 + ntlm_msg1_getdomainname(r, raw_msg, msglen, info->domain);
365 case 3:
366 return ntlm_msg3_getlm(r, raw_msg, msglen, info->lm)
367 + ntlm_msg3_getnt(r, raw_msg, msglen, info->nt)
368 + ntlm_msg3_getusername(r, raw_msg, msglen, info->user,*ntlmssp_flags)
369 + ntlm_msg3_gethostname(r, raw_msg, msglen, info->host,*ntlmssp_flags)
370 + ntlm_msg3_getdomainname(r, raw_msg, msglen, info->domain,*ntlmssp_flags);
371 }
372 return -1;
373 }
374
375 static int
376 ntlm_encode_msg2(unsigned char *nonce, struct ntlm_msg2 *msg)
377 {
378 memset(msg, 0, sizeof(struct ntlm_msg2));
379 strcpy(msg->protocol, "NTLMSSP");
380 msg->type = 0x02;
381 set_little_endian_word(msg->msg_len, sizeof(struct ntlm_msg2));
382 set_little_endian_word(msg->flags, 0x8201);
383 memcpy(msg->nonce, nonce, sizeof(msg->nonce));
384 return 0;
385 }
386
387 static int
388 ntlm_encode_msg2_win9x(unsigned char *nonce, struct ntlm_msg2_win9x *msg,char *domainname,unsigned ntlmssp_flags)
389 {
390 unsigned int size,len,flags;
391
392 memset(msg, 0, sizeof(struct ntlm_msg2_win9x));
393 strcpy(msg->protocol, "NTLMSSP");
394 msg->type = 0x02;
395 if (ntlmssp_flags & NTLMSSP_NEGOTIATE_UNICODE) {
396 /* unicode case */
397
398 len=strlen(domainname);
399 ntlm_put_in_unicode((char *)msg->dom,domainname,
400 len, MAX_DOMLEN);
401 len=len*2;
402 if (len>MAX_DOMLEN)
403 len=MAX_DOMLEN; /* fhz: bad very bad */
404 flags=NTLM_NTLMSSP_NEG_FLAGS | NTLMSSP_NEGOTIATE_UNICODE;
405 } else {
406 /* ascii case */
407 len=strlen(domainname);
408 if (len>MAX_DOMLEN)
409 len=MAX_DOMLEN; /* fhz: bad very bad */
410 strncpy(msg->dom,domainname,len);
411 flags=NTLM_NTLMSSP_NEG_FLAGS;
412 }
413 size=NTLM_MSG2_WIN9X_FIXED_SIZE+len;
414 set_little_endian_word(msg->dom_off, NTLM_MSG2_WIN9X_FIXED_SIZE);
415 set_little_endian_word(msg->dom_len1,len);
416 set_little_endian_word(msg->dom_len2,len);
417 set_little_endian_word(msg->msg_len,size);
418 set_little_endian_word(msg->flags,flags);
419 if (ntlmssp_flags & NTLMSSP_REQUEST_TARGET)
420 set_little_endian_word(msg->zero2, 0x01); /* == set NTLMSSP_TARGET_TYPE_DOMAIN */
421
422 memcpy(msg->nonce, nonce, sizeof(msg->nonce));
423 return size;
424 }