00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #ifdef HAVE_CONFIG_H
00027 # include <config.h>
00028 #endif
00029
00030 #include <sys/types.h>
00031 #include <pwd.h>
00032 #include <grp.h>
00033 #include <sys/time.h>
00034 #include <sys/resource.h>
00035 #include <unistd.h>
00036 #include <sys/socket.h>
00037 #include <sys/stat.h>
00038 #include <fcntl.h>
00039 #include <errno.h>
00040 #include <syslog.h>
00041
00042 #include "file.h"
00043 #include "errmanager.h"
00044 #include "daemonize.h"
00045 #include "dbug_mem.h"
00046
00047
00048
00049 extern int errno;
00050
00051
00052
00053 int
00054 sb_daemon_drop_privileges(void)
00055 {
00056 uid_t uid = getuid();
00057 gid_t gid = getgid();
00058 uid_t euid = geteuid();
00059 gid_t egid = getegid();
00060
00061
00062 if (egid != gid && (setgid(gid) == -1 || getegid() != getgid())) {
00063 return -1;
00064 }
00065
00066
00067 if (euid != uid && (setuid(uid) == -1 || geteuid() != getuid())) {
00068 return -1;
00069 }
00070
00071
00072 endpwent();
00073
00074 endgrent();
00075
00076 return 0;
00077 }
00078
00079
00080
00081 int
00082 sb_daemon_no_corefile(void)
00083 {
00084 struct rlimit limit[1] = {{ 0, 0 }};
00085
00086 if (getrlimit(RLIMIT_CORE, limit) == -1) {
00087 return -1;
00088 }
00089
00090 limit->rlim_cur = 0;
00091
00092 if (setrlimit(RLIMIT_CORE, limit) != 0) {
00093 return -1;
00094 }
00095
00096 return 0;
00097 }
00098
00099
00100
00101 int
00102 sb_daemon_is_started_by_init(void)
00103 {
00104
00105 if (getppid() == 1) {
00106 return 1;
00107 }
00108
00109 return 0;
00110 }
00111
00112
00113
00114 int
00115 sb_daemon_is_started_by_inetd(void)
00116 {
00117 size_t param_length = sizeof(int);
00118 int socket_type;
00119
00120
00121 if (getsockopt(STDIN_FILENO, SOL_SOCKET, SO_TYPE,
00122 &socket_type, (void *)¶m_length) == 0) {
00123 return 1;
00124 }
00125
00126 return 0;
00127 }
00128
00129
00130
00131 int
00132 sb_daemon_is_started_by_root(void)
00133 {
00134 if (getuid() != 0) {
00135 return 0;
00136 }
00137
00138 return 1;
00139 }
00140
00141
00142
00143 int
00144 sb_daemon_is_started_suid(void)
00145 {
00146
00147
00148
00149 if (getgid() != getegid()) {
00150 return 1;
00151 }
00152
00153
00154 if (getuid() != geteuid()) {
00155 return 1;
00156 }
00157
00158 return 0;
00159 }
00160
00161
00162
00163 int
00164 sb_daemon_create_fd(int fd, int mode)
00165 {
00166 int i;
00167
00168
00169 if ((i = open("/dev/null", mode)) == -1) {
00170 return -1;
00171 }
00172
00173 if (i != fd) {
00174 if (dup2(i, fd) == -1) {
00175 return -1;
00176 }
00177 close(i);
00178 }
00179
00180 return fd;
00181 }
00182
00183
00184
00185 int
00186 sb_daemon_change_user(uid_t uid, gid_t gid)
00187 {
00188
00189 if (sb_daemon_is_started_by_root() == 0) {
00190 return -1;
00191 }
00192
00193
00194 if ((setgid(gid) == -1) || (getgid() != gid) || (getegid() != gid)) {
00195 return -1;
00196 }
00197
00198
00199 if ((setuid(uid) == -1) || (getuid() != uid) || (geteuid() != uid)) {
00200 return -1;
00201 }
00202
00203 return 0;
00204 }
00205
00206
00207
00208 int
00209 sb_daemon_detach(const char *rundir)
00210 {
00211 long i;
00212 pid_t pid;
00213
00214
00215 if (sb_daemon_is_started_by_root() == 0) {
00216 return -1;
00217 }
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228 if ((!sb_daemon_is_started_by_init()) && (!sb_daemon_is_started_by_inetd())) {
00229
00230
00231
00232
00233
00234
00235 pid = fork();
00236 if (pid == -1) {
00237 return -1;
00238 }
00239 if (pid != 0) {
00240 exit(EXIT_SUCCESS);
00241 }
00242
00243
00244
00245
00246
00247
00248 setsid();
00249
00250
00251
00252
00253 signal(SIGHUP, SIG_IGN);
00254
00255
00256
00257
00258 pid = fork();
00259 if (pid == -1) {
00260 return -1;
00261 }
00262 if (pid != 0) {
00263 exit(EXIT_SUCCESS);
00264 }
00265
00266 }
00267
00268
00269
00270
00271
00272
00273
00274 if (rundir != NULL) {
00275 struct stat st;
00276 if ((stat(rundir, &st) == 0) && (S_ISDIR(st.st_mode))) {
00277 chdir(rundir);
00278 } else {
00279 return -1;
00280 }
00281 } else {
00282 chdir("/");
00283 }
00284
00285
00286
00287 umask(0);
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298 if (sb_daemon_is_started_by_inetd() == 1) {
00299
00300 for (i = 0; i < sysconf(_SC_OPEN_MAX); i++) {
00301 if ((i!=STDIN_FILENO) && (i!=STDOUT_FILENO) && (i!=STDERR_FILENO)) {
00302 close(i);
00303 }
00304 }
00305 } else {
00306
00307 for (i = 0; i < sysconf(_SC_OPEN_MAX); i++) {
00308 close(i);
00309 }
00310 }
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320 if (sb_daemon_is_started_by_inetd() == 0) {
00321
00322
00323
00324 if (sb_daemon_create_fd(STDIN_FILENO, O_RDONLY) == -1) {
00325 return -1;
00326 }
00327
00328
00329 if (sb_daemon_create_fd(STDOUT_FILENO, O_WRONLY) == -1) {
00330 return -1;
00331 }
00332
00333
00334 if (sb_daemon_create_fd(STDERR_FILENO, O_WRONLY) == -1) {
00335 return -1;
00336 }
00337 }
00338
00339 return 0;
00340 }
00341
00342
00343
00344 int
00345 sb_daemon_init(const char *name,
00346 const char *rundir,
00347 const char *pidfile)
00348 {
00349 int fd = -1;
00350
00351 if (sb_daemon_is_running(pidfile) == 1) {
00352 return -1;
00353 }
00354
00355
00356 emClose();
00357
00358
00359 if (sb_daemon_detach(rundir) != 0) {
00360
00361 emInit(LOG_DEBUG, EM_TYPE_SYSLOG, NULL, NULL, NULL, name);
00362 return -1;
00363 }
00364
00365
00366 emInit(LOG_DEBUG, EM_TYPE_SYSLOG, NULL, NULL, NULL, name);
00367
00368
00369 if (pidfile != NULL) {
00370 if ((fd = sb_daemon_pidfile_create_and_lock(pidfile)) == -1) {
00371 return -1;
00372 }
00373 if (sb_daemon_pidfile_write(fd) == -1) {
00374 return -1;
00375 }
00376 }
00377
00378 return 0;
00379 }
00380
00381
00382
00383 int
00384 sb_daemon_is_running(const char *pidfile)
00385 {
00386 int fd = -1;
00387
00388
00389 if (pidfile == NULL) {
00390 return ERRNO(EINVAL);
00391 }
00392
00393
00394 if ((fd = sb_daemon_pidfile_create_and_lock(pidfile)) == -1) {
00395 if ((errno == EACCES) || (errno == EAGAIN)) {
00396
00397 return 1;
00398 }
00399
00400 return -1;
00401 }
00402
00403
00404 sb_file_close(fd);
00405 sb_file_remove(pidfile);
00406
00407 return 0;
00408 }
00409
00410
00411
00412 int
00413 sb_daemon_destroy(const char *pidfile)
00414 {
00415
00416 sb_file_remove(pidfile);
00417
00418 return 0;
00419 }
00420
00421
00422
00423 int
00424 sb_daemon_pidfile_create_and_lock(const char *pidfile)
00425 {
00426 int fd = -1;
00427
00428
00429
00430
00431
00432
00433 if ((fd = sb_file_open_ext(pidfile,
00434 O_RDWR | O_SYNC | O_CREAT | O_EXCL,
00435 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
00436 {
00437
00438 if (errno != EEXIST) {
00439 return -1;
00440 }
00441
00442
00443
00444 if ((fd = sb_file_open(pidfile, O_RDWR | O_SYNC)) == -1) {
00445 return -1;
00446 }
00447 }
00448
00449
00450 if (sb_file_lock_acquire_write(fd) == -1) {
00451 return -1;
00452 }
00453
00454 return fd;
00455 }
00456
00457
00458
00459 int
00460 sb_daemon_pidfile_write(int fd)
00461 {
00462 ssize_t written = 0;
00463 char data[MAX_PIDDATA_LENGTH];
00464
00465
00466 memset(data, 0, sizeof(data));
00467 snprintf(data, MAX_PIDDATA_LENGTH, "%d\n", (int)getpid());
00468 data[MAX_PIDDATA_LENGTH-1] = '\0';
00469
00470
00471 lseek(fd, 0, SEEK_SET);
00472
00473
00474 if ((written = write(fd, data, strlen(data))) == -1) {
00475 return -1;
00476 }
00477 if ((size_t)written < strlen(data)) {
00478 return -1;
00479 }
00480
00481
00482 fsync(fd);
00483 sync();
00484
00485 return 0;
00486 }
00487
00488
00489
00490 pid_t
00491 sb_daemon_pidfile_read(const char *pidfile)
00492 {
00493 int fd = -1;
00494 char data[MAX_PIDDATA_LENGTH];
00495 int pid = -1;
00496
00497 if ((fd = sb_file_open(pidfile, O_RDONLY)) == -1) {
00498 return -1;
00499 }
00500
00501 memset(data, 0, sizeof(data));
00502 if (read(fd, &data, MAX_PIDDATA_LENGTH) == -1) {
00503 return -1;
00504 }
00505
00506 if (sscanf(data, "%d", &pid) != 1) {
00507 return -1;
00508 }
00509
00510 return pid;
00511 }