-
-
Notifications
You must be signed in to change notification settings - Fork 15
/
daemon.c
146 lines (121 loc) · 3.17 KB
/
daemon.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <sys/socket.h>
#include <netdb.h>
#include "daemon.h"
#include "globals.h"
#include "log.h"
#include "pidfile.h"
#ifndef MINIMALISTIC_BUILD
#define DAEMONIZE_OK 0
#define DAEMONIZE_UNPRIV -1
#define DAEMONIZE_CHROOT -2
#define DAEMONIZE_CHDIR -3
#define DAEMONIZE_DROP -4
#define DAEMONIZE_DAEMON -5
static void load_resolver()
{
struct addrinfo *result = NULL;
getaddrinfo("localhost", NULL, NULL, &result);
if (result) {
freeaddrinfo(result);
}
}
static int find_account(uid_t* uid, gid_t* gid)
{
struct passwd* pwd;
pwd = getpwnam("nobody");
if (!pwd) {
pwd = getpwnam("daemon");
}
if (pwd) {
*uid = pwd->pw_uid;
*gid = pwd->pw_gid;
return 0;
}
return -1;
}
static int drop_privs(struct globals_t* g)
{
if (
setgroups(0, NULL)
|| setgid(g->gid)
|| setuid(g->uid)
) {
return -1;
}
return 0;
}
static int daemonize(struct globals_t* g)
{
if (geteuid() == 0) {
if (!g->uid_set || !g->gid_set) {
uid_t uid;
gid_t gid;
if (-1 == find_account(&uid, &gid)) {
return DAEMONIZE_UNPRIV;
}
if (!g->uid_set) {
g->uid_set = 1;
g->uid = uid;
}
if (!g->gid_set) {
g->gid_set = 1;
g->gid = gid;
}
}
if (g->chroot_dir) {
load_resolver();
if (-1 == chroot(g->chroot_dir)) {
return DAEMONIZE_CHROOT;
}
if (-1 == chdir("/")) {
return DAEMONIZE_CHDIR;
}
}
if (-1 == drop_privs(g)) {
return DAEMONIZE_DROP;
}
}
if (!g->foreground && -1 == daemon(0, 0)) {
return DAEMONIZE_DAEMON;
}
return DAEMONIZE_OK;
}
#endif
void become_daemon(struct globals_t* g)
{
#ifndef MINIMALISTIC_BUILD
int res = daemonize(g);
if (res != DAEMONIZE_OK) {
int err = errno;
switch (res) {
case DAEMONIZE_UNPRIV:
fprintf(stderr, "ERROR: Failed to find an unprivileged account\n");
break;
case DAEMONIZE_CHROOT:
fprintf(stderr, "ERROR: Failed to chroot(%s): %s\n", globals.chroot_dir, strerror(err));
break;
case DAEMONIZE_CHDIR:
fprintf(stderr, "ERROR: Failed to chdir(%s): %s\n", globals.chroot_dir, strerror(err));
break;
case DAEMONIZE_DROP:
fprintf(stderr, "ERROR: Failed to drop privileges\n");
break;
case DAEMONIZE_DAEMON:
fprintf(stderr, "ERROR: Failed to daemonize: %s\n", strerror(err));
break;
}
exit(EXIT_FAILURE);
}
if (globals.pid_file && write_pid(globals.pid_fd)) {
my_log(LOG_DAEMON | LOG_CRIT, "ERROR: Failed to write to the PID file: %s", strerror(errno));
exit(EXIT_FAILURE);
}
#endif
}