1*4bff34e3Sthurlow /* 2*4bff34e3Sthurlow * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. 3*4bff34e3Sthurlow * 4*4bff34e3Sthurlow * @APPLE_LICENSE_HEADER_START@ 5*4bff34e3Sthurlow * 6*4bff34e3Sthurlow * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights 7*4bff34e3Sthurlow * Reserved. This file contains Original Code and/or Modifications of 8*4bff34e3Sthurlow * Original Code as defined in and that are subject to the Apple Public 9*4bff34e3Sthurlow * Source License Version 1.0 (the 'License'). You may not use this file 10*4bff34e3Sthurlow * except in compliance with the License. Please obtain a copy of the 11*4bff34e3Sthurlow * License at http://www.apple.com/publicsource and read it before using 12*4bff34e3Sthurlow * this file. 13*4bff34e3Sthurlow * 14*4bff34e3Sthurlow * The Original Code and all software distributed under the License are 15*4bff34e3Sthurlow * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16*4bff34e3Sthurlow * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17*4bff34e3Sthurlow * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18*4bff34e3Sthurlow * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 19*4bff34e3Sthurlow * License for the specific language governing rights and limitations 20*4bff34e3Sthurlow * under the License." 21*4bff34e3Sthurlow * 22*4bff34e3Sthurlow * @APPLE_LICENSE_HEADER_END@ 23*4bff34e3Sthurlow */ 24*4bff34e3Sthurlow 25*4bff34e3Sthurlow /* BEGIN CSTYLED */ 26*4bff34e3Sthurlow /* 27*4bff34e3Sthurlow * @(#)ui.c * 28*4bff34e3Sthurlow * (c) 2004 Apple Computer, Inc. All Rights Reserved 29*4bff34e3Sthurlow * 30*4bff34e3Sthurlow * 31*4bff34e3Sthurlow * netshareenum.c -- Routines for getting a list of share information 32*4bff34e3Sthurlow * from a server. 33*4bff34e3Sthurlow * 34*4bff34e3Sthurlow * MODIFICATION HISTORY: 35*4bff34e3Sthurlow * 27-Nov-2004 Guy Harris New today 36*4bff34e3Sthurlow */ 37*4bff34e3Sthurlow /* END CSTYLED */ 38*4bff34e3Sthurlow 39*4bff34e3Sthurlow #pragma ident "%Z%%M% %I% %E% SMI" 40*4bff34e3Sthurlow 41*4bff34e3Sthurlow #include <stdlib.h> 42*4bff34e3Sthurlow #include <string.h> 43*4bff34e3Sthurlow #include <stdio.h> 44*4bff34e3Sthurlow #include <errno.h> 45*4bff34e3Sthurlow 46*4bff34e3Sthurlow #include <netsmb/mchain.h> 47*4bff34e3Sthurlow #include <netsmb/smb_lib.h> 48*4bff34e3Sthurlow #include <netsmb/smb_rap.h> 49*4bff34e3Sthurlow #include <netsmb/smb_netshareenum.h> 50*4bff34e3Sthurlow #include "charsets.h" 51*4bff34e3Sthurlow 52*4bff34e3Sthurlow #if 0 /* XXX see below */ 53*4bff34e3Sthurlow #include <dce/exc_handling.h> 54*4bff34e3Sthurlow #include <attrb.h> 55*4bff34e3Sthurlow #include "srvsvc.h" 56*4bff34e3Sthurlow #endif 57*4bff34e3Sthurlow 58*4bff34e3Sthurlow /* 59*4bff34e3Sthurlow * Don't want RPC client-side code in here. 60*4bff34e3Sthurlow * It's good code; just doesn't belong here. 61*4bff34e3Sthurlow * 62*4bff34e3Sthurlow * The API provided by this library should be 63*4bff34e3Sthurlow * just files and pipes (and not much more). 64*4bff34e3Sthurlow * It MAY be useful to provide some of the 65*4bff34e3Sthurlow * RAP (remote API) functions functions like 66*4bff34e3Sthurlow * rap_netshareenum below... 67*4bff34e3Sthurlow * 68*4bff34e3Sthurlow * XXX: Not sure this file belongs here at all. 69*4bff34e3Sthurlow * smb_rap.h looks like a reasonable API 70*4bff34e3Sthurlow * for this library to export. 71*4bff34e3Sthurlow */ 72*4bff34e3Sthurlow #if 0 /* XXX */ 73*4bff34e3Sthurlow 74*4bff34e3Sthurlow static int 75*4bff34e3Sthurlow rpc_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp, 76*4bff34e3Sthurlow struct share_info **entries_listp) 77*4bff34e3Sthurlow { 78*4bff34e3Sthurlow char ctx_string[2+16+1]; /* enough for 64-bit pointer, in hex */ 79*4bff34e3Sthurlow unsigned_char_p_t binding; 80*4bff34e3Sthurlow unsigned32 binding_status; 81*4bff34e3Sthurlow rpc_binding_handle_t binding_h; 82*4bff34e3Sthurlow int error, i, entries; 83*4bff34e3Sthurlow char *addrstr, *srvnamestr; 84*4bff34e3Sthurlow unsigned short *usrvnamestr; 85*4bff34e3Sthurlow unsigned32 level; 86*4bff34e3Sthurlow SHARE_ENUM_STRUCT share_info; 87*4bff34e3Sthurlow SHARE_INFO_1_CONTAINER share_info_1_container; 88*4bff34e3Sthurlow SHARE_INFO_1 *shares, *share; 89*4bff34e3Sthurlow unsigned32 total_entries; 90*4bff34e3Sthurlow unsigned32 status, free_status; 91*4bff34e3Sthurlow struct share_info *entry_list, *elp; 92*4bff34e3Sthurlow static EXCEPTION rpc_x_connect_rejected; 93*4bff34e3Sthurlow static int exceptions_initialized; 94*4bff34e3Sthurlow 95*4bff34e3Sthurlow sprintf(ctx_string, "%p", ctx); 96*4bff34e3Sthurlow rpc_string_binding_compose(NULL, "ncacn_np", ctx_string, 97*4bff34e3Sthurlow "srvsvc", NULL, &binding, &binding_status); 98*4bff34e3Sthurlow if (binding_status != rpc_s_ok) { 99*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 100*4bff34e3Sthurlow "rpc_string_binding_compose failed with %d"), 101*4bff34e3Sthurlow 0, binding_status); 102*4bff34e3Sthurlow return (EINVAL); 103*4bff34e3Sthurlow } 104*4bff34e3Sthurlow rpc_binding_from_string_binding(binding, &binding_h, &status); 105*4bff34e3Sthurlow if (binding_status != rpc_s_ok) { 106*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 107*4bff34e3Sthurlow "rpc_binding_from_string_binding failed with %d"), 0, 108*4bff34e3Sthurlow binding_status); 109*4bff34e3Sthurlow return (EINVAL); 110*4bff34e3Sthurlow } 111*4bff34e3Sthurlow level = 1; 112*4bff34e3Sthurlow share_info.share_union.level = 1; 113*4bff34e3Sthurlow share_info.share_union.tagged_union.share1 = &share_info_1_container; 114*4bff34e3Sthurlow share_info_1_container.share_count = 0; 115*4bff34e3Sthurlow share_info_1_container.shares = NULL; 116*4bff34e3Sthurlow /* 117*4bff34e3Sthurlow * Convert the server IP address to a string, and send that as 118*4bff34e3Sthurlow * the "server name" - that's what Windows appears to do, and 119*4bff34e3Sthurlow * that avoids problems with NetBIOS names containing 120*4bff34e3Sthurlow * non-ASCII characters. 121*4bff34e3Sthurlow */ 122*4bff34e3Sthurlow addrstr = inet_ntoa(ctx->ct_srvinaddr.sin_addr); 123*4bff34e3Sthurlow srvnamestr = malloc(strlen(addrstr) + 3); 124*4bff34e3Sthurlow if (srvnamestr == NULL) { 125*4bff34e3Sthurlow status = errno; 126*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 127*4bff34e3Sthurlow "can't allocate string for server address"), status); 128*4bff34e3Sthurlow rpc_binding_free(&binding_h, &free_status); 129*4bff34e3Sthurlow return (status); 130*4bff34e3Sthurlow } 131*4bff34e3Sthurlow strcpy(srvnamestr, "\\\\"); 132*4bff34e3Sthurlow strcat(srvnamestr, addrstr); 133*4bff34e3Sthurlow #ifdef NOTYETDEFINED 134*4bff34e3Sthurlow usrvnamestr = convert_utf8_to_leunicode(srvnamestr); 135*4bff34e3Sthurlow #endif 136*4bff34e3Sthurlow usrvnamestr = srvnamestr; 137*4bff34e3Sthurlow if (usrvnamestr == NULL) { 138*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 139*4bff34e3Sthurlow "can't convert string for server address to Unicode"), 0); 140*4bff34e3Sthurlow rpc_binding_free(&binding_h, &free_status); 141*4bff34e3Sthurlow return (EINVAL); 142*4bff34e3Sthurlow } 143*4bff34e3Sthurlow if (!exceptions_initialized) { 144*4bff34e3Sthurlow EXCEPTION_INIT(rpc_x_connect_rejected); 145*4bff34e3Sthurlow exc_set_status(&rpc_x_connect_rejected, rpc_s_connect_rejected); 146*4bff34e3Sthurlow exceptions_initialized = 1; 147*4bff34e3Sthurlow } 148*4bff34e3Sthurlow /* printf("Calling NetrShareEnum.."); XXX */ 149*4bff34e3Sthurlow TRY 150*4bff34e3Sthurlow status = NetrShareEnum(binding_h, usrvnamestr, &level, 151*4bff34e3Sthurlow &share_info, 4294967295U, &total_entries, NULL); 152*4bff34e3Sthurlow if (status != 0) 153*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 154*4bff34e3Sthurlow "error from NetrShareEnum call: status = 0x%08x"), 155*4bff34e3Sthurlow 0, status); 156*4bff34e3Sthurlow /*CSTYLED*/ 157*4bff34e3Sthurlow CATCH (rpc_x_connect_rejected) 158*4bff34e3Sthurlow /* 159*4bff34e3Sthurlow * This is what we get if we can't open the pipe. 160*4bff34e3Sthurlow * That's a normal occurrence when we're talking 161*4bff34e3Sthurlow * to a system that (presumably) doesn't support 162*4bff34e3Sthurlow * DCE RPC on the server side, such as Windows 95/98/Me, 163*4bff34e3Sthurlow * so we don't log an error. 164*4bff34e3Sthurlow */ 165*4bff34e3Sthurlow /*CSTYLED*/ 166*4bff34e3Sthurlow status = ENOTSUP; 167*4bff34e3Sthurlow CATCH_ALL 168*4bff34e3Sthurlow /* 169*4bff34e3Sthurlow * XXX - should we handle some exceptions differently, 170*4bff34e3Sthurlow * returning different errors, and try RAP only for 171*4bff34e3Sthurlow * ENOTSUP? 172*4bff34e3Sthurlow */ 173*4bff34e3Sthurlow smb_error(dgettext(TEXT_DOMAIN, 174*4bff34e3Sthurlow "error from NetrShareEnum call: exception = %u"), 175*4bff34e3Sthurlow 0, THIS_CATCH->match.value); 176*4bff34e3Sthurlow status = ENOTSUP; 177*4bff34e3Sthurlow ENDTRY 178*4bff34e3Sthurlow rpc_binding_free(&binding_h, &free_status); 179*4bff34e3Sthurlow free(srvnamestr); 180*4bff34e3Sthurlow free(usrvnamestr); 181*4bff34e3Sthurlow if (status != 0) 182*4bff34e3Sthurlow return (ENOTSUP); 183*4bff34e3Sthurlow 184*4bff34e3Sthurlow /* 185*4bff34e3Sthurlow * XXX - if the IDL is correct, it's not clear whether the 186*4bff34e3Sthurlow * unmarshalling code will properly handle the case where 187*4bff34e3Sthurlow * a packet where "share_count" and the max count for the 188*4bff34e3Sthurlow * array of shares don't match; a valid DCE RPC implementation 189*4bff34e3Sthurlow * won't marshal something like that, but there's no guarantee 190*4bff34e3Sthurlow * that the server we're talking to has a valid implementation 191*4bff34e3Sthurlow * (which could be a *malicious* implementation!). 192*4bff34e3Sthurlow */ 193*4bff34e3Sthurlow entries = share_info.share_union.tagged_union.share1->share_count; 194*4bff34e3Sthurlow shares = share_info.share_union.tagged_union.share1->shares; 195*4bff34e3Sthurlow entry_list = calloc(entries, sizeof (struct share_info)); 196*4bff34e3Sthurlow if (entry_list == NULL) { 197*4bff34e3Sthurlow error = errno; 198*4bff34e3Sthurlow goto cleanup_and_return; 199*4bff34e3Sthurlow } 200*4bff34e3Sthurlow for (share = shares, elp = entry_list, i = 0; i < entries; 201*4bff34e3Sthurlow i++, share++) { 202*4bff34e3Sthurlow elp->type = share->shi1_type; 203*4bff34e3Sthurlow #ifdef NOTYETDEFINED 204*4bff34e3Sthurlow elp->netname = convert_unicode_to_utf8(share->shi1_share); 205*4bff34e3Sthurlow #endif 206*4bff34e3Sthurlow elp->netname = share->shi1_share; 207*4bff34e3Sthurlow if (elp->netname == NULL) 208*4bff34e3Sthurlow goto fail; 209*4bff34e3Sthurlow #ifdef NOTYETDEFINED 210*4bff34e3Sthurlow elp->remark = convert_unicode_to_utf8(share->shi1_remark); 211*4bff34e3Sthurlow #endif 212*4bff34e3Sthurlow elp->remark = share->shi1_remark; 213*4bff34e3Sthurlow if (elp->remark == NULL) 214*4bff34e3Sthurlow goto fail; 215*4bff34e3Sthurlow elp++; 216*4bff34e3Sthurlow } 217*4bff34e3Sthurlow *entriesp = entries; 218*4bff34e3Sthurlow *totalp = total_entries; 219*4bff34e3Sthurlow *entries_listp = entry_list; 220*4bff34e3Sthurlow error = 0; 221*4bff34e3Sthurlow goto cleanup_and_return; 222*4bff34e3Sthurlow 223*4bff34e3Sthurlow fail: 224*4bff34e3Sthurlow error = errno; 225*4bff34e3Sthurlow for (elp = entry_list, i = 0; i < entries; i++, elp++) { 226*4bff34e3Sthurlow /* 227*4bff34e3Sthurlow * elp->netname is set before elp->remark, so if 228*4bff34e3Sthurlow * elp->netname is null, elp->remark is also null. 229*4bff34e3Sthurlow * If either of them is null, we haven't done anything 230*4bff34e3Sthurlow * to any entries after this one. 231*4bff34e3Sthurlow */ 232*4bff34e3Sthurlow if (elp->netname == NULL) 233*4bff34e3Sthurlow break; 234*4bff34e3Sthurlow free(elp->netname); 235*4bff34e3Sthurlow if (elp->remark == NULL) 236*4bff34e3Sthurlow break; 237*4bff34e3Sthurlow free(elp->remark); 238*4bff34e3Sthurlow } 239*4bff34e3Sthurlow free(entry_list); 240*4bff34e3Sthurlow 241*4bff34e3Sthurlow cleanup_and_return: 242*4bff34e3Sthurlow for (share = shares, i = 0; i < entries; i++, share++) { 243*4bff34e3Sthurlow free(share->shi1_share); 244*4bff34e3Sthurlow free(share->shi1_remark); 245*4bff34e3Sthurlow } 246*4bff34e3Sthurlow free(shares); 247*4bff34e3Sthurlow /* 248*4bff34e3Sthurlow * XXX - "share1" should be a unique pointer, but we haven't 249*4bff34e3Sthurlow * changed the marshalling code to support non-full pointers 250*4bff34e3Sthurlow * in unions, so we leave it as a full pointer. 251*4bff34e3Sthurlow * 252*4bff34e3Sthurlow * That means that this might, or might not, be changed from 253*4bff34e3Sthurlow * pointing to "share_info_1_container" to pointing to a 254*4bff34e3Sthurlow * mallocated structure, according to the DCE RPC 1.1 IDL spec; 255*4bff34e3Sthurlow * we free it only if it's changed. 256*4bff34e3Sthurlow */ 257*4bff34e3Sthurlow if (share_info.share_union.tagged_union.share1 != 258*4bff34e3Sthurlow &share_info_1_container) 259*4bff34e3Sthurlow free(share_info.share_union.tagged_union.share1); 260*4bff34e3Sthurlow return (error); 261*4bff34e3Sthurlow } 262*4bff34e3Sthurlow #endif /* XXX */ 263*4bff34e3Sthurlow 264*4bff34e3Sthurlow static int 265*4bff34e3Sthurlow rap_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp, 266*4bff34e3Sthurlow struct share_info **entries_listp) 267*4bff34e3Sthurlow { 268*4bff34e3Sthurlow int error, bufsize, i, entries, total, nreturned; 269*4bff34e3Sthurlow struct smb_share_info_1 *rpbuf, *ep; 270*4bff34e3Sthurlow struct share_info *entry_list, *elp; 271*4bff34e3Sthurlow char *cp; 272*4bff34e3Sthurlow int lbound, rbound; 273*4bff34e3Sthurlow 274*4bff34e3Sthurlow bufsize = 0xffe0; /* samba notes win2k bug for 65535 */ 275*4bff34e3Sthurlow rpbuf = malloc(bufsize); 276*4bff34e3Sthurlow if (rpbuf == NULL) 277*4bff34e3Sthurlow return (errno); 278*4bff34e3Sthurlow 279*4bff34e3Sthurlow error = smb_rap_NetShareEnum(ctx, 1, rpbuf, &bufsize, &entries, &total); 280*4bff34e3Sthurlow if (error && 281*4bff34e3Sthurlow error != (SMB_ERROR_MORE_DATA | SMB_RAP_ERROR)) { 282*4bff34e3Sthurlow free(rpbuf); 283*4bff34e3Sthurlow return (error); 284*4bff34e3Sthurlow } 285*4bff34e3Sthurlow entry_list = malloc(entries * sizeof (struct share_info)); 286*4bff34e3Sthurlow if (entry_list == NULL) { 287*4bff34e3Sthurlow error = errno; 288*4bff34e3Sthurlow free(rpbuf); 289*4bff34e3Sthurlow return (error); 290*4bff34e3Sthurlow } 291*4bff34e3Sthurlow lbound = entries * (sizeof (struct smb_share_info_1)); 292*4bff34e3Sthurlow rbound = bufsize; 293*4bff34e3Sthurlow for (ep = rpbuf, elp = entry_list, i = 0, nreturned = 0; i < entries; 294*4bff34e3Sthurlow i++, ep++) { 295*4bff34e3Sthurlow elp->type = letohs(ep->shi1_type); 296*4bff34e3Sthurlow ep->shi1_pad = '\0'; /* ensure null termination */ 297*4bff34e3Sthurlow elp->netname = strdup(ep->shi1_netname); 298*4bff34e3Sthurlow #ifdef NOTYETDEFINED 299*4bff34e3Sthurlow elp->netname = convert_wincs_to_utf8(ep->shi1_netname); 300*4bff34e3Sthurlow #endif 301*4bff34e3Sthurlow if (elp->netname == NULL) 302*4bff34e3Sthurlow continue; /* punt on this entry */ 303*4bff34e3Sthurlow /* 304*4bff34e3Sthurlow * Check for validity of offset. 305*4bff34e3Sthurlow */ 306*4bff34e3Sthurlow if (ep->shi1_remark >= lbound && ep->shi1_remark < rbound) { 307*4bff34e3Sthurlow cp = (char *)rpbuf + ep->shi1_remark; 308*4bff34e3Sthurlow elp->remark = cp; 309*4bff34e3Sthurlow #ifdef NOTYETDEFINED 310*4bff34e3Sthurlow elp->remark = nls_str_toloc(cp, cp); 311*4bff34e3Sthurlow #endif 312*4bff34e3Sthurlow } else 313*4bff34e3Sthurlow elp->remark = NULL; 314*4bff34e3Sthurlow elp++; 315*4bff34e3Sthurlow nreturned++; 316*4bff34e3Sthurlow } 317*4bff34e3Sthurlow *entriesp = nreturned; 318*4bff34e3Sthurlow *totalp = total; 319*4bff34e3Sthurlow *entries_listp = entry_list; 320*4bff34e3Sthurlow free(rpbuf); 321*4bff34e3Sthurlow return (0); 322*4bff34e3Sthurlow } 323*4bff34e3Sthurlow 324*4bff34e3Sthurlow /* 325*4bff34e3Sthurlow * First we try the RPC-based NetrShareEnum, and, if that fails, we fall 326*4bff34e3Sthurlow * back on the RAP-based NetShareEnum. 327*4bff34e3Sthurlow */ 328*4bff34e3Sthurlow int 329*4bff34e3Sthurlow smb_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp, 330*4bff34e3Sthurlow struct share_info **entry_listp) 331*4bff34e3Sthurlow { 332*4bff34e3Sthurlow int error; 333*4bff34e3Sthurlow 334*4bff34e3Sthurlow #ifdef NOTYETDEFINED 335*4bff34e3Sthurlow /* 336*4bff34e3Sthurlow * Try getting a list of shares with the SRVSVC RPC service. 337*4bff34e3Sthurlow */ 338*4bff34e3Sthurlow error = rpc_netshareenum(ctx, entriesp, totalp, entry_listp); 339*4bff34e3Sthurlow if (error == 0) 340*4bff34e3Sthurlow return (0); 341*4bff34e3Sthurlow #endif 342*4bff34e3Sthurlow 343*4bff34e3Sthurlow /* 344*4bff34e3Sthurlow * OK, that didn't work - try RAP. 345*4bff34e3Sthurlow * XXX - do so only if it failed because we couldn't open 346*4bff34e3Sthurlow * the pipe? 347*4bff34e3Sthurlow */ 348*4bff34e3Sthurlow return (rap_netshareenum(ctx, entriesp, totalp, entry_listp)); 349*4bff34e3Sthurlow } 350