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*10023SGordon.Ross@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 418271SGordon.Ross@Sun.COM * Use is subject to license terms. 428271SGordon.Ross@Sun.COM */ 436007Sthurlow 446007Sthurlow #include <stdlib.h> 456007Sthurlow #include <string.h> 466007Sthurlow #include <stdio.h> 476007Sthurlow #include <errno.h> 486007Sthurlow 496007Sthurlow #include <netsmb/mchain.h> 50*10023SGordon.Ross@Sun.COM #include <netsmb/smb.h> 516007Sthurlow #include <netsmb/smb_lib.h> 526007Sthurlow #include <netsmb/smb_rap.h> 536007Sthurlow #include <netsmb/smb_netshareenum.h> 548271SGordon.Ross@Sun.COM #include <smb/charsets.h> 556007Sthurlow 566007Sthurlow #if 0 /* XXX see below */ 576007Sthurlow #include <dce/exc_handling.h> 588271SGordon.Ross@Sun.COM #include <rpc/attrb.h> 596007Sthurlow #include "srvsvc.h" 606007Sthurlow #endif 616007Sthurlow 626007Sthurlow /* 636007Sthurlow * Don't want RPC client-side code in here. 646007Sthurlow * It's good code; just doesn't belong here. 656007Sthurlow * 666007Sthurlow * The API provided by this library should be 676007Sthurlow * just files and pipes (and not much more). 686007Sthurlow * It MAY be useful to provide some of the 696007Sthurlow * RAP (remote API) functions functions like 706007Sthurlow * rap_netshareenum below... 716007Sthurlow * 726007Sthurlow * XXX: Not sure this file belongs here at all. 736007Sthurlow * smb_rap.h looks like a reasonable API 746007Sthurlow * for this library to export. 756007Sthurlow */ 766007Sthurlow #if 0 /* XXX */ 776007Sthurlow 786007Sthurlow static int 796007Sthurlow rpc_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp, 806007Sthurlow struct share_info **entries_listp) 816007Sthurlow { 826007Sthurlow char ctx_string[2+16+1]; /* enough for 64-bit pointer, in hex */ 836007Sthurlow unsigned_char_p_t binding; 846007Sthurlow unsigned32 binding_status; 856007Sthurlow rpc_binding_handle_t binding_h; 866007Sthurlow int error, i, entries; 876007Sthurlow char *addrstr, *srvnamestr; 886007Sthurlow unsigned short *usrvnamestr; 896007Sthurlow unsigned32 level; 906007Sthurlow SHARE_ENUM_STRUCT share_info; 916007Sthurlow SHARE_INFO_1_CONTAINER share_info_1_container; 926007Sthurlow SHARE_INFO_1 *shares, *share; 936007Sthurlow unsigned32 total_entries; 946007Sthurlow unsigned32 status, free_status; 956007Sthurlow struct share_info *entry_list, *elp; 966007Sthurlow static EXCEPTION rpc_x_connect_rejected; 976007Sthurlow static int exceptions_initialized; 986007Sthurlow 996007Sthurlow sprintf(ctx_string, "%p", ctx); 1006007Sthurlow rpc_string_binding_compose(NULL, "ncacn_np", ctx_string, 1016007Sthurlow "srvsvc", NULL, &binding, &binding_status); 1026007Sthurlow if (binding_status != rpc_s_ok) { 1036007Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1046007Sthurlow "rpc_string_binding_compose failed with %d"), 1056007Sthurlow 0, binding_status); 1066007Sthurlow return (EINVAL); 1076007Sthurlow } 1086007Sthurlow rpc_binding_from_string_binding(binding, &binding_h, &status); 1098271SGordon.Ross@Sun.COM rpc_string_free(&binding, (unsigned32 *)&free_status); 1106007Sthurlow if (binding_status != rpc_s_ok) { 1116007Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1126007Sthurlow "rpc_binding_from_string_binding failed with %d"), 0, 1136007Sthurlow binding_status); 1146007Sthurlow return (EINVAL); 1156007Sthurlow } 1166007Sthurlow level = 1; 1176007Sthurlow share_info.share_union.level = 1; 1186007Sthurlow share_info.share_union.tagged_union.share1 = &share_info_1_container; 1196007Sthurlow share_info_1_container.share_count = 0; 1206007Sthurlow share_info_1_container.shares = NULL; 1216007Sthurlow /* 1226007Sthurlow * Convert the server IP address to a string, and send that as 1236007Sthurlow * the "server name" - that's what Windows appears to do, and 1246007Sthurlow * that avoids problems with NetBIOS names containing 1256007Sthurlow * non-ASCII characters. 1266007Sthurlow */ 1276007Sthurlow addrstr = inet_ntoa(ctx->ct_srvinaddr.sin_addr); 1286007Sthurlow srvnamestr = malloc(strlen(addrstr) + 3); 1296007Sthurlow if (srvnamestr == NULL) { 1306007Sthurlow status = errno; 1316007Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1326007Sthurlow "can't allocate string for server address"), status); 1336007Sthurlow rpc_binding_free(&binding_h, &free_status); 1346007Sthurlow return (status); 1356007Sthurlow } 1366007Sthurlow strcpy(srvnamestr, "\\\\"); 1376007Sthurlow strcat(srvnamestr, addrstr); 1386007Sthurlow usrvnamestr = convert_utf8_to_leunicode(srvnamestr); 1396007Sthurlow if (usrvnamestr == NULL) { 1406007Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1416007Sthurlow "can't convert string for server address to Unicode"), 0); 1426007Sthurlow rpc_binding_free(&binding_h, &free_status); 1438271SGordon.Ross@Sun.COM free(srvnamestr); 1446007Sthurlow return (EINVAL); 1456007Sthurlow } 1466007Sthurlow if (!exceptions_initialized) { 1476007Sthurlow EXCEPTION_INIT(rpc_x_connect_rejected); 1486007Sthurlow exc_set_status(&rpc_x_connect_rejected, rpc_s_connect_rejected); 1496007Sthurlow exceptions_initialized = 1; 1506007Sthurlow } 1516007Sthurlow /* printf("Calling NetrShareEnum.."); XXX */ 1526007Sthurlow TRY 1536007Sthurlow status = NetrShareEnum(binding_h, usrvnamestr, &level, 1546007Sthurlow &share_info, 4294967295U, &total_entries, NULL); 1556007Sthurlow if (status != 0) 1566007Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1576007Sthurlow "error from NetrShareEnum call: status = 0x%08x"), 1586007Sthurlow 0, status); 1596007Sthurlow /*CSTYLED*/ 1606007Sthurlow CATCH (rpc_x_connect_rejected) 1616007Sthurlow /* 1626007Sthurlow * This is what we get if we can't open the pipe. 1636007Sthurlow * That's a normal occurrence when we're talking 1646007Sthurlow * to a system that (presumably) doesn't support 1656007Sthurlow * DCE RPC on the server side, such as Windows 95/98/Me, 1666007Sthurlow * so we don't log an error. 1676007Sthurlow */ 1686007Sthurlow /*CSTYLED*/ 1696007Sthurlow status = ENOTSUP; 1706007Sthurlow CATCH_ALL 1716007Sthurlow /* 1726007Sthurlow * XXX - should we handle some exceptions differently, 1736007Sthurlow * returning different errors, and try RAP only for 1746007Sthurlow * ENOTSUP? 1756007Sthurlow */ 1766007Sthurlow smb_error(dgettext(TEXT_DOMAIN, 1776007Sthurlow "error from NetrShareEnum call: exception = %u"), 1786007Sthurlow 0, THIS_CATCH->match.value); 1796007Sthurlow status = ENOTSUP; 1806007Sthurlow ENDTRY 1816007Sthurlow rpc_binding_free(&binding_h, &free_status); 1826007Sthurlow free(srvnamestr); 1836007Sthurlow free(usrvnamestr); 1846007Sthurlow if (status != 0) 1856007Sthurlow return (ENOTSUP); 1866007Sthurlow 1876007Sthurlow /* 1886007Sthurlow * XXX - if the IDL is correct, it's not clear whether the 1896007Sthurlow * unmarshalling code will properly handle the case where 1906007Sthurlow * a packet where "share_count" and the max count for the 1916007Sthurlow * array of shares don't match; a valid DCE RPC implementation 1926007Sthurlow * won't marshal something like that, but there's no guarantee 1936007Sthurlow * that the server we're talking to has a valid implementation 1946007Sthurlow * (which could be a *malicious* implementation!). 1956007Sthurlow */ 1966007Sthurlow entries = share_info.share_union.tagged_union.share1->share_count; 1976007Sthurlow shares = share_info.share_union.tagged_union.share1->shares; 1986007Sthurlow entry_list = calloc(entries, sizeof (struct share_info)); 1996007Sthurlow if (entry_list == NULL) { 2006007Sthurlow error = errno; 2016007Sthurlow goto cleanup_and_return; 2026007Sthurlow } 2036007Sthurlow for (share = shares, elp = entry_list, i = 0; i < entries; 2046007Sthurlow i++, share++) { 2056007Sthurlow elp->type = share->shi1_type; 2066007Sthurlow elp->netname = convert_unicode_to_utf8(share->shi1_share); 2076007Sthurlow if (elp->netname == NULL) 2086007Sthurlow goto fail; 2096007Sthurlow elp->remark = convert_unicode_to_utf8(share->shi1_remark); 2106007Sthurlow if (elp->remark == NULL) 2116007Sthurlow goto fail; 2126007Sthurlow elp++; 2136007Sthurlow } 2146007Sthurlow *entriesp = entries; 2156007Sthurlow *totalp = total_entries; 2166007Sthurlow *entries_listp = entry_list; 2176007Sthurlow error = 0; 2186007Sthurlow goto cleanup_and_return; 2196007Sthurlow 2206007Sthurlow fail: 2216007Sthurlow error = errno; 2226007Sthurlow for (elp = entry_list, i = 0; i < entries; i++, elp++) { 2236007Sthurlow /* 2246007Sthurlow * elp->netname is set before elp->remark, so if 2256007Sthurlow * elp->netname is null, elp->remark is also null. 2266007Sthurlow * If either of them is null, we haven't done anything 2276007Sthurlow * to any entries after this one. 2286007Sthurlow */ 2296007Sthurlow if (elp->netname == NULL) 2306007Sthurlow break; 2316007Sthurlow free(elp->netname); 2326007Sthurlow if (elp->remark == NULL) 2336007Sthurlow break; 2346007Sthurlow free(elp->remark); 2356007Sthurlow } 2366007Sthurlow free(entry_list); 2376007Sthurlow 2386007Sthurlow cleanup_and_return: 2396007Sthurlow for (share = shares, i = 0; i < entries; i++, share++) { 2406007Sthurlow free(share->shi1_share); 2416007Sthurlow free(share->shi1_remark); 2426007Sthurlow } 2436007Sthurlow free(shares); 2446007Sthurlow /* 2456007Sthurlow * XXX - "share1" should be a unique pointer, but we haven't 2466007Sthurlow * changed the marshalling code to support non-full pointers 2476007Sthurlow * in unions, so we leave it as a full pointer. 2486007Sthurlow * 2496007Sthurlow * That means that this might, or might not, be changed from 2506007Sthurlow * pointing to "share_info_1_container" to pointing to a 2516007Sthurlow * mallocated structure, according to the DCE RPC 1.1 IDL spec; 2526007Sthurlow * we free it only if it's changed. 2536007Sthurlow */ 2546007Sthurlow if (share_info.share_union.tagged_union.share1 != 2556007Sthurlow &share_info_1_container) 2566007Sthurlow free(share_info.share_union.tagged_union.share1); 2576007Sthurlow return (error); 2586007Sthurlow } 2596007Sthurlow #endif /* XXX */ 2606007Sthurlow 2618271SGordon.Ross@Sun.COM /* 2628271SGordon.Ross@Sun.COM * Enumerate shares using RAP 2638271SGordon.Ross@Sun.COM */ 2648271SGordon.Ross@Sun.COM 2658271SGordon.Ross@Sun.COM struct smb_share_info_1 { 2668271SGordon.Ross@Sun.COM char shi1_netname[13]; 2678271SGordon.Ross@Sun.COM char shi1_pad; 2688271SGordon.Ross@Sun.COM uint16_t shi1_type; 2698271SGordon.Ross@Sun.COM uint32_t shi1_remark; /* char * */ 2708271SGordon.Ross@Sun.COM }; 2718271SGordon.Ross@Sun.COM 2728271SGordon.Ross@Sun.COM static int 2738271SGordon.Ross@Sun.COM smb_rap_NetShareEnum(struct smb_ctx *ctx, int sLevel, void *pbBuffer, 2748271SGordon.Ross@Sun.COM int *cbBuffer, int *pcEntriesRead, int *pcTotalAvail) 2758271SGordon.Ross@Sun.COM { 2768271SGordon.Ross@Sun.COM struct smb_rap *rap; 2778271SGordon.Ross@Sun.COM long lval = -1; 2788271SGordon.Ross@Sun.COM int error; 2798271SGordon.Ross@Sun.COM 2808271SGordon.Ross@Sun.COM error = smb_rap_create(0, "WrLeh", "B13BWz", &rap); 2818271SGordon.Ross@Sun.COM if (error) 2828271SGordon.Ross@Sun.COM return (error); 2838271SGordon.Ross@Sun.COM smb_rap_setNparam(rap, sLevel); /* W - sLevel */ 2848271SGordon.Ross@Sun.COM smb_rap_setPparam(rap, pbBuffer); /* r - pbBuffer */ 2858271SGordon.Ross@Sun.COM smb_rap_setNparam(rap, *cbBuffer); /* L - cbBuffer */ 2868271SGordon.Ross@Sun.COM error = smb_rap_request(rap, ctx); 2878271SGordon.Ross@Sun.COM if (error == 0) { 2888271SGordon.Ross@Sun.COM *pcEntriesRead = rap->r_entries; 2898271SGordon.Ross@Sun.COM error = smb_rap_getNparam(rap, &lval); 2908271SGordon.Ross@Sun.COM *pcTotalAvail = lval; 2918271SGordon.Ross@Sun.COM /* Copy the data length into the IN/OUT variable. */ 2928271SGordon.Ross@Sun.COM *cbBuffer = rap->r_rcvbuflen; 2938271SGordon.Ross@Sun.COM } 2948271SGordon.Ross@Sun.COM error = smb_rap_error(rap, error); 2958271SGordon.Ross@Sun.COM smb_rap_done(rap); 2968271SGordon.Ross@Sun.COM return (error); 2978271SGordon.Ross@Sun.COM } 2988271SGordon.Ross@Sun.COM 2996007Sthurlow static int 3006007Sthurlow rap_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp, 3016007Sthurlow struct share_info **entries_listp) 3026007Sthurlow { 3036007Sthurlow int error, bufsize, i, entries, total, nreturned; 3046007Sthurlow struct smb_share_info_1 *rpbuf, *ep; 3056007Sthurlow struct share_info *entry_list, *elp; 3066007Sthurlow char *cp; 3076007Sthurlow int lbound, rbound; 3086007Sthurlow 3096007Sthurlow bufsize = 0xffe0; /* samba notes win2k bug for 65535 */ 3106007Sthurlow rpbuf = malloc(bufsize); 3116007Sthurlow if (rpbuf == NULL) 3126007Sthurlow return (errno); 3136007Sthurlow 3146007Sthurlow error = smb_rap_NetShareEnum(ctx, 1, rpbuf, &bufsize, &entries, &total); 3156007Sthurlow if (error && 3166007Sthurlow error != (SMB_ERROR_MORE_DATA | SMB_RAP_ERROR)) { 3176007Sthurlow free(rpbuf); 3186007Sthurlow return (error); 3196007Sthurlow } 3206007Sthurlow entry_list = malloc(entries * sizeof (struct share_info)); 3216007Sthurlow if (entry_list == NULL) { 3226007Sthurlow error = errno; 3236007Sthurlow free(rpbuf); 3246007Sthurlow return (error); 3256007Sthurlow } 3266007Sthurlow lbound = entries * (sizeof (struct smb_share_info_1)); 3276007Sthurlow rbound = bufsize; 3286007Sthurlow for (ep = rpbuf, elp = entry_list, i = 0, nreturned = 0; i < entries; 3296007Sthurlow i++, ep++) { 3306007Sthurlow elp->type = letohs(ep->shi1_type); 3316007Sthurlow ep->shi1_pad = '\0'; /* ensure null termination */ 3326007Sthurlow elp->netname = convert_wincs_to_utf8(ep->shi1_netname); 3336007Sthurlow if (elp->netname == NULL) 3346007Sthurlow continue; /* punt on this entry */ 3356007Sthurlow /* 3366007Sthurlow * Check for validity of offset. 3376007Sthurlow */ 3386007Sthurlow if (ep->shi1_remark >= lbound && ep->shi1_remark < rbound) { 3396007Sthurlow cp = (char *)rpbuf + ep->shi1_remark; 3408271SGordon.Ross@Sun.COM elp->remark = convert_wincs_to_utf8(cp); 3416007Sthurlow } else 3426007Sthurlow elp->remark = NULL; 3436007Sthurlow elp++; 3446007Sthurlow nreturned++; 3456007Sthurlow } 3466007Sthurlow *entriesp = nreturned; 3476007Sthurlow *totalp = total; 3486007Sthurlow *entries_listp = entry_list; 3496007Sthurlow free(rpbuf); 3506007Sthurlow return (0); 3516007Sthurlow } 3526007Sthurlow 3536007Sthurlow /* 3546007Sthurlow * First we try the RPC-based NetrShareEnum, and, if that fails, we fall 3556007Sthurlow * back on the RAP-based NetShareEnum. 3566007Sthurlow */ 3576007Sthurlow int 3586007Sthurlow smb_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp, 3596007Sthurlow struct share_info **entry_listp) 3606007Sthurlow { 3616007Sthurlow int error; 3626007Sthurlow 3636007Sthurlow #ifdef NOTYETDEFINED 3646007Sthurlow /* 3656007Sthurlow * Try getting a list of shares with the SRVSVC RPC service. 3666007Sthurlow */ 3676007Sthurlow error = rpc_netshareenum(ctx, entriesp, totalp, entry_listp); 3686007Sthurlow if (error == 0) 3696007Sthurlow return (0); 3706007Sthurlow #endif 3716007Sthurlow 3726007Sthurlow /* 3736007Sthurlow * OK, that didn't work - try RAP. 3746007Sthurlow * XXX - do so only if it failed because we couldn't open 3756007Sthurlow * the pipe? 3766007Sthurlow */ 377*10023SGordon.Ross@Sun.COM error = rap_netshareenum(ctx, entriesp, totalp, entry_listp); 378*10023SGordon.Ross@Sun.COM return (error); 3796007Sthurlow } 380