187866Ssheldonh/* 295267Ssheldonh * Copyright (c) 2000-2002, Boris Popov 387866Ssheldonh * All rights reserved. 487866Ssheldonh * 587866Ssheldonh * Redistribution and use in source and binary forms, with or without 687866Ssheldonh * modification, are permitted provided that the following conditions 787866Ssheldonh * are met: 887866Ssheldonh * 1. Redistributions of source code must retain the above copyright 987866Ssheldonh * notice, this list of conditions and the following disclaimer. 1087866Ssheldonh * 2. Redistributions in binary form must reproduce the above copyright 1187866Ssheldonh * notice, this list of conditions and the following disclaimer in the 1287866Ssheldonh * documentation and/or other materials provided with the distribution. 1387866Ssheldonh * 3. All advertising materials mentioning features or use of this software 1487866Ssheldonh * must display the following acknowledgement: 1587866Ssheldonh * This product includes software developed by Boris Popov. 1687866Ssheldonh * 4. Neither the name of the author nor the names of any co-contributors 1787866Ssheldonh * may be used to endorse or promote products derived from this software 1887866Ssheldonh * without specific prior written permission. 1987866Ssheldonh * 2087866Ssheldonh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2187866Ssheldonh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2287866Ssheldonh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2387866Ssheldonh * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2487866Ssheldonh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2587866Ssheldonh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2687866Ssheldonh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2787866Ssheldonh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2887866Ssheldonh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2987866Ssheldonh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3087866Ssheldonh * SUCH DAMAGE. 3187866Ssheldonh * 3295267Ssheldonh * $Id: mount_smbfs.c,v 1.17 2002/04/10 04:17:51 bp Exp $ 33117804Stjr * $FreeBSD$ 3487866Ssheldonh */ 3587866Ssheldonh#include <sys/param.h> 3687866Ssheldonh#include <sys/stat.h> 3787866Ssheldonh#include <sys/errno.h> 38130789Smux#include <sys/linker.h> 3987866Ssheldonh#include <sys/mount.h> 4087866Ssheldonh 4187866Ssheldonh#include <stdio.h> 4287866Ssheldonh#include <string.h> 4387866Ssheldonh#include <pwd.h> 4487866Ssheldonh#include <grp.h> 4587866Ssheldonh#include <unistd.h> 4687866Ssheldonh#include <ctype.h> 4787866Ssheldonh#include <stdlib.h> 4887866Ssheldonh#include <err.h> 4987866Ssheldonh#include <sysexits.h> 5087866Ssheldonh 5187866Ssheldonh#include <cflib.h> 5287866Ssheldonh 5387866Ssheldonh#include <netsmb/smb.h> 5487866Ssheldonh#include <netsmb/smb_conn.h> 5587866Ssheldonh#include <netsmb/smb_lib.h> 5687866Ssheldonh 5787866Ssheldonh#include <fs/smbfs/smbfs.h> 5887866Ssheldonh 5987866Ssheldonh#include "mntopts.h" 6087866Ssheldonh 6187866Ssheldonhstatic char mount_point[MAXPATHLEN + 1]; 6287866Ssheldonhstatic void usage(void); 6387866Ssheldonh 6487866Ssheldonhstatic struct mntopt mopts[] = { 6587866Ssheldonh MOPT_STDOPTS, 66152467Srodrigc MOPT_END 6787866Ssheldonh}; 6887866Ssheldonh 69152467Srodrigcstatic char smbfs_vfsname[] = "smbfs"; 7087866Ssheldonh 7187866Ssheldonhint 7287866Ssheldonhmain(int argc, char *argv[]) 7387866Ssheldonh{ 74152467Srodrigc struct iovec *iov; 75152467Srodrigc unsigned int iovlen; 7687866Ssheldonh struct smb_ctx sctx, *ctx = &sctx; 7787866Ssheldonh struct stat st; 7888282Ssheldonh#ifdef APPLE 7988282Ssheldonh extern void dropsuid(); 8088282Ssheldonh extern int loadsmbvfs(); 81130789Smux#else 82130789Smux struct xvfsconf vfc; 83128140Smux#endif 8487866Ssheldonh char *next; 85250236Sdavide int opt, error, mntflags, caseopt, fd; 86152467Srodrigc uid_t uid; 87152467Srodrigc gid_t gid; 88152467Srodrigc mode_t dir_mode, file_mode; 89152467Srodrigc char errmsg[255] = { 0 }; 9087866Ssheldonh 91152467Srodrigc iov = NULL; 92152467Srodrigc iovlen = 0; 93250236Sdavide fd = 0; 94152523Sru uid = (uid_t)-1; 95152523Sru gid = (gid_t)-1; 96152467Srodrigc caseopt = 0; 97152467Srodrigc file_mode = 0; 98152467Srodrigc dir_mode = 0; 9988282Ssheldonh 10088282Ssheldonh#ifdef APPLE 10188282Ssheldonh dropsuid(); 102128140Smux#endif 10387866Ssheldonh if (argc == 2) { 10487866Ssheldonh if (strcmp(argv[1], "-h") == 0) { 10587866Ssheldonh usage(); 10687866Ssheldonh } 10787866Ssheldonh } 10887866Ssheldonh if (argc < 3) 10987866Ssheldonh usage(); 11087866Ssheldonh 11188282Ssheldonh#ifdef APPLE 11288282Ssheldonh error = loadsmbvfs(); 113130789Smux#else 114152467Srodrigc error = getvfsbyname(smbfs_vfsname, &vfc); 115130789Smux if (error) { 116152467Srodrigc if (kldload(smbfs_vfsname) < 0) 117152467Srodrigc err(EX_OSERR, "kldload(%s)", smbfs_vfsname); 118152467Srodrigc error = getvfsbyname(smbfs_vfsname, &vfc); 119130789Smux } 120130789Smux#endif 12187866Ssheldonh if (error) 12287866Ssheldonh errx(EX_OSERR, "SMB filesystem is not available"); 12387866Ssheldonh 12487866Ssheldonh if (smb_lib_init() != 0) 12587866Ssheldonh exit(1); 12687866Ssheldonh 12787866Ssheldonh mntflags = error = 0; 128152467Srodrigc 12987866Ssheldonh caseopt = SMB_CS_NONE; 13087866Ssheldonh 13187866Ssheldonh if (smb_ctx_init(ctx, argc, argv, SMBL_SHARE, SMBL_SHARE, SMB_ST_DISK) != 0) 13287866Ssheldonh exit(1); 13387866Ssheldonh if (smb_ctx_readrc(ctx) != 0) 13487866Ssheldonh exit(1); 13587866Ssheldonh if (smb_rc) 13687866Ssheldonh rc_close(smb_rc); 13787866Ssheldonh 13887866Ssheldonh while ((opt = getopt(argc, argv, STDPARAM_OPT"c:d:f:g:l:n:o:u:w:")) != -1) { 13987866Ssheldonh switch (opt) { 14087866Ssheldonh case STDPARAM_ARGS: 14187866Ssheldonh error = smb_ctx_opt(ctx, opt, optarg); 14287866Ssheldonh if (error) 14387866Ssheldonh exit(1); 14487866Ssheldonh break; 14587866Ssheldonh case 'u': { 14687866Ssheldonh struct passwd *pwd; 14787866Ssheldonh 14887866Ssheldonh pwd = isdigit(optarg[0]) ? 14987866Ssheldonh getpwuid(atoi(optarg)) : getpwnam(optarg); 15087866Ssheldonh if (pwd == NULL) 15187866Ssheldonh errx(EX_NOUSER, "unknown user '%s'", optarg); 152152467Srodrigc uid = pwd->pw_uid; 15387866Ssheldonh break; 15487866Ssheldonh } 15587866Ssheldonh case 'g': { 15687866Ssheldonh struct group *grp; 15787866Ssheldonh 15887866Ssheldonh grp = isdigit(optarg[0]) ? 15987866Ssheldonh getgrgid(atoi(optarg)) : getgrnam(optarg); 16087866Ssheldonh if (grp == NULL) 16187866Ssheldonh errx(EX_NOUSER, "unknown group '%s'", optarg); 162152467Srodrigc gid = grp->gr_gid; 16387866Ssheldonh break; 16487866Ssheldonh } 16587866Ssheldonh case 'd': 16687866Ssheldonh errno = 0; 167152467Srodrigc dir_mode = strtol(optarg, &next, 8); 16887866Ssheldonh if (errno || *next != 0) 16987866Ssheldonh errx(EX_DATAERR, "invalid value for directory mode"); 17087866Ssheldonh break; 17187866Ssheldonh case 'f': 17287866Ssheldonh errno = 0; 173152467Srodrigc file_mode = strtol(optarg, &next, 8); 17487866Ssheldonh if (errno || *next != 0) 17587866Ssheldonh errx(EX_DATAERR, "invalid value for file mode"); 17687866Ssheldonh break; 17787866Ssheldonh case '?': 17887866Ssheldonh usage(); 17987866Ssheldonh /*NOTREACHED*/ 18087866Ssheldonh case 'n': { 18187866Ssheldonh char *inp, *nsp; 18287866Ssheldonh 18387866Ssheldonh nsp = inp = optarg; 18487866Ssheldonh while ((nsp = strsep(&inp, ",;:")) != NULL) { 185152467Srodrigc if (strcasecmp(nsp, "LONG") == 0) { 186152467Srodrigc build_iovec(&iov, &iovlen, 187152467Srodrigc "nolong", NULL, 0); 188152467Srodrigc } else { 189152467Srodrigc errx(EX_DATAERR, 190152467Srodrigc "unknown suboption '%s'", nsp); 191152467Srodrigc } 19287866Ssheldonh } 19387866Ssheldonh break; 19487866Ssheldonh }; 19587866Ssheldonh case 'o': 19687866Ssheldonh getmntopts(optarg, mopts, &mntflags, 0); 19787866Ssheldonh break; 19887866Ssheldonh case 'c': 19987866Ssheldonh switch (optarg[0]) { 20087866Ssheldonh case 'l': 20187866Ssheldonh caseopt |= SMB_CS_LOWER; 20287866Ssheldonh break; 20387866Ssheldonh case 'u': 20487866Ssheldonh caseopt |= SMB_CS_UPPER; 20587866Ssheldonh break; 20687866Ssheldonh default: 20787866Ssheldonh errx(EX_DATAERR, "invalid suboption '%c' for -c", 20887866Ssheldonh optarg[0]); 20987866Ssheldonh } 21087866Ssheldonh break; 21187866Ssheldonh default: 21287866Ssheldonh usage(); 21387866Ssheldonh } 21487866Ssheldonh } 21587866Ssheldonh 21687866Ssheldonh if (optind == argc - 2) 21787866Ssheldonh optind++; 21887866Ssheldonh 21987866Ssheldonh if (optind != argc - 1) 22087866Ssheldonh usage(); 22187866Ssheldonh realpath(argv[optind], mount_point); 22287866Ssheldonh 22387866Ssheldonh if (stat(mount_point, &st) == -1) 22487866Ssheldonh err(EX_OSERR, "could not find mount point %s", mount_point); 22587866Ssheldonh if (!S_ISDIR(st.st_mode)) { 22687866Ssheldonh errno = ENOTDIR; 22787866Ssheldonh err(EX_OSERR, "can't mount on %s", mount_point); 22887866Ssheldonh } 22987866Ssheldonh/* 23087866Ssheldonh if (smb_getextattr(mount_point, &einfo) == 0) 23187866Ssheldonh errx(EX_OSERR, "can't mount on %s twice", mount_point); 23287866Ssheldonh*/ 233152523Sru if (uid == (uid_t)-1) 234152467Srodrigc uid = st.st_uid; 235152523Sru if (gid == (gid_t)-1) 236152467Srodrigc gid = st.st_gid; 237152467Srodrigc if (file_mode == 0 ) 238152467Srodrigc file_mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); 239152467Srodrigc if (dir_mode == 0) { 240152467Srodrigc dir_mode = file_mode; 241152467Srodrigc if (dir_mode & S_IRUSR) 242152467Srodrigc dir_mode |= S_IXUSR; 243152467Srodrigc if (dir_mode & S_IRGRP) 244152467Srodrigc dir_mode |= S_IXGRP; 245152467Srodrigc if (dir_mode & S_IROTH) 246152467Srodrigc dir_mode |= S_IXOTH; 24787866Ssheldonh } 24887866Ssheldonh /* 24987866Ssheldonh * For now, let connection be private for this mount 25087866Ssheldonh */ 25187866Ssheldonh ctx->ct_ssn.ioc_opt |= SMBVOPT_PRIVATE; 25287866Ssheldonh ctx->ct_ssn.ioc_owner = ctx->ct_sh.ioc_owner = 0; /* root */ 253152467Srodrigc ctx->ct_ssn.ioc_group = ctx->ct_sh.ioc_group = gid; 25487866Ssheldonh opt = 0; 255152467Srodrigc if (dir_mode & S_IXGRP) 25687866Ssheldonh opt |= SMBM_EXECGRP; 257152467Srodrigc if (dir_mode & S_IXOTH) 25887866Ssheldonh opt |= SMBM_EXECOTH; 25987866Ssheldonh ctx->ct_ssn.ioc_rights |= opt; 26087866Ssheldonh ctx->ct_sh.ioc_rights |= opt; 26187866Ssheldonh error = smb_ctx_resolve(ctx); 26287866Ssheldonh if (error) 26387866Ssheldonh exit(1); 26487866Ssheldonh error = smb_ctx_lookup(ctx, SMBL_SHARE, SMBLK_CREATE); 26587866Ssheldonh if (error) { 26687866Ssheldonh exit(1); 26787866Ssheldonh } 268152467Srodrigc 269250236Sdavide fd = ctx->ct_fd; 270152467Srodrigc 271152467Srodrigc build_iovec(&iov, &iovlen, "fstype", strdup("smbfs"), -1); 272152467Srodrigc build_iovec(&iov, &iovlen, "fspath", mount_point, -1); 273250236Sdavide build_iovec_argf(&iov, &iovlen, "fd", "%d", fd); 274152467Srodrigc build_iovec(&iov, &iovlen, "mountpoint", mount_point, -1); 275152467Srodrigc build_iovec_argf(&iov, &iovlen, "uid", "%d", uid); 276152467Srodrigc build_iovec_argf(&iov, &iovlen, "gid", "%d", gid); 277152467Srodrigc build_iovec_argf(&iov, &iovlen, "file_mode", "%d", file_mode); 278152467Srodrigc build_iovec_argf(&iov, &iovlen, "dir_mode", "%d", dir_mode); 279152467Srodrigc build_iovec_argf(&iov, &iovlen, "caseopt", "%d", caseopt); 280152467Srodrigc build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof errmsg); 281152467Srodrigc 282152467Srodrigc error = nmount(iov, iovlen, mntflags); 28387866Ssheldonh smb_ctx_done(ctx); 28487866Ssheldonh if (error) { 285152467Srodrigc smb_error("mount error: %s %s", error, mount_point, errmsg); 28687866Ssheldonh exit(1); 28787866Ssheldonh } 28887866Ssheldonh return 0; 28987866Ssheldonh} 29087866Ssheldonh 29187866Ssheldonhstatic void 29287866Ssheldonhusage(void) 29387866Ssheldonh{ 29487866Ssheldonh fprintf(stderr, "%s\n%s\n%s\n%s\n", 29588492Ssheldonh "usage: mount_smbfs [-E cs1:cs2] [-I host] [-L locale] [-M crights:srights]", 29688492Ssheldonh " [-N] [-O cowner:cgroup/sowner:sgroup] [-R retrycount]", 29788492Ssheldonh " [-T timeout] [-W workgroup] [-c case] [-d mode] [-f mode]", 298187583Strhodes " [-g gid] [-n opt] [-u uid] [-U username] //user@server/share node"); 29987866Ssheldonh 30087866Ssheldonh exit (1); 30187866Ssheldonh} 302