int ethernet_open (struct device *dev) { error_t err; device_t master_device; struct ether_device *edev = (struct ether_device *) dev->priv; assert (edev->ether_port == MACH_PORT_NULL); err = ports_create_port (etherreadclass, etherport_bucket, sizeof (struct port_info), &edev->readpt); assert_perror (err); edev->readptname = ports_get_right (edev->readpt); mach_port_insert_right (mach_task_self (), edev->readptname, edev->readptname, MACH_MSG_TYPE_MAKE_SEND); mach_port_set_qlimit (mach_task_self (), edev->readptname, MACH_PORT_QLIMIT_MAX); master_device = file_name_lookup (dev->name, O_READ | O_WRITE, 0); if (master_device != MACH_PORT_NULL) { /* The device name here is the path of a device file. */ err = device_open (master_device, D_WRITE | D_READ, "eth", &edev->ether_port); mach_port_deallocate (mach_task_self (), master_device); if (err) error (2, err, "device_open on %s", dev->name); err = device_set_filter (edev->ether_port, ports_get_right (edev->readpt), MACH_MSG_TYPE_MAKE_SEND, 0, bpf_ether_filter, bpf_ether_filter_len); if (err) error (2, err, "device_set_filter on %s", dev->name); } else { /* No, perhaps a Mach device? */ int file_errno = errno; err = get_privileged_ports (0, &master_device); if (err) { error (0, file_errno, "file_name_lookup %s", dev->name); error (2, err, "and cannot get device master port"); } err = device_open (master_device, D_WRITE | D_READ, dev->name, &edev->ether_port); mach_port_deallocate (mach_task_self (), master_device); if (err) { error (0, file_errno, "file_name_lookup %s", dev->name); error (2, err, "device_open(%s)", dev->name); } err = device_set_filter (edev->ether_port, ports_get_right (edev->readpt), MACH_MSG_TYPE_MAKE_SEND, 0, ether_filter, ether_filter_len); if (err) error (2, err, "device_set_filter on %s", dev->name); } return 0; }
int ethernet_open (char *dev_name, device_t master_device, struct port_bucket *etherport_bucket, struct port_class *etherreadclass) { error_t err; assert (ether_port == MACH_PORT_NULL); err = ports_create_port (etherreadclass, etherport_bucket, sizeof (struct port_info), &readpt); if (err) error (2, err, "ports_create_port"); readptname = ports_get_right (readpt); mach_port_insert_right (mach_task_self (), readptname, readptname, MACH_MSG_TYPE_MAKE_SEND); mach_port_set_qlimit (mach_task_self (), readptname, MACH_PORT_QLIMIT_MAX); err = device_open (master_device, D_WRITE | D_READ, "eth", ðer_port); mach_port_deallocate (mach_task_self (), master_device); if (err) error (2, err, "device_open: %s", dev_name); err = device_set_filter (ether_port, ports_get_right (readpt), MACH_MSG_TYPE_MAKE_SEND, 0, (unsigned short *)ether_filter, ether_filter_len); if (err) error (2, err, "device_set_filter: %s", dev_name); set_promisc (dev_name, ether_port, 1); return 0; }
/* Callback function needed for calls to fshelp_fetch_root. See <hurd/fshelp.h> for the interface description. */ static error_t _netfs_translator_callback2_fn (void *cookie1, void *cookie2, int flags, mach_port_t *underlying, mach_msg_type_name_t *underlying_type) { error_t err; struct protid *cred; struct node *node = cookie1; struct iouser *user; err = iohelp_create_simple_iouser (&user, node->nn_stat.st_uid, node->nn_stat.st_gid); if (err) return err; cred = netfs_make_protid (netfs_make_peropen (node, flags, cookie2), user); if (cred) { *underlying = ports_get_right (cred); *underlying_type = MACH_MSG_TYPE_MAKE_SEND; ports_port_deref (cred); return 0; } else { iohelp_free_iouser (user); return errno; } }
/* Implement io_duplicate as described in <hurd/io.defs>. */ kern_return_t diskfs_S_io_duplicate (struct protid *cred, mach_port_t *port, mach_msg_type_name_t *portpoly) { error_t err; struct protid *newpi; if (!cred) return EOPNOTSUPP; mutex_lock (&cred->po->np->lock); err = diskfs_create_protid (cred->po, cred->user, &newpi); if (! err) { *port = ports_get_right (newpi); *portpoly = MACH_MSG_TYPE_MAKE_SEND; ports_port_deref (newpi); } mutex_unlock (&cred->po->np->lock); return err; }
error_t fshelp_get_identity (struct port_bucket *bucket, ino_t fileno, mach_port_t *pt) { struct idspec *i; error_t err = 0; error_t check_port (void *arg) { struct idspec *i = arg; if (i->fileno == fileno) { *pt = ports_get_right (i); return 1; } else return 0; } mutex_lock (&idlock); if (!idclass) id_initialize (); *pt = MACH_PORT_NULL; ports_class_iterate (idclass, check_port); if (*pt != MACH_PORT_NULL) { mutex_unlock (&idlock); return 0; } err = ports_create_port (idclass, bucket, sizeof (struct idspec), &i); if (err) { mutex_unlock (&idlock); return err; } i->fileno = fileno; *pt = ports_get_right (i); ports_port_deref (i); mutex_unlock (&idlock); return 0; }
/* Return a new connection from a socket previously listened. */ error_t S_socket_accept (struct sock_user *user, mach_port_t *port, mach_msg_type_name_t *port_type, mach_port_t *peer_addr_port, mach_msg_type_name_t *peer_addr_port_type) { error_t err; struct sock *sock; if (!user) return EOPNOTSUPP; sock = user->sock; err = ensure_connq (sock); if (!err) { struct timespec noblock = {0, 0}; struct sock *peer_sock; err = connq_listen (sock->listen_queue, (sock->flags & PFLOCAL_SOCK_NONBLOCK) ? &noblock : NULL, &peer_sock); if (!err) { struct addr *peer_addr; *port_type = MACH_MSG_TYPE_MAKE_SEND; err = sock_create_port (peer_sock, port); if (!err) err = sock_get_addr (peer_sock, &peer_addr); if (!err) { *peer_addr_port = ports_get_right (peer_addr); *peer_addr_port_type = MACH_MSG_TYPE_MAKE_SEND; ports_port_deref (peer_addr); } else { /* TEAR DOWN THE CONNECTION XXX */ } } } return err; }
/* Find out the name of a socket. */ error_t S_socket_name (struct sock_user *user, mach_port_t *addr_port, mach_msg_type_name_t *addr_port_type) { error_t err; struct addr *addr; if (!user) return EOPNOTSUPP; err = sock_get_addr (user->sock, &addr); if (err) return err; *addr_port = ports_get_right (addr); *addr_port_type = MACH_MSG_TYPE_MAKE_SEND; ports_port_deref (addr); return 0; }
error_t netfs_S_dir_mkfile (struct protid *diruser, int flags, mode_t mode, mach_port_t *newfile, mach_msg_type_name_t *newfiletype) { error_t err; struct node *np; struct iouser *user; struct protid *newpi; pthread_mutex_lock (&diruser->po->np->lock); err = netfs_attempt_mkfile (diruser->user, diruser->po->np, mode, &np); if (!err) { /* the dir is now unlocked and NP is locked */ flags &= OPENONLY_STATE_MODES; err = iohelp_dup_iouser (&user, diruser->user); if (! err) { newpi = netfs_make_protid (netfs_make_peropen (np, flags, diruser->po), user); if (newpi) { *newfile = ports_get_right (newpi); *newfiletype = MACH_MSG_TYPE_MAKE_SEND; ports_port_deref (newpi); } else { err = errno; iohelp_free_iouser (user); } } netfs_nput (np); } return err; }
error_t netfs_S_io_restrict_auth (struct protid *user, mach_port_t *newport, mach_msg_type_name_t *newporttype, uid_t *uids, mach_msg_type_number_t nuids, gid_t *gids, mach_msg_type_number_t ngids) { error_t err; struct protid *newpi; struct iouser *new_user; if (!user) return EOPNOTSUPP; err = iohelp_restrict_iouser (&new_user, user->user, uids, nuids, gids, ngids); if (err) return err; refcount_ref (&user->po->refcnt); newpi = netfs_make_protid (user->po, new_user); if (newpi) { *newport = ports_get_right (newpi); *newporttype = MACH_MSG_TYPE_MAKE_SEND; } else { refcount_deref (&user->po->refcnt); iohelp_free_iouser (new_user); err = ENOMEM; } ports_port_deref (newpi); return err; }
kern_return_t trivfs_S_io_restrict_auth (struct trivfs_protid *cred, mach_port_t reply, mach_msg_type_name_t replytype, mach_port_t *newport, mach_msg_type_name_t *newporttype, uid_t *uids, size_t nuids, uid_t *gids, size_t ngids) { int i; error_t err; struct trivfs_protid *newcred; struct idvec *uvec, *gvec; struct iouser *user; if (!cred) return EOPNOTSUPP; if (cred->isroot) /* CRED has root access, and so may use any ids. */ { err = iohelp_create_complex_iouser (&user, uids, nuids, gids, ngids); if (err) return err; } else { uvec = make_idvec (); if (! uvec) return ENOMEM; gvec = make_idvec (); if (! gvec) { idvec_free (uvec); return ENOMEM; } /* Otherwise, use any of the requested ids that CRED already has. */ for (i = 0; i < cred->user->uids->num; i++) if (listmember (uids, cred->user->uids->ids[i], nuids)) { err = idvec_add (uvec, cred->user->uids->ids[i]); if (err) goto out; } for (i = 0; i < cred->user->gids->num; i++) if (listmember (gids, cred->user->gids->ids[i], ngids)) { err = idvec_add (gvec, cred->user->gids->ids[i]); if (err) goto out; } err = iohelp_create_iouser (&user, uvec, gvec); if (err) { out: idvec_free (uvec); idvec_free (gvec); return err; } } err = ports_create_port (cred->po->cntl->protid_class, cred->po->cntl->protid_bucket, sizeof (struct trivfs_protid), &newcred); if (err) { iohelp_free_iouser (user); return err; } newcred->isroot = 0; mutex_lock (&cred->po->cntl->lock); newcred->po = cred->po; newcred->po->refcnt++; mutex_unlock (&cred->po->cntl->lock); if (cred->isroot && idvec_contains (user->uids, 0)) newcred->isroot = 1; newcred->user = user; newcred->hook = cred->hook; err = io_restrict_auth (cred->realnode, &newcred->realnode, user->uids->ids, user->uids->num, user->gids->ids, user->gids->num); if (!err && trivfs_protid_create_hook) { err = (*trivfs_protid_create_hook) (newcred); if (err) mach_port_deallocate (mach_task_self (), newcred->realnode); } if (err) /* Signal that the user destroy hook shouldn't be called on NEWCRED. */ newcred->realnode = MACH_PORT_NULL; else { *newport = ports_get_right (newcred); *newporttype = MACH_MSG_TYPE_MAKE_SEND; } /* This will destroy NEWCRED if we got an error and didn't do the ports_get_right above. */ ports_port_deref (newcred); return 0; }
/* Return in FILE & FILE_TYPE the file in FSYS corresponding to the NFS file handle HANDLE & HANDLE_LEN. */ error_t diskfs_S_fsys_getfile (mach_port_t fsys, mach_port_t reply, mach_msg_type_name_t reply_type, uid_t *uids, mach_msg_type_number_t nuids, gid_t *gids, mach_msg_type_number_t ngids, char *handle, mach_msg_type_number_t handle_len, mach_port_t *file, mach_msg_type_name_t *file_type) { int flags; error_t err; struct node *node; const union diskfs_fhandle *f; struct protid *new_cred; struct peropen *new_po; struct iouser *user; struct port_info *pt = ports_lookup_port (diskfs_port_bucket, fsys, diskfs_control_class); if (!pt) return EOPNOTSUPP; if (handle_len != sizeof *f) { ports_port_deref (pt); return EINVAL; } f = (const union diskfs_fhandle *) handle; err = diskfs_cached_lookup (f->data.cache_id, &node); if (err) { ports_port_deref (pt); return err; } if (node->dn_stat.st_gen != f->data.gen) { diskfs_nput (node); ports_port_deref (pt); return ESTALE; } err = iohelp_create_complex_iouser (&user, uids, nuids, gids, ngids); if (err) { diskfs_nput (node); ports_port_deref (pt); return err; } flags = 0; if (! fshelp_access (&node->dn_stat, S_IREAD, user)) flags |= O_READ; if (! fshelp_access (&node->dn_stat, S_IEXEC, user)) flags |= O_EXEC; if (! fshelp_access (&node->dn_stat, S_IWRITE, user) && ! S_ISDIR (node->dn_stat.st_mode) && ! diskfs_check_readonly ()) flags |= O_WRITE; err = diskfs_make_peropen (node, flags, 0, &new_po); if (! err) { err = diskfs_create_protid (new_po, user, &new_cred); if (err) diskfs_release_peropen (new_po); } iohelp_free_iouser (user); diskfs_nput (node); ports_port_deref (pt); if (! err) { *file = ports_get_right (new_cred); *file_type = MACH_MSG_TYPE_MAKE_SEND; } return err; }
int main (int argc, char **argv, char **envp) { mach_port_t boot; error_t err; void *genport; process_t startup_port; mach_port_t startup; struct argp argp = { 0, 0, 0, "Hurd process server" }; argp_parse (&argp, argc, argv, 0, 0, 0); initialize_version_info (); err = task_get_bootstrap_port (mach_task_self (), &boot); assert_perror (err); if (boot == MACH_PORT_NULL) error (2, 0, "proc server can only be run by init during boot"); proc_bucket = ports_create_bucket (); proc_class = ports_create_class (0, 0); generic_port_class = ports_create_class (0, 0); exc_class = ports_create_class (exc_clean, 0); ports_create_port (generic_port_class, proc_bucket, sizeof (struct port_info), &genport); generic_port = ports_get_right (genport); /* Create the initial proc object for init (PID 1). */ init_proc = create_init_proc (); /* Create the startup proc object for /hurd/init (PID 2). */ startup_proc = allocate_proc (MACH_PORT_NULL); startup_proc->p_deadmsg = 1; complete_proc (startup_proc, HURD_PID_STARTUP); /* Create our own proc object. */ self_proc = allocate_proc (mach_task_self ()); assert (self_proc); complete_proc (self_proc, HURD_PID_PROC); startup_port = ports_get_send_right (startup_proc); err = startup_procinit (boot, startup_port, &startup_proc->p_task, &authserver, &_hurd_host_priv, &_hurd_device_master); assert_perror (err); mach_port_deallocate (mach_task_self (), startup_port); mach_port_mod_refs (mach_task_self (), authserver, MACH_PORT_RIGHT_SEND, 1); _hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], authserver); mach_port_deallocate (mach_task_self (), boot); proc_death_notify (startup_proc); add_proc_to_hash (startup_proc); /* Now that we have the task port. */ /* Set our own argv and envp locations. */ self_proc->p_argv = (vm_address_t) argv; self_proc->p_envp = (vm_address_t) envp; /* Give ourselves good scheduling performance, because we are so important. */ err = increase_priority (); if (err) error (0, err, "Increasing priority failed"); #if 0 err = register_new_task_notification (_hurd_host_priv, generic_port, MACH_MSG_TYPE_MAKE_SEND); if (err) error (0, err, "Registering task notifications failed"); #endif { /* Get our stderr set up to print on the console, in case we have to panic or something. */ mach_port_t cons; error_t err; err = device_open (_hurd_device_master, D_READ|D_WRITE, "console", &cons); assert_perror (err); stdin = mach_open_devstream (cons, "r"); stdout = stderr = mach_open_devstream (cons, "w"); mach_port_deallocate (mach_task_self (), cons); } startup = file_name_lookup (_SERVERS_STARTUP, 0, 0); if (MACH_PORT_VALID (startup)) { err = startup_essential_task (startup, mach_task_self (), MACH_PORT_NULL, "proc", _hurd_host_priv); if (err) /* Due to the single-threaded nature of /hurd/startup, it can only handle requests once the core server bootstrap has completed. Therefore, it does not bind itself to /servers/startup until it is ready. */ /* Fall back to abusing the message port lookup. */ startup_fallback = 1; err = mach_port_deallocate (mach_task_self (), startup); assert_perror (err); } else /* Fall back to abusing the message port lookup. */ startup_fallback = 1; while (1) ports_manage_port_operations_multithread (proc_bucket, message_demuxer, 0, 0, 0); }
kern_return_t trivfs_S_fsys_getroot (struct trivfs_control *cntl, mach_port_t reply_port, mach_msg_type_name_t reply_port_type, mach_port_t dotdot, uid_t *uids, size_t nuids, uid_t *gids, size_t ngids, int flags, retry_type *do_retry, char *retry_name, mach_port_t *newpt, mach_msg_type_name_t *newpttype) { int perms; error_t err = 0; mach_port_t new_realnode; struct trivfs_protid *cred; struct iouser *user; if (!cntl) return EOPNOTSUPP; if (trivfs_getroot_hook) { err = (*trivfs_getroot_hook) (cntl, reply_port, reply_port_type, dotdot, uids, nuids, gids, ngids, flags, do_retry, retry_name, newpt, newpttype); if (err != EAGAIN) return err; } if ((flags & O_WRITE & trivfs_allow_open) != (flags & O_WRITE)) return EROFS; if ((flags & (O_READ|O_WRITE|O_EXEC) & trivfs_allow_open) != (flags & (O_READ|O_WRITE|O_EXEC))) return EACCES; /* O_CREAT and O_EXCL are not meaningful here; O_NOLINK and O_NOTRANS will only be useful when trivfs supports translators (which it doesn't now). */ flags &= O_HURD; flags &= ~(O_CREAT|O_EXCL|O_NOLINK|O_NOTRANS); struct idvec idvec = { .ids = uids, .num = nuids, .alloced = nuids, }; if (_is_privileged (&idvec)) /* Privileged users should be given all our rights. */ err = io_duplicate (cntl->underlying, &new_realnode); else /* Non-privileged, restrict rights. */ err = io_restrict_auth (cntl->underlying, &new_realnode, uids, nuids, gids, ngids); if (err) return err; err = iohelp_create_complex_iouser (&user, uids, nuids, gids, ngids); if (err) return err; /* Validate permissions. */ if (! trivfs_check_access_hook) file_check_access (new_realnode, &perms); else (*trivfs_check_access_hook) (cntl, user, new_realnode, &perms); if ((flags & (O_READ|O_WRITE|O_EXEC) & perms) != (flags & (O_READ|O_WRITE|O_EXEC))) err = EACCES; if (!err && trivfs_check_open_hook) err = (*trivfs_check_open_hook) (cntl, user, flags); if (!err) { if (! trivfs_open_hook) { err = trivfs_open (cntl, user, flags, new_realnode, &cred); if (!err) mach_port_deallocate (mach_task_self (), dotdot); } else err = (*trivfs_open_hook) (cntl, user, dotdot, flags, new_realnode, &cred); } if (err) { mach_port_deallocate (mach_task_self (), new_realnode); iohelp_free_iouser (user); } else { *do_retry = FS_RETRY_NORMAL; *retry_name = '\0'; *newpt = ports_get_right (cred); *newpttype = MACH_MSG_TYPE_MAKE_SEND; ports_port_deref (cred); } return err; }
int main (int argc, char **argv, char **envp) { mach_port_t boot; error_t err; mach_port_t pset, psetcntl; void *genport; process_t startup_port; struct argp argp = { 0, 0, 0, "Hurd process server" }; argp_parse (&argp, argc, argv, 0, 0, 0); initialize_version_info (); err = task_get_bootstrap_port (mach_task_self (), &boot); assert_perror (err); if (boot == MACH_PORT_NULL) error (2, 0, "proc server can only be run by init during boot"); proc_bucket = ports_create_bucket (); proc_class = ports_create_class (0, 0); generic_port_class = ports_create_class (0, 0); exc_class = ports_create_class (exc_clean, 0); ports_create_port (generic_port_class, proc_bucket, sizeof (struct port_info), &genport); generic_port = ports_get_right (genport); /* Create the initial proc object for init (PID 1). */ startup_proc = create_startup_proc (); /* Create our own proc object (we are PID 0). */ self_proc = allocate_proc (mach_task_self ()); assert (self_proc); complete_proc (self_proc, 0); startup_port = ports_get_send_right (startup_proc); err = startup_procinit (boot, startup_port, &startup_proc->p_task, &authserver, &master_host_port, &master_device_port); assert_perror (err); mach_port_deallocate (mach_task_self (), startup_port); mach_port_mod_refs (mach_task_self (), authserver, MACH_PORT_RIGHT_SEND, 1); _hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], authserver); mach_port_deallocate (mach_task_self (), boot); proc_death_notify (startup_proc); add_proc_to_hash (startup_proc); /* Now that we have the task port. */ /* Set our own argv and envp locations. */ self_proc->p_argv = (vm_address_t) argv; self_proc->p_envp = (vm_address_t) envp; /* Give ourselves good scheduling performance, because we are so important. */ err = thread_get_assignment (mach_thread_self (), &pset); assert_perror (err); err = host_processor_set_priv (master_host_port, pset, &psetcntl); assert_perror (err); thread_max_priority (mach_thread_self (), psetcntl, 0); assert_perror (err); err = task_priority (mach_task_self (), 2, 1); assert_perror (err); mach_port_deallocate (mach_task_self (), pset); mach_port_deallocate (mach_task_self (), psetcntl); { /* Get our stderr set up to print on the console, in case we have to panic or something. */ mach_port_t cons; error_t err; err = device_open (master_device_port, D_READ|D_WRITE, "console", &cons); assert_perror (err); stdin = mach_open_devstream (cons, "r"); stdout = stderr = mach_open_devstream (cons, "w"); mach_port_deallocate (mach_task_self (), cons); } while (1) ports_manage_port_operations_multithread (proc_bucket, message_demuxer, 0, 0, 0); }
/* Receive data from a socket, possibly including Mach ports. */ error_t S_socket_recv (struct sock_user *user, mach_port_t *addr, mach_msg_type_name_t *addr_type, int in_flags, char **data, size_t *data_len, mach_port_t **ports, mach_msg_type_name_t *ports_type, size_t *num_ports, char **control, size_t *control_len, int *out_flags, size_t amount) { error_t err; unsigned flags; struct pipe *pipe; void *source_addr = NULL; if (!user) return EOPNOTSUPP; if (in_flags & MSG_OOB) /* BSD local sockets don't support OOB data. */ return EINVAL; /* XXX */ /* Fill in the pipe FLAGS from any corresponding ones in IN_FLAGS. */ flags = in_flags & MSG_PEEK; err = sock_acquire_read_pipe (user->sock, &pipe); if (err == EPIPE) /* EOF */ { *data_len = 0; if (num_ports) *num_ports = 0; if (control_len) *control_len = 0; } else if (!err) { err = pipe_recv (pipe, user->sock->flags & PFLOCAL_SOCK_NONBLOCK, &flags, &source_addr, data, data_len, amount, control, control_len, ports, num_ports); pipe_release_reader (pipe); } if (!err) /* Setup mach ports for return. */ { *addr_type = MACH_MSG_TYPE_MAKE_SEND; *ports_type = MACH_MSG_TYPE_MOVE_SEND; if (source_addr) { *addr = ports_get_right (source_addr); ports_port_deref (source_addr); /* since get_right has one too. */ } else *addr = MACH_PORT_NULL; } *out_flags = 0; return err; }
kern_return_t trivfs_S_dir_lookup (struct trivfs_protid *cred, mach_port_t reply, mach_msg_type_name_t reply_type, char *filename, int flags, mode_t mode, retry_type *retry_type, char *retry_name, mach_port_t *retrypt, mach_msg_type_name_t *retrypt_type) { int perms; error_t err; struct trivfs_protid *newcred; if (!cred) return EOPNOTSUPP; if (filename[0]) return ENOTDIR; /* This is a null-pathname "reopen" call; do the right thing. */ /* Burn off flags we don't actually implement */ flags &= O_HURD; flags &= ~(O_CREAT|O_EXCL|O_NOLINK|O_NOTRANS); /* Validate permissions */ if (! trivfs_check_access_hook) file_check_access (cred->realnode, &perms); else (*trivfs_check_access_hook) (cred->po->cntl, cred->user, cred->realnode, &perms); if ((flags & (O_READ|O_WRITE|O_EXEC) & perms) != (flags & (O_READ|O_WRITE|O_EXEC))) return EACCES; /* Execute the open */ err = 0; if (trivfs_check_open_hook) err = (*trivfs_check_open_hook) (cred->po->cntl, cred->user, flags); if (!err) { struct iouser *user; err = iohelp_dup_iouser (&user, cred->user); if (err) return err; err = trivfs_open (cred->po->cntl, user, flags, cred->realnode, &newcred); if (err) iohelp_free_iouser (user); else mach_port_mod_refs (mach_task_self (), cred->realnode, MACH_PORT_RIGHT_SEND, +1); } if (err) return err; *retry_type = FS_RETRY_NORMAL; *retry_name = '\0'; *retrypt = ports_get_right (newcred); *retrypt_type = MACH_MSG_TYPE_MAKE_SEND; ports_port_deref (newcred); return 0; }