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