smbd/dmapi.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    DMAPI Support routines
00004 
00005    Copyright (C) James Peach 2006
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011    
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016    
00017    You should have received a copy of the GNU General Public License
00018    along with this program; if not, write to the Free Software
00019    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00020 */
00021 
00022 #include "includes.h"
00023 
00024 #undef DBGC_CLASS
00025 #define DBGC_CLASS DBGC_DMAPI
00026 
00027 #ifndef USE_DMAPI
00028 
00029 int dmapi_init_session(void) { return -1; }
00030 uint32 dmapi_file_flags(const char * const path) { return 0; }
00031 BOOL dmapi_have_session(void) { return False; }
00032 
00033 #else /* USE_DMAPI */
00034 
00035 #ifdef HAVE_XFS_DMAPI_H
00036 #include <xfs/dmapi.h>
00037 #elif defined(HAVE_SYS_DMI_H)
00038 #include <sys/dmi.h>
00039 #elif defined(HAVE_SYS_JFSDMAPI_H)
00040 #include <sys/jfsdmapi.h>
00041 #elif defined(HAVE_SYS_DMAPI_H)
00042 #include <sys/dmapi.h>
00043 #elif defined(HAVE_DMAPI_H)
00044 #include <dmapi.h>
00045 #endif
00046 
00047 #define DMAPI_SESSION_NAME "samba"
00048 #define DMAPI_TRACE 10
00049 
00050 static dm_sessid_t dmapi_session = DM_NO_SESSION;
00051 
00052 /* Initialise the DMAPI interface. Make sure that we only end up initialising
00053  * once per process to avoid resource leaks across different DMAPI
00054  * implementations.
00055  */
00056 static int init_dmapi_service(void)
00057 {
00058         static pid_t lastpid;
00059 
00060         pid_t mypid;
00061 
00062         mypid = sys_getpid();
00063         if (mypid != lastpid) {
00064                 char *version;
00065 
00066                 lastpid = mypid;
00067                 if (dm_init_service(&version) < 0) {
00068                         return -1;
00069                 }
00070 
00071                 DEBUG(0, ("Initializing DMAPI: %s\n", version));
00072         }
00073 
00074         return 0;
00075 }
00076 
00077 BOOL dmapi_have_session(void)
00078 {
00079         return dmapi_session != DM_NO_SESSION;
00080 }
00081 
00082 static dm_sessid_t *realloc_session_list(dm_sessid_t * sessions, int count)
00083 {
00084         dm_sessid_t *nsessions;
00085 
00086         nsessions = TALLOC_REALLOC_ARRAY(NULL, sessions, dm_sessid_t, count);
00087         if (nsessions == NULL) {
00088                 TALLOC_FREE(sessions);
00089                 return NULL;
00090         }
00091 
00092         return nsessions;
00093 }
00094 
00095 /* Initialise DMAPI session. The session is persistant kernel state, so it
00096  * might already exist, in which case we merely want to reconnect to it. This
00097  * function should be called as root.
00098  */
00099 int dmapi_init_session(void)
00100 {
00101         char    buf[DM_SESSION_INFO_LEN];
00102         size_t  buflen;
00103 
00104         uint        nsessions = 10;
00105         dm_sessid_t *sessions = NULL;
00106 
00107         int i, err;
00108 
00109         /* If we aren't root, something in the following will fail due to lack
00110          * of privileges. Aborting seems a little extreme.
00111          */
00112         SMB_WARN(getuid() == 0, "dmapi_init_session must be called as root");
00113 
00114         dmapi_session = DM_NO_SESSION;
00115         if (init_dmapi_service() < 0) {
00116                 return -1;
00117         }
00118 
00119 retry:
00120 
00121         if ((sessions = realloc_session_list(sessions, nsessions)) == NULL) {
00122                 return -1;
00123         }
00124 
00125         err = dm_getall_sessions(nsessions, sessions, &nsessions);
00126         if (err < 0) {
00127                 if (errno == E2BIG) {
00128                         nsessions *= 2;
00129                         goto retry;
00130                 }
00131 
00132                 DEBUGADD(DMAPI_TRACE,
00133                         ("failed to retrieve DMAPI sessions: %s\n",
00134                         strerror(errno)));
00135                 TALLOC_FREE(sessions);
00136                 return -1;
00137         }
00138 
00139         for (i = 0; i < nsessions; ++i) {
00140                 err = dm_query_session(sessions[i], sizeof(buf), buf, &buflen);
00141                 buf[sizeof(buf) - 1] = '\0';
00142                 if (err == 0 && strcmp(DMAPI_SESSION_NAME, buf) == 0) {
00143                         dmapi_session = sessions[i];
00144                         DEBUGADD(DMAPI_TRACE,
00145                                 ("attached to existing DMAPI session "
00146                                  "named '%s'\n", buf));
00147                         break;
00148                 }
00149         }
00150 
00151         TALLOC_FREE(sessions);
00152 
00153         /* No session already defined. */
00154         if (dmapi_session == DM_NO_SESSION) {
00155                 err = dm_create_session(DM_NO_SESSION, DMAPI_SESSION_NAME,
00156                                         &dmapi_session);
00157                 if (err < 0) {
00158                         DEBUGADD(DMAPI_TRACE,
00159                                 ("failed to create new DMAPI session: %s\n",
00160                                 strerror(errno)));
00161                         dmapi_session = DM_NO_SESSION;
00162                         return -1;
00163                 }
00164 
00165                 DEBUGADD(DMAPI_TRACE,
00166                         ("created new DMAPI session named '%s'\n",
00167                         DMAPI_SESSION_NAME));
00168         }
00169 
00170         /* Note that we never end the DMAPI session. This enables child
00171          * processes to continue to use the session after we exit. It also lets
00172          * you run a second Samba server on different ports without any
00173          * conflict.
00174          */
00175 
00176         return 0;
00177 }
00178 
00179 /* Reattach to an existing dmapi session. Called from service processes that
00180  * might not be running as root.
00181  */
00182 static int reattach_dmapi_session(void)
00183 {
00184         char    buf[DM_SESSION_INFO_LEN];
00185         size_t  buflen;
00186 
00187         if (dmapi_session != DM_NO_SESSION ) {
00188                 become_root();
00189 
00190                 /* NOTE: On Linux, this call opens /dev/dmapi, costing us a
00191                  * file descriptor. Ideally, we would close this when we fork.
00192                  */
00193                 if (init_dmapi_service() < 0) {
00194                         dmapi_session = DM_NO_SESSION;
00195                         unbecome_root();
00196                         return -1;
00197                 }
00198 
00199                 if (dm_query_session(dmapi_session, sizeof(buf),
00200                             buf, &buflen) < 0) {
00201                         /* Session is stale. Disable DMAPI. */
00202                         dmapi_session = DM_NO_SESSION;
00203                         unbecome_root();
00204                         return -1;
00205                 }
00206 
00207                 set_effective_capability(DMAPI_ACCESS_CAPABILITY);
00208 
00209                 DEBUG(DMAPI_TRACE, ("reattached DMAPI session\n"));
00210                 unbecome_root();
00211         }
00212 
00213         return 0;
00214 }
00215 
00216 uint32 dmapi_file_flags(const char * const path)
00217 {
00218         static int attached = 0;
00219 
00220         int             err;
00221         dm_eventset_t   events = {0};
00222         uint            nevents;
00223 
00224         void    *dm_handle;
00225         size_t  dm_handle_len;
00226 
00227         uint32  flags = 0;
00228 
00229         /* If a DMAPI session has been initialised, then we need to make sure
00230          * we are attached to it and have the correct privileges. This is
00231          * necessary to be able to do DMAPI operations across a fork(2). If
00232          * it fails, there is no liklihood of that failure being transient.
00233          *
00234          * Note that this use of the static attached flag relies on the fact
00235          * that dmapi_file_flags() is never called prior to forking the
00236          * per-client server process.
00237          */
00238         if (dmapi_have_session() && !attached) {
00239                 attached++;
00240                 if (reattach_dmapi_session() < 0) {
00241                         return 0;
00242                 }
00243         }
00244 
00245         /* AIX has DMAPI but no POSIX capablities support. In this case,
00246          * we need to be root to do DMAPI manipulations.
00247          */
00248 #ifndef HAVE_POSIX_CAPABILITIES
00249         become_root();
00250 #endif
00251 
00252         err = dm_path_to_handle(CONST_DISCARD(char *, path),
00253                 &dm_handle, &dm_handle_len);
00254         if (err < 0) {
00255                 DEBUG(DMAPI_TRACE, ("dm_path_to_handle(%s): %s\n",
00256                             path, strerror(errno)));
00257 
00258                 if (errno != EPERM) {
00259                         goto done;
00260                 }
00261 
00262                 /* Linux capabilities are broken in that changing our
00263                  * user ID will clobber out effective capabilities irrespective
00264                  * of whether we have set PR_SET_KEEPCAPS. Fortunately, the
00265                  * capabilities are not removed from our permitted set, so we
00266                  * can re-acquire them if necessary.
00267                  */
00268 
00269                 set_effective_capability(DMAPI_ACCESS_CAPABILITY);
00270 
00271                 err = dm_path_to_handle(CONST_DISCARD(char *, path),
00272                         &dm_handle, &dm_handle_len);
00273                 if (err < 0) {
00274                         DEBUG(DMAPI_TRACE,
00275                             ("retrying dm_path_to_handle(%s): %s\n",
00276                             path, strerror(errno)));
00277                         goto done;
00278                 }
00279         }
00280 
00281         err = dm_get_eventlist(dmapi_session, dm_handle, dm_handle_len,
00282                 DM_NO_TOKEN, DM_EVENT_MAX, &events, &nevents);
00283         if (err < 0) {
00284                 DEBUG(DMAPI_TRACE, ("dm_get_eventlist(%s): %s\n",
00285                             path, strerror(errno)));
00286                 dm_handle_free(dm_handle, dm_handle_len);
00287                 goto done;
00288         }
00289 
00290         /* We figure that the only reason a DMAPI application would be
00291          * interested in trapping read events is that part of the file is
00292          * offline.
00293          */
00294         DEBUG(DMAPI_TRACE, ("DMAPI event list for %s is %#llx\n",
00295                     path, events));
00296         if (DMEV_ISSET(DM_EVENT_READ, events)) {
00297                 flags = FILE_ATTRIBUTE_OFFLINE;
00298         }
00299 
00300         dm_handle_free(dm_handle, dm_handle_len);
00301 
00302         if (flags & FILE_ATTRIBUTE_OFFLINE) {
00303                 DEBUG(DMAPI_TRACE, ("%s is OFFLINE\n", path));
00304         }
00305 
00306 done:
00307 
00308 #ifndef HAVE_POSIX_CAPABILITIES
00309         unbecome_root();
00310 #endif
00311 
00312         return flags;
00313 }
00314 
00315 #endif /* USE_DMAPI */

Sambaに対してSat Aug 29 21:23:23 2009に生成されました。  doxygen 1.4.7