Eliminate two duplicate SEC_ACE_TYPE constants already provided by
[amitay/samba.git] / source3 / lib / fault.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Critical Fault handling
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Tim Prouty 2009
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
23 #ifdef HAVE_SYS_PRCTL_H
24 #include <sys/prctl.h>
25 #endif
26
27 static void (*cont_fn)(void *);
28 static char *corepath;
29
30 /*******************************************************************
31 report a fault
32 ********************************************************************/
33 static void fault_report(int sig)
34 {
35         static int counter;
36
37         if (counter) _exit(1);
38
39         counter++;
40
41         DEBUGSEP(0);
42         DEBUG(0,("INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)sys_getpid(),samba_version_string()));
43         DEBUG(0,("\nPlease read the Trouble-Shooting section of the Samba3-HOWTO\n"));
44         DEBUG(0,("\nFrom: http://www.samba.org/samba/docs/Samba3-HOWTO.pdf\n"));
45         DEBUGSEP(0);
46   
47         smb_panic("internal error");
48
49         if (cont_fn) {
50                 cont_fn(NULL);
51 #ifdef SIGSEGV
52                 CatchSignal(SIGSEGV,SIGNAL_CAST SIG_DFL);
53 #endif
54 #ifdef SIGBUS
55                 CatchSignal(SIGBUS,SIGNAL_CAST SIG_DFL);
56 #endif
57 #ifdef SIGABRT
58                 CatchSignal(SIGABRT,SIGNAL_CAST SIG_DFL);
59 #endif
60                 return; /* this should cause a core dump */
61         }
62         exit(1);
63 }
64
65 /****************************************************************************
66 catch serious errors
67 ****************************************************************************/
68 static void sig_fault(int sig)
69 {
70         fault_report(sig);
71 }
72
73 /*******************************************************************
74 setup our fault handlers
75 ********************************************************************/
76 void fault_setup(void (*fn)(void *))
77 {
78         cont_fn = fn;
79
80 #ifdef SIGSEGV
81         CatchSignal(SIGSEGV,SIGNAL_CAST sig_fault);
82 #endif
83 #ifdef SIGBUS
84         CatchSignal(SIGBUS,SIGNAL_CAST sig_fault);
85 #endif
86 #ifdef SIGABRT
87         CatchSignal(SIGABRT,SIGNAL_CAST sig_fault);
88 #endif
89 }
90
91 /**
92  * Build up the default corepath as "<logbase>/cores/<progname>"
93  */
94 static char *get_default_corepath(const char *logbase, const char *progname)
95 {
96         char *tmp_corepath;
97
98         /* Setup core dir in logbase. */
99         tmp_corepath = talloc_asprintf(NULL, "%s/cores", logbase);
100         if (!tmp_corepath)
101                 return NULL;
102
103         if ((mkdir(tmp_corepath, 0700) == -1) && errno != EEXIST)
104                 goto err_out;
105
106         if (chmod(tmp_corepath, 0700) == -1)
107                 goto err_out;
108
109         talloc_free(tmp_corepath);
110
111         /* Setup progname-specific core subdir */
112         tmp_corepath = talloc_asprintf(NULL, "%s/cores/%s", logbase, progname);
113         if (!tmp_corepath)
114                 return NULL;
115
116         if (mkdir(tmp_corepath, 0700) == -1 && errno != EEXIST)
117                 goto err_out;
118
119         if (chown(tmp_corepath, getuid(), getgid()) == -1)
120                 goto err_out;
121
122         if (chmod(tmp_corepath, 0700) == -1)
123                 goto err_out;
124
125         return tmp_corepath;
126
127  err_out:
128         talloc_free(tmp_corepath);
129         return NULL;
130 }
131
132 /**
133  * Get the FreeBSD corepath.
134  *
135  * On FreeBSD the current working directory is ignored when creating a core
136  * file.  Instead the core directory is controlled via sysctl.  This consults
137  * the value of "kern.corefile" so the correct corepath can be printed out
138  * before dump_core() calls abort.
139  */
140 #if (defined(FREEBSD) && defined(HAVE_SYSCTLBYNAME))
141 static char *get_freebsd_corepath(void)
142 {
143         char *tmp_corepath = NULL;
144         char *end = NULL;
145         size_t len = 128;
146         int ret;
147
148         /* Loop with increasing sizes so we don't allocate too much. */
149         do {
150                 if (len > 1024)  {
151                         goto err_out;
152                 }
153
154                 tmp_corepath = (char *)talloc_realloc(NULL, tmp_corepath,
155                                                       char, len);
156                 if (!tmp_corepath) {
157                         return NULL;
158                 }
159
160                 ret = sysctlbyname("kern.corefile", tmp_corepath, &len, NULL,
161                                    0);
162                 if (ret == -1) {
163                         if (errno != ENOMEM) {
164                                 DEBUG(0, ("sysctlbyname failed getting "
165                                           "kern.corefile %s\n",
166                                           strerror(errno)));
167                                 goto err_out;
168                         }
169
170                         /* Not a large enough array, try a bigger one. */
171                         len = len << 1;
172                 }
173         } while (ret == -1);
174
175         /* Strip off the common filename expansion */
176         if ((end = strrchr_m(tmp_corepath, '/'))) {
177                 *end = '\0';
178         }
179
180         return tmp_corepath;
181
182  err_out:
183         if (tmp_corepath) {
184                 talloc_free(tmp_corepath);
185         }
186         return NULL;
187 }
188 #endif
189
190 /**
191  * Try getting system-specific corepath if one exists.
192  *
193  * If the system doesn't define a corepath, then the default is used.
194  */
195 static char *get_corepath(const char *logbase, const char *progname)
196 {
197         char *tmp_corepath = NULL;
198
199         /* @todo: Add support for the linux corepath. */
200 #if (defined(FREEBSD) && defined(HAVE_SYSCTLBYNAME))
201         tmp_corepath = get_freebsd_corepath();
202 #endif
203
204         /* If this has been set correctly, we're done. */
205         if (tmp_corepath) {
206                 return tmp_corepath;
207         }
208
209         /* Fall back to the default. */
210         return get_default_corepath(logbase, progname);
211 }
212
213 /*******************************************************************
214 make all the preparations to safely dump a core file
215 ********************************************************************/
216
217 void dump_core_setup(const char *progname)
218 {
219         char *logbase = NULL;
220         char *end = NULL;
221
222         if (lp_logfile() && *lp_logfile()) {
223                 if (asprintf(&logbase, "%s", lp_logfile()) < 0) {
224                         return;
225                 }
226                 if ((end = strrchr_m(logbase, '/'))) {
227                         *end = '\0';
228                 }
229         } else {
230                 /* We will end up here if the log file is given on the command
231                  * line by the -l option but the "log file" option is not set
232                  * in smb.conf.
233                  */
234                 if (asprintf(&logbase, "%s", get_dyn_LOGFILEBASE()) < 0) {
235                         return;
236                 }
237         }
238
239         SMB_ASSERT(progname != NULL);
240
241         corepath = get_corepath(logbase, progname);
242         if (!corepath) {
243                 DEBUG(0, ("Unable to setup corepath for %s: %s\n", progname,
244                           strerror(errno)));
245                 goto out;
246         }
247
248
249 #ifdef HAVE_GETRLIMIT
250 #ifdef RLIMIT_CORE
251         {
252                 struct rlimit rlp;
253                 getrlimit(RLIMIT_CORE, &rlp);
254                 rlp.rlim_cur = MAX(16*1024*1024,rlp.rlim_cur);
255                 setrlimit(RLIMIT_CORE, &rlp);
256                 getrlimit(RLIMIT_CORE, &rlp);
257                 DEBUG(3,("Maximum core file size limits now %d(soft) %d(hard)\n",
258                          (int)rlp.rlim_cur,(int)rlp.rlim_max));
259         }
260 #endif
261 #endif
262
263 #if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
264         /* On Linux we lose the ability to dump core when we change our user
265          * ID. We know how to dump core safely, so let's make sure we have our
266          * dumpable flag set.
267          */
268         prctl(PR_SET_DUMPABLE, 1);
269 #endif
270
271         /* FIXME: if we have a core-plus-pid facility, configurably set
272          * this up here.
273          */
274  out:
275         SAFE_FREE(logbase);
276 }
277
278  void dump_core(void)
279 {
280         static bool called;
281
282         if (called) {
283                 DEBUG(0, ("dump_core() called recursive\n"));
284                 exit(1);
285         }
286         called = true;
287
288         /* Note that even if core dumping has been disabled, we still set up
289          * the core path. This is to handle the case where core dumping is
290          * turned on in smb.conf and the relevant daemon is not restarted.
291          */
292         if (!lp_enable_core_files()) {
293                 DEBUG(0, ("Exiting on internal error (core file administratively disabled)\n"));
294                 exit(1);
295         }
296
297 #if DUMP_CORE
298         /* If we're running as non root we might not be able to dump the core
299          * file to the corepath.  There must not be an unbecome_root() before
300          * we call abort(). */
301         if (geteuid() != 0) {
302                 become_root();
303         }
304
305         if (corepath == NULL) {
306                 DEBUG(0, ("Can not dump core: corepath not set up\n"));
307                 exit(1);
308         }
309
310         if (*corepath != '\0') {
311                 /* The chdir might fail if we dump core before we finish
312                  * processing the config file.
313                  */
314                 if (chdir(corepath) != 0) {
315                         DEBUG(0, ("unable to change to %s\n", corepath));
316                         DEBUGADD(0, ("refusing to dump core\n"));
317                         exit(1);
318                 }
319
320                 DEBUG(0,("dumping core in %s\n", corepath));
321         }
322
323         umask(~(0700));
324         dbgflush();
325
326         /* Ensure we don't have a signal handler for abort. */
327 #ifdef SIGABRT
328         CatchSignal(SIGABRT,SIGNAL_CAST SIG_DFL);
329 #endif
330
331         abort();
332
333 #else /* DUMP_CORE */
334         exit(1);
335 #endif /* DUMP_CORE */
336 }
337