File: utils.c

package info (click to toggle)
watchcatd 1.2.1-4
  • links: PTS
  • area: main
  • in suites: bookworm
  • size: 308 kB
  • sloc: ansic: 1,784; sh: 73; makefile: 59; perl: 46
file content (136 lines) | stat: -rw-r--r-- 3,452 bytes parent folder | download | duplicates (3)
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
/*
** $Id: utils.c 2698 2008-08-27 14:03:38Z andre.dig $
** watchcatd - Watchcat Daemon
** See copyright notice in distro's COPYRIGHT file
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>
#include <unistd.h>
#include <sched.h>
#include <syslog.h>
#include <errno.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/mman.h>

#include "utils.h"

extern char **environ;

/* You don't have to call _myassert directly, use the myassert macro.
 * The return mean nothing, it only prevents warnings.
 * The library client musts define mysyslog and mysyslog can't call myassert
 * or myassert_sys!
*/
int _myassert(char *exp, char *filename, int line, const char *func)
{
    mysyslog(LOG_ALERT, "FATAL ERROR, source_filename=`%s', "
             "line=%i, function=%s assertion=`%s'", filename, line, func, exp);
    exit(1);
    return 0;
}

/* You don't have to call _myassert_sys directly, use the myassert_sys macro.
 * The return mean nothing, it only prevents warnings.
 * The library client musts define mysyslog and mysyslog can't call myassert
 * or myassert_sys!
 */
int _myassert_sys(char *exp, char *filename, int line, const char *func)
{
    int e = errno;
    mysyslog(LOG_ALERT, "FATAL ERROR, source_filename=`%s', "
             "line=%i, function=%s assertion=`%s' errno=%i, strerror=`%s'",
             filename, line, func, exp, e, strerror(e));
    exit(e);
    return 0;
}

int is_fd_open(int fd)
{
    struct stat dummy;
    return fstat(fd, &dummy) == 0; 
}

struct env_list {
    char *name;
    char *val;
};

void restrict_env(void)
{
    int i;
    char *envp;
    char *allowed_env[] = { "TZ" };
#define NALLOWED (sizeof(allowed_env)/sizeof(char *))

    struct env_list newenv[NALLOWED];

    for (i = 0; i < NALLOWED; i++) {
        envp = getenv(allowed_env[i]);
        newenv[i].name = (envp ? strdup(allowed_env[i]) : NULL);
        newenv[i].val  = (envp ? strdup(envp) : NULL);
    }

    environ = NULL;
    for (i = 0; i < NALLOWED; i++)
        if (newenv[i].name != NULL)
            setenv(newenv[i].name, newenv[i].val, 1);

    setenv("PATH", "/bin/:/usr/bin/", 1);

    free(envp);
    envp = NULL;
}

/* These are all protections inherited across a fork and shared in watchcat's
 * process group.
 * The protect_process_group function must be called when watchcatd master
 * is starting.
 */
void protect_process_group(int nodaemon, int priority)
{
    struct sched_param sp;

    signal(SIGPIPE, SIG_IGN);

    sp.sched_priority = priority;
    myassert_sys(sched_setscheduler(0, SCHED_RR, &sp) == 0);

    restrict_env();

    if (nodaemon) {
        myassert_sys(chdir("/") == 0);
        myassert_sys(setpgid(0, 0) == 0);
        return;
    }
    myassert_sys(daemon(0, 0) == 0);
}

void drop_privileges(char *user)
{
    struct passwd *pw;
    myassert_sys(pw = getpwnam(user));

    /* Chroot */
    myassert_sys(chroot(pw->pw_dir) == 0);
    myassert_sys(chdir("/") == 0);

    /* Drop privileges */
    myassert_sys(initgroups(user, pw->pw_gid) == 0);
    myassert_sys(setgid(pw->pw_gid) == 0);
    myassert_sys(setuid(pw->pw_uid) == 0);
    myassert(seteuid(0) == -1 && setegid(0) == -1);
}

/* These are all protections doesn't inherited across a fork.
 * The protect_daemon function must be called when daemon is starting.
 */
void protect_daemon(int realtime)
{
    if (realtime)
        myassert_sys(mlockall(MCL_CURRENT | MCL_FUTURE) == 0);
}