]> code.delx.au - pulseaudio/blob - src/pulsecore/authkey.c
consolidate close() calls to pa_close(), and make sure on every occasion that we...
[pulseaudio] / src / pulsecore / authkey.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
8
9 PulseAudio is free software; you can redistribute it and/or modify
10 it under the terms of the GNU Lesser General Public License as
11 published by the Free Software Foundation; either version 2.1 of the
12 License, or (at your option) any later version.
13
14 PulseAudio is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public
20 License along with PulseAudio; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 USA.
23 ***/
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <stdio.h>
34 #include <inttypes.h>
35 #include <stdlib.h>
36 #include <time.h>
37 #include <limits.h>
38 #include <sys/stat.h>
39
40 #include <pulse/util.h>
41 #include <pulsecore/core-error.h>
42 #include <pulsecore/core-util.h>
43 #include <pulsecore/log.h>
44 #include <pulsecore/random.h>
45 #include <pulsecore/macro.h>
46
47 #include "authkey.h"
48
49 /* Generate a new authorization key, store it in file fd and return it in *data */
50 static int generate(int fd, void *ret_data, size_t length) {
51 ssize_t r;
52
53 pa_assert(fd >= 0);
54 pa_assert(ret_data);
55 pa_assert(length > 0);
56
57 pa_random(ret_data, length);
58
59 lseek(fd, 0, SEEK_SET);
60 (void) ftruncate(fd, 0);
61
62 if ((r = pa_loop_write(fd, ret_data, length, NULL)) < 0 || (size_t) r != length) {
63 pa_log("Failed to write cookie file: %s", pa_cstrerror(errno));
64 return -1;
65 }
66
67 return 0;
68 }
69
70 #ifndef O_BINARY
71 #define O_BINARY 0
72 #endif
73
74 /* Load an euthorization cookie from file fn and store it in data. If
75 * the cookie file doesn't exist, create it */
76 static int load(const char *fn, void *data, size_t length) {
77 int fd = -1;
78 int writable = 1;
79 int unlock = 0, ret = -1;
80 ssize_t r;
81
82 pa_assert(fn);
83 pa_assert(data);
84 pa_assert(length > 0);
85
86 if ((fd = open(fn, O_RDWR|O_CREAT|O_BINARY|O_NOCTTY, S_IRUSR|S_IWUSR)) < 0) {
87
88 if (errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY|O_NOCTTY)) < 0) {
89 pa_log("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("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 /* Load a cookie from a cookie file. If the file doesn't exist, create it. */
133 int pa_authkey_load(const char *path, void *data, size_t length) {
134 int ret;
135
136 pa_assert(path);
137 pa_assert(data);
138 pa_assert(length > 0);
139
140 if ((ret = load(path, data, length)) < 0)
141 pa_log("Failed to load authorization key '%s': %s", path, (ret < 0) ? pa_cstrerror(errno) : "File corrupt");
142
143 return ret;
144 }
145
146 /* If the specified file path starts with / return it, otherwise
147 * return path prepended with home directory */
148 static const char *normalize_path(const char *fn, char *s, size_t l) {
149
150 pa_assert(fn);
151 pa_assert(s);
152 pa_assert(l > 0);
153
154 #ifndef OS_IS_WIN32
155 if (fn[0] != '/') {
156 #else
157 if (strlen(fn) < 3 || !isalpha(fn[0]) || fn[1] != ':' || fn[2] != '\\') {
158 #endif
159 char homedir[PATH_MAX];
160
161 if (!pa_get_home_dir(homedir, sizeof(homedir)))
162 return NULL;
163
164 #ifndef OS_IS_WIN32
165 pa_snprintf(s, l, "%s/%s", homedir, fn);
166 #else
167 pa_snprintf(s, l, "%s\\%s", homedir, fn);
168 #endif
169 return s;
170 }
171
172 return fn;
173 }
174
175 /* Load a cookie from a file in the home directory. If the specified
176 * path starts with /, use it as absolute path instead. */
177 int pa_authkey_load_auto(const char *fn, void *data, size_t length) {
178 char path[PATH_MAX];
179 const char *p;
180
181 pa_assert(fn);
182 pa_assert(data);
183 pa_assert(length > 0);
184
185 if (!(p = normalize_path(fn, path, sizeof(path))))
186 return -2;
187
188 return pa_authkey_load(p, data, length);
189 }
190
191 /* Store the specified cookie in the speicified cookie file */
192 int pa_authkey_save(const char *fn, const void *data, size_t length) {
193 int fd = -1;
194 int unlock = 0, ret = -1;
195 ssize_t r;
196 char path[PATH_MAX];
197 const char *p;
198
199 pa_assert(fn);
200 pa_assert(data);
201 pa_assert(length > 0);
202
203 if (!(p = normalize_path(fn, path, sizeof(path))))
204 return -2;
205
206 if ((fd = open(p, O_RDWR|O_CREAT|O_NOCTTY, S_IRUSR|S_IWUSR)) < 0) {
207 pa_log("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 return ret;
234 }