Implement run_as wrappers for mkdir/mkdir_recursive/open
[lttng-tools.git] / lttng-sessiond / utils.c
CommitLineData
8e68d1c8 1/*
996b65c8 2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
1e307fab 3 * Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8e68d1c8 4 *
7272acf5
YB
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; only version 2 of the License.
8e68d1c8 8 *
7272acf5
YB
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
8e68d1c8 13 *
7272acf5
YB
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16 * Place - Suite 330, Boston, MA 02111-1307, USA.
8e68d1c8
DG
17 */
18
19#define _GNU_SOURCE
20#include <errno.h>
21#include <limits.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
fedf5c6b 25#include <sys/wait.h>
8e68d1c8
DG
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <unistd.h>
67f747d8 29#include <fcntl.h>
8e68d1c8 30
7272acf5
YB
31#include <lttngerr.h>
32
8e68d1c8
DG
33#include "utils.h"
34
67f747d8
MD
35struct mkdir_data {
36 const char *path;
37 mode_t mode;
38};
39
40struct open_data {
41 const char *path;
42 int flags;
43 mode_t mode;
44};
45
54d01ffb
DG
46/*
47 * Write to writable pipe used to notify a thread.
48 */
49int notify_thread_pipe(int wpipe)
50{
51 int ret;
52
53 ret = write(wpipe, "!", 1);
54 if (ret < 0) {
7272acf5 55 PERROR("write poll pipe");
54d01ffb
DG
56 }
57
58 return ret;
59}
60
b082db07 61/*
050349bb 62 * Return pointer to home directory path using the env variable HOME.
b082db07 63 *
050349bb 64 * No home, NULL is returned.
b082db07
DG
65 */
66const char *get_home_dir(void)
67{
68 return ((const char *) getenv("HOME"));
69}
70
71/*
050349bb 72 * Create recursively directory using the FULL path.
b082db07 73 */
fedf5c6b 74static
67f747d8 75int _mkdir_recursive(void *_data)
8e68d1c8 76{
67f747d8
MD
77 struct mkdir_data *data = _data;
78 const char *path;
49a1d1ed 79 char *p, tmp[PATH_MAX];
67f747d8
MD
80 struct stat statbuf;
81 mode_t mode;
49a1d1ed 82 size_t len;
67f747d8
MD
83 int ret;
84
85 path = data->path;
86 mode = data->mode;
8e68d1c8 87
49a1d1ed 88 ret = snprintf(tmp, sizeof(tmp), "%s", path);
8e68d1c8 89 if (ret < 0) {
7272acf5 90 PERROR("snprintf mkdir");
8e68d1c8
DG
91 goto error;
92 }
93
49a1d1ed
MD
94 len = ret;
95 if (tmp[len - 1] == '/') {
96 tmp[len - 1] = 0;
97 }
8e68d1c8 98
49a1d1ed
MD
99 for (p = tmp + 1; *p; p++) {
100 if (*p == '/') {
101 *p = 0;
67f747d8 102 ret = stat(tmp, &statbuf);
49a1d1ed 103 if (ret < 0) {
67f747d8
MD
104 ret = mkdir(tmp, mode);
105 if (ret < 0) {
106 if (!(errno == EEXIST)) {
107 PERROR("mkdir recursive");
108 ret = -errno;
109 goto error;
110 }
996b65c8 111 }
49a1d1ed
MD
112 }
113 *p = '/';
114 }
115 }
8e68d1c8 116
49a1d1ed 117 ret = mkdir(tmp, mode);
8e68d1c8 118 if (ret < 0) {
7272acf5
YB
119 if (!(errno == EEXIST)) {
120 PERROR("mkdir recursive last piece");
121 ret = -errno;
122 } else {
123 ret = 0;
124 }
8e68d1c8
DG
125 }
126
8e68d1c8 127error:
49a1d1ed 128 return ret;
8e68d1c8 129}
fedf5c6b
MD
130
131static
67f747d8
MD
132int _mkdir(void *_data)
133{
134 struct mkdir_data *data = _data;
135 return mkdir(data->path, data->mode);
136}
137
138static
139int _open(void *_data)
140{
141 struct open_data *data = _data;
142 return open(data->path, data->flags, data->mode);
143}
144
145static
146int run_as(int (*cmd)(void *data), void *data, uid_t uid, gid_t gid)
fedf5c6b
MD
147{
148 int ret = 0;
149 pid_t pid;
150
151 /*
152 * If we are non-root, we can only deal with our own uid.
153 */
154 if (geteuid() != 0) {
155 if (uid != geteuid()) {
156 ERR("Client (%d)/Server (%d) UID mismatch (and sessiond is not root)",
157 uid, geteuid());
158 return -EPERM;
159 }
67f747d8 160 return (*cmd)(data);
fedf5c6b
MD
161 }
162
163 pid = fork();
164 if (pid > 0) {
165 int status;
166
167 /*
168 * Parent: wait for child to return, in which case the
169 * shared memory map will have been created.
170 */
171 pid = wait(&status);
172 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
173 ret = -1;
174 goto end;
175 }
176 goto end;
177 } else if (pid == 0) {
178 /* Child */
179 setegid(gid);
180 if (ret < 0) {
181 perror("setegid");
182 exit(EXIT_FAILURE);
183 }
184 ret = seteuid(uid);
185 if (ret < 0) {
186 perror("seteuid");
187 exit(EXIT_FAILURE);
188 }
67f747d8
MD
189 umask(0);
190 ret = (*cmd)(data);
fedf5c6b
MD
191 if (!ret)
192 exit(EXIT_SUCCESS);
193 else
194 exit(EXIT_FAILURE);
195 } else {
196 return -1;
197 }
198end:
199 return ret;
200}
201
67f747d8 202int mkdir_recursive_run_as(const char *path, mode_t mode, uid_t uid, gid_t gid)
fedf5c6b 203{
67f747d8
MD
204 struct mkdir_data data;
205
fedf5c6b
MD
206 DBG3("mkdir() recursive %s with mode %d for uid %d and gid %d",
207 path, mode, uid, gid);
67f747d8
MD
208 data.path = path;
209 data.mode = mode;
210 return run_as(_mkdir_recursive, &data, uid, gid);
211}
212
213int mkdir_run_as(const char *path, mode_t mode, uid_t uid, gid_t gid)
214{
215 struct mkdir_data data;
216
217 DBG3("mkdir() %s with mode %d for uid %d and gid %d",
218 path, mode, uid, gid);
219 data.path = path;
220 data.mode = mode;
221 return run_as(_mkdir, &data, uid, gid);
222}
223
224int open_run_as(const char *path, int flags, mode_t mode, uid_t uid, gid_t gid)
225{
226 struct open_data data;
227
228 DBG3("open() %s with flags %d mode %d for uid %d and gid %d",
229 path, flags, mode, uid, gid);
230 data.path = path;
231 data.flags = flags;
232 data.mode = mode;
233 return run_as(_open, &data, uid, gid);
fedf5c6b 234}
This page took 0.034536 seconds and 4 git commands to generate.