2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
28 * (c) 2004 Apple Computer, Inc. All Rights Reserved
31 * netshareenum.c -- Routines for getting a list of share information
34 * MODIFICATION HISTORY:
35 * 27-Nov-2004 Guy Harris New today
40 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
48 #include <netsmb/mchain.h>
49 #include <netsmb/smb.h>
50 #include <netsmb/smb_lib.h>
51 #include <netsmb/smb_rap.h>
52 #include <netsmb/smb_netshareenum.h>
53 #include <smb/charsets.h>
55 #if 0 /* XXX see below */
56 #include <dce/exc_handling.h>
57 #include <rpc/attrb.h>
62 * Don't want RPC client-side code in here.
63 * It's good code; just doesn't belong here.
65 * The API provided by this library should be
66 * just files and pipes (and not much more).
67 * It MAY be useful to provide some of the
68 * RAP (remote API) functions functions like
69 * rap_netshareenum below...
71 * XXX: Not sure this file belongs here at all.
72 * smb_rap.h looks like a reasonable API
73 * for this library to export.
78 rpc_netshareenum(struct smb_ctx
*ctx
, int *entriesp
, int *totalp
,
79 struct share_info
**entries_listp
)
81 char ctx_string
[2+16+1]; /* enough for 64-bit pointer, in hex */
82 unsigned_char_p_t binding
;
83 unsigned32 binding_status
;
84 rpc_binding_handle_t binding_h
;
85 int error
, i
, entries
;
86 char *addrstr
, *srvnamestr
;
87 unsigned short *usrvnamestr
;
89 SHARE_ENUM_STRUCT share_info
;
90 SHARE_INFO_1_CONTAINER share_info_1_container
;
91 SHARE_INFO_1
*shares
, *share
;
92 unsigned32 total_entries
;
93 unsigned32 status
, free_status
;
94 struct share_info
*entry_list
, *elp
;
95 static EXCEPTION rpc_x_connect_rejected
;
96 static int exceptions_initialized
;
98 sprintf(ctx_string
, "%p", ctx
);
99 rpc_string_binding_compose(NULL
, "ncacn_np", ctx_string
,
100 "srvsvc", NULL
, &binding
, &binding_status
);
101 if (binding_status
!= rpc_s_ok
) {
102 smb_error(dgettext(TEXT_DOMAIN
,
103 "rpc_string_binding_compose failed with %d"),
107 rpc_binding_from_string_binding(binding
, &binding_h
, &status
);
108 rpc_string_free(&binding
, (unsigned32
*)&free_status
);
109 if (binding_status
!= rpc_s_ok
) {
110 smb_error(dgettext(TEXT_DOMAIN
,
111 "rpc_binding_from_string_binding failed with %d"), 0,
116 share_info
.share_union
.level
= 1;
117 share_info
.share_union
.tagged_union
.share1
= &share_info_1_container
;
118 share_info_1_container
.share_count
= 0;
119 share_info_1_container
.shares
= NULL
;
121 * Convert the server IP address to a string, and send that as
122 * the "server name" - that's what Windows appears to do, and
123 * that avoids problems with NetBIOS names containing
124 * non-ASCII characters.
126 addrstr
= inet_ntoa(ctx
->ct_srvinaddr
.sin_addr
);
127 srvnamestr
= malloc(strlen(addrstr
) + 3);
128 if (srvnamestr
== NULL
) {
130 smb_error(dgettext(TEXT_DOMAIN
,
131 "can't allocate string for server address"), status
);
132 rpc_binding_free(&binding_h
, &free_status
);
135 strcpy(srvnamestr
, "\\\\");
136 strcat(srvnamestr
, addrstr
);
137 usrvnamestr
= convert_utf8_to_leunicode(srvnamestr
);
138 if (usrvnamestr
== NULL
) {
139 smb_error(dgettext(TEXT_DOMAIN
,
140 "can't convert string for server address to Unicode"), 0);
141 rpc_binding_free(&binding_h
, &free_status
);
145 if (!exceptions_initialized
) {
146 EXCEPTION_INIT(rpc_x_connect_rejected
);
147 exc_set_status(&rpc_x_connect_rejected
, rpc_s_connect_rejected
);
148 exceptions_initialized
= 1;
150 /* printf("Calling NetrShareEnum.."); XXX */
152 status
= NetrShareEnum(binding_h
, usrvnamestr
, &level
,
153 &share_info
, 4294967295U, &total_entries
, NULL
);
155 smb_error(dgettext(TEXT_DOMAIN
,
156 "error from NetrShareEnum call: status = 0x%08x"),
159 CATCH (rpc_x_connect_rejected
)
161 * This is what we get if we can't open the pipe.
162 * That's a normal occurrence when we're talking
163 * to a system that (presumably) doesn't support
164 * DCE RPC on the server side, such as Windows 95/98/Me,
165 * so we don't log an error.
171 * XXX - should we handle some exceptions differently,
172 * returning different errors, and try RAP only for
175 smb_error(dgettext(TEXT_DOMAIN
,
176 "error from NetrShareEnum call: exception = %u"),
177 0, THIS_CATCH
->match
.value
);
180 rpc_binding_free(&binding_h
, &free_status
);
187 * XXX - if the IDL is correct, it's not clear whether the
188 * unmarshalling code will properly handle the case where
189 * a packet where "share_count" and the max count for the
190 * array of shares don't match; a valid DCE RPC implementation
191 * won't marshal something like that, but there's no guarantee
192 * that the server we're talking to has a valid implementation
193 * (which could be a *malicious* implementation!).
195 entries
= share_info
.share_union
.tagged_union
.share1
->share_count
;
196 shares
= share_info
.share_union
.tagged_union
.share1
->shares
;
197 entry_list
= calloc(entries
, sizeof (struct share_info
));
198 if (entry_list
== NULL
) {
200 goto cleanup_and_return
;
202 for (share
= shares
, elp
= entry_list
, i
= 0; i
< entries
;
204 elp
->type
= share
->shi1_type
;
205 elp
->netname
= convert_unicode_to_utf8(share
->shi1_share
);
206 if (elp
->netname
== NULL
)
208 elp
->remark
= convert_unicode_to_utf8(share
->shi1_remark
);
209 if (elp
->remark
== NULL
)
214 *totalp
= total_entries
;
215 *entries_listp
= entry_list
;
217 goto cleanup_and_return
;
221 for (elp
= entry_list
, i
= 0; i
< entries
; i
++, elp
++) {
223 * elp->netname is set before elp->remark, so if
224 * elp->netname is null, elp->remark is also null.
225 * If either of them is null, we haven't done anything
226 * to any entries after this one.
228 if (elp
->netname
== NULL
)
231 if (elp
->remark
== NULL
)
238 for (share
= shares
, i
= 0; i
< entries
; i
++, share
++) {
239 free(share
->shi1_share
);
240 free(share
->shi1_remark
);
244 * XXX - "share1" should be a unique pointer, but we haven't
245 * changed the marshalling code to support non-full pointers
246 * in unions, so we leave it as a full pointer.
248 * That means that this might, or might not, be changed from
249 * pointing to "share_info_1_container" to pointing to a
250 * mallocated structure, according to the DCE RPC 1.1 IDL spec;
251 * we free it only if it's changed.
253 if (share_info
.share_union
.tagged_union
.share1
!=
254 &share_info_1_container
)
255 free(share_info
.share_union
.tagged_union
.share1
);
261 * Enumerate shares using RAP
264 struct smb_share_info_1
{
265 char shi1_netname
[13];
268 uint32_t shi1_remark
; /* char * */
272 smb_rap_NetShareEnum(struct smb_ctx
*ctx
, int sLevel
, void *pbBuffer
,
273 int *cbBuffer
, int *pcEntriesRead
, int *pcTotalAvail
)
279 error
= smb_rap_create(0, "WrLeh", "B13BWz", &rap
);
282 (void) smb_rap_setNparam(rap
, sLevel
); /* W - sLevel */
283 (void) smb_rap_setPparam(rap
, pbBuffer
); /* r - pbBuffer */
284 (void) smb_rap_setNparam(rap
, *cbBuffer
); /* L - cbBuffer */
285 error
= smb_rap_request(rap
, ctx
);
287 *pcEntriesRead
= rap
->r_entries
;
288 error
= smb_rap_getNparam(rap
, &lval
);
289 *pcTotalAvail
= lval
;
290 /* Copy the data length into the IN/OUT variable. */
291 *cbBuffer
= rap
->r_rcvbuflen
;
293 error
= smb_rap_error(rap
, error
);
299 rap_netshareenum(struct smb_ctx
*ctx
, int *entriesp
, int *totalp
,
300 struct share_info
**entries_listp
)
302 int error
, bufsize
, i
, entries
, total
, nreturned
;
303 struct smb_share_info_1
*rpbuf
, *ep
;
304 struct share_info
*entry_list
, *elp
;
308 bufsize
= 0xffe0; /* samba notes win2k bug for 65535 */
309 rpbuf
= malloc(bufsize
);
313 error
= smb_rap_NetShareEnum(ctx
, 1, rpbuf
, &bufsize
, &entries
, &total
);
315 error
!= (ERROR_MORE_DATA
| SMB_RAP_ERROR
)) {
319 entry_list
= malloc(entries
* sizeof (struct share_info
));
320 if (entry_list
== NULL
) {
325 lbound
= entries
* (sizeof (struct smb_share_info_1
));
327 for (ep
= rpbuf
, elp
= entry_list
, i
= 0, nreturned
= 0; i
< entries
;
329 elp
->type
= letohs(ep
->shi1_type
);
330 ep
->shi1_pad
= '\0'; /* ensure null termination */
331 elp
->netname
= convert_wincs_to_utf8(ep
->shi1_netname
);
332 if (elp
->netname
== NULL
)
333 continue; /* punt on this entry */
335 * Check for validity of offset.
337 if (ep
->shi1_remark
>= lbound
&& ep
->shi1_remark
< rbound
) {
338 cp
= (char *)rpbuf
+ ep
->shi1_remark
;
339 elp
->remark
= convert_wincs_to_utf8(cp
);
345 *entriesp
= nreturned
;
347 *entries_listp
= entry_list
;
353 * First we try the RPC-based NetrShareEnum, and, if that fails, we fall
354 * back on the RAP-based NetShareEnum.
357 smb_netshareenum(struct smb_ctx
*ctx
, int *entriesp
, int *totalp
,
358 struct share_info
**entry_listp
)
364 * Try getting a list of shares with the SRVSVC RPC service.
366 error
= rpc_netshareenum(ctx
, entriesp
, totalp
, entry_listp
);
372 * OK, that didn't work - try RAP.
373 * XXX - do so only if it failed because we couldn't open
376 error
= rap_netshareenum(ctx
, entriesp
, totalp
, entry_listp
);