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