16007Sthurlow /*
26007Sthurlow * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
36007Sthurlow *
46007Sthurlow * @APPLE_LICENSE_HEADER_START@
56007Sthurlow *
66007Sthurlow * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
76007Sthurlow * Reserved. This file contains Original Code and/or Modifications of
86007Sthurlow * Original Code as defined in and that are subject to the Apple Public
96007Sthurlow * Source License Version 1.0 (the 'License'). You may not use this file
106007Sthurlow * except in compliance with the License. Please obtain a copy of the
116007Sthurlow * License at http://www.apple.com/publicsource and read it before using
126007Sthurlow * this file.
136007Sthurlow *
146007Sthurlow * The Original Code and all software distributed under the License are
156007Sthurlow * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
166007Sthurlow * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
176007Sthurlow * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
186007Sthurlow * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
196007Sthurlow * License for the specific language governing rights and limitations
206007Sthurlow * under the License."
216007Sthurlow *
226007Sthurlow * @APPLE_LICENSE_HEADER_END@
236007Sthurlow */
246007Sthurlow
256007Sthurlow /* BEGIN CSTYLED */
266007Sthurlow /*
276007Sthurlow * @(#)ui.c *
286007Sthurlow * (c) 2004 Apple Computer, Inc. All Rights Reserved
296007Sthurlow *
306007Sthurlow *
316007Sthurlow * netshareenum.c -- Routines for getting a list of share information
326007Sthurlow * from a server.
336007Sthurlow *
346007Sthurlow * MODIFICATION HISTORY:
356007Sthurlow * 27-Nov-2004 Guy Harris New today
366007Sthurlow */
376007Sthurlow /* END CSTYLED */
386007Sthurlow
398271SGordon.Ross@Sun.COM /*
40*12508Samw@Sun.COM * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
418271SGordon.Ross@Sun.COM */
426007Sthurlow
436007Sthurlow #include <stdlib.h>
446007Sthurlow #include <string.h>
456007Sthurlow #include <stdio.h>
466007Sthurlow #include <errno.h>
476007Sthurlow
486007Sthurlow #include <netsmb/mchain.h>
4910023SGordon.Ross@Sun.COM #include <netsmb/smb.h>
506007Sthurlow #include <netsmb/smb_lib.h>
516007Sthurlow #include <netsmb/smb_rap.h>
526007Sthurlow #include <netsmb/smb_netshareenum.h>
538271SGordon.Ross@Sun.COM #include <smb/charsets.h>
546007Sthurlow
556007Sthurlow #if 0 /* XXX see below */
566007Sthurlow #include <dce/exc_handling.h>
578271SGordon.Ross@Sun.COM #include <rpc/attrb.h>
586007Sthurlow #include "srvsvc.h"
596007Sthurlow #endif
606007Sthurlow
616007Sthurlow /*
626007Sthurlow * Don't want RPC client-side code in here.
636007Sthurlow * It's good code; just doesn't belong here.
646007Sthurlow *
656007Sthurlow * The API provided by this library should be
666007Sthurlow * just files and pipes (and not much more).
676007Sthurlow * It MAY be useful to provide some of the
686007Sthurlow * RAP (remote API) functions functions like
696007Sthurlow * rap_netshareenum below...
706007Sthurlow *
716007Sthurlow * XXX: Not sure this file belongs here at all.
726007Sthurlow * smb_rap.h looks like a reasonable API
736007Sthurlow * for this library to export.
746007Sthurlow */
756007Sthurlow #if 0 /* XXX */
766007Sthurlow
776007Sthurlow static int
786007Sthurlow rpc_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp,
796007Sthurlow struct share_info **entries_listp)
806007Sthurlow {
816007Sthurlow char ctx_string[2+16+1]; /* enough for 64-bit pointer, in hex */
826007Sthurlow unsigned_char_p_t binding;
836007Sthurlow unsigned32 binding_status;
846007Sthurlow rpc_binding_handle_t binding_h;
856007Sthurlow int error, i, entries;
866007Sthurlow char *addrstr, *srvnamestr;
876007Sthurlow unsigned short *usrvnamestr;
886007Sthurlow unsigned32 level;
896007Sthurlow SHARE_ENUM_STRUCT share_info;
906007Sthurlow SHARE_INFO_1_CONTAINER share_info_1_container;
916007Sthurlow SHARE_INFO_1 *shares, *share;
926007Sthurlow unsigned32 total_entries;
936007Sthurlow unsigned32 status, free_status;
946007Sthurlow struct share_info *entry_list, *elp;
956007Sthurlow static EXCEPTION rpc_x_connect_rejected;
966007Sthurlow static int exceptions_initialized;
976007Sthurlow
986007Sthurlow sprintf(ctx_string, "%p", ctx);
996007Sthurlow rpc_string_binding_compose(NULL, "ncacn_np", ctx_string,
1006007Sthurlow "srvsvc", NULL, &binding, &binding_status);
1016007Sthurlow if (binding_status != rpc_s_ok) {
1026007Sthurlow smb_error(dgettext(TEXT_DOMAIN,
1036007Sthurlow "rpc_string_binding_compose failed with %d"),
1046007Sthurlow 0, binding_status);
1056007Sthurlow return (EINVAL);
1066007Sthurlow }
1076007Sthurlow rpc_binding_from_string_binding(binding, &binding_h, &status);
1088271SGordon.Ross@Sun.COM rpc_string_free(&binding, (unsigned32 *)&free_status);
1096007Sthurlow if (binding_status != rpc_s_ok) {
1106007Sthurlow smb_error(dgettext(TEXT_DOMAIN,
1116007Sthurlow "rpc_binding_from_string_binding failed with %d"), 0,
1126007Sthurlow binding_status);
1136007Sthurlow return (EINVAL);
1146007Sthurlow }
1156007Sthurlow level = 1;
1166007Sthurlow share_info.share_union.level = 1;
1176007Sthurlow share_info.share_union.tagged_union.share1 = &share_info_1_container;
1186007Sthurlow share_info_1_container.share_count = 0;
1196007Sthurlow share_info_1_container.shares = NULL;
1206007Sthurlow /*
1216007Sthurlow * Convert the server IP address to a string, and send that as
1226007Sthurlow * the "server name" - that's what Windows appears to do, and
1236007Sthurlow * that avoids problems with NetBIOS names containing
1246007Sthurlow * non-ASCII characters.
1256007Sthurlow */
1266007Sthurlow addrstr = inet_ntoa(ctx->ct_srvinaddr.sin_addr);
1276007Sthurlow srvnamestr = malloc(strlen(addrstr) + 3);
1286007Sthurlow if (srvnamestr == NULL) {
1296007Sthurlow status = errno;
1306007Sthurlow smb_error(dgettext(TEXT_DOMAIN,
1316007Sthurlow "can't allocate string for server address"), status);
1326007Sthurlow rpc_binding_free(&binding_h, &free_status);
1336007Sthurlow return (status);
1346007Sthurlow }
1356007Sthurlow strcpy(srvnamestr, "\\\\");
1366007Sthurlow strcat(srvnamestr, addrstr);
1376007Sthurlow usrvnamestr = convert_utf8_to_leunicode(srvnamestr);
1386007Sthurlow if (usrvnamestr == NULL) {
1396007Sthurlow smb_error(dgettext(TEXT_DOMAIN,
1406007Sthurlow "can't convert string for server address to Unicode"), 0);
1416007Sthurlow rpc_binding_free(&binding_h, &free_status);
1428271SGordon.Ross@Sun.COM free(srvnamestr);
1436007Sthurlow return (EINVAL);
1446007Sthurlow }
1456007Sthurlow if (!exceptions_initialized) {
1466007Sthurlow EXCEPTION_INIT(rpc_x_connect_rejected);
1476007Sthurlow exc_set_status(&rpc_x_connect_rejected, rpc_s_connect_rejected);
1486007Sthurlow exceptions_initialized = 1;
1496007Sthurlow }
1506007Sthurlow /* printf("Calling NetrShareEnum.."); XXX */
1516007Sthurlow TRY
1526007Sthurlow status = NetrShareEnum(binding_h, usrvnamestr, &level,
1536007Sthurlow &share_info, 4294967295U, &total_entries, NULL);
1546007Sthurlow if (status != 0)
1556007Sthurlow smb_error(dgettext(TEXT_DOMAIN,
1566007Sthurlow "error from NetrShareEnum call: status = 0x%08x"),
1576007Sthurlow 0, status);
1586007Sthurlow /*CSTYLED*/
1596007Sthurlow CATCH (rpc_x_connect_rejected)
1606007Sthurlow /*
1616007Sthurlow * This is what we get if we can't open the pipe.
1626007Sthurlow * That's a normal occurrence when we're talking
1636007Sthurlow * to a system that (presumably) doesn't support
1646007Sthurlow * DCE RPC on the server side, such as Windows 95/98/Me,
1656007Sthurlow * so we don't log an error.
1666007Sthurlow */
1676007Sthurlow /*CSTYLED*/
1686007Sthurlow status = ENOTSUP;
1696007Sthurlow CATCH_ALL
1706007Sthurlow /*
1716007Sthurlow * XXX - should we handle some exceptions differently,
1726007Sthurlow * returning different errors, and try RAP only for
1736007Sthurlow * ENOTSUP?
1746007Sthurlow */
1756007Sthurlow smb_error(dgettext(TEXT_DOMAIN,
1766007Sthurlow "error from NetrShareEnum call: exception = %u"),
1776007Sthurlow 0, THIS_CATCH->match.value);
1786007Sthurlow status = ENOTSUP;
1796007Sthurlow ENDTRY
1806007Sthurlow rpc_binding_free(&binding_h, &free_status);
1816007Sthurlow free(srvnamestr);
1826007Sthurlow free(usrvnamestr);
1836007Sthurlow if (status != 0)
1846007Sthurlow return (ENOTSUP);
1856007Sthurlow
1866007Sthurlow /*
1876007Sthurlow * XXX - if the IDL is correct, it's not clear whether the
1886007Sthurlow * unmarshalling code will properly handle the case where
1896007Sthurlow * a packet where "share_count" and the max count for the
1906007Sthurlow * array of shares don't match; a valid DCE RPC implementation
1916007Sthurlow * won't marshal something like that, but there's no guarantee
1926007Sthurlow * that the server we're talking to has a valid implementation
1936007Sthurlow * (which could be a *malicious* implementation!).
1946007Sthurlow */
1956007Sthurlow entries = share_info.share_union.tagged_union.share1->share_count;
1966007Sthurlow shares = share_info.share_union.tagged_union.share1->shares;
1976007Sthurlow entry_list = calloc(entries, sizeof (struct share_info));
1986007Sthurlow if (entry_list == NULL) {
1996007Sthurlow error = errno;
2006007Sthurlow goto cleanup_and_return;
2016007Sthurlow }
2026007Sthurlow for (share = shares, elp = entry_list, i = 0; i < entries;
2036007Sthurlow i++, share++) {
2046007Sthurlow elp->type = share->shi1_type;
2056007Sthurlow elp->netname = convert_unicode_to_utf8(share->shi1_share);
2066007Sthurlow if (elp->netname == NULL)
2076007Sthurlow goto fail;
2086007Sthurlow elp->remark = convert_unicode_to_utf8(share->shi1_remark);
2096007Sthurlow if (elp->remark == NULL)
2106007Sthurlow goto fail;
2116007Sthurlow elp++;
2126007Sthurlow }
2136007Sthurlow *entriesp = entries;
2146007Sthurlow *totalp = total_entries;
2156007Sthurlow *entries_listp = entry_list;
2166007Sthurlow error = 0;
2176007Sthurlow goto cleanup_and_return;
2186007Sthurlow
2196007Sthurlow fail:
2206007Sthurlow error = errno;
2216007Sthurlow for (elp = entry_list, i = 0; i < entries; i++, elp++) {
2226007Sthurlow /*
2236007Sthurlow * elp->netname is set before elp->remark, so if
2246007Sthurlow * elp->netname is null, elp->remark is also null.
2256007Sthurlow * If either of them is null, we haven't done anything
2266007Sthurlow * to any entries after this one.
2276007Sthurlow */
2286007Sthurlow if (elp->netname == NULL)
2296007Sthurlow break;
2306007Sthurlow free(elp->netname);
2316007Sthurlow if (elp->remark == NULL)
2326007Sthurlow break;
2336007Sthurlow free(elp->remark);
2346007Sthurlow }
2356007Sthurlow free(entry_list);
2366007Sthurlow
2376007Sthurlow cleanup_and_return:
2386007Sthurlow for (share = shares, i = 0; i < entries; i++, share++) {
2396007Sthurlow free(share->shi1_share);
2406007Sthurlow free(share->shi1_remark);
2416007Sthurlow }
2426007Sthurlow free(shares);
2436007Sthurlow /*
2446007Sthurlow * XXX - "share1" should be a unique pointer, but we haven't
2456007Sthurlow * changed the marshalling code to support non-full pointers
2466007Sthurlow * in unions, so we leave it as a full pointer.
2476007Sthurlow *
2486007Sthurlow * That means that this might, or might not, be changed from
2496007Sthurlow * pointing to "share_info_1_container" to pointing to a
2506007Sthurlow * mallocated structure, according to the DCE RPC 1.1 IDL spec;
2516007Sthurlow * we free it only if it's changed.
2526007Sthurlow */
2536007Sthurlow if (share_info.share_union.tagged_union.share1 !=
2546007Sthurlow &share_info_1_container)
2556007Sthurlow free(share_info.share_union.tagged_union.share1);
2566007Sthurlow return (error);
2576007Sthurlow }
2586007Sthurlow #endif /* XXX */
2596007Sthurlow
2608271SGordon.Ross@Sun.COM /*
2618271SGordon.Ross@Sun.COM * Enumerate shares using RAP
2628271SGordon.Ross@Sun.COM */
2638271SGordon.Ross@Sun.COM
2648271SGordon.Ross@Sun.COM struct smb_share_info_1 {
2658271SGordon.Ross@Sun.COM char shi1_netname[13];
2668271SGordon.Ross@Sun.COM char shi1_pad;
2678271SGordon.Ross@Sun.COM uint16_t shi1_type;
2688271SGordon.Ross@Sun.COM uint32_t shi1_remark; /* char * */
2698271SGordon.Ross@Sun.COM };
2708271SGordon.Ross@Sun.COM
2718271SGordon.Ross@Sun.COM static int
smb_rap_NetShareEnum(struct smb_ctx * ctx,int sLevel,void * pbBuffer,int * cbBuffer,int * pcEntriesRead,int * pcTotalAvail)2728271SGordon.Ross@Sun.COM smb_rap_NetShareEnum(struct smb_ctx *ctx, int sLevel, void *pbBuffer,
2738271SGordon.Ross@Sun.COM int *cbBuffer, int *pcEntriesRead, int *pcTotalAvail)
2748271SGordon.Ross@Sun.COM {
2758271SGordon.Ross@Sun.COM struct smb_rap *rap;
2768271SGordon.Ross@Sun.COM long lval = -1;
2778271SGordon.Ross@Sun.COM int error;
2788271SGordon.Ross@Sun.COM
2798271SGordon.Ross@Sun.COM error = smb_rap_create(0, "WrLeh", "B13BWz", &rap);
2808271SGordon.Ross@Sun.COM if (error)
2818271SGordon.Ross@Sun.COM return (error);
28211332SGordon.Ross@Sun.COM (void) smb_rap_setNparam(rap, sLevel); /* W - sLevel */
28311332SGordon.Ross@Sun.COM (void) smb_rap_setPparam(rap, pbBuffer); /* r - pbBuffer */
28411332SGordon.Ross@Sun.COM (void) smb_rap_setNparam(rap, *cbBuffer); /* L - cbBuffer */
2858271SGordon.Ross@Sun.COM error = smb_rap_request(rap, ctx);
2868271SGordon.Ross@Sun.COM if (error == 0) {
2878271SGordon.Ross@Sun.COM *pcEntriesRead = rap->r_entries;
2888271SGordon.Ross@Sun.COM error = smb_rap_getNparam(rap, &lval);
2898271SGordon.Ross@Sun.COM *pcTotalAvail = lval;
2908271SGordon.Ross@Sun.COM /* Copy the data length into the IN/OUT variable. */
2918271SGordon.Ross@Sun.COM *cbBuffer = rap->r_rcvbuflen;
2928271SGordon.Ross@Sun.COM }
2938271SGordon.Ross@Sun.COM error = smb_rap_error(rap, error);
2948271SGordon.Ross@Sun.COM smb_rap_done(rap);
2958271SGordon.Ross@Sun.COM return (error);
2968271SGordon.Ross@Sun.COM }
2978271SGordon.Ross@Sun.COM
2986007Sthurlow static int
rap_netshareenum(struct smb_ctx * ctx,int * entriesp,int * totalp,struct share_info ** entries_listp)2996007Sthurlow rap_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp,
3006007Sthurlow struct share_info **entries_listp)
3016007Sthurlow {
3026007Sthurlow int error, bufsize, i, entries, total, nreturned;
3036007Sthurlow struct smb_share_info_1 *rpbuf, *ep;
3046007Sthurlow struct share_info *entry_list, *elp;
3056007Sthurlow char *cp;
3066007Sthurlow int lbound, rbound;
3076007Sthurlow
3086007Sthurlow bufsize = 0xffe0; /* samba notes win2k bug for 65535 */
3096007Sthurlow rpbuf = malloc(bufsize);
3106007Sthurlow if (rpbuf == NULL)
3116007Sthurlow return (errno);
3126007Sthurlow
3136007Sthurlow error = smb_rap_NetShareEnum(ctx, 1, rpbuf, &bufsize, &entries, &total);
3146007Sthurlow if (error &&
315*12508Samw@Sun.COM error != (ERROR_MORE_DATA | SMB_RAP_ERROR)) {
3166007Sthurlow free(rpbuf);
3176007Sthurlow return (error);
3186007Sthurlow }
3196007Sthurlow entry_list = malloc(entries * sizeof (struct share_info));
3206007Sthurlow if (entry_list == NULL) {
3216007Sthurlow error = errno;
3226007Sthurlow free(rpbuf);
3236007Sthurlow return (error);
3246007Sthurlow }
3256007Sthurlow lbound = entries * (sizeof (struct smb_share_info_1));
3266007Sthurlow rbound = bufsize;
3276007Sthurlow for (ep = rpbuf, elp = entry_list, i = 0, nreturned = 0; i < entries;
3286007Sthurlow i++, ep++) {
3296007Sthurlow elp->type = letohs(ep->shi1_type);
3306007Sthurlow ep->shi1_pad = '\0'; /* ensure null termination */
3316007Sthurlow elp->netname = convert_wincs_to_utf8(ep->shi1_netname);
3326007Sthurlow if (elp->netname == NULL)
3336007Sthurlow continue; /* punt on this entry */
3346007Sthurlow /*
3356007Sthurlow * Check for validity of offset.
3366007Sthurlow */
3376007Sthurlow if (ep->shi1_remark >= lbound && ep->shi1_remark < rbound) {
3386007Sthurlow cp = (char *)rpbuf + ep->shi1_remark;
3398271SGordon.Ross@Sun.COM elp->remark = convert_wincs_to_utf8(cp);
3406007Sthurlow } else
3416007Sthurlow elp->remark = NULL;
3426007Sthurlow elp++;
3436007Sthurlow nreturned++;
3446007Sthurlow }
3456007Sthurlow *entriesp = nreturned;
3466007Sthurlow *totalp = total;
3476007Sthurlow *entries_listp = entry_list;
3486007Sthurlow free(rpbuf);
3496007Sthurlow return (0);
3506007Sthurlow }
3516007Sthurlow
3526007Sthurlow /*
3536007Sthurlow * First we try the RPC-based NetrShareEnum, and, if that fails, we fall
3546007Sthurlow * back on the RAP-based NetShareEnum.
3556007Sthurlow */
3566007Sthurlow int
smb_netshareenum(struct smb_ctx * ctx,int * entriesp,int * totalp,struct share_info ** entry_listp)3576007Sthurlow smb_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp,
3586007Sthurlow struct share_info **entry_listp)
3596007Sthurlow {
3606007Sthurlow int error;
3616007Sthurlow
3626007Sthurlow #ifdef NOTYETDEFINED
3636007Sthurlow /*
3646007Sthurlow * Try getting a list of shares with the SRVSVC RPC service.
3656007Sthurlow */
3666007Sthurlow error = rpc_netshareenum(ctx, entriesp, totalp, entry_listp);
3676007Sthurlow if (error == 0)
3686007Sthurlow return (0);
3696007Sthurlow #endif
3706007Sthurlow
3716007Sthurlow /*
3726007Sthurlow * OK, that didn't work - try RAP.
3736007Sthurlow * XXX - do so only if it failed because we couldn't open
3746007Sthurlow * the pipe?
3756007Sthurlow */
37610023SGordon.Ross@Sun.COM error = rap_netshareenum(ctx, entriesp, totalp, entry_listp);
37710023SGordon.Ross@Sun.COM return (error);
3786007Sthurlow }
379