Use sec_initial_uid() in the places where being root doesn't matter,
[samba.git] / source3 / lib / fault.c
index 1964955f1b814693cc1b99dd527413af60d59de6..50fa2b83700e49811171263b61dc07029667f3de 100644 (file)
@@ -2,6 +2,7 @@
    Unix SMB/CIFS implementation.
    Critical Fault handling
    Copyright (C) Andrew Tridgell 1992-1998
+   Copyright (C) Tim Prouty 2009
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
 #include "includes.h"
 
+#ifdef HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
+
+
 #ifdef HAVE_SYS_PRCTL_H
 #include <sys/prctl.h>
 #endif
@@ -38,7 +44,7 @@ static void fault_report(int sig)
        counter++;
 
        DEBUGSEP(0);
-       DEBUG(0,("INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)sys_getpid(),SAMBA_VERSION_STRING));
+       DEBUG(0,("INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)sys_getpid(),samba_version_string()));
        DEBUG(0,("\nPlease read the Trouble-Shooting section of the Samba3-HOWTO\n"));
        DEBUG(0,("\nFrom: http://www.samba.org/samba/docs/Samba3-HOWTO.pdf\n"));
        DEBUGSEP(0);
@@ -87,6 +93,129 @@ void fault_setup(void (*fn)(void *))
 #endif
 }
 
+/**
+ * Build up the default corepath as "<logbase>/cores/<progname>"
+ */
+static char *get_default_corepath(const char *logbase, const char *progname)
+{
+       char *tmp_corepath;
+
+       /* Setup core dir in logbase. */
+       tmp_corepath = talloc_asprintf(NULL, "%s/cores", logbase);
+       if (!tmp_corepath)
+               return NULL;
+
+       if ((mkdir(tmp_corepath, 0700) == -1) && errno != EEXIST)
+               goto err_out;
+
+       if (chmod(tmp_corepath, 0700) == -1)
+               goto err_out;
+
+       talloc_free(tmp_corepath);
+
+       /* Setup progname-specific core subdir */
+       tmp_corepath = talloc_asprintf(NULL, "%s/cores/%s", logbase, progname);
+       if (!tmp_corepath)
+               return NULL;
+
+       if (mkdir(tmp_corepath, 0700) == -1 && errno != EEXIST)
+               goto err_out;
+
+       if (chown(tmp_corepath, getuid(), getgid()) == -1)
+               goto err_out;
+
+       if (chmod(tmp_corepath, 0700) == -1)
+               goto err_out;
+
+       return tmp_corepath;
+
+ err_out:
+       talloc_free(tmp_corepath);
+       return NULL;
+}
+
+/**
+ * Get the FreeBSD corepath.
+ *
+ * On FreeBSD the current working directory is ignored when creating a core
+ * file.  Instead the core directory is controlled via sysctl.  This consults
+ * the value of "kern.corefile" so the correct corepath can be printed out
+ * before dump_core() calls abort.
+ */
+#if (defined(FREEBSD) && defined(HAVE_SYSCTLBYNAME))
+static char *get_freebsd_corepath(void)
+{
+       char *tmp_corepath = NULL;
+       char *end = NULL;
+       size_t len = 128;
+       int ret;
+
+       /* Loop with increasing sizes so we don't allocate too much. */
+       do {
+               if (len > 1024)  {
+                       goto err_out;
+               }
+
+               tmp_corepath = (char *)talloc_realloc(NULL, tmp_corepath,
+                                                     char, len);
+               if (!tmp_corepath) {
+                       return NULL;
+               }
+
+               ret = sysctlbyname("kern.corefile", tmp_corepath, &len, NULL,
+                                  0);
+               if (ret == -1) {
+                       if (errno != ENOMEM) {
+                               DEBUG(0, ("sysctlbyname failed getting "
+                                         "kern.corefile %s\n",
+                                         strerror(errno)));
+                               goto err_out;
+                       }
+
+                       /* Not a large enough array, try a bigger one. */
+                       len = len << 1;
+               }
+       } while (ret == -1);
+
+       /* Strip off the common filename expansion */
+       if ((end = strrchr_m(tmp_corepath, '/'))) {
+               *end = '\0';
+       }
+
+       return tmp_corepath;
+
+ err_out:
+       if (tmp_corepath) {
+               talloc_free(tmp_corepath);
+       }
+       return NULL;
+}
+#endif
+
+/**
+ * Try getting system-specific corepath if one exists.
+ *
+ * If the system doesn't define a corepath, then the default is used.
+ */
+static char *get_corepath(const char *logbase, const char *progname)
+{
+#if (defined(FREEBSD) && defined(HAVE_SYSCTLBYNAME))
+
+       /* @todo: Add support for the linux corepath. */
+
+       char *tmp_corepath = NULL;
+       tmp_corepath = get_freebsd_corepath();
+
+       /* If this has been set correctly, we're done. */
+       if (tmp_corepath) {
+               return tmp_corepath;
+       }
+#endif
+
+       /* Fall back to the default. */
+       return get_default_corepath(logbase, progname);
+}
+
 /*******************************************************************
 make all the preparations to safely dump a core file
 ********************************************************************/
@@ -104,7 +233,7 @@ void dump_core_setup(const char *progname)
                        *end = '\0';
                }
        } else {
-               /* We will end up here is the log file is given on the command
+               /* We will end up here if the log file is given on the command
                 * line by the -l option but the "log file" option is not set
                 * in smb.conf.
                 */
@@ -115,24 +244,13 @@ void dump_core_setup(const char *progname)
 
        SMB_ASSERT(progname != NULL);
 
-       if (asprintf(&corepath, "%s/cores", logbase) < 0) {
-               SAFE_FREE(logbase);
-               return;
-       }
-       mkdir(corepath,0700);
-
-       SAFE_FREE(corepath);
-       if (asprintf(&corepath, "%s/cores/%s",
-                       logbase, progname) < 0) {
-               SAFE_FREE(logbase);
-               return;
+       corepath = get_corepath(logbase, progname);
+       if (!corepath) {
+               DEBUG(0, ("Unable to setup corepath for %s: %s\n", progname,
+                         strerror(errno)));
+               goto out;
        }
-       mkdir(corepath,0700);
 
-       sys_chown(corepath,getuid(),getgid());
-       chmod(corepath,0700);
-
-       SAFE_FREE(logbase);
 
 #ifdef HAVE_GETRLIMIT
 #ifdef RLIMIT_CORE
@@ -159,6 +277,8 @@ void dump_core_setup(const char *progname)
        /* FIXME: if we have a core-plus-pid facility, configurably set
         * this up here.
         */
+ out:
+       SAFE_FREE(logbase);
 }
 
  void dump_core(void)
@@ -184,10 +304,15 @@ void dump_core_setup(const char *progname)
        /* If we're running as non root we might not be able to dump the core
         * file to the corepath.  There must not be an unbecome_root() before
         * we call abort(). */
-       if (geteuid() != 0) {
+       if (geteuid() != sec_initial_uid()) {
                become_root();
        }
 
+       if (corepath == NULL) {
+               DEBUG(0, ("Can not dump core: corepath not set up\n"));
+               exit(1);
+       }
+
        if (*corepath != '\0') {
                /* The chdir might fail if we dump core before we finish
                 * processing the config file.