summaryrefslogtreecommitdiffstats
path: root/lib/privs.h
blob: d4a9609b5dbd745101d96045c3f11ac949ee5953 (plain)
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
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Zebra privileges header.
 *
 * Copyright (C) 2003 Paul Jakma.
 */

#ifndef _ZEBRA_PRIVS_H
#define _ZEBRA_PRIVS_H

#include <pthread.h>
#include <stdint.h>
#include "lib/queue.h"

#ifdef __cplusplus
extern "C" {
#endif

/* list of zebra capabilities */
typedef enum {
	ZCAP_SETID,
	ZCAP_BIND,
	ZCAP_NET_ADMIN,
	ZCAP_SYS_ADMIN,
	ZCAP_NET_RAW,
	ZCAP_CHROOT,
	ZCAP_NICE,
	ZCAP_PTRACE,
	ZCAP_DAC_OVERRIDE,
	ZCAP_READ_SEARCH,
	ZCAP_FOWNER,
	ZCAP_IPC_LOCK,
	ZCAP_SYS_RAWIO,
	ZCAP_MAX
} zebra_capabilities_t;

typedef enum {
	ZPRIVS_LOWERED,
	ZPRIVS_RAISED,
	ZPRIVS_UNKNOWN,
} zebra_privs_current_t;

typedef enum {
	ZPRIVS_RAISE,
	ZPRIVS_LOWER,
} zebra_privs_ops_t;

struct zebra_privs_refs_t {
	STAILQ_ENTRY(zebra_privs_refs_t) entry;
	pthread_t tid;
	uint32_t refcount;
	const char *raised_in_funcname;
};

struct zebra_privs_t {
	zebra_capabilities_t *caps_p; /* caps required for operation */
	zebra_capabilities_t *caps_i; /* caps to allow inheritance of */
	int cap_num_p;		      /* number of caps in arrays */
	int cap_num_i;

	/* Mutex and counter used to avoid race conditions in multi-threaded
	 * processes. If privs status is process-wide, we need to
	 * control changes to the privilege status among threads.
	 * If privs changes are per-thread, we need to be able to
	 * manage that too.
	 */
	pthread_mutex_t mutex;
	struct zebra_privs_refs_t process_refs;

	STAILQ_HEAD(thread_refs_q, zebra_privs_refs_t) thread_refs;

	const char *user; /* user and group to run as */
	const char *group;
	const char *vty_group; /* group to chown vty socket to */
	/* methods */
	int (*change)(zebra_privs_ops_t); /* change privileges, 0 on success */
	zebra_privs_current_t (*current_state)(
		void); /* current privilege state */
};

struct zprivs_ids_t {
	/* -1 is undefined */
	uid_t uid_priv;   /* privileged uid */
	uid_t uid_normal; /* normal uid */
	gid_t gid_priv;   /* privileged uid */
	gid_t gid_normal; /* normal uid */
	gid_t gid_vty;    /* vty gid */
};

extern struct zebra_privs_t *lib_privs;

/* initialise zebra privileges */
extern void zprivs_preinit(struct zebra_privs_t *zprivs);
extern void zprivs_init(struct zebra_privs_t *zprivs);
/* drop all and terminate privileges */
extern void zprivs_terminate(struct zebra_privs_t *);
/* query for runtime uid's and gid's, eg vty needs this */
extern void zprivs_get_ids(struct zprivs_ids_t *);

/*
 * Wrapper around zprivs, to be used as:
 *   frr_with_privs(&privs) {
 *     ... code ...
 *     if (error)
 *       break;         -- break can be used to get out of the block
 *     ... code ...
 *   }
 *
 * The argument to frr_with_privs() can be NULL to leave privileges as-is
 * (mostly useful for conditional privilege-raising, i.e.:)
 *   frr_with_privs(cond ? &privs : NULL) {}
 *
 * NB: The code block is always executed, regardless of whether privileges
 * could be raised or not, or whether NULL was given or not.  This is fully
 * intentional;  the user may have configured some RBAC or similar that we
 * are not aware of, but that allows our code to proceed without privileges.
 *
 * The point of this wrapper is to prevent accidental bugs where privileges
 * are elevated but then not dropped.  This can happen when, for example, a
 * "return", "goto" or "break" in the middle of the elevated-privilege code
 * skips past the privilege dropping call.
 *
 * The macro below uses variable cleanup to drop privileges as soon as the
 * code block is left in any way (and thus the _privs variable goes out of
 * scope.)  _once is just a trick to run the loop exactly once.
 */
extern struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
					   const char *funcname);
extern void _zprivs_lower(struct zebra_privs_t **privs);

#define frr_with_privs(privs)                                               \
	for (struct zebra_privs_t *_once = NULL,                               \
				  *_privs __attribute__(                       \
					  (unused, cleanup(_zprivs_lower))) =  \
					  _zprivs_raise(privs, __func__);      \
	     _once == NULL; _once = (void *)1)

#ifdef __cplusplus
}
#endif

#endif /* _ZEBRA_PRIVS_H */