Example #1
0
void
smbsharedfileput(SmbFile *f, SmbSharedFile *sf, int share)
{
    SmbSharedFileEntry *sfe, **sfep;
    qlock(&sharedfiletable);
    for (sfep = &sharedfiletable.list; (sfe = *sfep) != nil; sfep = &sfe->next) {
        if (sfe == sf) {
            sfe->ref--;
            if (sfe->ref == 0) {
                *sfep = sfe->next;
                if (sfe->deleteonclose && f)
                    smbremovefile(f->t, nil, f->name);
                smblogprintif(smbglobals.log.sharedfiles, "smbsharedfileput: removed\n");
                locklistfree(&sfe->locklist);
                free(sfe);
            }
            else {
                sfe->share = sharesubtract(sfe->share, share);
                smblogprintif(smbglobals.log.sharedfiles,
                              "smbsharedfileput: ref %d share %d\n", sfe->ref, sfe->share);
            }
            break;
        }
    }
    qunlock(&sharedfiletable);
}
Example #2
0
int
smbsharedfileunlock(SmbSharedFile *sf, SmbSession *s, uint16_t pid,
                    int64_t base, int64_t limit)
{
    SmbLockListEntry smblock;
    SmbLockListEntry *l, **lp;
    smblock.s = s;
    smblock.pid = pid;
    smblock.base = base;
    smblock.limit = limit;
    if (sf->locklist == nil)
        goto failed;
    for (lp = &sf->locklist->head; (l = *lp) != nil; lp = &l->next) {
        if (l->s != s || l->pid != pid)
            continue;
        switch (lockorder(&smblock, l)) {
        case 0:
            *lp = l->next;
            free(l);
            smblogprintif(smbglobals.log.locks, "smbsharedfilelock: unlock [%lld, %lld) succeeded\n", base, limit);
            return 1;
        case -1:
            goto failed;
        }
    }
failed:
    smblogprintif(smbglobals.log.locks, "smbsharedfilelock: unlock [%lld, %lld) failed\n", base, limit);
    return 0;
}
Example #3
0
static SmbProcessResult
netservergetinfo(SmbBuffer *inparam, SmbBuffer *outparam, SmbBuffer *outdata)
{
	uint16_t level;
	SmbProcessResult pr;

	/* WrLh
	 * ushort sLevel, RCVBUF pbBuffer, RCVBUFLEN cbBuffer, ushort *pcbTotalAvail
	*/

	if (!smbbuffergets(inparam, &level)) {
	fmtfail:
		pr = SmbProcessResultFormat;
		goto done;
	}
	
	smblogprintif(smbglobals.log.rap2, "netservergetinfo(%lud, %lud)\n",
		level, smbbufferwritespace(outdata));

	if (level > 1)
		goto fmtfail;

	pr = onethingfill(outparam, outdata, &shareinfo, level, &smbglobals.serverinfo);
			
done:
	return pr;
}
Example #4
0
SmbProcessResult
smbrap2(SmbSession *s)
{
	char *pstring;
	char *dstring;
	uint16_t pno;
	RapTableEntry *e;
	SmbProcessResult pr;
	SmbBuffer *inparam;

	inparam = smbbufferinit(s->transaction.in.parameters, s->transaction.in.parameters, s->transaction.in.tpcount);
	if (!smbbuffergets(inparam, &pno)
		|| !smbbuffergetstrinline(inparam, &pstring)
		|| !smbbuffergetstrinline(inparam, &dstring)) {
		smblogprintif(smbglobals.log.rap2, "smbrap2: not enough parameters\n");
		pr = SmbProcessResultFormat;
		goto done;
	}
	if (pno > nelem(raptable) || raptable[pno].name == nil) {
		smblogprint(-1, "smbrap2: unsupported procedure %ud\n", pno);
		pr = SmbProcessResultUnimp;
		goto done;
	}
	e = raptable + pno;
	pr = (*e->procedure)(inparam, s->transaction.out.parameters, s->transaction.out.data);
done:
	smbbufferfree(&inparam);
	return pr;
}
Example #5
0
SmbSharedFile *
smbsharedfileget(Dir *d, int p9mode, int *sharep)
{
    SmbSharedFileEntry *sfe;
    qlock(&sharedfiletable);
    for (sfe = sharedfiletable.list; sfe; sfe = sfe->next) {
        if (sfe->type == d->type && sfe->dev == d->dev && sfe->path == d->qid.path) {
            if (p9denied(p9mode, sfe->share)) {
                qunlock(&sharedfiletable);
                return nil;
            }
            *sharep = sharesubtract(*sharep, sfe->share);
            sfe->share = shareadd(sfe->share, *sharep);
            sfe->ref++;
            goto done;
        }
    }
    sfe = smbemallocz(sizeof(SmbSharedFileEntry), 1);
    sfe->type = d->type;
    sfe->dev = d->dev;
    sfe->path = d->qid.path;
//	sfe->name = smbestrdup(name);
    sfe->ref = 1;
    sfe->share = *sharep;
    sfe->next = sharedfiletable.list;
    sharedfiletable.list = sfe;
done:
    smblogprintif(smbglobals.log.sharedfiles, "smbsharedfileget: ref %d share %d\n",
                  sfe->ref, sfe->share);
    qunlock(&sharedfiletable);
    return sfe;
}
Example #6
0
static SmbProcessResult
netserverenum2(SmbBuffer *inparam, SmbBuffer *outparam, SmbBuffer *outdata)
{
	uint16_t level, rbl;
	char *domain;
	uint32_t servertype;
	SmbProcessResult pr;
	SmbServerInfo *si[3];
	SmbServerInfo domainsi;
	int entries;

	/* WrLehDz
	 * ushort sLevel, RCVBUF pbBuffer, RCVBUFLEN cbBuffer, ENTCOUNT pcEntriesRead, ushort *pcTotalAvail,
	 * ulong fServerType, char *pszDomain
	*/

	if (!smbbuffergets(inparam, &level)
		|| !smbbuffergets(inparam, &rbl)
		|| !smbbuffergetl(inparam, &servertype)
		|| !smbbuffergetstr(inparam, 0, &domain)) {
	fmtfail:
		pr = SmbProcessResultFormat;
		goto done;
	}
	
	smblogprintif(smbglobals.log.rap2, "netserverenum2(%lud, %lud, 0x%.8lux, %s)\n",
		level, smbbufferwritespace(outdata), servertype, domain);

	if (level > 1)
		goto fmtfail;

	if (servertype == 0xffffffff)
		servertype &= ~(SV_TYPE_DOMAIN_ENUM | SV_TYPE_LOCAL_LIST_ONLY);

	if ((servertype & SV_TYPE_LOCAL_LIST_ONLY) != 0 && (servertype & SV_TYPE_DOMAIN_ENUM) == 0) 
		servertype = SV_TYPE_ALL & ~(SV_TYPE_DOMAIN_ENUM);

	entries = 0;

	if ((servertype & SV_TYPE_SERVER) != 0
		&& (domain[0] == 0 || cistrcmp(domain, smbglobals.primarydomain) == 0)) {
		si[entries++] = &smbglobals.serverinfo;
	}

	if ((servertype & SV_TYPE_DOMAIN_ENUM) != 0) {
		/* there's only one that I know about */
		memset(&domainsi, 0, sizeof(domainsi));
		domainsi.name = smbglobals.primarydomain;
		domainsi.stype = SV_TYPE_DOMAIN_ENUM;
		si[entries++] = &domainsi;
	}
	si[entries] = 0;

	pr = thingfill(outparam, outdata, &serverinfo, level, si);
			
done:
	free(domain);
	return pr;
}
Example #7
0
static SmbProcessResult
netwkstagetinfo(SmbBuffer *inparam, SmbBuffer *outparam, SmbBuffer *outdata)
{
	uint16_t level;
	uint16_t usefulbytes;
	SmbProcessResult pr;
	int moredata;

	/* WrLh
	 * ushort sLevel, RCVBUF pbBuffer, RCVBUFLEN cbBuffer, ushort *pcbTotalAvail
	*/

	if (!smbbuffergets(inparam, &level)) {
	fmtfail:
		pr = SmbProcessResultFormat;
		goto done;
	}
	
	smblogprintif(smbglobals.log.rap2, "netwkstagetinfo(%lud, %lud)\n",
		level, smbbufferwritespace(outdata));

	if (level != 10)
		goto fmtfail;

	usefulbytes = 22 + smbstrlen(smbglobals.serverinfo.name) + smbstrlen(getuser())
		+ 3 * smbstrlen(smbglobals.primarydomain);

	moredata = usefulbytes > smbbufferwritespace(outdata);

	assert(smbbufferputl(outdata, 0));
	assert(smbbufferputl(outdata, 0));
	assert(smbbufferputl(outdata, 0));
	assert(smbbufferputb(outdata, smbglobals.serverinfo.vmaj));
	assert(smbbufferputb(outdata, smbglobals.serverinfo.vmin));
	assert(smbbufferputl(outdata, 0));
	assert(smbbufferputl(outdata, 0));
	assert(smbbufferfixupabsolutel(outdata, 0));
	assert(smbbufferputstring(outdata, nil, SMB_STRING_ASCII, smbglobals.serverinfo.name));
	assert(smbbufferfixupabsolutel(outdata, 4));
	assert(smbbufferputstring(outdata, nil, SMB_STRING_ASCII, getuser()));
	assert(smbbufferfixupabsolutel(outdata, 8));
	assert(smbbufferputstring(outdata, nil, SMB_STRING_ASCII, smbglobals.primarydomain));
	assert(smbbufferfixupabsolutel(outdata, 14));
	assert(smbbufferputstring(outdata, nil, SMB_STRING_ASCII, smbglobals.primarydomain));
	assert(smbbufferfixupabsolutel(outdata, 18));
	assert(smbbufferputstring(outdata, nil, SMB_STRING_ASCII, smbglobals.primarydomain));

	if (!smbbufferputs(outparam, moredata ? SMB_RAP_ERROR_MORE_DATA : SMB_RAP_NERR_SUCCESS)
		|| !smbbufferputs(outparam, 0)
		|| !smbbufferputs(outparam, usefulbytes)) {
		pr = SmbProcessResultFormat;
		goto done;
	}
	
	pr = SmbProcessResultReply;
			
done:
	return pr;
}
Example #8
0
void
smbfileclose(SmbSession *s, SmbFile *f)
{
	smblogprintif(smbglobals.log.fids, "smbfileclose: 0x%.4x/0x%.4x %s%s\n",
		f->t->id, f->id, f->t->serv->path, f->name);
	smbidmapremove(s->fidmap, f);
	smbfilefree(&f);
}
Example #9
0
void
smbsearchclose(SmbSession *s, SmbSearch *search)
{
	if (search) {
		smblogprintif(smbglobals.log.sids, "smbsearchclose: tid 0x%.4ux sid 0x%.4ux\n", search->t->id, search->id);
		smbidmapremove(s->sidmap, search);
		smbsearchfree(&search);
	}
}
Example #10
0
int
nbssaccept(void *v, NbSession *s, NBSSWRITEFN **writep)
{
	SmbSession *smbs = smbemallocz(sizeof(SmbSession), 1);
	smbs->nbss = s;
	s->magic = smbs;
	smbs->nextcommand = SMB_COM_NO_ANDX_COMMAND;
	*writep = nbwrite;
	smblogprintif(smbglobals.log.sessions, "netbios session started\n");
	return 1;
}
Example #11
0
int
cifsaccept(SmbCifsSession *s, SMBCIFSWRITEFN **writep)
{
	SmbSession *smbs = smbemallocz(sizeof(SmbSession), 1);
	smbs->cifss = s;
	s->magic = smbs;
	smbs->nextcommand = SMB_COM_NO_ANDX_COMMAND;
	*writep = cifswrite;
	smblogprintif(smbglobals.log.sessions, "cifs session started\n");
	return 1;
}
Example #12
0
SmbSearch *
smbsearchnew(SmbSession *s, SmbDirCache *dc, Reprog *r, SmbTree *t)
{
	SmbSearch *search;
	if (s->sidmap == nil)
		s->sidmap = smbidmapnew();
	search = smbemalloc(sizeof(SmbSearch));
	smbidmapadd(s->sidmap, search);
	search->dc = dc;
	search->rep = r;
	search->t = t;
	smblogprintif(smbglobals.log.sids, "smbsearchnew: 0x%.4ux\n", search->id);
	return search;
}
Example #13
0
int
smbsharedfilelock(SmbSharedFile *sf, SmbSession *s, uint16_t pid,
                  int64_t base,
                  int64_t limit)
{
    SmbLockListEntry smblock;
    SmbLockListEntry *l, *nl, **lp;
    smblock.s = s;
    smblock.pid = pid;
    smblock.base = base;
    smblock.limit = limit;
    if (sf->locklist) {
        for (l = sf->locklist->head; l; l = l->next)
            if (lockconflict(l, &smblock)) {
                smblogprintif(smbglobals.log.locks, "smbsharedfilelock: lock [%lld, %lld) failed because conflicts with [%lld, %lld)\n",
                              base, limit, l->base, l->limit);
                return 0;
            }
    }
    if (sf->locklist == nil)
        sf->locklist = smbemallocz(sizeof(SmbLockList), 1);
    for (lp = &sf->locklist->head; (l = *lp) != nil; lp = &l->next)
        if (lockorder(&smblock, l) <= 0)
            break;
    smblogprintif(smbglobals.log.locks, "smbsharedfilelock: lock [%lld, %lld) succeeded\n", base, limit);
    nl = smbemalloc(sizeof(*nl));
    *nl = smblock;
    nl->next = *lp;
    *lp = nl;
//{
//	smblogprintif(smbglobals.log.locks,"smbsharedfilelock: list\n");
//	for (l = sf->locklist->head; l; l = l->next)
//		smblogprintif(smbglobals.log.locks, "smbsharedfilelock: [%lld, %lld)\n", l->base, l->limit);
//}
    return 1;
}
Example #14
0
static SmbProcessResult
netshareenum(SmbBuffer *inparam, SmbBuffer *outparam, SmbBuffer *outdata)
{
	uint16_t level;

	/* WrLeh */
	/* ushort sLevel, RCVBUF pbBuffer, RCVBUFLEN cbBuffer, ENTCOUNT pcEntriesRead, ushort *pcTotalAvail */

	if (!smbbuffergets(inparam, &level))
		return SmbProcessResultFormat;
	
	smblogprintif(smbglobals.log.rap2, "netshareenum(%lud, %lud)\n",
		level, smbbufferwritespace(outdata));

	if (level != 1)
		return SmbProcessResultFormat;

	return thingfill(outparam, outdata, &shareinfo, level, nil);
}
Example #15
0
static SmbProcessResult
netsharegetinfo(SmbBuffer *inparam, SmbBuffer *outparam, SmbBuffer *outdata)
{
	char *netname;
	uint16_t level;
	SmbProcessResult pr;
	SmbService *serv;

	/*
	 * zWrLh
	 * char *pszNetName, ushort sLevel, RCVBUF pbBuffer, RCVBUFLEN cbBuffer, ushort *pcbTotalAvail
	*/

	if (!smbbuffergetstrinline(inparam, &netname)
		|| !smbbuffergets(inparam, &level)) {
	fmtfail:
		pr = SmbProcessResultFormat;
		goto done;
	}
	
	smblogprintif(smbglobals.log.rap2, "netsharegetinfo(%s, %lud, %lud)\n",
		netname, level, smbbufferwritespace(outdata));

	if (level > 2)
		goto fmtfail;

	for (serv = smbservices; serv; serv = serv->next)
		if (cistrcmp(serv->name, netname) == 0)
			break;

	if (serv == nil) {
		smblogprint(-1, "netsharegetinfo: service %s unimplemented\n", netname);
		pr = SmbProcessResultUnimp;
		goto done;
	}

	pr = onethingfill(outparam, outdata, &shareinfo, level, serv);

done:
	return pr;
}
Example #16
0
int
smbsessionwrite(SmbSession *smbs, void *p, int32_t n)
{
	SmbHeader h;
	SmbOpTableEntry *ote;
	uint8_t *pdata;
	int rv;
	SmbBuffer *b = nil;
	uint16_t bytecount;
	SmbProcessResult pr;

	if (smbs->response == nil)
		smbs->response = smbbuffernew(576);
	else
		smbresponsereset(smbs);
	smbs->errclass = SUCCESS;
	smbs->error = SUCCESS;
//	print("received %ld bytes\n", n);
	if (n <= 0)
		goto closedown;
	b = smbbufferinit(p, p, n);
	if (!smbbuffergetheader(b, &h, &pdata, &bytecount)) {
		smblogprint(-1, "smb: invalid header\n");
		goto closedown;
	}
smbloglock();
smblogprint(h.command, "received:\n");
smblogdata(h.command, smblogprint, p, n, 0x1000);
smblogunlock();
	ote = smboptable + h.command;
	if (ote->name == nil) {
		smblogprint(-1, "smb: illegal opcode 0x%.2x\n", h.command);
		goto unimp;
	}
	if (ote->process == nil) {
		smblogprint(-1, "smb: opcode %s unimplemented\n", ote->name);
		goto unimp;
	}
	if (smbs->nextcommand != SMB_COM_NO_ANDX_COMMAND
		&& smbs->nextcommand != h.command) {
		smblogprint(-1, "smb: wrong command - expected %.2x\n", smbs->nextcommand);
		goto misc;
	}
	smbs->nextcommand = SMB_COM_NO_ANDX_COMMAND;
	switch (h.command) {
	case SMB_COM_NEGOTIATE:
	case SMB_COM_SESSION_SETUP_ANDX:
	case SMB_COM_TREE_CONNECT_ANDX:
	case SMB_COM_ECHO:
		break;
	default:
		if (smbs->state != SmbSessionEstablished) {
			smblogprint(-1, "aquarela: command %.2x unexpected\n", h.command);
			goto unimp;
		}
	}
	pr = (*ote->process)(smbs, &h, pdata, b);
	switch (pr) {
	case SmbProcessResultUnimp:
	unimp:
		smbseterror(smbs, ERRDOS, ERRunsup);
		pr = SmbProcessResultError;
		break;
	case SmbProcessResultFormat:
		smbseterror(smbs, ERRSRV, ERRsmbcmd);
		pr = SmbProcessResultError;
		break;
	case SmbProcessResultMisc:
	misc:
		smbseterror(smbs, ERRSRV, ERRerror);
		pr = SmbProcessResultError;
		break;
	case SmbProcessResultOk:
	case SmbProcessResultError:
	case SmbProcessResultReply:
	case SmbProcessResultDie:
		break;
	}
	if (pr == SmbProcessResultError) {
		smblogprint(h.command, "reply: error %d/%d\n", smbs->errclass, smbs->error);
		if (!smbresponseputerror(smbs, &h, smbs->errclass, smbs->error))
			pr = SmbProcessResultDie;
		else
			pr = SmbProcessResultReply;
	}
	else
		smblogprint(h.command, "reply: ok\n");
	if (pr == SmbProcessResultReply)
		rv = smbresponsesend(smbs) == SmbProcessResultOk ? 0 : -1;
	else if (pr == SmbProcessResultDie)
		rv = -1;
	else
		rv = 0;
	goto done;
closedown:
	rv = -1;
done:
	if (rv < 0) {
		smblogprintif(smbglobals.log.sessions, "shutting down\n");
		smbsessionfree(smbs);
	}
	smbbufferfree(&b);
	if (smbglobals.log.poolparanoia)
		poolcheck(mainmem);
	return rv;
}
Example #17
0
SmbProcessResult
smbtrans2findnext2(SmbSession *s, SmbHeader *h)
{
	SmbBuffer *b;
	int debug;
	ushort sid, scount, infolevel;
	ulong resumekey;
	ushort flags;
	char *filename = nil;
	SmbProcessResult pr;
	ushort e;
	ulong nameoffset;
	ushort eos;
	SmbTree *t;
	SmbSearch *search;

	debug = smboptable[h->command].debug
		|| smbtrans2optable[SMB_TRANS2_FIND_NEXT2].debug
		|| smbglobals.log.find;
	b = smbbufferinit(s->transaction.in.parameters, s->transaction.in.parameters, s->transaction.in.tpcount);
	if (!smbbuffergets(b, &sid)
		|| !smbbuffergets(b, &scount)
		|| !smbbuffergets(b, &infolevel)
		|| !smbbuffergetl(b, &resumekey)
		|| !smbbuffergets(b, &flags)
		|| !smbbuffergetstring(b, h, 0, &filename)) {
		pr = SmbProcessResultFormat;
		goto done;
	}
	smblogprintif(debug,
		"smbtrans2findnext2: sid %d scount %d infolevel 0x%.4ux resumekey %lud flags 0x%.4ux filename %s\n",
		sid, scount, infolevel, resumekey, flags, filename);

	if (infolevel != SMB_INFO_STANDARD && infolevel != SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
		smblogprint(-1, "smbtrans2findnext2: infolevel 0x%.4ux not implemented\n", infolevel);
		smbseterror(s, ERRDOS, ERRunknownlevel);
		pr = SmbProcessResultError;
		goto done;
	}

	t = smbidmapfind(s->tidmap, h->tid);
	if (t == nil) {
		smbseterror(s, ERRSRV, ERRinvtid);
		pr = SmbProcessResultError;
		goto done;
	}

	search = smbidmapfind(s->sidmap, sid);
	if (search == nil) {
		smbseterror(s, ERRDOS, ERRnofiles);
		pr = SmbProcessResultError;
		goto done;
	}

	if (search->t != t) {
		smbseterror(s, ERRSRV, ERRinvtid);
		pr = SmbProcessResultError;
		goto done;
	}

	if ((flags & (1 << 3)) == 0) {
		long i;
		if (filename == nil) {
			smbseterror(s, ERRDOS, ERRnofiles);
			pr = SmbProcessResultError;
			goto done;
		}
		for (i = 0; i < search->dc->n; i++)
			if (strcmp(search->dc->buf[i].name, filename) == 0) {
				search->dc->i = i + 1;
				break;
			}
	}

	populate(s, search->dc, search->rep, infolevel, flags, scount, &e, &nameoffset);
	
	eos = search->dc->i >= search->dc->n;
	if ((flags & SMB_FIND_CLOSE) != 0 || ((flags & SMB_FIND_CLOSE_EOS) != 0 && eos))
		smbsearchclose(s, search);
	smbbufferputs(s->transaction.out.parameters, e);
	smbbufferputs(s->transaction.out.parameters, eos);
	smbbufferputs(s->transaction.out.parameters, 0);
	smbbufferputs(s->transaction.out.parameters, nameoffset);
	pr = SmbProcessResultReply;
done:
	smbbufferfree(&b);
	free(filename);
	return pr;
}
Example #18
0
SmbProcessResult
smbtrans2findfirst2(SmbSession *s, SmbHeader *h)
{
	SmbBuffer *b;
	char *pattern = nil;
	char *dir = nil;
	char *name = nil;
	ushort searchattributes, searchcount, flags, informationlevel;
	ulong searchstoragetype;
	SmbDirCache *dc = nil;
	ushort e;
	ulong nameoffset;
	ushort eos;
	SmbSearch *search;
	SmbProcessResult pr;
	Reprog *r = nil;
	SmbTree *t;
	int debug;

	debug = smboptable[h->command].debug
		|| smbtrans2optable[SMB_TRANS2_FIND_FIRST2].debug
		|| smbglobals.log.find;
poolcheck(mainmem);
	b = smbbufferinit(s->transaction.in.parameters, s->transaction.in.parameters, s->transaction.in.tpcount);
	if (!smbbuffergets(b, &searchattributes)
		|| !smbbuffergets(b, &searchcount)
		|| !smbbuffergets(b, &flags)
		|| !smbbuffergets(b, &informationlevel)
		|| !smbbuffergetl(b, &searchstoragetype)
		|| !smbbuffergetstring(b, h, SMB_STRING_PATH, &pattern)) {
		pr = SmbProcessResultFormat;
		goto done;
	}
	smbloglock();
	smblogprintif(debug, "searchattributes: 0x%.4ux\n", searchattributes);
	smblogprintif(debug, "searchcount: 0x%.4ux\n", searchcount);
	smblogprintif(debug, "flags: 0x%.4ux\n", flags);
	smblogprintif(debug, "informationlevel: 0x%.4ux\n", informationlevel);
	smblogprintif(debug, "searchstoragetype: 0x%.8lux\n", searchstoragetype);
	smblogprintif(debug, "pattern: %s\n", pattern);
	smblogunlock();
	smbpathsplit(pattern, &dir, &name);
	if (informationlevel != SMB_INFO_STANDARD && informationlevel != SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
		smblogprint(-1, "smbtrans2findfirst2: infolevel 0x%.4ux not implemented\n", informationlevel);
		smbseterror(s, ERRDOS, ERRunknownlevel);
		pr = SmbProcessResultError;
		goto done;
	}

	t = smbidmapfind(s->tidmap, h->tid);
	if (t == nil) {
		smbseterror(s, ERRSRV, ERRinvtid);
		pr = SmbProcessResultError;
		goto done;
	}

	dc = smbmkdircache(t, dir);
	if (dc == nil) {
		smbseterror(s, ERRDOS, ERRnoaccess);
		pr = SmbProcessResultError;
		goto done;
	}
poolcheck(mainmem);
	r = smbmkrep(name);
	populate(s, dc, r, informationlevel, flags, searchcount, &e, &nameoffset);
poolcheck(mainmem);
	eos = dc->i >= dc->n;
	if ((flags & SMB_FIND_CLOSE) != 0 || ((flags & SMB_FIND_CLOSE_EOS) != 0 && eos))
		smbdircachefree(&dc);
poolcheck(mainmem);
	if (dc) {
		/* create a search handle */
		search = smbsearchnew(s, dc, r, t);
		r = nil;
		dc = nil;
	}
	else
		search = nil;
	smbbufferputs(s->transaction.out.parameters, search ? search->id : 0);
	smbbufferputs(s->transaction.out.parameters, e);
	smbbufferputs(s->transaction.out.parameters, eos);
	smbbufferputs(s->transaction.out.parameters, 0);
	smbbufferputs(s->transaction.out.parameters, nameoffset);
	pr = SmbProcessResultReply;
done:
	smbbufferfree(&b);
	free(pattern);
	free(dir);
	free(name);
	smbdircachefree(&dc);
	free(r);
	return pr;
}