diff options
author | thurlow <none@none> | 2008-02-13 19:51:22 -0800 |
---|---|---|
committer | thurlow <none@none> | 2008-02-13 19:51:22 -0800 |
commit | 4bff34e37def8a90f9194d81bc345c52ba20086a (patch) | |
tree | 7bf2710d9da099e3b07fea38e12788bfd565f3c5 /usr/src/lib/libsmbfs/smb/netshareenum.c | |
parent | a916d99c7b27a531bf37c57f83b0b74120fd05bb (diff) | |
download | illumos-joyent-4bff34e37def8a90f9194d81bc345c52ba20086a.tar.gz |
PSARC 2005/695 CIFS Client on Solaris
PSARC 2007/303 pam_smb_login
PSARC 2008/073 CIFS Client on Solaris - Updates
6651904 CIFS Client - PSARC 2005/695
Diffstat (limited to 'usr/src/lib/libsmbfs/smb/netshareenum.c')
-rw-r--r-- | usr/src/lib/libsmbfs/smb/netshareenum.c | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/usr/src/lib/libsmbfs/smb/netshareenum.c b/usr/src/lib/libsmbfs/smb/netshareenum.c new file mode 100644 index 0000000000..4da5fd17a2 --- /dev/null +++ b/usr/src/lib/libsmbfs/smb/netshareenum.c @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.0 (the 'License'). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License." + * + * @APPLE_LICENSE_HEADER_END@ + */ + +/* BEGIN CSTYLED */ +/* + * @(#)ui.c * + * (c) 2004 Apple Computer, Inc. All Rights Reserved + * + * + * netshareenum.c -- Routines for getting a list of share information + * from a server. + * + * MODIFICATION HISTORY: + * 27-Nov-2004 Guy Harris New today + */ +/* END CSTYLED */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> + +#include <netsmb/mchain.h> +#include <netsmb/smb_lib.h> +#include <netsmb/smb_rap.h> +#include <netsmb/smb_netshareenum.h> +#include "charsets.h" + +#if 0 /* XXX see below */ +#include <dce/exc_handling.h> +#include <attrb.h> +#include "srvsvc.h" +#endif + +/* + * Don't want RPC client-side code in here. + * It's good code; just doesn't belong here. + * + * The API provided by this library should be + * just files and pipes (and not much more). + * It MAY be useful to provide some of the + * RAP (remote API) functions functions like + * rap_netshareenum below... + * + * XXX: Not sure this file belongs here at all. + * smb_rap.h looks like a reasonable API + * for this library to export. + */ +#if 0 /* XXX */ + +static int +rpc_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp, + struct share_info **entries_listp) +{ + char ctx_string[2+16+1]; /* enough for 64-bit pointer, in hex */ + unsigned_char_p_t binding; + unsigned32 binding_status; + rpc_binding_handle_t binding_h; + int error, i, entries; + char *addrstr, *srvnamestr; + unsigned short *usrvnamestr; + unsigned32 level; + SHARE_ENUM_STRUCT share_info; + SHARE_INFO_1_CONTAINER share_info_1_container; + SHARE_INFO_1 *shares, *share; + unsigned32 total_entries; + unsigned32 status, free_status; + struct share_info *entry_list, *elp; + static EXCEPTION rpc_x_connect_rejected; + static int exceptions_initialized; + + sprintf(ctx_string, "%p", ctx); + rpc_string_binding_compose(NULL, "ncacn_np", ctx_string, + "srvsvc", NULL, &binding, &binding_status); + if (binding_status != rpc_s_ok) { + smb_error(dgettext(TEXT_DOMAIN, + "rpc_string_binding_compose failed with %d"), + 0, binding_status); + return (EINVAL); + } + rpc_binding_from_string_binding(binding, &binding_h, &status); + if (binding_status != rpc_s_ok) { + smb_error(dgettext(TEXT_DOMAIN, + "rpc_binding_from_string_binding failed with %d"), 0, + binding_status); + return (EINVAL); + } + level = 1; + share_info.share_union.level = 1; + share_info.share_union.tagged_union.share1 = &share_info_1_container; + share_info_1_container.share_count = 0; + share_info_1_container.shares = NULL; + /* + * Convert the server IP address to a string, and send that as + * the "server name" - that's what Windows appears to do, and + * that avoids problems with NetBIOS names containing + * non-ASCII characters. + */ + addrstr = inet_ntoa(ctx->ct_srvinaddr.sin_addr); + srvnamestr = malloc(strlen(addrstr) + 3); + if (srvnamestr == NULL) { + status = errno; + smb_error(dgettext(TEXT_DOMAIN, + "can't allocate string for server address"), status); + rpc_binding_free(&binding_h, &free_status); + return (status); + } + strcpy(srvnamestr, "\\\\"); + strcat(srvnamestr, addrstr); +#ifdef NOTYETDEFINED + usrvnamestr = convert_utf8_to_leunicode(srvnamestr); +#endif + usrvnamestr = srvnamestr; + if (usrvnamestr == NULL) { + smb_error(dgettext(TEXT_DOMAIN, + "can't convert string for server address to Unicode"), 0); + rpc_binding_free(&binding_h, &free_status); + return (EINVAL); + } + if (!exceptions_initialized) { + EXCEPTION_INIT(rpc_x_connect_rejected); + exc_set_status(&rpc_x_connect_rejected, rpc_s_connect_rejected); + exceptions_initialized = 1; + } + /* printf("Calling NetrShareEnum.."); XXX */ + TRY + status = NetrShareEnum(binding_h, usrvnamestr, &level, + &share_info, 4294967295U, &total_entries, NULL); + if (status != 0) + smb_error(dgettext(TEXT_DOMAIN, + "error from NetrShareEnum call: status = 0x%08x"), + 0, status); + /*CSTYLED*/ + CATCH (rpc_x_connect_rejected) + /* + * This is what we get if we can't open the pipe. + * That's a normal occurrence when we're talking + * to a system that (presumably) doesn't support + * DCE RPC on the server side, such as Windows 95/98/Me, + * so we don't log an error. + */ + /*CSTYLED*/ + status = ENOTSUP; + CATCH_ALL + /* + * XXX - should we handle some exceptions differently, + * returning different errors, and try RAP only for + * ENOTSUP? + */ + smb_error(dgettext(TEXT_DOMAIN, + "error from NetrShareEnum call: exception = %u"), + 0, THIS_CATCH->match.value); + status = ENOTSUP; + ENDTRY + rpc_binding_free(&binding_h, &free_status); + free(srvnamestr); + free(usrvnamestr); + if (status != 0) + return (ENOTSUP); + + /* + * XXX - if the IDL is correct, it's not clear whether the + * unmarshalling code will properly handle the case where + * a packet where "share_count" and the max count for the + * array of shares don't match; a valid DCE RPC implementation + * won't marshal something like that, but there's no guarantee + * that the server we're talking to has a valid implementation + * (which could be a *malicious* implementation!). + */ + entries = share_info.share_union.tagged_union.share1->share_count; + shares = share_info.share_union.tagged_union.share1->shares; + entry_list = calloc(entries, sizeof (struct share_info)); + if (entry_list == NULL) { + error = errno; + goto cleanup_and_return; + } + for (share = shares, elp = entry_list, i = 0; i < entries; + i++, share++) { + elp->type = share->shi1_type; +#ifdef NOTYETDEFINED + elp->netname = convert_unicode_to_utf8(share->shi1_share); +#endif + elp->netname = share->shi1_share; + if (elp->netname == NULL) + goto fail; +#ifdef NOTYETDEFINED + elp->remark = convert_unicode_to_utf8(share->shi1_remark); +#endif + elp->remark = share->shi1_remark; + if (elp->remark == NULL) + goto fail; + elp++; + } + *entriesp = entries; + *totalp = total_entries; + *entries_listp = entry_list; + error = 0; + goto cleanup_and_return; + +fail: + error = errno; + for (elp = entry_list, i = 0; i < entries; i++, elp++) { + /* + * elp->netname is set before elp->remark, so if + * elp->netname is null, elp->remark is also null. + * If either of them is null, we haven't done anything + * to any entries after this one. + */ + if (elp->netname == NULL) + break; + free(elp->netname); + if (elp->remark == NULL) + break; + free(elp->remark); + } + free(entry_list); + +cleanup_and_return: + for (share = shares, i = 0; i < entries; i++, share++) { + free(share->shi1_share); + free(share->shi1_remark); + } + free(shares); + /* + * XXX - "share1" should be a unique pointer, but we haven't + * changed the marshalling code to support non-full pointers + * in unions, so we leave it as a full pointer. + * + * That means that this might, or might not, be changed from + * pointing to "share_info_1_container" to pointing to a + * mallocated structure, according to the DCE RPC 1.1 IDL spec; + * we free it only if it's changed. + */ + if (share_info.share_union.tagged_union.share1 != + &share_info_1_container) + free(share_info.share_union.tagged_union.share1); + return (error); +} +#endif /* XXX */ + +static int +rap_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp, + struct share_info **entries_listp) +{ + int error, bufsize, i, entries, total, nreturned; + struct smb_share_info_1 *rpbuf, *ep; + struct share_info *entry_list, *elp; + char *cp; + int lbound, rbound; + + bufsize = 0xffe0; /* samba notes win2k bug for 65535 */ + rpbuf = malloc(bufsize); + if (rpbuf == NULL) + return (errno); + + error = smb_rap_NetShareEnum(ctx, 1, rpbuf, &bufsize, &entries, &total); + if (error && + error != (SMB_ERROR_MORE_DATA | SMB_RAP_ERROR)) { + free(rpbuf); + return (error); + } + entry_list = malloc(entries * sizeof (struct share_info)); + if (entry_list == NULL) { + error = errno; + free(rpbuf); + return (error); + } + lbound = entries * (sizeof (struct smb_share_info_1)); + rbound = bufsize; + for (ep = rpbuf, elp = entry_list, i = 0, nreturned = 0; i < entries; + i++, ep++) { + elp->type = letohs(ep->shi1_type); + ep->shi1_pad = '\0'; /* ensure null termination */ + elp->netname = strdup(ep->shi1_netname); +#ifdef NOTYETDEFINED + elp->netname = convert_wincs_to_utf8(ep->shi1_netname); +#endif + if (elp->netname == NULL) + continue; /* punt on this entry */ + /* + * Check for validity of offset. + */ + if (ep->shi1_remark >= lbound && ep->shi1_remark < rbound) { + cp = (char *)rpbuf + ep->shi1_remark; + elp->remark = cp; +#ifdef NOTYETDEFINED + elp->remark = nls_str_toloc(cp, cp); +#endif + } else + elp->remark = NULL; + elp++; + nreturned++; + } + *entriesp = nreturned; + *totalp = total; + *entries_listp = entry_list; + free(rpbuf); + return (0); +} + +/* + * First we try the RPC-based NetrShareEnum, and, if that fails, we fall + * back on the RAP-based NetShareEnum. + */ +int +smb_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp, + struct share_info **entry_listp) +{ + int error; + +#ifdef NOTYETDEFINED + /* + * Try getting a list of shares with the SRVSVC RPC service. + */ + error = rpc_netshareenum(ctx, entriesp, totalp, entry_listp); + if (error == 0) + return (0); +#endif + + /* + * OK, that didn't work - try RAP. + * XXX - do so only if it failed because we couldn't open + * the pipe? + */ + return (rap_netshareenum(ctx, entriesp, totalp, entry_listp)); +} |