xref: /titanic_50/usr/src/lib/libsmbfs/smb/netshareenum.c (revision 4bff34e37def8a90f9194d81bc345c52ba20086a)
1*4bff34e3Sthurlow /*
2*4bff34e3Sthurlow  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3*4bff34e3Sthurlow  *
4*4bff34e3Sthurlow  * @APPLE_LICENSE_HEADER_START@
5*4bff34e3Sthurlow  *
6*4bff34e3Sthurlow  * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
7*4bff34e3Sthurlow  * Reserved.  This file contains Original Code and/or Modifications of
8*4bff34e3Sthurlow  * Original Code as defined in and that are subject to the Apple Public
9*4bff34e3Sthurlow  * Source License Version 1.0 (the 'License').  You may not use this file
10*4bff34e3Sthurlow  * except in compliance with the License.  Please obtain a copy of the
11*4bff34e3Sthurlow  * License at http://www.apple.com/publicsource and read it before using
12*4bff34e3Sthurlow  * this file.
13*4bff34e3Sthurlow  *
14*4bff34e3Sthurlow  * The Original Code and all software distributed under the License are
15*4bff34e3Sthurlow  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16*4bff34e3Sthurlow  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17*4bff34e3Sthurlow  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18*4bff34e3Sthurlow  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
19*4bff34e3Sthurlow  * License for the specific language governing rights and limitations
20*4bff34e3Sthurlow  * under the License."
21*4bff34e3Sthurlow  *
22*4bff34e3Sthurlow  * @APPLE_LICENSE_HEADER_END@
23*4bff34e3Sthurlow  */
24*4bff34e3Sthurlow 
25*4bff34e3Sthurlow /* BEGIN CSTYLED */
26*4bff34e3Sthurlow /*
27*4bff34e3Sthurlow  *      @(#)ui.c      *
28*4bff34e3Sthurlow  *      (c) 2004   Apple Computer, Inc.  All Rights Reserved
29*4bff34e3Sthurlow  *
30*4bff34e3Sthurlow  *
31*4bff34e3Sthurlow  *      netshareenum.c -- Routines for getting a list of share information
32*4bff34e3Sthurlow  *			  from a server.
33*4bff34e3Sthurlow  *
34*4bff34e3Sthurlow  *      MODIFICATION HISTORY:
35*4bff34e3Sthurlow  *       27-Nov-2004     Guy Harris	New today
36*4bff34e3Sthurlow  */
37*4bff34e3Sthurlow /* END CSTYLED */
38*4bff34e3Sthurlow 
39*4bff34e3Sthurlow #pragma ident	"%Z%%M%	%I%	%E% SMI"
40*4bff34e3Sthurlow 
41*4bff34e3Sthurlow #include <stdlib.h>
42*4bff34e3Sthurlow #include <string.h>
43*4bff34e3Sthurlow #include <stdio.h>
44*4bff34e3Sthurlow #include <errno.h>
45*4bff34e3Sthurlow 
46*4bff34e3Sthurlow #include <netsmb/mchain.h>
47*4bff34e3Sthurlow #include <netsmb/smb_lib.h>
48*4bff34e3Sthurlow #include <netsmb/smb_rap.h>
49*4bff34e3Sthurlow #include <netsmb/smb_netshareenum.h>
50*4bff34e3Sthurlow #include "charsets.h"
51*4bff34e3Sthurlow 
52*4bff34e3Sthurlow #if 0 /* XXX see below */
53*4bff34e3Sthurlow #include <dce/exc_handling.h>
54*4bff34e3Sthurlow #include <attrb.h>
55*4bff34e3Sthurlow #include "srvsvc.h"
56*4bff34e3Sthurlow #endif
57*4bff34e3Sthurlow 
58*4bff34e3Sthurlow /*
59*4bff34e3Sthurlow  * Don't want RPC client-side code in here.
60*4bff34e3Sthurlow  * It's good code; just doesn't belong here.
61*4bff34e3Sthurlow  *
62*4bff34e3Sthurlow  * The API provided by this library should be
63*4bff34e3Sthurlow  * just files and pipes (and not much more).
64*4bff34e3Sthurlow  * It MAY be useful to provide some of the
65*4bff34e3Sthurlow  * RAP (remote API) functions functions like
66*4bff34e3Sthurlow  * rap_netshareenum below...
67*4bff34e3Sthurlow  *
68*4bff34e3Sthurlow  * XXX: Not sure this file belongs here at all.
69*4bff34e3Sthurlow  * smb_rap.h looks like a reasonable API
70*4bff34e3Sthurlow  * for this library to export.
71*4bff34e3Sthurlow  */
72*4bff34e3Sthurlow #if 0 /* XXX */
73*4bff34e3Sthurlow 
74*4bff34e3Sthurlow static int
75*4bff34e3Sthurlow rpc_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp,
76*4bff34e3Sthurlow     struct share_info **entries_listp)
77*4bff34e3Sthurlow {
78*4bff34e3Sthurlow 	char ctx_string[2+16+1];	/* enough for 64-bit pointer, in hex */
79*4bff34e3Sthurlow 	unsigned_char_p_t binding;
80*4bff34e3Sthurlow 	unsigned32 binding_status;
81*4bff34e3Sthurlow 	rpc_binding_handle_t binding_h;
82*4bff34e3Sthurlow 	int error, i, entries;
83*4bff34e3Sthurlow 	char *addrstr, *srvnamestr;
84*4bff34e3Sthurlow 	unsigned short *usrvnamestr;
85*4bff34e3Sthurlow 	unsigned32 level;
86*4bff34e3Sthurlow 	SHARE_ENUM_STRUCT share_info;
87*4bff34e3Sthurlow 	SHARE_INFO_1_CONTAINER share_info_1_container;
88*4bff34e3Sthurlow 	SHARE_INFO_1 *shares, *share;
89*4bff34e3Sthurlow 	unsigned32 total_entries;
90*4bff34e3Sthurlow 	unsigned32 status, free_status;
91*4bff34e3Sthurlow 	struct share_info *entry_list, *elp;
92*4bff34e3Sthurlow 	static EXCEPTION rpc_x_connect_rejected;
93*4bff34e3Sthurlow 	static int exceptions_initialized;
94*4bff34e3Sthurlow 
95*4bff34e3Sthurlow 	sprintf(ctx_string, "%p", ctx);
96*4bff34e3Sthurlow 	rpc_string_binding_compose(NULL, "ncacn_np", ctx_string,
97*4bff34e3Sthurlow 	    "srvsvc", NULL, &binding, &binding_status);
98*4bff34e3Sthurlow 	if (binding_status != rpc_s_ok) {
99*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
100*4bff34e3Sthurlow 		    "rpc_string_binding_compose failed with %d"),
101*4bff34e3Sthurlow 		    0, binding_status);
102*4bff34e3Sthurlow 		return (EINVAL);
103*4bff34e3Sthurlow 	}
104*4bff34e3Sthurlow 	rpc_binding_from_string_binding(binding, &binding_h, &status);
105*4bff34e3Sthurlow 	if (binding_status != rpc_s_ok) {
106*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
107*4bff34e3Sthurlow 		    "rpc_binding_from_string_binding failed with %d"), 0,
108*4bff34e3Sthurlow 		    binding_status);
109*4bff34e3Sthurlow 		return (EINVAL);
110*4bff34e3Sthurlow 	}
111*4bff34e3Sthurlow 	level = 1;
112*4bff34e3Sthurlow 	share_info.share_union.level = 1;
113*4bff34e3Sthurlow 	share_info.share_union.tagged_union.share1 = &share_info_1_container;
114*4bff34e3Sthurlow 	share_info_1_container.share_count = 0;
115*4bff34e3Sthurlow 	share_info_1_container.shares = NULL;
116*4bff34e3Sthurlow 	/*
117*4bff34e3Sthurlow 	 * Convert the server IP address to a string, and send that as
118*4bff34e3Sthurlow 	 * the "server name" - that's what Windows appears to do, and
119*4bff34e3Sthurlow 	 * that avoids problems with NetBIOS names containing
120*4bff34e3Sthurlow 	 * non-ASCII characters.
121*4bff34e3Sthurlow 	 */
122*4bff34e3Sthurlow 	addrstr = inet_ntoa(ctx->ct_srvinaddr.sin_addr);
123*4bff34e3Sthurlow 	srvnamestr = malloc(strlen(addrstr) + 3);
124*4bff34e3Sthurlow 	if (srvnamestr == NULL) {
125*4bff34e3Sthurlow 		status = errno;
126*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
127*4bff34e3Sthurlow 		    "can't allocate string for server address"), status);
128*4bff34e3Sthurlow 		rpc_binding_free(&binding_h, &free_status);
129*4bff34e3Sthurlow 		return (status);
130*4bff34e3Sthurlow 	}
131*4bff34e3Sthurlow 	strcpy(srvnamestr, "\\\\");
132*4bff34e3Sthurlow 	strcat(srvnamestr, addrstr);
133*4bff34e3Sthurlow #ifdef NOTYETDEFINED
134*4bff34e3Sthurlow 	usrvnamestr = convert_utf8_to_leunicode(srvnamestr);
135*4bff34e3Sthurlow #endif
136*4bff34e3Sthurlow 	usrvnamestr = srvnamestr;
137*4bff34e3Sthurlow 	if (usrvnamestr == NULL) {
138*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
139*4bff34e3Sthurlow 		    "can't convert string for server address to Unicode"), 0);
140*4bff34e3Sthurlow 		rpc_binding_free(&binding_h, &free_status);
141*4bff34e3Sthurlow 		return (EINVAL);
142*4bff34e3Sthurlow 	}
143*4bff34e3Sthurlow 	if (!exceptions_initialized) {
144*4bff34e3Sthurlow 		EXCEPTION_INIT(rpc_x_connect_rejected);
145*4bff34e3Sthurlow 		exc_set_status(&rpc_x_connect_rejected, rpc_s_connect_rejected);
146*4bff34e3Sthurlow 		exceptions_initialized = 1;
147*4bff34e3Sthurlow 	}
148*4bff34e3Sthurlow 	/* printf("Calling NetrShareEnum.."); XXX */
149*4bff34e3Sthurlow 	TRY
150*4bff34e3Sthurlow 		status = NetrShareEnum(binding_h, usrvnamestr, &level,
151*4bff34e3Sthurlow 		    &share_info, 4294967295U, &total_entries, NULL);
152*4bff34e3Sthurlow 		if (status != 0)
153*4bff34e3Sthurlow 			smb_error(dgettext(TEXT_DOMAIN,
154*4bff34e3Sthurlow 			    "error from NetrShareEnum call: status = 0x%08x"),
155*4bff34e3Sthurlow 			    0, status);
156*4bff34e3Sthurlow 	/*CSTYLED*/
157*4bff34e3Sthurlow 	CATCH (rpc_x_connect_rejected)
158*4bff34e3Sthurlow 		/*
159*4bff34e3Sthurlow 		 * This is what we get if we can't open the pipe.
160*4bff34e3Sthurlow 		 * That's a normal occurrence when we're talking
161*4bff34e3Sthurlow 		 * to a system that (presumably) doesn't support
162*4bff34e3Sthurlow 		 * DCE RPC on the server side, such as Windows 95/98/Me,
163*4bff34e3Sthurlow 		 * so we don't log an error.
164*4bff34e3Sthurlow 		 */
165*4bff34e3Sthurlow 		/*CSTYLED*/
166*4bff34e3Sthurlow 		status = ENOTSUP;
167*4bff34e3Sthurlow 	CATCH_ALL
168*4bff34e3Sthurlow 		/*
169*4bff34e3Sthurlow 		 * XXX - should we handle some exceptions differently,
170*4bff34e3Sthurlow 		 * returning different errors, and try RAP only for
171*4bff34e3Sthurlow 		 * ENOTSUP?
172*4bff34e3Sthurlow 		 */
173*4bff34e3Sthurlow 		smb_error(dgettext(TEXT_DOMAIN,
174*4bff34e3Sthurlow 		    "error from NetrShareEnum call: exception = %u"),
175*4bff34e3Sthurlow 		    0, THIS_CATCH->match.value);
176*4bff34e3Sthurlow 		status = ENOTSUP;
177*4bff34e3Sthurlow 	ENDTRY
178*4bff34e3Sthurlow 	rpc_binding_free(&binding_h, &free_status);
179*4bff34e3Sthurlow 	free(srvnamestr);
180*4bff34e3Sthurlow 	free(usrvnamestr);
181*4bff34e3Sthurlow 	if (status != 0)
182*4bff34e3Sthurlow 		return (ENOTSUP);
183*4bff34e3Sthurlow 
184*4bff34e3Sthurlow 	/*
185*4bff34e3Sthurlow 	 * XXX - if the IDL is correct, it's not clear whether the
186*4bff34e3Sthurlow 	 * unmarshalling code will properly handle the case where
187*4bff34e3Sthurlow 	 * a packet where "share_count" and the max count for the
188*4bff34e3Sthurlow 	 * array of shares don't match; a valid DCE RPC implementation
189*4bff34e3Sthurlow 	 * won't marshal something like that, but there's no guarantee
190*4bff34e3Sthurlow 	 * that the server we're talking to has a valid implementation
191*4bff34e3Sthurlow 	 * (which could be a *malicious* implementation!).
192*4bff34e3Sthurlow 	 */
193*4bff34e3Sthurlow 	entries = share_info.share_union.tagged_union.share1->share_count;
194*4bff34e3Sthurlow 	shares = share_info.share_union.tagged_union.share1->shares;
195*4bff34e3Sthurlow 	entry_list = calloc(entries, sizeof (struct share_info));
196*4bff34e3Sthurlow 	if (entry_list == NULL) {
197*4bff34e3Sthurlow 		error = errno;
198*4bff34e3Sthurlow 		goto cleanup_and_return;
199*4bff34e3Sthurlow 	}
200*4bff34e3Sthurlow 	for (share = shares, elp = entry_list, i = 0; i < entries;
201*4bff34e3Sthurlow 	    i++, share++) {
202*4bff34e3Sthurlow 		elp->type = share->shi1_type;
203*4bff34e3Sthurlow #ifdef NOTYETDEFINED
204*4bff34e3Sthurlow 		elp->netname = convert_unicode_to_utf8(share->shi1_share);
205*4bff34e3Sthurlow #endif
206*4bff34e3Sthurlow 		elp->netname = share->shi1_share;
207*4bff34e3Sthurlow 		if (elp->netname == NULL)
208*4bff34e3Sthurlow 			goto fail;
209*4bff34e3Sthurlow #ifdef NOTYETDEFINED
210*4bff34e3Sthurlow 		elp->remark = convert_unicode_to_utf8(share->shi1_remark);
211*4bff34e3Sthurlow #endif
212*4bff34e3Sthurlow 		elp->remark = share->shi1_remark;
213*4bff34e3Sthurlow 		if (elp->remark == NULL)
214*4bff34e3Sthurlow 			goto fail;
215*4bff34e3Sthurlow 		elp++;
216*4bff34e3Sthurlow 	}
217*4bff34e3Sthurlow 	*entriesp = entries;
218*4bff34e3Sthurlow 	*totalp = total_entries;
219*4bff34e3Sthurlow 	*entries_listp = entry_list;
220*4bff34e3Sthurlow 	error = 0;
221*4bff34e3Sthurlow 	goto cleanup_and_return;
222*4bff34e3Sthurlow 
223*4bff34e3Sthurlow fail:
224*4bff34e3Sthurlow 	error = errno;
225*4bff34e3Sthurlow 	for (elp = entry_list, i = 0; i < entries; i++, elp++) {
226*4bff34e3Sthurlow 		/*
227*4bff34e3Sthurlow 		 * elp->netname is set before elp->remark, so if
228*4bff34e3Sthurlow 		 * elp->netname is null, elp->remark is also null.
229*4bff34e3Sthurlow 		 * If either of them is null, we haven't done anything
230*4bff34e3Sthurlow 		 * to any entries after this one.
231*4bff34e3Sthurlow 		 */
232*4bff34e3Sthurlow 		if (elp->netname == NULL)
233*4bff34e3Sthurlow 			break;
234*4bff34e3Sthurlow 		free(elp->netname);
235*4bff34e3Sthurlow 		if (elp->remark == NULL)
236*4bff34e3Sthurlow 			break;
237*4bff34e3Sthurlow 		free(elp->remark);
238*4bff34e3Sthurlow 	}
239*4bff34e3Sthurlow 	free(entry_list);
240*4bff34e3Sthurlow 
241*4bff34e3Sthurlow cleanup_and_return:
242*4bff34e3Sthurlow 	for (share = shares, i = 0; i < entries; i++, share++) {
243*4bff34e3Sthurlow 		free(share->shi1_share);
244*4bff34e3Sthurlow 		free(share->shi1_remark);
245*4bff34e3Sthurlow 	}
246*4bff34e3Sthurlow 	free(shares);
247*4bff34e3Sthurlow 	/*
248*4bff34e3Sthurlow 	 * XXX - "share1" should be a unique pointer, but we haven't
249*4bff34e3Sthurlow 	 * changed the marshalling code to support non-full pointers
250*4bff34e3Sthurlow 	 * in unions, so we leave it as a full pointer.
251*4bff34e3Sthurlow 	 *
252*4bff34e3Sthurlow 	 * That means that this might, or might not, be changed from
253*4bff34e3Sthurlow 	 * pointing to "share_info_1_container" to pointing to a
254*4bff34e3Sthurlow 	 * mallocated structure, according to the DCE RPC 1.1 IDL spec;
255*4bff34e3Sthurlow 	 * we free it only if it's changed.
256*4bff34e3Sthurlow 	 */
257*4bff34e3Sthurlow 	if (share_info.share_union.tagged_union.share1 !=
258*4bff34e3Sthurlow 	    &share_info_1_container)
259*4bff34e3Sthurlow 		free(share_info.share_union.tagged_union.share1);
260*4bff34e3Sthurlow 	return (error);
261*4bff34e3Sthurlow }
262*4bff34e3Sthurlow #endif /* XXX */
263*4bff34e3Sthurlow 
264*4bff34e3Sthurlow static int
265*4bff34e3Sthurlow rap_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp,
266*4bff34e3Sthurlow     struct share_info **entries_listp)
267*4bff34e3Sthurlow {
268*4bff34e3Sthurlow 	int error, bufsize, i, entries, total, nreturned;
269*4bff34e3Sthurlow 	struct smb_share_info_1 *rpbuf, *ep;
270*4bff34e3Sthurlow 	struct share_info *entry_list, *elp;
271*4bff34e3Sthurlow 	char *cp;
272*4bff34e3Sthurlow 	int lbound, rbound;
273*4bff34e3Sthurlow 
274*4bff34e3Sthurlow 	bufsize = 0xffe0;	/* samba notes win2k bug for 65535 */
275*4bff34e3Sthurlow 	rpbuf = malloc(bufsize);
276*4bff34e3Sthurlow 	if (rpbuf == NULL)
277*4bff34e3Sthurlow 		return (errno);
278*4bff34e3Sthurlow 
279*4bff34e3Sthurlow 	error = smb_rap_NetShareEnum(ctx, 1, rpbuf, &bufsize, &entries, &total);
280*4bff34e3Sthurlow 	if (error &&
281*4bff34e3Sthurlow 	    error != (SMB_ERROR_MORE_DATA | SMB_RAP_ERROR)) {
282*4bff34e3Sthurlow 		free(rpbuf);
283*4bff34e3Sthurlow 		return (error);
284*4bff34e3Sthurlow 	}
285*4bff34e3Sthurlow 	entry_list = malloc(entries * sizeof (struct share_info));
286*4bff34e3Sthurlow 	if (entry_list == NULL) {
287*4bff34e3Sthurlow 		error = errno;
288*4bff34e3Sthurlow 		free(rpbuf);
289*4bff34e3Sthurlow 		return (error);
290*4bff34e3Sthurlow 	}
291*4bff34e3Sthurlow 	lbound = entries * (sizeof (struct smb_share_info_1));
292*4bff34e3Sthurlow 	rbound = bufsize;
293*4bff34e3Sthurlow 	for (ep = rpbuf, elp = entry_list, i = 0, nreturned = 0; i < entries;
294*4bff34e3Sthurlow 	    i++, ep++) {
295*4bff34e3Sthurlow 		elp->type = letohs(ep->shi1_type);
296*4bff34e3Sthurlow 		ep->shi1_pad = '\0'; /* ensure null termination */
297*4bff34e3Sthurlow 		elp->netname = strdup(ep->shi1_netname);
298*4bff34e3Sthurlow #ifdef NOTYETDEFINED
299*4bff34e3Sthurlow 		elp->netname = convert_wincs_to_utf8(ep->shi1_netname);
300*4bff34e3Sthurlow #endif
301*4bff34e3Sthurlow 		if (elp->netname == NULL)
302*4bff34e3Sthurlow 			continue;	/* punt on this entry */
303*4bff34e3Sthurlow 		/*
304*4bff34e3Sthurlow 		 * Check for validity of offset.
305*4bff34e3Sthurlow 		 */
306*4bff34e3Sthurlow 		if (ep->shi1_remark >= lbound && ep->shi1_remark < rbound) {
307*4bff34e3Sthurlow 			cp = (char *)rpbuf + ep->shi1_remark;
308*4bff34e3Sthurlow 			elp->remark = cp;
309*4bff34e3Sthurlow #ifdef  NOTYETDEFINED
310*4bff34e3Sthurlow 			elp->remark = nls_str_toloc(cp, cp);
311*4bff34e3Sthurlow #endif
312*4bff34e3Sthurlow 		} else
313*4bff34e3Sthurlow 			elp->remark = NULL;
314*4bff34e3Sthurlow 		elp++;
315*4bff34e3Sthurlow 		nreturned++;
316*4bff34e3Sthurlow 	}
317*4bff34e3Sthurlow 	*entriesp = nreturned;
318*4bff34e3Sthurlow 	*totalp = total;
319*4bff34e3Sthurlow 	*entries_listp = entry_list;
320*4bff34e3Sthurlow 	free(rpbuf);
321*4bff34e3Sthurlow 	return (0);
322*4bff34e3Sthurlow }
323*4bff34e3Sthurlow 
324*4bff34e3Sthurlow /*
325*4bff34e3Sthurlow  * First we try the RPC-based NetrShareEnum, and, if that fails, we fall
326*4bff34e3Sthurlow  * back on the RAP-based NetShareEnum.
327*4bff34e3Sthurlow  */
328*4bff34e3Sthurlow int
329*4bff34e3Sthurlow smb_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp,
330*4bff34e3Sthurlow     struct share_info **entry_listp)
331*4bff34e3Sthurlow {
332*4bff34e3Sthurlow 	int error;
333*4bff34e3Sthurlow 
334*4bff34e3Sthurlow #ifdef NOTYETDEFINED
335*4bff34e3Sthurlow 	/*
336*4bff34e3Sthurlow 	 * Try getting a list of shares with the SRVSVC RPC service.
337*4bff34e3Sthurlow 	 */
338*4bff34e3Sthurlow 	error = rpc_netshareenum(ctx, entriesp, totalp, entry_listp);
339*4bff34e3Sthurlow 	if (error == 0)
340*4bff34e3Sthurlow 		return (0);
341*4bff34e3Sthurlow #endif
342*4bff34e3Sthurlow 
343*4bff34e3Sthurlow 	/*
344*4bff34e3Sthurlow 	 * OK, that didn't work - try RAP.
345*4bff34e3Sthurlow 	 * XXX - do so only if it failed because we couldn't open
346*4bff34e3Sthurlow 	 * the pipe?
347*4bff34e3Sthurlow 	 */
348*4bff34e3Sthurlow 	return (rap_netshareenum(ctx, entriesp, totalp, entry_listp));
349*4bff34e3Sthurlow }
350