librarize run_as
[lttng-tools.git] / librunas / runas.c
CommitLineData
60b6c79c
MD
1/*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 * Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 *
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.
8 *
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.
13 *
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.
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>
25#include <sys/wait.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <unistd.h>
29#include <fcntl.h>
30
31#include <lttngerr.h>
32
33struct mkdir_data {
34 const char *path;
35 mode_t mode;
36};
37
38struct open_data {
39 const char *path;
40 int flags;
41 mode_t mode;
42};
43
44/*
45 * Create recursively directory using the FULL path.
46 */
47static
48int _mkdir_recursive(void *_data)
49{
50 struct mkdir_data *data = _data;
51 const char *path;
52 char *p, tmp[PATH_MAX];
53 struct stat statbuf;
54 mode_t mode;
55 size_t len;
56 int ret;
57
58 path = data->path;
59 mode = data->mode;
60
61 ret = snprintf(tmp, sizeof(tmp), "%s", path);
62 if (ret < 0) {
63 PERROR("snprintf mkdir");
64 goto error;
65 }
66
67 len = ret;
68 if (tmp[len - 1] == '/') {
69 tmp[len - 1] = 0;
70 }
71
72 for (p = tmp + 1; *p; p++) {
73 if (*p == '/') {
74 *p = 0;
75 ret = stat(tmp, &statbuf);
76 if (ret < 0) {
77 ret = mkdir(tmp, mode);
78 if (ret < 0) {
79 if (!(errno == EEXIST)) {
80 PERROR("mkdir recursive");
81 ret = -errno;
82 goto error;
83 }
84 }
85 }
86 *p = '/';
87 }
88 }
89
90 ret = mkdir(tmp, mode);
91 if (ret < 0) {
92 if (!(errno == EEXIST)) {
93 PERROR("mkdir recursive last piece");
94 ret = -errno;
95 } else {
96 ret = 0;
97 }
98 }
99
100error:
101 return ret;
102}
103
104static
105int _mkdir(void *_data)
106{
107 struct mkdir_data *data = _data;
108 return mkdir(data->path, data->mode);
109}
110
111static
112int _open(void *_data)
113{
114 struct open_data *data = _data;
115 return open(data->path, data->flags, data->mode);
116}
117
118static
119int run_as(int (*cmd)(void *data), void *data, uid_t uid, gid_t gid)
120{
121 int ret = 0;
122 pid_t pid;
123
124 /*
125 * If we are non-root, we can only deal with our own uid.
126 */
127 if (geteuid() != 0) {
128 if (uid != geteuid()) {
129 ERR("Client (%d)/Server (%d) UID mismatch (and sessiond is not root)",
130 uid, geteuid());
131 return -EPERM;
132 }
133 return (*cmd)(data);
134 }
135
136 pid = fork();
137 if (pid > 0) {
138 int status;
139
140 /*
141 * Parent: wait for child to return, in which case the
142 * shared memory map will have been created.
143 */
144 pid = wait(&status);
145 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
146 ret = -1;
147 goto end;
148 }
149 goto end;
150 } else if (pid == 0) {
151 /* Child */
152 setegid(gid);
153 if (ret < 0) {
154 perror("setegid");
155 exit(EXIT_FAILURE);
156 }
157 ret = seteuid(uid);
158 if (ret < 0) {
159 perror("seteuid");
160 exit(EXIT_FAILURE);
161 }
162 umask(0);
163 ret = (*cmd)(data);
164 if (!ret)
165 exit(EXIT_SUCCESS);
166 else
167 exit(EXIT_FAILURE);
168 } else {
169 return -1;
170 }
171end:
172 return ret;
173}
174
175int mkdir_recursive_run_as(const char *path, mode_t mode, uid_t uid, gid_t gid)
176{
177 struct mkdir_data data;
178
179 DBG3("mkdir() recursive %s with mode %d for uid %d and gid %d",
180 path, mode, uid, gid);
181 data.path = path;
182 data.mode = mode;
183 return run_as(_mkdir_recursive, &data, uid, gid);
184}
185
186int mkdir_run_as(const char *path, mode_t mode, uid_t uid, gid_t gid)
187{
188 struct mkdir_data data;
189
190 DBG3("mkdir() %s with mode %d for uid %d and gid %d",
191 path, mode, uid, gid);
192 data.path = path;
193 data.mode = mode;
194 return run_as(_mkdir, &data, uid, gid);
195}
196
197/*
198 * Note: open_run_as is currently not working. We'd need to pass the fd
199 * opened in the child to the parent.
200 */
201int open_run_as(const char *path, int flags, mode_t mode, uid_t uid, gid_t gid)
202{
203 //struct open_data data;
204 int fd, ret;
205
206 DBG3("open() %s with flags %d mode %d for uid %d and gid %d",
207 path, flags, mode, uid, gid);
208 fd = open(path, flags, mode);
209 if (fd < 0) {
210 perror("open");
211 return fd;
212 }
213 ret = fchown(fd, uid, gid);
214 if (ret < 0) {
215 perror("fchown");
216 close(fd);
217 return ret;
218 }
219 return fd;
220#if 0
221 data.path = path;
222 data.flags = flags;
223 data.mode = mode;
224 return run_as(_open, &data, uid, gid);
225#endif
226}
This page took 0.031532 seconds and 5 git commands to generate.