#include enum {DENY_NONE, DENY_READ, DENY_WRITE, DENY_ALL, DENY_DOS, DENY_FCB}; enum {AFAIL,AREAD,AWRITE,AALL}; enum {DOSxxx, DOS_OPEN_RDONLY, DOS_OPEN_WRONLY, DOS_OPEN_RDWR}; #define BOOL int /******************************************************************* reproduce the share mode access table this is horrendoously complex, and really can't be justified on any rational grounds except that this is _exactly_ what NT does. See the DENY1 and DENY2 tests in smbtorture for a comprehensive set of test routines. ********************************************************************/ static int access_table1(int new_deny,int old_deny,int old_mode, BOOL same_pid, BOOL isexe) { if (new_deny == DENY_ALL || old_deny == DENY_ALL) return(AFAIL); if (same_pid) { if (isexe && old_mode == DOS_OPEN_RDONLY && old_deny == DENY_DOS && new_deny == DENY_READ) { return AFAIL; } if (!isexe && old_mode == DOS_OPEN_RDONLY && old_deny == DENY_DOS && new_deny == DENY_DOS) { return AREAD; } if (new_deny == DENY_FCB && old_deny == DENY_DOS) { if (isexe) return AFAIL; if (old_mode == DOS_OPEN_RDONLY) return AFAIL; return AALL; } if (old_mode == DOS_OPEN_RDONLY && old_deny == DENY_DOS) { if (new_deny == DENY_FCB || new_deny == DENY_READ) { if (isexe) return AREAD; return AFAIL; } } if (old_deny == DENY_FCB) { if (new_deny == DENY_DOS || new_deny == DENY_FCB) return AALL; return AFAIL; } } if (old_deny == DENY_DOS || new_deny == DENY_DOS || old_deny == DENY_FCB || new_deny == DENY_FCB) { if (isexe) { if (old_deny == DENY_FCB || new_deny == DENY_FCB) { return AFAIL; } if (old_deny == DENY_DOS) { if (new_deny == DENY_READ && (old_mode == DOS_OPEN_RDONLY || old_mode == DOS_OPEN_RDWR)) { return AFAIL; } if (new_deny == DENY_WRITE && (old_mode == DOS_OPEN_WRONLY || old_mode == DOS_OPEN_RDWR)) { return AFAIL; } return AALL; } if (old_deny == DENY_NONE) return AALL; if (old_deny == DENY_READ) return AWRITE; if (old_deny == DENY_WRITE) return AREAD; } /* it isn't a exe, dll, sym or com file */ if (old_deny == new_deny && same_pid) return(AALL); if (old_deny == DENY_READ || new_deny == DENY_READ) return AFAIL; if (old_mode == DOS_OPEN_RDONLY) return(AREAD); return(AFAIL); } switch (new_deny) { case DENY_WRITE: if (old_deny==DENY_WRITE && old_mode==DOS_OPEN_RDONLY) return(AREAD); if (old_deny==DENY_READ && old_mode==DOS_OPEN_RDONLY) return(AWRITE); if (old_deny==DENY_NONE && old_mode==DOS_OPEN_RDONLY) return(AALL); return(AFAIL); case DENY_READ: if (old_deny==DENY_WRITE && old_mode==DOS_OPEN_WRONLY) return(AREAD); if (old_deny==DENY_READ && old_mode==DOS_OPEN_WRONLY) return(AWRITE); if (old_deny==DENY_NONE && old_mode==DOS_OPEN_WRONLY) return(AALL); return(AFAIL); case DENY_NONE: if (old_deny==DENY_WRITE) return(AREAD); if (old_deny==DENY_READ) return(AWRITE); if (old_deny==DENY_NONE) return(AALL); return(AFAIL); } return(AFAIL); } static int access_fcb(int new_deny, int old_deny, int old_mode, BOOL same_pid, BOOL isexe) { if (!same_pid || old_deny < DENY_DOS || new_deny < DENY_DOS || old_deny == DENY_DOS && (isexe || old_mode == DOS_OPEN_RDONLY)) return AFAIL; return AALL; } static int access_dos(int new_deny, int old_deny, int old_mode, BOOL same_pid, BOOL isexe) { if ((new_deny == DENY_DOS && old_deny == DENY_DOS && same_pid) || isexe || old_mode == DOS_OPEN_RDONLY) return (isexe? AALL: old_mode | AREAD) & ~old_deny; return AFAIL; } static int access_table2(int new_deny, int old_deny, int old_mode, BOOL same_pid, BOOL isexe) { if (new_deny == DENY_FCB || old_deny == DENY_FCB) return access_fcb(new_deny, old_deny, old_mode, same_pid, isexe); if (new_deny & old_mode) return AFAIL; if (new_deny == DENY_DOS || old_deny == DENY_DOS) return access_dos(new_deny, old_deny, old_mode, same_pid, isexe); return AALL & ~old_deny; } #define B(x, n) (((x) >> (n)) & 1) main() { int od, nd, om, sp, ie, ret; for (od=DENY_NONE;od <= DENY_FCB; od++) for (nd=DENY_NONE;nd <= DENY_FCB; nd++) for (om=DOS_OPEN_RDONLY;om <= DOS_OPEN_RDWR; om++) for (sp=0; sp <= 1; sp++) for (ie=0; ie <= 1; ie++) { if (od == DENY_FCB && om != DOS_OPEN_RDWR) continue; ret = access_table1(nd, od, om, sp, ie); if (nd == DENY_FCB && ret != AALL) ret = AFAIL; if (ret != access_table2(nd, od, om, sp, ie)) { printf("failed nd=%d od=%d om=%d sp=%d ie=%d got %d s.b. %d\n", nd, od, om, sp, ie, access_table2(nd, od, om, sp, ie), ret); exit(1); } /*printf("<%d%d%d %d%d%d %d%d %d %d> <%d%d>\n", B(nd, 2), B(nd, 1), B(nd, 0), B(od, 2), B(od, 1), B(od, 0), B(om, 1), B(om, 0), sp, ie, B(ret, 1), B(ret, 0));*/ } return 0; }