summaryrefslogtreecommitdiff
path: root/usr/src/lib/libsmbfs/smb/netshareenum.c
diff options
context:
space:
mode:
authorthurlow <none@none>2008-02-13 19:51:22 -0800
committerthurlow <none@none>2008-02-13 19:51:22 -0800
commit4bff34e37def8a90f9194d81bc345c52ba20086a (patch)
tree7bf2710d9da099e3b07fea38e12788bfd565f3c5 /usr/src/lib/libsmbfs/smb/netshareenum.c
parenta916d99c7b27a531bf37c57f83b0b74120fd05bb (diff)
downloadillumos-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.c349
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));
+}