forsyth20121205-174063a80cc13 years agoHistory
2508 lines · 50.9 KB · C
RawDownload
#define UNICODE#define Unknown win_Unknown#include	<windows.h>#include	<winbase.h>#undef Unknown#undef	Sleep#include	"dat.h"#include	"fns.h"#include	"error.h"#include	<lm.h> /* TODO: try using / in place of \ in path names */ #ifndef SID_MAX_SUB_AUTHORITIES#define	SID_MAX_SUB_AUTHORITIES	15#endif enum{	MAX_SID		= sizeof(SID) + SID_MAX_SUB_AUTHORITIES*sizeof(DWORD),	ACL_ROCK	= sizeof(ACL) + 20*(sizeof(ACCESS_ALLOWED_ACE)+MAX_SID),	SD_ROCK		= SECURITY_DESCRIPTOR_MIN_LENGTH + MAX_SID + ACL_ROCK,	MAXCOMP		= 128,}; typedef struct	User	User;typedef struct  Gmem	Gmem;typedef	struct	Stat	Stat;typedef	struct Fsinfo	Fsinfo;typedef	WIN32_FIND_DATA	Fsdir; #ifndef INVALID_SET_FILE_POINTER#define	INVALID_SET_FILE_POINTER	((DWORD)-1)#endif struct Fsinfo{	int	uid;	int	gid;	int	mode;	int	fd;	vlong	offset;	QLock	oq;	char*	spec;	Rune*	srv;	Cname*	name;	/* Windows' idea of the file name */	ushort	usesec;	ushort	checksec;	Fsdir*	de;	/* non-nil for saved entry from last dirread at offset */};#define	FS(c)	((Fsinfo*)(c)->aux) /* * info about a user or group * there are two ways to specify a user: *	by sid, a unique identifier *	by user and domain names * this structure is used to convert between the two, * as well as figure out which groups a users belongs to. * the user information never gets thrown away, * but the group information gets refreshed with each setid. */struct User{	QLock	lk;		/* locks the gotgroup and group fields */	SID	*sid;	Rune	*name;	Rune	*dom;	int	type;		/* the type of sid, ie SidTypeUser, SidTypeAlias, ... */	int	gotgroup;	/* tried to add group */	Gmem	*group;		/* global and local groups to which this user or group belongs. */	User	*next;}; struct Gmem{	User	*user;	Gmem	*next;}; /* * intermediate stat information */struct Stat{	User	*owner;	User	*group;	ulong	mode;}; /* * some "well-known" sids */static	SID	*creatorowner;static	SID	*creatorgroup;static	SID	*everyone;static	SID	*ntignore;static	SID	*ntroot;	/* user who is supposed to run emu as a server */ /* * all users we ever see end up in this table * users are never deleted, but we should update * group information for users sometime */static struct{	QLock	lk;	User	*u;}users; /* * conversion from inferno permission modes to nt access masks * is this good enough?  this is what nt sets, except for NOMODE */#define	NOMODE	(READ_CONTROL|FILE_READ_EA|FILE_READ_ATTRIBUTES)#define	RMODE	(READ_CONTROL|SYNCHRONIZE\		|FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)#define	XMODE	(READ_CONTROL|SYNCHRONIZE\		|FILE_EXECUTE|FILE_READ_ATTRIBUTES)#define	WMODE	(DELETE|READ_CONTROL|SYNCHRONIZE|WRITE_DAC|WRITE_OWNER\		|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA\		|FILE_DELETE_CHILD|FILE_WRITE_ATTRIBUTES) static	intmodetomask[] ={	NOMODE,	XMODE,	WMODE,	WMODE|XMODE,	RMODE,	RMODE|XMODE,	RMODE|WMODE,	RMODE|WMODE|XMODE,}; extern	DWORD	PlatformId;	char    rootdir[MAXROOT] = "\\inferno";	Rune	rootname[] = L"inferno-server";static	Qid	rootqid;static	User	*fsnone;static	User	*fsuser;static	Rune	*ntsrv;static	int	usesec;static	int	checksec;static	int	isserver;static	int	file_share_delete;static	uchar	isntfrog[256]; static	void		fsremove(Chan*); 	wchar_t	*widen(char *s);	char		*narrowen(wchar_t *ws);	int		widebytes(wchar_t *ws); static char Etoolong[] = "file name too long"; /* * these lan manager functions are not supplied * on windows95, so we have to load the dll by hand */static struct {	NET_API_STATUS (NET_API_FUNCTION *UserGetLocalGroups)(		LPWSTR servername,		LPWSTR username,		DWORD level,		DWORD flags,		LPBYTE *bufptr,		DWORD prefmaxlen,		LPDWORD entriesread,		LPDWORD totalentries);	NET_API_STATUS (NET_API_FUNCTION *UserGetGroups)(		LPWSTR servername,		LPWSTR username,		DWORD level,		LPBYTE *bufptr,		DWORD prefmaxlen,		LPDWORD entriesread,		LPDWORD totalentries);	NET_API_STATUS (NET_API_FUNCTION *GetAnyDCName)(		LPCWSTR ServerName,		LPCWSTR DomainName,		LPBYTE *Buffer);	NET_API_STATUS (NET_API_FUNCTION *ApiBufferFree)(LPVOID Buffer);} net; extern	int		nth2fd(HANDLE);extern	HANDLE		ntfd2h(int);static	int		cnisroot(Cname*);static	int		fsisroot(Chan*);static	int		okelem(char*, int);static	int		fsexist(char*, Qid*);static	char*	fspath(Cname*, char*, char*, char*);static	Cname*	fswalkpath(Cname*, char*, int);static	char*	fslastelem(Cname*);static	long		fsdirread(Chan*, uchar*, int, vlong);static	ulong		fsqidpath(char*);static	int		fsomode(int);static	int		fsdirset(char*, int, WIN32_FIND_DATA*, char*, Chan*, int isdir);static 	int		fsdirsize(WIN32_FIND_DATA*, char*, Chan*);static	void		fssettime(char*, long, long);static	long		unixtime(FILETIME);static	FILETIME	wintime(ulong);static	void		secinit(void);static	int		secstat(Dir*, char*, Rune*);static	int		secsize(char*, Rune*);static	void		seccheck(char*, ulong, Rune*);static	int		sechasperm(char*, ulong, Rune*);static	SECURITY_DESCRIPTOR* secsd(char*, char[SD_ROCK]);static	int		secsdhasperm(SECURITY_DESCRIPTOR*, ulong, Rune*);static	int		secsdstat(SECURITY_DESCRIPTOR*, Stat*, Rune*);static	SECURITY_DESCRIPTOR* secmksd(char[SD_ROCK], Stat*, ACL*, int);static	SID		*dupsid(SID*);static	int		ismembersid(Rune*, User*, SID*);static	int		ismember(User*, User*);static	User		*sidtouser(Rune*, SID*);static	User		*domnametouser(Rune*, Rune*, Rune*);static	User		*nametouser(Rune*, Rune*);static	User		*unametouser(Rune*, char*);static	void		addgroups(User*, int);static	User		*mkuser(SID*, int, Rune*, Rune*);static	Rune		*domsrv(Rune *, Rune[MAX_PATH]);static	Rune		*filesrv(char*);static	int		fsacls(char*);static	User		*secuser(void); 	int		runeslen(Rune*);	Rune*		runesdup(Rune*);	Rune*		utftorunes(Rune*, char*, int);	char*		runestoutf(char*, Rune*, int);	int		runescmp(Rune*, Rune*);  intwinfilematch(char *path, WIN32_FIND_DATA *data){	char *p;	wchar_t *wpath;	int r; 	p = path+strlen(path);	while(p > path && p[-1] != '\\')		--p;	wpath = widen(p);	r = (data->cFileName[0] == '.' && runeslen(data->cFileName) == 1)			|| runescmp(data->cFileName, wpath) == 0;	free(wpath);	return r;} intwinfileclash(char *path){	HANDLE h;	WIN32_FIND_DATA data;	wchar_t *wpath; 	wpath = widen(path);	h = FindFirstFile(wpath, &data);	free(wpath);	if (h != INVALID_HANDLE_VALUE) {		FindClose(h);		return !winfilematch(path, &data);	}	return 0;}  /* * this gets called to set up the environment when we switch users */voidsetid(char *name, int owner){	User *u; 	if(owner && !iseve())		return; 	kstrdup(&up->env->user, name); 	if(!usesec)		return; 	u = unametouser(ntsrv, up->env->user);	if(u == nil)		u = fsnone;	else {		qlock(&u->lk);		addgroups(u, 1);		qunlock(&u->lk);	}	if(u == nil)		panic("setid: user nil\n"); 	up->env->ui = u;} static voidfsfree(Chan *c){	cnameclose(FS(c)->name);	if(FS(c)->de != nil)		free(FS(c)->de);	free(FS(c));} voidfsinit(void){	int n, isvol;	ulong attr;	char *p, tmp[MAXROOT];	wchar_t *wp, *wpath, *last;	wchar_t wrootdir[MAXROOT]; 	isntfrog['/'] = 1;	isntfrog['\\'] = 1;	isntfrog[':'] = 1;	isntfrog['*'] = 1;	isntfrog['?'] = 1;	isntfrog['"'] = 1;	isntfrog['<'] = 1;	isntfrog['>'] = 1; 	/*	 * vet the root	 */	strcpy(tmp, rootdir);	for(p = tmp; *p; p++)		if(*p == '/')			*p = '\\';	if(tmp[0] != 0 && tmp[1] == ':') {		if(tmp[2] == 0) {			tmp[2] = '\\';			tmp[3] = 0;		}		else if(tmp[2] != '\\') {			/* don't allow c:foo - only c:\foo */			panic("illegal root pathX");		}	}	wrootdir[0] = '\0';	wpath = widen(tmp);	for(wp = wpath; *wp; wp++) {		if(*wp < 32 || (*wp < 256 && isntfrog[*wp] && *wp != '\\' && *wp != ':'))			panic("illegal root path");	}	n = GetFullPathName(wpath, MAXROOT, wrootdir, &last);	free(wpath);		runestoutf(rootdir, wrootdir, MAXROOT);	if(n >= MAXROOT || n == 0)		panic("illegal root path"); 	/* get rid of trailing \ */	while(rootdir[n-1] == '\\') {		if(n <= 2) {			panic("illegal root path");		}		rootdir[--n] = '\0';	} 	isvol = 0;	if(rootdir[1] == ':' && rootdir[2] == '\0')		isvol = 1;	else if(rootdir[0] == '\\' && rootdir[1] == '\\') {		p = strchr(&rootdir[2], '\\');		if(p == nil)			panic("inferno root can't be a server");		isvol = strchr(p+1, '\\') == nil;	} 	if(strchr(rootdir, '\\') == nil)		strcat(rootdir, "\\.");	attr = GetFileAttributes(wrootdir);	if(attr == 0xFFFFFFFF)		panic("root path '%s' does not exist", narrowen(wrootdir));	rootqid.path = fsqidpath(rootdir);	if(attr & FILE_ATTRIBUTE_DIRECTORY)		rootqid.type |= QTDIR;	rootdir[n] = '\0'; 	rootqid.vers = time(0); 	/*	 * set up for nt file security checking	 */	ntsrv = filesrv(rootdir);	usesec = PlatformId == VER_PLATFORM_WIN32_NT; 	/* true for NT and 2000 */	if(usesec){		file_share_delete = FILE_SHARE_DELETE;	/* sensible handling of shared files by delete and rename */		secinit();		if(!fsacls(rootdir))			usesec = 0;	}	checksec = usesec && isserver;} Chan*fsattach(char *spec){	Chan *c;	static int devno;	static Lock l;	char *drive = (char *)spec; 	if (!emptystr(drive) && (drive[1] != ':' || drive[2] != '\0'))		error(Ebadspec); 	c = devattach('U', spec);	lock(&l);	c->dev = devno++;	unlock(&l);	c->qid = rootqid;	c->aux = smalloc(sizeof(Fsinfo));	FS(c)->srv = ntsrv;	if(!emptystr(spec)) {		char *s = smalloc(strlen(spec)+1);		strcpy(s, spec);		FS(c)->spec = s;		FS(c)->srv = filesrv(spec);		if(usesec)			FS(c)->usesec = fsacls(spec);		FS(c)->checksec = FS(c)->usesec && isserver;		c->qid.path = fsqidpath(spec);		c->qid.type = QTDIR;		c->qid.vers = 0;	}else{		FS(c)->usesec = usesec;		FS(c)->checksec = checksec;	}	FS(c)->name = newcname("/");	return c;} Walkqid*fswalk(Chan *c, Chan *nc, char **name, int nname){	int j, alloc;	Walkqid *wq;	char path[MAX_PATH], *p;	Cname *ph;	Cname *current, *next; 	if(nname > 0)		isdir(c); 	alloc = 0;	current = nil;	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));	if(waserror()){		if(alloc && wq->clone != nil)			cclose(wq->clone);		cnameclose(current);		free(wq);		return nil;	}	if(nc == nil){		nc = devclone(c);		nc->type = 0;		alloc = 1;	}	wq->clone = nc;	current = FS(c)->name;	if(current != nil)		incref(&current->r);	for(j = 0; j < nname; j++){		if(!(nc->qid.type&QTDIR)){			if(j==0)				error(Enotdir);			break;		}		if(!okelem(name[j], 0)){			if(j == 0)				error(Efilename);			break;		}		p = fspath(current, name[j], path, FS(c)->spec);		if(FS(c)->checksec) {			*p = '\0';			if(!sechasperm(path, XMODE, FS(c)->srv)){				if(j == 0)					error(Eperm);				break;			}			*p = '\\';		} 		if(strcmp(name[j], "..") == 0) {			if(fsisroot(c))				nc->qid = rootqid;			else{				ph = fswalkpath(current, "..", 1);				if(cnisroot(ph)){					nc->qid = rootqid;					current = ph;					if(current != nil)						incref(&current->r);				}				else {

Lines 1–500 of 2508.