author | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-02-25 22:50:24 (GMT) |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-02-25 22:50:24 (GMT) |
commit | 81640ab2b9ad954d4952aed43a70d7874da1c463 (patch) (unidiff) | |
tree | 8160066cb7259357f17a40121f7ed7d0fff5701e /src | |
parent | 9ec721b2a3a023f6339fe3c910635e477e4a311f (diff) | |
download | wydawca-81640ab2b9ad954d4952aed43a70d7874da1c463.tar.gz wydawca-81640ab2b9ad954d4952aed43a70d7874da1c463.tar.bz2 |
Switch to non-privileged UID/GID before startup.
* src/userprivs.c: New file.
* src/Makefile.am (wydawca_SOURCES): Add userprivs.c
* src/config.c (cb_access_method_params): Add missing gl_list_iterator_free.
(cb_user, cb_supp_groups): New callbacks.
(wydawca_kw): New keywords: user and group.
* src/wydawca.c (wydawca_uid, wydawca_gid)
(wydawca_supp_groupc, wydawca_supp_groups): New variables.
(wydawca_set_uid, wydawca_set_gid, wydawca_set_privs)
(wydawca_set_triplet_privs, wydawca_set_root_privs): Remove.
(main): --dry-run implies --cron.
Switch to non-privileged UID/GID before startup.
* src/wydawca.h (wydawca_uid, wydawca_gid)
(wydawca_supp_groupc, wydawca_supp_groups): New declarations.
* src/mail.c (do_notify): Duplicate admin_address, it gets freed in do_notify.
* src/directive.c, src/diskio.c, src/lock.c, src/triplet.c: Update.
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/config.c | 82 | ||||
-rw-r--r-- | src/directive.c | 2 | ||||
-rw-r--r-- | src/diskio.c | 68 | ||||
-rw-r--r-- | src/lock.c | 2 | ||||
-rw-r--r-- | src/mail.c | 2 | ||||
-rw-r--r-- | src/triplet.c | 6 | ||||
-rw-r--r-- | src/userprivs.c | 118 | ||||
-rw-r--r-- | src/wydawca.c | 90 | ||||
-rw-r--r-- | src/wydawca.h | 14 |
10 files changed, 260 insertions, 125 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index c91669e..993ce0d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am | |||
@@ -36,6 +36,7 @@ wydawca_SOURCES=\ | |||
36 | sql.h\ | 36 | sql.h\ |
37 | tcpwrap.c\ | 37 | tcpwrap.c\ |
38 | triplet.c\ | 38 | triplet.c\ |
39 | userprivs.c\ | ||
39 | verify.c\ | 40 | verify.c\ |
40 | wydawca.c\ | 41 | wydawca.c\ |
41 | wydawca.h\ | 42 | wydawca.h\ |
diff --git a/src/config.c b/src/config.c index b1f339f..b6e2533 100644 --- a/src/config.c +++ b/src/config.c | |||
@@ -978,6 +978,7 @@ cb_access_method_params (enum gconf_callback_command cmd, | |||
978 | 978 | ||
979 | meth->parmv[i] = xstrdup (vp->v.string); | 979 | meth->parmv[i] = xstrdup (vp->v.string); |
980 | } | 980 | } |
981 | gl_list_iterator_free (&itr); | ||
981 | meth->parmv[i] = NULL; | 982 | meth->parmv[i] = NULL; |
982 | } | 983 | } |
983 | return 0; | 984 | return 0; |
@@ -1224,6 +1225,82 @@ cb_spool (enum gconf_callback_command cmd, | |||
1224 | } | 1225 | } |
1225 | 1226 | ||
1226 | 1227 | ||
1228 | static int | ||
1229 | cb_user (enum gconf_callback_command cmd, | ||
1230 | gconf_locus_t *locus, | ||
1231 | void *varptr, | ||
1232 | gconf_value_t *value, | ||
1233 | void *cb_data) | ||
1234 | { | ||
1235 | int rc; | ||
1236 | struct passwd *pw; | ||
1237 | |||
1238 | if (assert_string_arg (locus, cmd, value)) | ||
1239 | return 1; | ||
1240 | |||
1241 | pw = getpwnam (value->v.string); | ||
1242 | if (!pw) | ||
1243 | { | ||
1244 | gconf_error (locus, 0, _("no such user: %s"), value->v.string); | ||
1245 | return 1; | ||
1246 | } | ||
1247 | |||
1248 | wydawca_uid = pw->pw_uid; | ||
1249 | wydawca_gid = pw->pw_gid; | ||
1250 | return 0; | ||
1251 | } | ||
1252 | |||
1253 | static int | ||
1254 | cb_supp_groups (enum gconf_callback_command cmd, | ||
1255 | gconf_locus_t *locus, | ||
1256 | void *varptr, | ||
1257 | gconf_value_t *value, | ||
1258 | void *cb_data) | ||
1259 | { | ||
1260 | if (cmd != gconf_callback_set_value) | ||
1261 | { | ||
1262 | gconf_error (locus, 0, _("Unexpected block statement")); | ||
1263 | return 1; | ||
1264 | } | ||
1265 | if (!value || value->type != GCONF_TYPE_LIST) | ||
1266 | { | ||
1267 | gconf_error (locus, 0, _("expected list value")); | ||
1268 | return 1; | ||
1269 | } | ||
1270 | |||
1271 | wydawca_supp_groupc = gl_list_size (value->v.list); | ||
1272 | if (wydawca_supp_groupc == 0) | ||
1273 | wydawca_supp_groups = NULL; | ||
1274 | else | ||
1275 | { | ||
1276 | int i; | ||
1277 | gl_list_iterator_t itr; | ||
1278 | const void *p; | ||
1279 | |||
1280 | wydawca_supp_groups = xcalloc (wydawca_supp_groupc, | ||
1281 | sizeof (wydawca_supp_groups[0])); | ||
1282 | itr = gl_list_iterator (value->v.list); | ||
1283 | for (i = 0; gl_list_iterator_next (&itr, &p, NULL); i++) | ||
1284 | { | ||
1285 | const gconf_value_t *vp = p; | ||
1286 | struct group *grp; | ||
1287 | |||
1288 | if (assert_string_arg (locus, cmd, vp)) | ||
1289 | break; | ||
1290 | grp = getgrnam (vp->v.string); | ||
1291 | if (!grp) | ||
1292 | { | ||
1293 | gconf_error (locus, 0, _("no such group: %s"), value->v.string); | ||
1294 | break; | ||
1295 | } | ||
1296 | wydawca_supp_groups[i] = grp->gr_gid; | ||
1297 | } | ||
1298 | gl_list_iterator_free (&itr); | ||
1299 | } | ||
1300 | return 0; | ||
1301 | } | ||
1302 | |||
1303 | |||
1227 | 1304 | ||
1228 | static struct gconf_keyword wydawca_kw[] = { | 1305 | static struct gconf_keyword wydawca_kw[] = { |
1229 | { "daemon", NULL, N_("Enable daemon mode"), | 1306 | { "daemon", NULL, N_("Enable daemon mode"), |
@@ -1237,6 +1314,11 @@ static struct gconf_keyword wydawca_kw[] = { | |||
1237 | { "pidfile", N_("file"), N_("Set pid file name"), | 1314 | { "pidfile", N_("file"), N_("Set pid file name"), |
1238 | gconf_type_string, &pidfile }, | 1315 | gconf_type_string, &pidfile }, |
1239 | 1316 | ||
1317 | { "user", N_("name"), N_("Run with UID and GID of this user"), | ||
1318 | gconf_type_string, NULL, 0, cb_user }, | ||
1319 | { "group", NULL, N_("Retain these supplementary groups"), | ||
1320 | gconf_type_string|GCONF_LIST, NULL, 0, cb_supp_groups }, | ||
1321 | |||
1240 | { "locking", NULL, N_("Enable or disable locking"), | 1322 | { "locking", NULL, N_("Enable or disable locking"), |
1241 | gconf_type_bool, &enable_locking }, | 1323 | gconf_type_bool, &enable_locking }, |
1242 | { "lockdir", N_("dir"), N_("Set directory for lock files"), | 1324 | { "lockdir", N_("dir"), N_("Set directory for lock files"), |
diff --git a/src/directive.c b/src/directive.c index 2915fee..416095f 100644 --- a/src/directive.c +++ b/src/directive.c | |||
@@ -337,9 +337,7 @@ process_directives (struct file_triplet *trp, const struct spool *spool) | |||
337 | break; | 337 | break; |
338 | 338 | ||
339 | case filename_dir: | 339 | case filename_dir: |
340 | wydawca_set_root_privs (); | ||
341 | rc = verify_detached_signature (trp, spool); | 340 | rc = verify_detached_signature (trp, spool); |
342 | wydawca_set_triplet_privs (trp); | ||
343 | if (rc == 0) | 341 | if (rc == 0) |
344 | { | 342 | { |
345 | if (move_file (trp, spool, file_dist, relative_dir) | 343 | if (move_file (trp, spool, file_dist, relative_dir) |
diff --git a/src/diskio.c b/src/diskio.c index fbd1050..35ba71e 100644 --- a/src/diskio.c +++ b/src/diskio.c | |||
@@ -58,9 +58,9 @@ concat_dir (const char *base, const char *name, size_t *pbaselen) | |||
58 | } | 58 | } |
59 | 59 | ||
60 | /* Create the directory DIR, eventually creating all intermediate directories | 60 | /* Create the directory DIR, eventually creating all intermediate directories |
61 | starting from DIR + BASELEN, with owner UID and GID. */ | 61 | starting from DIR + BASELEN. */ |
62 | int | 62 | int |
63 | create_hierarchy (char *dir, size_t baselen, uid_t uid, gid_t gid) | 63 | create_hierarchy (char *dir, size_t baselen) |
64 | { | 64 | { |
65 | int rc; | 65 | int rc; |
66 | struct stat st; | 66 | struct stat st; |
@@ -92,7 +92,7 @@ create_hierarchy (char *dir, size_t baselen, uid_t uid, gid_t gid) | |||
92 | *p = 0; | 92 | *p = 0; |
93 | } | 93 | } |
94 | 94 | ||
95 | rc = create_hierarchy (dir, baselen, uid, gid); | 95 | rc = create_hierarchy (dir, baselen); |
96 | if (rc == 0) | 96 | if (rc == 0) |
97 | { | 97 | { |
98 | if (p) | 98 | if (p) |
@@ -103,11 +103,6 @@ create_hierarchy (char *dir, size_t baselen, uid_t uid, gid_t gid) | |||
103 | dir, strerror (errno)); | 103 | dir, strerror (errno)); |
104 | rc = 1; | 104 | rc = 1; |
105 | } | 105 | } |
106 | if (chown (dir, uid, gid)) | ||
107 | { | ||
108 | logmsg (LOG_NOTICE, _("cannot change ownership of %s: %s"), | ||
109 | dir, strerror (errno)); | ||
110 | } | ||
111 | } | 106 | } |
112 | return rc; | 107 | return rc; |
113 | } | 108 | } |
@@ -116,18 +111,14 @@ create_hierarchy (char *dir, size_t baselen, uid_t uid, gid_t gid) | |||
116 | NAME). Use UID and GID as owner ids. | 111 | NAME). Use UID and GID as owner ids. |
117 | Do nothing if dry_run_mode is set. */ | 112 | Do nothing if dry_run_mode is set. */ |
118 | char * | 113 | char * |
119 | create_directory (const char *base, const char *name, uid_t uid, gid_t gid) | 114 | create_directory (const char *base, const char *name) |
120 | { | 115 | { |
121 | size_t baselen; | 116 | size_t baselen; |
122 | char *dir = concat_dir (base, name, &baselen); | 117 | char *dir = concat_dir (base, name, &baselen); |
123 | 118 | ||
124 | if (!dry_run_mode) | 119 | if (!dry_run_mode) |
125 | { | 120 | { |
126 | int rc; | 121 | if (create_hierarchy (dir, baselen)) |
127 | wydawca_set_root_privs (); | ||
128 | rc = create_hierarchy (dir, baselen, uid, gid); | ||
129 | wydawca_set_privs (uid, gid); | ||
130 | if (rc) | ||
131 | { | 122 | { |
132 | free (dir); | 123 | free (dir); |
133 | dir = NULL; | 124 | dir = NULL; |
@@ -137,9 +128,9 @@ create_directory (const char *base, const char *name, uid_t uid, gid_t gid) | |||
137 | } | 128 | } |
138 | 129 | ||
139 | 130 | ||
140 | /* Copy FILE to DST_FILE, creating the latter with owner UID and GID. */ | 131 | /* Copy FILE to DST_FILE. */ |
141 | int | 132 | int |
142 | copy_file (const char *file, const char *dst_file, uid_t uid, gid_t gid) | 133 | copy_file (const char *file, const char *dst_file) |
143 | { | 134 | { |
144 | int in_fd, out_fd; | 135 | int in_fd, out_fd; |
145 | struct stat st; | 136 | struct stat st; |
@@ -223,10 +214,9 @@ copy_file (const char *file, const char *dst_file, uid_t uid, gid_t gid) | |||
223 | } | 214 | } |
224 | 215 | ||
225 | /* Move FILE to DST_FILE. If they reside on different devices, use copy_file | 216 | /* Move FILE to DST_FILE. If they reside on different devices, use copy_file |
226 | + unlink. | 217 | + unlink. */ |
227 | UID and GID give DST_FILE ownership. */ | ||
228 | int | 218 | int |
229 | do_move_file (const char *file, const char *dst_file, uid_t uid, gid_t gid) | 219 | do_move_file (const char *file, const char *dst_file) |
230 | { | 220 | { |
231 | int rc = 0; | 221 | int rc = 0; |
232 | 222 | ||
@@ -234,7 +224,7 @@ do_move_file (const char *file, const char *dst_file, uid_t uid, gid_t gid) | |||
234 | { | 224 | { |
235 | if (errno == EXDEV) | 225 | if (errno == EXDEV) |
236 | { | 226 | { |
237 | if (copy_file (file, dst_file, uid, gid)) | 227 | if (copy_file (file, dst_file)) |
238 | { | 228 | { |
239 | logmsg (LOG_CRIT, _("cannot copy %s to %s: %s"), | 229 | logmsg (LOG_CRIT, _("cannot copy %s to %s: %s"), |
240 | file, dst_file, strerror (errno)); | 230 | file, dst_file, strerror (errno)); |
@@ -299,13 +289,12 @@ tar_append_file (const char *archive, const char *file) | |||
299 | DST_DIR - Directory part of DST_FILE. | 289 | DST_DIR - Directory part of DST_FILE. |
300 | FILE - File part of DST_FILE; can contain subdirs. | 290 | FILE - File part of DST_FILE; can contain subdirs. |
301 | ARCHIVE - Archive descriptor. | 291 | ARCHIVE - Archive descriptor. |
302 | UID, GID - Ownership | ||
303 | RELDIR - Directory part of FILE | 292 | RELDIR - Directory part of FILE |
304 | 293 | ||
305 | Do nothing if dry_run_mode is set. */ | 294 | Do nothing if dry_run_mode is set. */ |
306 | int | 295 | int |
307 | backup_file (const char *dst_file, const char *dst_dir, const char *file, | 296 | backup_file (const char *dst_file, const char *dst_dir, const char *file, |
308 | const struct archive_descr *archive, uid_t uid, gid_t gid, | 297 | const struct archive_descr *archive, |
309 | const char *reldir) | 298 | const char *reldir) |
310 | { | 299 | { |
311 | int rc = 0; | 300 | int rc = 0; |
@@ -313,9 +302,9 @@ backup_file (const char *dst_file, const char *dst_dir, const char *file, | |||
313 | char *file_name; | 302 | char *file_name; |
314 | 303 | ||
315 | if (archive->name[0] == '/') | 304 | if (archive->name[0] == '/') |
316 | adir = create_directory (archive->name, reldir, uid, gid); | 305 | adir = create_directory (archive->name, reldir); |
317 | else | 306 | else |
318 | adir = create_directory (dst_dir, archive->name, uid, gid); | 307 | adir = create_directory (dst_dir, archive->name); |
319 | if (!adir) | 308 | if (!adir) |
320 | return 1; | 309 | return 1; |
321 | 310 | ||
@@ -347,7 +336,7 @@ backup_file (const char *dst_file, const char *dst_dir, const char *file, | |||
347 | file_name, archive_file_name); | 336 | file_name, archive_file_name); |
348 | if (!dry_run_mode) | 337 | if (!dry_run_mode) |
349 | { | 338 | { |
350 | rc = do_move_file (file_name, archive_file_name, uid, gid); | 339 | rc = do_move_file (file_name, archive_file_name); |
351 | if (rc) | 340 | if (rc) |
352 | { | 341 | { |
353 | logmsg (LOG_ERR, _("backing `%s' up as `%s' failed: %s"), | 342 | logmsg (LOG_ERR, _("backing `%s' up as `%s' failed: %s"), |
@@ -366,7 +355,7 @@ backup_file (const char *dst_file, const char *dst_dir, const char *file, | |||
366 | logmsg (LOG_DEBUG, _("archiving `%s' to `%s'"), dst_file, file_name); | 355 | logmsg (LOG_DEBUG, _("archiving `%s' to `%s'"), dst_file, file_name); |
367 | if (!dry_run_mode) | 356 | if (!dry_run_mode) |
368 | { | 357 | { |
369 | rc = do_move_file (dst_file, file_name, uid, gid); | 358 | rc = do_move_file (dst_file, file_name); |
370 | if (rc) | 359 | if (rc) |
371 | logmsg (LOG_ERR, _("archiving `%s' as `%s' failed: %s"), | 360 | logmsg (LOG_ERR, _("archiving `%s' as `%s' failed: %s"), |
372 | dst_file, file_name, strerror (errno)); | 361 | dst_file, file_name, strerror (errno)); |
@@ -380,7 +369,7 @@ backup_file (const char *dst_file, const char *dst_dir, const char *file, | |||
380 | for the argument description. */ | 369 | for the argument description. */ |
381 | int | 370 | int |
382 | do_archive_file (const char *dst_file, const char *dst_dir, const char *file, | 371 | do_archive_file (const char *dst_file, const char *dst_dir, const char *file, |
383 | const struct archive_descr *archive, uid_t uid, gid_t gid, | 372 | const struct archive_descr *archive, |
384 | const char *reldir) | 373 | const char *reldir) |
385 | { | 374 | { |
386 | switch (archive->type) | 375 | switch (archive->type) |
@@ -389,7 +378,7 @@ do_archive_file (const char *dst_file, const char *dst_dir, const char *file, | |||
389 | break; | 378 | break; |
390 | 379 | ||
391 | case archive_directory: | 380 | case archive_directory: |
392 | return backup_file (dst_file, dst_dir, file, archive, uid, gid, reldir); | 381 | return backup_file (dst_file, dst_dir, file, archive, reldir); |
393 | 382 | ||
394 | case archive_tar: | 383 | case archive_tar: |
395 | if (tar_append_file (archive->name, dst_file)) | 384 | if (tar_append_file (archive->name, dst_file)) |
@@ -415,8 +404,7 @@ dir_move_file (struct file_triplet *trp, const struct spool *spool, | |||
415 | { | 404 | { |
416 | char *dst_file; | 405 | char *dst_file; |
417 | int rc = 0; | 406 | int rc = 0; |
418 | char *dst_dir = create_directory (spool->dest_dir, reldir, | 407 | char *dst_dir = create_directory (spool->dest_dir, reldir); |
419 | TRIPLET_UID (trp), TRIPLET_GID (trp)); | ||
420 | 408 | ||
421 | if (!dst_dir) | 409 | if (!dst_dir) |
422 | return 1; | 410 | return 1; |
@@ -428,12 +416,10 @@ dir_move_file (struct file_triplet *trp, const struct spool *spool, | |||
428 | 416 | ||
429 | if (access (dst_file, F_OK) == 0) | 417 | if (access (dst_file, F_OK) == 0) |
430 | rc = do_archive_file (dst_file, dst_dir, trp->file[file_id].name, | 418 | rc = do_archive_file (dst_file, dst_dir, trp->file[file_id].name, |
431 | &spool->archive, | 419 | &spool->archive, reldir); |
432 | TRIPLET_UID (trp), TRIPLET_GID (trp), reldir); | ||
433 | 420 | ||
434 | if (!dry_run_mode && rc == 0) | 421 | if (!dry_run_mode && rc == 0) |
435 | rc = do_move_file (trp->file[file_id].name, dst_file, | 422 | rc = do_move_file (trp->file[file_id].name, dst_file); |
436 | TRIPLET_UID (trp), TRIPLET_GID (trp)); | ||
437 | 423 | ||
438 | free (dst_file); | 424 | free (dst_file); |
439 | free (dst_dir); | 425 | free (dst_dir); |
@@ -453,8 +439,7 @@ archive_single_file (struct file_triplet *trp, const struct spool *spool, | |||
453 | { | 439 | { |
454 | char *dst_file; | 440 | char *dst_file; |
455 | int rc = 0; | 441 | int rc = 0; |
456 | char *dst_dir = create_directory (spool->dest_dir, reldir, | 442 | char *dst_dir = create_directory (spool->dest_dir, reldir); |
457 | TRIPLET_UID (trp), TRIPLET_GID (trp)); | ||
458 | 443 | ||
459 | if (!dst_dir) | 444 | if (!dst_dir) |
460 | return 1; | 445 | return 1; |
@@ -474,7 +459,7 @@ archive_single_file (struct file_triplet *trp, const struct spool *spool, | |||
474 | if (debug_level) | 459 | if (debug_level) |
475 | logmsg (LOG_DEBUG, _("archiving file `%s'"), dst_file); | 460 | logmsg (LOG_DEBUG, _("archiving file `%s'"), dst_file); |
476 | rc = do_archive_file (dst_file, dst_dir, file_name, &spool->archive, | 461 | rc = do_archive_file (dst_file, dst_dir, file_name, &spool->archive, |
477 | TRIPLET_UID (trp), TRIPLET_GID (trp), reldir); | 462 | reldir); |
478 | if (rc == 0) | 463 | if (rc == 0) |
479 | UPDATE_STATS (STAT_ARCHIVES); | 464 | UPDATE_STATS (STAT_ARCHIVES); |
480 | } | 465 | } |
@@ -543,8 +528,7 @@ dir_symlink_file (struct file_triplet *trp, const struct spool *spool, | |||
543 | { | 528 | { |
544 | int rc = 0; | 529 | int rc = 0; |
545 | struct saved_cwd cwd; | 530 | struct saved_cwd cwd; |
546 | char *dst_dir = create_directory (spool->dest_dir, reldir, | 531 | char *dst_dir = create_directory (spool->dest_dir, reldir); |
547 | TRIPLET_UID (trp), TRIPLET_GID (trp)); | ||
548 | char *src, *dst; | 532 | char *src, *dst; |
549 | 533 | ||
550 | if (!dst_dir) | 534 | if (!dst_dir) |
@@ -588,8 +572,7 @@ dir_symlink_file (struct file_triplet *trp, const struct spool *spool, | |||
588 | char *dir; | 572 | char *dir; |
589 | 573 | ||
590 | *p = 0; | 574 | *p = 0; |
591 | dir = create_directory (spool->dest_dir, dst, | 575 | dir = create_directory (spool->dest_dir, dst); |
592 | TRIPLET_UID (trp), TRIPLET_GID (trp)); | ||
593 | if (!dir) | 576 | if (!dir) |
594 | rc = 1; | 577 | rc = 1; |
595 | else | 578 | else |
@@ -703,8 +686,7 @@ dir_rmsymlink_file (struct file_triplet *trp, const struct spool *spool, | |||
703 | char *dst_file; | 686 | char *dst_file; |
704 | int rc = 0; | 687 | int rc = 0; |
705 | char *signame; | 688 | char *signame; |
706 | char *dst_dir = create_directory (spool->dest_dir, reldir, | 689 | char *dst_dir = create_directory (spool->dest_dir, reldir); |
707 | TRIPLET_UID (trp), TRIPLET_GID (trp)); | ||
708 | 690 | ||
709 | if (!dst_dir) | 691 | if (!dst_dir) |
710 | return 1; | 692 | return 1; |
@@ -233,7 +233,7 @@ wydawca_lock_init () | |||
233 | { | 233 | { |
234 | if (!lockdir) | 234 | if (!lockdir) |
235 | lockdir = xstrdup (LOCALSTATEDIR "/lock/" PACKAGE); | 235 | lockdir = xstrdup (LOCALSTATEDIR "/lock/" PACKAGE); |
236 | if (create_hierarchy (lockdir, 0, getuid (), getgid ())) | 236 | if (create_hierarchy (lockdir, 0)) |
237 | exit (EX_OSFILE); | 237 | exit (EX_OSFILE); |
238 | } | 238 | } |
239 | } | 239 | } |
@@ -335,7 +335,7 @@ do_notify (struct file_triplet *trp, enum notification_event ev, | |||
335 | switch (ntf->tgt) | 335 | switch (ntf->tgt) |
336 | { | 336 | { |
337 | case notify_admin: | 337 | case notify_admin: |
338 | rcpt = admin_address; | 338 | rcpt = mu_address_dup (admin_address); |
339 | break; | 339 | break; |
340 | 340 | ||
341 | case notify_user: | 341 | case notify_user: |
diff --git a/src/triplet.c b/src/triplet.c index 614e2b5..e060089 100644 --- a/src/triplet.c +++ b/src/triplet.c | |||
@@ -199,11 +199,7 @@ triplet_processor (void *data, void *proc_data) | |||
199 | case triplet_complete: | 199 | case triplet_complete: |
200 | if (debug_level) | 200 | if (debug_level) |
201 | logmsg (LOG_DEBUG, _("processing triplet `%s'"), trp->name); | 201 | logmsg (LOG_DEBUG, _("processing triplet `%s'"), trp->name); |
202 | if (wydawca_set_triplet_privs (trp) == 0) | 202 | process_directives (trp, spool); |
203 | { | ||
204 | process_directives (trp, spool); | ||
205 | wydawca_set_root_privs (); | ||
206 | } | ||
207 | return true; | 203 | return true; |
208 | 204 | ||
209 | case triplet_incomplete: | 205 | case triplet_incomplete: |
diff --git a/src/userprivs.c b/src/userprivs.c new file mode 100644 index 0000000..e6a18c8 --- a/dev/null +++ b/src/userprivs.c | |||
@@ -0,0 +1,118 @@ | |||
1 | /* wydawca - automatic release submission daemon | ||
2 | Copyright (C) 2007, 2009 Sergey Poznyakoff | ||
3 | |||
4 | Wydawca is free software; you can redistribute it and/or modify it | ||
5 | under the terms of the GNU General Public License as published by the | ||
6 | Free Software Foundation; either version 3 of the License, or (at your | ||
7 | option) any later version. | ||
8 | |||
9 | Wydawca is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License along | ||
15 | with wydawca. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include "wydawca.h" | ||
18 | |||
19 | int | ||
20 | wydawca_userprivs (uid_t uid, gid_t gid, gid_t *grplist, size_t ngrp) | ||
21 | { | ||
22 | int rc = 0; | ||
23 | size_t size = 1, j = 1; | ||
24 | |||
25 | if (uid == 0) | ||
26 | return 0; | ||
27 | |||
28 | /* Reset group permissions */ | ||
29 | if (geteuid () == 0 && setgroups (ngrp, grplist)) | ||
30 | { | ||
31 | logmsg (LOG_CRIT, "setgroups(%lu, %lu...): %s", | ||
32 | ngrp, grplist[0], 0, strerror (errno)); | ||
33 | return rc; | ||
34 | } | ||
35 | |||
36 | /* Switch to the user's gid. On some OSes the effective gid must | ||
37 | be reset first */ | ||
38 | |||
39 | #if defined(HAVE_SETEGID) | ||
40 | if ((rc = setegid (gid)) < 0) | ||
41 | logmsg (LOG_CRIT, "setegid(%lu): %s", gid, strerror (errno)); | ||
42 | #elif defined(HAVE_SETREGID) | ||
43 | if ((rc = setregid (gid, gid)) < 0) | ||
44 | logmsg (LOG_CRIT, "setregid(%lu,%lu)d: %s", | ||
45 | (unsigned long) gid, (unsigned long) gid, strerror (errno)); | ||
46 | #elif defined(HAVE_SETRESGID) | ||
47 | if ((rc = setresgid (gid, gid, gid)) < 0) | ||
48 | logmsg (LOG_CRIT, "setresgid(%lu,%lu,%lu): %s", | ||
49 | (unsigned long) gid, (unsigned long) gid, | ||
50 | (unsigned long) gid, | ||
51 | strerror (errno)); | ||
52 | #endif | ||
53 | |||
54 | if (rc == 0 && gid != 0) | ||
55 | { | ||
56 | if ((rc = setgid (gid)) < 0 && getegid () != gid) | ||
57 | logmsg (LOG_CRIT, "setgid(%lu): %s", | ||
58 | (unsigned long) gid, strerror (errno)); | ||
59 | if (rc == 0 && getegid () != gid) | ||
60 | { | ||
61 | logmsg (LOG_CRIT, _("cannot set effective gid to %lu"), | ||
62 | (unsigned long) gid); | ||
63 | rc = 1; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | /* Now reset uid */ | ||
68 | if (rc == 0 && uid != 0) | ||
69 | { | ||
70 | uid_t euid; | ||
71 | |||
72 | if (setuid (uid) | ||
73 | || geteuid () != uid | ||
74 | || (getuid () != uid | ||
75 | && (geteuid () == 0 || getuid () == 0))) | ||
76 | { | ||
77 | |||
78 | #if defined(HAVE_SETREUID) | ||
79 | if (geteuid () != uid) | ||
80 | { | ||
81 | if (setreuid (uid, -1) < 0) | ||
82 | { | ||
83 | logmsg (LOG_CRIT, "setreuid(%lu,-1): %s", | ||
84 | (unsigned long) uid, strerror (errno)); | ||
85 | rc = 1; | ||
86 | } | ||
87 | if (setuid (uid) < 0) | ||
88 | { | ||
89 | logmsg (LOG_CRIT, "setreuid(%lu,-1): %s", | ||
90 | (unsigned long) uid, strerror (errno)); | ||
91 | rc = 1; | ||
92 | } | ||
93 | } | ||
94 | else | ||
95 | #endif | ||
96 | { | ||
97 | logmsg (LOG_CRIT, "setuid(%lu): %s", | ||
98 | (unsigned long) uid, strerror (errno)); | ||
99 | rc = 1; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | euid = geteuid (); | ||
104 | if (uid != 0 && setuid (0) == 0) | ||
105 | { | ||
106 | logmsg (LOG_CRIT, _("seteuid(0) succeeded when it should not")); | ||
107 | rc = 1; | ||
108 | } | ||
109 | else if (uid != euid && setuid (euid) == 0) | ||
110 | { | ||
111 | logmsg (LOG_CRIT, _("cannot drop non-root setuid privileges")); | ||
112 | rc = 1; | ||
113 | } | ||
114 | |||
115 | } | ||
116 | |||
117 | return rc; | ||
118 | } | ||
diff --git a/src/wydawca.c b/src/wydawca.c index 48c27e9..f02ac99 100644 --- a/src/wydawca.c +++ b/src/wydawca.c | |||
@@ -19,6 +19,10 @@ | |||
19 | #include "argmatch.h" | 19 | #include "argmatch.h" |
20 | #include "version-etc.h" | 20 | #include "version-etc.h" |
21 | 21 | ||
22 | uid_t wydawca_uid; | ||
23 | gid_t wydawca_gid; | ||
24 | size_t wydawca_supp_groupc; | ||
25 | gid_t *wydawca_supp_groups; | ||
22 | char *conffile = SYSCONFDIR "/wydawca.rc" ; | 26 | char *conffile = SYSCONFDIR "/wydawca.rc" ; |
23 | int debug_level; | 27 | int debug_level; |
24 | int dry_run_mode; | 28 | int dry_run_mode; |
@@ -265,73 +269,6 @@ collect_uids (int argc, char **argv) | |||
265 | } | 269 | } |
266 | 270 | ||
267 | 271 | ||
268 | static int | ||
269 | wydawca_set_uid (uid_t uid) | ||
270 | { | ||
271 | int rc; | ||
272 | |||
273 | if (getuid () != 0) | ||
274 | return 0; | ||
275 | #if defined(HAVE_SETREUID) | ||
276 | rc = setreuid (0, uid); | ||
277 | #elif defined(HAVE_SETRESUID) | ||
278 | rc = setresuid (-1, uid, -1); | ||
279 | #elif defined(HAVE_SETEUID) | ||
280 | rc = seteuid (uid); | ||
281 | #else | ||
282 | # error "No way to reset user privileges?" | ||
283 | #endif | ||
284 | if (rc < 0) | ||
285 | logmsg (LOG_ERR, _("cannot switch to UID %d: %s (r=%d, e=%d)"), | ||
286 | uid, strerror (errno), getuid (), geteuid ()); | ||
287 | return rc; | ||
288 | } | ||
289 | |||
290 | static int | ||
291 | wydawca_set_gid (gid_t gid) | ||
292 | { | ||
293 | int rc; | ||
294 | |||
295 | if (getuid () != 0) | ||
296 | return 0; | ||
297 | #if defined(HAVE_SETREGID) | ||
298 | rc = setregid (0, gid); | ||
299 | #elif defined(HAVE_SETRESGID) | ||
300 | rc = setresgid (-1, gid, -1); | ||
301 | #elif defined(HAVE_SETEGID) | ||
302 | rc = setegid (gid); | ||
303 | #else | ||
304 | # error "No way to reset user privileges?" | ||
305 | #endif | ||
306 | if (rc < 0) | ||
307 | logmsg (LOG_ERR, _("cannot switch to GID %d: %s (r=%d, e=%d)"), | ||
308 | gid, strerror (errno), getgid (), getegid ()); | ||
309 | return rc; | ||
310 | } | ||
311 | |||
312 | int | ||
313 | wydawca_set_privs (uid_t uid, gid_t gid) | ||
314 | { | ||
315 | if (wydawca_set_gid (gid)) | ||
316 | return -1; | ||
317 | if (wydawca_set_uid (uid)) | ||
318 | return -1; | ||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | int | ||
323 | wydawca_set_triplet_privs (struct file_triplet *trp) | ||
324 | { | ||
325 | return wydawca_set_privs (TRIPLET_UID (trp), TRIPLET_GID (trp)); | ||
326 | } | ||
327 | |||
328 | int | ||
329 | wydawca_set_root_privs () | ||
330 | { | ||
331 | return wydawca_set_privs (0, 0); | ||
332 | } | ||
333 | |||
334 | |||
335 | char **x_argv; | 272 | char **x_argv; |
336 | extern int reconfigure; | 273 | extern int reconfigure; |
337 | 274 | ||
@@ -377,6 +314,8 @@ main (int argc, char **argv) | |||
377 | if (lint_mode) | 314 | if (lint_mode) |
378 | exit (0); | 315 | exit (0); |
379 | 316 | ||
317 | if (dry_run_mode) | ||
318 | cron_option = 1; | ||
380 | if (cron_option) | 319 | if (cron_option) |
381 | daemon_mode = 0; | 320 | daemon_mode = 0; |
382 | if (foreground_option >= 0) | 321 | if (foreground_option >= 0) |
@@ -394,6 +333,22 @@ main (int argc, char **argv) | |||
394 | log_printer = syslog_printer; | 333 | log_printer = syslog_printer; |
395 | } | 334 | } |
396 | 335 | ||
336 | if (getgid () == 0) | ||
337 | { | ||
338 | if (wydawca_uid == 0) | ||
339 | { | ||
340 | if (!force_startup) | ||
341 | { | ||
342 | logmsg (LOG_CRIT, _("won't run with root privileges")); | ||
343 | exit (EX_UNAVAILABLE); | ||
344 | } | ||
345 | } | ||
346 | else if (wydawca_userprivs (wydawca_uid, wydawca_gid, | ||
347 | wydawca_supp_groups, | ||
348 | wydawca_supp_groupc)) | ||
349 | exit (EX_UNAVAILABLE); | ||
350 | } | ||
351 | |||
397 | mail_init (); | 352 | mail_init (); |
398 | wydawca_lock_init (); | 353 | wydawca_lock_init (); |
399 | 354 | ||
@@ -414,7 +369,6 @@ main (int argc, char **argv) | |||
414 | if (reconfigure) | 369 | if (reconfigure) |
415 | { | 370 | { |
416 | int i; | 371 | int i; |
417 | wydawca_set_uid (0); | ||
418 | for (i = getdtablesize (); i > 2; i--) | 372 | for (i = getdtablesize (); i > 2; i--) |
419 | close (i); | 373 | close (i); |
420 | remove_pidfile (); | 374 | remove_pidfile (); |
diff --git a/src/wydawca.h b/src/wydawca.h index f786271..81e6509 100644 --- a/src/wydawca.h +++ b/src/wydawca.h | |||
@@ -303,6 +303,10 @@ void make_default_meta (struct metadef kwexp[5], const char *user, | |||
303 | 303 | ||
304 | 304 | ||
305 | /* Global variables */ | 305 | /* Global variables */ |
306 | extern uid_t wydawca_uid; | ||
307 | extern gid_t wydawca_gid; | ||
308 | extern size_t wydawca_supp_groupc; | ||
309 | extern gid_t *wydawca_supp_groups; | ||
306 | extern char *conffile; /* Configuration file name */ | 310 | extern char *conffile; /* Configuration file name */ |
307 | extern int debug_level; /* Debugging level */ | 311 | extern int debug_level; /* Debugging level */ |
308 | extern int dry_run_mode; /* Dry run indicator */ | 312 | extern int dry_run_mode; /* Dry run indicator */ |
@@ -355,8 +359,8 @@ size_t trim_length (const char *str); | |||
355 | size_t trim (char *str); | 359 | size_t trim (char *str); |
356 | void logmsg (int prio, char *fmt, ...) GSC_PRINTFLIKE(2,3); | 360 | void logmsg (int prio, char *fmt, ...) GSC_PRINTFLIKE(2,3); |
357 | int test_dir (const char *name, int *ec); | 361 | int test_dir (const char *name, int *ec); |
358 | char *create_directory (const char *base, const char *name, | 362 | char *create_directory (const char *base, const char *name); |
359 | uid_t uid, gid_t gid); | 363 | int create_hierarchy (char *dir, size_t baselen); |
360 | void parse_config (void); | 364 | void parse_config (void); |
361 | void log_output (int prio, const char *prog, FILE *fp); | 365 | void log_output (int prio, const char *prog, FILE *fp); |
362 | 366 | ||
@@ -428,9 +432,6 @@ int process_directives (struct file_triplet *trp, | |||
428 | 432 | ||
429 | int enabled_spool_p (const struct spool *spool); | 433 | int enabled_spool_p (const struct spool *spool); |
430 | 434 | ||
431 | int wydawca_set_privs (uid_t uid, gid_t gid); | ||
432 | int wydawca_set_triplet_privs (struct file_triplet *trp); | ||
433 | int wydawca_set_root_privs (void); | ||
434 | 435 | ||
435 | 436 | ||
436 | int parse_time_interval (const char *str, time_t *pint, const char **endp); | 437 | int parse_time_interval (const char *str, time_t *pint, const char **endp); |
@@ -538,3 +539,6 @@ void wydawca_lock_init (void); | |||
538 | /* tcpwrap.h */ | 539 | /* tcpwrap.h */ |
539 | extern struct gconf_keyword tcpwrapper_kw[]; | 540 | extern struct gconf_keyword tcpwrapper_kw[]; |
540 | int tcpwrap_access(int fd); | 541 | int tcpwrap_access(int fd); |
542 | |||
543 | /* userprivs.c */ | ||
544 | int wydawca_userprivs (uid_t uid, gid_t gid, gid_t *grplist, size_t ngrp); | ||