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
67typedef 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 */
77struct sec_buf {
78	uint16_t sb_length;
79	uint16_t sb_maxlen;
80	uint32_t sb_offset;
81};
82#define	ID_SZ 8
83static const char ntlmssp_id[ID_SZ] = "NTLMSSP";
84
85/*
86 * Get a "security buffer" (header part)
87 */
88static int
89md_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 */
104static int
105md_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 */
130static int
131mb_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 */
146static int
147mb_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 */
164static int
165mb_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 */
203int
204ntlmssp_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
279out:
280	free(ucdom);
281	free(ucwks);
282
283	return (err);
284}
285
286/*
287 * Parse a Type 2 message
288 */
289int
290ntlmssp_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
371out:
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 */
385int
386ntlmssp_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
494out:
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 */
509int
510ntlmssp_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
536out:
537	return (err);
538}
539
540/*
541 * ntlmssp_next_token
542 *
543 * See ssp.c: ssp_ctx_next_token
544 */
545int
546ntlmssp_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
584out:
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 */
595void
596ntlmssp_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 */
614int
615ntlmssp_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