소스 검색

Add chroot capability

tags/1.0
Timo Röhling 12 년 전
부모
커밋
c29c38d622
5개의 변경된 파일56개의 추가작업 그리고 12개의 파일을 삭제
  1. 2
    0
      CMakeLists.txt
  2. 6
    0
      postinstall.cmake.in
  3. 42
    10
      postsrsd.c
  4. 3
    1
      postsrsd.init.in
  5. 3
    1
      postsrsd.upstart.in

+ 2
- 0
CMakeLists.txt 파일 보기

@@ -3,6 +3,8 @@ project(postsrsd C)
3 3
 
4 4
 option(GENERATE_SRS_SECRET "Generate a random SRS secret if none exists during install" ON)
5 5
 
6
+set(CHROOT_DIR "${CMAKE_INSTALL_PREFIX}/lib/${PROJECT_NAME}" CACHE PATH "Chroot jail for daemon")
7
+
6 8
 find_program(HELP2MAN help2man DOC "path to help2man executable")
7 9
 find_program(DD dd DOC "path to dd executable")
8 10
 find_program(BASE64 base64 DOC "path to base64 executable")

+ 6
- 0
postinstall.cmake.in 파일 보기

@@ -1,10 +1,16 @@
1 1
 set(GENERATE_SRS_SECRET "@GENERATE_SRS_SECRET@")
2
+set(CHROOT_DIR "@CHROOT_DIR@")
2 3
 set(INIT_FLAVOR "@INIT_FLAVOR@")
3 4
 set(SECRET_FILE "@PROJECT_NAME@.secret")
4 5
 set(DD "@DD@")
5 6
 set(BASE64 "@BASE64@")
6 7
 set(INSSERV "@INSSERV@")
7 8
 
9
+if(CHROOT_DIR AND NOT EXISTS "$ENV{DESTDIR}${CHROOT_DIR}")
10
+	message(STATUS "Chroot jail: $ENV{DESTDIR}${CHROOT_DIR}")
11
+	file(MAKE_DIRECTORY "$ENV{DESTDIR}${CHROOT_DIR}")
12
+endif()
13
+
8 14
 if(INIT_FLAVOR AND NOT EXISTS "$ENV{DESTDIR}/etc/default/@PROJECT_NAME@")
9 15
 	file(INSTALL "@CMAKE_CURRENT_SOURCE_DIR@/@PROJECT_NAME@.default" DESTINATION "/etc/default" RENAME "@PROJECT_NAME@")
10 16
 endif()

+ 42
- 10
postsrsd.c 파일 보기

@@ -193,6 +193,7 @@ static void show_help ()
193 193
     "   -f<port>       set port for the forward SRS lookup (default: 10001)\n"
194 194
     "   -r<port>       set port for the reverse SRS lookup (default: 10002)\n"
195 195
     "   -p<pidfile>    write process ID to pidfile (default: none)\n"
196
+    "   -c<dir>        chroot to <dir> (default: none)\n"
196 197
     "   -u<user>       switch user id after port bind (default: none)\n"
197 198
     "   -t<seconds>    timeout for idle client connections (default: 1800)\n"
198 199
     "   -D             fork into background\n"
@@ -212,10 +213,11 @@ int main (int argc, char **argv)
212 213
   int opt, timeout = 1800, family = AF_UNSPEC;
213 214
   int daemonize = FALSE;
214 215
   char *forward_service = NULL, *reverse_service = NULL,
215
-       *user = NULL, *domain = NULL;
216
+       *user = NULL, *domain = NULL, *chroot_dir = NULL;
216 217
   int forward_sock, reverse_sock;
217 218
   char *secret_file = NULL, *pid_file = NULL;
218 219
   FILE *pf = NULL;
220
+  struct passwd *pwd = NULL;
219 221
   char secret[1024];
220 222
   char *tmp;
221 223
   srs_t *srs;
@@ -225,7 +227,7 @@ int main (int argc, char **argv)
225 227
   tmp = strrchr(argv[0], '/');
226 228
   if (tmp) self = strdup(tmp + 1); else self = strdup(argv[0]);
