| 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 | } |