]> code.delx.au - pulseaudio/blob - src/pulsecore/authkey.c
auth: move cookie file to ~/.config/pulse/cookie
[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, pa_bool_t 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 ((fd = pa_open_cloexec(fn, (create ? O_RDWR|O_CREAT : O_RDONLY)|O_BINARY, S_IRUSR|S_IWUSR)) < 0) {
86
87 if (!create || errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY)) < 0) {
88 pa_log_warn("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno));
89 goto finish;
90 } else
91 writable = 0;
92 }
93
94 unlock = pa_lock_fd(fd, 1) >= 0;
95
96 if ((r = pa_loop_read(fd, data, length, NULL)) < 0) {
97 pa_log("Failed to read cookie file '%s': %s", fn, pa_cstrerror(errno));
98 goto finish;
99 }
100
101 if ((size_t) r != length) {
102 pa_log_debug("Got %d bytes from cookie file '%s', expected %d", (int) r, fn, (int) length);
103
104 if (!writable) {
105 pa_log_warn("Unable to write cookie to read-only file");
106 goto finish;
107 }
108
109 if (generate(fd, data, length) < 0)
110 goto finish;
111 }
112
113 ret = 0;
114
115 finish:
116
117 if (fd >= 0) {
118
119 if (unlock)
120 pa_lock_fd(fd, 0);
121
122 if (pa_close(fd) < 0) {
123 pa_log_warn("Failed to close cookie file: %s", pa_cstrerror(errno));
124 ret = -1;
125 }
126 }
127
128 return ret;
129 }
130
131 /* Load a cookie from a cookie file. If the file doesn't exist, create it. */
132 int pa_authkey_load(const char *path, pa_bool_t create, void *data, size_t length) {
133 int ret;
134
135 pa_assert(path);
136 pa_assert(data);
137 pa_assert(length > 0);
138
139 if ((ret = load(path, create, data, length)) < 0)
140 pa_log_warn("Failed to load authorization key '%s': %s", path, (ret < 0) ? pa_cstrerror(errno) : "File corrupt");
141
142 return ret;
143 }
144
145 /* If the specified file path starts with / return it, otherwise
146 * return path prepended with home directory */
147 static char *normalize_path(const char *fn) {
148
149 pa_assert(fn);
150
151 #ifndef OS_IS_WIN32
152 if (fn[0] != '/') {
153 #else
154 if (strlen(fn) < 3 || !IsCharAlpha(fn[0]) || fn[1] != ':' || fn[2] != '\\') {
155 #endif
156 char *homedir, *s;
157
158 if (!(homedir = pa_get_home_dir_malloc()))
159 return NULL;
160
161 s = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", homedir, fn);
162 pa_xfree(homedir);
163
164 return s;
165 }
166
167 return pa_xstrdup(fn);
168 }
169
170 /* Load a cookie from a file in the home directory. If the specified
171 * path starts with /, use it as absolute path instead. */
172 int pa_authkey_load_auto(const char *fn, pa_bool_t create, void *data, size_t length) {
173 char *p;
174 int ret;
175
176 pa_assert(fn);
177 pa_assert(data);
178 pa_assert(length > 0);
179
180 if (!(p = normalize_path(fn)))
181 return -2;
182
183 ret = pa_authkey_load(p, create, data, length);
184 pa_xfree(p);
185
186 return ret;
187 }
188
189 /* Store the specified cookie in the specified cookie file */
190 int pa_authkey_save(const char *fn, const void *data, size_t length) {
191 int fd = -1;
192 int unlock = 0, ret = -1;
193 ssize_t r;
194 char *p;
195
196 pa_assert(fn);
197 pa_assert(data);
198 pa_assert(length > 0);
199
200 if (!(p = normalize_path(fn)))
201 return -2;
202
203 if ((fd = pa_open_cloexec(p, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
204 pa_log_warn("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno));
205 goto finish;
206 }
207
208 unlock = pa_lock_fd(fd, 1) >= 0;
209
210 if ((r = pa_loop_write(fd, data, length, NULL)) < 0 || (size_t) r != length) {
211 pa_log("Failed to read cookie file '%s': %s", fn, pa_cstrerror(errno));
212 goto finish;
213 }
214
215 ret = 0;
216
217 finish:
218
219 if (fd >= 0) {
220
221 if (unlock)
222 pa_lock_fd(fd, 0);
223
224 if (pa_close(fd) < 0) {
225 pa_log_warn("Failed to close cookie file: %s", pa_cstrerror(errno));
226 ret = -1;
227 }
228 }
229
230 pa_xfree(p);
231
232 return ret;
233 }