xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_dfs.c (revision 2067ad9da908e7634f4b17778a0523d3acca8102)
1a90cf9f2SGordon Ross /*
2a90cf9f2SGordon Ross  * CDDL HEADER START
3a90cf9f2SGordon Ross  *
4a90cf9f2SGordon Ross  * The contents of this file are subject to the terms of the
5a90cf9f2SGordon Ross  * Common Development and Distribution License (the "License").
6a90cf9f2SGordon Ross  * You may not use this file except in compliance with the License.
7a90cf9f2SGordon Ross  *
8a90cf9f2SGordon Ross  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9a90cf9f2SGordon Ross  * or http://www.opensolaris.org/os/licensing.
10a90cf9f2SGordon Ross  * See the License for the specific language governing permissions
11a90cf9f2SGordon Ross  * and limitations under the License.
12a90cf9f2SGordon Ross  *
13a90cf9f2SGordon Ross  * When distributing Covered Code, include this CDDL HEADER in each
14a90cf9f2SGordon Ross  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15a90cf9f2SGordon Ross  * If applicable, add the following below this CDDL HEADER, with the
16a90cf9f2SGordon Ross  * fields enclosed by brackets "[]" replaced with your own identifying
17a90cf9f2SGordon Ross  * information: Portions Copyright [yyyy] [name of copyright owner]
18a90cf9f2SGordon Ross  *
19a90cf9f2SGordon Ross  * CDDL HEADER END
20a90cf9f2SGordon Ross  */
21a90cf9f2SGordon Ross /*
22a90cf9f2SGordon Ross  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23a90cf9f2SGordon Ross  * Use is subject to license terms.
24a90cf9f2SGordon Ross  *
25adee6784SGordon Ross  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
26a44ccde2SGordon Ross  * Copyright 2021 RackTop Systems, Inc.
27a90cf9f2SGordon Ross  */
28a90cf9f2SGordon Ross 
29a90cf9f2SGordon Ross #include <smbsrv/smb_kproto.h>
30a90cf9f2SGordon Ross #include <smbsrv/smb_dfs.h>
31a90cf9f2SGordon Ross #include <smbsrv/smb_door.h>
32adee6784SGordon Ross #include <smb/winioctl.h>
33a90cf9f2SGordon Ross 
34a90cf9f2SGordon Ross /*
35a90cf9f2SGordon Ross  * Get Referral response header flags
36a90cf9f2SGordon Ross  * For exact meaning refer to MS-DFSC spec.
37a90cf9f2SGordon Ross  *
38a90cf9f2SGordon Ross  * R: ReferralServers
39a90cf9f2SGordon Ross  * S: StorageServers
40a90cf9f2SGordon Ross  * T: TargetFailback
41a90cf9f2SGordon Ross  */
42a90cf9f2SGordon Ross #define	DFS_HDRFLG_R		0x00000001
43a90cf9f2SGordon Ross #define	DFS_HDRFLG_S		0x00000002
44a90cf9f2SGordon Ross #define	DFS_HDRFLG_T		0x00000004
45a90cf9f2SGordon Ross 
46a90cf9f2SGordon Ross /*
47a90cf9f2SGordon Ross  * Entry flags
48a90cf9f2SGordon Ross  */
49a90cf9f2SGordon Ross #define	DFS_ENTFLG_T		0x0004
50a90cf9f2SGordon Ross 
51a90cf9f2SGordon Ross /*
52a90cf9f2SGordon Ross  * Referral entry types/versions
53a90cf9f2SGordon Ross  */
54a90cf9f2SGordon Ross #define	DFS_REFERRAL_V1		0x0001
55a90cf9f2SGordon Ross #define	DFS_REFERRAL_V2		0x0002
56a90cf9f2SGordon Ross #define	DFS_REFERRAL_V3		0x0003
57a90cf9f2SGordon Ross #define	DFS_REFERRAL_V4		0x0004
58a90cf9f2SGordon Ross 
59a90cf9f2SGordon Ross /*
60a90cf9f2SGordon Ross  * Valid values for ServerType field in referral entries
61a90cf9f2SGordon Ross  */
62a90cf9f2SGordon Ross #define	DFS_SRVTYPE_NONROOT	0x0000
63a90cf9f2SGordon Ross #define	DFS_SRVTYPE_ROOT	0x0001
64a90cf9f2SGordon Ross 
65a90cf9f2SGordon Ross /*
66a90cf9f2SGordon Ross  * Size of the fix part for each referral entry type
67a90cf9f2SGordon Ross  */
68a90cf9f2SGordon Ross #define	DFS_REFV1_ENTSZ		8
69a90cf9f2SGordon Ross #define	DFS_REFV2_ENTSZ		22
70a90cf9f2SGordon Ross #define	DFS_REFV3_ENTSZ		34
71a90cf9f2SGordon Ross #define	DFS_REFV4_ENTSZ		34
72a90cf9f2SGordon Ross 
73a90cf9f2SGordon Ross static dfs_reftype_t smb_dfs_get_reftype(const char *);
74a90cf9f2SGordon Ross static void smb_dfs_encode_hdr(mbuf_chain_t *, dfs_info_t *);
75a90cf9f2SGordon Ross static uint32_t smb_dfs_encode_refv1(smb_request_t *, mbuf_chain_t *,
76a90cf9f2SGordon Ross     dfs_info_t *);
77a90cf9f2SGordon Ross static uint32_t smb_dfs_encode_refv2(smb_request_t *, mbuf_chain_t *,
78a90cf9f2SGordon Ross     dfs_info_t *);
79a90cf9f2SGordon Ross static uint32_t smb_dfs_encode_refv3x(smb_request_t *, mbuf_chain_t *,
80a90cf9f2SGordon Ross     dfs_info_t *, uint16_t);
81a90cf9f2SGordon Ross static void smb_dfs_encode_targets(mbuf_chain_t *, dfs_info_t *);
82a90cf9f2SGordon Ross static uint32_t smb_dfs_referrals_get(smb_request_t *, char *, dfs_reftype_t,
83a90cf9f2SGordon Ross     dfs_referral_response_t *);
84a90cf9f2SGordon Ross static void smb_dfs_referrals_free(dfs_referral_response_t *);
85a90cf9f2SGordon Ross static uint16_t smb_dfs_referrals_unclen(dfs_info_t *, uint16_t);
86*2067ad9dSGordon Ross static uint32_t smb_dfs_get_referrals_ex(smb_request_t *, smb_fsctl_t *);
87a90cf9f2SGordon Ross 
88a90cf9f2SGordon Ross /*
8955f0a249SGordon Ross  * Handle device type FILE_DEVICE_DFS
9055f0a249SGordon Ross  * for smb2_ioctl
9155f0a249SGordon Ross  */
9255f0a249SGordon Ross uint32_t
smb_dfs_fsctl(smb_request_t * sr,smb_fsctl_t * fsctl)9355f0a249SGordon Ross smb_dfs_fsctl(smb_request_t *sr, smb_fsctl_t *fsctl)
9455f0a249SGordon Ross {
9555f0a249SGordon Ross 	uint32_t status;
9655f0a249SGordon Ross 
9755f0a249SGordon Ross 	if (!STYPE_ISIPC(sr->tid_tree->t_res_type))
9855f0a249SGordon Ross 		return (NT_STATUS_INVALID_DEVICE_REQUEST);
9955f0a249SGordon Ross 
100a44ccde2SGordon Ross 	/*
101a44ccde2SGordon Ross 	 * If the connection is not DFS capable, we should return
102a44ccde2SGordon Ross 	 * NT_STATUS_FS_DRIVER_REQUIRED for both of these DFS ioctls.
103a44ccde2SGordon Ross 	 * See [MS-SMB2] 3.3.5.15.2.
104a44ccde2SGordon Ross 	 */
105a44ccde2SGordon Ross 	if ((sr->session->srv_cap & SMB2_CAP_DFS) == 0)
106a44ccde2SGordon Ross 		return (NT_STATUS_FS_DRIVER_REQUIRED);
107a44ccde2SGordon Ross 
10855f0a249SGordon Ross 	switch (fsctl->CtlCode) {
10955f0a249SGordon Ross 	case FSCTL_DFS_GET_REFERRALS:
11055f0a249SGordon Ross 		status = smb_dfs_get_referrals(sr, fsctl);
11155f0a249SGordon Ross 		break;
112*2067ad9dSGordon Ross 	case FSCTL_DFS_GET_REFERRALS_EX:
113*2067ad9dSGordon Ross 		status = smb_dfs_get_referrals_ex(sr, fsctl);
114*2067ad9dSGordon Ross 		break;
11555f0a249SGordon Ross 	default:
116a44ccde2SGordon Ross 		/*
117a44ccde2SGordon Ross 		 * MS-SMB2 suggests INVALID_DEVICE_REQUEST
118a44ccde2SGordon Ross 		 * for unknown control codes, but using that
119a44ccde2SGordon Ross 		 * here makes Windows unhappy.
120a44ccde2SGordon Ross 		 */
121a44ccde2SGordon Ross 		status = NT_STATUS_FS_DRIVER_REQUIRED;
12255f0a249SGordon Ross 	}
12355f0a249SGordon Ross 
12455f0a249SGordon Ross 	return (status);
12555f0a249SGordon Ross }
12655f0a249SGordon Ross 
12755f0a249SGordon Ross /*
128*2067ad9dSGordon Ross  * XXX Instead of decoding the referral request and encoding
129*2067ad9dSGordon Ross  * the response here (in-kernel) we could pass the given
130*2067ad9dSGordon Ross  * request buffer in our door call, and let that return the
131*2067ad9dSGordon Ross  * response buffer ready to stuff into out_mbc.  That would
132*2067ad9dSGordon Ross  * allow all this decoding/encoding to happen at user-level.
133*2067ad9dSGordon Ross  * (and most of this file would go away. :-)
134*2067ad9dSGordon Ross  */
135*2067ad9dSGordon Ross 
136*2067ad9dSGordon Ross /*
137*2067ad9dSGordon Ross  * See [MS-DFSC] for details about this command
138*2067ad9dSGordon Ross  * Handles FSCTL_DFS_GET_REFERRALS_EX (only)
139*2067ad9dSGordon Ross  */
140*2067ad9dSGordon Ross uint32_t
smb_dfs_get_referrals_ex(smb_request_t * sr,smb_fsctl_t * fsctl)141*2067ad9dSGordon Ross smb_dfs_get_referrals_ex(smb_request_t *sr, smb_fsctl_t *fsctl)
142*2067ad9dSGordon Ross {
143*2067ad9dSGordon Ross 	dfs_info_t *referrals;
144*2067ad9dSGordon Ross 	dfs_referral_response_t refrsp;
145*2067ad9dSGordon Ross 	dfs_reftype_t reftype;
146*2067ad9dSGordon Ross 	char *path;
147*2067ad9dSGordon Ross 	uint16_t maxver;
148*2067ad9dSGordon Ross 	uint16_t flags;
149*2067ad9dSGordon Ross 	uint16_t fnlen;
150*2067ad9dSGordon Ross 	uint32_t datalen;
151*2067ad9dSGordon Ross 	uint32_t status;
152*2067ad9dSGordon Ross 	int rc;
153*2067ad9dSGordon Ross 
154*2067ad9dSGordon Ross 	/*
155*2067ad9dSGordon Ross 	 * The caller checks this, because the error reporting method
156*2067ad9dSGordon Ross 	 * varies across SMB versions.
157*2067ad9dSGordon Ross 	 */
158*2067ad9dSGordon Ross 	ASSERT(STYPE_ISIPC(sr->tid_tree->t_res_type));
159*2067ad9dSGordon Ross 
160*2067ad9dSGordon Ross 	/*
161*2067ad9dSGordon Ross 	 * Decode fixed part.
162*2067ad9dSGordon Ross 	 * Input data is (w) MaxReferralLevel, (w) Flags,
163*2067ad9dSGordon Ross 	 * (l) RequestDataLength, ... variable data ...
164*2067ad9dSGordon Ross 	 */
165*2067ad9dSGordon Ross 	rc = smb_mbc_decodef(fsctl->in_mbc, "wwl",
166*2067ad9dSGordon Ross 	    &maxver, &flags, &datalen);
167*2067ad9dSGordon Ross 	if (rc != 0)
168*2067ad9dSGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
169*2067ad9dSGordon Ross 
170*2067ad9dSGordon Ross 	/*
171*2067ad9dSGordon Ross 	 * Decode variable part:
172*2067ad9dSGordon Ross 	 * (w) file name length, (u) filename,
173*2067ad9dSGordon Ross 	 * ( if flags & 1 )
174*2067ad9dSGordon Ross 	 *	(w) site name len, (u) site name
175*2067ad9dSGordon Ross 	 * We don't decode or use the site name
176*2067ad9dSGordon Ross 	 */
177*2067ad9dSGordon Ross 	if (MBC_ROOM_FOR(fsctl->in_mbc, datalen) == 0)
178*2067ad9dSGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
179*2067ad9dSGordon Ross 	rc = smb_mbc_decodef(fsctl->in_mbc, "%wu",
180*2067ad9dSGordon Ross 	    sr, &fnlen, &path);
181*2067ad9dSGordon Ross 	if (rc != 0)
182*2067ad9dSGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
183*2067ad9dSGordon Ross 
184*2067ad9dSGordon Ross 	reftype = smb_dfs_get_reftype((const char *)path);
185*2067ad9dSGordon Ross 	switch (reftype) {
186*2067ad9dSGordon Ross 	case DFS_REFERRAL_INVALID:
187*2067ad9dSGordon Ross 		/* Need to check the error for this case */
188*2067ad9dSGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
189*2067ad9dSGordon Ross 
190*2067ad9dSGordon Ross 	case DFS_REFERRAL_DOMAIN:
191*2067ad9dSGordon Ross 	case DFS_REFERRAL_DC:
192*2067ad9dSGordon Ross 		/* MS-DFSC: this error is returned by non-DC root */
193*2067ad9dSGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
194*2067ad9dSGordon Ross 
195*2067ad9dSGordon Ross 	case DFS_REFERRAL_SYSVOL:
196*2067ad9dSGordon Ross 		/* MS-DFSC: this error is returned by non-DC root */
197*2067ad9dSGordon Ross 		return (NT_STATUS_NO_SUCH_DEVICE);
198*2067ad9dSGordon Ross 
199*2067ad9dSGordon Ross 	default:
200*2067ad9dSGordon Ross 		break;
201*2067ad9dSGordon Ross 	}
202*2067ad9dSGordon Ross 
203*2067ad9dSGordon Ross 	status = smb_dfs_referrals_get(sr, path, reftype, &refrsp);
204*2067ad9dSGordon Ross 	if (status != NT_STATUS_SUCCESS)
205*2067ad9dSGordon Ross 		return (status);
206*2067ad9dSGordon Ross 
207*2067ad9dSGordon Ross 	referrals = &refrsp.rp_referrals;
208*2067ad9dSGordon Ross 	smb_dfs_encode_hdr(fsctl->out_mbc, referrals);
209*2067ad9dSGordon Ross 
210*2067ad9dSGordon Ross 	/*
211*2067ad9dSGordon Ross 	 * Server may respond with any referral version at or below
212*2067ad9dSGordon Ross 	 * the maximum specified in the request.
213*2067ad9dSGordon Ross 	 */
214*2067ad9dSGordon Ross 	switch (maxver) {
215*2067ad9dSGordon Ross 	case DFS_REFERRAL_V1:
216*2067ad9dSGordon Ross 		status = smb_dfs_encode_refv1(sr, fsctl->out_mbc, referrals);
217*2067ad9dSGordon Ross 		break;
218*2067ad9dSGordon Ross 
219*2067ad9dSGordon Ross 	case DFS_REFERRAL_V2:
220*2067ad9dSGordon Ross 		status = smb_dfs_encode_refv2(sr, fsctl->out_mbc, referrals);
221*2067ad9dSGordon Ross 		break;
222*2067ad9dSGordon Ross 
223*2067ad9dSGordon Ross 	case DFS_REFERRAL_V3:
224*2067ad9dSGordon Ross 		status = smb_dfs_encode_refv3x(sr, fsctl->out_mbc, referrals,
225*2067ad9dSGordon Ross 		    DFS_REFERRAL_V3);
226*2067ad9dSGordon Ross 		break;
227*2067ad9dSGordon Ross 
228*2067ad9dSGordon Ross 	case DFS_REFERRAL_V4:
229*2067ad9dSGordon Ross 	default:
230*2067ad9dSGordon Ross 		status = smb_dfs_encode_refv3x(sr, fsctl->out_mbc, referrals,
231*2067ad9dSGordon Ross 		    DFS_REFERRAL_V4);
232*2067ad9dSGordon Ross 		break;
233*2067ad9dSGordon Ross 	}
234*2067ad9dSGordon Ross 
235*2067ad9dSGordon Ross 	smb_dfs_referrals_free(&refrsp);
236*2067ad9dSGordon Ross 
237*2067ad9dSGordon Ross 	return (status);
238*2067ad9dSGordon Ross }
239*2067ad9dSGordon Ross 
240*2067ad9dSGordon Ross /*
241a90cf9f2SGordon Ross  * Note: SMB1 callers in smb_trans2_dfs.c
242a90cf9f2SGordon Ross  * smb_com_trans2_report_dfs_inconsistency
243a90cf9f2SGordon Ross  * smb_com_trans2_get_dfs_referral
244a90cf9f2SGordon Ross  */
245a90cf9f2SGordon Ross 
246a90cf9f2SGordon Ross /*
247a90cf9f2SGordon Ross  * See [MS-DFSC] for details about this command
24855f0a249SGordon Ross  * Handles FSCTL_DFS_GET_REFERRALS (only)
249a90cf9f2SGordon Ross  */
250a90cf9f2SGordon Ross uint32_t
smb_dfs_get_referrals(smb_request_t * sr,smb_fsctl_t * fsctl)251a90cf9f2SGordon Ross smb_dfs_get_referrals(smb_request_t *sr, smb_fsctl_t *fsctl)
252a90cf9f2SGordon Ross {
253a90cf9f2SGordon Ross 	dfs_info_t *referrals;
254a90cf9f2SGordon Ross 	dfs_referral_response_t refrsp;
255a90cf9f2SGordon Ross 	dfs_reftype_t reftype;
256a90cf9f2SGordon Ross 	char *path;
257a90cf9f2SGordon Ross 	uint16_t maxver;
258a90cf9f2SGordon Ross 	uint32_t status;
259a90cf9f2SGordon Ross 	int rc;
260a90cf9f2SGordon Ross 
261a90cf9f2SGordon Ross 	/*
262a90cf9f2SGordon Ross 	 * The caller checks this, because the error reporting method
263a90cf9f2SGordon Ross 	 * varies across SMB versions.
264a90cf9f2SGordon Ross 	 */
265a90cf9f2SGordon Ross 	ASSERT(STYPE_ISIPC(sr->tid_tree->t_res_type));
266a90cf9f2SGordon Ross 
267a90cf9f2SGordon Ross 	/*
268a90cf9f2SGordon Ross 	 * Input data is (w) MaxReferralLevel, (U) path
269a90cf9f2SGordon Ross 	 */
270a90cf9f2SGordon Ross 	rc = smb_mbc_decodef(fsctl->in_mbc, "%wu",
271a90cf9f2SGordon Ross 	    sr, &maxver, &path);
272a90cf9f2SGordon Ross 	if (rc != 0)
273a90cf9f2SGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
274a90cf9f2SGordon Ross 
275a90cf9f2SGordon Ross 	reftype = smb_dfs_get_reftype((const char *)path);
276a90cf9f2SGordon Ross 	switch (reftype) {
277a90cf9f2SGordon Ross 	case DFS_REFERRAL_INVALID:
278a90cf9f2SGordon Ross 		/* Need to check the error for this case */
279a90cf9f2SGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
280a90cf9f2SGordon Ross 
281a90cf9f2SGordon Ross 	case DFS_REFERRAL_DOMAIN:
282a90cf9f2SGordon Ross 	case DFS_REFERRAL_DC:
283a90cf9f2SGordon Ross 		/* MS-DFSC: this error is returned by non-DC root */
284a90cf9f2SGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
285a90cf9f2SGordon Ross 
286a90cf9f2SGordon Ross 	case DFS_REFERRAL_SYSVOL:
287a90cf9f2SGordon Ross 		/* MS-DFSC: this error is returned by non-DC root */
288a90cf9f2SGordon Ross 		return (NT_STATUS_NO_SUCH_DEVICE);
289a90cf9f2SGordon Ross 
290a90cf9f2SGordon Ross 	default:
291a90cf9f2SGordon Ross 		break;
292a90cf9f2SGordon Ross 	}
293a90cf9f2SGordon Ross 
294a90cf9f2SGordon Ross 	status = smb_dfs_referrals_get(sr, path, reftype, &refrsp);
295a90cf9f2SGordon Ross 	if (status != NT_STATUS_SUCCESS)
296a90cf9f2SGordon Ross 		return (status);
297a90cf9f2SGordon Ross 
298a90cf9f2SGordon Ross 	referrals = &refrsp.rp_referrals;
299a90cf9f2SGordon Ross 	smb_dfs_encode_hdr(fsctl->out_mbc, referrals);
300a90cf9f2SGordon Ross 
301a90cf9f2SGordon Ross 	/*
302a90cf9f2SGordon Ross 	 * Server may respond with any referral version at or below
303a90cf9f2SGordon Ross 	 * the maximum specified in the request.
304a90cf9f2SGordon Ross 	 */
305a90cf9f2SGordon Ross 	switch (maxver) {
306a90cf9f2SGordon Ross 	case DFS_REFERRAL_V1:
307a90cf9f2SGordon Ross 		status = smb_dfs_encode_refv1(sr, fsctl->out_mbc, referrals);
308a90cf9f2SGordon Ross 		break;
309a90cf9f2SGordon Ross 
310a90cf9f2SGordon Ross 	case DFS_REFERRAL_V2:
311a90cf9f2SGordon Ross 		status = smb_dfs_encode_refv2(sr, fsctl->out_mbc, referrals);
312a90cf9f2SGordon Ross 		break;
313a90cf9f2SGordon Ross 
314a90cf9f2SGordon Ross 	case DFS_REFERRAL_V3:
315a90cf9f2SGordon Ross 		status = smb_dfs_encode_refv3x(sr, fsctl->out_mbc, referrals,
316a90cf9f2SGordon Ross 		    DFS_REFERRAL_V3);
317a90cf9f2SGordon Ross 		break;
318a90cf9f2SGordon Ross 
319a90cf9f2SGordon Ross 	case DFS_REFERRAL_V4:
320a90cf9f2SGordon Ross 	default:
321a90cf9f2SGordon Ross 		status = smb_dfs_encode_refv3x(sr, fsctl->out_mbc, referrals,
322a90cf9f2SGordon Ross 		    DFS_REFERRAL_V4);
323a90cf9f2SGordon Ross 		break;
324a90cf9f2SGordon Ross 	}
325a90cf9f2SGordon Ross 
326a90cf9f2SGordon Ross 	smb_dfs_referrals_free(&refrsp);
327a90cf9f2SGordon Ross 
328a90cf9f2SGordon Ross 	return (status);
329a90cf9f2SGordon Ross }
330a90cf9f2SGordon Ross 
331a90cf9f2SGordon Ross /*
332a90cf9f2SGordon Ross  * [MS-DFSC]: REQ_GET_DFS_REFERRAL
333a90cf9f2SGordon Ross  *
334a90cf9f2SGordon Ross  * Determines the referral type based on the specified path:
335a90cf9f2SGordon Ross  *
336a90cf9f2SGordon Ross  * Domain referral:
337a90cf9f2SGordon Ross  *    ""
338a90cf9f2SGordon Ross  *
339a90cf9f2SGordon Ross  * DC referral:
340a90cf9f2SGordon Ross  *    \<domain>
341a90cf9f2SGordon Ross  *
342a90cf9f2SGordon Ross  * Sysvol referral:
343a90cf9f2SGordon Ross  *    \<domain>\SYSVOL
344a90cf9f2SGordon Ross  *    \<domain>\NETLOGON
345a90cf9f2SGordon Ross  *
346a90cf9f2SGordon Ross  * Root referral:
347a90cf9f2SGordon Ross  *    \<domain>\<dfsname>
348a90cf9f2SGordon Ross  *    \<server>\<dfsname>
349a90cf9f2SGordon Ross  *
350a90cf9f2SGordon Ross  * Link referral:
351a90cf9f2SGordon Ross  *    \<domain>\<dfsname>\<linkpath>
352a90cf9f2SGordon Ross  *    \<server>\<dfsname>\<linkpath>
353a90cf9f2SGordon Ross  */
354a90cf9f2SGordon Ross static dfs_reftype_t
smb_dfs_get_reftype(const char * path)355a90cf9f2SGordon Ross smb_dfs_get_reftype(const char *path)
356a90cf9f2SGordon Ross {
357a90cf9f2SGordon Ross 	smb_unc_t unc;
358a90cf9f2SGordon Ross 	dfs_reftype_t reftype = 0;
359a90cf9f2SGordon Ross 
360a90cf9f2SGordon Ross 	if (*path == '\0')
361a90cf9f2SGordon Ross 		return (DFS_REFERRAL_DOMAIN);
362a90cf9f2SGordon Ross 
363a90cf9f2SGordon Ross 	if (smb_unc_init(path, &unc) != 0)
364a90cf9f2SGordon Ross 		return (DFS_REFERRAL_INVALID);
365a90cf9f2SGordon Ross 
366a90cf9f2SGordon Ross 	if (unc.unc_path != NULL) {
367a90cf9f2SGordon Ross 		reftype = DFS_REFERRAL_LINK;
368a90cf9f2SGordon Ross 	} else if (unc.unc_share != NULL) {
369a90cf9f2SGordon Ross 		if ((smb_strcasecmp(unc.unc_share, "SYSVOL", 0) == 0) ||
370a90cf9f2SGordon Ross 		    (smb_strcasecmp(unc.unc_share, "NETLOGON", 0) == 0)) {
371a90cf9f2SGordon Ross 			reftype = DFS_REFERRAL_SYSVOL;
372a90cf9f2SGordon Ross 		} else {
373a90cf9f2SGordon Ross 			reftype = DFS_REFERRAL_ROOT;
374a90cf9f2SGordon Ross 		}
375a90cf9f2SGordon Ross 	} else if (unc.unc_server != NULL) {
376a90cf9f2SGordon Ross 		reftype = DFS_REFERRAL_DC;
377a90cf9f2SGordon Ross 	}
378a90cf9f2SGordon Ross 
379a90cf9f2SGordon Ross 	smb_unc_free(&unc);
380a90cf9f2SGordon Ross 	return (reftype);
381a90cf9f2SGordon Ross }
382a90cf9f2SGordon Ross 
383a90cf9f2SGordon Ross static void
smb_dfs_encode_hdr(mbuf_chain_t * mbc,dfs_info_t * referrals)384a90cf9f2SGordon Ross smb_dfs_encode_hdr(mbuf_chain_t *mbc, dfs_info_t *referrals)
385a90cf9f2SGordon Ross {
386a90cf9f2SGordon Ross 	uint16_t path_consumed;
387a90cf9f2SGordon Ross 	uint32_t flags;
388a90cf9f2SGordon Ross 
389a90cf9f2SGordon Ross 	path_consumed = smb_wcequiv_strlen(referrals->i_uncpath);
390a90cf9f2SGordon Ross 	flags = DFS_HDRFLG_S;
391a90cf9f2SGordon Ross 	if (referrals->i_type == DFS_OBJECT_ROOT)
392a90cf9f2SGordon Ross 		flags |= DFS_HDRFLG_R;
393a90cf9f2SGordon Ross 
394a90cf9f2SGordon Ross 	/* Fill rep_param_mb in SMB1 caller. */
395a90cf9f2SGordon Ross 	(void) smb_mbc_encodef(mbc, "wwl", path_consumed,
396a90cf9f2SGordon Ross 	    referrals->i_ntargets, flags);
397a90cf9f2SGordon Ross }
398a90cf9f2SGordon Ross 
399a90cf9f2SGordon Ross static uint32_t
smb_dfs_encode_refv1(smb_request_t * sr,mbuf_chain_t * mbc,dfs_info_t * referrals)400a90cf9f2SGordon Ross smb_dfs_encode_refv1(smb_request_t *sr, mbuf_chain_t *mbc,
401a90cf9f2SGordon Ross     dfs_info_t *referrals)
402a90cf9f2SGordon Ross {
403a90cf9f2SGordon Ross 	_NOTE(ARGUNUSED(sr))
404a90cf9f2SGordon Ross 	uint16_t entsize, rep_bufsize;
405a90cf9f2SGordon Ross 	uint16_t server_type;
406a90cf9f2SGordon Ross 	uint16_t flags = 0;
407a90cf9f2SGordon Ross 	uint16_t r;
408a90cf9f2SGordon Ross 	char *target;
409a90cf9f2SGordon Ross 
410a90cf9f2SGordon Ross 	rep_bufsize = MBC_MAXBYTES(mbc);
411a90cf9f2SGordon Ross 
412a90cf9f2SGordon Ross 	server_type = (referrals->i_type == DFS_OBJECT_ROOT) ?
413a90cf9f2SGordon Ross 	    DFS_SRVTYPE_ROOT : DFS_SRVTYPE_NONROOT;
414a90cf9f2SGordon Ross 
415a90cf9f2SGordon Ross 	target = kmem_alloc(MAXPATHLEN, KM_SLEEP);
416a90cf9f2SGordon Ross 
417a90cf9f2SGordon Ross 	for (r = 0; r < referrals->i_ntargets; r++) {
418a90cf9f2SGordon Ross 		(void) snprintf(target, MAXPATHLEN, "\\%s\\%s",
419a90cf9f2SGordon Ross 		    referrals->i_targets[r].t_server,
420a90cf9f2SGordon Ross 		    referrals->i_targets[r].t_share);
421a90cf9f2SGordon Ross 
422a90cf9f2SGordon Ross 		entsize = DFS_REFV1_ENTSZ + smb_wcequiv_strlen(target) + 2;
423a90cf9f2SGordon Ross 		if (entsize > rep_bufsize)
424a90cf9f2SGordon Ross 			break;
425a90cf9f2SGordon Ross 
426a90cf9f2SGordon Ross 		(void) smb_mbc_encodef(mbc, "wwwwU",
427a90cf9f2SGordon Ross 		    DFS_REFERRAL_V1, entsize, server_type, flags, target);
428a90cf9f2SGordon Ross 		rep_bufsize -= entsize;
429a90cf9f2SGordon Ross 	}
430a90cf9f2SGordon Ross 
431a90cf9f2SGordon Ross 	kmem_free(target, MAXPATHLEN);
432a90cf9f2SGordon Ross 
433a90cf9f2SGordon Ross 	/*
434a90cf9f2SGordon Ross 	 * Need room for at least one entry.
435a90cf9f2SGordon Ross 	 * Windows will silently drop targets that do not fit in
436a90cf9f2SGordon Ross 	 * the response buffer.
437a90cf9f2SGordon Ross 	 */
438a90cf9f2SGordon Ross 	if (r == 0) {
439a90cf9f2SGordon Ross 		return (NT_STATUS_BUFFER_OVERFLOW);
440a90cf9f2SGordon Ross 	}
441a90cf9f2SGordon Ross 
442a90cf9f2SGordon Ross 	return (NT_STATUS_SUCCESS);
443a90cf9f2SGordon Ross }
444a90cf9f2SGordon Ross 
445a90cf9f2SGordon Ross /*
446a90cf9f2SGordon Ross  * Prepare a response with V2 referral format.
447a90cf9f2SGordon Ross  *
448a90cf9f2SGordon Ross  * Here is the response packet format.
449a90cf9f2SGordon Ross  * All the strings come after all the fixed size entry headers.
450a90cf9f2SGordon Ross  * These headers contain offsets to the strings at the end. Note
451a90cf9f2SGordon Ross  * that the two "dfs_path" after the last entry is shared between
452a90cf9f2SGordon Ross  * all the entries.
453a90cf9f2SGordon Ross  *
454a90cf9f2SGordon Ross  * ent1-hdr
455a90cf9f2SGordon Ross  * ent2-hdr
456a90cf9f2SGordon Ross  * ...
457a90cf9f2SGordon Ross  * entN-hdr
458a90cf9f2SGordon Ross  *   dfs_path
459a90cf9f2SGordon Ross  *   dfs_path
460a90cf9f2SGordon Ross  *   target1
461a90cf9f2SGordon Ross  *   target2
462a90cf9f2SGordon Ross  *   ...
463a90cf9f2SGordon Ross  *   targetN
464a90cf9f2SGordon Ross  *
465a90cf9f2SGordon Ross  * MS-DFSC mentions that strings can come after each entry header or all after
466a90cf9f2SGordon Ross  * the last entry header. Windows responses are in the format above.
467a90cf9f2SGordon Ross  */
468a90cf9f2SGordon Ross static uint32_t
smb_dfs_encode_refv2(smb_request_t * sr,mbuf_chain_t * mbc,dfs_info_t * referrals)469a90cf9f2SGordon Ross smb_dfs_encode_refv2(smb_request_t *sr, mbuf_chain_t *mbc,
470a90cf9f2SGordon Ross     dfs_info_t *referrals)
471a90cf9f2SGordon Ross {
472a90cf9f2SGordon Ross 	_NOTE(ARGUNUSED(sr))
473a90cf9f2SGordon Ross 	uint16_t entsize, rep_bufsize;
474a90cf9f2SGordon Ross 	uint16_t server_type;
475a90cf9f2SGordon Ross 	uint16_t flags = 0;
476a90cf9f2SGordon Ross 	uint32_t proximity = 0;
477a90cf9f2SGordon Ross 	uint16_t path_offs, altpath_offs, netpath_offs;
478a90cf9f2SGordon Ross 	uint16_t targetsz, total_targetsz = 0;
479a90cf9f2SGordon Ross 	uint16_t dfs_pathsz;
480a90cf9f2SGordon Ross 	uint16_t r;
481a90cf9f2SGordon Ross 
482a90cf9f2SGordon Ross 	rep_bufsize = MBC_MAXBYTES(mbc);
483a90cf9f2SGordon Ross 	dfs_pathsz = smb_wcequiv_strlen(referrals->i_uncpath) + 2;
484a90cf9f2SGordon Ross 	entsize = DFS_REFV2_ENTSZ + dfs_pathsz + dfs_pathsz +
485a90cf9f2SGordon Ross 	    smb_dfs_referrals_unclen(referrals, 0);
486a90cf9f2SGordon Ross 
487a90cf9f2SGordon Ross 	if (entsize > rep_bufsize) {
488a90cf9f2SGordon Ross 		/* need room for at least one referral */
489a90cf9f2SGordon Ross 		return (NT_STATUS_BUFFER_OVERFLOW);
490a90cf9f2SGordon Ross 	}
491a90cf9f2SGordon Ross 
492a90cf9f2SGordon Ross 	server_type = (referrals->i_type == DFS_OBJECT_ROOT) ?
493a90cf9f2SGordon Ross 	    DFS_SRVTYPE_ROOT : DFS_SRVTYPE_NONROOT;
494a90cf9f2SGordon Ross 
495a90cf9f2SGordon Ross 	rep_bufsize -= entsize;
496a90cf9f2SGordon Ross 	entsize = DFS_REFV2_ENTSZ;
497a90cf9f2SGordon Ross 
498a90cf9f2SGordon Ross 	for (r = 0; r < referrals->i_ntargets; r++) {
499a90cf9f2SGordon Ross 		path_offs = (referrals->i_ntargets - r) * DFS_REFV2_ENTSZ;
500a90cf9f2SGordon Ross 		altpath_offs = path_offs + dfs_pathsz;
501a90cf9f2SGordon Ross 		netpath_offs = altpath_offs + dfs_pathsz + total_targetsz;
502a90cf9f2SGordon Ross 		targetsz = smb_dfs_referrals_unclen(referrals, r);
503a90cf9f2SGordon Ross 
504a90cf9f2SGordon Ross 		if (r != 0) {
505a90cf9f2SGordon Ross 			entsize = DFS_REFV2_ENTSZ + targetsz;
506a90cf9f2SGordon Ross 			if (entsize > rep_bufsize)
507a90cf9f2SGordon Ross 				/* silently drop targets that do not fit */
508a90cf9f2SGordon Ross 				break;
509a90cf9f2SGordon Ross 			rep_bufsize -= entsize;
510a90cf9f2SGordon Ross 		}
511a90cf9f2SGordon Ross 
512a90cf9f2SGordon Ross 		(void) smb_mbc_encodef(mbc, "wwwwllwww",
513a90cf9f2SGordon Ross 		    DFS_REFERRAL_V2, DFS_REFV2_ENTSZ, server_type, flags,
514a90cf9f2SGordon Ross 		    proximity, referrals->i_timeout, path_offs, altpath_offs,
515a90cf9f2SGordon Ross 		    netpath_offs);
516a90cf9f2SGordon Ross 
517a90cf9f2SGordon Ross 		total_targetsz += targetsz;
518a90cf9f2SGordon Ross 	}
519a90cf9f2SGordon Ross 
520a90cf9f2SGordon Ross 	smb_dfs_encode_targets(mbc, referrals);
521a90cf9f2SGordon Ross 
522a90cf9f2SGordon Ross 	return (NT_STATUS_SUCCESS);
523a90cf9f2SGordon Ross }
524a90cf9f2SGordon Ross 
525a90cf9f2SGordon Ross /*
526a90cf9f2SGordon Ross  * Prepare a response with V3/V4 referral format.
527a90cf9f2SGordon Ross  *
528a90cf9f2SGordon Ross  * For more details, see comments for smb_dfs_encode_refv2() or see
529a90cf9f2SGordon Ross  * MS-DFSC specification.
530a90cf9f2SGordon Ross  */
531a90cf9f2SGordon Ross static uint32_t
smb_dfs_encode_refv3x(smb_request_t * sr,mbuf_chain_t * mbc,dfs_info_t * referrals,uint16_t ver)532a90cf9f2SGordon Ross smb_dfs_encode_refv3x(smb_request_t *sr, mbuf_chain_t *mbc,
5334f7f6babSGordon Ross     dfs_info_t *referrals, uint16_t ver)
534a90cf9f2SGordon Ross {
535a90cf9f2SGordon Ross 	_NOTE(ARGUNUSED(sr))
536a90cf9f2SGordon Ross 	uint16_t entsize, rep_bufsize, hdrsize;
537a90cf9f2SGordon Ross 	uint16_t server_type;
538a90cf9f2SGordon Ross 	uint16_t flags = 0;
539a90cf9f2SGordon Ross 	uint16_t path_offs, altpath_offs, netpath_offs;
540a90cf9f2SGordon Ross 	uint16_t targetsz, total_targetsz = 0;
541a90cf9f2SGordon Ross 	uint16_t dfs_pathsz;
542a90cf9f2SGordon Ross 	uint16_t r;
543a90cf9f2SGordon Ross 
544a90cf9f2SGordon Ross 	hdrsize = (ver == DFS_REFERRAL_V3) ? DFS_REFV3_ENTSZ : DFS_REFV4_ENTSZ;
545a90cf9f2SGordon Ross 	rep_bufsize = MBC_MAXBYTES(mbc);
546a90cf9f2SGordon Ross 	dfs_pathsz = smb_wcequiv_strlen(referrals->i_uncpath) + 2;
547a90cf9f2SGordon Ross 	entsize = hdrsize + dfs_pathsz + dfs_pathsz +
548a90cf9f2SGordon Ross 	    smb_dfs_referrals_unclen(referrals, 0);
549a90cf9f2SGordon Ross 
550a90cf9f2SGordon Ross 	if (entsize > rep_bufsize) {
551a90cf9f2SGordon Ross 		/* need room for at least one referral */
552a90cf9f2SGordon Ross 		return (NT_STATUS_BUFFER_OVERFLOW);
553a90cf9f2SGordon Ross 	}
554a90cf9f2SGordon Ross 
555a90cf9f2SGordon Ross 	server_type = (referrals->i_type == DFS_OBJECT_ROOT) ?
556a90cf9f2SGordon Ross 	    DFS_SRVTYPE_ROOT : DFS_SRVTYPE_NONROOT;
557a90cf9f2SGordon Ross 
558a90cf9f2SGordon Ross 	rep_bufsize -= entsize;
559a90cf9f2SGordon Ross 
560a90cf9f2SGordon Ross 	for (r = 0; r < referrals->i_ntargets; r++) {
561a90cf9f2SGordon Ross 		path_offs = (referrals->i_ntargets - r) * hdrsize;
562a90cf9f2SGordon Ross 		altpath_offs = path_offs + dfs_pathsz;
563a90cf9f2SGordon Ross 		netpath_offs = altpath_offs + dfs_pathsz + total_targetsz;
564a90cf9f2SGordon Ross 		targetsz = smb_dfs_referrals_unclen(referrals, r);
565a90cf9f2SGordon Ross 
566a90cf9f2SGordon Ross 		if (r != 0) {
567a90cf9f2SGordon Ross 			entsize = hdrsize + targetsz;
568a90cf9f2SGordon Ross 			if (entsize > rep_bufsize)
569a90cf9f2SGordon Ross 				/* silently drop targets that do not fit */
570a90cf9f2SGordon Ross 				break;
571a90cf9f2SGordon Ross 			rep_bufsize -= entsize;
572a90cf9f2SGordon Ross 			flags = 0;
573a90cf9f2SGordon Ross 		} else if (ver == DFS_REFERRAL_V4) {
574a90cf9f2SGordon Ross 			flags = DFS_ENTFLG_T;
575a90cf9f2SGordon Ross 		}
576a90cf9f2SGordon Ross 
577a90cf9f2SGordon Ross 		(void) smb_mbc_encodef(mbc, "wwwwlwww16.",
578a90cf9f2SGordon Ross 		    ver, hdrsize, server_type, flags,
579a90cf9f2SGordon Ross 		    referrals->i_timeout, path_offs, altpath_offs,
580a90cf9f2SGordon Ross 		    netpath_offs);
581a90cf9f2SGordon Ross 
582a90cf9f2SGordon Ross 		total_targetsz += targetsz;
583a90cf9f2SGordon Ross 	}
584a90cf9f2SGordon Ross 
585a90cf9f2SGordon Ross 	smb_dfs_encode_targets(mbc, referrals);
586a90cf9f2SGordon Ross 
587a90cf9f2SGordon Ross 	return (NT_STATUS_SUCCESS);
588a90cf9f2SGordon Ross }
589a90cf9f2SGordon Ross 
590a90cf9f2SGordon Ross /*
591a90cf9f2SGordon Ross  * Encodes DFS path, and target strings which come after fixed header
592a90cf9f2SGordon Ross  * entries.
593a90cf9f2SGordon Ross  *
594a90cf9f2SGordon Ross  * Windows 2000 and earlier set the DFSAlternatePathOffset to point to
595a90cf9f2SGordon Ross  * an 8.3 string representation of the string pointed to by
596a90cf9f2SGordon Ross  * DFSPathOffset if it is not a legal 8.3 string. Otherwise, if
597a90cf9f2SGordon Ross  * DFSPathOffset points to a legal 8.3 string, DFSAlternatePathOffset
598a90cf9f2SGordon Ross  * points to a separate copy of the same string. Windows Server 2003,
599a90cf9f2SGordon Ross  * Windows Server 2008 and Windows Server 2008 R2 set the
600a90cf9f2SGordon Ross  * DFSPathOffset and DFSAlternatePathOffset fields to point to separate
601a90cf9f2SGordon Ross  * copies of the identical string.
602a90cf9f2SGordon Ross  *
603a90cf9f2SGordon Ross  * Following Windows 2003 and later here.
604a90cf9f2SGordon Ross  */
605a90cf9f2SGordon Ross static void
smb_dfs_encode_targets(mbuf_chain_t * mbc,dfs_info_t * referrals)606a90cf9f2SGordon Ross smb_dfs_encode_targets(mbuf_chain_t *mbc, dfs_info_t *referrals)
607a90cf9f2SGordon Ross {
608a90cf9f2SGordon Ross 	char *target;
609a90cf9f2SGordon Ross 	int r;
610a90cf9f2SGordon Ross 
611a90cf9f2SGordon Ross 	(void) smb_mbc_encodef(mbc, "UU", referrals->i_uncpath,
612a90cf9f2SGordon Ross 	    referrals->i_uncpath);
613a90cf9f2SGordon Ross 
614a90cf9f2SGordon Ross 	target = kmem_alloc(MAXPATHLEN, KM_SLEEP);
615a90cf9f2SGordon Ross 	for (r = 0; r < referrals->i_ntargets; r++) {
616a90cf9f2SGordon Ross 		(void) snprintf(target, MAXPATHLEN, "\\%s\\%s",
617a90cf9f2SGordon Ross 		    referrals->i_targets[r].t_server,
618a90cf9f2SGordon Ross 		    referrals->i_targets[r].t_share);
619a90cf9f2SGordon Ross 		(void) smb_mbc_encodef(mbc, "U", target);
620a90cf9f2SGordon Ross 	}
621a90cf9f2SGordon Ross 	kmem_free(target, MAXPATHLEN);
622a90cf9f2SGordon Ross }
623a90cf9f2SGordon Ross 
624a90cf9f2SGordon Ross /*
625a90cf9f2SGordon Ross  * Get referral information for the specified path from user space
626a90cf9f2SGordon Ross  * using a door call.
627a90cf9f2SGordon Ross  */
628a90cf9f2SGordon Ross static uint32_t
smb_dfs_referrals_get(smb_request_t * sr,char * dfs_path,dfs_reftype_t reftype,dfs_referral_response_t * refrsp)629a90cf9f2SGordon Ross smb_dfs_referrals_get(smb_request_t *sr, char *dfs_path, dfs_reftype_t reftype,
630a90cf9f2SGordon Ross     dfs_referral_response_t *refrsp)
631a90cf9f2SGordon Ross {
632a90cf9f2SGordon Ross 	dfs_referral_query_t	req;
633a90cf9f2SGordon Ross 	int			rc;
634a90cf9f2SGordon Ross 
635a90cf9f2SGordon Ross 	req.rq_type = reftype;
636a90cf9f2SGordon Ross 	req.rq_path = dfs_path;
637a90cf9f2SGordon Ross 
638a90cf9f2SGordon Ross 	bzero(refrsp, sizeof (dfs_referral_response_t));
639a90cf9f2SGordon Ross 	refrsp->rp_status = NT_STATUS_NOT_FOUND;
640a90cf9f2SGordon Ross 
641a90cf9f2SGordon Ross 	rc = smb_kdoor_upcall(sr->sr_server, SMB_DR_DFS_GET_REFERRALS,
642a90cf9f2SGordon Ross 	    &req, dfs_referral_query_xdr, refrsp, dfs_referral_response_xdr);
643a90cf9f2SGordon Ross 
644a44ccde2SGordon Ross 	if (rc != 0)
6454f7f6babSGordon Ross 		return (NT_STATUS_FS_DRIVER_REQUIRED);
646a44ccde2SGordon Ross 
647a44ccde2SGordon Ross 	/*
648a44ccde2SGordon Ross 	 * Map the Win error to one of the NT status codes
649a44ccde2SGordon Ross 	 * documented in MS-DFSC. The most common, when we
650a44ccde2SGordon Ross 	 * have no DFS root configured, is NOT_FOUND.
651a44ccde2SGordon Ross 	 */
652a44ccde2SGordon Ross 	switch (refrsp->rp_status) {
653a44ccde2SGordon Ross 	case ERROR_SUCCESS:
654a44ccde2SGordon Ross 		break;
655a44ccde2SGordon Ross 	case ERROR_INVALID_PARAMETER:
656a44ccde2SGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
657a44ccde2SGordon Ross 	case ERROR_NOT_ENOUGH_MEMORY:
658a44ccde2SGordon Ross 		return (NT_STATUS_INSUFFICIENT_RESOURCES);
659a44ccde2SGordon Ross 	case ERROR_NOT_FOUND:
660a44ccde2SGordon Ross 		return (NT_STATUS_NOT_FOUND);
661a44ccde2SGordon Ross 	default:
662a44ccde2SGordon Ross 		return (NT_STATUS_UNEXPECTED_NETWORK_ERROR);
663a90cf9f2SGordon Ross 	}
664a90cf9f2SGordon Ross 
665a90cf9f2SGordon Ross 	(void) strsubst(refrsp->rp_referrals.i_uncpath, '/', '\\');
666a90cf9f2SGordon Ross 	return (NT_STATUS_SUCCESS);
667a90cf9f2SGordon Ross }
668a90cf9f2SGordon Ross 
669a90cf9f2SGordon Ross static void
smb_dfs_referrals_free(dfs_referral_response_t * refrsp)670a90cf9f2SGordon Ross smb_dfs_referrals_free(dfs_referral_response_t *refrsp)
671a90cf9f2SGordon Ross {
672a90cf9f2SGordon Ross 	xdr_free(dfs_referral_response_xdr, (char *)refrsp);
673a90cf9f2SGordon Ross }
674a90cf9f2SGordon Ross 
675a90cf9f2SGordon Ross /*
676a90cf9f2SGordon Ross  * Returns the Unicode string length for the target UNC of
677a90cf9f2SGordon Ross  * the specified entry by 'refno'
678a90cf9f2SGordon Ross  *
679a90cf9f2SGordon Ross  * Note that the UNC path should be encoded with ONE leading
680a90cf9f2SGordon Ross  * slash not two as is common to user-visible UNC paths.
681a90cf9f2SGordon Ross  */
682a90cf9f2SGordon Ross static uint16_t
smb_dfs_referrals_unclen(dfs_info_t * referrals,uint16_t refno)683a90cf9f2SGordon Ross smb_dfs_referrals_unclen(dfs_info_t *referrals, uint16_t refno)
684a90cf9f2SGordon Ross {
685a90cf9f2SGordon Ross 	uint16_t len;
686a90cf9f2SGordon Ross 
687a90cf9f2SGordon Ross 	if (refno >= referrals->i_ntargets)
688a90cf9f2SGordon Ross 		return (0);
689a90cf9f2SGordon Ross 
690a90cf9f2SGordon Ross 	/* Encoded target UNC \server\share */
691a90cf9f2SGordon Ross 	len = smb_wcequiv_strlen(referrals->i_targets[refno].t_server) +
692a90cf9f2SGordon Ross 	    smb_wcequiv_strlen(referrals->i_targets[refno].t_share) +
693a90cf9f2SGordon Ross 	    smb_wcequiv_strlen("\\\\") + 2; /* two '\' + NULL */
694a90cf9f2SGordon Ross 
695a90cf9f2SGordon Ross 	return (len);
696a90cf9f2SGordon Ross }
697