]> code.delx.au - pulseaudio/blob - src/pulsecore/authkey.c
remap: Change remapping function argument type from void to int16_t / float as approp...
[pulseaudio] / 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, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <sys/stat.h>
34
35 #include <pulse/util.h>
36 #include <pulse/xmalloc.h>
37 #include <pulsecore/core-error.h>
38 #include <pulsecore/core-util.h>
39 #include <pulsecore/log.h>
40 #include <pulsecore/random.h>
41 #include <pulsecore/macro.h>
42
43 #include "authkey.h"
44
45 /* Generate a new authorization key, store it in file fd and return it in *data */
46 static int generate(int fd, void *ret_data, size_t length) {
47 ssize_t r;
48
49 pa_assert(fd >= 0);
50 pa_assert(ret_data);
51 pa_assert(length > 0);
52
53 pa_random(ret_data, length);
54
55 lseek(fd, (off_t) 0, SEEK_SET);
56 if (ftruncate(fd, (off_t) 0) < 0) {
57 pa_log("Failed to truncate cookie file: %s", pa_cstrerror(errno));
58 return -1;
59 }
60
61 if ((r = pa_loop_write(fd, ret_data, length, NULL)) < 0 || (size_t) r != length) {
62 pa_log("Failed to write cookie file: %s", pa_cstrerror(errno));
63 return -1;
64 }
65
66 return 0;
67 }
68
69 #ifndef O_BINARY
70 #define O_BINARY 0
71 #endif
72
73 /* Load an authorization cookie from file fn and store it in data. If
74 * the cookie file doesn't exist, create it */
75 static int load(const char *fn, bool create, void *data, size_t length) {
76 int fd = -1;
77 int writable = 1;
78 int unlock = 0, ret = -1;
79 ssize_t r;
80
81 pa_assert(fn);
82 pa_assert(data);
83 pa_assert(length > 0);
84
85 if (create)
86 pa_make_secure_parent_dir(fn, pa_in_system_mode() ? 0755U : 0700U, -1, -1, false);
87
88 if ((fd = pa_open_cloexec(fn, (create ? O_RDWR|O_CREAT : O_RDONLY)|O_BINARY, S_IRUSR|S_IWUSR)) < 0) {
89
90 if (!create || errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY)) < 0) {
91 pa_log_warn("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno));
92 goto finish;
93 } else
94 writable = 0;
95 }
96
97 unlock = pa_lock_fd(fd, 1) >= 0;
98
99 if ((r = pa_loop_read(fd, data, length, NULL)) < 0) {
100 pa_log("Failed to read cookie file '%s': %s", fn, pa_cstrerror(errno));
101 goto finish;
102 }
103
104 if ((size_t) r != length) {
105 pa_log_debug("Got %d bytes from cookie file '%s', expected %d", (int) r, fn, (int) length);
106
107 if (!writable) {
108 pa_log_warn("Unable to write cookie to read-only file");
109 goto finish;
110 }
111
112 if (generate(fd, data, length) < 0)
113 goto finish;
114 }
115
116 ret = 0;
117
118 finish:
119
120 if (fd >= 0) {
121
122 if (unlock)
123 pa_lock_fd(fd, 0);
124
125 if (pa_close(fd) < 0) {
126 pa_log_warn("Failed to close cookie file: %s", pa_cstrerror(errno));
127 ret = -1;
128 }
129 }
130
131 return ret;
132 }
133
134 /* Load a cookie from a cookie file. If the file doesn't exist, create it. */
135 int pa_authkey_load(const char *path, bool create, void *data, size_t length) {
136 int ret;
137
138 pa_assert(path);
139 pa_assert(data);
140 pa_assert(length > 0);
141
142 if ((ret = load(path, create, data, length)) < 0)
143 pa_log_warn("Failed to load authorization key '%s': %s", path, (ret < 0) ? pa_cstrerror(errno) : "File corrupt");
144
145 return ret;
146 }
147
148 /* If the specified file path starts with / return it, otherwise
149 * return path prepended with home directory */
150 static char *normalize_path(const char *fn) {
151
152 pa_assert(fn);
153
154 #ifndef OS_IS_WIN32
155 if (fn[0] != '/') {
156 #else
157 if (strlen(fn) < 3 || !IsCharAlpha(fn[0]) || fn[1] != ':' || fn[2] != '\\') {
158 #endif
159 char *homedir, *s;
160
161 if (!(homedir = pa_get_home_dir_malloc()))
162 return NULL;
163
164 s = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", homedir, fn);
165 pa_xfree(homedir);
166
167 return s;
168 }
169
170 return pa_xstrdup(fn);
171 }
172
173 /* Load a cookie from a file in the home directory. If the specified
174 * path starts with /, use it as absolute path instead. */
175 int pa_authkey_load_auto(const char *fn, bool create, void *data, size_t length) {
176 char *p;
177 int ret;
178
179 pa_assert(fn);
180 pa_assert(data);
181 pa_assert(length > 0);
182
183 if (!(p = normalize_path(fn)))
184 return -2;
185
186 ret = pa_authkey_load(p, create, data, length);
187 pa_xfree(p);
188
189 return ret;
190 }
191
192 /* Store the specified cookie in the specified cookie file */
193 int pa_authkey_save(const char *fn, const void *data, size_t length) {
194 int fd = -1;
195 int unlock = 0, ret = -1;
196 ssize_t r;
197 char *p;
198
199 pa_assert(fn);
200 pa_assert(data);
201 pa_assert(length > 0);
202
203 if (!(p = normalize_path(fn)))
204 return -2;
205
206 if ((fd = pa_open_cloexec(p, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
207 pa_log_warn("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno));
208 goto finish;
209 }
210
211 unlock = pa_lock_fd(fd, 1) >= 0;
212
213 if ((r = pa_loop_write(fd, data, length, NULL)) < 0 || (size_t) r != length) {
214 pa_log("Failed to read cookie file '%s': %s", fn, pa_cstrerror(errno));
215 goto finish;
216 }
217
218 ret = 0;
219
220 finish:
221
222 if (fd >= 0) {
223
224 if (unlock)
225 pa_lock_fd(fd, 0);
226
227 if (pa_close(fd) < 0) {
228 pa_log_warn("Failed to close cookie file: %s", pa_cstrerror(errno));
229 ret = -1;
230 }
231 }
232
233 pa_xfree(p);
234
235 return ret;
236 }