diff --git a/servers/vfs/device.c b/servers/vfs/device.c index f9809c17e..c304c30b7 100644 --- a/servers/vfs/device.c +++ b/servers/vfs/device.c @@ -621,30 +621,48 @@ message *mess_ptr; /* pointer to message for task */ int r, proc_e; - if(task_nr == SYSTEM) printf("VFS: sending %d to SYSTEM\n", mess_ptr->m_type); - - proc_e = mess_ptr->IO_ENDPT; - r = sendrec(task_nr, mess_ptr); - if(r == OK && mess_ptr->REP_STATUS == ERESTART) r = EDEADEPT; - if (r != OK) { - if (r == EDEADSRCDST || r == EDEADEPT) { - printf("fs: dead driver %d\n", task_nr); - dmap_unmap_by_endpt(task_nr); - return(r); - } - if (r == ELOCKED) { - printf("fs: ELOCKED talking to %d\n", task_nr); - return(r); - } - panic("call_task: can't send/receive: %d", r); + if(task_nr == SYSTEM) { + printf("VFS: sending %d to SYSTEM\n", mess_ptr->m_type); } - /* Did the process we did the sendrec() for get a result? */ - if (mess_ptr->REP_ENDPT != proc_e) { - printf("fs: strange device reply from %d, type = %d, proc = %d " - "(not %d) (2) ignored\n", mess_ptr->m_source, mess_ptr->m_type, - proc_e, mess_ptr->REP_ENDPT); - return(EIO); + proc_e = mess_ptr->IO_ENDPT; + + for (;;) { + + r = sendrec(task_nr, mess_ptr); + if(r == OK && mess_ptr->REP_STATUS == ERESTART) r = EDEADEPT; + if (r != OK) { + if (r == EDEADSRCDST || r == EDEADEPT) { + printf("fs: dead driver %d\n", task_nr); + dmap_unmap_by_endpt(task_nr); + return(r); + } + if (r == ELOCKED) { + printf("fs: ELOCKED talking to %d\n", task_nr); + return(r); + } + panic("call_task: can't send/receive: %d", r); + } + + /* Did the process we did the sendrec() for get a result? */ + if (mess_ptr->REP_ENDPT != proc_e && VFS_PROC_NR != proc_e) { + + printf("fs: strange device reply from %d, type = %d, " + "proc = %d (not %d) (2) ignored\n", mess_ptr->m_source, + mess_ptr->m_type, proc_e, mess_ptr->REP_ENDPT); + + return(EIO); + } + + if (mess_ptr->m_type == TASK_REPLY || + IS_DEV_RS(mess_ptr->m_type) || + mess_ptr->m_type <= 0) { + + break; /* reply */ + } else { + + nested_dev_call(mess_ptr); + } } return(OK); diff --git a/servers/vfs/exec.c b/servers/vfs/exec.c index 334f1f097..c6fccecad 100644 --- a/servers/vfs/exec.c +++ b/servers/vfs/exec.c @@ -115,7 +115,7 @@ vir_bytes *pc; progname[PROC_NAME_LEN-1] = '\0'; /* Open executable */ - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); if ((vp->v_mode & I_TYPE) != I_REGULAR) r = ENOEXEC; diff --git a/servers/vfs/filedes.c b/servers/vfs/filedes.c index a6c677969..65da4bcf6 100644 --- a/servers/vfs/filedes.c +++ b/servers/vfs/filedes.c @@ -1,14 +1,22 @@ /* This file contains the procedures that manipulate file descriptors. * * The entry points into this file are - * get_fd: look for free file descriptor and free filp slots - * get_filp: look up the filp entry for a given file descriptor - * find_filp: find a filp slot that points to a given vnode - * inval_filp: invalidate a filp and associated fd's, only let close() - * happen on it + * get_fd: look for free file descriptor and free filp slots + * get_filp: look up the filp entry for a given file descriptor + * find_filp: find a filp slot that points to a given vnode + * inval_filp: invalidate a filp and associated fd's, only let close() + * happen on it + * do_verify_fd: verify whether the given file descriptor is valid for + * the given endpoint. + * do_set_filp: marks a filp as in-flight. + * do_copy_filp: copies a filp to another endpoint. + * do_put_filp: marks a filp as not in-flight anymore. + * do_cancel_fd: cancel the transaction when something goes wrong for + * the receiver. */ #include +#include #include #include #include "fs.h" @@ -139,3 +147,205 @@ PUBLIC int invalidate(struct filp *fp) return(n); /* Report back how often this filp has been invalidated. */ } + +/*===========================================================================* + * verify_fd * + *===========================================================================*/ +PUBLIC filp_id_t verify_fd(ep, fd) +endpoint_t ep; +int fd; +{ + /* + * verify whether the given file descriptor 'fd' is valid for the + * endpoint 'ep'. When the file descriptor is valid verify_fd returns a + * pointer to that filp, else it returns NULL. + */ + int proc; + + if (isokendpt(ep, &proc) != OK) { + return NULL; + } + + return get_filp2(&fproc[proc], fd); +} + +/*===========================================================================* + * do_verify_fd * + *===========================================================================*/ +PUBLIC int do_verify_fd(void) +{ + m_out.ADDRESS = (void *) verify_fd(m_in.IO_ENDPT, m_in.COUNT); + return (m_out.ADDRESS != NULL) ? OK : EINVAL; +} + +/*===========================================================================* + * set_filp * + *===========================================================================*/ +PUBLIC int set_filp(sfilp) +filp_id_t sfilp; +{ + if (sfilp == NULL) { + return EINVAL; + } else { + sfilp->filp_count++; + return OK; + } +} + +/*===========================================================================* + * do_set_filp * + *===========================================================================*/ +PUBLIC int do_set_filp(void) +{ + return set_filp((filp_id_t) m_in.ADDRESS);; +} + +/*===========================================================================* + * copy_filp * + *===========================================================================*/ +PUBLIC int copy_filp(to_ep, cfilp) +endpoint_t to_ep; +filp_id_t cfilp; +{ + int j; + int proc; + + if (isokendpt(to_ep, &proc) != OK) { + return EINVAL; + } + + /* Find an open slot in fp_filp */ + for (j = 0; j < OPEN_MAX; j++) { + if (fproc[proc].fp_filp[j] == NULL && + !FD_ISSET(j, &fproc[proc].fp_filp_inuse)) { + + /* Found a free slot, add descriptor */ + FD_SET(j, &fproc[proc].fp_filp_inuse); + fproc[proc].fp_filp[j] = cfilp; + fproc[proc].fp_filp[j]->filp_count++; + return j; + } + } + + /* File Descriptor Table is Full */ + return EMFILE; +} + +/*===========================================================================* + * do_copy_filp * + *===========================================================================*/ +PUBLIC int do_copy_filp(void) +{ + return copy_filp(m_in.IO_ENDPT, (filp_id_t) m_in.ADDRESS); +} + +/*===========================================================================* + * put_filp * + *===========================================================================*/ +PUBLIC int put_filp(pfilp) +filp_id_t pfilp; +{ + if (pfilp == NULL) { + return EINVAL; + } else { + close_filp(pfilp); + return OK; + } +} + +/*===========================================================================* + * do_put_filp * + *===========================================================================*/ +PUBLIC int do_put_filp(void) +{ + return put_filp((filp_id_t) m_in.ADDRESS); +} + +/*===========================================================================* + * cancel_fd * + *===========================================================================*/ +PUBLIC int cancel_fd(ep, fd) +endpoint_t ep; +int fd; +{ + int j; + int proc; + + if (isokendpt(ep, &proc) != OK) { + return EINVAL; + } + + /* Check that the input 'fd' is valid */ + if (verify_fd(ep, fd) != NULL) { + + /* Found a valid descriptor, remove it */ + FD_CLR(fd, &fproc[proc].fp_filp_inuse); + fproc[proc].fp_filp[fd]->filp_count--; + fproc[proc].fp_filp[fd] = NULL; + + return fd; + } + + /* File descriptor is not valid for the endpoint. */ + return EINVAL; +} + +/*===========================================================================* + * do_cancel_fd * + *===========================================================================*/ +PUBLIC int do_cancel_fd(void) +{ + return cancel_fd(m_in.IO_ENDPT, m_in.COUNT); +} + +/*===========================================================================* + * close_filp * + *===========================================================================*/ +PUBLIC void close_filp(fp) +struct filp *fp; +{ + int mode_word, rw; + dev_t dev; + struct vnode *vp; + + vp = fp->filp_vno; + if (fp->filp_count - 1 == 0 && fp->filp_mode != FILP_CLOSED) { + /* Check to see if the file is special. */ + mode_word = vp->v_mode & I_TYPE; + if (mode_word == I_CHAR_SPECIAL || mode_word == I_BLOCK_SPECIAL) { + dev = (dev_t) vp->v_sdev; + if (mode_word == I_BLOCK_SPECIAL) { + if (vp->v_bfs_e == ROOT_FS_E) { + /* Invalidate the cache unless the special is + * mounted. Assume that the root filesystem's + * is open only for fsck. + */ + req_flush(vp->v_bfs_e, dev); + } + } + /* Do any special processing on device close. */ + (void) dev_close(dev, fp-filp); + /* Ignore any errors, even SUSPEND. */ + + fp->filp_mode = FILP_CLOSED; + } + } + + /* If the inode being closed is a pipe, release everyone hanging on it. */ + if (vp->v_pipe == I_PIPE) { + rw = (fp->filp_mode & R_BIT ? WRITE : READ); + release(vp, rw, NR_PROCS); + } + + /* If a write has been done, the inode is already marked as DIRTY. */ + if (--fp->filp_count == 0) { + if (vp->v_pipe == I_PIPE) { + /* Last reader or writer is going. Tell PFS about latest + * pipe size. + */ + truncate_vnode(vp, vp->v_size); + } + + put_vnode(fp->filp_vno); + } +} diff --git a/servers/vfs/fscall.c b/servers/vfs/fscall.c index 9ba3fe7ec..c6026ef4a 100644 --- a/servers/vfs/fscall.c +++ b/servers/vfs/fscall.c @@ -3,6 +3,8 @@ * * The entry points into this file are * nested_fs_call perform a nested call from a file system server + * nested_dev_call perform a nested call from a device driver server + * */ #include "fs.h" @@ -11,6 +13,7 @@ #include #include #include +#include /* maximum nested call stack depth */ #define MAX_DEPTH 1 @@ -149,3 +152,51 @@ message *m; /* request/reply message pointer */ m->m_type = r; } + +/*===========================================================================* + * nested_dev_call * + *===========================================================================*/ +PUBLIC void nested_dev_call(m) +message *m; /* request/reply message pointer */ +{ +/* Handle a nested call from a device driver server. + */ + int r; + + /* Save global variables of the current call */ + if ((r = push_globals()) != OK) { + printf("VFS: error saving globals in call %d from driver %d\n", + m->m_type, m->m_source); + } else { + /* Initialize global variables for the nested call */ + set_globals(m); + + if (call_nr >= PFS_BASE) { + call_nr -= PFS_BASE; + } + + /* Perform the nested call */ + if (call_nr < 0 || call_nr >= PFS_NREQS) { + + printf("VFS: invalid nested call %d from driver %d\n", + call_nr, who_e); + + r = ENOSYS; + } else if (who_e == PFS_PROC_NR) { + + r = (*pfs_call_vec[call_nr])(); + } else { + + printf("VFS: only the PFS device can make nested VFS calls\n"); + + r = ENOSYS; + } + + /* Store the result, and restore original global variables */ + *m = m_out; + + pop_globals(); + } + + m->m_type = r; +} diff --git a/servers/vfs/glo.h b/servers/vfs/glo.h index 737f1c938..f6f54b1ca 100644 --- a/servers/vfs/glo.h +++ b/servers/vfs/glo.h @@ -34,5 +34,6 @@ EXTERN int err_code; /* temporary storage for error number */ /* Data initialized elsewhere. */ extern _PROTOTYPE (int (*call_vec[]), (void) ); /* sys call table */ +extern _PROTOTYPE (int (*pfs_call_vec[]), (void) ); /* pfs callback table */ extern char dot1[2]; /* dot1 (&dot1[0]) and dot2 (&dot2[0]) have a special */ extern char dot2[3]; /* meaning to search_dir: no access permission check. */ diff --git a/servers/vfs/link.c b/servers/vfs/link.c index 3b8a6171f..bb0c148e1 100644 --- a/servers/vfs/link.c +++ b/servers/vfs/link.c @@ -34,12 +34,12 @@ PUBLIC int do_link() /* See if 'name1' (file to be linked to) exists. */ if(fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); /* Does the final directory of 'name2' exist? */ if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) r = err_code; - else if ((vp_d = last_dir()) == NULL) + else if ((vp_d = last_dir(fp)) == NULL) r = err_code; if (r != OK) { put_vnode(vp); @@ -76,7 +76,7 @@ PUBLIC int do_unlink() /* Get the last directory in the path. */ if(fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code); - if ((vldirp = last_dir()) == NULL) return(err_code); + if ((vldirp = last_dir(fp)) == NULL) return(err_code); /* Make sure that the object is a directory */ if((vldirp->v_mode & I_TYPE) != I_DIRECTORY) { @@ -94,7 +94,7 @@ PUBLIC int do_unlink() user is allowed to unlink */ if ((vldirp->v_mode & S_ISVTX) == S_ISVTX) { /* Look up inode of file to unlink to retrieve owner */ - vp = advance(vldirp, PATH_RET_SYMLINK); + vp = advance(vldirp, PATH_RET_SYMLINK, fp); if (vp != NULL) { if(vp->v_uid != fp->fp_effuid && fp->fp_effuid != SU_UID) r = EPERM; @@ -129,13 +129,13 @@ PUBLIC int do_rename() /* See if 'name1' (existing file) exists. Get dir and file inodes. */ if(fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ((old_dirp = last_dir()) == NULL) return(err_code); + if ((old_dirp = last_dir(fp)) == NULL) return(err_code); /* If the sticky bit is set, only the owner of the file or a privileged user is allowed to rename */ if((old_dirp->v_mode & S_ISVTX) == S_ISVTX) { /* Look up inode of file to unlink to retrieve owner */ - vp = advance(old_dirp, PATH_RET_SYMLINK); + vp = advance(old_dirp, PATH_RET_SYMLINK, fp); if (vp != NULL) { if(vp->v_uid != fp->fp_effuid && fp->fp_effuid != SU_UID) r = EPERM; @@ -158,7 +158,7 @@ PUBLIC int do_rename() /* See if 'name2' (new name) exists. Get dir inode */ if(fetch_name(m_in.name2, m_in.name2_length, M1) != OK) r = err_code; - else if ((new_dirp = last_dir()) == NULL) + else if ((new_dirp = last_dir(fp)) == NULL) r = err_code; if (r != OK) { put_vnode(old_dirp); @@ -198,7 +198,7 @@ PUBLIC int do_truncate() /* Temporarily open file */ if (fetch_name(m_in.m2_p1, m_in.m2_i1, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); /* Ask FS to truncate the file */ if ((r = forbidden(vp, W_BIT)) == OK) @@ -259,7 +259,7 @@ PUBLIC int do_slink() /* Get dir inode of 'name2' */ if(fetch_name(m_in.name2, m_in.name2_length, M1) != OK) return(err_code); - if ((vp = last_dir()) == NULL) return(err_code); + if ((vp = last_dir(fp)) == NULL) return(err_code); if ((r = forbidden(vp, W_BIT|X_BIT)) == OK) { r = req_slink(vp->v_fs_e, vp->v_inode_nr, user_fullpath, who_e, @@ -271,6 +271,32 @@ PUBLIC int do_slink() return(r); } +/*===========================================================================* + * rdlink_direct * + *===========================================================================*/ +PUBLIC int rdlink_direct(orig_path, link_path, rfp) +char *orig_path; +char *link_path; /* should have length PATH_MAX+1 */ +struct fproc *rfp; +{ +/* Perform a readlink()-like call from within the VFS */ + int r; + struct vnode *vp; + + /* Temporarily open the file containing the symbolic link */ + strncpy(user_fullpath, orig_path, PATH_MAX); + if ((vp = eat_path(PATH_RET_SYMLINK, rfp)) == NULL) return(err_code); + + /* Make sure this is a symbolic link */ + if((vp->v_mode & I_TYPE) != I_SYMBOLIC_LINK) + r = EINVAL; + else + r = req_rdlink(vp->v_fs_e, vp->v_inode_nr, (endpoint_t) 0, + link_path, PATH_MAX+1, 1); + + put_vnode(vp); + return r; +} /*===========================================================================* * do_rdlink * @@ -286,13 +312,14 @@ PUBLIC int do_rdlink() /* Temporarily open the file containing the symbolic link */ if(fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_RET_SYMLINK)) == NULL) return(err_code); + if ((vp = eat_path(PATH_RET_SYMLINK, fp)) == NULL) return(err_code); /* Make sure this is a symbolic link */ if((vp->v_mode & I_TYPE) != I_SYMBOLIC_LINK) r = EINVAL; else - r = req_rdlink(vp->v_fs_e, vp->v_inode_nr, who_e, m_in.name2, copylen); + r = req_rdlink(vp->v_fs_e, vp->v_inode_nr, who_e, m_in.name2, + copylen, 0); put_vnode(vp); return(r); diff --git a/servers/vfs/mount.c b/servers/vfs/mount.c index 6a731a5cc..5064be82f 100644 --- a/servers/vfs/mount.c +++ b/servers/vfs/mount.c @@ -213,7 +213,7 @@ PRIVATE int mount_fs(endpoint_t fs_e) /* Now get the inode of the file to be mounted on. */ if (fetch_name(m_in.name2, m_in.name2_length, M1)!=OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); if (vp->v_ref_count != 1) { put_vnode(vp); return(EBUSY); @@ -254,7 +254,7 @@ PRIVATE int mount_fs(endpoint_t fs_e) if(!replace_root) { /* Get vnode of mountpoint */ - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); if (vp->v_ref_count != 1) { put_vnode(vp); @@ -451,7 +451,8 @@ PUBLIC int unmount( panic("unmount: strange fs endpoint: %d", vmp->m_fs_e); if ((r = req_unmount(vmp->m_fs_e)) != OK) /* Not recoverable. */ - printf("VFS: ignoring failed umount attempt (%d)\n", r); + printf("VFS: ignoring failed umount attempt (%d) fs pid: %d\n", r, + _ENDPOINT_P(vmp->m_fs_e)); if (is_nonedev(vmp->m_dev)) free_nonedev(vmp->m_dev); @@ -507,7 +508,7 @@ PRIVATE dev_t name_to_dev(int allow_mountpt) struct vnode *vp; /* Request lookup */ - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) { + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) { return(NO_DEV); } diff --git a/servers/vfs/open.c b/servers/vfs/open.c index 1ef32ca35..ae116b252 100644 --- a/servers/vfs/open.c +++ b/servers/vfs/open.c @@ -104,7 +104,7 @@ PRIVATE int common_open(register int oflags, mode_t omode) flag is set this is an error */ } else { /* Scan path name */ - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); } /* Claim the file descriptor and filp slot and fill them in. */ @@ -254,10 +254,10 @@ PRIVATE struct vnode *new_node(int oflags, mode_t bits) if (oflags & O_EXCL) flags |= PATH_RET_SYMLINK; /* See if the path can be opened down to the last directory. */ - if ((dirp = last_dir()) == NULL) return(NULL); + if ((dirp = last_dir(fp)) == NULL) return(NULL); /* The final directory is accessible. Get final component of the path. */ - vp = advance(dirp, flags); + vp = advance(dirp, flags, fp); /* The combination of a symlink with absolute path followed by a danglink * symlink results in a new path that needs to be re-resolved entirely. */ @@ -280,7 +280,7 @@ PRIVATE struct vnode *new_node(int oflags, mode_t bits) struct vnode *slp, *old_wd; /* Resolve path up to symlink */ - slp = advance(dirp, PATH_RET_SYMLINK); + slp = advance(dirp, PATH_RET_SYMLINK, fp); if (slp != NULL) { if (S_ISLNK(slp->v_mode)) { /* Get contents of link */ @@ -291,7 +291,7 @@ PRIVATE struct vnode *new_node(int oflags, mode_t bits) slp->v_inode_nr, VFS_PROC_NR, user_fullpath, - max_linklen); + max_linklen, 0); if (r < 0) { /* Failed to read link */ put_vnode(slp); @@ -406,7 +406,7 @@ PUBLIC int do_mknod() /* Open directory that's going to hold the new node. */ if(fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if((vp = last_dir()) == NULL) return(err_code); + if((vp = last_dir(fp)) == NULL) return(err_code); /* Make sure that the object is a directory */ if((vp->v_mode & I_TYPE) != I_DIRECTORY) { @@ -439,7 +439,7 @@ PUBLIC int do_mkdir() bits = I_DIRECTORY | (m_in.mode & RWX_MODES & fp->fp_umask); /* Request lookup */ - if((vp = last_dir()) == NULL) return(err_code); + if((vp = last_dir(fp)) == NULL) return(err_code); /* Make sure that the object is a directory */ if ((vp->v_mode & I_TYPE) != I_DIRECTORY) { @@ -596,60 +596,6 @@ int fd_nr; return(OK); } - -/*===========================================================================* - * close_filp * - *===========================================================================*/ -PUBLIC void close_filp(fp) -struct filp *fp; -{ - int mode_word, rw; - dev_t dev; - struct vnode *vp; - - vp = fp->filp_vno; - if (fp->filp_count - 1 == 0 && fp->filp_mode != FILP_CLOSED) { - /* Check to see if the file is special. */ - mode_word = vp->v_mode & I_TYPE; - if (mode_word == I_CHAR_SPECIAL || mode_word == I_BLOCK_SPECIAL) { - dev = (dev_t) vp->v_sdev; - if (mode_word == I_BLOCK_SPECIAL) { - if (vp->v_bfs_e == ROOT_FS_E) { - /* Invalidate the cache unless the special is - * mounted. Assume that the root filesystem's - * is open only for fsck. - */ - req_flush(vp->v_bfs_e, dev); - } - } - /* Do any special processing on device close. */ - (void) dev_close(dev, fp-filp); - /* Ignore any errors, even SUSPEND. */ - - fp->filp_mode = FILP_CLOSED; - } - } - - /* If the inode being closed is a pipe, release everyone hanging on it. */ - if (vp->v_pipe == I_PIPE) { - rw = (fp->filp_mode & R_BIT ? WRITE : READ); - release(vp, rw, NR_PROCS); - } - - /* If a write has been done, the inode is already marked as DIRTY. */ - if (--fp->filp_count == 0) { - if (vp->v_pipe == I_PIPE) { - /* Last reader or writer is going. Tell PFS about latest - * pipe size. - */ - truncate_vnode(vp, vp->v_size); - } - - put_vnode(fp->filp_vno); - } -} - - /*===========================================================================* * close_reply * *===========================================================================*/ diff --git a/servers/vfs/path.c b/servers/vfs/path.c index c85af71f7..3bd7f6019 100644 --- a/servers/vfs/path.c +++ b/servers/vfs/path.c @@ -13,6 +13,9 @@ #include #include #include +#include +#include +#include #include "fproc.h" #include "vmnt.h" #include "vnode.h" @@ -29,14 +32,15 @@ #define DO_POSIX_PATHNAME_RES 0 FORWARD _PROTOTYPE( int lookup, (struct vnode *dirp, int flags, - node_details_t *node) ); + node_details_t *node, struct fproc *rfp)); /*===========================================================================* * advance * *===========================================================================*/ -PUBLIC struct vnode *advance(dirp, flags) +PUBLIC struct vnode *advance(dirp, flags, rfp) struct vnode *dirp; int flags; +struct fproc *rfp; { /* Resolve a pathname (in user_fullpath) starting at dirp to a vnode. */ int r; @@ -50,7 +54,7 @@ int flags; if((new_vp = get_free_vnode()) == NULL) return(NULL); /* Lookup vnode belonging to the file. */ - if ((r = lookup(dirp, flags, &res)) != OK) { + if ((r = lookup(dirp, flags, &res, rfp)) != OK) { err_code = r; return(NULL); } @@ -86,21 +90,23 @@ int flags; /*===========================================================================* * eat_path * *===========================================================================*/ -PUBLIC struct vnode *eat_path(flags) +PUBLIC struct vnode *eat_path(flags, rfp) int flags; +struct fproc *rfp; { /* Resolve 'user_fullpath' to a vnode. advance does the actual work. */ struct vnode *vp; - vp = (user_fullpath[0] == '/' ? fp->fp_rd : fp->fp_wd); - return advance(vp, flags); + vp = (user_fullpath[0] == '/' ? rfp->fp_rd : rfp->fp_wd); + return advance(vp, flags, rfp); } /*===========================================================================* - * last_dir * + * last_dir * *===========================================================================*/ -PUBLIC struct vnode *last_dir(void) +PUBLIC struct vnode *last_dir(rfp) +struct fproc *rfp; { /* Parse a path, 'user_fullpath', as far as the last directory, fetch the vnode * for the last directory into the vnode table, and return a pointer to the @@ -117,7 +123,7 @@ PUBLIC struct vnode *last_dir(void) struct vnode *vp, *res; /* Is the path absolute or relative? Initialize 'vp' accordingly. */ - vp = (user_fullpath[0] == '/' ? fp->fp_rd : fp->fp_wd); + vp = (user_fullpath[0] == '/' ? rfp->fp_rd : rfp->fp_wd); len = strlen(user_fullpath); @@ -155,7 +161,7 @@ PUBLIC struct vnode *last_dir(void) cp--; } - res = advance(vp, PATH_NOFLAGS); + res = advance(vp, PATH_NOFLAGS, rfp); if (res == NULL) return(NULL); /* Copy the directory entry back to user_fullpath */ @@ -168,10 +174,11 @@ PUBLIC struct vnode *last_dir(void) /*===========================================================================* * lookup * *===========================================================================*/ -PRIVATE int lookup(start_node, flags, node) +PRIVATE int lookup(start_node, flags, node, rfp) struct vnode *start_node; int flags; node_details_t *node; +struct fproc *rfp; { /* Resolve a pathname (in user_fullpath) relative to start_node. */ @@ -191,8 +198,8 @@ node_details_t *node; return(ENOENT); } - if(!fp->fp_rd || !fp->fp_wd) { - printf("VFS: lookup_rel %d: no rd/wd\n", fp->fp_endpoint); + if(!rfp->fp_rd || !rfp->fp_wd) { + printf("VFS: lookup_rel %d: no rd/wd\n", rfp->fp_endpoint); return(ENOENT); } @@ -201,19 +208,19 @@ node_details_t *node; /* Is the process' root directory on the same partition?, * if so, set the chroot directory too. */ - if (fp->fp_rd->v_dev == fp->fp_wd->v_dev) - root_ino = fp->fp_rd->v_inode_nr; + if (rfp->fp_rd->v_dev == rfp->fp_wd->v_dev) + root_ino = rfp->fp_rd->v_inode_nr; else root_ino = 0; /* Set user and group ids according to the system call */ - uid = (call_nr == ACCESS ? fp->fp_realuid : fp->fp_effuid); - gid = (call_nr == ACCESS ? fp->fp_realgid : fp->fp_effgid); + uid = (call_nr == ACCESS ? rfp->fp_realuid : rfp->fp_effuid); + gid = (call_nr == ACCESS ? rfp->fp_realgid : rfp->fp_effgid); symloop = 0; /* Number of symlinks seen so far */ /* Issue the request */ - r = req_lookup(fs_e, dir_ino, root_ino, uid, gid, flags, &res); + r = req_lookup(fs_e, dir_ino, root_ino, uid, gid, flags, &res, rfp); if (r != OK && r != EENTERMOUNT && r != ELEAVEMOUNT && r != ESYMLINK) return(r); /* i.e., an error occured */ @@ -234,7 +241,7 @@ node_details_t *node; /* Symlink encountered with absolute path */ if (r == ESYMLINK) { - dir_vp = fp->fp_rd; + dir_vp = rfp->fp_rd; } else if (r == EENTERMOUNT) { /* Entering a new partition */ dir_vp = 0; @@ -278,12 +285,12 @@ node_details_t *node; /* Is the process' root directory on the same partition?, * if so, set the chroot directory too. */ - if(dir_vp->v_dev == fp->fp_rd->v_dev) - root_ino = fp->fp_rd->v_inode_nr; + if(dir_vp->v_dev == rfp->fp_rd->v_dev) + root_ino = rfp->fp_rd->v_inode_nr; else root_ino = 0; - r = req_lookup(fs_e, dir_ino, root_ino, uid, gid, flags, &res); + r = req_lookup(fs_e, dir_ino, root_ino, uid, gid, flags, &res, rfp); if(r != OK && r != EENTERMOUNT && r != ELEAVEMOUNT && r != ESYMLINK) return(r); @@ -300,3 +307,229 @@ node_details_t *node; return(r); } + +/*===========================================================================* + * get_name * + *===========================================================================*/ +PUBLIC int get_name(dirp, entry, ename) +struct vnode *dirp; +struct vnode *entry; +char ename[NAME_MAX + 1]; +{ + u64_t pos = {0, 0}, new_pos; + int r, consumed, totalbytes; + char buf[(sizeof(struct dirent) + NAME_MAX) * 8]; + struct dirent *cur; + + if ((dirp->v_mode & I_TYPE) != I_DIRECTORY) { + return(EBADF); + } + + do { + r = req_getdents(dirp->v_fs_e, dirp->v_inode_nr, pos, + buf, sizeof(buf), &new_pos, 1); + + if (r == 0) { + return(ENOENT); /* end of entries -- matching inode !found */ + } else if (r < 0) { + return(r); /* error */ + } + + consumed = 0; /* bytes consumed */ + totalbytes = r; /* number of bytes to consume */ + + do { + cur = (struct dirent *) (buf + consumed); + if (entry->v_inode_nr == cur->d_ino) { + /* found the entry we were looking for */ + strncpy(ename, cur->d_name, NAME_MAX); + ename[NAME_MAX] = '\0'; + return(OK); + } + + /* not a match -- move on to the next dirent */ + consumed += cur->d_reclen; + } while (consumed < totalbytes); + + pos = new_pos; + } while (1); +} + +/*===========================================================================* + * canonical_path * + *===========================================================================*/ +PUBLIC int canonical_path(orig_path, canon_path, rfp) +char *orig_path; +char *canon_path; /* should have length PATH_MAX+1 */ +struct fproc *rfp; +{ + int len = 0; + int r, symloop = 0; + struct vnode *dir_vp, *parent_dir; + char component[NAME_MAX+1]; + char link_path[PATH_MAX+1]; + + dir_vp = NULL; + strncpy(user_fullpath, orig_path, PATH_MAX); + + do { + if (dir_vp) put_vnode(dir_vp); + + /* Resolve to the last directory holding the socket file */ + if ((dir_vp = last_dir(rfp)) == NULL) { + return(err_code); + } + + /* dir_vp points to dir and user_fullpath now contains only the + * filename. + */ + strcpy(canon_path, user_fullpath); /* Store file name */ + + /* check if the file is a symlink, if so resolve it */ + r = rdlink_direct(canon_path, link_path, rfp); + if (r <= 0) { + strcpy(user_fullpath, canon_path); + break; + } + + /* encountered a symlink -- loop again */ + strcpy(user_fullpath, link_path); + + symloop++; + } while (symloop < SYMLOOP_MAX); + + if (symloop >= SYMLOOP_MAX) { + if (dir_vp) put_vnode(dir_vp); + return ELOOP; + } + + while(dir_vp != rfp->fp_rd) { + + strcpy(user_fullpath, ".."); + + /* check if we're at the root node of the file system */ + if (dir_vp->v_vmnt->m_root_node == dir_vp) { + put_vnode(dir_vp); + dir_vp = dir_vp->v_vmnt->m_mounted_on; + dup_vnode(dir_vp); + } + + if ((parent_dir = advance(dir_vp, PATH_NOFLAGS, rfp)) == NULL) { + put_vnode(dir_vp); + return(err_code); + } + + /* now we have to retrieve the name of the parent directory */ + if (get_name(parent_dir, dir_vp, component) != OK) { + put_vnode(dir_vp); + put_vnode(parent_dir); + return(ENOENT); + } + + len += strlen(component) + 1; + if (len > PATH_MAX) { + /* adding the component to canon_path would exceed PATH_MAX */ + put_vnode(dir_vp); + put_vnode(parent_dir); + return(ENOMEM); + } + + /* store result of component in canon_path */ + + /* first make space by moving the contents of canon_path to + * the right. Move strlen + 1 bytes to include the terminating '\0'. + */ + memmove(canon_path+strlen(component)+1, canon_path, + strlen(canon_path) + 1); + + /* Copy component into canon_path */ + memmove(canon_path, component, strlen(component)); + + /* Put slash into place */ + canon_path[strlen(component)] = '/'; + + /* Store parent_dir result, and continue the loop once more */ + put_vnode(dir_vp); + dir_vp = parent_dir; + } + + put_vnode(dir_vp); + + /* add the leading slash */ + if (strlen(canon_path) >= PATH_MAX) return(ENAMETOOLONG); + memmove(canon_path+1, canon_path, strlen(canon_path)); + canon_path[0] = '/'; + + return(OK); +} + +/*===========================================================================* + * check_perms * + *===========================================================================*/ +PUBLIC int check_perms(ep, io_gr, pathlen) +endpoint_t ep; +cp_grant_id_t io_gr; +int pathlen; +{ + int r, i; + struct vnode *vp; + struct fproc *rfp; + char orig_path[PATH_MAX+1]; + char canon_path[PATH_MAX+1]; + + i = _ENDPOINT_P(ep); + if (pathlen < UNIX_PATH_MAX || pathlen > PATH_MAX || i < 0 || i >= NR_PROCS) { + return EINVAL; + } + rfp = &(fproc[i]); + + memset(canon_path, '\0', PATH_MAX+1); + + r = sys_safecopyfrom(PFS_PROC_NR, io_gr, (vir_bytes) 0, + (vir_bytes) &user_fullpath, pathlen, D); + if (r != OK) { + return r; + } + user_fullpath[pathlen] = '\0'; + + /* save path from pfs before permissions checking modifies it */ + memcpy(orig_path, user_fullpath, PATH_MAX+1); + + /* get the canonical path to the socket file */ + r = canonical_path(orig_path, canon_path, rfp); + if (r != OK) { + return r; + } + + if (strlen(canon_path) >= pathlen) { + return ENAMETOOLONG; + } + + /* copy canon_path back to PFS */ + r = sys_safecopyto(PFS_PROC_NR, (cp_grant_id_t) io_gr, (vir_bytes) 0, + (vir_bytes) canon_path, strlen(canon_path)+1, + D); + if (r != OK) { + return r; + } + + /* reload user_fullpath for permissions checking */ + memcpy(user_fullpath, orig_path, PATH_MAX+1); + if ((vp = eat_path(PATH_NOFLAGS, rfp)) == NULL) { + return(err_code); + } + + /* check permissions */ + r = forbidden(vp, (R_BIT | W_BIT)); + + put_vnode(vp); + return(r); +} + +/*===========================================================================* + * do_check_perms * + *===========================================================================*/ +PUBLIC int do_check_perms(void) +{ + return check_perms(m_in.IO_ENDPT, (cp_grant_id_t) m_in.IO_GRANT, m_in.COUNT); +} diff --git a/servers/vfs/protect.c b/servers/vfs/protect.c index 83b116944..558cf4f90 100644 --- a/servers/vfs/protect.c +++ b/servers/vfs/protect.c @@ -18,8 +18,6 @@ #include "vnode.h" #include "vmnt.h" -FORWARD _PROTOTYPE( int in_group, (gid_t grp) ); - /*===========================================================================* * do_chmod * *===========================================================================*/ @@ -35,7 +33,7 @@ PUBLIC int do_chmod() if (call_nr == CHMOD) { /* Temporarily open the file */ if(fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); } else { /* call_nr == FCHMOD */ /* File is already opened; get a pointer to vnode from filp. */ if (!(flp = get_filp(m_in.fd))) return(err_code); @@ -85,7 +83,7 @@ PUBLIC int do_chown() if (call_nr == CHOWN) { /* Temporarily open the file. */ if(fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); } else { /* call_nr == FCHOWN */ /* File is already opened; get a pointer to the vnode from filp. */ if (!(flp = get_filp(m_in.fd))) return(err_code); @@ -152,7 +150,7 @@ PUBLIC int do_access() /* Temporarily open the file. */ if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); r = forbidden(vp, m_in.mode); put_vnode(vp); @@ -196,7 +194,7 @@ PUBLIC int forbidden(struct vnode *vp, mode_t access_desired) } else { if (uid == vp->v_uid) shift = 6; /* owner */ else if (gid == vp->v_gid) shift = 3; /* group */ - else if (in_group(vp->v_gid) == OK) shift = 3; /* suppl. groups */ + else if (in_group(fp, vp->v_gid) == OK) shift = 3; /* suppl. groups */ else shift = 0; /* other */ perm_bits = (bits >> shift) & (R_BIT | W_BIT | X_BIT); } @@ -215,22 +213,6 @@ PUBLIC int forbidden(struct vnode *vp, mode_t access_desired) return(r); } - -/*===========================================================================* - * in_group * - *===========================================================================*/ -PRIVATE int in_group(gid_t grp) -{ - int i; - - for (i = 0; i < fp->fp_ngroups; i++) - if (fp->fp_sgroups[i] == grp) - return(OK); - - return(EINVAL); -} - - /*===========================================================================* * read_only * *===========================================================================*/ diff --git a/servers/vfs/proto.h b/servers/vfs/proto.h index 10fd86194..1cb17b9ca 100644 --- a/servers/vfs/proto.h +++ b/servers/vfs/proto.h @@ -10,6 +10,8 @@ struct fproc; struct vmnt; struct vnode; +typedef struct filp * filp_id_t; + /* device.c */ _PROTOTYPE( int dev_open, (dev_t dev, int proc, int flags) ); _PROTOTYPE( int dev_reopen, (dev_t dev, int filp_no, int flags) ); @@ -54,9 +56,21 @@ _PROTOTYPE( int get_fd, (int start, mode_t bits, int *k, _PROTOTYPE( struct filp *get_filp, (int fild) ); _PROTOTYPE( struct filp *get_filp2, (struct fproc *rfp, int fild) ); _PROTOTYPE( int invalidate, (struct filp *) ); +_PROTOTYPE( filp_id_t verify_fd, (endpoint_t ep, int fd) ); +_PROTOTYPE( int do_verify_fd, (void) ); +_PROTOTYPE( int set_filp, (filp_id_t sfilp) ); +_PROTOTYPE( int do_set_filp, (void) ); +_PROTOTYPE( int copy_filp, (endpoint_t to_ep, filp_id_t cfilp) ); +_PROTOTYPE( int do_copy_filp, (void) ); +_PROTOTYPE( int put_filp, (filp_id_t pfilp) ); +_PROTOTYPE( int do_put_filp, (void) ); +_PROTOTYPE( int cancel_fd, (endpoint_t ep, int fd) ); +_PROTOTYPE( int do_cancel_fd, (void) ); +_PROTOTYPE( void close_filp, (struct filp *fp) ); /* fscall.c */ _PROTOTYPE( void nested_fs_call, (message *m) ); +_PROTOTYPE( void nested_dev_call, (message *m) ); /* link.c */ _PROTOTYPE( int do_link, (void) ); @@ -64,7 +78,9 @@ _PROTOTYPE( int do_unlink, (void) ); _PROTOTYPE( int do_rename, (void) ); _PROTOTYPE( int do_truncate, (void) ); _PROTOTYPE( int do_ftruncate, (void) ); -_PROTOTYPE( int truncate_vnode, (struct vnode *vp, off_t newsize) ); +_PROTOTYPE( int truncate_vnode, (struct vnode *vp, off_t newsize) ); +_PROTOTYPE( int rdlink_direct, (char *orig_path, char *link_path, + struct fproc *rfp) ); /* lock.c */ _PROTOTYPE( int lock_op, (struct filp *f, int req) ); @@ -99,7 +115,6 @@ _PROTOTYPE( int unmount, (dev_t dev, char *label) ); /* open.c */ _PROTOTYPE( int do_close, (void) ); _PROTOTYPE( int close_fd, (struct fproc *rfp, int fd_nr) ); -_PROTOTYPE( void close_filp, (struct filp *fp) ); _PROTOTYPE( void close_reply, (void) ); _PROTOTYPE( int do_creat, (void) ); _PROTOTYPE( int do_lseek, (void) ); @@ -112,9 +127,17 @@ _PROTOTYPE( int do_vm_open, (void) ); _PROTOTYPE( int do_vm_close, (void) ); /* path.c */ -_PROTOTYPE( struct vnode *advance, (struct vnode *dirp, int flags) ); -_PROTOTYPE( struct vnode *eat_path, (int flags) ); -_PROTOTYPE( struct vnode *last_dir, (void) ); +_PROTOTYPE( struct vnode *advance, (struct vnode *dirp, int flags, + struct fproc *rfp) ); +_PROTOTYPE( struct vnode *eat_path, (int flags, struct fproc *rfp) ); +_PROTOTYPE( struct vnode *last_dir, (struct fproc *rfp) ); +_PROTOTYPE( int get_name, (struct vnode *dirp, struct vnode *entry, + char *_name) ); +_PROTOTYPE( int canonical_path, (char *orig_path, char *canon_path, + struct fproc *rfp) ); +_PROTOTYPE( int check_perms, (endpoint_t ep, cp_grant_id_t gid, + int strlen) ); +_PROTOTYPE( int do_check_perms, (void) ); /* pipe.c */ _PROTOTYPE( int do_pipe, (void) ); @@ -168,14 +191,15 @@ _PROTOTYPE( int req_fstatfs, (int fs_e, int who_e, char *buf) ); _PROTOTYPE( int req_statvfs, (int fs_e, int who_e, char *buf) ); _PROTOTYPE( int req_ftrunc, (endpoint_t fs_e, ino_t inode_nr, off_t start, off_t end) ); -_PROTOTYPE( int req_getdents, (endpoint_t fs_e, ino_t inode_nr, u64_t pos, - char *buf, size_t size, u64_t *new_pos) ); +_PROTOTYPE( int req_getdents, (endpoint_t fs_e, ino_t inode_nr, + u64_t pos, char *buf, size_t size, + u64_t *new_pos, int direct) ); _PROTOTYPE( int req_inhibread, (endpoint_t fs_e, ino_t inode_nr) ); _PROTOTYPE( int req_link, (endpoint_t fs_e, ino_t link_parent, char *lastc, ino_t linked_file) ); _PROTOTYPE( int req_lookup, (endpoint_t fs_e, ino_t dir_ino, ino_t root_ino, uid_t uid, gid_t gid, int flags, - lookup_res_t *res) ); + lookup_res_t *res, struct fproc *rfp) ); _PROTOTYPE( int req_mkdir, (endpoint_t fs_e, ino_t inode_nr, char *lastc, uid_t uid, gid_t gid, mode_t dmode) ); _PROTOTYPE( int req_mknod, (endpoint_t fs_e, ino_t inode_nr, @@ -187,7 +211,8 @@ _PROTOTYPE( int req_newnode, (endpoint_t fs_e, uid_t uid, dev_t dev, struct node_details *res) ); _PROTOTYPE( int req_putnode, (int fs_e, ino_t inode_nr, int count) ); _PROTOTYPE( int req_rdlink, (endpoint_t fs_e, ino_t inode_nr, - endpoint_t who_e, char *buf, size_t len) ); + endpoint_t who_e, char *buf, size_t len, + int direct) ); _PROTOTYPE( int req_readsuper, (endpoint_t fs_e, char *driver_name, dev_t dev, int readonly, int isroot, struct node_details *res_nodep) ); @@ -236,6 +261,7 @@ _PROTOTYPE( long conv4, (int norm, long x) ); _PROTOTYPE( int fetch_name, (char *path, int len, int flag) ); _PROTOTYPE( int no_sys, (void) ); _PROTOTYPE( int isokendpt_f, (char *f, int l, endpoint_t e, int *p, int ft)); +_PROTOTYPE( int in_group, (struct fproc *rfp, gid_t grp) ); #define okendpt(e, p) isokendpt_f(__FILE__, __LINE__, (e), (p), 1) #define isokendpt(e, p) isokendpt_f(__FILE__, __LINE__, (e), (p), 0) diff --git a/servers/vfs/read.c b/servers/vfs/read.c index 9b6853ac3..06bf6dcf2 100644 --- a/servers/vfs/read.c +++ b/servers/vfs/read.c @@ -168,7 +168,7 @@ PUBLIC int do_getdents() panic("do_getdents: should handle large offsets"); r = req_getdents(rfilp->filp_vno->v_fs_e, rfilp->filp_vno->v_inode_nr, - rfilp->filp_pos, m_in.buffer, m_in.nbytes, &new_pos); + rfilp->filp_pos, m_in.buffer, m_in.nbytes, &new_pos, 0); if (r > 0) rfilp->filp_pos = new_pos; diff --git a/servers/vfs/request.c b/servers/vfs/request.c index cdd208da4..ecc01ee89 100644 --- a/servers/vfs/request.c +++ b/servers/vfs/request.c @@ -283,16 +283,25 @@ PUBLIC int req_getdents( u64_t pos, char *buf, size_t size, - u64_t *new_pos + u64_t *new_pos, + int direct ) { int r; message m; cp_grant_id_t grant_id; - - grant_id = cpf_grant_magic(fs_e, who_e, (vir_bytes) buf, size, CPF_WRITE); + + if (direct) { + grant_id = cpf_grant_direct(fs_e, (vir_bytes) buf, size, + CPF_WRITE); + } else { + grant_id = cpf_grant_magic(fs_e, who_e, (vir_bytes) buf, size, + CPF_WRITE); + } + if (grant_id < 0) - panic("req_getdents: cpf_grant_magic failed: %d", grant_id); + panic("req_getdents: cpf_grant_direct/cpf_grant_magic failed: %d", + grant_id); m.m_type = REQ_GETDENTS; m.REQ_INODE_NR = inode_nr; @@ -312,7 +321,6 @@ PUBLIC int req_getdents( return(r); } - /*===========================================================================* * req_inhibread * *===========================================================================*/ @@ -373,7 +381,8 @@ PUBLIC int req_lookup( uid_t uid, gid_t gid, int flags, - lookup_res_t *res + lookup_res_t *res, + struct fproc *rfp ) { int r; @@ -396,16 +405,16 @@ PUBLIC int req_lookup( m.REQ_DIR_INO = dir_ino; m.REQ_ROOT_INO = root_ino; - if(fp->fp_ngroups > 0) { /* Is the process member of multiple groups? */ + if(rfp->fp_ngroups > 0) { /* Is the process member of multiple groups? */ /* In that case the FS has to copy the uid/gid credentials */ int i; /* Set credentials */ - credentials.vu_uid = fp->fp_effuid; - credentials.vu_gid = fp->fp_effgid; - credentials.vu_ngroups = fp->fp_ngroups; - for (i = 0; i < fp->fp_ngroups; i++) - credentials.vu_sgroups[i] = fp->fp_sgroups[i]; + credentials.vu_uid = rfp->fp_effuid; + credentials.vu_gid = rfp->fp_effgid; + credentials.vu_ngroups = rfp->fp_ngroups; + for (i = 0; i < rfp->fp_ngroups; i++) + credentials.vu_sgroups[i] = rfp->fp_sgroups[i]; grant_id2 = cpf_grant_direct(fs_e, (vir_bytes) &credentials, sizeof(credentials), CPF_READ); @@ -427,7 +436,7 @@ PUBLIC int req_lookup( /* Send/rec request */ r = fs_sendrec(fs_e, &m); cpf_revoke(grant_id); - if(fp->fp_ngroups > 0) cpf_revoke(grant_id2); + if(rfp->fp_ngroups > 0) cpf_revoke(grant_id2); /* Fill in response according to the return value */ res->fs_e = m.m_source; @@ -653,18 +662,24 @@ int count; /*===========================================================================* * req_rdlink * *===========================================================================*/ -PUBLIC int req_rdlink(fs_e, inode_nr, who_e, buf, len) +PUBLIC int req_rdlink(fs_e, inode_nr, who_e, buf, len, direct) endpoint_t fs_e; ino_t inode_nr; endpoint_t who_e; char *buf; size_t len; +int direct; /* set to 1 to use direct grants instead of magic grants */ { message m; int r; cp_grant_id_t grant_id; - grant_id = cpf_grant_magic(fs_e, who_e, (vir_bytes) buf, len, CPF_WRITE); + if (direct) { + grant_id = cpf_grant_direct(fs_e, (vir_bytes) buf, len, CPF_WRITE); + } else { + grant_id = cpf_grant_magic(fs_e, who_e, (vir_bytes) buf, len, + CPF_WRITE); + } if(grant_id == -1) panic("req_rdlink: cpf_grant_magic failed"); diff --git a/servers/vfs/stadir.c b/servers/vfs/stadir.c index 3805f63db..55d80c290 100644 --- a/servers/vfs/stadir.c +++ b/servers/vfs/stadir.c @@ -80,7 +80,7 @@ int len; /* length of the directory name string */ /* Try to open the directory */ if (fetch_name(name_ptr, len, M3) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); return change_into(iip, vp); } @@ -123,7 +123,7 @@ PUBLIC int do_stat() struct vnode *vp; if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); r = req_stat(vp->v_fs_e, vp->v_inode_nr, who_e, m_in.name2, 0); put_vnode(vp); @@ -181,7 +181,7 @@ PUBLIC int do_statvfs() struct vnode *vp; if (fetch_name(m_in.STATVFS_NAME, m_in.STATVFS_LEN, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); r = req_statvfs(vp->v_fs_e, who_e, m_in.STATVFS_BUF); put_vnode(vp); @@ -214,7 +214,7 @@ PUBLIC int do_lstat() int r; if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_RET_SYMLINK)) == NULL) return(err_code); + if ((vp = eat_path(PATH_RET_SYMLINK, fp)) == NULL) return(err_code); r = req_stat(vp->v_fs_e, vp->v_inode_nr, who_e, m_in.name2, 0); put_vnode(vp); diff --git a/servers/vfs/table.c b/servers/vfs/table.c index 2c7c3e413..c46a04cca 100644 --- a/servers/vfs/table.c +++ b/servers/vfs/table.c @@ -133,3 +133,13 @@ PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = { /* This should not fail with "array size is negative": */ extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 : -1]; +PUBLIC _PROTOTYPE (int (*pfs_call_vec[]), (void) ) = { + + no_sys, /* 0 */ + do_check_perms, /* 1 */ + do_verify_fd, /* 2 */ + do_set_filp, /* 3 */ + do_copy_filp, /* 4 */ + do_put_filp, /* 5 */ + do_cancel_fd /* 6 */ +}; diff --git a/servers/vfs/time.c b/servers/vfs/time.c index cf279ddac..749581cba 100644 --- a/servers/vfs/time.c +++ b/servers/vfs/time.c @@ -32,7 +32,7 @@ PUBLIC int do_utime() /* Temporarily open the file */ if (fetch_name(m_in.utime_file, len, M1) != OK) return(err_code); - if ((vp = eat_path(PATH_NOFLAGS)) == NULL) return(err_code); + if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code); /* Only the owner of a file or the super user can change its name. */ r = OK; diff --git a/servers/vfs/utility.c b/servers/vfs/utility.c index 296fe1bee..0c99b8ef0 100644 --- a/servers/vfs/utility.c +++ b/servers/vfs/utility.c @@ -8,6 +8,7 @@ * panic: something awful has occurred; MINIX cannot continue * conv2: do byte swapping on a 16-bit int * conv4: do byte swapping on a 32-bit long + * in_group: determines if group 'grp' is in rfp->fp_sgroups[] */ #include "fs.h" @@ -140,3 +141,19 @@ PUBLIC time_t clock_time() return( (time_t) (boottime + (uptime/system_hz))); } +/*===========================================================================* + * in_group * + *===========================================================================*/ +PUBLIC int in_group(struct fproc *rfp, gid_t grp) +{ + int i; + + for (i = 0; i < rfp->fp_ngroups; i++) { + if (rfp->fp_sgroups[i] == grp) { + return(OK); + } + } + + return(EINVAL); +} +