]> code.delx.au - pulseaudio/blob - src/pulsecore/authkey.c
dbusiface-stream: Implement about a half of the Stream D-Bus interface.
[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 <inttypes.h>
33 #include <stdlib.h>
34 #include <time.h>
35 #include <limits.h>
36 #include <sys/stat.h>
37
38 #include <pulse/util.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>
44
45 #include "authkey.h"
46
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;
50
51 pa_assert(fd >= 0);
52 pa_assert(ret_data);
53 pa_assert(length > 0);
54
55 pa_random(ret_data, length);
56
57 lseek(fd, (off_t) 0, SEEK_SET);
58 (void) ftruncate(fd, (off_t) 0);
59
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;
63 }
64
65 return 0;
66 }
67
68 #ifndef O_BINARY
69 #define O_BINARY 0
70 #endif
71
72 #ifndef O_NOCTTY
73 #define O_NOCTTY 0
74 #endif
75
76 /* Load an euthorization cookie from file fn and store it in data. If
77 * the cookie file doesn't exist, create it */
78 static int load(const char *fn, void *data, size_t length) {
79 int fd = -1;
80 int writable = 1;
81 int unlock = 0, ret = -1;
82 ssize_t r;
83
84 pa_assert(fn);
85 pa_assert(data);
86 pa_assert(length > 0);
87
88 if ((fd = open(fn, O_RDWR|O_CREAT|O_BINARY|O_NOCTTY, S_IRUSR|S_IWUSR)) < 0) {
89
90 if (errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY|O_NOCTTY)) < 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, 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, 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 const char *normalize_path(const char *fn, char *s, size_t l) {
151
152 pa_assert(fn);
153 pa_assert(s);
154 pa_assert(l > 0);
155
156 #ifndef OS_IS_WIN32
157 if (fn[0] != '/') {
158 #else
159 if (strlen(fn) < 3 || !isalpha(fn[0]) || fn[1] != ':' || fn[2] != '\\') {
160 #endif
161 char homedir[PATH_MAX];
162
163 if (!pa_get_home_dir(homedir, sizeof(homedir)))
164 return NULL;
165
166 #ifndef OS_IS_WIN32
167 pa_snprintf(s, l, "%s/%s", homedir, fn);
168 #else
169 pa_snprintf(s, l, "%s\\%s", homedir, fn);
170 #endif
171 return s;
172 }
173
174 return fn;
175 }
176
177 /* Load a cookie from a file in the home directory. If the specified
178 * path starts with /, use it as absolute path instead. */
179 int pa_authkey_load_auto(const char *fn, void *data, size_t length) {
180 char path[PATH_MAX];
181 const char *p;
182
183 pa_assert(fn);
184 pa_assert(data);
185 pa_assert(length > 0);
186
187 if (!(p = normalize_path(fn, path, sizeof(path))))
188 return -2;
189
190 return pa_authkey_load(p, data, length);
191 }
192
193 /* Store the specified cookie in the specified cookie file */
194 int pa_authkey_save(const char *fn, const void *data, size_t length) {
195 int fd = -1;
196 int unlock = 0, ret = -1;
197 ssize_t r;
198 char path[PATH_MAX];
199 const char *p;
200
201 pa_assert(fn);
202 pa_assert(data);
203 pa_assert(length > 0);
204
205 if (!(p = normalize_path(fn, path, sizeof(path))))
206 return -2;
207
208 if ((fd = open(p, O_RDWR|O_CREAT|O_NOCTTY, S_IRUSR|S_IWUSR)) < 0) {
209 pa_log_warn("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno));
210 goto finish;
211 }
212
213 unlock = pa_lock_fd(fd, 1) >= 0;
214
215 if ((r = pa_loop_write(fd, data, length, NULL)) < 0 || (size_t) r != length) {
216 pa_log("Failed to read cookie file '%s': %s", fn, pa_cstrerror(errno));
217 goto finish;
218 }
219
220 ret = 0;
221
222 finish:
223
224 if (fd >= 0) {
225
226 if (unlock)
227 pa_lock_fd(fd, 0);
228
229 if (pa_close(fd) < 0) {
230 pa_log_warn("Failed to close cookie file: %s", pa_cstrerror(errno));
231 ret = -1;
232 }
233 }
234
235 return ret;
236 }