mirror of
https://github.com/samba-team/samba.git
synced 2025-03-26 18:50:30 +03:00
r14668: Set the FILE_STATUS_OFFLINE bit by observing the events a DMAPI-based
HSM is interested in. Tested on both IRIX and SLES9. (This used to be commit 514a767c57f8194547e5b708ad2573ab9a0719c6)
This commit is contained in:
parent
e836508704
commit
40d0707827
@ -416,7 +416,7 @@ SMBD_OBJ_SRV = smbd/files.o smbd/chgpasswd.o smbd/connection.o \
|
||||
smbd/change_trust_pw.o smbd/fake_file.o \
|
||||
smbd/quotas.o smbd/ntquotas.o $(AFS_OBJ) smbd/msdfs.o \
|
||||
$(AFS_SETTOKEN_OBJ) smbd/aio.o smbd/statvfs.o \
|
||||
$(MANGLE_OBJ) @VFS_STATIC@
|
||||
smbd/dmapi.o $(MANGLE_OBJ) @VFS_STATIC@
|
||||
|
||||
SMBD_OBJ_BASE = $(PARAM_OBJ) $(SMBD_OBJ_SRV) $(LIBSMB_OBJ) \
|
||||
$(RPC_SERVER_OBJ) $(RPC_PARSE_OBJ) $(SECRETS_OBJ) \
|
||||
|
@ -829,6 +829,7 @@ AC_CHECK_HEADERS(sys/termio.h sys/statfs.h sys/dustat.h sys/statvfs.h stdarg.h s
|
||||
AC_CHECK_HEADERS(sys/sysmacros.h security/_pam_macros.h dlfcn.h)
|
||||
AC_CHECK_HEADERS(sys/syslog.h syslog.h execinfo.h)
|
||||
AC_CHECK_HEADERS(langinfo.h locale.h)
|
||||
AC_CHECK_HEADERS(sys/dmi.h xfs/dmapi.h)
|
||||
|
||||
AC_CHECK_HEADERS(rpcsvc/yp_prot.h,,,[[
|
||||
#if HAVE_RPC_RPC_H
|
||||
@ -2337,6 +2338,17 @@ if test x"$samba_cv_HAVE_LIBFAM" = x"yes" ; then
|
||||
[])
|
||||
fi
|
||||
|
||||
#################################################
|
||||
# Check for DMAPI interfaces in libdm.
|
||||
|
||||
AC_CHECK_LIB(dm, dm_get_eventlist,
|
||||
[samba_cv_HAVE_LIBDM=yes; samba_dmapi_libs="-ldm"],
|
||||
[samba_cv_HAVE_LIBDM=no])
|
||||
|
||||
if test x"$samba_cv_HAVE_LIBDM" = x"yes" ; then
|
||||
AC_DEFINE(HAVE_LIBDM, 1, [Whether libdm is available])
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([for kernel share modes],samba_cv_HAVE_KERNEL_SHARE_MODES,[
|
||||
AC_TRY_RUN([
|
||||
#include <sys/types.h>
|
||||
@ -5423,8 +5435,9 @@ AC_TRY_RUN([#include "${srcdir-.}/tests/summary.c"],
|
||||
builddir=`pwd`
|
||||
AC_SUBST(builddir)
|
||||
|
||||
# Stuff the FAM libraries at the end of the smbd link path (if we have them).
|
||||
SMBD_LIBS="$samba_fam_libs"
|
||||
# Stuff the smbd-only libraries at the end of the smbd link
|
||||
# path (if we have them).
|
||||
SMBD_LIBS="$samba_fam_libs $samba_dmapi_libs"
|
||||
AC_SUBST(SMBD_LIBS)
|
||||
|
||||
dnl Remove -L/usr/lib/? from LDFLAGS and LIBS
|
||||
|
@ -102,6 +102,7 @@ extern int DEBUGLEVEL;
|
||||
#define DBGC_ACLS 15
|
||||
#define DBGC_LOCKING 16
|
||||
#define DBGC_MSDFS 17
|
||||
#define DBGC_DMAPI 18
|
||||
|
||||
/* So you can define DBGC_CLASS before including debug.h */
|
||||
#ifndef DBGC_CLASS
|
||||
|
@ -1567,7 +1567,8 @@ minimum length == 18.
|
||||
*/
|
||||
|
||||
enum smbd_capability {
|
||||
KERNEL_OPLOCK_CAPABILITY
|
||||
KERNEL_OPLOCK_CAPABILITY,
|
||||
DMAPI_ACCESS_CAPABILITY
|
||||
};
|
||||
|
||||
/* if a kernel does support oplocks then a structure of the following
|
||||
|
@ -76,6 +76,10 @@
|
||||
(DEBUG(0,("PANIC: assert failed at %s(%d)\n", __FILE__, __LINE__))))
|
||||
#endif
|
||||
|
||||
#define SMB_WARN(condition, message) \
|
||||
((condition) ? (void)0 : \
|
||||
DEBUG(0, ("WARNING: %s: %s\n", #condition, message)))
|
||||
|
||||
#define SMB_ASSERT_ARRAY(a,n) SMB_ASSERT((sizeof(a)/sizeof((a)[0])) >= (n))
|
||||
|
||||
/* these are useful macros for checking validity of handles */
|
||||
|
@ -166,6 +166,7 @@ static const char *default_classname_table[] = {
|
||||
"acls", /* DBGC_ACLS */
|
||||
"locking", /* DBGC_LOCKING */
|
||||
"msdfs", /* DBGC_MSDFS */
|
||||
"dmapi", /* DBGC_DMAPI */
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -62,9 +62,10 @@ int smbrun(const char *cmd, int *outfd)
|
||||
gid_t gid = current_user.ut.gid;
|
||||
|
||||
/*
|
||||
* Lose any kernel oplock capabilities we may have.
|
||||
* Lose any elevated privileges.
|
||||
*/
|
||||
drop_effective_capability(KERNEL_OPLOCK_CAPABILITY);
|
||||
drop_effective_capability(DMAPI_ACCESS_CAPABILITY);
|
||||
|
||||
/* point our stdout at the file we want output to go into */
|
||||
|
||||
@ -194,9 +195,10 @@ int smbrunsecret(const char *cmd, const char *secret)
|
||||
int ifd[2];
|
||||
|
||||
/*
|
||||
* Lose any kernel oplock capabilities we may have.
|
||||
* Lose any elevated privileges.
|
||||
*/
|
||||
drop_effective_capability(KERNEL_OPLOCK_CAPABILITY);
|
||||
drop_effective_capability(DMAPI_ACCESS_CAPABILITY);
|
||||
|
||||
/* build up an input pipe */
|
||||
if(pipe(ifd)) {
|
||||
|
@ -22,6 +22,10 @@
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#ifdef HAVE_SYS_PRCTL_H
|
||||
#include <sys/prctl.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
The idea is that this file will eventually have wrappers around all
|
||||
important system calls in samba. The aims are:
|
||||
@ -661,6 +665,19 @@ static BOOL set_process_capability(enum smbd_capability capability,
|
||||
|
||||
cap_t cap;
|
||||
|
||||
#if defined(HAVE_PRCTL) && defined(PR_GET_KEEPCAPS) && defined(PR_SET_KEEPCAPS)
|
||||
/* On Linux, make sure that any capabilities we grab are sticky
|
||||
* across UID changes. We expect that this would allow us to keep both
|
||||
* the effective and permitted capability sets, but as of circa 2.6.16,
|
||||
* only the permitted set is kept. It is a bug (which we work around)
|
||||
* that the effective set is lost, but we still require the effective
|
||||
* set to be kept.
|
||||
*/
|
||||
if (!prctl(PR_GET_KEEPCAPS)) {
|
||||
prctl(PR_SET_KEEPCAPS, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
cap = cap_get_proc();
|
||||
if (cap == NULL) {
|
||||
DEBUG(0,("set_process_capability: cap_get_proc failed: %s\n",
|
||||
@ -673,6 +690,15 @@ static BOOL set_process_capability(enum smbd_capability capability,
|
||||
#ifdef CAP_NETWORK_MGT
|
||||
/* IRIX has CAP_NETWORK_MGT for oplocks. */
|
||||
cap_vals[num_cap_vals++] = CAP_NETWORK_MGT;
|
||||
#endif
|
||||
break;
|
||||
case DMAPI_ACCESS_CAPABILITY:
|
||||
#ifdef CAP_DEVICE_MGT
|
||||
/* IRIX has CAP_DEVICE_MGT for DMAPI access. */
|
||||
cap_vals[num_cap_vals++] = CAP_DEVICE_MGT;
|
||||
#elif CAP_MKNOD
|
||||
/* Linux has CAP_MKNOD for DMAPI access. */
|
||||
cap_vals[num_cap_vals++] = CAP_MKNOD;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@ -686,6 +712,10 @@ static BOOL set_process_capability(enum smbd_capability capability,
|
||||
|
||||
cap_set_flag(cap, CAP_EFFECTIVE, num_cap_vals, cap_vals,
|
||||
enable ? CAP_SET : CAP_CLEAR);
|
||||
|
||||
/* We never want to pass capabilities down to our children, so make
|
||||
* sure they are not inherited.
|
||||
*/
|
||||
cap_set_flag(cap, CAP_INHERITABLE, num_cap_vals, cap_vals, CAP_CLEAR);
|
||||
|
||||
if (cap_set_proc(cap) == -1) {
|
||||
|
@ -410,6 +410,7 @@ typedef struct {
|
||||
BOOL bMap_hidden;
|
||||
BOOL bMap_archive;
|
||||
BOOL bStoreDosAttributes;
|
||||
BOOL bDmapiSupport;
|
||||
BOOL bLocking;
|
||||
int iStrictLocking;
|
||||
BOOL bPosixLocking;
|
||||
@ -547,6 +548,7 @@ static service sDefault = {
|
||||
False, /* bMap_hidden */
|
||||
True, /* bMap_archive */
|
||||
False, /* bStoreDosAttributes */
|
||||
False, /* bDmapiSupport */
|
||||
True, /* bLocking */
|
||||
True, /* iStrictLocking */
|
||||
True, /* bPosixLocking */
|
||||
@ -1097,6 +1099,8 @@ static struct parm_struct parm_table[] = {
|
||||
{"max stat cache size", P_INTEGER, P_GLOBAL, &Globals.iMaxStatCacheSize, NULL, NULL, FLAG_ADVANCED},
|
||||
{"stat cache", P_BOOL, P_GLOBAL, &Globals.bStatCache, NULL, NULL, FLAG_ADVANCED},
|
||||
{"store dos attributes", P_BOOL, P_LOCAL, &sDefault.bStoreDosAttributes, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL},
|
||||
{"dmapi support", P_BOOL, P_LOCAL, &sDefault.bDmapiSupport, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL},
|
||||
|
||||
|
||||
{N_("Domain Options"), P_SEP, P_SEPARATOR},
|
||||
|
||||
@ -2024,6 +2028,7 @@ FN_LOCAL_BOOL(lp_print_ok, bPrint_ok)
|
||||
FN_LOCAL_BOOL(lp_map_hidden, bMap_hidden)
|
||||
FN_LOCAL_BOOL(lp_map_archive, bMap_archive)
|
||||
FN_LOCAL_BOOL(lp_store_dos_attributes, bStoreDosAttributes)
|
||||
FN_LOCAL_BOOL(lp_dmapi_support, bDmapiSupport)
|
||||
FN_LOCAL_BOOL(lp_locking, bLocking)
|
||||
FN_LOCAL_INTEGER(lp_strict_locking, iStrictLocking)
|
||||
FN_LOCAL_BOOL(lp_posix_locking, bPosixLocking)
|
||||
|
@ -415,9 +415,10 @@ while we were waiting\n", WTERMSIG(wstat)));
|
||||
/* CHILD */
|
||||
|
||||
/*
|
||||
* Lose any oplock capabilities.
|
||||
* Lose any elevated privileges.
|
||||
*/
|
||||
drop_effective_capability(KERNEL_OPLOCK_CAPABILITY);
|
||||
drop_effective_capability(DMAPI_ACCESS_CAPABILITY);
|
||||
|
||||
/* make sure it doesn't freeze */
|
||||
alarm(20);
|
||||
|
576
source3/smbd/dmapi.c
Normal file
576
source3/smbd/dmapi.c
Normal file
@ -0,0 +1,576 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
DMAPI Support routines
|
||||
|
||||
Copyright (C) James Peach 2006
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#undef DBGC_CLASS
|
||||
#define DBGC_CLASS DBGC_DMAPI
|
||||
|
||||
#if defined(HAVE_LIBDM)
|
||||
#if (defined(HAVE_XFS_DMAPI_H) || defined(HAVE_SYS_DMI_H))
|
||||
#define USE_DMAPI 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef USE_DMAPI
|
||||
|
||||
int dmapi_init_session(void) { return -1; }
|
||||
uint32 dmapi_file_flags(const char * const path) { return 0; }
|
||||
BOOL dmapi_have_session(void) { return False; }
|
||||
|
||||
#else /* USE_DMAPI */
|
||||
|
||||
#ifdef HAVE_XFS_DMAPI_H
|
||||
#include <xfs/dmapi.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_DMI_H
|
||||
#include <sys/dmi.h>
|
||||
#endif
|
||||
|
||||
#define DMAPI_SESSION_NAME "samba"
|
||||
#define DMAPI_TRACE 10
|
||||
|
||||
static dm_sessid_t dmapi_session = DM_NO_SESSION;
|
||||
|
||||
/* Initialise the DMAPI interface. Make sure that we only end up initialising
|
||||
* once per process to avoid resource leaks across different DMAPI
|
||||
* implementations.
|
||||
*/
|
||||
static int init_dmapi_service(void)
|
||||
{
|
||||
static pid_t lastpid;
|
||||
|
||||
pid_t mypid;
|
||||
|
||||
mypid = sys_getpid();
|
||||
if (mypid != lastpid) {
|
||||
char *version;
|
||||
|
||||
lastpid = mypid;
|
||||
if (dm_init_service(&version) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG(0, ("Initializing DMAPI: %s\n", version));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL dmapi_have_session(void)
|
||||
{
|
||||
return dmapi_session != DM_NO_SESSION;
|
||||
}
|
||||
|
||||
static dm_sessid_t *realloc_session_list(dm_sessid_t * sessions, int count)
|
||||
{
|
||||
dm_sessid_t *nsessions;
|
||||
|
||||
nsessions = TALLOC_REALLOC_ARRAY(NULL, sessions, dm_sessid_t, count);
|
||||
if (nsessions == NULL) {
|
||||
TALLOC_FREE(sessions);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return nsessions;
|
||||
}
|
||||
|
||||
/* Initialise DMAPI session. The session is persistant kernel state, so it
|
||||
* might already exist, in which case we merely want to reconnect to it. This
|
||||
* function should be called as root.
|
||||
*/
|
||||
int dmapi_init_session(void)
|
||||
{
|
||||
char buf[DM_SESSION_INFO_LEN];
|
||||
size_t buflen;
|
||||
|
||||
uint nsessions = 10;
|
||||
dm_sessid_t *sessions = NULL;
|
||||
|
||||
int i, err;
|
||||
|
||||
/* If we aren't root, something in the following will fail due to lack
|
||||
* of privileges. Aborting seems a little extreme.
|
||||
*/
|
||||
SMB_WARN(getuid() == 0, "dmapi_init_session must be called as root");
|
||||
|
||||
dmapi_session = DM_NO_SESSION;
|
||||
if (init_dmapi_service() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
retry:
|
||||
|
||||
if ((sessions = realloc_session_list(sessions, nsessions)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = dm_getall_sessions(nsessions, sessions, &nsessions);
|
||||
if (err < 0) {
|
||||
if (errno == E2BIG) {
|
||||
nsessions *= 2;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
DEBUGADD(DMAPI_TRACE,
|
||||
("failed to retrieve DMAPI sessions: %s\n",
|
||||
strerror(errno)));
|
||||
TALLOC_FREE(sessions);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < nsessions; ++i) {
|
||||
err = dm_query_session(sessions[i], sizeof(buf), buf, &buflen);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
if (err == 0 && strcmp(DMAPI_SESSION_NAME, buf) == 0) {
|
||||
dmapi_session = sessions[i];
|
||||
DEBUGADD(DMAPI_TRACE,
|
||||
("attached to existing DMAPI session "
|
||||
"named '%s'\n", buf));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TALLOC_FREE(sessions);
|
||||
|
||||
/* No session already defined. */
|
||||
if (dmapi_session == DM_NO_SESSION) {
|
||||
err = dm_create_session(DM_NO_SESSION, DMAPI_SESSION_NAME,
|
||||
&dmapi_session);
|
||||
if (err < 0) {
|
||||
DEBUGADD(DMAPI_TRACE,
|
||||
("failed to create new DMAPI session: %s\n",
|
||||
strerror(errno)));
|
||||
dmapi_session = DM_NO_SESSION;
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUGADD(DMAPI_TRACE,
|
||||
("created new DMAPI session named '%s'\n",
|
||||
DMAPI_SESSION_NAME));
|
||||
}
|
||||
|
||||
/* Note that we never end the DMAPI session. This enables child
|
||||
* processes to continue to use the session after we exit. It also lets
|
||||
* you run a second Samba server on different ports without any
|
||||
* conflict.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reattach to an existing dmapi session. Called from service processes that
|
||||
* might not be running as root.
|
||||
*/
|
||||
static int reattach_dmapi_session(void)
|
||||
{
|
||||
char buf[DM_SESSION_INFO_LEN];
|
||||
size_t buflen;
|
||||
|
||||
if (dmapi_session != DM_NO_SESSION ) {
|
||||
become_root();
|
||||
|
||||
/* NOTE: On Linux, this call opens /dev/dmapi, costing us a
|
||||
* file descriptor. Ideally, we would close this when we fork.
|
||||
*/
|
||||
if (init_dmapi_service() < 0) {
|
||||
dmapi_session = DM_NO_SESSION;
|
||||
unbecome_root();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dm_query_session(dmapi_session, sizeof(buf),
|
||||
buf, &buflen) < 0) {
|
||||
/* Session is stale. Disable DMAPI. */
|
||||
dmapi_session = DM_NO_SESSION;
|
||||
unbecome_root();
|
||||
return -1;
|
||||
}
|
||||
|
||||
set_effective_capability(DMAPI_ACCESS_CAPABILITY);
|
||||
|
||||
DEBUG(DMAPI_TRACE, ("reattached DMAPI session\n"));
|
||||
unbecome_root();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 dmapi_file_flags(const char * const path)
|
||||
{
|
||||
static int attached = 0;
|
||||
|
||||
int err;
|
||||
dm_eventset_t events = {0};
|
||||
uint nevents;
|
||||
|
||||
void *dm_handle;
|
||||
size_t dm_handle_len;
|
||||
|
||||
uint32 flags = 0;
|
||||
|
||||
/* If a DMAPI session has been initialised, then we need to make sure
|
||||
* we are attached to it and have the correct privileges. This is
|
||||
* necessary to be able to do DMAPI operations across a fork(2). If
|
||||
* it fails, there is no liklihood of that failure being transient.
|
||||
*
|
||||
* Note that this use of the static attached flag relies on the fact
|
||||
* that dmapi_file_flags() is never called prior to forking the
|
||||
* per-client server process.
|
||||
*/
|
||||
if (dmapi_have_session() && !attached) {
|
||||
attached++;
|
||||
if (reattach_dmapi_session() < 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
err = dm_path_to_handle(CONST_DISCARD(char *, path),
|
||||
&dm_handle, &dm_handle_len);
|
||||
if (err < 0) {
|
||||
DEBUG(DMAPI_TRACE, ("dm_path_to_handle(%s): %s\n",
|
||||
path, strerror(errno)));
|
||||
|
||||
if (errno != EPERM) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Linux capabilities are broken in that changing our
|
||||
* user ID will clobber out effective capabilities irrespective
|
||||
* of whether we have set PR_SET_KEEPCAPS. Fortunately, the
|
||||
* capabilities are not removed from our permitted set, so we
|
||||
* can re-acquire them if necessary.
|
||||
*/
|
||||
|
||||
set_effective_capability(DMAPI_ACCESS_CAPABILITY);
|
||||
|
||||
err = dm_path_to_handle(CONST_DISCARD(char *, path),
|
||||
&dm_handle, &dm_handle_len);
|
||||
if (err < 0) {
|
||||
DEBUG(DMAPI_TRACE,
|
||||
("retrying dm_path_to_handle(%s): %s\n",
|
||||
path, strerror(errno)));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
err = dm_get_eventlist(dmapi_session, dm_handle, dm_handle_len,
|
||||
DM_NO_TOKEN, DM_EVENT_MAX, &events, &nevents);
|
||||
if (err < 0) {
|
||||
DEBUG(DMAPI_TRACE, ("dm_get_eventlist(%s): %s\n",
|
||||
path, strerror(errno)));
|
||||
dm_handle_free(dm_handle, dm_handle_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We figure that the only reason a DMAPI application would be
|
||||
* interested in trapping read events is that part of the file is
|
||||
* offline.
|
||||
*/
|
||||
DEBUG(DMAPI_TRACE, ("DMAPI event list for %s is %#llx\n",
|
||||
path, events));
|
||||
if (DMEV_ISSET(DM_EVENT_READ, events)) {
|
||||
flags = FILE_ATTRIBUTE_OFFLINE;
|
||||
}
|
||||
|
||||
dm_handle_free(dm_handle, dm_handle_len);
|
||||
|
||||
if (flags & FILE_ATTRIBUTE_OFFLINE) {
|
||||
DEBUG(DMAPI_TRACE, ("%s is OFFLINE\n", path));
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
#endif /* USE_DMAPI */
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
DMAPI Support routines
|
||||
|
||||
Copyright (C) Silicon Graphics, Inc. 2006. All rights reserved.
|
||||
James Peach <jpeach@sgi.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#undef DBGC_CLASS
|
||||
#define DBGC_CLASS DBGC_DMAPI
|
||||
|
||||
#if defined(HAVE_LIBDM)
|
||||
#if (defined(HAVE_XFS_DMAPI_H) || defined(HAVE_SYS_DMI_H))
|
||||
#define USE_DMAPI 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef USE_DMAPI
|
||||
|
||||
int dmapi_init_session(void) { return -1; }
|
||||
uint32 dmapi_file_flags(const char * const path) { return 0; }
|
||||
BOOL dmapi_have_session(void) { return False; }
|
||||
|
||||
#else /* USE_DMAPI */
|
||||
|
||||
#ifdef HAVE_XFS_DMAPI_H
|
||||
#include <xfs/dmapi.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_DMI_H
|
||||
#include <sys/dmi.h>
|
||||
#endif
|
||||
|
||||
#define DMAPI_SESSION_NAME "samba"
|
||||
#define DMAPI_TRACE 10
|
||||
|
||||
static dm_sessid_t dmapi_session = DM_NO_SESSION;
|
||||
|
||||
/* Initialise the DMAPI interface. Make sure that we only end up initialising
|
||||
* once per process to avoid resource leaks across different DMAPI
|
||||
* implementations.
|
||||
*/
|
||||
static int init_dmapi_service(void)
|
||||
{
|
||||
static pid_t lastpid;
|
||||
|
||||
pid_t mypid;
|
||||
|
||||
mypid = sys_getpid();
|
||||
if (mypid != lastpid) {
|
||||
char *version;
|
||||
|
||||
lastpid = mypid;
|
||||
if (dm_init_service(&version) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG(0, ("Initializing DMAPI: %s\n", version));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL dmapi_have_session(void)
|
||||
{
|
||||
return dmapi_session != DM_NO_SESSION;
|
||||
}
|
||||
|
||||
static dm_sessid_t *realloc_session_list(dm_sessid_t * sessions, int count)
|
||||
{
|
||||
dm_sessid_t *nsessions;
|
||||
|
||||
nsessions = TALLOC_REALLOC_ARRAY(NULL, sessions, dm_sessid_t, count);
|
||||
if (nsessions == NULL) {
|
||||
TALLOC_FREE(sessions);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return nsessions;
|
||||
}
|
||||
|
||||
/* Initialise DMAPI session. The session is persistant kernel state, so it
|
||||
* might already exist, in which case we merely want to reconnect to it. This
|
||||
* function should be called as root.
|
||||
*/
|
||||
int dmapi_init_session(void)
|
||||
{
|
||||
char buf[DM_SESSION_INFO_LEN];
|
||||
size_t buflen;
|
||||
|
||||
uint nsessions = 10;
|
||||
dm_sessid_t *sessions = NULL;
|
||||
|
||||
int i, err;
|
||||
|
||||
/* If we aren't root, something in the following will fail due to lack
|
||||
* of privileges. Aborting seems a little extreme.
|
||||
*/
|
||||
SMB_WARN(getuid() == 0, "dmapi_init_session must be called as root");
|
||||
|
||||
dmapi_session = DM_NO_SESSION;
|
||||
if (init_dmapi_service() < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
retry:
|
||||
|
||||
if ((sessions = realloc_session_list(sessions, nsessions)) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = dm_getall_sessions(nsessions, sessions, &nsessions);
|
||||
if (err < 0) {
|
||||
if (errno == E2BIG) {
|
||||
nsessions *= 2;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
DEBUGADD(DMAPI_TRACE,
|
||||
("failed to retrieve DMAPI sessions: %s\n",
|
||||
strerror(errno)));
|
||||
TALLOC_FREE(sessions);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < nsessions; ++i) {
|
||||
err = dm_query_session(sessions[i], sizeof(buf), buf, &buflen);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
if (err == 0 && strcmp(DMAPI_SESSION_NAME, buf) == 0) {
|
||||
dmapi_session = sessions[i];
|
||||
DEBUGADD(DMAPI_TRACE,
|
||||
("attached to existing DMAPI session "
|
||||
"named '%s'\n", buf));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TALLOC_FREE(sessions);
|
||||
|
||||
/* No session already defined. */
|
||||
if (dmapi_session == DM_NO_SESSION) {
|
||||
err = dm_create_session(DM_NO_SESSION, DMAPI_SESSION_NAME,
|
||||
&dmapi_session);
|
||||
if (err < 0) {
|
||||
DEBUGADD(DMAPI_TRACE,
|
||||
("failed to create new DMAPI session: %s\n",
|
||||
strerror(errno)));
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUGADD(DMAPI_TRACE,
|
||||
("created new DMAPI session named '%s'\n",
|
||||
DMAPI_SESSION_NAME));
|
||||
}
|
||||
|
||||
/* Note that we never end the DMAPI session. This enables child
|
||||
* processes to continue to use the session after we exit. It also lets
|
||||
* you run a second Samba server on different ports without any
|
||||
* conflict.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reattach to an existing dmapi session. Called from service processes that
|
||||
* might not be running as root.
|
||||
*/
|
||||
static int reattach_dmapi_session(void)
|
||||
{
|
||||
char buf[DM_SESSION_INFO_LEN];
|
||||
size_t buflen;
|
||||
|
||||
if (dmapi_session != DM_NO_SESSION ) {
|
||||
become_root();
|
||||
|
||||
/* NOTE: On Linux, this call opens /dev/dmapi, costing us a
|
||||
* file descriptor. Ideally, we would close this when we fork.
|
||||
*/
|
||||
if (init_dmapi_service() < 0) {
|
||||
dmapi_session = DM_NO_SESSION;
|
||||
unbecome_root();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dm_query_session(dmapi_session, sizeof(buf),
|
||||
buf, &buflen) < 0) {
|
||||
/* Session is stale. Disable DMAPI. */
|
||||
dmapi_session = DM_NO_SESSION;
|
||||
unbecome_root();
|
||||
return -1;
|
||||
}
|
||||
|
||||
set_effective_capability(DMAPI_ACCESS_CAPABILITY);
|
||||
|
||||
DEBUG(DMAPI_TRACE, ("reattached DMAPI session\n"));
|
||||
unbecome_root();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32 dmapi_file_flags(const char * const path)
|
||||
{
|
||||
int err;
|
||||
dm_eventset_t events = {0};
|
||||
uint nevents;
|
||||
|
||||
void *dm_handle;
|
||||
size_t dm_handle_len;
|
||||
|
||||
uint32 flags = 0;
|
||||
|
||||
if (dmapi_have_session()) {
|
||||
if (reattach_dmapi_session() < 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
err = dm_path_to_handle(CONST_DISCARD(char *, path),
|
||||
&dm_handle, &dm_handle_len);
|
||||
if (err < 0) {
|
||||
DEBUG(DMAPI_TRACE, ("dm_path_to_handle(%s): %s\n",
|
||||
path, strerror(errno)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = dm_get_eventlist(dmapi_session, dm_handle, dm_handle_len,
|
||||
DM_NO_TOKEN, DM_EVENT_MAX, &events, &nevents);
|
||||
if (err < 0) {
|
||||
DEBUG(DMAPI_TRACE, ("dm_get_eventlist: %s\n",
|
||||
strerror(errno)));
|
||||
dm_handle_free(dm_handle, dm_handle_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We figure that the only reason a DMAPI application would be
|
||||
* interested in trapping read events is that part of the file is
|
||||
* offline.
|
||||
*/
|
||||
DEBUG(DMAPI_TRACE, ("DMAPI event list for %s is %#llx\n",
|
||||
path, events));
|
||||
if (DMEV_ISSET(DM_EVENT_READ, events)) {
|
||||
flags = FILE_ATTRIBUTE_OFFLINE;
|
||||
}
|
||||
|
||||
dm_handle_free(dm_handle, dm_handle_len);
|
||||
|
||||
if (flags & FILE_ATTRIBUTE_OFFLINE) {
|
||||
DEBUG(DMAPI_TRACE, ("%s is OFFLINE\n", path));
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
#endif /* USE_DMAPI */
|
@ -2,6 +2,7 @@
|
||||
Unix SMB/CIFS implementation.
|
||||
dos mode handling functions
|
||||
Copyright (C) Andrew Tridgell 1992-1998
|
||||
Copyright (C) James Peach 2006
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -30,6 +31,31 @@ static int set_sparse_flag(const SMB_STRUCT_STAT * const sbuf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Work out whether this file is offline
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef ISDOT
|
||||
#define ISDOT(p) (*(p) == '.' && *((p) + 1) == '\0')
|
||||
#endif /* ISDOT */
|
||||
|
||||
#ifndef ISDOTDOT
|
||||
#define ISDOTDOT(p) (*(p) == '.' && *((p) + 1) == '.' && *((p) + 2) == '\0')
|
||||
#endif /* ISDOTDOT */
|
||||
|
||||
static uint32 set_offline_flag(connection_struct *conn, const char *const path)
|
||||
{
|
||||
if (ISDOT(path) || ISDOTDOT(path)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return dmapi_file_flags(path);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Change a dos mode to a unix mode.
|
||||
Base permission for files:
|
||||
@ -325,6 +351,10 @@ uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
|
||||
result |= dos_mode_from_sbuf(conn, path, sbuf);
|
||||
}
|
||||
|
||||
if (S_ISREG(sbuf->st_mode)) {
|
||||
result |= set_offline_flag(conn, path);
|
||||
}
|
||||
|
||||
/* Optimization : Only call is_hidden_path if it's not already
|
||||
hidden. */
|
||||
if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) {
|
||||
|
@ -930,6 +930,12 @@ void build_options(BOOL screen);
|
||||
if ( is_daemon && !interactive )
|
||||
start_background_queue();
|
||||
|
||||
/* Always attempt to initialize DMAPI. We will only use it later if
|
||||
* lp_dmapi_support is set on the share, but we need a single global
|
||||
* session to work with.
|
||||
*/
|
||||
dmapi_init_session();
|
||||
|
||||
if (!open_sockets_smbd(is_daemon, interactive, ports))
|
||||
exit(1);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user