server: skip chown if not a super user
[platform/core/uifw/libtbm.git] / src / tbm_drm_helper_server.c
1 /**************************************************************************
2
3 libtbm
4
5 Copyright 2012 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: SooChan Lim <sc1.lim@samsung.com>, Sangjin Lee <lsj119@samsung.com>
8 Boram Park <boram1288.park@samsung.com>, Changyeon Lee <cyeon.lee@samsung.com>
9
10 Permission is hereby granted, free of charge, to any person obtaining a
11 copy of this software and associated documentation files (the
12 "Software"), to deal in the Software without restriction, including
13 without limitation the rights to use, copy, modify, merge, publish,
14 distribute, sub license, and/or sell copies of the Software, and to
15 permit persons to whom the Software is furnished to do so, subject to
16 the following conditions:
17
18 The above copyright notice and this permission notice (including the
19 next paragraph) shall be included in all copies or substantial portions
20 of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
25 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
30 **************************************************************************/
31
32 #define WL_HIDE_DEPRECATED
33
34 #include "config.h"
35
36 #include <xf86drm.h>
37 #include <grp.h>
38
39 #include "tbm_bufmgr_int.h"
40
41 #include "wayland-tbm-drm-auth-server-protocol.h"
42
43 struct wayland_tbm_drm_auth_server {
44         struct wl_display *display;
45         struct wl_global *wl_tbm_drm_auth_global;
46
47         char *device_name;
48         uint32_t fd;
49         uint32_t flags;
50 };
51
52 #define MIN(x, y) (((x) < (y)) ? (x) : (y))
53
54 struct wayland_tbm_drm_auth_server *tbm_drm_auth_srv;
55
56 /* LCOV_EXCL_START */
57 static void
58 _send_server_auth_info(struct wayland_tbm_drm_auth_server *tbm_drm_auth_srv,
59                        struct wl_resource *resource)
60 {
61         int fd = -1;
62         uint32_t capabilities;
63         char *device_name = NULL;
64         drm_magic_t magic = 0;
65
66         fd = open(tbm_drm_auth_srv->device_name, O_RDWR | O_CLOEXEC);
67         if (fd == -1 && errno == EINVAL) {
68                 fd = open(tbm_drm_auth_srv->device_name, O_RDWR);
69                 if (fd != -1)
70                         fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
71         }
72
73         if (fd < 0) {
74                 TBM_LOG_E("failed to open drm : device_name, %s\n", tbm_drm_auth_srv->device_name);
75
76                 wl_resource_post_error(resource, WL_TBM_DRM_AUTH_ERROR_AUTHENTICATE_FAIL,
77                                        "authenicate failed::open_drm");
78                 goto fini;
79         }
80
81         if (drmGetMagic(fd, &magic) < 0) {
82                 if (errno != EACCES) {
83                         TBM_LOG_E("failed to get magic\n");
84
85                         wl_resource_post_error(resource, WL_TBM_DRM_AUTH_ERROR_AUTHENTICATE_FAIL,
86                                                "authenicate failed::get_magic");
87                         goto fini;
88                 }
89         }
90
91         if (drmAuthMagic(tbm_drm_auth_srv->fd, magic) < 0) {
92                 TBM_LOG_E("failed to authenticate magic\n");
93
94                 wl_resource_post_error(resource, WL_TBM_DRM_AUTH_ERROR_AUTHENTICATE_FAIL,
95                                        "authenicate failed::auth_magic");
96                 goto fini;
97         }
98
99         capabilities = tbm_drm_auth_srv->flags;
100         device_name = tbm_drm_auth_srv->device_name;
101
102         /* send */
103         wl_tbm_drm_auth_send_authentication_info(resource, device_name, capabilities, fd);
104
105 fini:
106         if (fd >= 0)
107                 close(fd);
108
109         if (device_name && device_name != tbm_drm_auth_srv->device_name)
110                 free(device_name);
111
112 }
113
114 static void
115 _wayland_tbm_drm_auth_server_impl_get_authentication_info(struct wl_client *client,
116                 struct wl_resource *resource)
117 {
118         struct wayland_tbm_drm_auth_server *tbm_drm_auth_srv = wl_resource_get_user_data(resource);
119
120         /* if display server is the client of the host display server, for embedded server */
121         _send_server_auth_info(tbm_drm_auth_srv, resource);
122 }
123
124
125 static const struct wl_tbm_drm_auth_interface _wayland_tbm_drm_auth_server_implementation = {
126         _wayland_tbm_drm_auth_server_impl_get_authentication_info,
127 };
128
129 static void
130 _wayland_tbm_drm_auth_server_bind_cb(struct wl_client *client, void *data,
131                             uint32_t version,
132                             uint32_t id)
133 {
134         struct wl_resource *resource;
135
136         resource = wl_resource_create(client, &wl_tbm_drm_auth_interface, MIN(version, 1), id);
137         if (!resource) {
138                 wl_client_post_no_memory(client);
139                 return;
140         }
141
142         wl_resource_set_implementation(resource,
143                                        &_wayland_tbm_drm_auth_server_implementation,
144                                        data,
145                                        NULL);
146 }
147
148 static int
149 _tbm_getgrnam_r(const char *name)
150 {
151         struct group *grp = NULL;
152         struct group *grp_res = NULL;
153         char* buf = NULL;
154         size_t buf_len;
155         int ret;
156         int id;
157
158         buf_len = sysconf(_SC_GETGR_R_SIZE_MAX);
159         if (buf_len == -1)
160                 buf_len = 2048;
161
162         buf = calloc(1, buf_len * sizeof(char));
163         if (!buf) {
164                 TBM_LOG_E("creating buffer failed\n");
165                 goto failed;
166         }
167
168         grp = calloc(1, sizeof(struct group));
169         if (!grp) {
170                 TBM_LOG_E("creating group failed\n");
171                 goto failed;
172         }
173
174         ret = getgrnam_r(name, grp, buf, buf_len, &grp_res);
175         if (ret < 0) {
176                 TBM_LOG_E("getgrnam_r failed errno:%d(%m)\n", ret);
177                 goto failed;
178         }
179
180         if (grp_res == NULL) {
181                 TBM_LOG_E("finding name:%s group failed\n", name);
182                 goto failed;
183         }
184
185         id = grp->gr_gid;
186         free(buf);
187         free(grp);
188
189         return id;
190
191 failed:
192         if (buf)
193                 free(buf);
194         if (grp)
195                 free(grp);
196
197         return -1;
198 }
199
200 static int
201 _tbm_drm_auth_socket_init(struct wayland_tbm_drm_auth_server *tbm_drm_auth_srv)
202 {
203         const char *dir = NULL;
204         char socket_path[128];
205         int ret = -1;
206         uid_t uid;
207         gid_t gid;
208
209         if (wl_display_add_socket(tbm_drm_auth_srv->display, "tbm-drm-auth")) {
210                 TBM_LOG_E("createing a tdm-socket failed\n");
211                 return 0;
212         }
213
214         dir = getenv("XDG_RUNTIME_DIR");
215         if (!dir) {
216                 TBM_LOG_E("getting XDG_RUNTIME_DIR failed\n");
217                 return 0;
218         }
219
220         snprintf(socket_path, sizeof(socket_path), "%s/%s", dir, "tbm-drm-auth");
221
222         ret = chmod(socket_path, 509);
223         if (ret < 0) {
224                 TBM_LOG_E("changing modes of socket file failed:%s (%m)\n", socket_path);
225                 return 0;
226         }
227
228         /* if not super user, we don't need to change owner and group */
229         if (getuid() != 0)
230                 return 1;
231
232         ret = _tbm_getgrnam_r("root");
233         if (ret < 0) {
234                 TBM_LOG_E("getting uid failed\n");
235                 return 0;
236         }
237         uid = ret;
238
239         ret = _tbm_getgrnam_r("display");
240         if (ret < 0) {
241                 TBM_LOG_E("getting gid failed\n");
242                 return 0;
243         }
244         gid = ret;
245
246         ret = chown(socket_path, uid, gid);
247         if (ret < 0) {
248                 TBM_LOG_E("changing owner of socket file failed:%s (%m)\n", socket_path);
249                 return 0;
250         }
251
252         return 1;
253 }
254
255 int
256 tbm_drm_helper_wl_auth_server_init(void *wl_display,   int fd, const char *device_name, uint32_t flags)
257 {
258         if (!tbm_drm_auth_srv) {
259                 TBM_RETURN_VAL_IF_FAIL(wl_display != NULL, 0);
260
261                 tbm_drm_auth_srv = calloc(1, sizeof(struct wayland_tbm_drm_auth_server));
262                 TBM_RETURN_VAL_IF_FAIL(tbm_drm_auth_srv != NULL, 0);
263
264                 tbm_drm_auth_srv->display = (struct wl_display *)wl_display;
265                 tbm_drm_auth_srv->device_name = strdup(device_name);
266                 tbm_drm_auth_srv->fd = fd;
267                 tbm_drm_auth_srv->flags = flags;
268
269                 if (!_tbm_drm_auth_socket_init(tbm_drm_auth_srv)) {
270                         TBM_LOG_E("[TBM_DRM] fail to _tbm_drm_auth_socket_init\n");
271
272                         if (tbm_drm_auth_srv->device_name)
273                                 free(tbm_drm_auth_srv->device_name);
274
275                         free(tbm_drm_auth_srv);
276                         tbm_drm_auth_srv = NULL;
277
278                         return 0;
279                 }
280
281                 /* init the client resource list */
282                 tbm_drm_auth_srv->wl_tbm_drm_auth_global = wl_global_create(tbm_drm_auth_srv->display, &wl_tbm_drm_auth_interface, 1,
283                                          tbm_drm_auth_srv, _wayland_tbm_drm_auth_server_bind_cb);
284         }
285
286         return 1;
287 }
288
289 void
290 tbm_drm_helper_wl_auth_server_deinit(void)
291 {
292         if (tbm_drm_auth_srv) {
293                 wl_global_destroy(tbm_drm_auth_srv->wl_tbm_drm_auth_global);
294
295                 if (tbm_drm_auth_srv->device_name)
296                         free(tbm_drm_auth_srv->device_name);
297
298                 free(tbm_drm_auth_srv);
299                 tbm_drm_auth_srv = NULL;
300         }
301 }
302
303 int
304 tbm_drm_helper_get_master_fd(void)
305 {
306         const char *value;
307         int flags, fd = -1;
308         int new_fd = -1;
309         char *end;
310         errno = 0;
311
312         value = (const char*)getenv("TDM_DRM_MASTER_FD");
313         if (!value)
314                 return -1;
315
316         const long sl = strtol(value, &end, 10);
317         if (end == value) {
318                 TBM_LOG_E("%s: not a decimal number\n", value);
319                 return -1;
320         } else if (*end != '\0') {
321                 TBM_LOG_E("%s: extra characters at end of input: %s\n", value, end);
322                 return -1;
323         } else if ((sl == LONG_MIN || sl == LONG_MAX) && errno == ERANGE) {
324                 TBM_LOG_E("%s out of range of type long\n", value);
325                 return -1;
326         } else if (sl > INT_MAX) {
327                 TBM_LOG_E("%ld greater than INT_MAX\n", sl);
328                 return -1;
329         } else if (sl < INT_MIN) {
330                 TBM_LOG_E("%ld less than INT_MIN\n", sl);
331                 return -1;
332         } else {
333                 fd = (int)sl;
334                 if (fd < 0) {
335                         TBM_LOG_E("%d out of fd range\n", fd);
336                         return -1;
337                 }
338         }
339
340         TBM_LOG_I("TDM_DRM_MASTER_FD: %d\n", fd);
341
342         flags = fcntl(fd, F_GETFD);
343         if (flags == -1) {
344                 TBM_LOG_E("fcntl failed: %m");
345                 return -1;
346         }
347
348         new_fd = dup(fd);
349         if (new_fd < 0) {
350                 TBM_LOG_E("dup failed: %m");
351                 return -1;
352         }
353
354         fcntl(new_fd, F_SETFD, flags|FD_CLOEXEC);
355
356         TBM_LOG_I("Return MASTER_FD: %d\n", new_fd);
357
358         return new_fd;
359 }
360
361 void
362 tbm_drm_helper_set_tbm_master_fd(int fd)
363 {
364         char buf[32];
365         int ret;
366
367         snprintf(buf, sizeof(buf), "%d", fd);
368
369         ret = setenv("TBM_DRM_MASTER_FD", (const char*)buf, 1);
370         if (ret) {
371                 TBM_LOG_E("failed to set TIZEN_DRM_MASTER_FD to %d\n", fd);
372                 return;
373         }
374
375         TBM_LOG_I("TBM_DRM_MASTER_FD: %d\n", fd);
376 }
377
378 void
379 tbm_drm_helper_unset_tbm_master_fd(void)
380 {
381         int ret;
382
383         ret = unsetenv("TBM_DRM_MASTER_FD");
384         if (ret) {
385                 TBM_LOG_E("failed to unset TBM_DRM_MASTER_FD\n");
386                 return;
387         }
388 }
389 /* LCOV_EXCL_STOP */
390