|
@@ -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) {
|