#include #include #include #include #include #include #include #include #include #include #include #include #define MAXGLOBALMAILBOXES 50 #define MPERM_OWNER_READ 0x100 #define MPERM_OWNER_WRITE 0x080 #define MPERM_OWNER_ADMIN 0x040 #define MPERM_GROUP_READ 0x020 #define MPERM_GROUP_WRITE 0x010 #define MPERM_GROUP_ADMIN 0x008 #define MPERM_OTHER_READ 0x004 #define MPERM_OTHER_WRITE 0x002 #define MPERM_OTHER_ADMIN 0x001 #define MPERM_READ_ALLOWED 0x4 #define MPERM_WRITE_ALLOWED 0x2 #define MPERM_ADMIN_ALLOWED 0x1 MALLOC_DECLARE(M_MBOX); MALLOC_DEFINE(M_MBOX, "mailbox_system", "Buffers to hold mboxgr and mbox structs and their associated data"); // Function Prototypes //========================== static void mboxinit(void *dummy); struct mboxgr* find_gmboxgr(const char *name, const int flag); struct mboxgr* find_umboxgr(const uid_t uid, const int flag); int check_mperms(struct proc *p, int perms, uid_t owner, int numGroups, gid_t *groups); // Global Data //========================== struct sx all_gmboxgr_lock; struct sx all_umboxgr_lock; LIST_HEAD(mboxgrlist, mboxgr); struct mboxgrlist all_gmboxgr; struct mboxgrlist all_umboxgr; int numGlobalGroups; // Data Structures //============================ struct mboxgr { int type; // 0 for user, 1 for global char name[9]; // name of GLOBAL mboxgr int perms; // permissions uid_t owner; // uid of owner gid_t groups[NGROUPS+1]; // groups the owner belonged to when this mboxgr was created int numGroups; LIST_ENTRY(mboxgr) mlist; struct mbox *boxes[8]; int numBoxes; struct mtx m_mtx; // lock for this struct }; struct mbox { char name[256]; // name of mbox int perms; // permissions uid_t owner; // uid of owner gid_t groups[NGROUPS+1]; // groups the owner belonged to when this mboxgr was created int numGroups; char message[256]; // message in mbox int hasMessage; // 0 if mbox is empty, 1 if there is a message struct mtx m_mtx; struct cv *readable; // lock for this struct struct cv *writeable; }; // SUPPORT FUNCTIONS: //====================== static void mboxinit(dummy) void *dummy; { printf("mailbox: Initializing CSE422 Project0 mailbox subsystem.\n"); sx_init(&all_gmboxgr_lock, "allgmboxgr"); sx_init(&all_umboxgr_lock, "allumboxgr"); numGlobalGroups = 0; LIST_INIT(&all_gmboxgr); LIST_INIT(&all_umboxgr); } SYSINIT(mbox, SI_SUB_MBOX, SI_ORDER_ANY, mboxinit, NULL) struct mboxgr* find_gmboxgr(name, flag) const char *name; const int flag; { struct mboxgr *g; sx_assert(&all_gmboxgr_lock, SA_LOCKED); LIST_FOREACH(g, &all_gmboxgr, mlist) { if(strcmp(name, g->name) == 0) { if(flag) mtx_lock(&g->m_mtx); return g; } } return NULL; } struct mboxgr* find_umboxgr(uid, flag) const uid_t uid; const int flag; { struct mboxgr *g; sx_assert(&all_umboxgr_lock, SA_LOCKED); LIST_FOREACH(g, &all_umboxgr, mlist) { if(uid == g->owner) { if(flag) mtx_lock(&g->m_mtx); return g; } } return NULL; } int check_mperms(p,perms, owner, numGroups, groups) struct proc *p; int perms; uid_t owner; int numGroups; gid_t *groups; { int auth = 0; int haveCommonGroup = 0; PROC_LOCK_ASSERT(p, MA_OWNED); auth = perms & (MPERM_OTHER_READ | MPERM_OTHER_WRITE | MPERM_OTHER_ADMIN); if(owner == p->p_ucred->cr_ruid) auth = auth & ((perms & (MPERM_OWNER_READ | MPERM_OWNER_WRITE | MPERM_OWNER_ADMIN)) >> 6); for(int i = 0; i < p->p_ucred->cr_ngroups;i++) { for(int j = 0; j < numGroups; j++) { if(p->p_ucred->cr_groups[i] == groups[j]) { haveCommonGroup = 1; i = p->p_ucred->cr_ngroups; // set this to break out of outer loop. break; } } } if(haveCommonGroup) auth = auth & ((perms & (MPERM_GROUP_READ | MPERM_GROUP_WRITE | MPERM_GROUP_ADMIN)) >> 3); return auth; } // SYSTEM CALLS: //============================= //(int type, char *name, uid_t uid, int perms) int create_mboxgr(td, uap) struct thread *td; register struct create_mboxgr_args *uap; { struct mboxgr *g; uid_t targetUID; if(uap->type < 0 || uap->type > 1) return (EINVAL); if((uap->type == 0 && uap->name != NULL) || (uap->type == 1 && uap->name == NULL)) return (EINVAL); if((uap->type==1) && (uap->name[0]==0)) return (EINVAL); targetUID = uap->uid; if(uap->uid != 0) { if(priv_check_cred(td->td_ucred, PRIV_ROOT,0)!=0) return (EACCES); } else { targetUID = td->td_ucred->cr_ruid; } if(uap->type == 0) { sx_xlock(&all_umboxgr_lock); if((g = find_umboxgr(uap->uid, 0)) != NULL) { sx_xunlock(&all_umboxgr_lock); return (EINVAL); } MALLOC(g, struct mboxgr *, sizeof(struct mboxgr), M_MBOX, M_WAITOK); g->type = 0; g->name[0] = 0; g->perms = uap->perms; g->owner = targetUID; g->numBoxes = 0; mtx_init(&g->m_mtx,"struct mboxgr mutex",NULL, MTX_DEF); g->numGroups = td->td_ucred->cr_ngroups + 1; g->groups[0] = td->td_ucred->cr_rgid; for(int j =1; jnumGroups; j++) { g->groups[j] = td->td_ucred->cr_groups[j-1]; } LIST_INSERT_HEAD(&all_umboxgr, g, mlist); sx_xunlock(&all_umboxgr_lock); } else // (uap->type == 1) { sx_xlock(&all_gmboxgr_lock); if(numGlobalGroups == MAXGLOBALMAILBOXES) { sx_xunlock(&all_gmboxgr_lock); return (EPERM); } if((g = find_gmboxgr(uap->name, 0)) != NULL) { sx_xunlock(&all_gmboxgr_lock); return (EINVAL); } MALLOC(g, struct mboxgr *, sizeof(struct mboxgr), M_MBOX, M_WAITOK); g->type = 1; strncpy(uap->name, g->name, 8); g->name[8]=0; g->perms = uap->perms; //FIXME g->owner = targetUID; g->numBoxes = 0; mtx_init(&g->m_mtx,"struct mboxgr mutex",NULL, MTX_DEF); g->numGroups = td->td_ucred->cr_ngroups + 1; g->groups[0] = td->td_ucred->cr_rgid; for(int j =1; jnumGroups; j++) { g->groups[j] = td->td_ucred->cr_groups[j-1]; } LIST_INSERT_HEAD(&all_gmboxgr, g, mlist); numGlobalGroups++; sx_xunlock(&all_gmboxgr_lock); } return 0; } int destroy_mboxgr(td, uap) register struct thread *td; struct destroy_mboxgr_args *uap; //(int type, char *name, uid_t uid) { struct mboxgr *g; int authorization; int rootPrivs; if(uap->type < 0 || uap->type > 1) return (EINVAL); if((uap->type == 0 && uap->name != NULL) || (uap->type == 1 && uap->name == NULL)) return (EINVAL); if((uap->type==1) && (uap->name[0]==0)) return (EINVAL); if(priv_check_cred(td->td_ucred, PRIV_ROOT,0)==0) rootPrivs = 1; else rootPrivs = 0; if(uap->type == 1) { sx_xlock(&all_gmboxgr_lock); if((g = find_gmboxgr(uap->name, 1)) != NULL) { if(!rootPrivs) // root can destroy any mailbox group???? { PROC_LOCK(td->td_proc); authorization = check_mperms(td->td_proc,g->perms,g->owner,g->numGroups,g->groups); PROC_UNLOCK(td->td_proc); if((authorization & MPERM_ADMIN_ALLOWED) == 0) { mtx_unlock(&g->m_mtx); sx_xunlock(&all_gmboxgr_lock); return (EACCES); } } LIST_REMOVE(g, mlist); numGlobalGroups--; } else { sx_xunlock(&all_gmboxgr_lock); return 0; // No such group, so return success. } } else // uap->type == 0 { sx_xlock(&all_umboxgr_lock); if((g = find_umboxgr(uap->uid,1)) != NULL) { if(!rootPrivs) // root can destroy any mailbox group???? { PROC_LOCK(td->td_proc); authorization = check_mperms(td->td_proc,g->perms,g->owner,g->numGroups,g->groups); PROC_UNLOCK(td->td_proc); if((authorization & MPERM_ADMIN_ALLOWED) == 0) { mtx_unlock(&g->m_mtx); sx_xunlock(&all_gmboxgr_lock); return (EACCES); } } LIST_REMOVE(g, mlist); } else { sx_xunlock(&all_umboxgr_lock); return 0; // No such group, so return success. } } // replace this with calls to mbox_destroy() if neccessary to check we have perm. to delete each mbox?...? for(int i = 0; i < g->numBoxes; i++) { mtx_lock(&g->boxes[i]->m_mtx); cv_broadcast(g->boxes[i]->readable); cv_broadcast(g->boxes[i]->writeable); cv_destroy(g->boxes[i]->readable); cv_destroy(g->boxes[i]->writeable); mtx_destroy(&g->boxes[i]->m_mtx); FREE(g->boxes[i],M_MBOX); } mtx_destroy(&g->m_mtx); FREE(g,M_MBOX); if(uap->type == 0) sx_xunlock(&all_umboxgr_lock); else sx_xunlock(&all_gmboxgr_lock); return 0; } int join_mboxgr(td, uap) register struct thread *td; struct join_mboxgr_args *uap; //(char *name, pid_t pid) { struct mboxgr *g; struct proc* p; p = NULL; int authorization; int rootPrivs = 0; //int i; if(uap->name==NULL) return (EINVAL); if(uap->name[0]==0) return (EINVAL); if(priv_check_cred(td->td_ucred, PRIV_ROOT,0)==0) rootPrivs = 1; else rootPrivs = 0; if(uap->pid == 0) { p = td->td_proc; PROC_LOCK(p); } else //uap->pid != 0 { if((p = pfind(uap->pid)) == NULL) { return (ESRCH); } } sx_slock(&all_gmboxgr_lock); if((g = find_gmboxgr(uap->name,1)) != NULL) // uap->name is a valid global mailbox group name { if(!rootPrivs) // root can destroy any mailbox group???? { authorization = check_mperms(p,g->perms,g->owner,g->numGroups,g->groups); mtx_unlock(&g->m_mtx); if((authorization & (MPERM_READ_ALLOWED | MPERM_WRITE_ALLOWED)) == 0) { PROC_UNLOCK(p); sx_sunlock(&all_gmboxgr_lock); return (EACCES); } } mtx_unlock(&g->m_mtx); strncpy(uap->name, p->p_gmboxgr, 8); p->p_gmboxgr[8] = 0; PROC_UNLOCK(p); sx_sunlock(&all_gmboxgr_lock); } else { if(uap->name == NULL && (rootPrivs || (p->p_ucred->cr_ruid == td->td_ucred->cr_ruid))) { p->p_gmboxgr[0] = 0; PROC_UNLOCK(p); sx_sunlock(&all_gmboxgr_lock); } else { PROC_UNLOCK(p); sx_sunlock(&all_gmboxgr_lock); return (EACCES); } } return 0; } int create_mbox(td, uap) register struct thread *td; struct create_mbox_args *uap; //(int type, char *name, uid_t uid, int perms) { uid_t targetUID; struct mboxgr *g; struct mbox *b; struct proc* p; p = NULL; int authorization; int rootPrivs = 0; int i; if(uap->type < 0 || uap->type > 1) return (EINVAL); if(uap->name == NULL) return (EINVAL); if((uap->name[0])==0) return (EINVAL); if((uap->type == 1) && (td->td_proc->p_gmboxgr[0]==0)) return (EINVAL); if(strlen(uap->name)>255) return (E2BIG); if(priv_check_cred(td->td_ucred, PRIV_ROOT,0)==0) rootPrivs = 1; else rootPrivs = 0; if(uap->type == 1) { sx_slock(&all_gmboxgr_lock); g = find_gmboxgr(td->td_proc->p_gmboxgr,1); sx_sunlock(&all_gmboxgr_lock); } else // uap->type == 0 { targetUID = uap->uid; if(targetUID == 0) { targetUID = td->td_ucred->cr_ruid; } sx_slock(&all_umboxgr_lock); g = find_umboxgr(targetUID,1); sx_sunlock(&all_umboxgr_lock); } if(g == NULL) { return (EINVAL); // mailbox group not found } if(!rootPrivs) { PROC_LOCK(td->td_proc); authorization = check_mperms(td->td_proc,g->perms,g->owner,g->numGroups,g->groups); PROC_UNLOCK(td->td_proc); if((authorization & MPERM_ADMIN_ALLOWED) == 0) { mtx_unlock(&g->m_mtx); return (EACCES); // not allowed to create new mbox } } if(g->numBoxes == 8) { mtx_unlock(&g->m_mtx); return (EPERM); // not allowed to create any more mboxs } for(int i = 0; i < g->numBoxes; i++) { mtx_lock(&g->boxes[i]->m_mtx); if(strcmp(g->boxes[i]->name, uap->name) == 0) { mtx_unlock(&g->boxes[i]->m_mtx); mtx_unlock(&g->m_mtx); return (EINVAL); // already a box with that name } mtx_unlock(&g->boxes[i]->m_mtx); } MALLOC(b, struct mbox *, sizeof(struct mbox), M_MBOX, M_WAITOK); // dont use strncpy because it'd copy 255 bytes every time. for(i = 0; i < 255 && uap->name[i] != 0; i++) { b->name[i] = uap->name[i]; } b->name[i] = 0; b->perms = uap->perms; b->owner = td->td_ucred->cr_ruid; mtx_init(&b->m_mtx,"struct mbox mutex",NULL, MTX_DEF); cv_init(b->readable,"struct mbox readable condition variable"); cv_init(b->writeable,"struct mbox writable condition variable"); b->numGroups = td->td_ucred->cr_ngroups + 1; b->groups[0] = td->td_ucred->cr_rgid; for(int i =1; inumGroups; i++) { b->groups[i] = td->td_ucred->cr_groups[i-1]; } g->boxes[g->numBoxes++] = b; mtx_unlock(&g->m_mtx); return 0; } int destroy_mbox(td, uap) register struct thread *td; struct destroy_mbox_args *uap; //(int type, char *name, uid_t uid) { struct mboxgr *g; struct mbox *b; struct proc* p; uid_t targetUID; p = NULL; int authorization; int rootPrivs = 0; int i; int foundBox; if(uap->type < 0 || uap->type > 1) return (EINVAL); if(uap->name == NULL) return (EINVAL); if(uap->name[0]==0) return (EINVAL); if((uap->type == 1) && (td->td_proc->p_gmboxgr[0]==0)) return (EINVAL); if(strlen(uap->name)>255) return (E2BIG); if(priv_check_cred(td->td_ucred, PRIV_ROOT,0)==0) rootPrivs = 1; else rootPrivs = 0; if(uap->type == 1) { sx_slock(&all_gmboxgr_lock); g = find_gmboxgr(td->td_proc->p_gmboxgr,1); sx_sunlock(&all_gmboxgr_lock); } else // uap->type == 0 { targetUID = uap->uid; if(targetUID == 0) { targetUID = td->td_ucred->cr_ruid; } sx_slock(&all_umboxgr_lock); g = find_umboxgr(targetUID,1); sx_slock(&all_umboxgr_lock); } if(g == NULL) { return (EINVAL); // mailbox group not found } foundBox = 0; for(i = 0; i < g->numBoxes; i++) { mtx_lock(&g->boxes[i]->m_mtx); if(strcmp(g->boxes[i]->name, uap->name) == 0) { foundBox = 1; b = g->boxes[i]; break; } mtx_unlock(&g->boxes[i]->m_mtx); } if(!foundBox) { mtx_unlock(&g->m_mtx); return (EINVAL); // mailbox not found } if(!rootPrivs) { PROC_LOCK(td->td_proc); authorization = check_mperms(td->td_proc,b->perms,b->owner,b->numGroups,b->groups); PROC_UNLOCK(td->td_proc); if((authorization & MPERM_ADMIN_ALLOWED) == 0) { mtx_unlock(&b->m_mtx); mtx_unlock(&g->m_mtx); return (EACCES); // not allowed to create new mbox } } if(i != ((g->numBoxes)-1)) { g->boxes[i] = g->boxes[(g->numBoxes)-1]; } g->boxes[(g->numBoxes)-1] = NULL; g->numBoxes--; cv_broadcast(b->readable); cv_broadcast(b->writeable); cv_destroy(b->readable); cv_destroy(b->writeable); mtx_destroy(&b->m_mtx); FREE(b,M_MBOX); mtx_unlock(&g->m_mtx); return 0; } int write_mbox(td, uap) register struct thread *td; struct write_mbox_args *uap; //(int type, char *name, uid_t uid, char *message, int flag) { struct mbox *b; struct proc* p; struct mboxgr *g; uid_t targetUID; p = NULL; int authorization; int rootPrivs = 0; int i; int foundBox; if(uap->type < 0 || uap->type > 1) return (EINVAL); if(uap->name == NULL) return (EINVAL); if(uap->name[0]==0) return (EINVAL); if((uap->type == 1) && (td->td_proc->p_gmboxgr[0]==0)) return (EINVAL); if(strlen(uap->name)>255) return (E2BIG); if(strlen(uap->message)>255) return (E2BIG); if(priv_check_cred(td->td_ucred, PRIV_ROOT,0)==0) rootPrivs = 1; else rootPrivs = 0; do { if(uap->type == 1) { sx_slock(&all_gmboxgr_lock); g = find_gmboxgr(td->td_proc->p_gmboxgr,1); sx_sunlock(&all_gmboxgr_lock); } else // uap->type == 0 { targetUID = uap->uid; if(targetUID == 0) { targetUID = td->td_ucred->cr_ruid; } sx_slock(&all_umboxgr_lock); g = find_umboxgr(targetUID,1); sx_sunlock(&all_umboxgr_lock); } if(g == NULL) { return (EINVAL); // mailbox group not found } foundBox = 0; b=NULL; for(i = 0; i < g->numBoxes; i++) { mtx_lock(&g->boxes[i]->m_mtx); if(strcmp(g->boxes[i]->name, uap->name) == 0) { foundBox = 1; b = g->boxes[i]; break; } mtx_unlock(&g->boxes[i]->m_mtx); } mtx_unlock(&g->m_mtx); if(!foundBox) { return (EINVAL); // mailbox not found } if(!rootPrivs) { PROC_LOCK(td->td_proc); authorization = check_mperms(td->td_proc,b->perms,b->owner,b->numGroups,b->groups); PROC_UNLOCK(td->td_proc); if((authorization & (MPERM_WRITE_ALLOWED)) == 0) { mtx_unlock(&b->m_mtx); return (EACCES); // not allowed to create new mbox } } if(b->hasMessage == 0) { //write message b->hasMessage = 1; cv_broadcast(b->readable); mtx_unlock(&b->m_mtx); return 0; } if(uap->flag) { mtx_unlock(&b->m_mtx); return (EWOULDBLOCK); } cv_wait_unlock(b->writeable, &b->m_mtx); } while(1); return 0;//should never get here } int read_mbox(td, uap) register struct thread *td; struct read_mbox_args *uap; //(int type, char *name, uid_t uid, char *message, int len, int flag) { struct mbox *b; struct proc* p; struct mboxgr *g; uid_t targetUID; p = NULL; int authorization; int rootPrivs = 0; int i; int foundBox; if(uap->type < 0 || uap->type > 1) return (EINVAL); if(uap->name == NULL) return (EINVAL); if(uap->name[0]==0) return (EINVAL); if((uap->type == 1) && (td->td_proc->p_gmboxgr[0]==0)) return (EINVAL); if(strlen(uap->name)>255) return (E2BIG); if(strlen(uap->message)>255) return (E2BIG); if(priv_check_cred(td->td_ucred, PRIV_ROOT,0)==0) rootPrivs = 1; else rootPrivs = 0; do { if(uap->type == 1) { sx_slock(&all_gmboxgr_lock); g = find_gmboxgr(td->td_proc->p_gmboxgr,1); sx_sunlock(&all_gmboxgr_lock); } else // uap->type == 0 { targetUID = uap->uid; if(targetUID == 0) { targetUID = td->td_ucred->cr_ruid; } sx_slock(&all_umboxgr_lock); g = find_umboxgr(targetUID,1); sx_sunlock(&all_umboxgr_lock); } if(g == NULL) { return (EINVAL); // mailbox group not found } foundBox = 0; b=NULL; for(i = 0; i < g->numBoxes; i++) { mtx_lock(&g->boxes[i]->m_mtx); if(strcmp(g->boxes[i]->name, uap->name) == 0) { foundBox = 1; b = g->boxes[i]; break; } mtx_unlock(&g->boxes[i]->m_mtx); } mtx_unlock(&g->m_mtx); if(!foundBox) { return (EINVAL); // mailbox not found } if(!rootPrivs) { PROC_LOCK(td->td_proc); authorization = check_mperms(td->td_proc,b->perms,b->owner,b->numGroups,b->groups); PROC_UNLOCK(td->td_proc); if((authorization & (MPERM_READ_ALLOWED)) == 0) { mtx_unlock(&b->m_mtx); return (EACCES); // not allowed to create new mbox } } if(b->hasMessage == 1) { //read message b->hasMessage = 0; cv_broadcast(b->writeable); mtx_unlock(&b->m_mtx); return 0; } if(uap->flag) { mtx_unlock(&b->m_mtx); return (EWOULDBLOCK); } mtx_unlock(&b->m_mtx); cv_wait_unlock(b->readable, &b->m_mtx); } while(1); } int clear_mbox(td, uap) register struct thread *td; struct clear_mbox_args *uap; //(int type, char *name, uid_t uid) { struct mboxgr *g; struct mbox *b; struct proc* p; uid_t targetUID; p = NULL; int authorization; int rootPrivs = 0; int i; int foundBox; if(uap->type < 0 || uap->type > 1) return (EINVAL); if(uap->name == NULL) return (EINVAL); if(uap->name[0]==0) return (EINVAL); if((uap->type == 1) && (td->td_proc->p_gmboxgr[0]==0)) return (E2BIG); if(strlen(uap->name)>255) return (E2BIG); if(priv_check_cred(td->td_ucred, PRIV_ROOT,0)==0) rootPrivs = 1; else rootPrivs = 0; if(uap->type == 1) { sx_slock(&all_gmboxgr_lock); g = find_gmboxgr(td->td_proc->p_gmboxgr,1); sx_sunlock(&all_gmboxgr_lock); } else // uap->type == 0 { targetUID = uap->uid; if(targetUID == 0) { targetUID = td->td_ucred->cr_ruid; } sx_slock(&all_umboxgr_lock); g = find_umboxgr(targetUID,1); sx_sunlock(&all_umboxgr_lock); } if(g == NULL) { return (EINVAL); // mailbox group not found } foundBox = 0; b=NULL; for(i = 0; i < g->numBoxes; i++) { mtx_lock(&g->boxes[i]->m_mtx); if(strcmp(g->boxes[i]->name, uap->name) == 0) { foundBox = 1; b = g->boxes[i]; break; } mtx_unlock(&g->boxes[i]->m_mtx); } mtx_unlock(&g->m_mtx); if(!foundBox) { return (EINVAL); // mailbox not found } if(!rootPrivs) { PROC_LOCK(td->td_proc); authorization = check_mperms(td->td_proc,b->perms,b->owner,b->numGroups,b->groups); PROC_UNLOCK(td->td_proc); if((authorization & (MPERM_ADMIN_ALLOWED|MPERM_READ_ALLOWED)) == 0) { mtx_unlock(&b->m_mtx); return (EACCES); // not allowed to create new mbox } } b->hasMessage = 0; cv_broadcast(b->readable); cv_broadcast(b->writeable); mtx_unlock(&b->m_mtx); return 0; }