]> code.delx.au - pulseaudio/blob - src/pulsecore/authkey.c
a6150d0e0a5d7280c629581e68480c5847a65a2a
[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 <assert.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <stdio.h>
35 #include <inttypes.h>
36 #include <stdlib.h>
37 #include <time.h>
38 #include <limits.h>
39 #include <sys/stat.h>
40
41 #include <pulse/util.h>
42 #include <pulsecore/core-error.h>
43 #include <pulsecore/core-util.h>
44 #include <pulsecore/log.h>
45 #include <pulsecore/random.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 assert(fd >= 0 && ret_data && length);
53
54 pa_random(ret_data, length);
55
56 lseek(fd, 0, SEEK_SET);
57 ftruncate(fd, 0);
58
59 if ((r = pa_loop_write(fd, ret_data, length, NULL)) < 0 || (size_t) r != length) {
60 pa_log("failed to write cookie file: %s", pa_cstrerror(errno));
61 return -1;
62 }
63
64 return 0;
65 }
66
67 #ifndef O_BINARY
68 #define O_BINARY 0
69 #endif
70
71 /* Load an euthorization cookie from file fn and store it in data. If
72 * the cookie file doesn't exist, create it */
73 static int load(const char *fn, void *data, size_t length) {
74 int fd = -1;
75 int writable = 1;
76 int unlock = 0, ret = -1;
77 ssize_t r;
78 assert(fn && data && length);
79
80 if ((fd = open(fn, O_RDWR|O_CREAT|O_BINARY, S_IRUSR|S_IWUSR)) < 0) {
81 if (errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY)) < 0) {
82 pa_log("failed to open cookie file '%s': %s", fn, pa_cstrerror(errno));
83 goto finish;
84 } else
85 writable = 0;
86 }
87
88 unlock = pa_lock_fd(fd, 1) >= 0;
89
90 if ((r = pa_loop_read(fd, data, length, NULL)) < 0) {
91 pa_log("failed to read cookie file '%s': %s", fn, pa_cstrerror(errno));
92 goto finish;
93 }
94
95 if ((size_t) r != length) {
96 pa_log_debug("got %d bytes from cookie file '%s', expected %d", (int)r, fn, (int)length);
97
98 if (!writable) {
99 pa_log("unable to write cookie to read only file");
100 goto finish;
101 }
102
103 if (generate(fd, data, length) < 0)
104 goto finish;
105 }
106
107 ret = 0;
108
109 finish:
110
111 if (fd >= 0) {
112
113 if (unlock)
114 pa_lock_fd(fd, 0);
115
116 close(fd);
117 }
118
119 return ret;
120 }
121
122 /* Load a cookie from a cookie file. If the file doesn't exist, create it. */
123 int pa_authkey_load(const char *path, void *data, size_t length) {
124 int ret;
125
126 assert(path && data && length);
127
128 ret = load(path, data, length);
129
130 if (ret < 0)
131 pa_log("Failed to load authorization key '%s': %s", path,
132 (ret == -1) ? pa_cstrerror(errno) : "file corrupt");
133
134 return ret;
135 }
136
137 /* If the specified file path starts with / return it, otherwise
138 * return path prepended with home directory */
139 static const char *normalize_path(const char *fn, char *s, size_t l) {
140 assert(fn && s && l > 0);
141
142 #ifndef OS_IS_WIN32
143 if (fn[0] != '/') {
144 #else
145 if (strlen(fn) < 3 || !isalpha(fn[0]) || fn[1] != ':' || fn[2] != '\\') {
146 #endif
147 char homedir[PATH_MAX];
148 if (!pa_get_home_dir(homedir, sizeof(homedir)))
149 return NULL;
150
151 #ifndef OS_IS_WIN32
152 snprintf(s, l, "%s/%s", homedir, fn);
153 #else
154 snprintf(s, l, "%s\\%s", homedir, fn);
155 #endif
156 return s;
157 }
158
159 return fn;
160 }
161
162 /* Load a cookie from a file in the home directory. If the specified
163 * path starts with /, use it as absolute path instead. */
164 int pa_authkey_load_auto(const char *fn, void *data, size_t length) {
165 char path[PATH_MAX];
166 const char *p;
167 assert(fn && data && length);
168
169 if (!(p = normalize_path(fn, path, sizeof(path))))
170 return -2;
171
172 return pa_authkey_load(p, data, length);
173 }
174
175 /* Store the specified cookie in the speicified cookie file */
176 int pa_authkey_save(const char *fn, const void *data, size_t length) {
177 int fd = -1;
178 int unlock = 0, ret = -1;
179 ssize_t r;
180 char path[PATH_MAX];
181 const char *p;
182 assert(fn && data && length);
183
184 if (!(p = normalize_path(fn, path, sizeof(path))))
185 return -2;
186
187 if ((fd = open(p, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
188 pa_log("failed to open cookie file '%s': %s", fn, pa_cstrerror(errno));
189 goto finish;
190 }
191
192 unlock = pa_lock_fd(fd, 1) >= 0;
193
194 if ((r = pa_loop_write(fd, data, length, NULL)) < 0 || (size_t) r != length) {
195 pa_log("failed to read cookie file '%s': %s", fn, pa_cstrerror(errno));
196 goto finish;
197 }
198
199 ret = 0;
200
201 finish:
202
203 if (fd >= 0) {
204
205 if (unlock)
206 pa_lock_fd(fd, 0);
207
208 close(fd);
209 }
210
211 return ret;
212 }