Commit | Line | Data |
---|---|---|
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 |
35 | struct mkdir_data { |
36 | const char *path; | |
37 | mode_t mode; | |
38 | }; | |
39 | ||
40 | struct 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 | */ | |
49 | int 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 | */ |
66 | const 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 | 74 | static |
67f747d8 | 75 | int _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 | 127 | error: |
49a1d1ed | 128 | return ret; |
8e68d1c8 | 129 | } |
fedf5c6b MD |
130 | |
131 | static | |
67f747d8 MD |
132 | int _mkdir(void *_data) |
133 | { | |
134 | struct mkdir_data *data = _data; | |
135 | return mkdir(data->path, data->mode); | |
136 | } | |
137 | ||
138 | static | |
139 | int _open(void *_data) | |
140 | { | |
141 | struct open_data *data = _data; | |
142 | return open(data->path, data->flags, data->mode); | |
143 | } | |
144 | ||
145 | static | |
146 | int 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 | } | |
198 | end: | |
199 | return ret; | |
200 | } | |
201 | ||
67f747d8 | 202 | int 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 | ||
213 | int 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 | ||
224 | int 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 | } |