NTSTATUS SMBReleaseServer( SMBHANDLE inConnection) { refcount_t refcount; refcount = OSAtomicDecrement32(&inConnection->refcount); if (refcount == 0) { smb_ctx_done(inConnection->context); free(inConnection); } return STATUS_SUCCESS; }
/* * SMBNetFsCreateSessionRef * * Load the smbfs kext if need, initialize anything needed by the library and * create a session reference structure, the first element must have our schema * as a CFStringRef. */ int32_t SMBNetFsCreateSessionRef(SMBHANDLE *outConnection) { void *hContext; int error; *outConnection = NULL; /* Need to initialize the library and load the kext */ error = smb_load_library(); if (error) { return error; } /* create_smb_ctx can only fail because of an allocation failure */ hContext = create_smb_ctx(); if (hContext == NULL) { return ENOMEM; } *outConnection = SMBAllocateAndSetContext(hContext); if (*outConnection == NULL) { smb_ctx_done(hContext); return ENOMEM; } return 0; }
/* * Would prefer to do all of this as the user that mounted the volume, but it * seems the sysctlbyfsid requires you to be root. So do the sysctlbyfsid as * root and everything else as the user. */ int smb_remount_with_fsid(fsid_t fsid) { int error, error2; struct smb_ctx *ctx = NULL; struct smb_remount_info remountInfo; uid_t rootUID = geteuid(); /* Get the remount information need for the remount */ memset(&remountInfo, 0, sizeof(remountInfo)); error = SysctlRemountInfo(fsid, &remountInfo); if (error) { goto done; } smb_log_info("%s: mount url smb:%s", ASL_LEVEL_DEBUG, __FUNCTION__, remountInfo.mntURL); smb_log_info("%s: client principal name %s", ASL_LEVEL_DEBUG, __FUNCTION__, remountInfo.mntClientPrincipalName); smb_log_info("%s: client principal name type %d", ASL_LEVEL_DEBUG, __FUNCTION__, remountInfo.mntClientPrincipalNameType); smb_log_info("%s: authorization flags 0x%x", ASL_LEVEL_DEBUG, __FUNCTION__, remountInfo.mntAuthFlags); smb_log_info("%s: owner of mount point %d", ASL_LEVEL_DEBUG, __FUNCTION__, remountInfo.mntOwner); /* Switch to the user that owns the mount */ error2 = seteuid(remountInfo.mntOwner); if (error2) { smb_log_info("%s: seteuid failed %d for mntOwner", ASL_LEVEL_ERR, __FUNCTION__, error2); goto done; } error = create_smb_ctx_with_url(&ctx, remountInfo.mntURL); if (error) { smb_log_info("%s: Could create ctx from url smb:%s", ASL_LEVEL_ERR, __FUNCTION__, remountInfo.mntURL); error2 = seteuid(rootUID); if (error2) { smb_log_info("%s: seteuid failed %d for rootUID", ASL_LEVEL_ERR, __FUNCTION__, error2); } goto done; } error = GetRootShareConnection(ctx, remountInfo.mntURL, remountInfo.mntAuthFlags, remountInfo.mntClientPrincipalName, remountInfo.mntClientPrincipalNameType, remountInfo.mntDeadTimer); if (!error) { struct smb_ctx *dfs_ctx = NULL; /* * XXX - Need to handle the DfsRoot remount case, we should check to * see if this is just a DfsRoot, if so then continue with the remount * because we found a different domain control to access. */ error = checkForDfsReferral(ctx, &dfs_ctx, NULL, NULL); if (error || (ctx == dfs_ctx) || (dfs_ctx == NULL)) { error2 = seteuid(rootUID); if (error2) { smb_log_info("%s: seteuid failed %d for rootUID", ASL_LEVEL_ERR, __FUNCTION__, error2); } goto done; } smb_ctx_done(ctx); ctx = dfs_ctx; } error2 = seteuid(rootUID); if (error2) { smb_log_info("%s: seteuid failed %d for rootUID", ASL_LEVEL_ERR, __FUNCTION__, error2); goto done; } if (error) { goto done; } if (smb_tree_conn_fstype(ctx) == SMB_FS_FAT) { smb_log_info("%s: Could remount url smb:%s found a fat file system", ASL_LEVEL_ERR, __FUNCTION__, remountInfo.mntURL); error = ENOTSUP; goto done; } if (!error) { error = SysctlRemountFS(fsid, ctx->ct_fd); } done: if (ctx) { error2 = seteuid(remountInfo.mntOwner); if (error2) { smb_log_info("%s: seteuid failed %d for mntOwner", ASL_LEVEL_ERR, __FUNCTION__, error2); } smb_ctx_done(ctx); error2 = seteuid(rootUID); if (error2) { smb_log_info("%s: seteuid failed %d for rootUID", ASL_LEVEL_ERR, __FUNCTION__, error2); } } if (error) { smb_log_info("%s: remount failed for url %s with error = %d", ASL_LEVEL_ERR, __FUNCTION__, remountInfo.mntURL, error); } return error; }
int main(int argc, char *argv[]) { struct iovec *iov; unsigned int iovlen; struct smb_ctx sctx, *ctx = &sctx; struct stat st; #ifdef APPLE extern void dropsuid(); extern int loadsmbvfs(); #else struct xvfsconf vfc; #endif char *next, *p, *val; int opt, error, mntflags, caseopt, fd; uid_t uid; gid_t gid; mode_t dir_mode, file_mode; char errmsg[255] = { 0 }; iov = NULL; iovlen = 0; fd = 0; uid = (uid_t)-1; gid = (gid_t)-1; caseopt = 0; file_mode = 0; dir_mode = 0; #ifdef APPLE dropsuid(); #endif if (argc == 2) { if (strcmp(argv[1], "-h") == 0) { usage(); } } if (argc < 3) usage(); #ifdef APPLE error = loadsmbvfs(); #else error = getvfsbyname(smbfs_vfsname, &vfc); if (error) { if (kldload(smbfs_vfsname) < 0) err(EX_OSERR, "kldload(%s)", smbfs_vfsname); error = getvfsbyname(smbfs_vfsname, &vfc); } #endif if (error) errx(EX_OSERR, "SMB filesystem is not available"); if (smb_lib_init() != 0) exit(1); mntflags = error = 0; caseopt = SMB_CS_NONE; if (smb_ctx_init(ctx, argc, argv, SMBL_SHARE, SMBL_SHARE, SMB_ST_DISK) != 0) exit(1); if (smb_ctx_readrc(ctx) != 0) exit(1); if (smb_rc) rc_close(smb_rc); while ((opt = getopt(argc, argv, STDPARAM_OPT"c:d:f:g:l:n:o:u:w:")) != -1) { switch (opt) { case STDPARAM_ARGS: error = smb_ctx_opt(ctx, opt, optarg); if (error) exit(1); break; case 'u': { struct passwd *pwd; pwd = isdigit(optarg[0]) ? getpwuid(atoi(optarg)) : getpwnam(optarg); if (pwd == NULL) errx(EX_NOUSER, "unknown user '%s'", optarg); uid = pwd->pw_uid; break; } case 'g': { struct group *grp; grp = isdigit(optarg[0]) ? getgrgid(atoi(optarg)) : getgrnam(optarg); if (grp == NULL) errx(EX_NOUSER, "unknown group '%s'", optarg); gid = grp->gr_gid; break; } case 'd': errno = 0; dir_mode = strtol(optarg, &next, 8); if (errno || *next != 0) errx(EX_DATAERR, "invalid value for directory mode"); break; case 'f': errno = 0; file_mode = strtol(optarg, &next, 8); if (errno || *next != 0) errx(EX_DATAERR, "invalid value for file mode"); break; case '?': usage(); /*NOTREACHED*/ case 'n': { char *inp, *nsp; nsp = inp = optarg; while ((nsp = strsep(&inp, ",;:")) != NULL) { if (strcasecmp(nsp, "LONG") == 0) { build_iovec(&iov, &iovlen, "nolong", NULL, 0); } else { errx(EX_DATAERR, "unknown suboption '%s'", nsp); } } break; }; case 'o': getmntopts(optarg, mopts, &mntflags, 0); p = strchr(optarg, '='); val = NULL; if (p != NULL) { *p = '\0'; val = p + 1; } build_iovec(&iov, &iovlen, optarg, val, (size_t)-1); break; case 'c': switch (optarg[0]) { case 'l': caseopt |= SMB_CS_LOWER; break; case 'u': caseopt |= SMB_CS_UPPER; break; default: errx(EX_DATAERR, "invalid suboption '%c' for -c", optarg[0]); } break; default: usage(); } } if (optind == argc - 2) optind++; if (optind != argc - 1) usage(); realpath(argv[optind], mount_point); if (stat(mount_point, &st) == -1) err(EX_OSERR, "could not find mount point %s", mount_point); if (!S_ISDIR(st.st_mode)) { errno = ENOTDIR; err(EX_OSERR, "can't mount on %s", mount_point); } /* if (smb_getextattr(mount_point, &einfo) == 0) errx(EX_OSERR, "can't mount on %s twice", mount_point); */ if (uid == (uid_t)-1) uid = st.st_uid; if (gid == (gid_t)-1) gid = st.st_gid; if (file_mode == 0 ) file_mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); if (dir_mode == 0) { dir_mode = file_mode; if (dir_mode & S_IRUSR) dir_mode |= S_IXUSR; if (dir_mode & S_IRGRP) dir_mode |= S_IXGRP; if (dir_mode & S_IROTH) dir_mode |= S_IXOTH; } /* * For now, let connection be private for this mount */ ctx->ct_ssn.ioc_opt |= SMBVOPT_PRIVATE; ctx->ct_ssn.ioc_owner = ctx->ct_sh.ioc_owner = 0; /* root */ ctx->ct_ssn.ioc_group = ctx->ct_sh.ioc_group = gid; opt = 0; if (dir_mode & S_IXGRP) opt |= SMBM_EXECGRP; if (dir_mode & S_IXOTH) opt |= SMBM_EXECOTH; ctx->ct_ssn.ioc_rights |= opt; ctx->ct_sh.ioc_rights |= opt; error = smb_ctx_resolve(ctx); if (error) exit(1); error = smb_ctx_lookup(ctx, SMBL_SHARE, SMBLK_CREATE); if (error) { exit(1); } fd = ctx->ct_fd; build_iovec(&iov, &iovlen, "fstype", strdup("smbfs"), -1); build_iovec(&iov, &iovlen, "fspath", mount_point, -1); build_iovec_argf(&iov, &iovlen, "fd", "%d", fd); build_iovec(&iov, &iovlen, "mountpoint", mount_point, -1); build_iovec_argf(&iov, &iovlen, "uid", "%d", uid); build_iovec_argf(&iov, &iovlen, "gid", "%d", gid); build_iovec_argf(&iov, &iovlen, "file_mode", "%d", file_mode); build_iovec_argf(&iov, &iovlen, "dir_mode", "%d", dir_mode); build_iovec_argf(&iov, &iovlen, "caseopt", "%d", caseopt); build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof errmsg); error = nmount(iov, iovlen, mntflags); smb_ctx_done(ctx); if (error) { smb_error("mount error: %s %s", error, mount_point, errmsg); exit(1); } return 0; }
static int mount_struct(_Bool verbose, struct mount_data_s *mntdp) { fsu_fs_t *fs; int rv; fs = mntdp->mntd_fs; /* * Switch the default process to the native syscalls. * The bad thing about this is that it will fail in unobvious * way if programs using this go multithreaded, but worry about * that if it happens. */ rump_i_know_what_i_am_doing_with_sysents = 1; rump_pub_lwproc_sysent_usenative(); rv = fs->fs_parseargs(mntdp->mntd_argc, mntdp->mntd_argv, fs->fs_args, &(mntdp->mntd_flags), mntdp->mntd_canon_dev, mntdp->mntd_canon_dir); if (rv != 0) return -1; if (rump_sys_mkdir(MOUNT_DIRECTORY, 0777) == -1 && errno != EEXIST) err(-1, "mkdir"); strcpy(mntdp->mntd_canon_dir, MOUNT_DIRECTORY); rv = fsu_load_fs(fs->fs_name); if (rv == 0) { rv = rump_sys_mount(fs->fs_name, mntdp->mntd_canon_dir, mntdp->mntd_flags, fs->fs_args, fs->fs_args_size); #if 0 /* * This will result in a lot of spam for fs type autodetection, * so need to come up with a better scheme here. */ if (rv == -1) warn("mount failed"); #endif } if (rv == 0) { /* fork a rump kernel process to chroot() to the mountpoint */ if ((rv = rump_pub_lwproc_rfork(RUMP_RFCFDG)) != 0) { warnx("fork failed!"); rump_sys_unmount(MOUNT_DIRECTORY, 0); } else { atexit(fsu_unmount); rump_sys_chroot(MOUNT_DIRECTORY); } } #ifdef WITH_SMBFS if (strcmp(fs->fs_name, MOUNT_SMBFS) == 0) { extern struct smb_ctx sctx; smb_ctx_done(&sctx); } #endif if (rv != 0 && verbose) { warn(NULL); fprintf(stderr, "%s is not a valid %s image\n", mntdp->mntd_fsdevice, fs->fs_name); } return rv; }