File: | obj-scan-build/trans/../../trans/fakeroot.c |
Location: | line 425, column 5 |
Description: | Use of memory after it is freed |
1 | /* fakeroot -- a translator for faking actions that aren't really permitted | |||
2 | Copyright (C) 2002, 2003, 2008, 2013 Free Software Foundation, Inc. | |||
3 | ||||
4 | This program is free software; you can redistribute it and/or | |||
5 | modify it under the terms of the GNU General Public License as | |||
6 | published by the Free Software Foundation; either version 2, or (at | |||
7 | your option) any later version. | |||
8 | ||||
9 | This program is distributed in the hope that it will be useful, but | |||
10 | WITHOUT ANY WARRANTY; without even the implied warranty of | |||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
12 | General Public License for more details. | |||
13 | ||||
14 | You should have received a copy of the GNU General Public License | |||
15 | along with this program; if not, write to the Free Software | |||
16 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ | |||
17 | ||||
18 | #include <hurd/netfs.h> | |||
19 | #include <stddef.h> | |||
20 | #include <stdio.h> | |||
21 | #include <stdlib.h> | |||
22 | #include <argp.h> | |||
23 | #include <error.h> | |||
24 | #include <string.h> | |||
25 | #include <fcntl.h> | |||
26 | #include <sys/mman.h> | |||
27 | #include <sys/stat.h> | |||
28 | #include <pthread.h> | |||
29 | #include <hurd/ihash.h> | |||
30 | #include <hurd/paths.h> | |||
31 | ||||
32 | #include <version.h> | |||
33 | ||||
34 | #include "libnetfs/fs_S.h" | |||
35 | #include "libnetfs/io_S.h" | |||
36 | #include "libnetfs/fsys_S.h" | |||
37 | #include "libports/notify_S.h" | |||
38 | #include "libports/interrupt_S.h" | |||
39 | ||||
40 | const char *argp_program_version = STANDARD_HURD_VERSION (fakeroot)"fakeroot" " (GNU Hurd) " "0.5"; | |||
41 | ||||
42 | char *netfs_server_name = "fakeroot"; | |||
43 | char *netfs_server_version = HURD_VERSION"0.5"; | |||
44 | int netfs_maxsymlinks = 16; /* arbitrary */ | |||
45 | ||||
46 | static auth_t fakeroot_auth_port; | |||
47 | ||||
48 | struct netnode | |||
49 | { | |||
50 | hurd_ihash_locp_t idport_locp;/* easy removal pointer in idport ihash */ | |||
51 | mach_port_t idport; /* port from io_identity */ | |||
52 | int openmodes; /* O_READ | O_WRITE | O_EXEC */ | |||
53 | file_t file; /* port on real file */ | |||
54 | ||||
55 | unsigned int faked; | |||
56 | }; | |||
57 | ||||
58 | #define FAKE_UID(1 << 0) (1 << 0) | |||
59 | #define FAKE_GID(1 << 1) (1 << 1) | |||
60 | #define FAKE_AUTHOR(1 << 2) (1 << 2) | |||
61 | #define FAKE_MODE(1 << 3) (1 << 3) | |||
62 | #define FAKE_DEFAULT(1 << 4) (1 << 4) | |||
63 | ||||
64 | pthread_mutex_t idport_ihash_lock = PTHREAD_MUTEX_INITIALIZER{ ((__pthread_spinlock_t) 0), ((__pthread_spinlock_t) 0), 0, 0 , 0, 0, 0, 0 }; | |||
65 | struct hurd_ihash idport_ihash | |||
66 | = HURD_IHASH_INITIALIZER (sizeof (struct node){ .nr_items = 0, .size = 0, .cleanup = (hurd_ihash_cleanup_t) 0, .max_load = 96, .locp_offset = (sizeof (struct node) + __builtin_offsetof (struct netnode, idport_locp))} | |||
67 | + offsetof (struct netnode, idport_locp)){ .nr_items = 0, .size = 0, .cleanup = (hurd_ihash_cleanup_t) 0, .max_load = 96, .locp_offset = (sizeof (struct node) + __builtin_offsetof (struct netnode, idport_locp))}; | |||
68 | ||||
69 | ||||
70 | /* Make a new virtual node. Always consumes the ports. If | |||
71 | successful, NP will be locked. */ | |||
72 | static error_t | |||
73 | new_node (file_t file, mach_port_t idport, int locked, int openmodes, | |||
74 | struct node **np) | |||
75 | { | |||
76 | error_t err; | |||
77 | struct netnode *nn; | |||
78 | *np = netfs_make_node_alloc (sizeof *nn); | |||
79 | if (*np == 0) | |||
80 | { | |||
81 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), file); | |||
82 | if (idport != MACH_PORT_NULL((mach_port_t) 0)) | |||
83 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), idport); | |||
84 | if (locked) | |||
85 | pthread_mutex_unlock (&idport_ihash_lock); | |||
86 | return ENOMEM((0x10 << 26) | ((12) & 0x3fff)); | |||
87 | } | |||
88 | nn = netfs_node_netnode (*np); | |||
89 | nn->file = file; | |||
90 | nn->openmodes = openmodes; | |||
91 | if (idport != MACH_PORT_NULL((mach_port_t) 0)) | |||
92 | nn->idport = idport; | |||
93 | else | |||
94 | { | |||
95 | ino_t fileno; | |||
96 | mach_port_t fsidport; | |||
97 | assert (!locked)((!locked) ? (void) (0) : __assert_fail ("!locked", "../../trans/fakeroot.c" , 97, __PRETTY_FUNCTION__)); | |||
98 | err = io_identity (file, &nn->idport, &fsidport, &fileno); | |||
99 | if (err) | |||
100 | { | |||
101 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), file); | |||
102 | free (*np); | |||
103 | return err; | |||
104 | } | |||
105 | } | |||
106 | ||||
107 | if (!locked) | |||
108 | pthread_mutex_lock (&idport_ihash_lock); | |||
109 | err = hurd_ihash_add (&idport_ihash, nn->idport, *np); | |||
110 | if (err) | |||
111 | goto lose; | |||
112 | ||||
113 | pthread_mutex_lock (&(*np)->lock); | |||
114 | pthread_mutex_unlock (&idport_ihash_lock); | |||
115 | return 0; | |||
116 | ||||
117 | lose: | |||
118 | pthread_mutex_unlock (&idport_ihash_lock); | |||
119 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), nn->idport); | |||
120 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), file); | |||
121 | free (*np); | |||
122 | return err; | |||
123 | } | |||
124 | ||||
125 | static void | |||
126 | set_default_attributes (struct node *np) | |||
127 | { | |||
128 | netfs_node_netnode (np)->faked = FAKE_UID(1 << 0) | FAKE_GID(1 << 1) | FAKE_DEFAULT(1 << 4); | |||
129 | np->nn_stat.st_uid = 0; | |||
130 | np->nn_stat.st_gid = 0; | |||
131 | } | |||
132 | ||||
133 | static void | |||
134 | set_faked_attribute (struct node *np, unsigned int faked) | |||
135 | { | |||
136 | netfs_node_netnode (np)->faked |= faked; | |||
137 | ||||
138 | if (netfs_node_netnode (np)->faked & FAKE_DEFAULT(1 << 4)) | |||
139 | { | |||
140 | /* Now that the node has non-default faked attributes, they have to be | |||
141 | retained for future accesses. Account for the hash table reference. | |||
142 | ||||
143 | XXX This means such nodes are currently leaked. Hopefully, there | |||
144 | won't be too many of them until the translator is shut down, and | |||
145 | the data structures should make implementing garbage collection | |||
146 | easy enough if it's ever needed, although scalability could be | |||
147 | improved. */ | |||
148 | netfs_nref (np); | |||
149 | netfs_node_netnode (np)->faked &= ~FAKE_DEFAULT(1 << 4); | |||
150 | } | |||
151 | } | |||
152 | ||||
153 | /* Node NP has no more references; free all its associated storage. */ | |||
154 | void | |||
155 | netfs_node_norefs (struct node *np) | |||
156 | { | |||
157 | pthread_mutex_unlock (&np->lock); | |||
158 | pthread_spin_unlock (&netfs_node_refcnt_lock); | |||
159 | ||||
160 | pthread_mutex_lock (&idport_ihash_lock); | |||
161 | hurd_ihash_locp_remove (&idport_ihash, netfs_node_netnode (np)->idport_locp); | |||
162 | pthread_mutex_unlock (&idport_ihash_lock); | |||
163 | ||||
164 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), netfs_node_netnode (np)->file); | |||
165 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), netfs_node_netnode (np)->idport); | |||
166 | free (np); | |||
167 | ||||
168 | pthread_spin_lock (&netfs_node_refcnt_lock); | |||
169 | } | |||
170 | ||||
171 | /* This is the cleanup function we install in netfs_protid_class. If | |||
172 | the associated nodes reference count would also drop to zero, and | |||
173 | the node has no faked attributes, we destroy it as well. */ | |||
174 | static void | |||
175 | fakeroot_netfs_release_protid (void *cookie) | |||
176 | { | |||
177 | netfs_release_protid (cookie); | |||
178 | ||||
179 | int cports = ports_count_class (netfs_control_class); | |||
180 | int nports = ports_count_class (netfs_protid_class); | |||
181 | ports_enable_class (netfs_control_class); | |||
182 | ports_enable_class (netfs_protid_class); | |||
183 | if (cports == 0 && nports == 0) | |||
184 | { | |||
185 | /* The last client is gone. Our job is done. */ | |||
186 | error_t err = netfs_shutdown (0); | |||
187 | if (! err) | |||
188 | exit (EXIT_SUCCESS0); | |||
189 | ||||
190 | /* If netfs_shutdown returns EBUSY, we lost a race against | |||
191 | fsys_goaway. Hence we ignore this error. */ | |||
192 | if (err != EBUSY((0x10 << 26) | ((16) & 0x3fff))) | |||
193 | error (1, err, "netfs_shutdown"); | |||
194 | } | |||
195 | } | |||
196 | ||||
197 | /* Given an existing node, make sure it has NEWMODES in its openmodes. | |||
198 | If not null, FILE is a port with those openmodes. */ | |||
199 | static error_t | |||
200 | check_openmodes (struct netnode *nn, int newmodes, file_t file) | |||
201 | { | |||
202 | error_t err = 0; | |||
203 | ||||
204 | if (newmodes &~ nn->openmodes) | |||
205 | { | |||
206 | /* The user wants openmodes we haven't tried before. */ | |||
207 | ||||
208 | if (file != MACH_PORT_NULL((mach_port_t) 0) && (nn->openmodes & ~newmodes)) | |||
209 | { | |||
210 | /* Intersecting sets. | |||
211 | We need yet another new peropen on this node. */ | |||
212 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), file); | |||
213 | file = MACH_PORT_NULL((mach_port_t) 0); | |||
214 | } | |||
215 | if (file == MACH_PORT_NULL((mach_port_t) 0)) | |||
216 | { | |||
217 | enum retry_type bad_retry; | |||
218 | char bad_retryname[1024]; /* XXX */ | |||
219 | err = dir_lookup (nn->file, "", nn->openmodes | newmodes, 0, | |||
220 | &bad_retry, bad_retryname, &file); | |||
221 | if (!err && (bad_retry != FS_RETRY_NORMAL | |||
222 | || bad_retryname[0] != '\0')) | |||
223 | { | |||
224 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), file); | |||
225 | err = EGRATUITOUS((0x10 << 26) | ((105) & 0x3fff)); | |||
226 | } | |||
227 | } | |||
228 | if (! err) | |||
229 | { | |||
230 | /* The new port has more openmodes than | |||
231 | the old one. We can just use it now. */ | |||
232 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), nn->file); | |||
233 | nn->file = file; | |||
234 | nn->openmodes = newmodes; | |||
235 | } | |||
236 | } | |||
237 | else if (file != MACH_PORT_NULL((mach_port_t) 0)) | |||
238 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), file); | |||
239 | ||||
240 | return err; | |||
241 | } | |||
242 | ||||
243 | /* This is called by netfs_S_fsys_getroot. */ | |||
244 | error_t | |||
245 | netfs_check_open_permissions (struct iouser *user, struct node *np, | |||
246 | int flags, int newnode) | |||
247 | { | |||
248 | return check_openmodes (netfs_node_netnode (np), | |||
249 | flags & (O_RDWR(0x0001|0x0002)|O_EXEC0x0004), MACH_PORT_NULL((mach_port_t) 0)); | |||
250 | } | |||
251 | ||||
252 | error_t | |||
253 | netfs_S_dir_lookup (struct protid *diruser, | |||
254 | char *filename, | |||
255 | int flags, | |||
256 | mode_t mode, | |||
257 | retry_type *do_retry, | |||
258 | char *retry_name, | |||
259 | mach_port_t *retry_port, | |||
260 | mach_msg_type_name_t *retry_port_type) | |||
261 | { | |||
262 | struct node *dnp, *np; | |||
263 | error_t err; | |||
264 | struct protid *newpi; | |||
265 | struct iouser *user; | |||
266 | mach_port_t file; | |||
267 | mach_port_t idport, fsidport; | |||
268 | ino_t fileno; | |||
269 | ||||
270 | if (!diruser) | |||
| ||||
271 | return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); | |||
272 | ||||
273 | dnp = diruser->po->np; | |||
274 | ||||
275 | mach_port_t dir = netfs_node_netnode (dnp)->file; | |||
276 | redo_lookup: | |||
277 | err = dir_lookup (dir, filename, | |||
278 | flags & (O_NOLINK0x0040|O_RDWR(0x0001|0x0002)|O_EXEC0x0004|O_CREAT0x0010|O_EXCL0x0020|O_NONBLOCK0x0008), | |||
279 | mode, do_retry, retry_name, &file); | |||
280 | if (dir != netfs_node_netnode (dnp)->file) | |||
281 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), dir); | |||
282 | if (err) | |||
283 | return err; | |||
284 | ||||
285 | switch (*do_retry) | |||
286 | { | |||
287 | case FS_RETRY_REAUTH: | |||
288 | { | |||
289 | mach_port_t ref = mach_reply_port (); | |||
290 | err = io_reauthenticate (file, ref, MACH_MSG_TYPE_MAKE_SEND20); | |||
291 | if (! err) | |||
292 | { | |||
293 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), file); | |||
294 | err = auth_user_authenticate (fakeroot_auth_port, ref, | |||
295 | MACH_MSG_TYPE_MAKE_SEND20, | |||
296 | &dir); | |||
297 | } | |||
298 | mach_port_destroy (mach_task_self ()((__mach_task_self_ + 0)), ref); | |||
299 | if (err) | |||
300 | return err; | |||
301 | } | |||
302 | filename = retry_name; | |||
303 | goto redo_lookup; | |||
304 | ||||
305 | case FS_RETRY_NORMAL: | |||
306 | if (retry_name[0] != '\0') | |||
307 | { | |||
308 | dir = file; | |||
309 | filename = retry_name; | |||
310 | goto redo_lookup; | |||
311 | } | |||
312 | break; | |||
313 | ||||
314 | case FS_RETRY_MAGICAL: | |||
315 | if (file == MACH_PORT_NULL((mach_port_t) 0)) | |||
316 | { | |||
317 | *retry_port = MACH_PORT_NULL((mach_port_t) 0); | |||
318 | *retry_port_type = MACH_MSG_TYPE_COPY_SEND19; | |||
319 | return 0; | |||
320 | } | |||
321 | /* Fallthrough. */ | |||
322 | ||||
323 | default: | |||
324 | /* Invalid response to our dir_lookup request. */ | |||
325 | if (file != MACH_PORT_NULL((mach_port_t) 0)) | |||
326 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), file); | |||
327 | *retry_port = MACH_PORT_NULL((mach_port_t) 0); | |||
328 | *retry_port_type = MACH_MSG_TYPE_COPY_SEND19; | |||
329 | return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); | |||
330 | } | |||
331 | ||||
332 | /* We have a new port to an underlying node. | |||
333 | Find or make our corresponding virtual node. */ | |||
334 | ||||
335 | np = 0; | |||
336 | err = io_identity (file, &idport, &fsidport, &fileno); | |||
337 | if (err) | |||
338 | { | |||
339 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), file); | |||
340 | return err; | |||
341 | } | |||
342 | ||||
343 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), fsidport); | |||
344 | ||||
345 | redo_hash_lookup: | |||
346 | pthread_mutex_lock (&idport_ihash_lock); | |||
347 | pthread_mutex_lock (&dnp->lock); | |||
348 | /* The hashtable may not hold a true reference on the node. Acquire the | |||
349 | refcount lock so that, if a node is found, its reference counter cannot | |||
350 | drop to 0 before we get our own reference. */ | |||
351 | pthread_spin_lock (&netfs_node_refcnt_lock); | |||
352 | np = hurd_ihash_find (&idport_ihash, idport); | |||
353 | if (np != NULL((void*)0)) | |||
354 | { | |||
355 | /* We already know about this node. */ | |||
356 | ||||
357 | if (np->references == 0) | |||
358 | { | |||
359 | /* But it might be in the process of being released. If so, | |||
360 | unlock the hash table to give the node a chance to actually | |||
361 | be removed and retry. */ | |||
362 | pthread_spin_unlock (&netfs_node_refcnt_lock); | |||
363 | pthread_mutex_unlock (&dnp->lock); | |||
364 | pthread_mutex_unlock (&idport_ihash_lock); | |||
365 | goto redo_hash_lookup; | |||
366 | } | |||
367 | ||||
368 | /* Otherwise, reference it right away. */ | |||
369 | np->references++; | |||
370 | pthread_spin_unlock (&netfs_node_refcnt_lock); | |||
371 | ||||
372 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), idport); | |||
373 | ||||
374 | if (np == dnp) | |||
375 | { | |||
376 | /* dnp is already locked. */ | |||
377 | } | |||
378 | else | |||
379 | { | |||
380 | pthread_mutex_lock (&np->lock); | |||
381 | pthread_mutex_unlock (&dnp->lock); | |||
382 | } | |||
383 | ||||
384 | err = check_openmodes (netfs_node_netnode (np), | |||
385 | (flags & (O_RDWR(0x0001|0x0002)|O_EXEC0x0004)), file); | |||
386 | pthread_mutex_unlock (&idport_ihash_lock); | |||
387 | } | |||
388 | else | |||
389 | { | |||
390 | pthread_spin_unlock (&netfs_node_refcnt_lock); | |||
391 | err = new_node (file, idport, 1, flags, &np); | |||
392 | pthread_mutex_unlock (&dnp->lock); | |||
393 | if (!err) | |||
394 | { | |||
395 | set_default_attributes (np); | |||
396 | err = netfs_validate_stat (np, diruser->user); | |||
397 | } | |||
398 | } | |||
399 | if (err) | |||
400 | goto lose; | |||
401 | ||||
402 | assert (retry_name[0] == '\0' && *do_retry == FS_RETRY_NORMAL)((retry_name[0] == '\0' && *do_retry == FS_RETRY_NORMAL ) ? (void) (0) : __assert_fail ("retry_name[0] == '\\0' && *do_retry == FS_RETRY_NORMAL" , "../../trans/fakeroot.c", 402, __PRETTY_FUNCTION__)); | |||
403 | flags &= ~(O_CREAT0x0010|O_EXCL0x0020|O_NOLINK0x0040|O_NOTRANS0x0080|O_NONBLOCK0x0008); | |||
404 | ||||
405 | err = iohelp_dup_iouser (&user, diruser->user); | |||
406 | if (!err) | |||
407 | { | |||
408 | newpi = netfs_make_protid (netfs_make_peropen (np, flags, diruser->po), | |||
409 | user); | |||
410 | if (! newpi) | |||
411 | { | |||
412 | iohelp_free_iouser (user); | |||
413 | err = errno(*__errno_location ()); | |||
414 | } | |||
415 | else | |||
416 | { | |||
417 | *retry_port = ports_get_right (newpi); | |||
418 | *retry_port_type = MACH_MSG_TYPE_MAKE_SEND20; | |||
419 | ports_port_deref (newpi); | |||
420 | } | |||
421 | } | |||
422 | ||||
423 | lose: | |||
424 | if (np != NULL((void*)0)) | |||
425 | netfs_nput (np); | |||
| ||||
426 | return err; | |||
427 | } | |||
428 | ||||
429 | /* These callbacks are used only by the standard netfs_S_dir_lookup, | |||
430 | which we do not use. But the shared library requires us to define them. */ | |||
431 | error_t | |||
432 | netfs_attempt_lookup (struct iouser *user, struct node *dir, | |||
433 | char *name, struct node **np) | |||
434 | { | |||
435 | assert (! "should not be here")((! "should not be here") ? (void) (0) : __assert_fail ("! \"should not be here\"" , "../../trans/fakeroot.c", 435, __PRETTY_FUNCTION__)); | |||
436 | return EIEIO((0x10 << 26) | ((104) & 0x3fff)); | |||
437 | } | |||
438 | ||||
439 | error_t | |||
440 | netfs_attempt_create_file (struct iouser *user, struct node *dir, | |||
441 | char *name, mode_t mode, struct node **np) | |||
442 | { | |||
443 | assert (! "should not be here")((! "should not be here") ? (void) (0) : __assert_fail ("! \"should not be here\"" , "../../trans/fakeroot.c", 443, __PRETTY_FUNCTION__)); | |||
444 | return EIEIO((0x10 << 26) | ((104) & 0x3fff)); | |||
445 | } | |||
446 | ||||
447 | /* Make sure that NP->nn_stat is filled with the most current information. | |||
448 | CRED identifies the user responsible for the operation. NP is locked. */ | |||
449 | error_t | |||
450 | netfs_validate_stat (struct node *np, struct iouser *cred) | |||
451 | { | |||
452 | struct stat st; | |||
453 | error_t err = io_stat (netfs_node_netnode (np)->file, &st); | |||
454 | if (err) | |||
455 | return err; | |||
456 | ||||
457 | if (netfs_node_netnode (np)->faked & FAKE_UID(1 << 0)) | |||
458 | st.st_uid = np->nn_stat.st_uid; | |||
459 | if (netfs_node_netnode (np)->faked & FAKE_GID(1 << 1)) | |||
460 | st.st_gid = np->nn_stat.st_gid; | |||
461 | if (netfs_node_netnode (np)->faked & FAKE_AUTHOR(1 << 2)) | |||
462 | st.st_author = np->nn_stat.st_author; | |||
463 | if (netfs_node_netnode (np)->faked & FAKE_MODE(1 << 3)) | |||
464 | st.st_mode = np->nn_stat.st_mode; | |||
465 | ||||
466 | np->nn_stat = st; | |||
467 | np->nn_translated = S_ISLNK (st.st_mode)((((st.st_mode)) & 0170000) == (0120000)) ? S_IFLNK0120000 : 0; | |||
468 | ||||
469 | return 0; | |||
470 | } | |||
471 | ||||
472 | /* Various netfs functions will call fshelp_isowner to check whether | |||
473 | USER is allowed to do some operation. As fakeroot is not running | |||
474 | within the fakeauth'ed environment, USER contains the real | |||
475 | user. Hence, we override this check. */ | |||
476 | error_t | |||
477 | fshelp_isowner (struct stat *st, struct iouser *user) | |||
478 | { | |||
479 | return 0; | |||
480 | } | |||
481 | ||||
482 | error_t | |||
483 | netfs_attempt_chown (struct iouser *cred, struct node *np, | |||
484 | uid_t uid, uid_t gid) | |||
485 | { | |||
486 | if (uid != ~0U) | |||
487 | { | |||
488 | set_faked_attribute (np, FAKE_UID(1 << 0)); | |||
489 | np->nn_stat.st_uid = uid; | |||
490 | } | |||
491 | if (gid != ~0U) | |||
492 | { | |||
493 | set_faked_attribute (np, FAKE_GID(1 << 1)); | |||
494 | np->nn_stat.st_gid = gid; | |||
495 | } | |||
496 | return 0; | |||
497 | } | |||
498 | ||||
499 | error_t | |||
500 | netfs_attempt_chauthor (struct iouser *cred, struct node *np, uid_t author) | |||
501 | { | |||
502 | set_faked_attribute (np, FAKE_AUTHOR(1 << 2)); | |||
503 | np->nn_stat.st_author = author; | |||
504 | return 0; | |||
505 | } | |||
506 | ||||
507 | /* Return the mode that the real underlying file should have if the | |||
508 | fake mode is being set to MODE. We always give ourselves read and | |||
509 | write permission so that we can open the file as root would be able | |||
510 | to. We give ourselves execute permission iff any execute bit is | |||
511 | set in the fake mode. */ | |||
512 | static inline mode_t | |||
513 | real_from_fake_mode (mode_t mode) | |||
514 | { | |||
515 | return mode | S_IREAD00400 | S_IWRITE00200 | (((mode << 3) | (mode << 6)) & S_IEXEC00100); | |||
516 | } | |||
517 | ||||
518 | /* This should attempt a chmod call for the user specified by CRED on | |||
519 | locked node NODE, to change the mode to MODE. Unlike the normal Unix | |||
520 | and Hurd meaning of chmod, this function is also used to attempt to | |||
521 | change files into other types. If such a transition is attempted which | |||
522 | is impossible, then return EOPNOTSUPP. */ | |||
523 | error_t | |||
524 | netfs_attempt_chmod (struct iouser *cred, struct node *np, mode_t mode) | |||
525 | { | |||
526 | if ((mode & S_IFMT0170000) == 0) | |||
527 | mode |= np->nn_stat.st_mode & S_IFMT0170000; | |||
528 | if ((mode & S_IFMT0170000) != (np->nn_stat.st_mode & S_IFMT0170000)) | |||
529 | return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); | |||
530 | ||||
531 | /* We don't bother with error checking since the fake mode change should | |||
532 | always succeed--worst case a later open will get EACCES. */ | |||
533 | (void) file_chmod (netfs_node_netnode (np)->file, mode); | |||
534 | set_faked_attribute (np, FAKE_MODE(1 << 3)); | |||
535 | np->nn_stat.st_mode = mode; | |||
536 | return 0; | |||
537 | } | |||
538 | ||||
539 | /* The user must define this function. Attempt to turn locked node NP | |||
540 | (user CRED) into a symlink with target NAME. */ | |||
541 | error_t | |||
542 | netfs_attempt_mksymlink (struct iouser *cred, struct node *np, char *name) | |||
543 | { | |||
544 | int namelen = strlen (name) + 1; | |||
545 | char trans[sizeof _HURD_SYMLINK"/hurd/" "symlink" + namelen]; | |||
546 | memcpy (trans, _HURD_SYMLINK"/hurd/" "symlink", sizeof _HURD_SYMLINK"/hurd/" "symlink"); | |||
547 | memcpy (&trans[sizeof _HURD_SYMLINK"/hurd/" "symlink"], name, namelen); | |||
548 | return file_set_translator (netfs_node_netnode (np)->file, | |||
549 | FS_TRANS_EXCL0x00000002|FS_TRANS_SET0x00000004, | |||
550 | FS_TRANS_EXCL0x00000002|FS_TRANS_SET0x00000004, 0, | |||
551 | trans, sizeof trans, | |||
552 | MACH_PORT_NULL((mach_port_t) 0), MACH_MSG_TYPE_COPY_SEND19); | |||
553 | } | |||
554 | ||||
555 | error_t | |||
556 | netfs_attempt_mkdev (struct iouser *cred, struct node *np, | |||
557 | mode_t type, dev_t indexes) | |||
558 | { | |||
559 | char *trans = 0; | |||
560 | int translen = asprintf (&trans, "%s%c%d%c%d", | |||
561 | S_ISCHR (type)((((type)) & 0170000) == (0020000)) ? _HURD_CHRDEV"/hurd/" "chrdev" : _HURD_BLKDEV"/hurd/" "blkdev", | |||
562 | '\0', major (indexes)((int)(((unsigned int) (indexes) >> 8) & 0xff)), '\0', minor (indexes)((int)((indexes) & 0xff))); | |||
563 | if (trans == 0) | |||
564 | return ENOMEM((0x10 << 26) | ((12) & 0x3fff)); | |||
565 | else | |||
566 | { | |||
567 | error_t err = file_set_translator (netfs_node_netnode (np)->file, | |||
568 | FS_TRANS_EXCL0x00000002|FS_TRANS_SET0x00000004, | |||
569 | FS_TRANS_EXCL0x00000002|FS_TRANS_SET0x00000004, 0, | |||
570 | trans, translen + 1, | |||
571 | MACH_PORT_NULL((mach_port_t) 0), | |||
572 | MACH_MSG_TYPE_COPY_SEND19); | |||
573 | free (trans); | |||
574 | return err; | |||
575 | } | |||
576 | } | |||
577 | ||||
578 | error_t | |||
579 | netfs_attempt_chflags (struct iouser *cred, struct node *np, int flags) | |||
580 | { | |||
581 | return file_chflags (netfs_node_netnode (np)->file, flags); | |||
582 | } | |||
583 | ||||
584 | error_t | |||
585 | netfs_attempt_utimes (struct iouser *cred, struct node *np, | |||
586 | struct timespec *atime, struct timespec *mtime) | |||
587 | { | |||
588 | union tv | |||
589 | { | |||
590 | struct timeval tv; | |||
591 | time_value_t tvt; | |||
592 | }; | |||
593 | union tv a, m; | |||
594 | if (atime) | |||
595 | { | |||
596 | TIMESPEC_TO_TIMEVAL (&a.tv, atime){ (&a.tv)->tv_sec = (atime)->tv_sec; (&a.tv)-> tv_usec = (atime)->tv_nsec / 1000; }; | |||
597 | } | |||
598 | else | |||
599 | a.tv.tv_sec = a.tv.tv_usec = -1; | |||
600 | if (mtime) | |||
601 | { | |||
602 | TIMESPEC_TO_TIMEVAL (&m.tv, mtime){ (&m.tv)->tv_sec = (mtime)->tv_sec; (&m.tv)-> tv_usec = (mtime)->tv_nsec / 1000; }; | |||
603 | } | |||
604 | else | |||
605 | m.tv.tv_sec = m.tv.tv_usec = -1; | |||
606 | ||||
607 | return file_utimes (netfs_node_netnode (np)->file, a.tvt, m.tvt); | |||
608 | } | |||
609 | ||||
610 | error_t | |||
611 | netfs_attempt_set_size (struct iouser *cred, struct node *np, off_t size) | |||
612 | { | |||
613 | return file_set_size (netfs_node_netnode (np)->file, size); | |||
614 | } | |||
615 | ||||
616 | error_t | |||
617 | netfs_attempt_statfs (struct iouser *cred, struct node *np, struct statfs *st) | |||
618 | { | |||
619 | return file_statfs (netfs_node_netnode (np)->file, st); | |||
620 | } | |||
621 | ||||
622 | error_t | |||
623 | netfs_attempt_sync (struct iouser *cred, struct node *np, int wait) | |||
624 | { | |||
625 | return file_sync (netfs_node_netnode (np)->file, wait, 0); | |||
626 | } | |||
627 | ||||
628 | error_t | |||
629 | netfs_attempt_syncfs (struct iouser *cred, int wait) | |||
630 | { | |||
631 | return 0; | |||
632 | } | |||
633 | ||||
634 | error_t | |||
635 | netfs_attempt_mkdir (struct iouser *user, struct node *dir, | |||
636 | char *name, mode_t mode) | |||
637 | { | |||
638 | return dir_mkdir (netfs_node_netnode (dir)->file, name, mode | S_IRWXU(00400|00200|00100)); | |||
639 | } | |||
640 | ||||
641 | ||||
642 | /* XXX | |||
643 | Removing a node should mark the netnode so that it is GC'd when | |||
644 | it has no hard refs. | |||
645 | */ | |||
646 | ||||
647 | error_t | |||
648 | netfs_attempt_unlink (struct iouser *user, struct node *dir, char *name) | |||
649 | { | |||
650 | return dir_unlink (netfs_node_netnode (dir)->file, name); | |||
651 | } | |||
652 | ||||
653 | error_t | |||
654 | netfs_attempt_rename (struct iouser *user, struct node *fromdir, | |||
655 | char *fromname, struct node *todir, | |||
656 | char *toname, int excl) | |||
657 | { | |||
658 | return dir_rename (netfs_node_netnode (fromdir)->file, fromname, | |||
659 | netfs_node_netnode (todir)->file, toname, excl); | |||
660 | } | |||
661 | ||||
662 | error_t | |||
663 | netfs_attempt_rmdir (struct iouser *user, | |||
664 | struct node *dir, char *name) | |||
665 | { | |||
666 | return dir_rmdir (netfs_node_netnode (dir)->file, name); | |||
667 | } | |||
668 | ||||
669 | error_t | |||
670 | netfs_attempt_link (struct iouser *user, struct node *dir, | |||
671 | struct node *file, char *name, int excl) | |||
672 | { | |||
673 | return dir_link (netfs_node_netnode (dir)->file, netfs_node_netnode (file)->file, name, excl); | |||
674 | } | |||
675 | ||||
676 | error_t | |||
677 | netfs_attempt_mkfile (struct iouser *user, struct node *dir, | |||
678 | mode_t mode, struct node **np) | |||
679 | { | |||
680 | file_t newfile; | |||
681 | error_t err = dir_mkfile (netfs_node_netnode (dir)->file, O_RDWR(0x0001|0x0002)|O_EXEC0x0004, | |||
682 | real_from_fake_mode (mode), &newfile); | |||
683 | pthread_mutex_unlock (&dir->lock); | |||
684 | if (err == 0) | |||
685 | err = new_node (newfile, MACH_PORT_NULL((mach_port_t) 0), 0, O_RDWR(0x0001|0x0002)|O_EXEC0x0004, np); | |||
686 | if (err == 0) | |||
687 | pthread_mutex_unlock (&(*np)->lock); | |||
688 | return err; | |||
689 | } | |||
690 | ||||
691 | error_t | |||
692 | netfs_attempt_readlink (struct iouser *user, struct node *np, char *buf) | |||
693 | { | |||
694 | char transbuf[sizeof _HURD_SYMLINK"/hurd/" "symlink" + np->nn_stat.st_size + 1]; | |||
695 | char *trans = transbuf; | |||
696 | size_t translen = sizeof transbuf; | |||
697 | error_t err = file_get_translator (netfs_node_netnode (np)->file, | |||
698 | &trans, &translen); | |||
699 | if (err == 0) | |||
700 | { | |||
701 | if (translen < sizeof _HURD_SYMLINK"/hurd/" "symlink" | |||
702 | || memcmp (trans, _HURD_SYMLINK"/hurd/" "symlink", sizeof _HURD_SYMLINK"/hurd/" "symlink") != 0) | |||
703 | err = EINVAL((0x10 << 26) | ((22) & 0x3fff)); | |||
704 | else | |||
705 | { | |||
706 | assert (translen <= sizeof _HURD_SYMLINK + np->nn_stat.st_size + 1)((translen <= sizeof "/hurd/" "symlink" + np->nn_stat.st_size + 1) ? (void) (0) : __assert_fail ("translen <= sizeof \"/hurd/\" \"symlink\" + np->nn_stat.st_size + 1" , "../../trans/fakeroot.c", 706, __PRETTY_FUNCTION__)); | |||
707 | memcpy (buf, &trans[sizeof _HURD_SYMLINK"/hurd/" "symlink"], | |||
708 | translen - sizeof _HURD_SYMLINK"/hurd/" "symlink"); | |||
709 | } | |||
710 | if (trans != transbuf) | |||
711 | munmap (trans, translen); | |||
712 | } | |||
713 | return err; | |||
714 | } | |||
715 | ||||
716 | error_t | |||
717 | netfs_attempt_read (struct iouser *cred, struct node *np, | |||
718 | off_t offset, size_t *len, void *data) | |||
719 | { | |||
720 | char *buf = data; | |||
721 | error_t err = io_read (netfs_node_netnode (np)->file, | |||
722 | &buf, len, offset, *len); | |||
723 | if (err == 0 && buf != data) | |||
724 | { | |||
725 | memcpy (data, buf, *len); | |||
726 | munmap (buf, *len); | |||
727 | } | |||
728 | return err; | |||
729 | } | |||
730 | ||||
731 | error_t | |||
732 | netfs_attempt_write (struct iouser *cred, struct node *np, | |||
733 | off_t offset, size_t *len, void *data) | |||
734 | { | |||
735 | return io_write (netfs_node_netnode (np)->file, data, *len, offset, len); | |||
736 | } | |||
737 | ||||
738 | error_t | |||
739 | netfs_report_access (struct iouser *cred, struct node *np, int *types) | |||
740 | { | |||
741 | *types = O_RDWR(0x0001|0x0002)|O_EXEC0x0004; | |||
742 | return 0; | |||
743 | } | |||
744 | ||||
745 | error_t | |||
746 | netfs_get_dirents (struct iouser *cred, struct node *dir, | |||
747 | int entry, int nentries, char **data, | |||
748 | mach_msg_type_number_t *datacnt, | |||
749 | vm_size_t bufsize, int *amt) | |||
750 | { | |||
751 | return dir_readdir (netfs_node_netnode (dir)->file, data, datacnt, | |||
752 | entry, nentries, bufsize, amt); | |||
753 | } | |||
754 | ||||
755 | error_t | |||
756 | netfs_file_get_storage_info (struct iouser *cred, | |||
757 | struct node *np, | |||
758 | mach_port_t **ports, | |||
759 | mach_msg_type_name_t *ports_type, | |||
760 | mach_msg_type_number_t *num_ports, | |||
761 | int **ints, | |||
762 | mach_msg_type_number_t *num_ints, | |||
763 | off_t **offsets, | |||
764 | mach_msg_type_number_t *num_offsets, | |||
765 | char **data, | |||
766 | mach_msg_type_number_t *data_len) | |||
767 | { | |||
768 | *ports_type = MACH_MSG_TYPE_MOVE_SEND17; | |||
769 | return file_get_storage_info (netfs_node_netnode (np)->file, | |||
770 | ports, num_ports, | |||
771 | ints, num_ints, | |||
772 | offsets, num_offsets, | |||
773 | data, data_len); | |||
774 | } | |||
775 | ||||
776 | kern_return_t | |||
777 | netfs_S_file_exec (struct protid *user, | |||
778 | task_t task, | |||
779 | int flags, | |||
780 | char *argv, | |||
781 | size_t argvlen, | |||
782 | char *envp, | |||
783 | size_t envplen, | |||
784 | mach_port_t *fds, | |||
785 | size_t fdslen, | |||
786 | mach_port_t *portarray, | |||
787 | size_t portarraylen, | |||
788 | int *intarray, | |||
789 | size_t intarraylen, | |||
790 | mach_port_t *deallocnames, | |||
791 | size_t deallocnameslen, | |||
792 | mach_port_t *destroynames, | |||
793 | size_t destroynameslen) | |||
794 | { | |||
795 | error_t err; | |||
796 | file_t file; | |||
797 | ||||
798 | if (!user) | |||
799 | return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); | |||
800 | ||||
801 | pthread_mutex_lock (&user->po->np->lock); | |||
802 | err = check_openmodes (netfs_node_netnode (user->po->np), | |||
803 | O_EXEC0x0004, MACH_PORT_NULL((mach_port_t) 0)); | |||
804 | file = netfs_node_netnode (user->po->np)->file; | |||
805 | if (!err) | |||
806 | err = mach_port_mod_refs (mach_task_self ()((__mach_task_self_ + 0)), | |||
807 | file, MACH_PORT_RIGHT_SEND((mach_port_right_t) 0), 1); | |||
808 | pthread_mutex_unlock (&user->po->np->lock); | |||
809 | ||||
810 | if (!err) | |||
811 | { | |||
812 | /* We cannot use MACH_MSG_TYPE_MOVE_SEND because we might need to | |||
813 | retry an interrupted call that would have consumed the rights. */ | |||
814 | err = file_exec (netfs_node_netnode (user->po->np)->file, | |||
815 | task, flags, argv, argvlen, | |||
816 | envp, envplen, fds, MACH_MSG_TYPE_COPY_SEND19, fdslen, | |||
817 | portarray, MACH_MSG_TYPE_COPY_SEND19, portarraylen, | |||
818 | intarray, intarraylen, deallocnames, deallocnameslen, | |||
819 | destroynames, destroynameslen); | |||
820 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), file); | |||
821 | } | |||
822 | ||||
823 | if (err == 0) | |||
824 | { | |||
825 | size_t i; | |||
826 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), task); | |||
827 | for (i = 0; i < fdslen; ++i) | |||
828 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), fds[i]); | |||
829 | for (i = 0; i < portarraylen; ++i) | |||
830 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), portarray[i]); | |||
831 | } | |||
832 | return err; | |||
833 | } | |||
834 | ||||
835 | error_t | |||
836 | netfs_S_io_map (struct protid *user, | |||
837 | mach_port_t *rdobj, mach_msg_type_name_t *rdobjtype, | |||
838 | mach_port_t *wrobj, mach_msg_type_name_t *wrobjtype) | |||
839 | { | |||
840 | error_t err; | |||
841 | ||||
842 | if (!user) | |||
843 | return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); | |||
844 | *rdobjtype = *wrobjtype = MACH_MSG_TYPE_MOVE_SEND17; | |||
845 | ||||
846 | pthread_mutex_lock (&user->po->np->lock); | |||
847 | err = io_map (netfs_node_netnode (user->po->np)->file, rdobj, wrobj); | |||
848 | pthread_mutex_unlock (&user->po->np->lock); | |||
849 | return err; | |||
850 | } | |||
851 | ||||
852 | error_t | |||
853 | netfs_S_io_map_cntl (struct protid *user, | |||
854 | mach_port_t *obj, | |||
855 | mach_msg_type_name_t *objtype) | |||
856 | { | |||
857 | error_t err; | |||
858 | ||||
859 | if (!user) | |||
860 | return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); | |||
861 | *objtype = MACH_MSG_TYPE_MOVE_SEND17; | |||
862 | ||||
863 | pthread_mutex_lock (&user->po->np->lock); | |||
864 | err = io_map_cntl (netfs_node_netnode (user->po->np)->file, obj); | |||
865 | pthread_mutex_unlock (&user->po->np->lock); | |||
866 | return err; | |||
867 | } | |||
868 | ||||
869 | error_t | |||
870 | netfs_S_io_identity (struct protid *user, | |||
871 | mach_port_t *id, | |||
872 | mach_msg_type_name_t *idtype, | |||
873 | mach_port_t *fsys, | |||
874 | mach_msg_type_name_t *fsystype, | |||
875 | ino_t *fileno) | |||
876 | { | |||
877 | error_t err; | |||
878 | ||||
879 | if (!user) | |||
880 | return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); | |||
881 | ||||
882 | *idtype = *fsystype = MACH_MSG_TYPE_MOVE_SEND17; | |||
883 | ||||
884 | pthread_mutex_lock (&user->po->np->lock); | |||
885 | err = io_identity (netfs_node_netnode (user->po->np)->file, | |||
886 | id, fsys, fileno); | |||
887 | pthread_mutex_unlock (&user->po->np->lock); | |||
888 | return err; | |||
889 | } | |||
890 | ||||
891 | #define NETFS_S_SIMPLE(name)error_t netfs_S_name (struct protid *user) { error_t err; if ( !user) return ((0x10 << 26) | ((45) & 0x3fff)); pthread_mutex_lock (&user->po->np->lock); err = name (netfs_node_netnode (user->po->np)->file); pthread_mutex_unlock (&user ->po->np->lock); return err; } \ | |||
892 | error_t \ | |||
893 | netfs_S_##name (struct protid *user) \ | |||
894 | { \ | |||
895 | error_t err; \ | |||
896 | \ | |||
897 | if (!user) \ | |||
898 | return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); \ | |||
899 | \ | |||
900 | pthread_mutex_lock (&user->po->np->lock); \ | |||
901 | err = name (netfs_node_netnode (user->po->np)->file); \ | |||
902 | pthread_mutex_unlock (&user->po->np->lock); \ | |||
903 | return err; \ | |||
904 | } | |||
905 | ||||
906 | NETFS_S_SIMPLE (io_get_conch)error_t netfs_S_io_get_conch (struct protid *user) { error_t err ; if (!user) return ((0x10 << 26) | ((45) & 0x3fff) ); pthread_mutex_lock (&user->po->np->lock); err = io_get_conch (netfs_node_netnode (user->po->np)-> file); pthread_mutex_unlock (&user->po->np->lock ); return err; } | |||
907 | NETFS_S_SIMPLE (io_release_conch)error_t netfs_S_io_release_conch (struct protid *user) { error_t err; if (!user) return ((0x10 << 26) | ((45) & 0x3fff )); pthread_mutex_lock (&user->po->np->lock); err = io_release_conch (netfs_node_netnode (user->po->np)-> file); pthread_mutex_unlock (&user->po->np->lock ); return err; } | |||
908 | NETFS_S_SIMPLE (io_eofnotify)error_t netfs_S_io_eofnotify (struct protid *user) { error_t err ; if (!user) return ((0x10 << 26) | ((45) & 0x3fff) ); pthread_mutex_lock (&user->po->np->lock); err = io_eofnotify (netfs_node_netnode (user->po->np)-> file); pthread_mutex_unlock (&user->po->np->lock ); return err; } | |||
909 | NETFS_S_SIMPLE (io_readnotify)error_t netfs_S_io_readnotify (struct protid *user) { error_t err; if (!user) return ((0x10 << 26) | ((45) & 0x3fff )); pthread_mutex_lock (&user->po->np->lock); err = io_readnotify (netfs_node_netnode (user->po->np)-> file); pthread_mutex_unlock (&user->po->np->lock ); return err; } | |||
910 | NETFS_S_SIMPLE (io_readsleep)error_t netfs_S_io_readsleep (struct protid *user) { error_t err ; if (!user) return ((0x10 << 26) | ((45) & 0x3fff) ); pthread_mutex_lock (&user->po->np->lock); err = io_readsleep (netfs_node_netnode (user->po->np)-> file); pthread_mutex_unlock (&user->po->np->lock ); return err; } | |||
911 | NETFS_S_SIMPLE (io_sigio)error_t netfs_S_io_sigio (struct protid *user) { error_t err; if (!user) return ((0x10 << 26) | ((45) & 0x3fff)) ; pthread_mutex_lock (&user->po->np->lock); err = io_sigio (netfs_node_netnode (user->po->np)->file); pthread_mutex_unlock (&user->po->np->lock); return err; } | |||
912 | ||||
913 | error_t | |||
914 | netfs_S_io_prenotify (struct protid *user, | |||
915 | vm_offset_t start, vm_offset_t stop) | |||
916 | { | |||
917 | error_t err; | |||
918 | ||||
919 | if (!user) | |||
920 | return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); | |||
921 | ||||
922 | pthread_mutex_lock (&user->po->np->lock); | |||
923 | err = io_prenotify (netfs_node_netnode (user->po->np)->file, start, stop); | |||
924 | pthread_mutex_unlock (&user->po->np->lock); | |||
925 | return err; | |||
926 | } | |||
927 | ||||
928 | error_t | |||
929 | netfs_S_io_postnotify (struct protid *user, | |||
930 | vm_offset_t start, vm_offset_t stop) | |||
931 | { | |||
932 | error_t err; | |||
933 | ||||
934 | if (!user) | |||
935 | return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); | |||
936 | ||||
937 | pthread_mutex_lock (&user->po->np->lock); | |||
938 | err = io_postnotify (netfs_node_netnode (user->po->np)->file, start, stop); | |||
939 | pthread_mutex_unlock (&user->po->np->lock); | |||
940 | return err; | |||
941 | } | |||
942 | ||||
943 | /* This overrides the library's definition. */ | |||
944 | int | |||
945 | netfs_demuxer (mach_msg_header_t *inp, | |||
946 | mach_msg_header_t *outp) | |||
947 | { | |||
948 | mig_routine_t routine; | |||
949 | if ((routine = netfs_io_server_routine (inp)) || | |||
950 | (routine = netfs_fs_server_routine (inp)) || | |||
951 | (routine = ports_notify_server_routine (inp)) || | |||
952 | (routine = netfs_fsys_server_routine (inp)) || | |||
953 | /* XXX we should intercept interrupt_operation and do | |||
954 | the ports_S_interrupt_operation work as well as | |||
955 | sending an interrupt_operation to the underlying file. | |||
956 | */ | |||
957 | (routine = ports_interrupt_server_routine (inp))) | |||
958 | { | |||
959 | (*routine) (inp, outp); | |||
960 | return TRUE((boolean_t) 1); | |||
961 | } | |||
962 | else | |||
963 | { | |||
964 | /* We didn't recognize the message ID, so pass the message through | |||
965 | unchanged to the underlying file. */ | |||
966 | struct protid *cred = ports_lookup_port (netfs_port_bucket, | |||
967 | inp->msgh_local_port, | |||
968 | netfs_protid_class); | |||
969 | if (cred == 0) | |||
970 | /* This must be an unknown message on our fsys control port. */ | |||
971 | return 0; | |||
972 | else | |||
973 | { | |||
974 | error_t err; | |||
975 | assert (MACH_MSGH_BITS_LOCAL (inp->msgh_bits)(((((inp->msgh_bits) & 0x0000ff00) >> 8) == 17) ? (void) (0) : __assert_fail ("(((inp->msgh_bits) & 0x0000ff00) >> 8) == 17" , "../../trans/fakeroot.c", 976, __PRETTY_FUNCTION__)) | |||
976 | == MACH_MSG_TYPE_MOVE_SEND)(((((inp->msgh_bits) & 0x0000ff00) >> 8) == 17) ? (void) (0) : __assert_fail ("(((inp->msgh_bits) & 0x0000ff00) >> 8) == 17" , "../../trans/fakeroot.c", 976, __PRETTY_FUNCTION__)); | |||
977 | inp->msgh_bits = (inp->msgh_bits & MACH_MSGH_BITS_COMPLEX0x80000000U) | |||
978 | | MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND,((19) | ((((inp->msgh_bits) & 0x000000ff)) << 8) ) | |||
979 | MACH_MSGH_BITS_REMOTE (inp->msgh_bits))((19) | ((((inp->msgh_bits) & 0x000000ff)) << 8) ); | |||
980 | inp->msgh_local_port = inp->msgh_remote_port; /* reply port */ | |||
981 | inp->msgh_remote_port = netfs_node_netnode (cred->po->np)->file; | |||
982 | err = mach_msg (inp, MACH_SEND_MSG0x00000001, inp->msgh_size, 0, | |||
983 | MACH_PORT_NULL((mach_port_t) 0), MACH_MSG_TIMEOUT_NONE((mach_msg_timeout_t) 0), | |||
984 | MACH_PORT_NULL((mach_port_t) 0)); | |||
985 | assert_perror (err)(!(err) ? (void) (0) : __assert_perror_fail ((err), "../../trans/fakeroot.c" , 985, __PRETTY_FUNCTION__)); /* XXX should synthesize reply */ | |||
986 | ports_port_deref (cred); | |||
987 | /* We already sent the message, so the server loop shouldn't do it again. */ | |||
988 | ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY-305; | |||
989 | return 1; | |||
990 | } | |||
991 | } | |||
992 | } | |||
993 | ||||
994 | ||||
995 | int | |||
996 | main (int argc, char **argv) | |||
997 | { | |||
998 | error_t err; | |||
999 | mach_port_t bootstrap; | |||
1000 | ||||
1001 | struct argp argp = { .doc = "\ | |||
1002 | A translator for faking privileged access to an underlying filesystem.\v\ | |||
1003 | This translator appears to give transparent access to the underlying \ | |||
1004 | directory node. However, all accesses are made using the credentials \ | |||
1005 | of the translator regardless of the client and the translator fakes \ | |||
1006 | success for chown and chmod operations that only root could actually do, \ | |||
1007 | reporting the faked IDs and modes in later stat calls, and allows \ | |||
1008 | any user to open nodes regardless of permissions as is done for root." }; | |||
1009 | ||||
1010 | /* Parse our command line arguments (all none of them). */ | |||
1011 | argp_parse (&argp, argc, argv, ARGP_IN_ORDER0x08, 0, 0); | |||
1012 | ||||
1013 | fakeroot_auth_port = getauth (); | |||
1014 | ||||
1015 | task_get_bootstrap_port (mach_task_self (), &bootstrap)(task_get_special_port((((__mach_task_self_ + 0))), 4, (& bootstrap))); | |||
1016 | netfs_init (); | |||
1017 | ||||
1018 | /* Install our own clean routine. */ | |||
1019 | netfs_protid_class->clean_routine = fakeroot_netfs_release_protid; | |||
1020 | ||||
1021 | /* Get our underlying node (we presume it's a directory) and use | |||
1022 | that to make the root node of the filesystem. */ | |||
1023 | err = new_node (netfs_startup (bootstrap, O_READ0x0001), MACH_PORT_NULL((mach_port_t) 0), 0, O_READ0x0001, | |||
1024 | &netfs_root_node); | |||
1025 | if (err) | |||
1026 | error (5, err, "Cannot create root node"); | |||
1027 | ||||
1028 | err = netfs_validate_stat (netfs_root_node, 0); | |||
1029 | if (err) | |||
1030 | error (6, err, "Cannot stat underlying node"); | |||
1031 | ||||
1032 | netfs_root_node->nn_stat.st_mode &= ~(S_IPTRANS000010000000 | S_IATRANS000020000000); | |||
1033 | netfs_root_node->nn_stat.st_mode |= S_IROOT000040000000; | |||
1034 | set_faked_attribute (netfs_root_node, FAKE_MODE(1 << 3)); | |||
1035 | pthread_mutex_unlock (&netfs_root_node->lock); | |||
1036 | ||||
1037 | netfs_server_loop (); /* Never returns. */ | |||
1038 | ||||
1039 | /*NOTREACHED*/ | |||
1040 | return 0; | |||
1041 | } |