1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * NT Lan Manager Security Support Provider (NTLMSSP)
28 *
29 * Based on information from the "Davenport NTLM" page:
30 * http://davenport.sourceforge.net/ntlm.html
31 */
32
33
34 #include <errno.h>
35 #include <stdio.h>
36 #include <stddef.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <strings.h>
40 #include <netdb.h>
41 #include <libintl.h>
42 #include <xti.h>
43 #include <assert.h>
44
45 #include <sys/types.h>
46 #include <sys/time.h>
47 #include <sys/byteorder.h>
48 #include <sys/socket.h>
49 #include <sys/fcntl.h>
50
51 #include <netinet/in.h>
52 #include <netinet/tcp.h>
53 #include <arpa/inet.h>
54
55 #include <netsmb/smb.h>
56 #include <netsmb/smb_lib.h>
57 #include <netsmb/mchain.h>
58
59 #include "private.h"
60 #include "charsets.h"
61 #include "spnego.h"
62 #include "derparse.h"
63 #include "ssp.h"
64 #include "ntlm.h"
65 #include "ntlmssp.h"
66
67 typedef struct ntlmssp_state {
68 uint32_t ss_flags;
69 char *ss_target_name;
70 struct mbuf *ss_target_info;
71 } ntlmssp_state_t;
72
73 /*
74 * So called "security buffer".
75 * A lot like an RPC string.
76 */
77 struct sec_buf {
78 uint16_t sb_length;
79 uint16_t sb_maxlen;
80 uint32_t sb_offset;
81 };
82 #define ID_SZ 8
83 static const char ntlmssp_id[ID_SZ] = "NTLMSSP";
84
85 /*
86 * Get a "security buffer" (header part)
87 */
88 static int
md_get_sb_hdr(struct mbdata * mbp,struct sec_buf * sb)89 md_get_sb_hdr(struct mbdata *mbp, struct sec_buf *sb)
90 {
91 int err;
92
93 (void) md_get_uint16le(mbp, &sb->sb_length);
94 (void) md_get_uint16le(mbp, &sb->sb_maxlen);
95 err = md_get_uint32le(mbp, &sb->sb_offset);
96
97 return (err);
98 }
99
100 /*
101 * Get a "security buffer" (data part), where
102 * the data is delivered as an mbuf.
103 */
104 static int
md_get_sb_data(struct mbdata * mbp,struct sec_buf * sb,struct mbuf ** mp)105 md_get_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf **mp)
106 {
107 struct mbdata tmp_mb;
108 int err;
109
110 /*
111 * Setup tmp_mb to point to the start of the header.
112 * This is a dup ref - do NOT free it.
113 */
114 mb_initm(&tmp_mb, mbp->mb_top);
115
116 /* Skip data up to the offset. */
117 err = md_get_mem(&tmp_mb, NULL, sb->sb_offset, MB_MSYSTEM);
118 if (err)
119 return (err);
120
121 /* Get the data (as an mbuf). */
122 err = md_get_mbuf(&tmp_mb, sb->sb_maxlen, mp);
123
124 return (err);
125 }
126
127 /*
128 * Put a "security buffer" (header part)
129 */
130 static int
mb_put_sb_hdr(struct mbdata * mbp,struct sec_buf * sb)131 mb_put_sb_hdr(struct mbdata *mbp, struct sec_buf *sb)
132 {
133 int err;
134
135 (void) mb_put_uint16le(mbp, sb->sb_length);
136 (void) mb_put_uint16le(mbp, sb->sb_maxlen);
137 err = mb_put_uint32le(mbp, sb->sb_offset);
138
139 return (err);
140 }
141
142 /*
143 * Put a "security buffer" (data part), where
144 * the data is an mbuf. Note: consumes m.
145 */
146 static int
mb_put_sb_data(struct mbdata * mbp,struct sec_buf * sb,struct mbuf * m)147 mb_put_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf *m)
148 {
149 int cnt0, err;
150
151 sb->sb_offset = cnt0 = mbp->mb_count;
152 err = mb_put_mbuf(mbp, m);
153 sb->sb_maxlen = sb->sb_length = mbp->mb_count - cnt0;
154
155 return (err);
156 }
157
158 /*
159 * Put a "security buffer" (data part), where
160 * the data is a string (OEM or unicode).
161 *
162 * The string is NOT null terminated.
163 */
164 static int
mb_put_sb_string(struct mbdata * mbp,struct sec_buf * sb,const char * s,int unicode)165 mb_put_sb_string(struct mbdata *mbp, struct sec_buf *sb,
166 const char *s, int unicode)
167 {
168 int err, trim;
169 struct mbdata tmp_mb;
170
171 /*
172 * Put the string into a temp. mbuf,
173 * then chop off the null terminator
174 * before appending to caller's mbp.
175 */
176 err = mb_init(&tmp_mb);
177 if (err)
178 return (err);
179 err = mb_put_string(&tmp_mb, s, unicode);
180 if (err)
181 return (err);
182
183 trim = (unicode) ? 2 : 1;
184 if (tmp_mb.mb_cur->m_len < trim)
185 return (EFAULT);
186 tmp_mb.mb_cur->m_len -= trim;
187
188 err = mb_put_sb_data(mbp, sb, tmp_mb.mb_top);
189 /*
190 * Note: tmp_mb.mb_top is consumed,
191 * so do NOT free it (no mb_done)
192 */
193 return (err);
194 }
195
196 /*
197 * Build a Type 1 message
198 *
199 * This message has a header section containing offsets to
200 * data later in the message. We use the common trick of
201 * building it in two parts and then concatenatening.
202 */
203 int
ntlmssp_put_type1(struct ssp_ctx * sp,struct mbdata * out_mb)204 ntlmssp_put_type1(struct ssp_ctx *sp, struct mbdata *out_mb)
205 {
206 struct type1hdr {
207 char h_id[ID_SZ];
208 uint32_t h_type;
209 uint32_t h_flags;
210 struct sec_buf h_cldom;
211 struct sec_buf h_wksta;
212 } hdr;
213 struct mbdata mb2; /* 2nd part */
214 int err;
215 struct smb_ctx *ctx = sp->smb_ctx;
216 ntlmssp_state_t *ssp_st = sp->sp_private;
217 char *ucdom = NULL;
218 char *ucwks = NULL;
219
220 if ((err = mb_init(&mb2)) != 0)
221 return (err);
222 mb2.mb_count = sizeof (hdr);
223
224 /*
225 * Initialize the negotiation flags, and
226 * save what we sent. For reference:
227 * [MS-NLMP] spec. (also ntlmssp.h)
228 */
229 ssp_st->ss_flags =
230 NTLMSSP_REQUEST_TARGET |
231 NTLMSSP_NEGOTIATE_NTLM |
232 NTLMSSP_NEGOTIATE_TARGET_INFO |
233 NTLMSSP_NEGOTIATE_128 |
234 NTLMSSP_NEGOTIATE_56;
235
236 if (ctx->ct_hflags2 & SMB_FLAGS2_UNICODE)
237 ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_UNICODE;
238 else
239 ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_OEM;
240
241 if (ctx->ct_vcflags & SMBV_WILL_SIGN) {
242 ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
243 ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
244 }
245
246 bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
247 hdr.h_type = 1; /* Type 1 */
248 hdr.h_flags = ssp_st->ss_flags;
249
250 /*
251 * Put the client domain, client name strings.
252 * These are always in OEM format, upper-case.
253 */
254 ucdom = utf8_str_toupper(ctx->ct_domain);
255 ucwks = utf8_str_toupper(ctx->ct_locname);
256 if (ucdom == NULL || ucwks == NULL) {
257 err = ENOMEM;
258 goto out;
259 }
260 err = mb_put_sb_string(&mb2, &hdr.h_cldom, ucdom, 0);
261 if (err)
262 goto out;
263 err = mb_put_sb_string(&mb2, &hdr.h_wksta, ucwks, 0);
264 if (err)
265 goto out;
266
267 /*
268 * Marshal the header (in LE order)
269 * then concatenate the 2nd part.
270 */
271 (void) mb_put_mem(out_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM);
272 (void) mb_put_uint32le(out_mb, hdr.h_type);
273 (void) mb_put_uint32le(out_mb, hdr.h_flags);
274 (void) mb_put_sb_hdr(out_mb, &hdr.h_cldom);
275 (void) mb_put_sb_hdr(out_mb, &hdr.h_wksta);
276
277 err = mb_put_mbuf(out_mb, mb2.mb_top);
278
279 out:
280 free(ucdom);
281 free(ucwks);
282
283 return (err);
284 }
285
286 /*
287 * Parse a Type 2 message
288 */
289 int
ntlmssp_get_type2(struct ssp_ctx * sp,struct mbdata * in_mb)290 ntlmssp_get_type2(struct ssp_ctx *sp, struct mbdata *in_mb)
291 {
292 struct type2hdr {
293 char h_id[ID_SZ];
294 uint32_t h_type;
295 struct sec_buf h_target_name;
296 uint32_t h_flags;
297 uint8_t h_challenge[8];
298 uint32_t h_context[2]; /* optional */
299 struct sec_buf h_target_info; /* optional */
300 } hdr;
301 struct mbdata top_mb, tmp_mb;
302 struct mbuf *m;
303 int err, uc;
304 int min_hdr_sz = offsetof(struct type2hdr, h_context);
305 struct smb_ctx *ctx = sp->smb_ctx;
306 ntlmssp_state_t *ssp_st = sp->sp_private;
307 char *buf = NULL;
308
309 if (m_totlen(in_mb->mb_top) < min_hdr_sz) {
310 err = EBADRPC;
311 goto out;
312 }
313
314 /*
315 * Save the mbdata pointers before we consume anything.
316 * Careful to NOT free this (would be dup. free)
317 * We use this below to find data based on offsets
318 * from the start of the header.
319 */
320 top_mb = *in_mb;
321
322 /* Parse the fixed size header stuff. */
323 bzero(&hdr, sizeof (hdr));
324 (void) md_get_mem(in_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM);
325 (void) md_get_uint32le(in_mb, &hdr.h_type);
326 if (hdr.h_type != 2) {
327 err = EPROTO;
328 goto out;
329 }
330 (void) md_get_sb_hdr(in_mb, &hdr.h_target_name);
331 (void) md_get_uint32le(in_mb, &hdr.h_flags);
332 (void) md_get_mem(in_mb, &hdr.h_challenge, NTLM_CHAL_SZ, MB_MSYSTEM);
333
334 /*
335 * Save flags, challenge for later.
336 */
337 ssp_st->ss_flags = hdr.h_flags;
338 uc = hdr.h_flags & NTLMSSP_NEGOTIATE_UNICODE;
339 bcopy(&hdr.h_challenge, ctx->ct_ntlm_chal, NTLM_CHAL_SZ);
340
341 /*
342 * Now find out if the optional parts are there.
343 */
344 if ((m_totlen(top_mb.mb_top) > sizeof (hdr)) &&
345 (hdr.h_target_name.sb_offset >= sizeof (hdr))) {
346 (void) md_get_uint32le(in_mb, &hdr.h_context[0]);
347 (void) md_get_uint32le(in_mb, &hdr.h_context[1]);
348 (void) md_get_sb_hdr(in_mb, &hdr.h_target_info);
349 }
350
351 /*
352 * Get the target name string. First get a copy of
353 * the data from the offset/length indicated in the
354 * security buffer header; then parse the string.
355 */
356 err = md_get_sb_data(&top_mb, &hdr.h_target_name, &m);
357 if (err)
358 goto out;
359 mb_initm(&tmp_mb, m);
360 err = md_get_string(&tmp_mb, &ssp_st->ss_target_name, uc);
361 mb_done(&tmp_mb);
362
363 /*
364 * Get the target info blob, if present.
365 */
366 if (hdr.h_target_info.sb_offset >= sizeof (hdr)) {
367 err = md_get_sb_data(&top_mb, &hdr.h_target_info,
368 &ssp_st->ss_target_info);
369 }
370
371 out:
372 if (buf != NULL)
373 free(buf);
374
375 return (err);
376 }
377
378 /*
379 * Build a Type 3 message
380 *
381 * This message has a header section containing offsets to
382 * data later in the message. We use the common trick of
383 * building it in two parts and then concatenatening.
384 */
385 int
ntlmssp_put_type3(struct ssp_ctx * sp,struct mbdata * out_mb)386 ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb)
387 {
388 struct type3hdr {
389 char h_id[ID_SZ];
390 uint32_t h_type;
391 struct sec_buf h_lm_resp;
392 struct sec_buf h_nt_resp;
393 struct sec_buf h_domain;
394 struct sec_buf h_user;
395 struct sec_buf h_wksta;
396 struct sec_buf h_ssn_key;
397 uint32_t h_flags;
398 } hdr;
399 struct mbdata lm_mbc; /* LM response */
400 struct mbdata nt_mbc; /* NT response */
401 struct mbdata ti_mbc; /* target info */
402 struct mbdata mb2; /* payload */
403 int err, uc;
404 struct smb_ctx *ctx = sp->smb_ctx;
405 ntlmssp_state_t *ssp_st = sp->sp_private;
406
407 bzero(&hdr, sizeof (hdr));
408 bzero(&lm_mbc, sizeof (lm_mbc));
409 bzero(&nt_mbc, sizeof (nt_mbc));
410 bzero(&ti_mbc, sizeof (ti_mbc));
411 bzero(&mb2, sizeof (mb2));
412
413 /*
414 * Fill in the NTLMSSP header, etc.
415 */
416 if ((err = mb_init(&mb2)) != 0)
417 goto out;
418 mb2.mb_count = sizeof (hdr);
419 uc = ssp_st->ss_flags & NTLMSSP_NEGOTIATE_UNICODE;
420
421 bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
422 hdr.h_type = 3; /* Type 3 */
423 hdr.h_flags = ssp_st->ss_flags;
424
425 /*
426 * Put the LMv2,NTLMv2 responses, or
427 * possibly LM, NTLM (v1) responses.
428 */
429 if (ctx->ct_authflags & SMB_AT_NTLM2) {
430 /* Build the NTLMv2 "target info" blob. */
431 err = ntlm_build_target_info(ctx,
432 ssp_st->ss_target_info, &ti_mbc);
433 if (err)
434 goto out;
435 err = ntlm_put_v2_responses(ctx, &ti_mbc,
436 &lm_mbc, &nt_mbc);
437 } else {
438 err = ntlm_put_v1_responses(ctx,
439 &lm_mbc, &nt_mbc);
440 }
441 if (err)
442 goto out;
443
444 err = mb_put_sb_data(&mb2, &hdr.h_lm_resp, lm_mbc.mb_top);
445 lm_mbc.mb_top = NULL; /* consumed */
446 if (err)
447 goto out;
448 err = mb_put_sb_data(&mb2, &hdr.h_nt_resp, nt_mbc.mb_top);
449 nt_mbc.mb_top = NULL; /* consumed */
450 if (err)
451 goto out;
452
453 /*
454 * Put the "target" (domain), user, workstation
455 */
456 err = mb_put_sb_string(&mb2, &hdr.h_domain, ctx->ct_domain, uc);
457 if (err)
458 goto out;
459 err = mb_put_sb_string(&mb2, &hdr.h_user, ctx->ct_user, uc);
460 if (err)
461 goto out;
462 err = mb_put_sb_string(&mb2, &hdr.h_wksta, ctx->ct_locname, uc);
463 if (err)
464 goto out;
465
466 /*
467 * Put the "Random Session Key". We don't set
468 * NTLMSSP_NEGOTIATE_KEY_EXCH, so it's empty.
469 * (In-line mb_put_sb_data here.)
470 */
471 hdr.h_ssn_key.sb_maxlen = hdr.h_ssn_key.sb_length = 0;
472 hdr.h_ssn_key.sb_offset = mb2.mb_count;
473
474 /*
475 * Marshal the header (in LE order)
476 * then concatenate the 2nd part.
477 */
478 (void) mb_put_mem(out_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM);
479 (void) mb_put_uint32le(out_mb, hdr.h_type);
480
481 (void) mb_put_sb_hdr(out_mb, &hdr.h_lm_resp);
482 (void) mb_put_sb_hdr(out_mb, &hdr.h_nt_resp);
483
484 (void) mb_put_sb_hdr(out_mb, &hdr.h_domain);
485 (void) mb_put_sb_hdr(out_mb, &hdr.h_user);
486 (void) mb_put_sb_hdr(out_mb, &hdr.h_wksta);
487
488 (void) mb_put_sb_hdr(out_mb, &hdr.h_ssn_key);
489 (void) mb_put_uint32le(out_mb, hdr.h_flags);
490
491 err = mb_put_mbuf(out_mb, mb2.mb_top);
492 mb2.mb_top = NULL; /* consumed */
493
494 out:
495 mb_done(&mb2);
496 mb_done(&lm_mbc);
497 mb_done(&nt_mbc);
498 mb_done(&ti_mbc);
499
500 return (err);
501 }
502
503 /*
504 * ntlmssp_final
505 *
506 * Called after successful authentication.
507 * Setup the MAC key for signing.
508 */
509 int
ntlmssp_final(struct ssp_ctx * sp)510 ntlmssp_final(struct ssp_ctx *sp)
511 {
512 struct smb_ctx *ctx = sp->smb_ctx;
513 int err = 0;
514
515 /*
516 * MAC_key is just the session key, but
517 * Only on the first successful auth.
518 */
519 if ((ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) &&
520 (ctx->ct_mackey == NULL)) {
521 ctx->ct_mackeylen = NTLM_HASH_SZ;
522 ctx->ct_mackey = malloc(ctx->ct_mackeylen);
523 if (ctx->ct_mackey == NULL) {
524 ctx->ct_mackeylen = 0;
525 err = ENOMEM;
526 goto out;
527 }
528 memcpy(ctx->ct_mackey, ctx->ct_ssn_key, NTLM_HASH_SZ);
529 /*
530 * Apparently, the server used seq. no. zero
531 * for our previous message, so next is two.
532 */
533 ctx->ct_mac_seqno = 2;
534 }
535
536 out:
537 return (err);
538 }
539
540 /*
541 * ntlmssp_next_token
542 *
543 * See ssp.c: ssp_ctx_next_token
544 */
545 int
ntlmssp_next_token(struct ssp_ctx * sp,struct mbdata * in_mb,struct mbdata * out_mb)546 ntlmssp_next_token(struct ssp_ctx *sp, struct mbdata *in_mb,
547 struct mbdata *out_mb)
548 {
549 int err;
550
551 if (out_mb == NULL) {
552 /* final call on successful auth. */
553 err = ntlmssp_final(sp);
554 goto out;
555 }
556
557 /* Will build an ouptut token. */
558 err = mb_init(out_mb);
559 if (err)
560 goto out;
561
562 /*
563 * When called with in_mb == NULL, it means
564 * this is the first call for this session,
565 * so put a Type 1 (initialize) token.
566 */
567 if (in_mb == NULL) {
568 err = ntlmssp_put_type1(sp, out_mb);
569 goto out;
570 }
571
572 /*
573 * This is not the first call, so
574 * parse the response token we received.
575 * It should be a Type 2 (challenge).
576 * Then put a Type 3 (authenticate)
577 */
578 err = ntlmssp_get_type2(sp, in_mb);
579 if (err)
580 goto out;
581
582 err = ntlmssp_put_type3(sp, out_mb);
583
584 out:
585 if (err)
586 DPRINT("ret: %d", err);
587 return (err);
588 }
589
590 /*
591 * ntlmssp_ctx_destroy
592 *
593 * Destroy mechanism-specific data.
594 */
595 void
ntlmssp_destroy(struct ssp_ctx * sp)596 ntlmssp_destroy(struct ssp_ctx *sp)
597 {
598 ntlmssp_state_t *ssp_st;
599
600 ssp_st = sp->sp_private;
601 if (ssp_st != NULL) {
602 sp->sp_private = NULL;
603 free(ssp_st->ss_target_name);
604 m_freem(ssp_st->ss_target_info);
605 free(ssp_st);
606 }
607 }
608
609 /*
610 * ntlmssp_init_clnt
611 *
612 * Initialize a new NTLMSSP client context.
613 */
614 int
ntlmssp_init_client(struct ssp_ctx * sp)615 ntlmssp_init_client(struct ssp_ctx *sp)
616 {
617 ntlmssp_state_t *ssp_st;
618
619 if ((sp->smb_ctx->ct_authflags &
620 (SMB_AT_NTLM2 | SMB_AT_NTLM1)) == 0) {
621 DPRINT("No NTLM authflags");
622 return (ENOTSUP);
623 }
624
625 ssp_st = calloc(1, sizeof (*ssp_st));
626 if (ssp_st == NULL)
627 return (ENOMEM);
628
629 sp->sp_nexttok = ntlmssp_next_token;
630 sp->sp_destroy = ntlmssp_destroy;
631 sp->sp_private = ssp_st;
632
633 return (0);
634 }
635