Add default-monitor-time-sec
[platform/upstream/pulseaudio.git] / src / pulsecore / authkey.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2004-2006 Lennart Poettering
5   Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7   PulseAudio is free software; you can redistribute it and/or modify
8   it under the terms of the GNU Lesser General Public License as
9   published by the Free Software Foundation; either version 2.1 of the
10   License, or (at your option) any later version.
11
12   PulseAudio is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   Lesser General Public License for more details.
16
17   You should have received a copy of the GNU Lesser General Public
18   License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <sys/stat.h>
32
33 #include <pulse/util.h>
34 #include <pulse/xmalloc.h>
35 #include <pulsecore/core-error.h>
36 #include <pulsecore/core-util.h>
37 #include <pulsecore/log.h>
38 #include <pulsecore/random.h>
39 #include <pulsecore/macro.h>
40
41 #include "authkey.h"
42
43 /* Generate a new authentication key, store it in file fd and return it in *data  */
44 static int generate(int fd, void *ret_data, size_t length) {
45     ssize_t r;
46
47     pa_assert(fd >= 0);
48     pa_assert(ret_data);
49     pa_assert(length > 0);
50
51     pa_random(ret_data, length);
52
53     lseek(fd, (off_t) 0, SEEK_SET);
54     if (ftruncate(fd, (off_t) 0) < 0) {
55         pa_log("Failed to truncate cookie file: %s", pa_cstrerror(errno));
56         return -1;
57     }
58
59     if ((r = pa_loop_write(fd, ret_data, length, NULL)) < 0 || (size_t) r != length) {
60         pa_log("Failed to write cookie file: %s", pa_cstrerror(errno));
61         return -1;
62     }
63
64     return 0;
65 }
66
67 #ifndef O_BINARY
68 #define O_BINARY 0
69 #endif
70
71 /* Load an authentication cookie from file fn and store it in data. If
72  * the cookie file doesn't exist, create it */
73 static int load(const char *fn, bool create, void *data, size_t length) {
74     int fd = -1;
75     int writable = 1;
76     int unlock = 0, ret = -1;
77     ssize_t r;
78
79     pa_assert(fn);
80     pa_assert(data);
81     pa_assert(length > 0);
82
83     if (create)
84         pa_make_secure_parent_dir(fn, pa_in_system_mode() ? 0755U : 0700U, -1, -1, false);
85
86     if ((fd = pa_open_cloexec(fn, (create ? O_RDWR|O_CREAT : O_RDONLY)|O_BINARY, S_IRUSR|S_IWUSR)) < 0) {
87
88         if (!create || errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY)) < 0) {
89             pa_log_warn("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno));
90             goto finish;
91         } else
92             writable = 0;
93     }
94
95     unlock = pa_lock_fd(fd, 1) >= 0;
96
97     if ((r = pa_loop_read(fd, data, length, NULL)) < 0) {
98         pa_log("Failed to read cookie file '%s': %s", fn, pa_cstrerror(errno));
99         goto finish;
100     }
101
102     if ((size_t) r != length) {
103         pa_log_debug("Got %d bytes from cookie file '%s', expected %d", (int) r, fn, (int) length);
104
105         if (!writable) {
106             pa_log_warn("Unable to write cookie to read-only file");
107             goto finish;
108         }
109
110         if (generate(fd, data, length) < 0)
111             goto finish;
112     }
113
114     ret = 0;
115
116 finish:
117
118     if (fd >= 0) {
119
120         if (unlock)
121             pa_lock_fd(fd, 0);
122
123         if (pa_close(fd) < 0) {
124             pa_log_warn("Failed to close cookie file: %s", pa_cstrerror(errno));
125             ret = -1;
126         }
127     }
128
129     return ret;
130 }
131
132 /* If the specified file path starts with / return it, otherwise
133  * return path prepended with the config home directory. */
134 static int normalize_path(const char *fn, char **_r) {
135     pa_assert(fn);
136     pa_assert(_r);
137
138     if (!pa_is_path_absolute(fn))
139         return pa_append_to_config_home_dir(fn, _r);
140
141     *_r = pa_xstrdup(fn);
142     return 0;
143 }
144
145 int pa_authkey_load(const char *fn, bool create, void *data, size_t length) {
146     char *p;
147     int ret;
148
149     pa_assert(fn);
150     pa_assert(data);
151     pa_assert(length > 0);
152
153     if ((ret = normalize_path(fn, &p)) < 0)
154         return ret;
155
156     if ((ret = load(p, create, data, length)) < 0)
157         pa_log_warn("Failed to load authentication key '%s': %s", p, (ret < 0) ? pa_cstrerror(errno) : "File corrupt");
158
159     pa_xfree(p);
160
161     return ret;
162 }
163
164 /* Store the specified cookie in the specified cookie file */
165 int pa_authkey_save(const char *fn, const void *data, size_t length) {
166     int fd = -1;
167     int unlock = 0, ret;
168     ssize_t r;
169     char *p;
170
171     pa_assert(fn);
172     pa_assert(data);
173     pa_assert(length > 0);
174
175     if ((ret = normalize_path(fn, &p)) < 0)
176         return ret;
177
178     if ((fd = pa_open_cloexec(p, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
179         pa_log_warn("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno));
180         ret = -1;
181         goto finish;
182     }
183
184     unlock = pa_lock_fd(fd, 1) >= 0;
185
186     if ((r = pa_loop_write(fd, data, length, NULL)) < 0 || (size_t) r != length) {
187         pa_log("Failed to read cookie file '%s': %s", fn, pa_cstrerror(errno));
188         ret = -1;
189         goto finish;
190     }
191
192 finish:
193
194     if (fd >= 0) {
195
196         if (unlock)
197             pa_lock_fd(fd, 0);
198
199         if (pa_close(fd) < 0) {
200             pa_log_warn("Failed to close cookie file: %s", pa_cstrerror(errno));
201             ret = -1;
202         }
203     }
204
205     pa_xfree(p);
206
207     return ret;
208 }