virtual-sink: Fix a crash when moving the sink to a new master right after setup.
[pulseaudio-raopUDP/pulseaudio-raop-alac.git] / src / pulsecore / authkey.c
blob92509d89a0984e6f60478edfe1b3774df50ec42d
1 /***
2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
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.
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.
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 ***/
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <inttypes.h>
33 #include <stdlib.h>
34 #include <limits.h>
35 #include <sys/stat.h>
37 #include <pulse/util.h>
38 #include <pulse/xmalloc.h>
39 #include <pulsecore/core-error.h>
40 #include <pulsecore/core-util.h>
41 #include <pulsecore/log.h>
42 #include <pulsecore/random.h>
43 #include <pulsecore/macro.h>
45 #include "authkey.h"
47 /* Generate a new authorization key, store it in file fd and return it in *data */
48 static int generate(int fd, void *ret_data, size_t length) {
49 ssize_t r;
51 pa_assert(fd >= 0);
52 pa_assert(ret_data);
53 pa_assert(length > 0);
55 pa_random(ret_data, length);
57 lseek(fd, (off_t) 0, SEEK_SET);
58 (void) ftruncate(fd, (off_t) 0);
60 if ((r = pa_loop_write(fd, ret_data, length, NULL)) < 0 || (size_t) r != length) {
61 pa_log("Failed to write cookie file: %s", pa_cstrerror(errno));
62 return -1;
65 return 0;
68 #ifndef O_BINARY
69 #define O_BINARY 0
70 #endif
72 /* Load an euthorization cookie from file fn and store it in data. If
73 * the cookie file doesn't exist, create it */
74 static int load(const char *fn, void *data, size_t length) {
75 int fd = -1;
76 int writable = 1;
77 int unlock = 0, ret = -1;
78 ssize_t r;
80 pa_assert(fn);
81 pa_assert(data);
82 pa_assert(length > 0);
84 if ((fd = pa_open_cloexec(fn, O_RDWR|O_CREAT|O_BINARY, S_IRUSR|S_IWUSR)) < 0) {
86 if (errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY)) < 0) {
87 pa_log_warn("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno));
88 goto finish;
89 } else
90 writable = 0;
93 unlock = pa_lock_fd(fd, 1) >= 0;
95 if ((r = pa_loop_read(fd, data, length, NULL)) < 0) {
96 pa_log("Failed to read cookie file '%s': %s", fn, pa_cstrerror(errno));
97 goto finish;
100 if ((size_t) r != length) {
101 pa_log_debug("Got %d bytes from cookie file '%s', expected %d", (int) r, fn, (int) length);
103 if (!writable) {
104 pa_log_warn("Unable to write cookie to read-only file");
105 goto finish;
108 if (generate(fd, data, length) < 0)
109 goto finish;
112 ret = 0;
114 finish:
116 if (fd >= 0) {
118 if (unlock)
119 pa_lock_fd(fd, 0);
121 if (pa_close(fd) < 0) {
122 pa_log_warn("Failed to close cookie file: %s", pa_cstrerror(errno));
123 ret = -1;
127 return ret;
130 /* Load a cookie from a cookie file. If the file doesn't exist, create it. */
131 int pa_authkey_load(const char *path, void *data, size_t length) {
132 int ret;
134 pa_assert(path);
135 pa_assert(data);
136 pa_assert(length > 0);
138 if ((ret = load(path, data, length)) < 0)
139 pa_log_warn("Failed to load authorization key '%s': %s", path, (ret < 0) ? pa_cstrerror(errno) : "File corrupt");
141 return ret;
144 /* If the specified file path starts with / return it, otherwise
145 * return path prepended with home directory */
146 static char *normalize_path(const char *fn) {
148 pa_assert(fn);
150 #ifndef OS_IS_WIN32
151 if (fn[0] != '/') {
152 #else
153 if (strlen(fn) < 3 || !IsCharAlpha(fn[0]) || fn[1] != ':' || fn[2] != '\\') {
154 #endif
155 char *homedir, *s;
157 if (!(homedir = pa_get_home_dir_malloc()))
158 return NULL;
160 s = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", homedir, fn);
161 pa_xfree(homedir);
163 return s;
166 return pa_xstrdup(fn);
169 /* Load a cookie from a file in the home directory. If the specified
170 * path starts with /, use it as absolute path instead. */
171 int pa_authkey_load_auto(const char *fn, void *data, size_t length) {
172 char *p;
173 int ret;
175 pa_assert(fn);
176 pa_assert(data);
177 pa_assert(length > 0);
179 if (!(p = normalize_path(fn)))
180 return -2;
182 ret = pa_authkey_load(p, data, length);
183 pa_xfree(p);
185 return ret;
188 /* Store the specified cookie in the specified cookie file */
189 int pa_authkey_save(const char *fn, const void *data, size_t length) {
190 int fd = -1;
191 int unlock = 0, ret = -1;
192 ssize_t r;
193 char *p;
195 pa_assert(fn);
196 pa_assert(data);
197 pa_assert(length > 0);
199 if (!(p = normalize_path(fn)))
200 return -2;
202 if ((fd = pa_open_cloexec(p, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
203 pa_log_warn("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno));
204 goto finish;
207 unlock = pa_lock_fd(fd, 1) >= 0;
209 if ((r = pa_loop_write(fd, data, length, NULL)) < 0 || (size_t) r != length) {
210 pa_log("Failed to read cookie file '%s': %s", fn, pa_cstrerror(errno));
211 goto finish;
214 ret = 0;
216 finish:
218 if (fd >= 0) {
220 if (unlock)
221 pa_lock_fd(fd, 0);
223 if (pa_close(fd) < 0) {
224 pa_log_warn("Failed to close cookie file: %s", pa_cstrerror(errno));
225 ret = -1;
229 pa_xfree(p);
231 return ret;