Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Samba utility functions
4 :
5 : Copyright (C) Andrew Tridgell 1992-2011
6 :
7 : based on old fault.c code, which had:
8 :
9 : Copyright (C) Jeremy Allison 2001-2007
10 : Copyright (C) Simo Sorce 2001
11 : Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
12 : Copyright (C) James Peach 2006
13 :
14 : This program is free software; you can redistribute it and/or modify
15 : it under the terms of the GNU General Public License as published by
16 : the Free Software Foundation; either version 3 of the License, or
17 : (at your option) any later version.
18 :
19 : This program is distributed in the hope that it will be useful,
20 : but WITHOUT ANY WARRANTY; without even the implied warranty of
21 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 : GNU General Public License for more details.
23 :
24 : You should have received a copy of the GNU General Public License
25 : along with this program. If not, see <http://www.gnu.org/licenses/>.
26 : */
27 :
28 : #include "includes.h"
29 : #include "lib/util/util_file.h"
30 : #include "system/filesys.h"
31 :
32 : #ifdef HAVE_SYS_SYSCTL_H
33 : #include <sys/sysctl.h>
34 : #endif
35 :
36 : #ifdef HAVE_SYS_PRCTL_H
37 : #include <sys/prctl.h>
38 : #endif
39 :
40 : static char *corepath;
41 : static bool using_helper_binary = false;
42 :
43 : /**
44 : * Build up the default corepath as "<logbase>/cores/<progname>"
45 : */
46 862 : static char *get_default_corepath(const char *logbase, const char *progname)
47 : {
48 862 : const mode_t mode = 0700;
49 862 : const uid_t uid = getuid();
50 0 : char *tmp_corepath;
51 :
52 : /* Setup core dir in logbase. */
53 862 : tmp_corepath = talloc_asprintf(NULL, "%s/cores", logbase);
54 862 : if (!tmp_corepath) {
55 0 : DEBUG(0, ("Out of memory\n"));
56 0 : return NULL;
57 : }
58 :
59 862 : if (!directory_create_or_exist_strict(tmp_corepath, uid, mode)) {
60 0 : DEBUG(0, ("Failed to create %s for user %d with mode 0%o\n",
61 : tmp_corepath, (int)uid, (int)mode));
62 0 : goto err_out;
63 : }
64 :
65 : /* Setup progname-specific core subdir */
66 862 : tmp_corepath = talloc_asprintf_append(tmp_corepath, "/%s", progname);
67 862 : if (!tmp_corepath) {
68 0 : DEBUG(0, ("Out of memory\n"));
69 0 : goto err_out;
70 : }
71 :
72 862 : if (!directory_create_or_exist(tmp_corepath, mode)) {
73 0 : DEBUG(0, ("Failed to create %s for user %d with mode 0%o\n",
74 : tmp_corepath, (int)uid, (int)mode));
75 0 : goto err_out;
76 : }
77 :
78 862 : return tmp_corepath;
79 :
80 0 : err_out:
81 0 : talloc_free(tmp_corepath);
82 0 : return NULL;
83 : }
84 :
85 :
86 : /**
87 : * Get the FreeBSD corepath.
88 : *
89 : * On FreeBSD the current working directory is ignored when creating a core
90 : * file. Instead the core directory is controlled via sysctl. This consults
91 : * the value of "kern.corefile" so the correct corepath can be printed out
92 : * before dump_core() calls abort.
93 : */
94 : #if (defined(FREEBSD) && defined(HAVE_SYSCTLBYNAME))
95 : static char *get_freebsd_corepath(void)
96 : {
97 : char *tmp_corepath = NULL;
98 : char *end = NULL;
99 : size_t len = 128;
100 : int ret;
101 :
102 : /* Loop with increasing sizes so we don't allocate too much. */
103 : do {
104 : if (len > 1024) {
105 : goto err_out;
106 : }
107 :
108 : tmp_corepath = (char *)talloc_realloc(NULL, tmp_corepath,
109 : char, len);
110 : if (!tmp_corepath) {
111 : return NULL;
112 : }
113 :
114 : ret = sysctlbyname("kern.corefile", tmp_corepath, &len, NULL,
115 : 0);
116 : if (ret == -1) {
117 : if (errno != ENOMEM) {
118 : DEBUG(0, ("sysctlbyname failed getting "
119 : "kern.corefile %s\n",
120 : strerror(errno)));
121 : goto err_out;
122 : }
123 :
124 : /* Not a large enough array, try a bigger one. */
125 : len = len << 1;
126 : }
127 : } while (ret == -1);
128 :
129 : /* Strip off the common filename expansion */
130 : if ((end = strrchr_m(tmp_corepath, '/'))) {
131 : *end = '\0';
132 : }
133 :
134 : return tmp_corepath;
135 :
136 : err_out:
137 : if (tmp_corepath) {
138 : talloc_free(tmp_corepath);
139 : }
140 : return NULL;
141 : }
142 : #endif
143 :
144 : #if defined(HAVE_SYS_KERNEL_PROC_CORE_PATTERN)
145 :
146 : /**
147 : * Get the Linux corepath.
148 : *
149 : * On Linux the contents of /proc/sys/kernel/core_pattern indicates the
150 : * location of the core path.
151 : */
152 862 : static char *get_linux_corepath(void)
153 : {
154 0 : char *end;
155 0 : int fd;
156 0 : char *result;
157 :
158 862 : fd = open("/proc/sys/kernel/core_pattern", O_RDONLY, 0);
159 862 : if (fd == -1) {
160 0 : return NULL;
161 : }
162 :
163 862 : result = afdgets(fd, NULL, 0);
164 862 : close(fd);
165 :
166 862 : if (result == NULL) {
167 0 : return NULL;
168 : }
169 :
170 862 : if (result[0] != '/') {
171 : /*
172 : * No absolute path, use the default (cwd)
173 : */
174 862 : if (result[0] == '|') {
175 : /*
176 : * Core dump handled by helper binaries
177 : */
178 862 : using_helper_binary = true;
179 : }
180 862 : TALLOC_FREE(result);
181 862 : return NULL;
182 : }
183 : /* Strip off the common filename expansion */
184 :
185 0 : end = strrchr_m(result, '/');
186 :
187 0 : if ((end != result) /* this would be the only / */
188 0 : && (end != NULL)) {
189 0 : *end = '\0';
190 : }
191 0 : return result;
192 : }
193 : #endif
194 :
195 :
196 : /**
197 : * Try getting system-specific corepath if one exists.
198 : *
199 : * If the system doesn't define a corepath, then the default is used.
200 : */
201 862 : static char *get_corepath(const char *logbase, const char *progname)
202 : {
203 : #if (defined(FREEBSD) && defined(HAVE_SYSCTLBYNAME))
204 : char *tmp_corepath = NULL;
205 : tmp_corepath = get_freebsd_corepath();
206 :
207 : /* If this has been set correctly, we're done. */
208 : if (tmp_corepath) {
209 : return tmp_corepath;
210 : }
211 : #endif
212 :
213 : #if defined(HAVE_SYS_KERNEL_PROC_CORE_PATTERN)
214 862 : char *tmp_corepath = NULL;
215 862 : tmp_corepath = get_linux_corepath();
216 :
217 : /* If this has been set correctly, we're done. */
218 862 : if (tmp_corepath) {
219 0 : return tmp_corepath;
220 : }
221 : #endif
222 :
223 : /* Fall back to the default. */
224 862 : return get_default_corepath(logbase, progname);
225 : }
226 :
227 : /*******************************************************************
228 : make all the preparations to safely dump a core file
229 : ********************************************************************/
230 :
231 862 : void dump_core_setup(const char *progname, const char *log_file)
232 : {
233 862 : char *logbase = NULL;
234 862 : char *end = NULL;
235 :
236 862 : if (log_file && *log_file) {
237 862 : if (asprintf(&logbase, "%s", log_file) < 0) {
238 0 : return;
239 : }
240 1066 : if ((end = strrchr_m(logbase, '/'))) {
241 862 : *end = '\0';
242 : }
243 : } else {
244 : /* We will end up here if the log file is given on the command
245 : * line by the -l option but the "log file" option is not set
246 : * in smb.conf.
247 : */
248 0 : if (asprintf(&logbase, "%s", get_dyn_LOGFILEBASE()) < 0) {
249 0 : return;
250 : }
251 : }
252 :
253 862 : SMB_ASSERT(progname != NULL);
254 :
255 862 : corepath = get_corepath(logbase, progname);
256 862 : if (!corepath) {
257 0 : DEBUG(0, ("Unable to setup corepath for %s: %s\n", progname,
258 : strerror(errno)));
259 0 : goto out;
260 : }
261 :
262 : /* FIXME: if we have a core-plus-pid facility, configurably set
263 : * this up here.
264 : */
265 862 : out:
266 862 : SAFE_FREE(logbase);
267 : }
268 :
269 0 : void dump_core(void)
270 : {
271 0 : static bool called;
272 :
273 0 : if (called) {
274 0 : DEBUG(0, ("dump_core() called recursive\n"));
275 0 : exit(1);
276 : }
277 0 : called = true;
278 :
279 : /* Note that even if core dumping has been disabled, we still set up
280 : * the core path. This is to handle the case where core dumping is
281 : * turned on in smb.conf and the relevant daemon is not restarted.
282 : */
283 0 : if (!lp_enable_core_files()) {
284 0 : DEBUG(0, ("Exiting on internal error (core file administratively disabled)\n"));
285 0 : exit(1);
286 : }
287 :
288 : #if DUMP_CORE
289 : /* If we're running as non root we might not be able to dump the core
290 : * file to the corepath. There must not be an unbecome_root() before
291 : * we call abort(). */
292 0 : if (geteuid() != sec_initial_uid()) {
293 0 : become_root();
294 : }
295 :
296 0 : if (corepath == NULL) {
297 0 : DEBUG(0, ("Can not dump core: corepath not set up\n"));
298 0 : exit(1);
299 : }
300 :
301 0 : if (*corepath != '\0') {
302 : /*
303 : * Check whether coredump is handled by helper binaries or not.
304 : * If so skip chdir().
305 : */
306 0 : if (!using_helper_binary) {
307 : /* The chdir might fail if we dump core before we finish
308 : * processing the config file.
309 : */
310 0 : if (chdir(corepath) != 0) {
311 0 : DEBUG(0, ("unable to change to %s\n", corepath));
312 0 : DEBUGADD(0, ("refusing to dump core\n"));
313 0 : exit(1);
314 : }
315 :
316 0 : DEBUG(0,("dumping core in %s\n", corepath));
317 : } else {
318 0 : DEBUG(0,("coredump is handled by helper binary "
319 : "specified at /proc/sys/kernel/core_pattern\n"));
320 : }
321 : }
322 :
323 0 : umask(~(0700));
324 0 : dbgflush();
325 :
326 : #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
327 : /* On Linux we lose the ability to dump core when we change our user
328 : * ID. We know how to dump core safely, so let's make sure we have our
329 : * dumpable flag set.
330 : */
331 0 : prctl(PR_SET_DUMPABLE, 1);
332 : #endif
333 :
334 : /* Ensure we don't have a signal handler for abort. */
335 : #ifdef SIGABRT
336 0 : CatchSignal(SIGABRT, SIG_DFL);
337 : #endif
338 :
339 0 : abort();
340 :
341 : #else /* DUMP_CORE */
342 : exit(1);
343 : #endif /* DUMP_CORE */
344 : }
|