xref: /titanic_44/usr/src/lib/libsmbfs/smb/ssnsetup.c (revision 3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9)
1 /*
2  * Copyright (c) 2000-2001 Boris Popov
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *    This product includes software developed by Boris Popov.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 /*
34  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
35  */
36 
37 /*
38  * SMB Session Setup, and related.
39  * Copied from the driver: smb_smb.c
40  */
41 
42 #include <errno.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <unistd.h>
46 #include <strings.h>
47 #include <netdb.h>
48 #include <libintl.h>
49 #include <xti.h>
50 #include <assert.h>
51 
52 #include <sys/types.h>
53 #include <sys/time.h>
54 #include <sys/byteorder.h>
55 #include <sys/socket.h>
56 #include <sys/fcntl.h>
57 
58 #include <netinet/in.h>
59 #include <netinet/tcp.h>
60 #include <arpa/inet.h>
61 
62 #include <netsmb/mchain.h>
63 #include <netsmb/netbios.h>
64 #include <netsmb/smb_dev.h>
65 #include <netsmb/smb.h>
66 
67 #include <netsmb/smb_lib.h>
68 #include <netsmb/nb_lib.h>
69 
70 #include "private.h"
71 #include "charsets.h"
72 #include "ntlm.h"
73 #include "smb_crypt.h"
74 
75 /*
76  * When we have a _real_ ntstatus.h, eliminate this.
77  * XXX: Current smb.h defines it without the high bits.
78  */
79 #define	STATUS_MORE_PROCESSING_REQUIRED 0xC0000016
80 
81 static int
82 smb__ssnsetup(struct smb_ctx *ctx,
83 	struct mbdata *mbc1, struct mbdata *mbc2,
84 	uint32_t *statusp, uint16_t *actionp);
85 
86 /*
87  * Session Setup: NULL session (anonymous)
88  */
89 int
90 smb_ssnsetup_null(struct smb_ctx *ctx)
91 {
92 	int err;
93 	uint32_t ntstatus;
94 	uint16_t action = 0;
95 
96 	if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) {
97 		/* Should not get here with... */
98 		err = EINVAL;
99 		goto out;
100 	}
101 
102 	err = smb__ssnsetup(ctx, NULL, NULL, &ntstatus, &action);
103 	if (err)
104 		goto out;
105 
106 	DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
107 	if (ntstatus != 0)
108 		err = EAUTH;
109 
110 out:
111 	return (err);
112 }
113 
114 
115 /*
116  * SMB Session Setup, using NTLMv1 (and maybe LMv1)
117  */
118 int
119 smb_ssnsetup_ntlm1(struct smb_ctx *ctx)
120 {
121 	struct mbdata lm_mbc, nt_mbc;
122 	int err;
123 	uint32_t ntstatus;
124 	uint16_t action = 0;
125 
126 	if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) {
127 		/* Should not get here with... */
128 		err = EINVAL;
129 		goto out;
130 	}
131 
132 	/* Make mb_done calls at out safe. */
133 	bzero(&lm_mbc, sizeof (lm_mbc));
134 	bzero(&nt_mbc, sizeof (nt_mbc));
135 
136 	/* Put the LM,NTLM responses (as mbdata). */
137 	err = ntlm_put_v1_responses(ctx, &lm_mbc, &nt_mbc);
138 	if (err)
139 		goto out;
140 
141 	/*
142 	 * If we negotiated signing, compute the MAC key
143 	 * and start signing messages, but only on the
144 	 * first non-null session login.
145 	 */
146 	if ((ctx->ct_vcflags & SMBV_WILL_SIGN) &&
147 	    (ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) {
148 		struct mbuf *m = nt_mbc.mb_top;
149 		char *p;
150 
151 		/*
152 		 * MAC_key = concat(session_key, nt_response)
153 		 */
154 		ctx->ct_mackeylen = NTLM_HASH_SZ + m->m_len;
155 		ctx->ct_mackey = malloc(ctx->ct_mackeylen);
156 		if (ctx->ct_mackey == NULL) {
157 			ctx->ct_mackeylen = 0;
158 			err = ENOMEM;
159 			goto out;
160 		}
161 		p = ctx->ct_mackey;
162 		memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ);
163 		memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len);
164 
165 		/* OK, start signing! */
166 		ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
167 	}
168 
169 	err = smb__ssnsetup(ctx, &lm_mbc, &nt_mbc, &ntstatus, &action);
170 	if (err)
171 		goto out;
172 
173 	DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
174 	if (ntstatus != 0)
175 		err = EAUTH;
176 
177 out:
178 	mb_done(&lm_mbc);
179 	mb_done(&nt_mbc);
180 
181 	return (err);
182 }
183 
184 /*
185  * SMB Session Setup, using NTLMv2 (and LMv2)
186  */
187 int
188 smb_ssnsetup_ntlm2(struct smb_ctx *ctx)
189 {
190 	struct mbdata lm_mbc, nt_mbc, ti_mbc;
191 	int err;
192 	uint32_t ntstatus;
193 	uint16_t action = 0;
194 
195 	if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) {
196 		/* Should not get here with... */
197 		err = EINVAL;
198 		goto out;
199 	}
200 
201 	/* Make mb_done calls at out safe. */
202 	bzero(&lm_mbc, sizeof (lm_mbc));
203 	bzero(&nt_mbc, sizeof (nt_mbc));
204 	bzero(&ti_mbc, sizeof (ti_mbc));
205 
206 	/* Build the NTLMv2 "target info" blob (as mbdata) */
207 	err = ntlm_build_target_info(ctx, NULL, &ti_mbc);
208 	if (err)
209 		goto out;
210 
211 	/* Put the LMv2, NTLMv2 responses (as mbdata). */
212 	err = ntlm_put_v2_responses(ctx, &ti_mbc, &lm_mbc, &nt_mbc);
213 	if (err)
214 		goto out;
215 
216 	/*
217 	 * If we negotiated signing, compute the MAC key
218 	 * and start signing messages, but only on the
219 	 * first non-null session login.
220 	 */
221 	if ((ctx->ct_vcflags & SMBV_WILL_SIGN) &&
222 	    (ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) {
223 		struct mbuf *m = nt_mbc.mb_top;
224 		char *p;
225 
226 		/*
227 		 * MAC_key = concat(session_key, nt_response)
228 		 */
229 		ctx->ct_mackeylen = NTLM_HASH_SZ + m->m_len;
230 		ctx->ct_mackey = malloc(ctx->ct_mackeylen);
231 		if (ctx->ct_mackey == NULL) {
232 			ctx->ct_mackeylen = 0;
233 			err = ENOMEM;
234 			goto out;
235 		}
236 		p = ctx->ct_mackey;
237 		memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ);
238 		memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len);
239 
240 		/* OK, start signing! */
241 		ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
242 	}
243 
244 	err = smb__ssnsetup(ctx, &lm_mbc, &nt_mbc, &ntstatus, &action);
245 	if (err)
246 		goto out;
247 
248 	DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
249 	if (ntstatus != 0)
250 		err = EAUTH;
251 
252 out:
253 	mb_done(&ti_mbc);
254 	mb_done(&lm_mbc);
255 	mb_done(&nt_mbc);
256 
257 	return (err);
258 }
259 
260 int
261 smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb)
262 {
263 	struct mbdata send_mb, recv_mb;
264 	int		err;
265 	uint32_t	ntstatus;
266 	uint16_t	action = 0;
267 
268 	err = ssp_ctx_create_client(ctx, hint_mb);
269 	if (err)
270 		goto out;
271 
272 	bzero(&send_mb, sizeof (send_mb));
273 	bzero(&recv_mb, sizeof (recv_mb));
274 
275 	/* NULL input indicates first call. */
276 	err = ssp_ctx_next_token(ctx, NULL, &send_mb);
277 	if (err)
278 		goto out;
279 
280 	for (;;) {
281 		err = smb__ssnsetup(ctx, &send_mb, &recv_mb,
282 		    &ntstatus, &action);
283 		if (err)
284 			goto out;
285 		if (ntstatus == 0)
286 			break; /* normal loop termination */
287 		if (ntstatus != STATUS_MORE_PROCESSING_REQUIRED) {
288 			err = EAUTH;
289 			goto out;
290 		}
291 
292 		/* middle calls get both in, out */
293 		err = ssp_ctx_next_token(ctx, &recv_mb, &send_mb);
294 		if (err)
295 			goto out;
296 	}
297 	DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
298 
299 	/* NULL output indicates last call. */
300 	(void) ssp_ctx_next_token(ctx, &recv_mb, NULL);
301 
302 out:
303 	ssp_ctx_destroy(ctx);
304 
305 	return (err);
306 }
307 
308 /*
309  * Session Setup function used for all the forms we support.
310  * To allow this sharing, the crypto stuff is computed by
311  * callers and passed in as mbdata chains.  Also, the args
312  * have different meanings for extended security vs. old.
313  * Some may be used as either IN or OUT parameters.
314  *
315  * For NTLM (v1, v2), all parameters are inputs
316  * 	mbc1: [in] LM password hash
317  * 	mbc2: [in] NT password hash
318  * For Extended security (spnego)
319  *	mbc1: [in]  outgoing blob data
320  *	mbc2: [out] received blob data
321  * For both forms, these are optional:
322  *	statusp: [out] NT status
323  *	actionp: [out] Logon Action (i.e. SMB_ACT_GUEST)
324  */
325 static int
326 smb__ssnsetup(struct smb_ctx *ctx,
327 	struct mbdata *mbc1, struct mbdata *mbc2,
328 	uint32_t *statusp, uint16_t *actionp)
329 {
330 	static const char NativeOS[] = "Solaris";
331 	static const char LanMan[] = "NETSMB";
332 	struct smb_sopt *sv = &ctx->ct_sopt;
333 	struct smb_iods *is = &ctx->ct_iods;
334 	struct smb_rq	*rqp = NULL;
335 	struct mbdata	*mbp;
336 	struct mbuf	*m;
337 	int err, uc;
338 	uint32_t caps;
339 	uint16_t bc, len1, len2, sblen;
340 	uint8_t wc;
341 
342 	/*
343 	 * Some of the "capability" bits we offer will be copied
344 	 * from those offered by the server, with a mask applied.
345 	 * This is the mask of capabilies copied from the server.
346 	 * Some others get special handling below.
347 	 */
348 	static const uint32_t caps_mask =
349 	    SMB_CAP_UNICODE |
350 	    SMB_CAP_LARGE_FILES |
351 	    SMB_CAP_NT_SMBS |
352 	    SMB_CAP_STATUS32 |
353 	    SMB_CAP_EXT_SECURITY;
354 
355 	caps = ctx->ct_sopt.sv_caps & caps_mask;
356 	uc = ctx->ct_hflags2 & SMB_FLAGS2_UNICODE;
357 
358 	err = smb_rq_init(ctx, SMB_COM_SESSION_SETUP_ANDX, &rqp);
359 	if (err)
360 		goto out;
361 
362 	/*
363 	 * Build the SMB request.
364 	 */
365 	mbp = &rqp->rq_rq;
366 	smb_rq_wstart(rqp);
367 	mb_put_uint16le(mbp, 0xff);		/* 0: AndXCommand */
368 	mb_put_uint16le(mbp, 0);		/* 1: AndXOffset */
369 	mb_put_uint16le(mbp, sv->sv_maxtx);	/* 2: MaxBufferSize */
370 	mb_put_uint16le(mbp, sv->sv_maxmux);	/* 3: MaxMpxCount */
371 	mb_put_uint16le(mbp, 1);		/* 4: VcNumber */
372 	mb_put_uint32le(mbp, sv->sv_skey);	/* 5,6: Session Key */
373 
374 	if (caps & SMB_CAP_EXT_SECURITY) {
375 		len1 = mbc1 ? mbc1->mb_count : 0;
376 		mb_put_uint16le(mbp, len1);	/* 7: Sec. Blob Len */
377 		mb_put_uint32le(mbp, 0);	/* 8,9: reserved */
378 		mb_put_uint32le(mbp, caps);	/* 10,11: Capabilities */
379 		smb_rq_wend(rqp);		/* 12: Byte Count */
380 		smb_rq_bstart(rqp);
381 		if (mbc1 && mbc1->mb_top) {
382 			mb_put_mbuf(mbp, mbc1->mb_top);	/* sec. blob */
383 			mbc1->mb_top = NULL; /* consumed */
384 		}
385 		/* mbc2 is required below */
386 		if (mbc2 == NULL) {
387 			err = EINVAL;
388 			goto out;
389 		}
390 	} else {
391 		len1 = mbc1 ? mbc1->mb_count : 0;
392 		len2 = mbc2 ? mbc2->mb_count : 0;
393 		mb_put_uint16le(mbp, len1);	/* 7: LM pass. len */
394 		mb_put_uint16le(mbp, len2);	/* 8: NT pass. len */
395 		mb_put_uint32le(mbp, 0);	/* 9,10: reserved */
396 		mb_put_uint32le(mbp, caps);	/* 11,12: Capabilities */
397 		smb_rq_wend(rqp);		/* 13: Byte Count */
398 		smb_rq_bstart(rqp);
399 		if (mbc1 && mbc1->mb_top) {
400 			mb_put_mbuf(mbp, mbc1->mb_top);	/* LM password */
401 			mbc1->mb_top = NULL; /* consumed */
402 		}
403 		if (mbc2 && mbc2->mb_top) {
404 			mb_put_mbuf(mbp, mbc2->mb_top);	/* NT password */
405 			mbc2->mb_top = NULL; /* consumed */
406 		}
407 		mb_put_string(mbp, ctx->ct_user, uc);
408 		mb_put_string(mbp, ctx->ct_domain, uc);
409 	}
410 	mb_put_string(mbp, NativeOS, uc);
411 	mb_put_string(mbp, LanMan, uc);
412 	smb_rq_bend(rqp);
413 
414 	err = smb_rq_internal(ctx, rqp);
415 	if (err)
416 		goto out;
417 
418 	if (statusp)
419 		*statusp = rqp->rq_status;
420 
421 	/*
422 	 * If we have a real error, the response probably has
423 	 * no more data, so don't try to parse any more.
424 	 * Note: err=0, means rq_status is valid.
425 	 */
426 	if (rqp->rq_status != 0 &&
427 	    rqp->rq_status != STATUS_MORE_PROCESSING_REQUIRED) {
428 		goto out;
429 	}
430 
431 	/*
432 	 * Parse the reply
433 	 */
434 	uc = rqp->rq_hflags2 & SMB_FLAGS2_UNICODE;
435 	is->is_smbuid = rqp->rq_uid;
436 	mbp = &rqp->rq_rp;
437 
438 	err = md_get_uint8(mbp, &wc);
439 	if (err)
440 		goto out;
441 
442 	err = EBADRPC; /* for any problems in this section */
443 	if (caps & SMB_CAP_EXT_SECURITY) {
444 		if (wc != 4)
445 			goto out;
446 		md_get_uint16le(mbp, NULL);	/* secondary cmd */
447 		md_get_uint16le(mbp, NULL);	/* andxoffset */
448 		md_get_uint16le(mbp, actionp);	/* action */
449 		md_get_uint16le(mbp, &sblen);	/* sec. blob len */
450 		md_get_uint16le(mbp, &bc);	/* byte count */
451 		/*
452 		 * Get the security blob, after
453 		 * sanity-checking the length.
454 		 */
455 		if (sblen == 0 || bc < sblen)
456 			goto out;
457 		err = md_get_mbuf(mbp, sblen, &m);
458 		if (err)
459 			goto out;
460 		mb_initm(mbc2, m);
461 		mbc2->mb_count = sblen;
462 	} else {
463 		if (wc != 3)
464 			goto out;
465 		md_get_uint16le(mbp, NULL);	/* secondary cmd */
466 		md_get_uint16le(mbp, NULL);	/* andxoffset */
467 		md_get_uint16le(mbp, actionp);	/* action */
468 		err = md_get_uint16le(mbp, &bc); /* byte count */
469 		if (err)
470 			goto out;
471 	}
472 
473 	/*
474 	 * Native OS, LANMGR, & Domain follow here.
475 	 * Parse these strings and store for later.
476 	 * If unicode, they should be aligned.
477 	 *
478 	 * Note that with Extended security, we may use
479 	 * multiple calls to this function.  Only parse
480 	 * these strings on the last one (status == 0).
481 	 * Ditto for the CAP_LARGE work-around.
482 	 */
483 	if (rqp->rq_status != 0)
484 		goto out;
485 
486 	/* Ignore any parsing errors for these strings. */
487 	err = md_get_string(mbp, &ctx->ct_srv_OS, uc);
488 	DPRINT("server OS: %s", err ? "?" : ctx->ct_srv_OS);
489 	err = md_get_string(mbp, &ctx->ct_srv_LM, uc);
490 	DPRINT("server LM: %s", err ? "?" : ctx->ct_srv_LM);
491 	/*
492 	 * There's sometimes a server domain folloing
493 	 * at this point, but we don't need it.
494 	 */
495 
496 	/* Success! (See Ignore any ... above) */
497 	err = 0;
498 
499 	/*
500 	 * Windows systems don't suport CAP_LARGE_READX,WRITEX
501 	 * when signing is enabled, so adjust sv_caps.
502 	 */
503 	if (ctx->ct_srv_OS &&
504 	    0 == strncmp(ctx->ct_srv_OS, "Windows ", 8)) {
505 		DPRINT("Server is Windows");
506 		if (ctx->ct_vcflags & SMBV_WILL_SIGN) {
507 			DPRINT("disable CAP_LARGE_(r/w)");
508 			ctx->ct_sopt.sv_caps &=
509 			    ~(SMB_CAP_LARGE_READX | SMB_CAP_LARGE_WRITEX);
510 		}
511 	}
512 
513 out:
514 	if (rqp)
515 		smb_rq_done(rqp);
516 
517 	return (err);
518 }
519