#ident "%Z%%M% %I% %E% SMI" Copyright (c) 2000, 2001 Boris Popov All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed by Boris Popov. 4. Neither the name of the author nor the names of any co-contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ident "%Z%%M% %I% %E% SMI" In the development process next sources were used: Various documents from the Microsoft ftp site. HTML docs published by Thursby Software. Special thanks to the Samba team for permission to use their source code as reference. Author - Boris Popov , # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright 2017 Nexenta Systems, Inc. All rights reserved. # # # cmd/fs.d/smbclnt/Makefile # contains the CIFS client commands # include $(SRC)/Makefile.master SUBDIRS_CATALOG= smbutil mount umount share SUBDIRS= $(SUBDIRS_CATALOG) chacl lsacl \ smbiod smbiod-svc svc fksmbcl # for messaging catalog files # POFILES= smbutil/smbutil_all.po mount/mount.po umount/umount.po \ share/share.po share/unshare.po POFILE= smbclnt.po all: TARGET= all install: TARGET= install clean: TARGET= clean clobber: TARGET= clobber catalog: TARGET= catalog .KEEP_STATE: .PARALLEL: $(SUBDIRS) all install clean clobber: $(SUBDIRS) catalog: $(SUBDIRS_CATALOG) $(RM) $(POFILE) cat $(POFILES) > $(POFILE) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # FSTYPE= smbfs LIBPROG= chacl ROOTFS_PROG= $(LIBPROG) include ../../Makefile.fstype OBJS= $(LIBPROG).o LDLIBS += -lsmbfs -lsec # Hammerhead: GNU ld needs rpath-link to resolve mech_krb5.so.1 (transitive dep of libsmbfs) LDFLAGS += -Wl,-rpath-link,$(ROOT)/usr/lib/gss CFLAGS += $(CCVERBOSE) CERRWARN += -Wno-unused-variable CLOBBERFILES += $(LIBPROG) all: $(ROOTFS_PROG) install: $(ROOTLIBFSTYPEPROG) clean: $(RM) $(OBJS) .KEEP_STATE: /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2018, Joyent, Inc. */ /* * This is the smbfs/chacl command. * (just for testing - not installed) * * Works like chmod(1), but only supporting A=... forms. * i.e. chacl A=everyone@:full_set:fd:allow /mnt/foo * * Some more test cases: * /usr/lib/fs/smbfs/chacl -v * A=user:2147483649:rwxpdDaARWcCos::allow, * user:2147483653:raRcs::allow, * everyone@:raRcs::allow */ #include #include #include #include #include #include #include #include #include #include #include #include char *progname; int Vflag; void chacl(char *, uint32_t, uid_t, gid_t, acl_t *); static const char Usage[] = "Usage: %s [-v] [-u UID] [-g GID] A=ACL... file ...\n" "\twhere A=ACL is like chmod(1)\n"; void usage(void) { fprintf(stderr, Usage, progname); exit(1); } int main(int argc, char **argv) { uid_t uid = (uid_t)-1; gid_t gid = (gid_t)-1; acl_t *acl = NULL; char *acl_arg; ulong_t tl; int c, error; uint32_t selector; progname = argv[0]; while ((c = getopt(argc, argv, "vu:g:")) != -1) { switch (c) { case 'v': Vflag++; break; case 'u': tl = strtoul(optarg, NULL, 10); if (tl == 0) goto badopt; uid = (uid_t)tl; break; case 'g': tl = strtoul(optarg, NULL, 10); if (tl == 0) goto badopt; gid = (gid_t)tl; break; case ':': fprintf(stderr, "%s: option %c requires arg\n", progname, c); usage(); break; badopt: default: fprintf(stderr, "%s: bad option: %c\n", progname, c); usage(); break; } } if (optind + 1 > argc) usage(); acl_arg = argv[optind++]; /* * Ask libsec to parse the ACL arg. */ if (strncmp(acl_arg, "A=", 2) != 0) usage(); error = acl_parse(acl_arg + 2, &acl); if (error) { fprintf(stderr, "%s: can not parse ACL: %s\n", progname, acl_arg); exit(1); } if (acl->acl_type != ACE_T) { fprintf(stderr, "%s: ACL not ACE_T type: %s\n", progname, acl_arg); exit(1); } /* * Which parts of the SD are being modified? */ selector = DACL_SECURITY_INFORMATION; if (uid != (uid_t)-1) selector |= OWNER_SECURITY_INFORMATION; if (gid != (gid_t)-1) selector |= GROUP_SECURITY_INFORMATION; if (optind == argc) usage(); for (; optind < argc; optind++) chacl(argv[optind], selector, uid, gid, acl); acl_free(acl); return (0); } void chacl(char *file, uint32_t selector, uid_t uid, gid_t gid, acl_t *acl) { struct stat st; struct i_ntsd *sd = NULL; int error, fd; /* * OK, try setting the ACL (via ioctl). Open * read-only because we're NOT writing data. * The driver will re-open with the necessary * access rights to set the ACL. */ fd = open(file, O_RDONLY, 0); if (fd < 0) { perror(file); exit(1); } if (uid == (uid_t)-1 || gid == (gid_t)-1) { /* * If not setting owner or group, we need the * current owner and group for translating * references via owner@ or group@ ACEs. */ if (fstat(fd, &st) != 0) { perror(file); exit(1); } if (uid == (uid_t)-1) uid = st.st_uid; if (gid == (gid_t)-1) gid = st.st_gid; } /* * Convert the ZFS ACL to an NT SD. */ error = smbfs_acl_zfs2sd(acl, uid, gid, selector, &sd); if (error) { fprintf(stderr, "%s: failed to convert ACL\n", progname); exit(1); } if (Vflag) { /* * Print the SD in ZFS form. */ printf("Solaris security data:\n"); if (uid == (uid_t)-1) printf("owner: -1\n"); else printf("owner: %u\n", uid); if (gid == (gid_t)-1) printf("group: -1\n"); else printf("group: %u\n", gid); acl_printacl(acl, 80, 1); printf("\n"); /* * Print the SD in Windows form. */ printf("CIFS security data:\n"); smbfs_acl_print_sd(stdout, sd); printf("\n"); } error = smbfs_acl_setsd(fd, selector, sd); (void) close(fd); if (error) { fprintf(stderr, "%s: ACL set failed, %s\n", file, strerror(error)); exit(1); } smbfs_acl_free_sd(sd); } # # This file and its contents are supplied under the terms of the # Common Development and Distribution License ("CDDL"), version 1.0. # You may only use this file in accordance with the terms of version # 1.0 of the CDDL. # # A full copy of the text of the CDDL should have accompanied this # source. A copy of the CDDL is also available via the Internet at # http://www.illumos.org/license/CDDL. # # # Copyright 2017 Nexenta Systems, Inc. All rights reserved. # # set -o emacs # fksmbcl is always 32-bit setenv LD_LIBRARY_PATH ${ROOT}/usr/lib/smbfs:${ROOT}/usr/lib:${ROOT}/lib echo 'Do one of: attach ${PID}' echo 'or: debug ${ROOT}/usr/lib/smbfs/fksmbcl' echo 'then: run -v //localhost' # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright 2017 Nexenta Systems, Inc. All rights reserved. # Copyright 2019, Joyent, Inc. # PROG= fksmbcl OBJS_LOCAL = \ fksmbcl_main.o \ fkdev.o \ fknewvc.o \ fkiod_cl.o \ shares.o OBJS= ${OBJS_LOCAL} SRCS= ${OBJS_LOCAL:.o=.c} include ../../../Makefile.cmd include ../../../Makefile.ctf # Force SOURCEDEBUG CSOURCEDEBUGFLAGS = -g CCSOURCEDEBUGFLAGS = -g STRIP_STABS = : # Note: need our sys includes _before_ ENVCPPFLAGS, proto etc. # Also, like Makefile.uts, reset CPPFLAGS # CPPFLAGS.first += -I$(SRC)/lib/libfakekernel/common CPPFLAGS.first += -I$(SRC)/lib/smbclnt/libfknsmb/common CPPFLAGS= $(CPPFLAGS.first) INCS += -I$(SRC)/uts/common/fs/smbclnt INCS += -I$(SRC)/uts/common INCS += -I$(SRC)/common/smbclnt INCS += -I$(SRC)/common # Allow cpp to find libfknsmb.h etc. via # include INCS += -I$(SRC)/lib/smbclnt INCS += -I$(SRC)/lib/libsmbfs INCS += -I$(SRC)/lib/libsmbfs/netsmb CPPFLAGS += $(INCS) CPPFLAGS += -D_REENTRANT CPPFLAGS += -D_FILE_OFFSET_BITS=64 CPPFLAGS += -D_LARGEFILE64_SOURCE=1 CPPFLAGS += -DFKSMBCL # Always want DEBUG here CPPFLAGS += -DDEBUG # needs work SMOFF += all_func_returns CSTD= $(CSTD_GNU99) CFLAGS += $(CCVERBOSE) CFLAGS64 += $(CCVERBOSE) LDFLAGS += $(ZNOLAZYLOAD) LDFLAGS += -R/usr/lib/smbfs # Hammerhead: GNU ld needs rpath-link to resolve mech_krb5.so.1 (transitive dep of libsmbfs) LDFLAGS += -Wl,-rpath-link,$(ROOT)/usr/lib/gss LDLIBS += -L$(ROOT)/usr/lib/smbfs LDLIBS += -lsmbfs -lfksmbfs -lfknsmb LDLIBS += -lsocket ROOTSMBDDIR = $(ROOTLIB)/smbfs ROOTSMBDFILE = $(PROG:%=$(ROOTSMBDDIR)/%) .KEEP_STATE: all: $(PROG) $(PROG): $(OBJS) $(LINK.c) -o $(PROG) $(OBJS) $(LDLIBS) $(POST_PROCESS) clean: -$(RM) $(OBJS) include ../../../Makefile.targ install: all $(ROOTSMBDFILE) $(ROOTSMBDDIR)/%: % $(INS.file) # # This file and its contents are supplied under the terms of the # Common Development and Distribution License ("CDDL"), version 1.0. # You may only use this file in accordance with the terms of version # 1.0 of the CDDL. # # A full copy of the text of the CDDL should have accompanied this # source. A copy of the CDDL is also available via the Internet at # http://www.illumos.org/license/CDDL. # # # Copyright 2017 Nexenta Systems, Inc. All rights reserved. # This directory builds a program linking all of the SMB client code into a user-level process. The result is not a fully functional SMB client but is very useful for some kinds of development work. The architecture of this roughly parallels the in-kernel version, where the kernel modules are built as libraries including: libfksmbfs, libfknsmb Just as with the kernel code, there are mdb modules that know how to walk data structures in libfksmbfs, etc. For debugging, etc. it's easiest to run this as a normal user, i.e. yourself (not root) Now you can run fksmbcl from the proto area using this script: ./Run.sh -df You can also run it under dbx (see the .dbxrc file). To run it under mdb (with mdb modules build here): mdb -L $ROOT/usr/lib/mdb/proc:/usr/lib/mdb/proc ... where ... is one of: fksmbcl, core.nnn, -p $PID There are also some dtrace scripts in here, and in ../dtrace for watching either all activity or only selected areas. Run these like: dtrace -s Watch-all.d -p $PID -o output These two (from over in ../dtrace) also work with fksmbcl: dtrace -s fksmbcl.d -p `pgrep fksmbcl` -o output Here is the help output: > help Commands: help exit logon [user [dom [pass]]] logoff [close-driver] shares mount {share} [optstr] umount unmount statfs dir {rdir} [lfile] dirx {rdir} [lfile] get {rfile} [lfile] put {lfile} [rfile] mv {from} {to} rm {rfile} mkdir {rfile} rmdir {rfile} opt {option} Here is an example of how to connect, mount, and list a directory: $ ./Run.sh //myserver # Start with: > logon [user [dom [pw]]] > shares > mount {share} > logon test test test > shares open pipe: /srvsvc enum strings junk c$ Default Share test1 ipc$ Remote IPC test > mount test > dir 1224750917 . 1224750917 .. 900818955 test9.dat 3908265151 lock1.txt 2452346625 test_dir > umount > logoff > exit $ #!/bin/sh # # This file and its contents are supplied under the terms of the # Common Development and Distribution License ("CDDL"), version 1.0. # You may only use this file in accordance with the terms of version # 1.0 of the CDDL. # # A full copy of the text of the CDDL should have accompanied this # source. A copy of the CDDL is also available via the Internet at # http://www.illumos.org/license/CDDL. # # # Copyright 2017 Nexenta Systems, Inc. All rights reserved. # # Helper program to run fksmbd (user-space smbd for debugging) # using binaries from the proto area. [ -n "$ROOT" ] || { echo "Need a bldenv to set ROOT=..." exit 1; } # OK, setup env. to run it. LD_LIBRARY_PATH=$ROOT/usr/lib/smbfs:$ROOT/usr/lib:$ROOT/lib export LD_LIBRARY_PATH # run with the passed options exec $ROOT/usr/lib/smbfs/fksmbcl "$@" #!/usr/sbin/dtrace -s /* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* * User-level dtrace for fksmbcl * Usage: dtrace -s Watch-fksmbcl.d -p $PID */ /* * If traced, print entry/return */ pid$target:fksmbcl::entry, pid$target:libsmbfs.so.1::entry, pid$target:libfksmbfs.so.1::entry, pid$target:libfknsmb.so.1::entry, pid$target:libfakekernel.so.1::entry { printf("\t0x%x", arg0); printf("\t0x%x", arg1); printf("\t0x%x", arg2); printf("\t0x%x", arg3); printf("\t0x%x", arg4); printf("\t0x%x", arg5); } pid$target:fksmbcl::return, pid$target:libsmbfs.so.1::return, pid$target:libfksmbfs.so.1::return, pid$target:libfknsmb.so.1::return, pid$target:libfakekernel.so.1::entry { printf("\t0x%x", arg1); } pid$target::smbfslookup:entry { printf("\tname = %s\n", copyinstr(arg1)); } pid$target:libfknsmb.so.1:smb_dtrace2:entry /copyinstr(arg0) == "debugmsg2"/ { this->f = copyinstr(arg1); this->m = copyinstr(arg2); printf("\n\t debugmsg2: %s: %s ", this->f, this->m); } pid$target:libfknsmb.so.1:smb_dtrace3:entry /copyinstr(arg0) == "debugmsg3"/ { this->f = copyinstr(arg1); this->m = copyinstr(arg2); printf("\n\t debugmsg3: %s: %s ", this->f, this->m); trace(arg3); } /* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright 2017 Nexenta Systems, Inc. All rights reserved. */ /* * This file implements device open/close/ioctl wrappers that * redirect access from the real "nsmb" device to the in-process * device simulation in libfknsmb. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "smb/charsets.h" #include "smb/private.h" int smb_open_driver(void) { dev32_t dev; int fd; int rc; rc = nsmb_drv_open(&dev, 0, 0); if (rc != 0) { errno = rc; return (-1); } assert((dev & 0xFFFF0000) != 0); fd = (int)dev; return (fd); } int nsmb_ioctl(int fd, int cmd, void *arg) { dev32_t dev; int err; dev = (dev32_t)fd; assert((dev & 0xFFFF0000) != 0); err = nsmb_drv_ioctl(dev, cmd, (intptr_t)arg, 0); if (err != 0) { errno = err; return (-1); } return (0); } int nsmb_close(int fd) { dev32_t dev; dev = (dev32_t)fd; assert((dev & 0xFFFF0000) != 0); (void) nsmb_drv_close(dev, 0, 0); return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2017 Nexenta Systems, Inc. All rights reserved. */ /* * Client-side interface to the IO Daemon (IOD) */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "smb/charsets.h" #include "smb/private.h" /* * Make sure we don't call the real IOD here. */ int smb_iod_open_door(int *fdp) { *fdp = -1; return (ENOTSUP); } /* * Get a door handle to the IOD... */ int smb_iod_start(smb_ctx_t *ctx) { return (0); } void * iod_work(void *arg) { smb_ctx_t *ctx = arg; (void) smb_iod_work(ctx); smb_ctx_free(ctx); return (NULL); } /* * Ask the IOD to connect using the info in ctx. * Called by newvc. * * This function largely follows smbiod.c : iod_newvc() */ int smb_iod_cl_newvc(smb_ctx_t *cl_ctx) { smb_ctx_t *ctx; thread_t tid; int err = 0; /* * Clone the context, like in smbiod.c */ err = smb_ctx_alloc(&ctx); if (err) return (err); bcopy(&cl_ctx->ct_iod_ssn, &ctx->ct_iod_ssn, sizeof (ctx->ct_iod_ssn)); /* * Create the driver session first... */ if ((err = smb_ctx_gethandle(ctx)) != 0) goto out; if (nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_SSN_CREATE, &ctx->ct_ssn) < 0) { err = errno; if (err == EEXIST) err = 0; /* see above */ goto out; } /* * Do the initial connection setup here, so we can * report the outcome to the door client. */ err = smb_iod_connect(ctx); if (err != 0) { fprintf(stderr, "smb_iod_connect, err=%d\n", err); goto out; } /* The rest happens in the iod_work thread. */ err = thr_create(NULL, 0, iod_work, ctx, THR_DETACHED, &tid); if (err == 0) { /* * Given to the new thread. * free at end of iod_work */ ctx = NULL; } out: if (ctx != NULL) smb_ctx_free(ctx); return (err); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright 2017 Nexenta Systems, Inc. All rights reserved. */ /* * Create a new VC given a list of addresses. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "smb/charsets.h" #include "smb/private.h" /* * Ask the IOD to create a VC with this IP address. */ static int fknewvc(struct smb_ctx *ctx, struct addrinfo *ai) { char host[256]; char svc[32]; smbioc_ossn_t *ssn = &ctx->ct_ssn; int err; if (smb_debug) { err = getnameinfo(ai->ai_addr, ai->ai_addrlen, host, sizeof (host), svc, sizeof (svc), AI_NUMERICHOST); if (err != 0) { strlcpy(host, "(?)", sizeof (host)); strlcpy(svc, "?", sizeof (host)); } printf("fknewvc: Try AF=%d %s:%s\n", ai->ai_family, host, svc); } /* * Copy the passed address into ssn_srvaddr, * but first sanity-check lengths. Also, * zero it first to avoid trailing junk. */ if (ai->ai_addrlen > sizeof (ssn->ssn_srvaddr)) return (EINVAL); bzero(&ssn->ssn_srvaddr, sizeof (ssn->ssn_srvaddr)); bcopy(ai->ai_addr, &ssn->ssn_srvaddr, ai->ai_addrlen); /* Ask the IOD to connect using the info in ctx. */ err = smb_iod_cl_newvc(ctx); if (smb_debug) { printf("fknewvc: iod_cl_newvc err=%d\n", err); } return (err); } /* * Setup a new VC via the IOD. * Similar to findvc.c */ int smb_ctx_newvc(struct smb_ctx *ctx) { struct addrinfo *ai; int err; /* Should already have the address list. */ if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) return (EINVAL); err = EPROTONOSUPPORT; /* in case no AF match */ for (ai = ctx->ct_addrinfo; ai; ai = ai->ai_next) { switch (ai->ai_family) { case AF_INET: case AF_INET6: case AF_NETBIOS: err = fknewvc(ctx, ai); if (err == 0) return (0); break; default: break; } } /* * In the error case, the caller may try again * with new auth. info, so keep the door open. * Error return will close in smb_ctx_done. */ return (err); } /* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* * Test & debug program for the SMB client * * This implements a simple command reader which accepts * commands to simulate system calls into the file system. */ #include #include #include #include #include #include /* SL_NOTE */ #include #include #include #include #include #include #include #include #include #include #include #include #if _FILE_OFFSET_BITS != 64 #error "This calls (fake) VFS code which requires 64-bit off_t" #endif extern int list_shares(struct smb_ctx *); #define MAXARG 10 struct cmd_tbl_ent { void (*ce_func)(int, char **); const char *ce_name; const char *ce_argdesc; }; static struct cmd_tbl_ent cmd_tbl[]; static struct smb_ctx *ctx = NULL; static char *server = NULL; static vfs_t *vfsp = NULL; static void show_dents(vnode_t *, offset_t *, char *, int); static void run_cli(void); #define TBUFSZ 8192 static char tbuf[TBUFSZ]; static void fksmbcl_usage(void) { printf("usage: fksmbcl //user@server (like smbutil)\n"); exit(1); } int main(int argc, char *argv[]) { int error, opt; /* * Initializations */ nsmb_drv_load(); nsmb_drv_init(); fksmbfs_init(); while ((opt = getopt(argc, argv, "dv")) != -1) { switch (opt) { case 'd': smb_debug++; break; case 'v': smb_verbose++; break; case '?': fksmbcl_usage(); break; } } if (optind >= argc) fksmbcl_usage(); server = argv[optind]; /* * Setup the libsmbfs context */ error = smb_ctx_alloc(&ctx); if (error) { fprintf(stderr, "%s: smb_ctx_alloc failed (%d)\n", argv[0], error); return (1); } error = smb_ctx_scan_argv(ctx, argc, argv, SMBL_SERVER, SMBL_SERVER, USE_WILDCARD); if (error) { fprintf(stderr, "logon: smb_ctx_scan_argv, error %d\n", error); return (1); } error = smb_ctx_readrc(ctx); if (error) { fprintf(stderr, "logon: smb_ctx_readrc, error %d\n", error); return (1); } /* Do smb_ctx_setshare later, and smb_ctx_resolve. */ /* * Next would be smb_ctx_get_ssn() but don't do that until * the "logon" command so one can set breakpoints etc. */ /* * Run the CLI */ run_cli(); /* * Cleanup */ fksmbfs_fini(); nsmb_drv_fini(); return (0); } static void run_cli() { static char cmdbuf[100]; int argc, i; char *argv[MAXARG]; char *cmd; char *savep = NULL; char *sep = " \t\n"; char *prompt = NULL; struct cmd_tbl_ent *ce; if (isatty(0)) { fputs("# Start with:\n" "> logon [user [dom [pw]]]\n" "> shares\n" "> mount {share}\n\n", stdout); prompt = "> "; } for (;;) { if (prompt) { fputs(prompt, stdout); fflush(stdout); } cmd = fgets(cmdbuf, sizeof (cmdbuf), stdin); if (cmd == NULL) break; if (cmd[0] == '#') continue; if (prompt == NULL) { /* Put commands in the output too. */ fprintf(stdout, "+ %s", cmdbuf); } argv[0] = strtok_r(cmd, sep, &savep); if (argv[0] == NULL) continue; for (argc = 1; argc < MAXARG; argc++) { argv[argc] = strtok_r(NULL, sep, &savep); if (argv[argc] == NULL) break; } for (i = argc; i < MAXARG; i++) argv[i++] = NULL; for (ce = cmd_tbl; ce->ce_name != NULL; ce++) if (strcmp(ce->ce_name, argv[0]) == 0) break; if (ce->ce_name != NULL) { ce->ce_func(argc, argv); } else { fprintf(stderr, "%s unknown command. Try help\n", argv[0]); } } } /* * Command handlers */ static void do_exit(int argc, char **argv) { exit(0); } static void do_help(int argc, char **argv) { struct cmd_tbl_ent *ce; printf("Commands:\n"); for (ce = cmd_tbl; ce->ce_func != NULL; ce++) printf("%s %s\n", ce->ce_name, ce->ce_argdesc); } static void do_logon(int argc, char **argv) { int error; if (argc > 1) { if (argv[1][0] == '-') { smb_ctx_setuser(ctx, "", B_TRUE); ctx->ct_flags |= SMBCF_NOPWD; } else { smb_ctx_setuser(ctx, argv[1], B_TRUE); } } if (argc > 2) smb_ctx_setdomain(ctx, argv[2], B_TRUE); if (argc > 3) smb_ctx_setpassword(ctx, argv[3], 0); /* * Resolve the server address, setup derived defaults. */ error = smb_ctx_resolve(ctx); if (error) { fprintf(stderr, "logon: smb_ctx_resolve, error %d\n", error); return; } /* * Have server, share, etc. now. * Get the logon session. */ again: error = smb_ctx_get_ssn(ctx); if (error == EAUTH) { int err2; err2 = smb_get_authentication(ctx); if (err2 == 0) goto again; } if (error) { fprintf(stderr, "//%s: login failed, error %d\n", ctx->ct_fullserver, error); } } /* * Drop session created by the "logon" command. */ static void do_logoff(int argc, char **argv) { (void) nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_SSN_RELE, NULL); if (argc > 1) { smb_ctx_done(ctx); (void) smb_ctx_init(ctx); } } /* * List shares */ static void do_shares(int argc, char **argv) { int error; smb_ctx_setshare(ctx, "IPC$", USE_IPC); error = smb_ctx_get_tree(ctx); if (error) { fprintf(stderr, "shares, tcon IPC$, error=%d\n", error); return; } error = list_shares(ctx); if (error) { fprintf(stderr, "shares, enum, error=%d\n", error); } (void) nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_TREE_RELE, NULL); } char mnt_opt_buf[MAX_MNTOPT_STR]; char mnt_resource[MAXPATHLEN]; /* * Minimal excerpt from vfs.c:domount() */ void do_mount(int argc, char **argv) { struct smbfs_args mdata; struct mounta ma; char *shrname; int error; if (vfsp != NULL) { fprintf(stderr, "Already mounted\n"); return; } if (argc < 2) { fprintf(stderr, "%s: missing share name\n", argv[0]); return; } shrname = argv[1]; if (argc > 2) strlcpy(mnt_opt_buf, argv[2], sizeof (mnt_opt_buf)); else memset(mnt_opt_buf, 0, sizeof (mnt_opt_buf)); smb_ctx_setshare(ctx, shrname, USE_DISKDEV); error = smb_ctx_get_tree(ctx); if (error) { fprintf(stderr, "//%s/%s: tree connect failed, %d\n", server, shrname, error); return; } (void) snprintf(mnt_resource, sizeof (mnt_resource), "//%s/%s", ctx->ct_fullserver, shrname); bzero(&mdata, sizeof (mdata)); mdata.version = SMBFS_VERSION; /* smbfs mount version */ mdata.file_mode = S_IRWXU; mdata.dir_mode = S_IRWXU; mdata.devfd = ctx->ct_dev_fd; /* Build mount args */ bzero(&ma, sizeof (ma)); ma.spec = mnt_resource; ma.dir = "/"; ma.flags = MS_DATA | MS_OPTIONSTR | MS_NOSPLICE | MS_NOSUID; ma.fstype = "smbfs"; ma.dataptr = (void *) &mdata; ma.datalen = sizeof (mdata); ma.optptr = mnt_opt_buf; ma.optlen = sizeof (mnt_opt_buf); error = fake_domount("smbfs", &ma, &vfsp); if (error != 0) { fprintf(stderr, "domount error=%d\n", error); } /* Mount takes a ref, so always rele here. */ (void) nsmb_ioctl(ctx->ct_dev_fd, SMBIOC_TREE_RELE, NULL); } void do_unmount(int argc, char **argv) { int error; if (vfsp == NULL) { fprintf(stderr, "Not mounted\n"); return; } error = fake_dounmount(vfsp, 0); if (error != 0) { fprintf(stderr, "dounmount error=%d\n", error); return; } vfsp = NULL; } void do_statfs(int argc, char **argv) { statvfs64_t st; int error; if (vfsp == NULL) { fprintf(stderr, "Not mounted\n"); return; } error = fsop_statfs(vfsp, &st); if (error != 0) { fprintf(stderr, "df error=%d\n", error); return; } printf("bsize=%ld\n", st.f_bsize); printf("frsize=%ld\n", st.f_frsize); printf("blocks=%" PRIu64 "\n", st.f_blocks); printf(" bfree=%" PRIu64 "\n", st.f_bfree); printf("bavail=%" PRIu64 "\n", st.f_bavail); } void do_dir(int argc, char **argv) { char *rdir; vnode_t *vp = NULL; offset_t off; int cnt; int error; if (vfsp == NULL) { fprintf(stderr, "mnt required first\n"); return; } if (argc > 1) rdir = argv[1]; else rdir = ""; error = vn_open(rdir, 0, FREAD, 0, &vp, 0, 0); if (error != 0) { fprintf(stderr, "do_dir, vn_open error=%d\n", error); return; } off = 0; do { cnt = fake_getdents(vp, &off, tbuf, TBUFSZ); if (cnt < 0) { fprintf(stderr, "do_dir, getdents %d\n", -cnt); break; } show_dents(vp, &off, tbuf, cnt); } while (cnt > 0); if (vp != NULL) vn_close_rele(vp, 0); } void do_dirx(int argc, char **argv) { char *rdir; vnode_t *vp = NULL; offset_t off; int cnt; int error; if (vfsp == NULL) { fprintf(stderr, "mnt required first\n"); return; } if (argc > 1) rdir = argv[1]; else rdir = ""; error = vn_open(rdir, 0, FREAD|FXATTRDIROPEN, 0, &vp, 0, 0); if (error != 0) { fprintf(stderr, "do_dirx, vn_open error=%d\n", error); return; } off = 0; do { cnt = fake_getdents(vp, &off, tbuf, TBUFSZ); if (cnt < 0) { fprintf(stderr, "do_dirx, getdents %d\n", -cnt); break; } show_dents(vp, &off, tbuf, cnt); } while (cnt > 0); if (vp != NULL) vn_close_rele(vp, 0); } static void show_dents(vnode_t *dvp, offset_t *offp, char *buf, int cnt) { char time_buf[40]; struct stat64 st; vnode_t *vp; char *p; dirent_t *d; offset_t offset = (offset_t)-1L; int error; uint_t mode; char type; p = buf; while (p < (buf + cnt)) { d = (dirent_t *)(void *)p; p += d->d_reclen; offset = d->d_off; error = fake_lookup(dvp, d->d_name, &vp); if (error != 0) { fprintf(stderr, "%s: lookup error=%d\n", d->d_name, error); continue; } error = fake_stat(vp, &st, 0); vn_rele(vp); if (error != 0) { fprintf(stderr, "%s: stat error=%d\n", d->d_name, error); continue; } /* * Print type, mode, size, name * First mode (only dir, file expected here) */ if (S_ISDIR(st.st_mode)) { type = 'd'; } else if (S_ISREG(st.st_mode)) { type = ' '; } else { type = '?'; } mode = st.st_mode & 0777; (void) strftime(time_buf, sizeof (time_buf), "%b %e %T %Y", localtime(&st.st_mtime)); printf("%c 0%3o %9" PRIu64 " %s %s\n", type, mode, (uint64_t)st.st_size, time_buf, d->d_name); } *offp = offset; } /* * get rname [lname] */ void do_get(int argc, char **argv) { struct stat64 st; char *rname; char *lname; vnode_t *vp = NULL; offset_t off; ssize_t cnt, x; int oflg = O_RDWR | O_CREAT; int lfd = -1; int error; if (vfsp == NULL) { fprintf(stderr, "mnt required first\n"); return; } if (argc < 2) { fprintf(stderr, "rname required\n"); return; } rname = argv[1]; if (argc > 2) { lname = argv[2]; /* * When local name is specified, overwrite. * Convenient for scripts etc. */ oflg |= O_TRUNC; } else { lname = rname; /* Local file should not exist. */ oflg |= O_EXCL; } lfd = open(lname, oflg, 0644); if (lfd < 0) { perror(lname); return; } error = vn_open(rname, 0, FREAD, 0, &vp, 0, 0); if (error != 0) { fprintf(stderr, "do_get, vn_open error=%d\n", error); goto out; } error = fake_stat(vp, &st, 0); if (error != 0) { fprintf(stderr, "do_get, stat error=%d\n", error); goto out; } off = 0; do { cnt = fake_pread(vp, tbuf, TBUFSZ, off); if (cnt < 0) { fprintf(stderr, "do_get, read %d\n", -cnt); goto out; } x = write(lfd, tbuf, cnt); if (x < 0) { fprintf(stderr, "do_get, write %d\n", errno); goto out; } off += x; } while (off < st.st_size); out: if (vp != NULL) vn_close_rele(vp, 0); if (lfd != -1) close(lfd); } /* * put lname [rname] */ void do_put(int argc, char **argv) { struct stat64 rst; struct stat st; char *rname; char *lname; vnode_t *vp = NULL; offset_t off; ssize_t cnt, x; int oflg = FREAD|FWRITE|FCREAT; int lfd = -1; int error; if (vfsp == NULL) { fprintf(stderr, "mnt required first\n"); return; } if (argc < 2) { fprintf(stderr, "lname required\n"); return; } lname = argv[1]; if (argc > 2) { rname = argv[2]; /* * When remote name is specified, overwrite. * Convenient for scripts etc. */ oflg |= FTRUNC; } else { rname = lname; /* Remote file should not exist. */ oflg |= FEXCL; } lfd = open(lname, O_RDONLY, 0); if (lfd < 0) { perror(lname); return; } error = fstat(lfd, &st); if (error != 0) { fprintf(stderr, "do_put, stat error=%d\n", error); goto out; } error = vn_open(rname, 0, oflg, 0, &vp, 0, 0); if (error != 0) { fprintf(stderr, "do_put, vn_open error=%d\n", error); goto out; } off = 0; do { cnt = pread(lfd, tbuf, TBUFSZ, off); if (cnt < 0) { fprintf(stderr, "do_put, read %d\n", errno); goto out; } x = fake_pwrite(vp, tbuf, cnt, off); if (x < 0) { fprintf(stderr, "do_put, write %d\n", -x); goto out; } off += cnt; } while (off < st.st_size); /* This getattr should go OtW. */ error = fake_stat(vp, &rst, 0); if (error != 0) { fprintf(stderr, "do_put, stat error=%d\n", error); goto out; } if (rst.st_size != st.st_size) { fprintf(stderr, "do_put, wrong size?\n"); } out: if (vp != NULL) vn_close_rele(vp, 0); if (lfd != -1) close(lfd); } /* * rm rname */ void do_rm(int argc, char **argv) { char *rname; int error; if (vfsp == NULL) { fprintf(stderr, "mnt required first\n"); return; } if (argc < 2) { fprintf(stderr, "rname required\n"); return; } rname = argv[1]; error = fake_unlink(rname, 0); if (error != 0) { fprintf(stderr, "do_rm, unlink error=%d\n", error); } } /* * mv fromname toname */ void do_mv(int argc, char **argv) { int error; if (vfsp == NULL) { fprintf(stderr, "mnt required first\n"); return; } if (argc < 3) { fprintf(stderr, "from_name to_name required\n"); return; } error = fake_rename(argv[1], argv[2]); if (error != 0) { fprintf(stderr, "do_mv, rename error=%d\n", error); } } /* * mkdir rname */ void do_mkdir(int argc, char **argv) { char *rname; vnode_t *vp = NULL; int error; if (vfsp == NULL) { fprintf(stderr, "mnt required first\n"); return; } if (argc < 2) { fprintf(stderr, "rname required\n"); return; } rname = argv[1]; error = vn_open(rname, 0, FCREAT, 0, &vp, CRMKDIR, 0); if (error != 0) { fprintf(stderr, "do_mkdir, vn_open error=%d\n", error); } if (vp != NULL) vn_close_rele(vp, 0); } /* * rmdir rname */ void do_rmdir(int argc, char **argv) { char *rname; int error; if (vfsp == NULL) { fprintf(stderr, "mnt required first\n"); return; } if (argc < 2) { fprintf(stderr, "rname required\n"); return; } rname = argv[1]; error = fake_unlink(rname, AT_REMOVEDIR); if (error != 0) { fprintf(stderr, "do_rmdir, unlink error=%d\n", error); } } /* * Simple option setting * * Each arg is handled as one line in .nsmbrc [default] */ void do_opt(int argc, char **argv) { static char template[20] = "/tmp/fksmbclXXXXXX"; static char rcname[30]; char *tdname; char *save_home; FILE *fp; int err, i; if (argc < 2) { fprintf(stderr, "opt {key}[=value]\n"); return; } tdname = mkdtemp(template); if (tdname == NULL) { perror("mkdtemp"); return; } (void) snprintf(rcname, sizeof (rcname), "%s/.nsmbrc", tdname); fp = fopen(rcname, "w"); if (fp == NULL) { perror(rcname); goto out; } fprintf(fp, "[default]\n"); for (i = 1; i < argc; i++) fprintf(fp, "%s\n", argv[i]); fclose(fp); save_home = ctx->ct_home; ctx->ct_home = tdname; err = smb_ctx_readrc(ctx); ctx->ct_home = save_home; if (err != 0) fprintf(stderr, "readrc, err=%d\n", err); out: (void) unlink(rcname); (void) rmdir(tdname); } /* * Command table */ static struct cmd_tbl_ent cmd_tbl[] = { { do_help, "help", "" }, { do_exit, "exit", "" }, { do_logon, "logon", "[user [dom [pass]]]" }, { do_logoff, "logoff", "[close-driver]" }, { do_shares, "shares", "" }, { do_mount, "mount", "{share} [optstr]" }, { do_unmount, "umount", "" }, { do_unmount, "unmount", "" }, { do_statfs, "statfs", "" }, { do_dir, "dir", "{rdir} [lfile]" }, { do_dirx, "dirx", "{rdir} [lfile]" }, { do_get, "get", "{rfile} [lfile]" }, { do_put, "put", "{lfile} [rfile]" }, { do_mv, "mv", "{from} {to}" }, { do_rm, "rm", "{rfile}" }, { do_mkdir, "mkdir", "{rfile}" }, { do_rmdir, "rmdir", "{rfile}" }, { do_opt, "opt", "{option}" }, { NULL, NULL, NULL } }; /* * Provide a real function (one that prints something) to replace * the stub in libfakekernel. This prints cmn_err() messages. */ void fakekernel_putlog(char *msg, size_t len, int flags) { /* * [CE_CONT, CE_NOTE, CE_WARN, CE_PANIC] maps to * [SL_NOTE, SL_NOTE, SL_WARN, SL_FATAL] */ if (smb_debug == 0 && (flags & SL_NOTE)) return; (void) fwrite(msg, 1, len, stdout); (void) fflush(stdout); } /* * Print nsmb debug messages via driver smb_debugmsg() */ void smb_debugmsg(const char *func, char *msg) { if (smb_debug < 2) return; printf("[kmod] %s: %s\n", func, msg); } /* * Enable libumem debugging */ const char * _umem_debug_init(void) { return ("default,verbose"); /* $UMEM_DEBUG setting */ } const char * _umem_logging_init(void) { return ("fail,contents"); /* $UMEM_LOGGING setting */ } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2017 Nexenta Systems, Inc. All rights reserved. */ /* * Test program for the smbfs named pipe API. */ #include #include #include #include #include #include #include #include #include #include /* * This is a quick hack for testing client-side named pipes. * Its purpose is to test SMB named-pipe interface separately * from the RPC implementation. It's a "hack" because it uses * hand-crafted RPC messages (extracted from network traffic). */ /* This is a DCE/RPC bind call for "srvsvc". */ static const uchar_t srvsvc_bind[] = { 0x05, 0x00, 0x0b, 0x03, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xc8, 0x4f, 0x32, 0x4b, 0x70, 0x16, 0xd3, 0x01, 0x12, 0x78, 0x5a, 0x47, 0xbf, 0x6e, 0xe1, 0x88, 0x03, 0x00, 0x00, 0x00, 0x04, 0x5d, 0x88, 0x8a, 0xeb, 0x1c, 0xc9, 0x11, 0x9f, 0xe8, 0x08, 0x00, 0x2b, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00 }; /* This is a srvsvc "enum servers" call, in two parts */ static const uchar_t srvsvc_enum1[] = { 0x05, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, #define ENUM_RPCLEN_OFF 8 /* V - RPC frag length */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ... and the operation number is: VVVV */ 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x0f, 0x00, #define ENUM_SLEN1_OFF 28 #define ENUM_SLEN2_OFF 36 /* server name, length 14 vv ... */ 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00 }; /* UNC server here, i.e.: "\\192.168.1.6" */ static const uchar_t srvsvc_enum2[] = { 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }; static uchar_t sendbuf[1024]; static uchar_t recvbuf[4096]; /* * Print strings found in the buffer. */ static void pstrings(const uchar_t *buf, int len) { const uchar_t *p = buf; uint16_t u2; boolean_t instr = B_FALSE; while (len > 2) { u2 = *p++; u2 |= (*p++) << 8; len -= 2; if ((u2 & 0xFF80) == 0 && isprint(u2)) { /* printable */ instr = B_TRUE; putchar(u2); } else { /* not printalbe */ if (instr) putchar('\n'); instr = B_FALSE; } } if (instr) putchar('\n'); } /* * Put a unicode UNC server name, including the null. * Quick-n-dirty, just for this test... */ static int put_uncserver(const char *s, uchar_t *buf) { uchar_t *p = buf; char c; *p++ = '\\'; *p++ = '\0'; *p++ = '\\'; *p++ = '\0'; do { c = *s++; if (c == '/') c = '\\'; *p++ = c; *p++ = '\0'; } while (c != 0); return (p - buf); } /* * Send the bind and read the ack. * This tests smb_fh_xactnp. */ static int do_bind(int fid) { int err, len, more; more = 0; len = sizeof (recvbuf); err = smb_fh_xactnp(fid, sizeof (srvsvc_bind), (char *)srvsvc_bind, &len, (char *)recvbuf, &more); if (err) { printf("xact bind, err=%d\n", err); return (err); } if (more > 0) { if (more > sizeof (recvbuf)) { printf("bogus more=%d\n", more); more = sizeof (recvbuf); } len = smb_fh_read(fid, 0, more, (char *)recvbuf); if (len == -1) { err = EIO; printf("read enum resp, err=%d\n", err); return (err); } } return (0); } static int do_enum(char *server, int fid) { int err, len, rlen, wlen; uchar_t *p; /* * Build the enum request - three parts. * See above: srvsvc_enum1, srvsvc_enum2 * * First part: RPC header, etc. */ p = sendbuf; len = sizeof (srvsvc_enum1); /* 40 */ memcpy(p, srvsvc_enum1, len); p += len; /* Second part: UNC server name */ len = put_uncserver(server, p); p += len; sendbuf[ENUM_SLEN1_OFF] = len / 2; sendbuf[ENUM_SLEN2_OFF] = len / 2; /* Third part: level, etc. (align4) */ for (len = (p - sendbuf) & 3; len; len--) *p++ = '\0'; len = sizeof (srvsvc_enum2); /* 28 */ memcpy(p, srvsvc_enum2, len); p += len; /* * Compute total length, and fixup RPC header. */ len = p - sendbuf; sendbuf[ENUM_RPCLEN_OFF] = len; /* * Send the enum request, read the response. * This tests smb_fh_write, smb_fh_read. */ wlen = smb_fh_write(fid, 0, len, (char *)sendbuf); if (wlen == -1) { err = errno; printf("write enum req, err=%d\n", err); return (err); } if (wlen != len) { printf("write enum req, short write %d\n", wlen); return (EIO); } rlen = smb_fh_read(fid, 0, sizeof (recvbuf), (char *)recvbuf); if (rlen == -1) { err = errno; printf("read enum resp, err=%d\n", err); return (err); } /* * Just dump strings found in the response data. * Skip the first 0x90 (RPC wrappers). */ printf("enum strings\n"); pstrings(recvbuf + 0x90, rlen - 0x90); return (0); } int list_shares(struct smb_ctx *ctx) { static char path[] = "/srvsvc"; static uchar_t key[16]; char *server = ctx->ct_srvname; int err, fd; printf("open pipe: %s\n", path); fd = smb_fh_open(ctx, path, O_RDWR); if (fd < 0) { perror(path); return (errno); } /* Test this too. */ err = smb_fh_getssnkey(fd, key, sizeof (key)); if (err) { printf("getssnkey: %d\n", err); goto out; } err = do_bind(fd); if (err) { printf("do_bind: %d\n", err); goto out; } err = do_enum(server, fd); if (err) printf("do_enum: %d\n", err); out: smb_fh_close(fd); return (0); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # FSTYPE= smbfs LIBPROG= lsacl ROOTFS_PROG= $(LIBPROG) include ../../Makefile.fstype OBJS= $(LIBPROG).o LDLIBS += -lsmbfs -lsec # Hammerhead: GNU ld needs rpath-link to resolve mech_krb5.so.1 (transitive dep of libsmbfs) LDFLAGS += -Wl,-rpath-link,$(ROOT)/usr/lib/gss CFLAGS += $(CCVERBOSE) CLOBBERFILES += $(LIBPROG) all: $(ROOTFS_PROG) install: $(ROOTLIBFSTYPEPROG) clean: $(RM) $(OBJS) .KEEP_STATE: /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * This is the smbfs/lsacl command. * (just for testing - not installed) */ #include #include #include #include #include #include #include #include #include #include #include #include extern acl_t *acl_alloc(acl_type_t); char *progname; int Vflag; uint32_t selector = DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION; void lsacl(char *); void usage(void) { fprintf(stderr, "Usage: %s [-v] file ...\n", progname); exit(1); } int main(int argc, char **argv) { int c; progname = argv[0]; while ((c = getopt(argc, argv, "v")) != -1) { switch (c) { case 'v': Vflag++; break; default: fprintf(stderr, "%s: bad option: %c\n", progname, c); usage(); break; } } if (optind == argc) usage(); for (; optind < argc; optind++) lsacl(argv[optind]); return (0); } void lsacl(char *file) { struct i_ntsd *sd; acl_t *acl; uid_t uid; gid_t gid; int error, fd; fd = open(file, O_RDONLY, 0); if (fd < 0) { perror(file); exit(1); } /* First, get the SD in internal form. */ error = smbfs_acl_getsd(fd, selector, &sd); (void) close(fd); if (error) { fprintf(stderr, "%s: getsd, %s\n", progname, strerror(error)); exit(1); } if (Vflag) { /* * Print it first in Windows form. This way, * if any of the conversion has problems, * one can try mapping each SID by hand, i.e.: * idmap show sid:S-1-xxx-yyy-zzz */ printf("CIFS security data:\n"); smbfs_acl_print_sd(stdout, sd); printf("\n"); } /* * Convert the internal SD to a ZFS ACL. */ acl = acl_alloc(ACE_T); error = smbfs_acl_sd2zfs(sd, acl, &uid, &gid); if (error) { fprintf(stderr, "%s: sd2zfs, %s\n", progname, strerror(error)); exit(1); } smbfs_acl_free_sd(sd); /* * Print it as a ZFS-style ACL (ACE_T) */ printf("Solaris security data:\n"); if (uid == (uid_t)-1) printf("owner: -1\n"); else printf("owner: %u\n", uid); if (gid == (gid_t)-1) printf("group: -1\n"); else printf("group: %u\n", gid); acl_printacl(acl, 80, 1); printf("\n"); acl_free(acl); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright 2019 Nexenta by DDN, Inc. All rights reserved. # # # cmd/fs.d/smbclnt/mount/Makefile # FSTYPE= smbfs LIBPROG= mount ROOTFS_PROG= $(LIBPROG) include ../../Makefile.fstype OBJS= $(LIBPROG).o POFILE= $(LIBPROG).po CLOBBERFILES += $(LIBPROG) $(ROOTLIBFSTYPE)/mount : FILEMODE= 0555 CFLAGS += $(CCVERBOSE) CERRWARN += -Wno-parentheses LDLIBS += -lsmbfs # Hammerhead: GNU ld needs rpath-link to resolve mech_krb5.so.1 (transitive dep of libsmbfs) LDFLAGS += -Wl,-rpath-link,$(ROOT)/usr/lib/gss CPPFLAGS += -I$(SRC)/uts/common -I$(SRC)/lib/libsmbfs .KEEP_STATE: all: $(ROOTFS_PROG) POFILE= mount.po catalog: $(POFILE) install: $(ROOTLIBFSTYPEPROG) clean: $(RM) $(OBJS) $(POFILE) /* * Copyright (c) 2000-2001, Boris Popov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Boris Popov. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: mount_smbfs.c,v 1.28.44.2 2005/06/02 00:55:41 lindak Exp $ */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright 2019 Nexenta by DDN, Inc. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* This needs to know ctx->ct_dev_fd, etc. */ #include extern char *optarg; extern int optind; static char mount_point[MAXPATHLEN + 1]; static void usage(void); static int setsubopt(smb_ctx_t *, struct smbfs_args *, char *); const char * const optlist[] = { /* Generic VFS options. */ #define OPT_RO 0 MNTOPT_RO, #define OPT_RW 1 MNTOPT_RW, #define OPT_SUID 2 MNTOPT_SUID, #define OPT_NOSUID 3 MNTOPT_NOSUID, #define OPT_DEVICES 4 MNTOPT_DEVICES, #define OPT_NODEVICES 5 MNTOPT_NODEVICES, #define OPT_SETUID 6 MNTOPT_SETUID, #define OPT_NOSETUID 7 MNTOPT_NOSETUID, #define OPT_EXEC 8 MNTOPT_EXEC, #define OPT_NOEXEC 9 MNTOPT_NOEXEC, #define OPT_XATTR 10 MNTOPT_XATTR, #define OPT_NOXATTR 11 MNTOPT_NOXATTR, /* Sort of generic (from NFS) */ #define OPT_NOAC 12 MNTOPT_NOAC, #define OPT_ACTIMEO 13 MNTOPT_ACTIMEO, #define OPT_ACREGMIN 14 MNTOPT_ACREGMIN, #define OPT_ACREGMAX 15 MNTOPT_ACREGMAX, #define OPT_ACDIRMIN 16 MNTOPT_ACDIRMIN, #define OPT_ACDIRMAX 17 MNTOPT_ACDIRMAX, /* smbfs-specifis options */ #define OPT_DOMAIN 18 "domain", #define OPT_USER 19 "user", #define OPT_UID 20 "uid", #define OPT_GID 21 "gid", #define OPT_DIRPERMS 22 "dirperms", #define OPT_FILEPERMS 23 "fileperms", #define OPT_NOPROMPT 24 "noprompt", #define OPT_ACL 25 MNTOPT_ACL, #define OPT_NOACL 26 MNTOPT_NOACL, NULL }; static int Oflg = 0; /* Overlay mounts */ static int qflg = 0; /* quiet - don't print warnings on bad options */ static int noprompt = 0; /* don't prompt for password */ /* Note: smbfs uses _both_ kinds of options. */ static int mntflags = MS_DATA | MS_OPTIONSTR; #define EX_OK 0 /* normal */ #define EX_OPT 1 /* bad options, usage, etc */ #define EX_MNT 2 /* mount point problems, etc */ #define RET_ERR 3 /* later errors */ #define SERVICE "svc:/network/smb/client:default" struct smbfs_args mdata; struct mnttab mnt; /* * Initialize this with "rw" just to have something there, * so we don't have to decide whether to add a comma when * we strcat another option. Note the "rw" may be changed * to an "ro" by option processing. */ char optbuf[MAX_MNTOPT_STR] = "rw"; char special[MAXPATHLEN]; int main(int argc, char *argv[]) { struct smb_ctx *ctx = NULL; struct stat st; int opt, error, err2; static char *fstype = MNTTYPE_SMBFS; char *env; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif (void) textdomain(TEXT_DOMAIN); /* * Normal users are allowed to run "mount -F smbfs ..." * to mount on a directory they own. To allow that, this * program has an exec_attr that adds SYS_MOUNT priv. * * The __init_suid_priv call was designed for SUID programs, * but also works for privileges granted via exec_attr with * one difference: the added privileges are already effective * when the program starts, and remain effective after the call. * To make this work more like the SUID case we'll turn off the * additional privileges with a __priv_bracket() call here. * Later calls to __priv_bracket() make the extra privileges * effective only when we need them. */ if (__init_suid_priv(0, PRIV_SYS_MOUNT, (char *)NULL) < 0) { (void) fprintf(stderr, gettext("Insufficient privileges, " "%s should have sys_mount privilege via exec_attr\n"), argv[0]); exit(RET_ERR); } (void) __priv_bracket(PRIV_OFF); if (argc == 2) { if (strcmp(argv[1], "-h") == 0) { usage(); } else if (strcmp(argv[1], "-v") == 0) { errx(EX_OK, gettext("version %d.%d.%d"), SMBFS_VERSION / 100000, (SMBFS_VERSION % 10000) / 1000, (SMBFS_VERSION % 1000) / 100); } } if (argc < 3) usage(); /* Debugging support. */ if ((env = getenv("SMBFS_DEBUG")) != NULL) { smb_debug = atoi(env); if (smb_debug < 1) smb_debug = 1; } error = smb_lib_init(); if (error) exit(RET_ERR); mnt.mnt_mntopts = optbuf; bzero(&mdata, sizeof (mdata)); mdata.version = SMBFS_VERSION; /* smbfs mount version */ mdata.uid = (uid_t)-1; mdata.gid = (gid_t)-1; error = smb_ctx_alloc(&ctx); if (error) exit(RET_ERR); /* * Parse the UNC path so we have the server (etc.) * that we need during rcfile+sharectl parsing. */ if (argc < 3) usage(); error = smb_ctx_parseunc(ctx, argv[argc - 2], SMBL_SHARE, SMBL_SHARE, USE_DISKDEV, NULL); if (error) exit(EX_OPT); error = smb_ctx_readrc(ctx); if (error) exit(EX_OPT); while ((opt = getopt(argc, argv, "ro:Oq")) != -1) { switch (opt) { case 'O': Oflg++; break; case 'q': qflg++; break; case 'r': mntflags |= MS_RDONLY; break; case 'o': { char *nextopt, *comma, *sopt; int ret; for (sopt = optarg; sopt != NULL; sopt = nextopt) { comma = strchr(sopt, ','); if (comma) { nextopt = comma + 1; *comma = '\0'; } else nextopt = NULL; ret = setsubopt(ctx, &mdata, sopt); if (ret != 0) exit(EX_OPT); /* undo changes to optarg */ if (comma) *comma = ','; } break; } case '?': default: usage(); } } if (Oflg) mntflags |= MS_OVERLAY; if (mntflags & MS_RDONLY) { char *p; /* convert "rw"->"ro" */ if (p = strstr(optbuf, "rw")) { if (*(p+2) == ',' || *(p+2) == '\0') *(p+1) = 'o'; } } if (optind + 2 != argc) usage(); (void) snprintf(special, sizeof (special), "//%s/%s", ctx->ct_fullserver, ctx->ct_origshare); mnt.mnt_special = special; mnt.mnt_mountp = argv[optind+1]; if ((realpath(argv[optind+1], mount_point) == NULL) || (stat(mount_point, &st) == -1)) { err(EX_MNT, gettext("could not find mount point %s"), argv[optind+1]); } if (!S_ISDIR(st.st_mode)) { errno = ENOTDIR; err(EX_MNT, gettext("can't mount on %s"), mount_point); } /* * Fill in mdata defaults. */ if (mdata.uid == (uid_t)-1) mdata.uid = getuid(); if (mdata.gid == (gid_t)-1) mdata.gid = getgid(); if (mdata.file_mode == 0) mdata.file_mode = S_IRWXU; if (mdata.dir_mode == 0) { mdata.dir_mode = mdata.file_mode; if (mdata.dir_mode & S_IRUSR) mdata.dir_mode |= S_IXUSR; if (mdata.dir_mode & S_IRGRP) mdata.dir_mode |= S_IXGRP; if (mdata.dir_mode & S_IROTH) mdata.dir_mode |= S_IXOTH; } ctx->ct_ssn.ssn_owner = SMBM_ANY_OWNER; if (noprompt) ctx->ct_flags |= SMBCF_NOPWD; /* * Resolve the server address, * setup derived defaults. */ error = smb_ctx_resolve(ctx); if (error) exit(RET_ERR); /* * Have server, share, etc. from above: * smb_ctx_scan_argv, option settings. * Get the session and tree. */ again: error = smb_ctx_get_ssn(ctx); if (error == EAUTH && noprompt == 0) { err2 = smb_get_authentication(ctx); if (err2 == 0) goto again; } if (error) { smb_error(gettext("//%s: login failed"), error, ctx->ct_fullserver); exit(RET_ERR); } error = smb_ctx_get_tree(ctx); if (error) { smb_error(gettext("//%s/%s: tree connect failed"), error, ctx->ct_fullserver, ctx->ct_origshare); exit(RET_ERR); } /* * Have tree connection, now mount it. */ mdata.devfd = ctx->ct_dev_fd; /* Need sys_mount privilege for the mount call. */ (void) __priv_bracket(PRIV_ON); err2 = mount(mnt.mnt_special, mnt.mnt_mountp, mntflags, fstype, &mdata, sizeof (mdata), mnt.mnt_mntopts, MAX_MNTOPT_STR); (void) __priv_bracket(PRIV_OFF); if (err2 < 0) { if (errno != ENOENT) { err(EX_MNT, gettext("mount_smbfs: %s"), mnt.mnt_mountp); } else { struct stat sb; if (stat(mnt.mnt_mountp, &sb) < 0 && errno == ENOENT) err(EX_MNT, gettext("mount_smbfs: %s"), mnt.mnt_mountp); else err(EX_MNT, gettext("mount_smbfs: %s"), mnt.mnt_special); } } smb_ctx_free(ctx); return (0); } #define bad(val) (val == NULL || !isdigit(*val)) int setsubopt(smb_ctx_t *ctx, struct smbfs_args *mdatap, char *subopt) { char *equals, *optarg; struct passwd *pwd; struct group *grp; long val; int rc = EX_OK; int index; char *p; equals = strchr(subopt, '='); if (equals) { *equals = '\0'; optarg = equals + 1; } else optarg = NULL; for (index = 0; optlist[index] != NULL; index++) { if (strcmp(subopt, optlist[index]) == 0) break; } /* * Note: if the option was unknown, index will * point to the NULL at the end of optlist[], * and we'll take the switch default. */ switch (index) { case OPT_ACL: case OPT_NOACL: case OPT_SUID: case OPT_NOSUID: case OPT_DEVICES: case OPT_NODEVICES: case OPT_SETUID: case OPT_NOSETUID: case OPT_EXEC: case OPT_NOEXEC: case OPT_XATTR: case OPT_NOXATTR: /* * These options are handled via the * generic option string mechanism. * None of these take an optarg. */ if (optarg != NULL) goto badval; (void) strlcat(optbuf, ",", sizeof (optbuf)); if (strlcat(optbuf, subopt, sizeof (optbuf)) >= sizeof (optbuf)) { if (!qflg) warnx(gettext("option string too long")); rc = EX_OPT; } break; /* * OPT_RO, OPT_RW, are actually generic too, * but we use the mntflags for these, and * then update the options string later. */ case OPT_RO: mntflags |= MS_RDONLY; break; case OPT_RW: mntflags &= ~MS_RDONLY; break; /* * NFS-derived options for attribute cache * handling (disable, set min/max timeouts) */ case OPT_NOAC: mdatap->flags |= SMBFS_MF_NOAC; break; case OPT_ACTIMEO: errno = 0; val = strtol(optarg, &p, 10); if (errno || *p != 0) goto badval; mdatap->acdirmin = mdatap->acregmin = val; mdatap->acdirmax = mdatap->acregmax = val; mdatap->flags |= SMBFS_MF_ACDIRMAX; mdatap->flags |= SMBFS_MF_ACREGMAX; mdatap->flags |= SMBFS_MF_ACDIRMIN; mdatap->flags |= SMBFS_MF_ACREGMIN; break; case OPT_ACREGMIN: errno = 0; val = strtol(optarg, &p, 10); if (errno || *p != 0) goto badval; mdatap->acregmin = val; mdatap->flags |= SMBFS_MF_ACREGMIN; break; case OPT_ACREGMAX: errno = 0; val = strtol(optarg, &p, 10); if (errno || *p != 0) goto badval; mdatap->acregmax = val; mdatap->flags |= SMBFS_MF_ACREGMAX; break; case OPT_ACDIRMIN: errno = 0; val = strtol(optarg, &p, 10); if (errno || *p != 0) goto badval; mdatap->acdirmin = val; mdatap->flags |= SMBFS_MF_ACDIRMIN; break; case OPT_ACDIRMAX: errno = 0; val = strtol(optarg, &p, 10); if (errno || *p != 0) goto badval; mdatap->acdirmax = val; mdatap->flags |= SMBFS_MF_ACDIRMAX; break; /* * SMBFS-specific options. Some of these * don't go through the mount system call, * but just set libsmbfs options. */ case OPT_DOMAIN: if (smb_ctx_setdomain(ctx, optarg, B_TRUE) != 0) rc = EX_OPT; break; case OPT_USER: if (smb_ctx_setuser(ctx, optarg, B_TRUE) != 0) rc = EX_OPT; break; case OPT_UID: pwd = isdigit(optarg[0]) ? getpwuid(atoi(optarg)) : getpwnam(optarg); if (pwd == NULL) { if (!qflg) warnx(gettext("unknown user '%s'"), optarg); rc = EX_OPT; } else { mdatap->uid = pwd->pw_uid; } break; case OPT_GID: grp = isdigit(optarg[0]) ? getgrgid(atoi(optarg)) : getgrnam(optarg); if (grp == NULL) { if (!qflg) warnx(gettext("unknown group '%s'"), optarg); rc = EX_OPT; } else { mdatap->gid = grp->gr_gid; } break; case OPT_DIRPERMS: errno = 0; val = strtol(optarg, &p, 8); if (errno || *p != 0) goto badval; mdatap->dir_mode = val; break; case OPT_FILEPERMS: errno = 0; val = strtol(optarg, &p, 8); if (errno || *p != 0) goto badval; mdatap->file_mode = val; break; case OPT_NOPROMPT: noprompt++; break; default: if (!qflg) warnx(gettext("unknown option %s"), subopt); rc = EX_OPT; break; badval: if (!qflg) warnx(gettext("invalid value for %s"), subopt); rc = EX_OPT; break; } /* Undo changes made to subopt */ if (equals) *equals = '='; return (rc); } static void usage(void) { (void) fprintf(stderr, "%s\n", gettext("usage: mount -F smbfs [-Orq] [-o option[,option]]" " //[workgroup;][user[:password]@]server[/share] path")); exit(EX_OPT); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # cmd/fs.d/smbclnt/scripts/Makefile FSTYPE= smbfs LIBPROG= dfshares share unshare include ../../Makefile.fstype POFILE= share.po unshare.po CLOBBERFILES+= $(LIBPROG) $(POFILE) catalog: $(POFILE) .KEEP_STATE: #!/usr/bin/sh # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # dfshares is a server utility but smbfs is a client # filesystem, so dfshares for smbfs will do nothing. # This utility is needed because smbfs is included in # /etc/dfs/fstypes. exit 0 #!/usr/bin/sh # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # This utility is needed because smbfs is included in # /etc/dfs/fstypes. echo `gettext "smbfs share is not supported"` 1>&2 exit 1 #!/usr/bin/sh # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # This utility is needed because smbfs is included in # /etc/dfs/fstypes. echo `gettext "smbfs unshare is not supported"` 1>&2 exit 1 # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # # Copyright (c) 2018, Joyent, Inc. FSTYPE= smbfs TYPEPROG= smbiod-svc include ../../Makefile.fstype OBJS= $(TYPEPROG).o SRCS= $(TYPEPROG).c POFILE= $(TYPEPROG).po CFLAGS += $(CCVERBOSE) CPPFLAGS += -I$(SRC)/lib/libsmbfs \ -I$(SRC)/uts/common/smbclnt -I$(SRC)/uts/common # not linted SMATCH=off # Debugging - Hammerhead: converted from dmake conditional ifneq ($(NOT_RELEASE_BUILD),$(POUND_SIGN)) CPPFLAGS += -DDEBUG endif all: $(TYPEPROG) catalog: $(POFILE) clean: $(RM) $(OBJS) $(POFILE) .KEEP_STATE: /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. */ /* * SMBFS I/O Daemon (SMF service) */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static boolean_t d_flag = B_FALSE; /* Keep a list of child processes. */ typedef struct _child { LIST_ENTRY(_child) list; pid_t pid; uid_t uid; } child_t; static LIST_HEAD(, _child) child_list = { 0 }; mutex_t cl_mutex = DEFAULTMUTEX; static const char smbiod_path[] = "/usr/lib/smbfs/smbiod"; static const char door_path[] = SMBIOD_SVC_DOOR; void svc_dispatch(void *cookie, char *argp, size_t argsz, door_desc_t *dp, uint_t n_desc); static int cmd_start(uid_t uid, gid_t gid); static int new_child(uid_t uid, gid_t gid); static void svc_sigchld(void); static void child_gone(uid_t, pid_t, int); static void svc_cleanup(void); static child_t * child_find_by_pid(pid_t pid) { child_t *cp; assert(MUTEX_HELD(&cl_mutex)); LIST_FOREACH(cp, &child_list, list) { if (cp->pid == pid) return (cp); } return (NULL); } static child_t * child_find_by_uid(uid_t uid) { child_t *cp; assert(MUTEX_HELD(&cl_mutex)); LIST_FOREACH(cp, &child_list, list) { if (cp->uid == uid) return (cp); } return (NULL); } /* * Find out if the service is already running. * Return: true, false. */ static boolean_t already_running(void) { door_info_t info; int fd, rc; if ((fd = open(door_path, O_RDONLY)) < 0) return (B_FALSE); rc = door_info(fd, &info); close(fd); if (rc < 0) return (B_FALSE); return (B_TRUE); } /* * This function will fork off a child process, * from which only the child will return. * * The parent exit status is taken as the SMF start method * success or failure, so the parent waits (via pipe read) * for the child to finish initialization before it exits. * Use SMF error codes only on exit. */ static int daemonize_init(void) { int pid, st; int pfds[2]; chdir("/"); if (pipe(pfds) < 0) { perror("pipe"); exit(SMF_EXIT_ERR_FATAL); } if ((pid = fork1()) == -1) { perror("fork"); exit(SMF_EXIT_ERR_FATAL); } /* * If we're the parent process, wait for either the child to send us * the appropriate exit status over the pipe or for the read to fail * (presumably with 0 for EOF if our child terminated abnormally). * If the read fails, exit with either the child's exit status if it * exited or with SMF_EXIT_ERR_FATAL if it died from a fatal signal. */ if (pid != 0) { /* parent */ close(pfds[1]); if (read(pfds[0], &st, sizeof (st)) == sizeof (st)) _exit(st); if (waitpid(pid, &st, 0) == pid && WIFEXITED(st)) _exit(WEXITSTATUS(st)); _exit(SMF_EXIT_ERR_FATAL); } /* child */ close(pfds[0]); return (pfds[1]); } static void daemonize_fini(int pfd, int rc) { /* Tell parent we're ready. */ (void) write(pfd, &rc, sizeof (rc)); close(pfd); } int main(int argc, char **argv) { sigset_t oldmask, tmpmask; struct sigaction sa; struct rlimit rl; int door_fd = -1, tmp_fd = -1, pfd = -1; int c, sig; int rc = SMF_EXIT_ERR_FATAL; boolean_t created = B_FALSE, attached = B_FALSE; /* set locale and text domain for i18n */ (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); while ((c = getopt(argc, argv, "d")) != -1) { switch (c) { case 'd': /* Do debug messages. */ d_flag = B_TRUE; break; default: fprintf(stderr, "Usage: %s [-d]\n", argv[0]); return (SMF_EXIT_ERR_CONFIG); } } if (already_running()) { fprintf(stderr, "%s: already running", argv[0]); return (rc); } /* * Raise the fd limit to max * errors here are non-fatal */ if (getrlimit(RLIMIT_NOFILE, &rl) != 0) { fprintf(stderr, "getrlimit failed, err %d\n", errno); } else if (rl.rlim_cur < rl.rlim_max) { rl.rlim_cur = rl.rlim_max; if (setrlimit(RLIMIT_NOFILE, &rl) != 0) fprintf(stderr, "setrlimit " "RLIMIT_NOFILE %d, err %d", (int)rl.rlim_cur, errno); } /* * Want all signals blocked, as we're doing * synchronous delivery via sigwait below. */ sigfillset(&tmpmask); sigprocmask(SIG_BLOCK, &tmpmask, &oldmask); /* * Do want SIGCHLD, and will waitpid(). */ sa.sa_flags = SA_NOCLDSTOP; sa.sa_handler = SIG_DFL; sigemptyset(&sa.sa_mask); sigaction(SIGCHLD, &sa, NULL); /* * Daemonize, unless debugging. */ if (d_flag) { /* debug: run in foregound (not a service) */ putenv("SMBFS_DEBUG=1"); } else { /* Non-debug: start daemon in the background. */ pfd = daemonize_init(); } /* * Create directory for all smbiod doors. */ if ((mkdir(SMBIOD_RUNDIR, 0755) < 0) && errno != EEXIST) { perror(SMBIOD_RUNDIR); goto out; } /* * Create a file for the main service door. */ unlink(door_path); tmp_fd = open(door_path, O_RDWR|O_CREAT|O_EXCL, 0644); if (tmp_fd < 0) { perror(door_path); goto out; } close(tmp_fd); tmp_fd = -1; created = B_TRUE; /* Setup the door service. */ door_fd = door_create(svc_dispatch, NULL, DOOR_REFUSE_DESC | DOOR_NO_CANCEL); if (door_fd == -1) { perror("svc door_create"); goto out; } fdetach(door_path); if (fattach(door_fd, door_path) < 0) { fprintf(stderr, "%s: fattach failed, %s\n", door_path, strerror(errno)); goto out; } attached = B_TRUE; /* * Initializations done. Tell start method we're up. */ rc = SMF_EXIT_OK; if (pfd != -1) { daemonize_fini(pfd, rc); pfd = -1; } /* * Main thread just waits for signals. */ again: sig = sigwait(&tmpmask); if (d_flag) fprintf(stderr, "main: sig=%d\n", sig); switch (sig) { case SIGINT: case SIGTERM: /* * The whole process contract gets a SIGTERM * at once. Give children a chance to exit * so we can do normal SIGCHLD cleanup. * Prevent new door_open calls. */ fdetach(door_path); attached = B_FALSE; alarm(2); goto again; case SIGALRM: break; /* normal termination */ case SIGCHLD: svc_sigchld(); goto again; case SIGCONT: goto again; default: /* Unexpected signal. */ fprintf(stderr, "svc_main: unexpected sig=%d\n", sig); break; } out: if (attached) fdetach(door_path); if (door_fd != -1) door_revoke(door_fd); if (created) unlink(door_path); /* NB: door threads gone now. */ svc_cleanup(); /* If startup error, report to parent. */ if (pfd != -1) daemonize_fini(pfd, rc); return (rc); } /*ARGSUSED*/ void svc_dispatch(void *cookie, char *argp, size_t argsz, door_desc_t *dp, uint_t n_desc) { ucred_t *ucred = NULL; uid_t uid; gid_t gid; int32_t cmd, rc; /* * Allow a NULL arg call to check if this * daemon is running. Just return zero. */ if (argp == NULL) { rc = 0; goto out; } /* * Get the caller's credentials. * (from client side of door) */ if (door_ucred(&ucred) != 0) { rc = EACCES; goto out; } uid = ucred_getruid(ucred); gid = ucred_getrgid(ucred); /* * Arg is just an int command code. * Reply is also an int. */ if (argsz != sizeof (cmd)) { rc = EINVAL; goto out; } bcopy(argp, &cmd, sizeof (cmd)); switch (cmd) { case SMBIOD_START: rc = cmd_start(uid, gid); break; default: rc = EINVAL; goto out; } out: if (ucred != NULL) ucred_free(ucred); door_return((void *)&rc, sizeof (rc), NULL, 0); } /* * Start a per-user smbiod, if not already running. */ int cmd_start(uid_t uid, gid_t gid) { char door_file[64]; child_t *cp; int pid, fd = -1; mutex_lock(&cl_mutex); cp = child_find_by_uid(uid); if (cp != NULL) { /* This UID already has an IOD. */ mutex_unlock(&cl_mutex); if (d_flag) { fprintf(stderr, "cmd_start: uid %d" " already has an iod\n", uid); } return (0); } /* * OK, create a new child. */ cp = malloc(sizeof (*cp)); if (cp == NULL) { mutex_unlock(&cl_mutex); return (ENOMEM); } cp->pid = 0; /* update below */ cp->uid = uid; LIST_INSERT_HEAD(&child_list, cp, list); mutex_unlock(&cl_mutex); /* * The child will not have permission to create or * destroy files in SMBIOD_RUNDIR so do that here. */ snprintf(door_file, sizeof (door_file), SMBIOD_USR_DOOR, cp->uid); unlink(door_file); fd = open(door_file, O_RDWR|O_CREAT|O_EXCL, 0600); if (fd < 0) { perror(door_file); goto errout; } if (fchown(fd, uid, gid) < 0) { perror(door_file); goto errout; } close(fd); fd = -1; if ((pid = fork1()) == -1) { perror("fork"); goto errout; } if (pid == 0) { (void) new_child(uid, gid); _exit(1); } /* parent */ cp->pid = pid; if (d_flag) { fprintf(stderr, "cmd_start: uid %d new iod, pid %d\n", uid, pid); } return (0); errout: if (fd != -1) close(fd); mutex_lock(&cl_mutex); LIST_REMOVE(cp, list); mutex_unlock(&cl_mutex); free(cp); return (errno); } /* * Assume the passed credentials (from the door client), * drop any extra privileges, and exec the per-user iod. */ static int new_child(uid_t uid, gid_t gid) { char *argv[2]; int flags, rc; flags = PU_RESETGROUPS | PU_LIMITPRIVS | PU_INHERITPRIVS; rc = __init_daemon_priv(flags, uid, gid, PRIV_NET_ACCESS, NULL); if (rc != 0) return (errno); argv[0] = "smbiod"; argv[1] = NULL; (void) execv(smbiod_path, argv); return (errno); } static void svc_sigchld(void) { child_t *cp; pid_t pid; int err, status, found = 0; mutex_lock(&cl_mutex); while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { found++; if (d_flag) fprintf(stderr, "svc_sigchld: pid %d\n", (int)pid); cp = child_find_by_pid(pid); if (cp == NULL) { fprintf(stderr, "Unknown pid %d\n", (int)pid); continue; } child_gone(cp->uid, cp->pid, status); LIST_REMOVE(cp, list); free(cp); } err = errno; mutex_unlock(&cl_mutex); /* ECHILD is the normal end of loop. */ if (pid < 0 && err != ECHILD) fprintf(stderr, "svc_sigchld: waitpid err %d\n", err); if (found == 0) fprintf(stderr, "svc_sigchld: no children?\n"); } static void child_gone(uid_t uid, pid_t pid, int status) { char door_file[64]; int x; if (d_flag) fprintf(stderr, "child_gone: uid %d pid %d\n", uid, (int)pid); snprintf(door_file, sizeof (door_file), SMBIOD_RUNDIR "/%d", uid); unlink(door_file); if (WIFEXITED(status)) { x = WEXITSTATUS(status); if (x != 0) { fprintf(stderr, "uid %d, pid %d exit %d\n", uid, (int)pid, x); } } if (WIFSIGNALED(status)) { x = WTERMSIG(status); fprintf(stderr, "uid %d, pid %d signal %d\n", uid, (int)pid, x); } } /* * Final cleanup before exit. Unlink child doors, etc. * Called while single threaded, so no locks needed here. * The list is normally empty by now due to svc_sigchld * calls during shutdown. But in case there were any * straglers, do cleanup here. Don't bother freeing any * list elements here, as we're exiting. */ static void svc_cleanup(void) { child_t *cp; LIST_FOREACH(cp, &child_list, list) { child_gone(cp->uid, cp->pid, 0); } } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2018, Joyent, Inc. # # # cmd/fs.d/smbclnt/smbiod/Makefile # FSTYPE= smbfs TYPEPROG= smbiod include ../../Makefile.fstype OBJS= $(TYPEPROG).o SRCS= $(TYPEPROG).c POFILE= $(TYPEPROG).po CFLAGS += $(CCVERBOSE) LDLIBS += -lsmbfs -lumem # Hammerhead: GNU ld needs rpath-link to resolve mech_krb5.so.1 (transitive dep of libsmbfs) LDFLAGS += -Wl,-rpath-link,$(ROOT)/usr/lib/gss CPPFLAGS += -I$(SRC)/lib/libsmbfs \ -I$(SRC)/uts/common/smbclnt -I$(SRC)/uts/common # not linted SMATCH=off # Debugging - Hammerhead: converted from dmake conditional ifneq ($(NOT_RELEASE_BUILD),$(POUND_SIGN)) CPPFLAGS += -DDEBUG endif all: $(TYPEPROG) catalog: $(POFILE) clean: $(RM) $(OBJS) $(POFILE) .KEEP_STATE: /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2012 Nexenta Systems, Inc. All rights reserved. */ /* * SMBFS I/O Daemon (Per-user IOD) */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DPRINT(...) do \ { \ if (smb_debug) \ fprintf(stderr, __VA_ARGS__); \ _NOTE(CONSTCOND) \ } while (0) mutex_t iod_mutex = DEFAULTMUTEX; int iod_thr_count; /* threads, excluding main */ int iod_terminating; int iod_alarm_time = 30; /* sec. */ void iod_dispatch(void *cookie, char *argp, size_t argsz, door_desc_t *dp, uint_t n_desc); int iod_newvc(smb_iod_ssn_t *clnt_ssn); void * iod_work(void *arg); int main(int argc, char **argv) { sigset_t oldmask, tmpmask; char *env, *door_path = NULL; int door_fd = -1; int err, sig; int rc = SMF_EXIT_ERR_FATAL; boolean_t attached = B_FALSE; /* set locale and text domain for i18n */ (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); /* Debugging support. */ if ((env = getenv("SMBFS_DEBUG")) != NULL) { smb_debug = atoi(env); if (smb_debug < 1) smb_debug = 1; iod_alarm_time = 300; } /* * If a user runs this command (i.e. by accident) * don't interfere with any already running IOD. */ err = smb_iod_open_door(&door_fd); if (err == 0) { close(door_fd); door_fd = -1; DPRINT("%s: already running\n", argv[0]); exit(SMF_EXIT_OK); } /* * Want all signals blocked, as we're doing * synchronous delivery via sigwait below. */ sigfillset(&tmpmask); sigprocmask(SIG_BLOCK, &tmpmask, &oldmask); /* Setup the door service. */ door_path = smb_iod_door_path(); door_fd = door_create(iod_dispatch, NULL, DOOR_REFUSE_DESC | DOOR_NO_CANCEL); if (door_fd == -1) { perror("iod door_create"); goto out; } fdetach(door_path); if (fattach(door_fd, door_path) < 0) { fprintf(stderr, "%s: fattach failed, %s\n", door_path, strerror(errno)); goto out; } attached = B_TRUE; /* Initializations done. */ rc = SMF_EXIT_OK; /* * Post the initial alarm, and then just * wait for signals. */ alarm(iod_alarm_time); again: sig = sigwait(&tmpmask); DPRINT("main: sig=%d\n", sig); switch (sig) { case SIGCONT: goto again; case SIGALRM: /* No threads active for a while. */ mutex_lock(&iod_mutex); if (iod_thr_count > 0) { /* * Door call thread creation raced with * the alarm. Ignore this alaram. */ mutex_unlock(&iod_mutex); goto again; } /* Prevent a race with iod_thr_count */ iod_terminating = 1; mutex_unlock(&iod_mutex); break; case SIGINT: case SIGTERM: break; /* normal termination */ default: /* Unexpected signal. */ fprintf(stderr, "iod_main: unexpected sig=%d\n", sig); break; } out: iod_terminating = 1; if (attached) fdetach(door_path); if (door_fd != -1) door_revoke(door_fd); /* * We need a reference in -lumem to satisfy check_rtime, * else we get build hoise. This is sufficient. */ free(NULL); return (rc); } /*ARGSUSED*/ void iod_dispatch(void *cookie, char *argp, size_t argsz, door_desc_t *dp, uint_t n_desc) { smb_iod_ssn_t *ssn; ucred_t *ucred; uid_t cl_uid; int rc; /* * Verify that the calling process has the same UID. * Paranoia: The door we created has mode 0600, so * this check is probably redundant. */ ucred = NULL; if (door_ucred(&ucred) != 0) { rc = EACCES; goto out; } cl_uid = ucred_getruid(ucred); ucred_free(ucred); ucred = NULL; if (cl_uid != getuid()) { DPRINT("iod_dispatch: wrong UID\n"); rc = EACCES; goto out; } /* * The library uses a NULL arg call to check if * the daemon is running. Just return zero. */ if (argp == NULL) { rc = 0; goto out; } /* * Otherwise, the arg must be the (fixed size) * smb_iod_ssn_t */ if (argsz != sizeof (*ssn)) { rc = EINVAL; goto out; } mutex_lock(&iod_mutex); if (iod_terminating) { mutex_unlock(&iod_mutex); DPRINT("iod_dispatch: terminating\n"); rc = EINTR; goto out; } if (iod_thr_count++ == 0) { alarm(0); DPRINT("iod_dispatch: cancelled alarm\n"); } mutex_unlock(&iod_mutex); ssn = (void *) argp; rc = iod_newvc(ssn); mutex_lock(&iod_mutex); if (--iod_thr_count == 0) { DPRINT("iod_dispatch: schedule alarm\n"); alarm(iod_alarm_time); } mutex_unlock(&iod_mutex); out: door_return((void *)&rc, sizeof (rc), NULL, 0); } /* * Try making a connection with the server described by * the info in the smb_iod_ssn_t arg. If successful, * start an IOD thread to service it, then return to * the client side of the door. */ int iod_newvc(smb_iod_ssn_t *clnt_ssn) { smb_ctx_t *ctx; thread_t tid; int err; /* * This needs to essentially "clone" the smb_ctx_t * from the client side of the door, or at least * as much of it as we need while creating a VC. */ err = smb_ctx_alloc(&ctx); if (err) return (err); bcopy(clnt_ssn, &ctx->ct_iod_ssn, sizeof (ctx->ct_iod_ssn)); /* * Create the driver session first, so that any subsequent * requests for the same session will find this one and * wait, the same as when a reconnect is triggered. * * There is still an inherent race here, where two callers * both find no VC in the driver, and both come here trying * to create the VC. In this case, we want the first one * to actually do the VC setup, and the second to proceed * as if the VC had been found in the driver. The second * caller gets an EEXIST error from the ioctl in this case, * which we therefore ignore here so that the caller will * go ahead and look again in the driver for the new VC. */ if ((err = smb_ctx_gethandle(ctx)) != 0) goto out; if (ioctl(ctx->ct_dev_fd, SMBIOC_SSN_CREATE, &ctx->ct_ssn) < 0) { err = errno; if (err == EEXIST) err = 0; /* see above */ goto out; } /* * Do the initial connection setup here, so we can * report the outcome to the door client. */ err = smb_iod_connect(ctx); if (err != 0) goto out; /* The rest happens in the iod_work thread. */ err = thr_create(NULL, 0, iod_work, ctx, THR_DETACHED, &tid); if (err == 0) { /* * Given to the new thread. * free at end of iod_work */ ctx = NULL; } out: if (ctx) smb_ctx_free(ctx); return (err); } /* * Be the reader thread for some VC. * * This is started by a door call thread, which means * this is always at least the 2nd thread, therefore * it should never see thr_count==0 or terminating. */ void * iod_work(void *arg) { smb_ctx_t *ctx = arg; mutex_lock(&iod_mutex); if (iod_thr_count++ == 0) { alarm(0); DPRINT("iod_work: cancelled alarm\n"); } mutex_unlock(&iod_mutex); (void) smb_iod_work(ctx); mutex_lock(&iod_mutex); if (--iod_thr_count == 0) { DPRINT("iod_work: schedule alarm\n"); alarm(iod_alarm_time); } mutex_unlock(&iod_mutex); smb_ctx_free(ctx); return (NULL); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright 2018 Nexenta Systems, Inc. All rights reserved. # Copyright (c) 2018, Joyent, Inc. # # # cmd/fs.d/smbclnt/smbutil/Makefile # PROG= smbutil OBJS= smbutil.o discon.o info.o login.o lookup.o print.o status.o view.o \ shares_rpc.o srvsvc1_clnt.o srvsvc1_ndr.o include $(SRC)/cmd/Makefile.cmd POFILE= smbutil_all.po POFILES= $(OBJS:%.o=%.po) CLEANFILES += srvsvc1_ndr.c CLOBBERFILES+= $(POFILE) $(POFILES) CSTD= $(CSTD_GNU99) LDLIBS += -lmlrpc -lsmbfs -lnsl # Hammerhead: GNU ld needs rpath-link to resolve mech_krb5.so.1 (transitive dep of libsmbfs) LDFLAGS += -Wl,-rpath-link,$(ROOT)/usr/lib/gss CPPFLAGS += -I$(SRC)/lib/libsmbfs \ -I$(SRC)/uts/common/smbclnt -I$(SRC)/uts/common # not linted SMATCH=off # Debugging $(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG all: $(PROG) $(PROG): $(OBJS) $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(POST_PROCESS) install: all $(ROOTPROG) $(ROOTPROG): $(PROG) $(INS.file) catalog: $(POFILE) $(POFILE): $(POFILES) $(RM) $@ $(CAT) $(POFILES) > $@ clean: $(RM) $(OBJS) $(CLEANFILES) include ../../../Makefile.targ srvsvc1_ndr.c : srvsvc1.ndl $(NDRGEN) -Y $(ANSI_CPP) $(CPPFLAGS) srvsvc1.ndl .KEEP_STATE: /* * Copyright (c) 2000, Boris Popov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Boris Popov. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Copyright 2013 Nexenta Systems, Inc. All rights reserved. */ #ifndef _SMBUTIL_COMMON_H #define _SMBUTIL_COMMON_H #ifdef __cplusplus extern "C" { #endif #include #include int cmd_crypt(int argc, char *argv[]); int cmd_discon(int argc, char *argv[]); int cmd_help(int argc, char *argv[]); int cmd_info(int argc, char *argv[]); int cmd_login(int argc, char *argv[]); int cmd_logout(int argc, char *argv[]); int cmd_logoutall(int argc, char *argv[]); int cmd_lookup(int argc, char *argv[]); int cmd_print(int argc, char *argv[]); int cmd_status(int argc, char *argv[]); int cmd_view(int argc, char *argv[]); void crypt_usage(void); void discon_usage(void); void help_usage(void); void info_usage(void); void login_usage(void); void logout_usage(void); void logoutall_usage(void); void lookup_usage(void); void print_usage(void); void status_usage(void); void view_usage(void); /* See view.c */ int share_enum_rap(struct smb_ctx *ctx); int share_enum_rpc(struct smb_ctx *ctx, char *server); void view_print_share(char *share, int type, char *comment); #ifdef __cplusplus } #endif #endif /* _SMBUTIL_COMMON_H */ /* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* * smbutil "discon" sub-command to disconnect a session * (mostly for usr/src/test/smbclient-tests) */ #include #include #include #include #include #include #include #include #include #include #include #include "common.h" void discon_usage(void) { printf(gettext("usage: smbutil discon [connection options] " "//[workgroup;][user@]server\n")); exit(1); } int cmd_discon(int argc, char *argv[]) { struct smb_ctx *ctx; int error, opt; if (argc < 2) discon_usage(); error = smb_ctx_alloc(&ctx); if (error != 0) return (error); error = smb_ctx_scan_argv(ctx, argc, argv, SMBL_SERVER, SMBL_SERVER, USE_WILDCARD); if (error != 0) goto out; error = smb_ctx_readrc(ctx); if (error != 0) goto out; while ((opt = getopt(argc, argv, STDPARAM_OPT)) != EOF) { if (opt == '?') discon_usage(); error = smb_ctx_opt(ctx, opt, optarg); if (error != 0) goto out; } /* * Resolve the server address, * setup derived defaults. */ error = smb_ctx_resolve(ctx); if (error != 0) goto out; /* * Have server, user, etc. from above: * smb_ctx_scan_argv, option settings. * * Lookup a session without creating. * (First part of smb_ctx_get_ssn) * If we find the session, kill it. */ error = smb_ctx_findvc(ctx); if (error == ENOENT) { /* Already gone. We're done. */ if (smb_debug) fprintf(stderr, "session not found\n"); error = 0; goto out; } if (error == 0) { /* Found session. Kill it. */ error = smb_ctx_kill(ctx); } if (error != 0) { smb_error(gettext("//%s: discon failed"), error, ctx->ct_fullserver); } out: smb_ctx_free(ctx); return (error); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright 2013 Nexenta Systems, Inc. All rights reserved. */ /* * Show information about the remote server, as offered by * NetServerGetInfo with SERVER_INFO_101 */ #include #include #include #include #include #include #include #include #include "srvsvc1_clnt.h" #include "common.h" static int get_info(smb_ctx_t *); void info_usage(void) { printf(gettext("usage: smbutil info [connection options] //" "[workgroup;][user[:password]@]server\n")); exit(1); } int cmd_info(int argc, char *argv[]) { struct smb_ctx *ctx; int error, err2, opt; if (argc < 2) info_usage(); error = smb_ctx_alloc(&ctx); if (error) return (error); error = smb_ctx_scan_argv(ctx, argc, argv, SMBL_SERVER, SMBL_SERVER, USE_WILDCARD); if (error) goto out; error = smb_ctx_readrc(ctx); if (error) goto out; while ((opt = getopt(argc, argv, STDPARAM_OPT)) != EOF) { if (opt == '?') info_usage(); error = smb_ctx_opt(ctx, opt, optarg); if (error) goto out; } smb_ctx_setshare(ctx, "IPC$", USE_IPC); /* * Resolve the server address, * setup derived defaults. */ error = smb_ctx_resolve(ctx); if (error) goto out; /* * Have server, share, etc. from above: * smb_ctx_scan_argv, option settings. * Get the session and tree. */ again: error = smb_ctx_get_ssn(ctx); if (error == EAUTH) { err2 = smb_get_authentication(ctx); if (err2 == 0) goto again; } if (error) { smb_error(gettext("//%s: login failed"), error, ctx->ct_fullserver); goto out; } error = smb_ctx_get_tree(ctx); if (error) { smb_error(gettext("//%s/%s: tree connect failed"), error, ctx->ct_fullserver, ctx->ct_origshare); goto out; } /* * Have IPC$ tcon. Get the server info. */ error = get_info(ctx); if (error) smb_error("cannot get server info.", error); out: smb_ctx_free(ctx); return (error); } int get_info(smb_ctx_t *ctx) { char pf_unk[32]; mlrpc_handle_t handle; ndr_service_t *svc; union mslm_NetServerGetInfo_ru res; struct mslm_SERVER_INFO_101 *sv101; char *platform_name; int err; /* * Create an RPC handle using the smb_ctx we already have. * Just local allocation and initialization. */ srvsvc1_initialize(); svc = ndr_svc_lookup_name("srvsvc"); if (svc == NULL) return (ENOENT); err = mlrpc_clh_create(&handle, ctx); if (err) return (err); /* * Try to bind to the RPC service. If it fails, * just return the error and the caller will * fall back to RAP. */ err = mlrpc_clh_bind(&handle, svc); if (err) goto out; err = srvsvc_net_server_getinfo(&handle, ctx->ct_fullserver, 101, &res); if (err) goto out; sv101 = res.info101; switch (sv101->sv101_platform_id) { case SV_PLATFORM_ID_DOS: platform_name = "DOS"; break; case SV_PLATFORM_ID_OS2: platform_name = "OS2"; break; case SV_PLATFORM_ID_NT: platform_name = "NT"; break; case SV_PLATFORM_ID_OSF: platform_name = "OSF"; break; case SV_PLATFORM_ID_VMS: platform_name = "VMS"; break; default: platform_name = pf_unk; snprintf(pf_unk, sizeof (pf_unk), "(%d)", sv101->sv101_platform_id); break; } printf("server info:\n"); printf(" platform_id %s\n", platform_name); printf(" vers.major %d\n", sv101->sv101_version_major); printf(" vers.minor %d\n", sv101->sv101_version_minor); if (smb_verbose) printf(" type_flags 0x%x\n", sv101->sv101_type); printf(" name \"%s\"\n", sv101->sv101_name); printf(" comment \"%s\"\n", sv101->sv101_comment); out: (void) mlrpc_clh_free(&handle); return (err); } /* * Copyright (c) 2000, Boris Popov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Boris Popov. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: login.c,v 1.8 2004/03/19 01:49:48 lindak Exp $ */ #include #include #include #include #include #include #include #include #include #include #include #include "common.h" /* defaults */ static char def_dom[256]; static char def_usr[256]; static char tmp_arg[256]; /* * Parse the string: domuser, which may be any of: * "user@domain" or "domain/user" or "domain\\user" * and return pointers to the domain and user parts. * Modifies the string domuser in-place. Returned * string pointers are within the string domusr. */ int smbfs_parse_domuser(char *domuser, char **dom, char **usr) { const char sep[] = "@/\\"; char sc, *p, *s1, *s2; p = strpbrk(domuser, sep); if (p == NULL) { /* No separators - whole string is the user. */ *dom = NULL; *usr = domuser; return (0); } /* Have two strings. */ s1 = domuser; sc = *p; /* Save the sep. char */ *p++ = '\0'; /* zap it */ s2 = p; /* Enforce just one separator */ p = strpbrk(s2, sep); if (p) return (-1); /* * Now, which order are they? * "user@domain" or "domain/user" */ if (sc == '@') { *usr = s1; *dom = s2; } else { *dom = s1; *usr = s2; } return (0); } void login_usage(void) { printf(gettext("usage: smbutil login [-c] [[domain/]user]\n")); printf(gettext(" smbutil login [-c] [user[@domain]]\n")); exit(1); } int cmd_login(int argc, char *argv[]) { static char prompt[64]; char *dom, *usr, *pass; int err, opt; int check = 0; while ((opt = getopt(argc, argv, "c")) != EOF) { switch (opt) { case 'c': /* smbutil login -c ... */ check = 1; break; default: login_usage(); break; } } dom = usr = NULL; if (optind < argc) { strcpy(tmp_arg, argv[optind]); err = smbfs_parse_domuser(tmp_arg, &dom, &usr); if (err) errx(1, gettext("failed to parse %s"), argv[optind]); optind++; } if (optind != argc) login_usage(); if (dom == NULL || usr == NULL) { err = smbfs_default_dom_usr(NULL, NULL, def_dom, sizeof (def_dom), def_usr, sizeof (def_usr)); if (err) errx(1, gettext("failed to get defaults")); } if (dom == NULL) dom = def_dom; else nls_str_upper(dom, dom); if (usr == NULL) usr = def_usr; if (check) { err = smbfs_keychain_chk(dom, usr); if (!err) printf(gettext("Keychain entry exists.\n")); else printf(gettext("Keychain entry not found.\n")); return (0); } snprintf(prompt, sizeof (prompt), gettext("Password for %s/%s:"), dom, usr); pass = getpassphrase(prompt); err = smbfs_keychain_add((uid_t)-1, dom, usr, pass); if (err) errx(1, gettext("failed to add keychain entry")); return (0); } void logout_usage(void) { printf(gettext("usage: smbutil logout [[domain/]user]\n")); printf(gettext(" smbutil logout [user[@domain]]\n")); printf(gettext(" smbutil logout -a\n")); exit(1); } int cmd_logout(int argc, char *argv[]) { char *dom, *usr; int err, opt; while ((opt = getopt(argc, argv, "a")) != EOF) { switch (opt) { case 'a': /* smbutil logout -a */ if (optind != argc) logout_usage(); err = smbfs_keychain_del_owner(); if (err) errx(1, gettext("failed to delete keychain entries")); return (0); default: logout_usage(); break; } } /* This part is like login. */ dom = usr = NULL; if (optind < argc) { strcpy(tmp_arg, argv[optind]); err = smbfs_parse_domuser(tmp_arg, &dom, &usr); if (err) errx(1, gettext("failed to parse %s"), argv[optind]); optind++; } if (optind != argc) logout_usage(); if (dom == NULL || usr == NULL) { err = smbfs_default_dom_usr(NULL, NULL, def_dom, sizeof (def_dom), def_usr, sizeof (def_usr)); if (err) errx(1, gettext("failed to get defaults")); } if (dom == NULL) dom = def_dom; else nls_str_upper(dom, dom); if (usr == NULL) usr = def_usr; err = smbfs_keychain_del((uid_t)-1, dom, usr); if (err) errx(1, gettext("failed to delete keychain entry")); return (0); } void logoutall_usage(void) { printf(gettext("usage: smbutil logoutall\n")); exit(1); } int cmd_logoutall(int argc, char *argv[]) { int err; if (optind != argc) logoutall_usage(); err = smbfs_keychain_del_everyone(); if (err == EPERM) { errx(1, gettext("You must have super-user privileges to use this sub-command\n")); } if (err) { errx(1, gettext("Failed to delete all keychain entries: %s\n"), smb_strerror(err)); } return (0); } /* * Copyright (c) 2000, Boris Popov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Boris Popov. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: lookup.c,v 1.1.1.1 2001/06/09 00:28:13 zarzycki Exp $ */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "common.h" int cmd_lookup(int argc, char *argv[]) { struct nb_ctx *ctx; struct sockaddr *sap; char *hostname; int error, opt; if (argc < 2) lookup_usage(); error = nb_ctx_create(&ctx); if (error) { smb_error(gettext("unable to create nbcontext"), error); exit(1); } if (smb_open_rcfile(NULL) == 0) { if (nb_ctx_readrcsection(NULL, ctx, "default", 0) != 0) exit(1); smb_close_rcfile(); } if ((ctx->nb_flags & NBCF_NS_ENABLE) == 0) { fprintf(stderr, gettext("nbns_enable=false, cannot do lookup\n")); exit(1); } while ((opt = getopt(argc, argv, "w:")) != EOF) { switch (opt) { case 'w': nb_ctx_setns(ctx, optarg); break; default: lookup_usage(); /*NOTREACHED*/ } } if (optind >= argc) lookup_usage(); if (nb_ctx_resolve(ctx) != 0) exit(1); hostname = argv[argc - 1]; error = nbns_resolvename(hostname, ctx, &sap); if (error) { smb_error(gettext("unable to resolve %s"), error, hostname); exit(1); } printf(gettext("Got response from %s\n"), inet_ntoa(ctx->nb_lastns.sin_addr)); printf(gettext("IP address of %s: %s\n"), hostname, inet_ntoa(((struct sockaddr_in *)sap)->sin_addr)); return (0); } void lookup_usage(void) { printf(gettext("usage: smbutil lookup [-w host] name\n")); exit(1); } /* * Copyright (c) 2000, Boris Popov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Boris Popov. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: Id: print.c,v 1.4 2001/01/28 07:35:01 bp Exp */ /* * Copyright 2011 Nexenta Systems, Inc. All rights reserved. * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include "common.h" static char titlebuf[256]; static char databuf[4096]; static int print_file(smb_ctx_t *, char *, int); void print_usage(void) { printf(gettext("usage: smbutil print [connection options] //" "[workgroup;][user[:password]@]" "server/share {print_file|-}\n")); exit(1); } int cmd_print(int argc, char *argv[]) { struct smb_ctx *ctx = NULL; char *filename; int error, opt; int file = -1; /* last arg is the print file. */ if (argc < 3) print_usage(); error = smb_ctx_alloc(&ctx); if (error) goto out; error = smb_ctx_scan_argv(ctx, argc-1, argv, SMBL_SHARE, SMBL_SHARE, USE_SPOOLDEV); if (error) goto out; error = smb_ctx_readrc(ctx); if (error) goto out; while ((opt = getopt(argc-1, argv, STDPARAM_OPT)) != EOF) { if (opt == '?') print_usage(); error = smb_ctx_opt(ctx, opt, optarg); if (error) goto out; } if (optind != argc-2) print_usage(); filename = argv[argc-1]; if (strcmp(filename, "-") == 0) { file = 0; /* stdin */ filename = "stdin"; } else { file = open(filename, O_RDONLY, 0); if (file < 0) { smb_error("could not open file %s\n", errno, filename); exit(1); } } /* * Resolve the server address, * setup derived defaults. */ error = smb_ctx_resolve(ctx); if (error) goto out; /* * Have server + share names, options etc. * Get the session and tree. */ again: error = smb_ctx_get_ssn(ctx); if (error == EAUTH) { int err2 = smb_get_authentication(ctx); if (err2 == 0) goto again; } if (error) { smb_error(gettext("//%s: login failed"), error, ctx->ct_fullserver); goto out; } error = smb_ctx_get_tree(ctx); if (error) { smb_error(gettext("//%s/%s: tree connect failed"), error, ctx->ct_fullserver, ctx->ct_origshare); goto out; } /* * Have the printer share connection. * Print the file. */ snprintf(titlebuf, sizeof (titlebuf), "%s %s", ctx->ct_user, filename); error = print_file(ctx, titlebuf, file); out: /* don't close stdin (file=0) */ if (file > 0) close(file); smb_ctx_free(ctx); return (error); } /* * Documentation for OPEN_PRINT_FILE is scarse. * It's in a 1996 MS doc. entitled: * SMB FILE SHARING PROTOCOL * * The extra parameters are: * SetupLength: what part of the file is printer setup * Mode: text or graphics (raw data) * IdentifierString: job title */ enum { MODE_TEXT = 0, /* TAB expansion, etc. */ MODE_GRAPHICS /* raw data */ }; static int print_file(smb_ctx_t *ctx, char *title, int file) { off_t offset; int rcnt, wcnt; int setup_len = 0; /* No printer setup data */ int mode = MODE_GRAPHICS; /* treat as raw data */ int error = 0; int pfd = -1; pfd = smb_open_printer(ctx, title, setup_len, mode); if (pfd < 0) { error = errno; smb_error("could not open print job", error); return (error); } offset = 0; for (;;) { rcnt = read(file, databuf, sizeof (databuf)); if (rcnt < 0) { error = errno; smb_error("error reading input file\n", error); break; } if (rcnt == 0) break; wcnt = smb_fh_write(pfd, offset, rcnt, databuf); if (wcnt < 0) { error = errno; smb_error("error writing spool file\n", error); break; } if (wcnt != rcnt) { smb_error("incomplete write to spool file\n", 0); error = EIO; break; } offset += wcnt; } (void) smb_fh_close(pfd); return (error); } /* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright 2013 Nexenta Systems, Inc. All rights reserved. */ /* * Share enumeration using Remote Procedure Call (RPC) */ #include #include #include #include #include #include #include #include "srvsvc1_clnt.h" #include "common.h" int share_enum_rpc(struct smb_ctx *ctx, char *server) { mlrpc_handle_t handle; ndr_service_t *svc; union mslm_NetShareEnum_ru res; struct mslm_NetShareInfo_1 *nsi1; int err, i, count; /* * Create an RPC handle using the smb_ctx we already have. * Just local allocation and initialization. */ srvsvc1_initialize(); svc = ndr_svc_lookup_name("srvsvc"); if (svc == NULL) return (ENOENT); err = mlrpc_clh_create(&handle, ctx); if (err) return (err); /* * Try to bind to the RPC service. If it fails, * just return the error and the caller will * fall back to RAP. */ err = mlrpc_clh_bind(&handle, svc); if (err) goto out; err = srvsvc_net_share_enum(&handle, server, 1, &res); if (err) goto out; /* Print the header line. */ view_print_share(NULL, 0, NULL); /* Print the share list. */ count = res.bufptr1->entriesread; i = 0, nsi1 = res.bufptr1->entries; while (i < count) { /* Convert UTF-8 to local code set? */ view_print_share((char *)nsi1->shi1_netname, nsi1->shi1_type, (char *)nsi1->shi1_comment); i++, nsi1++; } out: (void) mlrpc_clh_free(&handle); return (err); } /* * Copyright (c) 2000, Boris Popov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Boris Popov. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright 2018 Nexenta Systems, Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include "common.h" #ifndef EX_DATAERR #define EX_DATAERR 1 #endif static void help(void) __NORETURN; typedef int cmd_fn_t (int argc, char *argv[]); typedef void cmd_usage_t (void); #define CMDFL_NO_KMOD 0x0001 static struct commands { const char *name; cmd_fn_t *fn; cmd_usage_t *usage; int flags; } commands[] = { {"crypt", cmd_crypt, NULL, CMDFL_NO_KMOD}, {"discon", cmd_discon, discon_usage, 0}, {"help", cmd_help, help_usage, CMDFL_NO_KMOD}, {"info", cmd_info, info_usage, 0}, {"login", cmd_login, login_usage, 0}, {"logout", cmd_logout, logout_usage, 0}, {"logoutall", cmd_logoutall, logoutall_usage, 0}, {"lookup", cmd_lookup, lookup_usage, CMDFL_NO_KMOD}, {"print", cmd_print, print_usage, 0}, {"status", cmd_status, status_usage, CMDFL_NO_KMOD}, {"view", cmd_view, view_usage, 0}, {NULL, NULL, NULL, 0} }; static struct commands * lookupcmd(const char *name) { struct commands *cmd; for (cmd = commands; cmd->name; cmd++) { if (strcmp(cmd->name, name) == 0) return (cmd); } return (NULL); } int cmd_crypt(int argc, char *argv[]) { char *cp, *psw; if (argc < 2) psw = getpassphrase(gettext("Password:")); else psw = argv[1]; /* XXX Better to embed malloc/free in smb_simplecrypt? */ cp = malloc(4 + 2 * strlen(psw)); if (cp == NULL) errx(EX_DATAERR, gettext("out of memory")); smb_simplecrypt(cp, psw); printf("%s\n", cp); free(cp); return (0); } int cmd_help(int argc, char *argv[]) { struct commands *cmd; char *cp; if (argc < 2) help_usage(); cp = argv[1]; cmd = lookupcmd(cp); if (cmd == NULL) errx(EX_DATAERR, gettext("unknown command %s"), cp); if (cmd->usage == NULL) errx(EX_DATAERR, gettext("no specific help for command %s"), cp); cmd->usage(); return (0); } int main(int argc, char *argv[]) { struct commands *cmd; char *cp; int err, opt; (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); #ifdef APPLE dropsuid(); /* see libsmbfs */ #endif if (argc < 2) help(); while ((opt = getopt(argc, argv, "dhv")) != EOF) { switch (opt) { case 'd': smb_debug++; break; case 'h': help(); /* NOTREACHED */ case 'v': smb_verbose++; break; default: help(); /* NOTREACHED */ } } if (optind >= argc) help(); cp = argv[optind]; cmd = lookupcmd(cp); if (cmd == NULL) errx(EX_DATAERR, gettext("unknown command %s"), cp); if ((cmd->flags & CMDFL_NO_KMOD) == 0 && smb_lib_init() != 0) exit(1); argc -= optind; argv += optind; optind = 1; err = cmd->fn(argc, argv); return ((err) ? 1 : 0); } static void help(void) { printf("\n"); printf(gettext("usage: %s [-hv] subcommand [args]\n"), __progname); printf(gettext("where subcommands are:\n" " crypt slightly obscure password\n" " help display help on specified subcommand\n" " info display server type and version\n" " login login to specified host\n" " logout logout from specified host\n" " logoutall logout all users (requires privilege)\n" " lookup resolve NetBIOS name to IP address\n" " print print file to the specified remote printer\n" " status resolve IP address or DNS name to NetBIOS names\n" " view list resources on specified host\n" "\n")); exit(1); } void help_usage(void) { printf(gettext("usage: smbutil help command\n")); exit(1); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2013 Nexenta Systems, Inc. All rights reserved. */ /* * SRVSVC - Server Service (partial) * * This module needs only NetShareEnum (levels 0, 1) * and NetServerGetInfo (levels 100, 101) */ #include /* * SRVSVC - Server Service */ #define SRVSVC_OPNUM_NetShareEnum 0x0f #define SRVSVC_OPNUM_NetServerGetInfo 0x15 /* * SRVSVC NetShareEnum ( * IN LPTSTR servername, * IN DWORD level; * OUT union switch(level) { * case 0: struct { * DWORD entriesread; * [size_is(entriesread)] * _SHARE_INFO_0 *entries; * } *bufptr0; * case 1: struct { * DWORD entriesread; * [size_is(entriesread)] * _SHARE_INFO_1 *entries; * } *bufptr1; * ... * } bufptr, * IN DWORD prefmaxlen, * OUT DWORD totalentries, * IN OUT DWORD ?* resume_handle, * OUT DWORD status * ) */ struct mslm_NetShareInfo_0 { LPTSTR shi0_netname; }; struct mslm_NetShareInfo_0_result { DWORD entriesread; SIZE_IS(entriesread) struct mslm_NetShareInfo_0 *entries; }; struct mslm_NetShareInfo_1 { LPTSTR shi1_netname; DWORD shi1_type; /* type of resource such as IPC$ */ LPTSTR shi1_comment; }; struct mslm_NetShareInfo_1_result { DWORD entriesread; SIZE_IS(entriesread) struct mslm_NetShareInfo_1 *entries; }; union mslm_NetShareEnum_ru { CASE(0) struct mslm_NetShareInfo_0_result *bufptr0; CASE(1) struct mslm_NetShareInfo_1_result *bufptr1; DEFAULT char *nullptr; }; struct mslm_NetShareEnum_result { DWORD level; SWITCH(level) union mslm_NetShareEnum_ru ru; }; OPERATION(SRVSVC_OPNUM_NetShareEnum) struct mslm_NetShareEnum { IN LPTSTR servername; INOUT DWORD level; INOUT struct mslm_NetShareEnum_result result; IN DWORD prefmaxlen; OUT DWORD totalentries; INOUT DWORD *resume_handle; OUT DWORD status; }; /* * SRVSVC NetServerGetInfo ( * IN LPTSTR servername, * IN DWORD level, * OUT union switch(level) { * case 100: _SERVER_INFO_100 * p100; * case 101: _SERVER_INFO_101 * p101; * case 102: _SERVER_INFO_102 * p102; * } bufptr, * OUT DWORD status * ) */ /* for svX_platform (note: decimal!) */ #define SV_PLATFORM_ID_DOS 300 #define SV_PLATFORM_ID_OS2 400 #define SV_PLATFORM_ID_NT 500 #define SV_PLATFORM_ID_OSF 600 #define SV_PLATFORM_ID_VMS 700 struct mslm_SERVER_INFO_100 { DWORD sv100_platform_id; LPTSTR sv100_name; }; struct mslm_SERVER_INFO_101 { DWORD sv101_platform_id; LPTSTR sv101_name; DWORD sv101_version_major; DWORD sv101_version_minor; DWORD sv101_type; LPTSTR sv101_comment; }; union mslm_NetServerGetInfo_ru { CASE(100) struct mslm_SERVER_INFO_100 *info100; CASE(101) struct mslm_SERVER_INFO_101 *info101; DEFAULT char *nullptr; }; struct mslm_NetServerGetInfo_result { DWORD level; SWITCH(level) union mslm_NetServerGetInfo_ru ru; }; OPERATION(SRVSVC_OPNUM_NetServerGetInfo) struct mslm_NetServerGetInfo { IN LPTSTR servername; IN DWORD level; OUT struct mslm_NetServerGetInfo_result result; OUT DWORD status; }; /* * The SRVSVC interface */ INTERFACE(0) union srvsvc_interface { CASE(SRVSVC_OPNUM_NetShareEnum) struct mslm_NetShareEnum NetShareEnum; CASE(SRVSVC_OPNUM_NetServerGetInfo) struct mslm_NetServerGetInfo NetServerGetInfo; }; typedef union srvsvc_interface srvsvc_interface_t; EXTERNTYPEINFO(srvsvc_interface) /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright 2013 Nexenta Systems, Inc. All rights reserved. */ /* * A few excerpts from lib/smbsrv/libmlsvc * See longer comment in srvsvc1.ndl */ #include #include #include #include #include #include #include "srvsvc1_clnt.h" static ndr_service_t srvsvc_service = { "SRVSVC", /* name */ "Server services", /* desc */ "\\srvsvc", /* endpoint */ "\\PIPE\\ntsvcs", /* sec_addr_port */ "4b324fc8-1670-01d3-1278-5a47bf6ee188", 3, /* abstract */ NDR_TRANSFER_SYNTAX_UUID, 2, /* transfer */ 0, /* no bind_instance_size */ 0, /* no bind_req() */ 0, /* no unbind_and_close() */ 0, /* use generic_call_stub() */ &TYPEINFO(srvsvc_interface), /* interface_ti */ NULL /* stub_table */ }; /* * srvsvc_initialize * * This function registers the SRVSVC RPC interface with the RPC runtime * library. It must be called in order to use either the client side * or the server side functions. */ void srvsvc1_initialize(void) { static int init_done; if (init_done) return; init_done = 1; (void) ndr_svc_register(&srvsvc_service); } /* * Client-side stub for NetServerGetInfo */ int srvsvc_net_server_getinfo(mlrpc_handle_t *handle, char *server, int level, union mslm_NetServerGetInfo_ru *resp) { struct mslm_NetServerGetInfo arg; int len, opnum, rc; opnum = SRVSVC_OPNUM_NetServerGetInfo; bzero(&arg, sizeof (arg)); len = strlen(server) + 4; arg.servername = ndr_rpc_malloc(handle, len); if (arg.servername == NULL) return (ENOMEM); (void) snprintf((char *)arg.servername, len, "\\\\%s", server); arg.level = level; rc = ndr_rpc_call(handle, opnum, &arg); if ((rc != 0) || (arg.status != 0)) return (EIO); *resp = arg.result.ru; return (0); } /* * Client-side stub for NetShareEnum */ int srvsvc_net_share_enum(mlrpc_handle_t *handle, char *server, int level, union mslm_NetShareEnum_ru *resp) { /* Any enum result type is OK for nres. */ struct mslm_NetShareInfo_0_result nres; struct mslm_NetShareEnum arg; int len, opnum, rc; opnum = SRVSVC_OPNUM_NetShareEnum; bzero(&nres, sizeof (nres)); bzero(&arg, sizeof (arg)); len = strlen(server) + 4; arg.servername = ndr_rpc_malloc(handle, len); if (arg.servername == NULL) return (ENOMEM); (void) snprintf((char *)arg.servername, len, "\\\\%s", server); arg.level = level; arg.result.level = level; arg.result.ru.bufptr0 = &nres; arg.prefmaxlen = 0xFFFFFFFF; arg.resume_handle = NULL; rc = ndr_rpc_call(handle, opnum, &arg); if ((rc != 0) || (arg.status != 0)) return (EIO); *resp = arg.result.ru; return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright 2013 Nexenta Systems, Inc. All rights reserved. */ #ifndef _SRVSVC1_CLNT_H #define _SRVSVC1_CLNT_H /* * Excerpts from lib/smbsrv/libmlsvc * Just enough for share enumeration. */ #include #include "srvsvc1.ndl" void srvsvc1_initialize(void); int srvsvc_net_share_enum(mlrpc_handle_t *handle, char *server, int level, union mslm_NetShareEnum_ru *resp); int srvsvc_net_server_getinfo(mlrpc_handle_t *handle, char *server, int level, union mslm_NetServerGetInfo_ru *resp); #endif /* _SRVSVC1_CLNT_H */ /* * Copyright (c) 2001, Apple Computer, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Boris Popov. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: status.c,v 1.2 2001/08/18 05:44:50 conrad Exp $ */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "common.h" int cmd_status(int argc, char *argv[]) { struct nb_ctx *ctx; struct in_addr ina; char *hostname; char servername[NB_NAMELEN]; char workgroupname[NB_NAMELEN]; int error, opt; if (argc < 2) status_usage(); error = nb_ctx_create(&ctx); if (error) { smb_error(gettext("unable to create nbcontext"), error); exit(1); } if (smb_open_rcfile(NULL) == 0) { if (nb_ctx_readrcsection(NULL, ctx, "default", 0) != 0) exit(1); smb_close_rcfile(); } while ((opt = getopt(argc, argv, "")) != EOF) { switch (opt) { default: status_usage(); /*NOTREACHED*/ } } if (optind >= argc) status_usage(); hostname = argv[argc - 1]; error = nb_resolvehost_in(hostname, &ina); if (error) { smb_error(gettext( "unable to resolve DNS hostname %s"), error, hostname); exit(1); } if ((ctx->nb_flags & NBCF_NS_ENABLE) == 0) { fprintf(stderr, gettext("nbns_enable=false, cannot get status\n")); exit(1); } servername[0] = (char)0; workgroupname[0] = (char)0; error = nbns_getnodestatus(ctx, &ina, servername, workgroupname); if (error) { smb_error( gettext("unable to get status from %s"), error, hostname); exit(1); } if (workgroupname[0]) { printf(gettext("Workgroup: %s\n"), workgroupname); } if (servername[0]) { printf(gettext("Server: %s\n"), servername); } return (0); } void status_usage(void) { printf(gettext("usage: smbutil status hostname\n")); exit(1); } /* * Copyright (c) 2000, Boris Popov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Boris Popov. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: view.c,v 1.9 2004/12/13 00:25:39 lindak Exp $ */ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include "common.h" void view_usage(void) { printf(gettext("usage: smbutil view [connection options] //" "[workgroup;][user[:password]@]server\n")); exit(1); } int cmd_view(int argc, char *argv[]) { struct smb_ctx *ctx; int error, err2, opt; if (argc < 2) view_usage(); error = smb_ctx_alloc(&ctx); if (error) return (error); error = smb_ctx_scan_argv(ctx, argc, argv, SMBL_SERVER, SMBL_SERVER, USE_WILDCARD); if (error) goto out; error = smb_ctx_readrc(ctx); if (error) goto out; while ((opt = getopt(argc, argv, STDPARAM_OPT)) != EOF) { if (opt == '?') view_usage(); error = smb_ctx_opt(ctx, opt, optarg); if (error) goto out; } smb_ctx_setshare(ctx, "IPC$", USE_IPC); /* * Resolve the server address, * setup derived defaults. */ error = smb_ctx_resolve(ctx); if (error) goto out; /* * Have server, share, etc. from above: * smb_ctx_scan_argv, option settings. * Get the session and tree. */ again: error = smb_ctx_get_ssn(ctx); if (error == EAUTH) { err2 = smb_get_authentication(ctx); if (err2 == 0) goto again; } if (error) { smb_error(gettext("//%s: login failed"), error, ctx->ct_fullserver); goto out; } error = smb_ctx_get_tree(ctx); if (error) { smb_error(gettext("//%s/%s: tree connect failed"), error, ctx->ct_fullserver, ctx->ct_origshare); goto out; } /* * Have IPC$ tcon, now list shares. */ error = share_enum_rpc(ctx, ctx->ct_fullserver); out: smb_ctx_free(ctx); return (error); } #ifdef I18N /* not defined, put here so xgettext(1) can find strings */ static char *shtype[] = { gettext("disk"), gettext("printer"), gettext("device"), /* Communications device */ gettext("IPC"), /* Inter process communication */ gettext("unknown") }; #else static char *shtype[] = { "disk", "printer", "device", /* Communications device */ "IPC", /* IPC Inter process communication */ "unknown" }; #endif /* * Print one line of the share list, or * if SHARE is null, print the header line. */ void view_print_share(char *share, int type, char *comment) { char *stname; int stindex; if (share == NULL) { printf(gettext("Share Type Comment\n")); printf("-------------------------------\n"); return; } stindex = type & STYPE_MASK; if (stindex > STYPE_UNKNOWN) stindex = STYPE_UNKNOWN; stname = gettext(shtype[stindex]); if (comment == NULL) comment = ""; printf("%-12s %-10s %s\n", share, stname, comment); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright 2019 Nexenta by DDN, Inc. All rights reserved. # MANIFEST= client.xml SVCMETHOD= smb-client include $(SRC)/cmd/Makefile.cmd ETCSECURITYFILES = exec_attr.d/SUNWsmbfs ROOTETCSECURITY = $(ROOT)/etc/security $(ROOTETCSECURITY) : DIRMODE = 0755 ROOTETCSECURITYFILES = $(ETCSECURITYFILES:%=$(ROOTETCSECURITY)/%) $(ROOTETCSECURITYFILES) : FILEMODE = 0644 ROOTMANIFESTDIR= $(ROOTSVCNETWORKSMB) all: install: $(ROOTMANIFEST) $(ROOTSVCMETHOD) $(ROOTETCSECURITYFILES) $(ROOTETCSECURITY)/exec_attr.d/%:% $(INS.file) clean: clobber: check: $(CHKMANIFEST) include $(SRC)/cmd/Makefile.targ Basic Solaris User:solaris:cmd:::/usr/lib/fs/smbfs/mount:privs=sys_mount Basic Solaris User:solaris:cmd:::/usr/lib/fs/smbfs/umount:privs=sys_mount #!/sbin/sh # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. # # # Start/stop client SMB service # . /lib/svc/share/smf_include.sh result=${SMF_EXIT_OK} case "$1" in 'start') # Start the main smbiod service /usr/lib/smbfs/smbiod-svc result=$? # Do smbfs mounts (background) /usr/bin/ctrun -l none \ /sbin/mountall -F smbfs ;; 'stop') # First destroy the mounts, /sbin/umountall -F smbfs # then kill the smbiod service. smf_kill_contract $2 TERM 1 result=$? ;; *) echo "Usage: $0 { start | stop }" result=1 ;; esac exit $result # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright 2019 Nexenta by DDN, Inc. All rights reserved. # # # cmd/fs.d/smbclnt/umount/Makefile # FSTYPE= smbfs LIBPROG= umount ROOTFS_PROG= $(LIBPROG) include ../../Makefile.fstype COMMON= $(FSLIB) OBJS= $(LIBPROG).o $(COMMON) SRCS= $(LIBPROG).c $(FSLIBSRC) $(ROOTLIBFSTYPE)/umount : FILEMODE= 0555 CPPFLAGS += -I../.. -I../lib CFLAGS += $(CCVERBOSE) # # Message catalog # POFILE= $(LIBPROG).po catalog: $(POFILE) $(POFILE): $(SRCS) $(RM) $@ $(COMPILE.cpp) $(SRCS) > $(POFILE).i $(XGETTEXT) $(XGETFLAGS) $(POFILE).i sed "/^domain/d" messages.po > $@ $(RM) messages.po $(POFILE).i $(LIBPROG): $(OBJS) $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(POST_PROCESS) clean: $(RM) $(OBJS) /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2018, Joyent, Inc. * Copyright 2019 Nexenta by DDN, Inc. All rights reserved. */ /* * smbfs umount */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define RET_OK 0 #define RET_ERR 32 static void pr_err(const char *fmt, ...); static void usage(); static int smbfs_unmount(char *, int); static struct extmnttab *mnttab_find(); int main(int argc, char *argv[]) { extern int optind; int c; int umnt_flag = 0; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif (void) textdomain(TEXT_DOMAIN); /* * Normal users are allowed to umount smbfs mounts they own. * To allow that, this program has an exec_attr that adds * SYS_MOUNT privilege. * * The __init_suid_priv call was designed for SUID programs, * but also works for privileges granted via exec_attr with * one difference: the added privileges are already effective * when the program starts, and remain effective after the call. * To make this work more like the SUID case we'll turn off the * additional privileges with a __priv_bracket() call here. * Later calls to __priv_bracket() make the extra privileges * effective only when we need them. */ if (__init_suid_priv(0, PRIV_SYS_MOUNT, (char *)NULL) < 0) { (void) fprintf(stderr, gettext("Insufficient privileges, " "%s should have sys_mount privilege via exec_attr\n"), argv[0]); exit(RET_ERR); } (void) __priv_bracket(PRIV_OFF); /* * Set options */ while ((c = getopt(argc, argv, "f")) != EOF) { switch (c) { case 'f': umnt_flag |= MS_FORCE; /* forced unmount is desired */ break; default: usage(); exit(RET_ERR); } } if (argc - optind != 1) { usage(); exit(RET_ERR); } return (smbfs_unmount(argv[optind], umnt_flag)); } static void pr_err(const char *fmt, ...) { va_list ap; va_start(ap, fmt); (void) fprintf(stderr, "smbfs/umount: "); (void) vfprintf(stderr, fmt, ap); (void) fflush(stderr); va_end(ap); } static void usage() { (void) fprintf(stderr, gettext("Usage: smbfs umount [-o opts] {//server/share | dir}\n")); exit(RET_ERR); } static int smbfs_unmount(char *pathname, int umnt_flag) { struct extmnttab *mntp; int rc; mntp = mnttab_find(pathname); if (mntp) { pathname = mntp->mnt_mountp; } /* Need sys_mount privilege for the umount call. */ (void) __priv_bracket(PRIV_ON); rc = umount2(pathname, umnt_flag); (void) __priv_bracket(PRIV_OFF); if (rc < 0) { pr_err(gettext("%s: %s\n"), pathname, strerror(errno)); return (RET_ERR); } return (RET_OK); } /* * Find the mnttab entry that corresponds to "name". * We're not sure what the name represents: either * a mountpoint name, or a special name (server:/path). * Return the last entry in the file that matches. */ static struct extmnttab * mnttab_find(char *dirname) { FILE *fp; struct extmnttab mnt; struct extmnttab *res = NULL; fp = fopen(MNTTAB, "r"); if (fp == NULL) { pr_err("%s: %s\n", MNTTAB, strerror(errno)); return (NULL); } while (getextmntent(fp, &mnt, sizeof (struct extmnttab)) == 0) { if (strcmp(mnt.mnt_mountp, dirname) == 0 || strcmp(mnt.mnt_special, dirname) == 0) { if (res) fsfreemnttab(res); res = fsdupmnttab(&mnt); } } (void) fclose(fp); return (res); }