• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source3/smbd/
1/*
2   Unix SMB/CIFS implementation.
3   DMAPI Support routines
4
5   Copyright (C) James Peach 2006
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program.  If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#include "includes.h"
22#include "smbd/globals.h"
23
24#undef DBGC_CLASS
25#define DBGC_CLASS DBGC_DMAPI
26
27#ifndef USE_DMAPI
28
29uint32 dmapi_file_flags(const char * const path) { return 0; }
30bool dmapi_have_session(void) { return False; }
31const void * dmapi_get_current_session(void) { return NULL; }
32
33#else /* USE_DMAPI */
34
35#ifdef HAVE_XFS_DMAPI_H
36#include <xfs/dmapi.h>
37#elif defined(HAVE_SYS_DMI_H)
38#include <sys/dmi.h>
39#elif defined(HAVE_SYS_JFSDMAPI_H)
40#include <sys/jfsdmapi.h>
41#elif defined(HAVE_SYS_DMAPI_H)
42#include <sys/dmapi.h>
43#elif defined(HAVE_DMAPI_H)
44#include <dmapi.h>
45#endif
46
47#define DMAPI_SESSION_NAME "samba"
48#define DMAPI_TRACE 10
49
50struct smbd_dmapi_context {
51	dm_sessid_t session;
52	unsigned session_num;
53};
54
55/*
56   Initialise DMAPI session. The session is persistant kernel state,
57   so it might already exist, in which case we merely want to
58   reconnect to it. This function should be called as root.
59*/
60static int dmapi_init_session(struct smbd_dmapi_context *ctx)
61{
62	char	buf[DM_SESSION_INFO_LEN];
63	size_t	buflen;
64	uint	    nsessions = 5;
65	dm_sessid_t *sessions = NULL;
66	char    *version;
67	char    *session_name;
68	TALLOC_CTX *tmp_ctx = talloc_new(NULL);
69
70	int i, err;
71
72	if (ctx->session_num == 0) {
73		session_name = talloc_strdup(tmp_ctx, DMAPI_SESSION_NAME);
74	} else {
75		session_name = talloc_asprintf(tmp_ctx, "%s%u", DMAPI_SESSION_NAME,
76					       ctx->session_num);
77	}
78
79	if (session_name == NULL) {
80		DEBUG(0,("Out of memory in dmapi_init_session\n"));
81		talloc_free(tmp_ctx);
82		return -1;
83	}
84
85
86	if (dm_init_service(&version) < 0) {
87		DEBUG(0, ("dm_init_service failed - disabling DMAPI\n"));
88		talloc_free(tmp_ctx);
89		return -1;
90	}
91
92	ZERO_STRUCT(buf);
93
94	/* Fetch kernel DMAPI sessions until we get any of them */
95	do {
96		dm_sessid_t *new_sessions;
97		nsessions *= 2;
98		new_sessions = TALLOC_REALLOC_ARRAY(tmp_ctx, sessions,
99						    dm_sessid_t, nsessions);
100		if (new_sessions == NULL) {
101			talloc_free(tmp_ctx);
102			return -1;
103		}
104
105		sessions = new_sessions;
106		err = dm_getall_sessions(nsessions, sessions, &nsessions);
107	} while (err == -1 && errno == E2BIG);
108
109	if (err == -1) {
110		DEBUGADD(DMAPI_TRACE,
111			("failed to retrieve DMAPI sessions: %s\n",
112			strerror(errno)));
113		talloc_free(tmp_ctx);
114		return -1;
115	}
116
117	/* Look through existing kernel DMAPI sessions to find out ours */
118	for (i = 0; i < nsessions; ++i) {
119		err = dm_query_session(sessions[i], sizeof(buf), buf, &buflen);
120		buf[sizeof(buf) - 1] = '\0';
121		if (err == 0 && strcmp(session_name, buf) == 0) {
122			ctx->session = sessions[i];
123			DEBUGADD(DMAPI_TRACE,
124				("attached to existing DMAPI session "
125				 "named '%s'\n", buf));
126			break;
127		}
128	}
129
130	/* No session already defined. */
131	if (ctx->session == DM_NO_SESSION) {
132		err = dm_create_session(DM_NO_SESSION,
133					session_name,
134					&ctx->session);
135		if (err < 0) {
136			DEBUGADD(DMAPI_TRACE,
137				("failed to create new DMAPI session: %s\n",
138				strerror(errno)));
139			ctx->session = DM_NO_SESSION;
140			talloc_free(tmp_ctx);
141			return -1;
142		}
143
144		DEBUG(0, ("created new DMAPI session named '%s' for %s\n",
145			  session_name, version));
146	}
147
148	if (ctx->session != DM_NO_SESSION) {
149		set_effective_capability(DMAPI_ACCESS_CAPABILITY);
150	}
151
152	/*
153	   Note that we never end the DMAPI session. It gets re-used if possiblie.
154	   DMAPI session is a kernel resource that is usually lives until server reboot
155	   and doesn't get destroed when an application finishes.
156
157	   However, we free list of references to DMAPI sessions we've got from the kernel
158	   as it is not needed anymore once we have found (or created) our session.
159	 */
160
161	talloc_free(tmp_ctx);
162	return 0;
163}
164
165/*
166  Return a pointer to our DMAPI session, if available.
167  This assumes that you have called dmapi_have_session() first.
168*/
169const void *dmapi_get_current_session(void)
170{
171	if (!dmapi_ctx) {
172		return NULL;
173	}
174
175	if (dmapi_ctx->session == DM_NO_SESSION) {
176		return NULL;
177	}
178
179	return (void *)&dmapi_ctx->session;
180}
181
182/*
183  dmapi_have_session() must be the first DMAPI call you make in Samba. It will
184  initialize DMAPI, if available, and tell you if you can get a DMAPI session.
185  This should be called in the client-specific child process.
186*/
187
188bool dmapi_have_session(void)
189{
190	if (!dmapi_ctx) {
191		dmapi_ctx = talloc(talloc_autofree_context(),
192				   struct smbd_dmapi_context);
193		if (!dmapi_ctx) {
194			exit_server("unable to allocate smbd_dmapi_context");
195		}
196		dmapi_ctx->session = DM_NO_SESSION;
197		dmapi_ctx->session_num = 0;
198
199		become_root();
200		dmapi_init_session(dmapi_ctx);
201		unbecome_root();
202
203	}
204
205	return dmapi_ctx->session != DM_NO_SESSION;
206}
207
208/*
209  only call this when you get back an EINVAL error indicating that the
210  session you are using is invalid. This destroys the existing session
211  and creates a new one.
212 */
213bool dmapi_new_session(void)
214{
215	if (dmapi_have_session()) {
216		/* try to destroy the old one - this may not succeed */
217		dm_destroy_session(dmapi_ctx->session);
218	}
219	dmapi_ctx->session = DM_NO_SESSION;
220	become_root();
221	dmapi_ctx->session_num++;
222	dmapi_init_session(dmapi_ctx);
223	unbecome_root();
224	return dmapi_ctx->session != DM_NO_SESSION;
225}
226
227/*
228    only call this when exiting from master smbd process. DMAPI sessions
229    are long-lived kernel resources we ought to share across smbd processes.
230    However, we must free them when all smbd processes are finished to
231    allow other subsystems clean up properly. Not freeing DMAPI session
232    blocks certain HSM implementations from proper shutdown.
233*/
234bool dmapi_destroy_session(void)
235{
236	if (!dmapi_ctx) {
237		return true;
238	}
239	if (dmapi_ctx->session != DM_NO_SESSION) {
240		become_root();
241		if (0 == dm_destroy_session(dmapi_ctx->session)) {
242			dmapi_ctx->session_num--;
243			dmapi_ctx->session = DM_NO_SESSION;
244		} else {
245			DEBUG(0,("Couldn't destroy DMAPI session: %s\n",
246				 strerror(errno)));
247		}
248		unbecome_root();
249	}
250	return dmapi_ctx->session == DM_NO_SESSION;
251}
252
253
254/*
255   This is default implementation of dmapi_file_flags() that is
256   called from VFS is_offline() call to know whether file is offline.
257   For GPFS-specific version see modules/vfs_tsmsm.c. It might be
258   that approach on quering existence of a specific attribute that
259   is used in vfs_tsmsm.c will work with other DMAPI-based HSM
260   implementations as well.
261*/
262uint32 dmapi_file_flags(const char * const path)
263{
264	int		err;
265	dm_eventset_t   events = {0};
266	uint		nevents;
267
268	dm_sessid_t     dmapi_session;
269	const void      *dmapi_session_ptr;
270	void	        *dm_handle = NULL;
271	size_t	        dm_handle_len = 0;
272
273	uint32	        flags = 0;
274
275	dmapi_session_ptr = dmapi_get_current_session();
276	if (dmapi_session_ptr == NULL) {
277		return 0;
278	}
279
280	dmapi_session = *(dm_sessid_t *)dmapi_session_ptr;
281	if (dmapi_session == DM_NO_SESSION) {
282		return 0;
283	}
284
285	/* AIX has DMAPI but no POSIX capablities support. In this case,
286	 * we need to be root to do DMAPI manipulations.
287	 */
288#ifndef HAVE_POSIX_CAPABILITIES
289	become_root();
290#endif
291
292	err = dm_path_to_handle(CONST_DISCARD(char *, path),
293		&dm_handle, &dm_handle_len);
294	if (err < 0) {
295		DEBUG(DMAPI_TRACE, ("dm_path_to_handle(%s): %s\n",
296			    path, strerror(errno)));
297
298		if (errno != EPERM) {
299			goto done;
300		}
301
302		/* Linux capabilities are broken in that changing our
303		 * user ID will clobber out effective capabilities irrespective
304		 * of whether we have set PR_SET_KEEPCAPS. Fortunately, the
305		 * capabilities are not removed from our permitted set, so we
306		 * can re-acquire them if necessary.
307		 */
308
309		set_effective_capability(DMAPI_ACCESS_CAPABILITY);
310
311		err = dm_path_to_handle(CONST_DISCARD(char *, path),
312			&dm_handle, &dm_handle_len);
313		if (err < 0) {
314			DEBUG(DMAPI_TRACE,
315			    ("retrying dm_path_to_handle(%s): %s\n",
316			    path, strerror(errno)));
317			goto done;
318		}
319	}
320
321	err = dm_get_eventlist(dmapi_session, dm_handle, dm_handle_len,
322		DM_NO_TOKEN, DM_EVENT_MAX, &events, &nevents);
323	if (err < 0) {
324		DEBUG(DMAPI_TRACE, ("dm_get_eventlist(%s): %s\n",
325			    path, strerror(errno)));
326		dm_handle_free(dm_handle, dm_handle_len);
327		goto done;
328	}
329
330	/* We figure that the only reason a DMAPI application would be
331	 * interested in trapping read events is that part of the file is
332	 * offline.
333	 */
334	DEBUG(DMAPI_TRACE, ("DMAPI event list for %s\n", path));
335	if (DMEV_ISSET(DM_EVENT_READ, events)) {
336		flags = FILE_ATTRIBUTE_OFFLINE;
337	}
338
339	dm_handle_free(dm_handle, dm_handle_len);
340
341	if (flags & FILE_ATTRIBUTE_OFFLINE) {
342		DEBUG(DMAPI_TRACE, ("%s is OFFLINE\n", path));
343	}
344
345done:
346
347#ifndef HAVE_POSIX_CAPABILITIES
348	unbecome_root();
349#endif
350
351	return flags;
352}
353
354
355#endif /* USE_DMAPI */
356