Bug Summary

File:obj-scan-build/trans/../../trans/fakeroot.c
Location:line 425, column 5
Description:Use of memory after it is freed

Annotated Source Code

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
40const char *argp_program_version = STANDARD_HURD_VERSION (fakeroot)"fakeroot" " (GNU Hurd) " "0.5";
41
42char *netfs_server_name = "fakeroot";
43char *netfs_server_version = HURD_VERSION"0.5";
44int netfs_maxsymlinks = 16; /* arbitrary */
45
46static auth_t fakeroot_auth_port;
47
48struct 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
64pthread_mutex_t idport_ihash_lock = PTHREAD_MUTEX_INITIALIZER{ ((__pthread_spinlock_t) 0), ((__pthread_spinlock_t) 0), 0, 0
, 0, 0, 0, 0 }
;
65struct 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. */
72static error_t
73new_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)
14
Taking false branch
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))
15
Assuming 'idport' is not equal to 0
16
Taking true branch
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)
17
Taking false branch
108 pthread_mutex_lock (&idport_ihash_lock);
109 err = hurd_ihash_add (&idport_ihash, nn->idport, *np);
110 if (err)
18
Assuming 'err' is not equal to 0
19
Taking true branch
111 goto lose;
20
Control jumps to line 118
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);
21
Memory is released
122 return err;
123}
124
125static void
126set_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
133static void
134set_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. */
154void
155netfs_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. */
174static void
175fakeroot_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. */
199static error_t
200check_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. */
244error_t
245netfs_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
252error_t
253netfs_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)
1
Assuming 'diruser' is non-null
2
Taking false branch
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)
3
Taking false branch
281 mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), dir);
282 if (err)
4
Assuming 'err' is 0
5
Taking false branch
283 return err;
284
285 switch (*do_retry)
6
Control jumps to 'case FS_RETRY_NORMAL:' at line 305
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')
7
Taking false branch
307 {
308 dir = file;
309 filename = retry_name;
310 goto redo_lookup;
311 }
312 break;
8
Execution continues on line 335
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)
9
Assuming 'err' is 0
10
Taking false branch
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))
11
Assuming 'np' is equal to null
12
Taking false branch
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);
13
Calling 'new_node'
22
Returned released memory via 5th parameter
392 pthread_mutex_unlock (&dnp->lock);
393 if (!err)
23
Taking false branch
394 {
395 set_default_attributes (np);
396 err = netfs_validate_stat (np, diruser->user);
397 }
398 }
399 if (err)
24
Taking true branch
400 goto lose;
25
Control jumps to line 424
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))
26
Taking true branch
425 netfs_nput (np);
27
Use of memory after it is freed
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. */
431error_t
432netfs_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
439error_t
440netfs_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. */
449error_t
450netfs_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. */
476error_t
477fshelp_isowner (struct stat *st, struct iouser *user)
478{
479 return 0;
480}
481
482error_t
483netfs_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
499error_t
500netfs_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. */
512static inline mode_t
513real_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. */
523error_t
524netfs_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. */
541error_t
542netfs_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
555error_t
556netfs_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
578error_t
579netfs_attempt_chflags (struct iouser *cred, struct node *np, int flags)
580{
581 return file_chflags (netfs_node_netnode (np)->file, flags);
582}
583
584error_t
585netfs_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
610error_t
611netfs_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
616error_t
617netfs_attempt_statfs (struct iouser *cred, struct node *np, struct statfs *st)
618{
619 return file_statfs (netfs_node_netnode (np)->file, st);
620}
621
622error_t
623netfs_attempt_sync (struct iouser *cred, struct node *np, int wait)
624{
625 return file_sync (netfs_node_netnode (np)->file, wait, 0);
626}
627
628error_t
629netfs_attempt_syncfs (struct iouser *cred, int wait)
630{
631 return 0;
632}
633
634error_t
635netfs_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
647error_t
648netfs_attempt_unlink (struct iouser *user, struct node *dir, char *name)
649{
650 return dir_unlink (netfs_node_netnode (dir)->file, name);
651}
652
653error_t
654netfs_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
662error_t
663netfs_attempt_rmdir (struct iouser *user,
664 struct node *dir, char *name)
665{
666 return dir_rmdir (netfs_node_netnode (dir)->file, name);
667}
668
669error_t
670netfs_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
676error_t
677netfs_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
691error_t
692netfs_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
716error_t
717netfs_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
731error_t
732netfs_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
738error_t
739netfs_report_access (struct iouser *cred, struct node *np, int *types)
740{
741 *types = O_RDWR(0x0001|0x0002)|O_EXEC0x0004;
742 return 0;
743}
744
745error_t
746netfs_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
755error_t
756netfs_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
776kern_return_t
777netfs_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
835error_t
836netfs_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
852error_t
853netfs_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
869error_t
870netfs_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; }
\
892error_t \
893netfs_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
906NETFS_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; }
907NETFS_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; }
908NETFS_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; }
909NETFS_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; }
910NETFS_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; }
911NETFS_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
913error_t
914netfs_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
928error_t
929netfs_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. */
944int
945netfs_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
995int
996main (int argc, char **argv)
997{
998 error_t err;
999 mach_port_t bootstrap;
1000
1001 struct argp argp = { .doc = "\
1002A translator for faking privileged access to an underlying filesystem.\v\
1003This translator appears to give transparent access to the underlying \
1004directory node. However, all accesses are made using the credentials \
1005of the translator regardless of the client and the translator fakes \
1006success for chown and chmod operations that only root could actually do, \
1007reporting the faked IDs and modes in later stat calls, and allows \
1008any 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}