14bff34e3Sthurlow /*
24bff34e3Sthurlow * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
34bff34e3Sthurlow *
44bff34e3Sthurlow * @APPLE_LICENSE_HEADER_START@
54bff34e3Sthurlow *
64bff34e3Sthurlow * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
74bff34e3Sthurlow * Reserved. This file contains Original Code and/or Modifications of
84bff34e3Sthurlow * Original Code as defined in and that are subject to the Apple Public
94bff34e3Sthurlow * Source License Version 1.0 (the 'License'). You may not use this file
104bff34e3Sthurlow * except in compliance with the License. Please obtain a copy of the
114bff34e3Sthurlow * License at http://www.apple.com/publicsource and read it before using
124bff34e3Sthurlow * this file.
134bff34e3Sthurlow *
144bff34e3Sthurlow * The Original Code and all software distributed under the License are
154bff34e3Sthurlow * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
164bff34e3Sthurlow * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
174bff34e3Sthurlow * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
184bff34e3Sthurlow * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
194bff34e3Sthurlow * License for the specific language governing rights and limitations
204bff34e3Sthurlow * under the License."
214bff34e3Sthurlow *
224bff34e3Sthurlow * @APPLE_LICENSE_HEADER_END@
234bff34e3Sthurlow */
244bff34e3Sthurlow
254bff34e3Sthurlow /* BEGIN CSTYLED */
264bff34e3Sthurlow /*
274bff34e3Sthurlow * @(#)ui.c *
284bff34e3Sthurlow * (c) 2004 Apple Computer, Inc. All Rights Reserved
294bff34e3Sthurlow *
304bff34e3Sthurlow *
314bff34e3Sthurlow * netshareenum.c -- Routines for getting a list of share information
324bff34e3Sthurlow * from a server.
334bff34e3Sthurlow *
344bff34e3Sthurlow * MODIFICATION HISTORY:
354bff34e3Sthurlow * 27-Nov-2004 Guy Harris New today
364bff34e3Sthurlow */
374bff34e3Sthurlow /* END CSTYLED */
384bff34e3Sthurlow
399c9af259SGordon Ross /*
40*148c5f43SAlan Wright * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
419c9af259SGordon Ross */
424bff34e3Sthurlow
434bff34e3Sthurlow #include <stdlib.h>
444bff34e3Sthurlow #include <string.h>
454bff34e3Sthurlow #include <stdio.h>
464bff34e3Sthurlow #include <errno.h>
474bff34e3Sthurlow
484bff34e3Sthurlow #include <netsmb/mchain.h>
49613a2f6bSGordon Ross #include <netsmb/smb.h>
504bff34e3Sthurlow #include <netsmb/smb_lib.h>
514bff34e3Sthurlow #include <netsmb/smb_rap.h>
524bff34e3Sthurlow #include <netsmb/smb_netshareenum.h>
539c9af259SGordon Ross #include <smb/charsets.h>
544bff34e3Sthurlow
554bff34e3Sthurlow #if 0 /* XXX see below */
564bff34e3Sthurlow #include <dce/exc_handling.h>
579c9af259SGordon Ross #include <rpc/attrb.h>
584bff34e3Sthurlow #include "srvsvc.h"
594bff34e3Sthurlow #endif
604bff34e3Sthurlow
614bff34e3Sthurlow /*
624bff34e3Sthurlow * Don't want RPC client-side code in here.
634bff34e3Sthurlow * It's good code; just doesn't belong here.
644bff34e3Sthurlow *
654bff34e3Sthurlow * The API provided by this library should be
664bff34e3Sthurlow * just files and pipes (and not much more).
674bff34e3Sthurlow * It MAY be useful to provide some of the
684bff34e3Sthurlow * RAP (remote API) functions functions like
694bff34e3Sthurlow * rap_netshareenum below...
704bff34e3Sthurlow *
714bff34e3Sthurlow * XXX: Not sure this file belongs here at all.
724bff34e3Sthurlow * smb_rap.h looks like a reasonable API
734bff34e3Sthurlow * for this library to export.
744bff34e3Sthurlow */
754bff34e3Sthurlow #if 0 /* XXX */
764bff34e3Sthurlow
774bff34e3Sthurlow static int
784bff34e3Sthurlow rpc_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp,
794bff34e3Sthurlow struct share_info **entries_listp)
804bff34e3Sthurlow {
814bff34e3Sthurlow char ctx_string[2+16+1]; /* enough for 64-bit pointer, in hex */
824bff34e3Sthurlow unsigned_char_p_t binding;
834bff34e3Sthurlow unsigned32 binding_status;
844bff34e3Sthurlow rpc_binding_handle_t binding_h;
854bff34e3Sthurlow int error, i, entries;
864bff34e3Sthurlow char *addrstr, *srvnamestr;
874bff34e3Sthurlow unsigned short *usrvnamestr;
884bff34e3Sthurlow unsigned32 level;
894bff34e3Sthurlow SHARE_ENUM_STRUCT share_info;
904bff34e3Sthurlow SHARE_INFO_1_CONTAINER share_info_1_container;
914bff34e3Sthurlow SHARE_INFO_1 *shares, *share;
924bff34e3Sthurlow unsigned32 total_entries;
934bff34e3Sthurlow unsigned32 status, free_status;
944bff34e3Sthurlow struct share_info *entry_list, *elp;
954bff34e3Sthurlow static EXCEPTION rpc_x_connect_rejected;
964bff34e3Sthurlow static int exceptions_initialized;
974bff34e3Sthurlow
984bff34e3Sthurlow sprintf(ctx_string, "%p", ctx);
994bff34e3Sthurlow rpc_string_binding_compose(NULL, "ncacn_np", ctx_string,
1004bff34e3Sthurlow "srvsvc", NULL, &binding, &binding_status);
1014bff34e3Sthurlow if (binding_status != rpc_s_ok) {
1024bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN,
1034bff34e3Sthurlow "rpc_string_binding_compose failed with %d"),
1044bff34e3Sthurlow 0, binding_status);
1054bff34e3Sthurlow return (EINVAL);
1064bff34e3Sthurlow }
1074bff34e3Sthurlow rpc_binding_from_string_binding(binding, &binding_h, &status);
1089c9af259SGordon Ross rpc_string_free(&binding, (unsigned32 *)&free_status);
1094bff34e3Sthurlow if (binding_status != rpc_s_ok) {
1104bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN,
1114bff34e3Sthurlow "rpc_binding_from_string_binding failed with %d"), 0,
1124bff34e3Sthurlow binding_status);
1134bff34e3Sthurlow return (EINVAL);
1144bff34e3Sthurlow }
1154bff34e3Sthurlow level = 1;
1164bff34e3Sthurlow share_info.share_union.level = 1;
1174bff34e3Sthurlow share_info.share_union.tagged_union.share1 = &share_info_1_container;
1184bff34e3Sthurlow share_info_1_container.share_count = 0;
1194bff34e3Sthurlow share_info_1_container.shares = NULL;
1204bff34e3Sthurlow /*
1214bff34e3Sthurlow * Convert the server IP address to a string, and send that as
1224bff34e3Sthurlow * the "server name" - that's what Windows appears to do, and
1234bff34e3Sthurlow * that avoids problems with NetBIOS names containing
1244bff34e3Sthurlow * non-ASCII characters.
1254bff34e3Sthurlow */
1264bff34e3Sthurlow addrstr = inet_ntoa(ctx->ct_srvinaddr.sin_addr);
1274bff34e3Sthurlow srvnamestr = malloc(strlen(addrstr) + 3);
1284bff34e3Sthurlow if (srvnamestr == NULL) {
1294bff34e3Sthurlow status = errno;
1304bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN,
1314bff34e3Sthurlow "can't allocate string for server address"), status);
1324bff34e3Sthurlow rpc_binding_free(&binding_h, &free_status);
1334bff34e3Sthurlow return (status);
1344bff34e3Sthurlow }
1354bff34e3Sthurlow strcpy(srvnamestr, "\\\\");
1364bff34e3Sthurlow strcat(srvnamestr, addrstr);
1374bff34e3Sthurlow usrvnamestr = convert_utf8_to_leunicode(srvnamestr);
1384bff34e3Sthurlow if (usrvnamestr == NULL) {
1394bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN,
1404bff34e3Sthurlow "can't convert string for server address to Unicode"), 0);
1414bff34e3Sthurlow rpc_binding_free(&binding_h, &free_status);
1429c9af259SGordon Ross free(srvnamestr);
1434bff34e3Sthurlow return (EINVAL);
1444bff34e3Sthurlow }
1454bff34e3Sthurlow if (!exceptions_initialized) {
1464bff34e3Sthurlow EXCEPTION_INIT(rpc_x_connect_rejected);
1474bff34e3Sthurlow exc_set_status(&rpc_x_connect_rejected, rpc_s_connect_rejected);
1484bff34e3Sthurlow exceptions_initialized = 1;
1494bff34e3Sthurlow }
1504bff34e3Sthurlow /* printf("Calling NetrShareEnum.."); XXX */
1514bff34e3Sthurlow TRY
1524bff34e3Sthurlow status = NetrShareEnum(binding_h, usrvnamestr, &level,
1534bff34e3Sthurlow &share_info, 4294967295U, &total_entries, NULL);
1544bff34e3Sthurlow if (status != 0)
1554bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN,
1564bff34e3Sthurlow "error from NetrShareEnum call: status = 0x%08x"),
1574bff34e3Sthurlow 0, status);
1584bff34e3Sthurlow /*CSTYLED*/
1594bff34e3Sthurlow CATCH (rpc_x_connect_rejected)
1604bff34e3Sthurlow /*
1614bff34e3Sthurlow * This is what we get if we can't open the pipe.
1624bff34e3Sthurlow * That's a normal occurrence when we're talking
1634bff34e3Sthurlow * to a system that (presumably) doesn't support
1644bff34e3Sthurlow * DCE RPC on the server side, such as Windows 95/98/Me,
1654bff34e3Sthurlow * so we don't log an error.
1664bff34e3Sthurlow */
1674bff34e3Sthurlow /*CSTYLED*/
1684bff34e3Sthurlow status = ENOTSUP;
1694bff34e3Sthurlow CATCH_ALL
1704bff34e3Sthurlow /*
1714bff34e3Sthurlow * XXX - should we handle some exceptions differently,
1724bff34e3Sthurlow * returning different errors, and try RAP only for
1734bff34e3Sthurlow * ENOTSUP?
1744bff34e3Sthurlow */
1754bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN,
1764bff34e3Sthurlow "error from NetrShareEnum call: exception = %u"),
1774bff34e3Sthurlow 0, THIS_CATCH->match.value);
1784bff34e3Sthurlow status = ENOTSUP;
1794bff34e3Sthurlow ENDTRY
1804bff34e3Sthurlow rpc_binding_free(&binding_h, &free_status);
1814bff34e3Sthurlow free(srvnamestr);
1824bff34e3Sthurlow free(usrvnamestr);
1834bff34e3Sthurlow if (status != 0)
1844bff34e3Sthurlow return (ENOTSUP);
1854bff34e3Sthurlow
1864bff34e3Sthurlow /*
1874bff34e3Sthurlow * XXX - if the IDL is correct, it's not clear whether the
1884bff34e3Sthurlow * unmarshalling code will properly handle the case where
1894bff34e3Sthurlow * a packet where "share_count" and the max count for the
1904bff34e3Sthurlow * array of shares don't match; a valid DCE RPC implementation
1914bff34e3Sthurlow * won't marshal something like that, but there's no guarantee
1924bff34e3Sthurlow * that the server we're talking to has a valid implementation
1934bff34e3Sthurlow * (which could be a *malicious* implementation!).
1944bff34e3Sthurlow */
1954bff34e3Sthurlow entries = share_info.share_union.tagged_union.share1->share_count;
1964bff34e3Sthurlow shares = share_info.share_union.tagged_union.share1->shares;
1974bff34e3Sthurlow entry_list = calloc(entries, sizeof (struct share_info));
1984bff34e3Sthurlow if (entry_list == NULL) {
1994bff34e3Sthurlow error = errno;
2004bff34e3Sthurlow goto cleanup_and_return;
2014bff34e3Sthurlow }
2024bff34e3Sthurlow for (share = shares, elp = entry_list, i = 0; i < entries;
2034bff34e3Sthurlow i++, share++) {
2044bff34e3Sthurlow elp->type = share->shi1_type;
2054bff34e3Sthurlow elp->netname = convert_unicode_to_utf8(share->shi1_share);
2064bff34e3Sthurlow if (elp->netname == NULL)
2074bff34e3Sthurlow goto fail;
2084bff34e3Sthurlow elp->remark = convert_unicode_to_utf8(share->shi1_remark);
2094bff34e3Sthurlow if (elp->remark == NULL)
2104bff34e3Sthurlow goto fail;
2114bff34e3Sthurlow elp++;
2124bff34e3Sthurlow }
2134bff34e3Sthurlow *entriesp = entries;
2144bff34e3Sthurlow *totalp = total_entries;
2154bff34e3Sthurlow *entries_listp = entry_list;
2164bff34e3Sthurlow error = 0;
2174bff34e3Sthurlow goto cleanup_and_return;
2184bff34e3Sthurlow
2194bff34e3Sthurlow fail:
2204bff34e3Sthurlow error = errno;
2214bff34e3Sthurlow for (elp = entry_list, i = 0; i < entries; i++, elp++) {
2224bff34e3Sthurlow /*
2234bff34e3Sthurlow * elp->netname is set before elp->remark, so if
2244bff34e3Sthurlow * elp->netname is null, elp->remark is also null.
2254bff34e3Sthurlow * If either of them is null, we haven't done anything
2264bff34e3Sthurlow * to any entries after this one.
2274bff34e3Sthurlow */
2284bff34e3Sthurlow if (elp->netname == NULL)
2294bff34e3Sthurlow break;
2304bff34e3Sthurlow free(elp->netname);
2314bff34e3Sthurlow if (elp->remark == NULL)
2324bff34e3Sthurlow break;
2334bff34e3Sthurlow free(elp->remark);
2344bff34e3Sthurlow }
2354bff34e3Sthurlow free(entry_list);
2364bff34e3Sthurlow
2374bff34e3Sthurlow cleanup_and_return:
2384bff34e3Sthurlow for (share = shares, i = 0; i < entries; i++, share++) {
2394bff34e3Sthurlow free(share->shi1_share);
2404bff34e3Sthurlow free(share->shi1_remark);
2414bff34e3Sthurlow }
2424bff34e3Sthurlow free(shares);
2434bff34e3Sthurlow /*
2444bff34e3Sthurlow * XXX - "share1" should be a unique pointer, but we haven't
2454bff34e3Sthurlow * changed the marshalling code to support non-full pointers
2464bff34e3Sthurlow * in unions, so we leave it as a full pointer.
2474bff34e3Sthurlow *
2484bff34e3Sthurlow * That means that this might, or might not, be changed from
2494bff34e3Sthurlow * pointing to "share_info_1_container" to pointing to a
2504bff34e3Sthurlow * mallocated structure, according to the DCE RPC 1.1 IDL spec;
2514bff34e3Sthurlow * we free it only if it's changed.
2524bff34e3Sthurlow */
2534bff34e3Sthurlow if (share_info.share_union.tagged_union.share1 !=
2544bff34e3Sthurlow &share_info_1_container)
2554bff34e3Sthurlow free(share_info.share_union.tagged_union.share1);
2564bff34e3Sthurlow return (error);
2574bff34e3Sthurlow }
2584bff34e3Sthurlow #endif /* XXX */
2594bff34e3Sthurlow
2609c9af259SGordon Ross /*
2619c9af259SGordon Ross * Enumerate shares using RAP
2629c9af259SGordon Ross */
2639c9af259SGordon Ross
2649c9af259SGordon Ross struct smb_share_info_1 {
2659c9af259SGordon Ross char shi1_netname[13];
2669c9af259SGordon Ross char shi1_pad;
2679c9af259SGordon Ross uint16_t shi1_type;
2689c9af259SGordon Ross uint32_t shi1_remark; /* char * */
2699c9af259SGordon Ross };
2709c9af259SGordon Ross
2719c9af259SGordon Ross static int
smb_rap_NetShareEnum(struct smb_ctx * ctx,int sLevel,void * pbBuffer,int * cbBuffer,int * pcEntriesRead,int * pcTotalAvail)2729c9af259SGordon Ross smb_rap_NetShareEnum(struct smb_ctx *ctx, int sLevel, void *pbBuffer,
2739c9af259SGordon Ross int *cbBuffer, int *pcEntriesRead, int *pcTotalAvail)
2749c9af259SGordon Ross {
2759c9af259SGordon Ross struct smb_rap *rap;
2769c9af259SGordon Ross long lval = -1;
2779c9af259SGordon Ross int error;
2789c9af259SGordon Ross
2799c9af259SGordon Ross error = smb_rap_create(0, "WrLeh", "B13BWz", &rap);
2809c9af259SGordon Ross if (error)
2819c9af259SGordon Ross return (error);
28202d09e03SGordon Ross (void) smb_rap_setNparam(rap, sLevel); /* W - sLevel */
28302d09e03SGordon Ross (void) smb_rap_setPparam(rap, pbBuffer); /* r - pbBuffer */
28402d09e03SGordon Ross (void) smb_rap_setNparam(rap, *cbBuffer); /* L - cbBuffer */
2859c9af259SGordon Ross error = smb_rap_request(rap, ctx);
2869c9af259SGordon Ross if (error == 0) {
2879c9af259SGordon Ross *pcEntriesRead = rap->r_entries;
2889c9af259SGordon Ross error = smb_rap_getNparam(rap, &lval);
2899c9af259SGordon Ross *pcTotalAvail = lval;
2909c9af259SGordon Ross /* Copy the data length into the IN/OUT variable. */
2919c9af259SGordon Ross *cbBuffer = rap->r_rcvbuflen;
2929c9af259SGordon Ross }
2939c9af259SGordon Ross error = smb_rap_error(rap, error);
2949c9af259SGordon Ross smb_rap_done(rap);
2959c9af259SGordon Ross return (error);
2969c9af259SGordon Ross }
2979c9af259SGordon Ross
2984bff34e3Sthurlow static int
rap_netshareenum(struct smb_ctx * ctx,int * entriesp,int * totalp,struct share_info ** entries_listp)2994bff34e3Sthurlow rap_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp,
3004bff34e3Sthurlow struct share_info **entries_listp)
3014bff34e3Sthurlow {
3024bff34e3Sthurlow int error, bufsize, i, entries, total, nreturned;
3034bff34e3Sthurlow struct smb_share_info_1 *rpbuf, *ep;
3044bff34e3Sthurlow struct share_info *entry_list, *elp;
3054bff34e3Sthurlow char *cp;
3064bff34e3Sthurlow int lbound, rbound;
3074bff34e3Sthurlow
3084bff34e3Sthurlow bufsize = 0xffe0; /* samba notes win2k bug for 65535 */
3094bff34e3Sthurlow rpbuf = malloc(bufsize);
3104bff34e3Sthurlow if (rpbuf == NULL)
3114bff34e3Sthurlow return (errno);
3124bff34e3Sthurlow
3134bff34e3Sthurlow error = smb_rap_NetShareEnum(ctx, 1, rpbuf, &bufsize, &entries, &total);
3144bff34e3Sthurlow if (error &&
315*148c5f43SAlan Wright error != (ERROR_MORE_DATA | SMB_RAP_ERROR)) {
3164bff34e3Sthurlow free(rpbuf);
3174bff34e3Sthurlow return (error);
3184bff34e3Sthurlow }
3194bff34e3Sthurlow entry_list = malloc(entries * sizeof (struct share_info));
3204bff34e3Sthurlow if (entry_list == NULL) {
3214bff34e3Sthurlow error = errno;
3224bff34e3Sthurlow free(rpbuf);
3234bff34e3Sthurlow return (error);
3244bff34e3Sthurlow }
3254bff34e3Sthurlow lbound = entries * (sizeof (struct smb_share_info_1));
3264bff34e3Sthurlow rbound = bufsize;
3274bff34e3Sthurlow for (ep = rpbuf, elp = entry_list, i = 0, nreturned = 0; i < entries;
3284bff34e3Sthurlow i++, ep++) {
3294bff34e3Sthurlow elp->type = letohs(ep->shi1_type);
3304bff34e3Sthurlow ep->shi1_pad = '\0'; /* ensure null termination */
3314bff34e3Sthurlow elp->netname = convert_wincs_to_utf8(ep->shi1_netname);
3324bff34e3Sthurlow if (elp->netname == NULL)
3334bff34e3Sthurlow continue; /* punt on this entry */
3344bff34e3Sthurlow /*
3354bff34e3Sthurlow * Check for validity of offset.
3364bff34e3Sthurlow */
3374bff34e3Sthurlow if (ep->shi1_remark >= lbound && ep->shi1_remark < rbound) {
3384bff34e3Sthurlow cp = (char *)rpbuf + ep->shi1_remark;
3399c9af259SGordon Ross elp->remark = convert_wincs_to_utf8(cp);
3404bff34e3Sthurlow } else
3414bff34e3Sthurlow elp->remark = NULL;
3424bff34e3Sthurlow elp++;
3434bff34e3Sthurlow nreturned++;
3444bff34e3Sthurlow }
3454bff34e3Sthurlow *entriesp = nreturned;
3464bff34e3Sthurlow *totalp = total;
3474bff34e3Sthurlow *entries_listp = entry_list;
3484bff34e3Sthurlow free(rpbuf);
3494bff34e3Sthurlow return (0);
3504bff34e3Sthurlow }
3514bff34e3Sthurlow
3524bff34e3Sthurlow /*
3534bff34e3Sthurlow * First we try the RPC-based NetrShareEnum, and, if that fails, we fall
3544bff34e3Sthurlow * back on the RAP-based NetShareEnum.
3554bff34e3Sthurlow */
3564bff34e3Sthurlow int
smb_netshareenum(struct smb_ctx * ctx,int * entriesp,int * totalp,struct share_info ** entry_listp)3574bff34e3Sthurlow smb_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp,
3584bff34e3Sthurlow struct share_info **entry_listp)
3594bff34e3Sthurlow {
3604bff34e3Sthurlow int error;
3614bff34e3Sthurlow
3624bff34e3Sthurlow #ifdef NOTYETDEFINED
3634bff34e3Sthurlow /*
3644bff34e3Sthurlow * Try getting a list of shares with the SRVSVC RPC service.
3654bff34e3Sthurlow */
3664bff34e3Sthurlow error = rpc_netshareenum(ctx, entriesp, totalp, entry_listp);
3674bff34e3Sthurlow if (error == 0)
3684bff34e3Sthurlow return (0);
3694bff34e3Sthurlow #endif
3704bff34e3Sthurlow
3714bff34e3Sthurlow /*
3724bff34e3Sthurlow * OK, that didn't work - try RAP.
3734bff34e3Sthurlow * XXX - do so only if it failed because we couldn't open
3744bff34e3Sthurlow * the pipe?
3754bff34e3Sthurlow */
376613a2f6bSGordon Ross error = rap_netshareenum(ctx, entriesp, totalp, entry_listp);
377613a2f6bSGordon Ross return (error);
3784bff34e3Sthurlow }
379