SSPCPP-412 - systemd integration changes
[shibboleth/cpp-sp.git] / shibd / shibd.cpp
index e820685..e8afdea 100644 (file)
@@ -19,7 +19,7 @@
  */
 
 /*
- * shibd.cpp -- the shibd "main" code.  All the functionality is elsewhere
+ * shibd.cpp -- the shibd "main" code.
  */
 
 
 #include <shibsp/SPConfig.h>
 
 #ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#include <sys/select.h>
+# include <unistd.h>
+# include <sys/select.h>
+#endif
+
+#if defined(HAVE_GRP_H) && defined(HAVE_PWD_H)
+# include <pwd.h>
+# include <grp.h>
 #endif
 
 #include <stdio.h>
 #include <xmltooling/util/XMLConstants.h>
 #include <xmltooling/util/XMLHelper.h>
 
+#ifdef HAVE_SD_NOTIFY
+#include <systemd/sd-daemon.h>
+#else
+#define SD_EMERG   ""
+#define SD_ALERT   ""
+#define SD_CRIT    ""
+#define SD_ERR     ""
+#define SD_WARNING ""
+#define SD_NOTICE  ""
+#define SD_INFO    ""
+#define SD_DEBUG   ""
+#endif
+
 using namespace shibsp;
 using namespace xmltooling;
 using namespace std;
@@ -105,9 +123,14 @@ int MyAllocHook(int nAllocType, void *pvData,
 
 int real_main(int preinit)
 {
-    SPConfig& conf=SPConfig::getConfig();
-    if (preinit) {
+    if (shar_version) {
+        if (preinit)
+            fprintf(stdout, PACKAGE_STRING"\n");
+        return 0;
+    }
 
+    SPConfig& conf = SPConfig::getConfig();
+    if (preinit) {
         // Initialize the SP library.
         conf.setFeatures(
             SPConfig::Listener |
@@ -168,8 +191,8 @@ int real_main(int preinit)
 int daemon_wait = 3;
 bool shibd_running = false;
 bool daemonize = true;
-uid_t runasuser = 0;
-gid_t runasgroup = 0;
+const char* runasuser = nullptr;
+const char* runasgroup = nullptr;
 
 static void term_handler(int arg)
 {
@@ -235,7 +258,7 @@ static int setup_signals(void)
 
 static void usage(char* whoami)
 {
-    fprintf(stderr, "usage: %s [-dcxtfpvh]\n", whoami);
+    fprintf(stderr, "usage: %s [-dcxtfFpwugvh]\n", whoami);
     fprintf(stderr, "  -d\tinstallation prefix to use\n");
     fprintf(stderr, "  -c\tconfig file to use\n");
     fprintf(stderr, "  -x\tXML schema catalogs to use\n");
@@ -244,8 +267,8 @@ static void usage(char* whoami)
     fprintf(stderr, "  -F\tstay in the foreground\n");
     fprintf(stderr, "  -p\tpid file to use\n");
     fprintf(stderr, "  -w\tseconds to wait for successful daemonization\n");
-    fprintf(stderr, "  -u\tuid to run under\n");
-    fprintf(stderr, "  -g\tgid to run under\n");
+    fprintf(stderr, "  -u\tuser to run under\n");
+    fprintf(stderr, "  -g\tgroup to run under\n");
     fprintf(stderr, "  -v\tprint software version\n");
     fprintf(stderr, "  -h\tprint this help message\n");
     exit(1);
@@ -290,11 +313,11 @@ static int parse_args(int argc, char* argv[])
                 break;
             case 'u':
                 if (optarg)
-                    runasuser = atoi(optarg);
+                    runasuser = optarg;
                 break;
             case 'g':
                 if (optarg)
-                    runasgroup = atoi(optarg);
+                    runasgroup = optarg;
                 break;
             default:
                 return -1;
@@ -315,14 +338,45 @@ int main(int argc, char *argv[])
     if (setup_signals() != 0)
         return -1;
 
-    if (runasuser > 0 && setuid(runasuser) != 0) {
-        fprintf(stderr, "setuid failed, check -u option");
+    if (runasgroup) {
+#ifdef HAVE_GETGRNAM
+        struct group* grp = getgrnam(runasgroup);
+        if (!grp) {
+            fprintf(stderr, "getgrnam failed, check -g option\n");
+            return -1;
+        }
+        if (setgid(grp->gr_gid) != 0) {
+            fprintf(stderr, "setgid failed, check -g option\n");
+            return -1;
+        }
+#else
+        fprintf(stderr, "-g not supported on this platform");
         return -1;
+#endif
     }
 
-    if (runasgroup > 0 && setgid(runasgroup) != 0) {
-        fprintf(stderr, "setgid failed, check -g option");
+    if (runasuser) {
+#ifdef HAVE_GETPWNAM
+        struct passwd* pwd = getpwnam(runasuser);
+        if (!pwd) {
+            fprintf(stderr, "getpwnam failed, check -u option\n");
+            return -1;
+        }
+#ifdef HAVE_INITGROUPS
+        // w/out initgroups/setgroups process retains supplementary groups
+        if (initgroups(pwd->pw_name, pwd->pw_gid) != 0) {
+            fprintf(stderr, "initgroups failed, check -u option\n");
+            return -1;
+        }
+#endif
+        if (setuid(pwd->pw_uid) != 0) {
+            fprintf(stderr, "setuid failed, check -u option\n");
+            return -1;
+        }
+#else
+        fprintf(stderr, "-u not supported on this platform");
         return -1;
+#endif
     }
 
     // initialize the shib-target library
@@ -339,7 +393,7 @@ int main(int argc, char *argv[])
         (shar_checkonly ? SPConfig::RequestMapping : SPConfig::Logging)
         );
     if (!conf.init(shar_schemadir, shar_prefix)) {
-        fprintf(stderr, "configuration is invalid, check console for specific problems\n");
+        fprintf(stderr, SD_ERR "configuration is invalid, check console for specific problems\n");
         return -1;
     }
 
@@ -359,7 +413,7 @@ int main(int argc, char *argv[])
     }
 
     if (!conf.instantiate(shar_config)) {
-        fprintf(stderr, "configuration is invalid, check console for specific problems\n");
+        fprintf(stderr, SD_ERR "configuration is invalid, check console for specific problems\n");
         conf.term();
         return -2;
     }
@@ -370,7 +424,7 @@ int main(int argc, char *argv[])
         // Init the listener.
         ListenerService* listener = conf.getServiceProvider()->getListenerService();
         if (!listener->init(unlink_socket)) {
-            fprintf(stderr, "listener failed to initialize\n");
+            fprintf(stderr, SD_ERR "listener failed to initialize\n");
             conf.term();
             return -3;
         }
@@ -405,8 +459,11 @@ int main(int argc, char *argv[])
         }
 
         // Run the listener.
+#ifdef HAVE_SD_NOTIFY
+        sd_notify(0, "READY=1");
+#endif
         if (!listener->run(&shibd_shutdown)) {
-            fprintf(stderr, "listener failure during service\n");
+            fprintf(stderr, SD_ERR "listener failure during service\n");
             listener->term();
             conf.term();
             if (daemonize && pidfile)
@@ -415,7 +472,9 @@ int main(int argc, char *argv[])
         }
         listener->term();
     }
-
+#ifdef HAVE_SD_NOTIFY
+    sd_notify(0, "STOPPING=1");
+#endif
     conf.term();
     if (daemonize && pidfile)
         unlink(pidfile);