227 229
 
228
-  while ((opt = getopt(argc, argv, "46d:f:r:s:u:t:p:Dhv")) != -1) {
230
+  while ((opt = getopt(argc, argv, "46d:f:r:s:u:t:p:c:Dhv")) != -1) {
229 231
     switch (opt) {
230 232
       case '?':
231 233
         return EXIT_FAILURE;
@@ -256,6 +258,9 @@ int main (int argc, char **argv)
256 258
       case 'u':
257 259
         user = strdup(optarg);
258 260
         break;
261
+      case 'c':
262
+	chroot_dir = strdup(optarg);
263
+	break;
259 264
       case 'D':
260 265
         daemonize = TRUE;
261 266
         break;
@@ -267,6 +272,15 @@ int main (int argc, char **argv)
267 272
 	return EXIT_SUCCESS;
268 273
     }
269 274
   }
275
+  if (domain == NULL) {
276
+    fprintf (stderr, "%s: You must set a home domain (-d)\n", self);
277
+    show_help();
278
+    return EXIT_FAILURE;
279
+  }
280
+
281
+  /* The stuff we do first may not be possible from within chroot or without privileges */
282
+
283
+  /* Open pid file for writing (the actual process ID is filled in later) */
270 284
   if (pid_file) {
271 285
     pf = fopen (pid_file, "w");
272 286
     if (pf == NULL) {
@@ -274,11 +288,7 @@ int main (int argc, char **argv)
274 288
       return EXIT_FAILURE;
275 289
     }
276 290
   }
277
-  if (domain == NULL) {
278
-    fprintf (stderr, "%s: You must set a home domain (-d)\n", self);
279
-    show_help();
280
-    return EXIT_FAILURE;
281
-  }
291
+  /* Read secret. The default installation makes this root accessible only. */
282 292
   if (secret_file != NULL) {
283 293
     size_t len;
284 294
     FILE *fp = fopen(secret_file, "rb");
@@ -298,6 +308,7 @@ int main (int argc, char **argv)
298 308
     show_help();
299 309
     return EXIT_FAILURE;
300 310
   }
311
+  /* Bind ports. May require privileges if the config specifies ports below 1024 */
301 312
   if (forward_service != NULL) {
302 313
     forward_sock = bind_service(forward_service, family);
303 314
     free (forward_service);
@@ -312,8 +323,11 @@ int main (int argc, char **argv)
312 323
     reverse_sock = bind_service("10002", family);
313 324
   }
314 325
   if (reverse_sock < 0) return EXIT_FAILURE;
326
+
327
+  /* Open syslog now (NDELAY), because it may no longer reachable from chroot */
328
+  openlog (self, LOG_PID | LOG_NDELAY, LOG_MAIL);
329
+  /* We also have to lookup the uid of the unprivileged user for the same reason. */
315 330
   if (user) {
316
-    struct passwd *pwd;
317 331
     errno = 0;
318 332
     pwd = getpwnam(user);
319 333
     if (pwd == NULL) {
@@ -323,23 +337,38 @@ int main (int argc, char **argv)
323 337
         fprintf (stderr, "%s: No such user: %s\n", self, user);
324 338
       return EXIT_FAILURE;
325 339
     }
340
+  }
341
+  /* Now we can chroot, which again requires root privileges */
342
+  if (chroot_dir) {
343
+    if (chdir(chroot_dir) < 0) {
344
+      fprintf (stderr, "%s: Cannot change to chroot: %s\n", self, strerror(errno));
345
+      return EXIT_FAILURE;
346
+    }
347
+    if (chroot(chroot_dir) < 0) {
348
+      fprintf (stderr, "%s: Failed to enable chroot: %s\n", self, strerror(errno));
349
+      return EXIT_FAILURE;
350
+    }
351
+  }
352
+  /* Finally, we revert to the unprivileged user */
353
+  if (pwd) {
326 354
     if (setuid(pwd->pw_uid) < 0) {
327 355
       fprintf (stderr, "%s: Failed to switch user id: %s\n", self, strerror(errno));
328 356
       return EXIT_FAILURE;
329 357
     }
330 358
   }
359
+  /* Standard double fork technique to disavow all knowledge about the controlling terminal */
331 360
   if (daemonize) {
332 361
     close(0); close(1); close(2);
333 362
     if (fork() != 0) return EXIT_SUCCESS;
334 363
     setsid();
335 364
     if (fork() != 0) return EXIT_SUCCESS;
336 365
   }
366
+  /* Make note of our actual process ID */
337 367
   if (pf) {
338 368
     fprintf (pf, "%d", (int)getpid());
339 369
     fclose (pf);
340 370
   }
341 371
 
342
-  openlog ("postsrsd", LOG_PID, LOG_MAIL);
343 372
   srs = srs_new();
344 373
   srs_add_secret (srs, secret);
345 374
   srs_set_separator (srs, '+');
@@ -356,7 +385,10 @@ int main (int argc, char **argv)
356 385
     char keybuf[1024], *key;
357 386
 
358 387
     if (poll(fds, 2, 1000) < 0) {
359
-      if (!daemonize) fprintf (stderr, "%s: Poll failure: %s\n", self, strerror(errno));
388
+      if (daemonize)
389
+        syslog (LOG_MAIL | LOG_ERR, "Poll failure: %s", strerror(errno));
390
+      else
391
+        fprintf (stderr, "%s: Poll failure: %s\n", self, strerror(errno));
360 392
       return EXIT_FAILURE;
361 393
     }
362 394
     for (i = 0; i < 2; ++i) {

+ 3
- 1
postsrsd.init.in 파일 보기

@@ -33,6 +33,7 @@ SRS_FORWARD_PORT=10001
33 33
 SRS_REVERSE_PORT=10002
34 34
 SRS_SECRET=/etc/@PROJECT_NAME@.secret
35 35
 RUN_AS=nobody
36
+CHROOT=@CHROOT_DIR@
36 37
 
37 38
 # Read config file if it is present.
38 39
 if [ -r /etc/default/$NAME ]
@@ -40,7 +41,7 @@ then
40 41
     . /etc/default/$NAME
41 42
 fi
42 43
 
43
-POSTSRS_OPTS="-4 -f$SRS_FORWARD_PORT -r$SRS_REVERSE_PORT -d$SRS_DOMAIN -s$SRS_SECRET -u$RUN_AS -p$PIDFILE -D"
44
+POSTSRS_OPTS="-4 -f$SRS_FORWARD_PORT -r$SRS_REVERSE_PORT -d$SRS_DOMAIN -s$SRS_SECRET -u$RUN_AS -p$PIDFILE -c$CHROOT -D"
44 45
 
45 46
 test -r "$SRS_SECRET" -a -n "$SRS_DOMAIN" || exit 0
46 47
 
@@ -83,3 +84,4 @@ case "$1" in
83 84
 esac
84 85
 
85 86
 exit $ret
87
+

+ 3
- 1
postsrsd.upstart.in 파일 보기

@@ -13,8 +13,10 @@ script
13 13
 	SRS_REVERSE_PORT=10002
14 14
 	SRS_SECRET=/etc/@PROJECT_NAME@.secret
15 15
 	RUN_AS=nobody
16
+	CHROOT=@CHROOT_DIR@
16 17
 	if [ -r "$DEFAULTFILE" ]; then
17 18
 		. "$DEFAULTFILE"
18 19
 	fi
19
-	exec @CMAKE_INSTALL_PREFIX@/sbin/@POSTSRSD@ -4 -f$SRS_FORWARD_PORT -r$SRS_REVERSE_PORT -d$SRS_DOMAIN -s$SRS_SECRET -u$RUN_AS
20
+	exec @CMAKE_INSTALL_PREFIX@/sbin/@POSTSRSD@ -4 -f$SRS_FORWARD_PORT -r$SRS_REVERSE_PORT -d$SRS_DOMAIN -s$SRS_SECRET -u$RUN_AS -c$CHROOT
20 21
 end script
22
+

Loading…
취소
저장