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 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 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 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