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