]> code.delx.au - pulseaudio/blob - src/pulsecore/authkey.c
64 bit fixes and minor gcc shut ups
[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 close(fd);
124 }
125
126 return ret;
127 }
128
129 /* Load a cookie from a cookie file. If the file doesn't exist, create it. */
130 int pa_authkey_load(const char *path, void *data, size_t length) {
131 int ret;
132
133 pa_assert(path);
134 pa_assert(data);
135 pa_assert(length > 0);
136
137 if ((ret = load(path, data, length)) < 0)
138 pa_log("Failed to load authorization key '%s': %s", path, (ret < 0) ? pa_cstrerror(errno) : "File corrupt");
139
140 return ret;
141 }
142
143 /* If the specified file path starts with / return it, otherwise
144 * return path prepended with home directory */
145 static const char *normalize_path(const char *fn, char *s, size_t l) {
146
147 pa_assert(fn);
148 pa_assert(s);
149 pa_assert(l > 0);
150
151 #ifndef OS_IS_WIN32
152 if (fn[0] != '/') {
153 #else
154 if (strlen(fn) < 3 || !isalpha(fn[0]) || fn[1] != ':' || fn[2] != '\\') {
155 #endif
156 char homedir[PATH_MAX];
157
158 if (!pa_get_home_dir(homedir, sizeof(homedir)))
159 return NULL;
160
161 #ifndef OS_IS_WIN32
162 pa_snprintf(s, l, "%s/%s", homedir, fn);
163 #else
164 pa_snprintf(s, l, "%s\\%s", homedir, fn);
165 #endif
166 return s;
167 }
168
169 return fn;
170 }
171
172 /* Load a cookie from a file in the home directory. If the specified
173 * path starts with /, use it as absolute path instead. */
174 int pa_authkey_load_auto(const char *fn, void *data, size_t length) {
175 char path[PATH_MAX];
176 const char *p;
177
178 pa_assert(fn);
179 pa_assert(data);
180 pa_assert(length > 0);
181
182 if (!(p = normalize_path(fn, path, sizeof(path))))
183 return -2;
184
185 return pa_authkey_load(p, data, length);
186 }
187
188 /* Store the specified cookie in the speicified 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 path[PATH_MAX];
194 const char *p;
195
196 pa_assert(fn);
197 pa_assert(data);
198 pa_assert(length > 0);
199
200 if (!(p = normalize_path(fn, path, sizeof(path))))
201 return -2;
202
203 if ((fd = open(p, O_RDWR|O_CREAT|O_NOCTTY, S_IRUSR|S_IWUSR)) < 0) {
204 pa_log("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 close(fd);
225 }
226
227 return ret;
228 }