コード例 #1
0
ファイル: smbtrans2find.c プロジェクト: AustenConrad/plan-9
static int
findbothflatten(SmbBuffer *b, SmbPeerInfo *p, Dir *d, ulong resumekey, ulong *nameoffsetp)
{
	vlong mtime, atime;
	ulong fixup;

	fixup = smbbufferwriteoffset(b);
	mtime = smbplan9time2time(d->mtime);
	atime = smbplan9time2time(d->atime);
poolcheck(mainmem);
	if (!smbbufferputl(b, 0)
		|| !smbbufferputl(b, resumekey)
		|| !smbbufferputv(b, mtime)
		|| !smbbufferputv(b, atime)
		|| !smbbufferputv(b, mtime)
		|| !smbbufferputv(b, mtime)
		|| !smbbufferputv(b, d->length)
		|| !smbbufferputv(b, smbl2roundupvlong(d->length, smbglobals.l2allocationsize))			// ha
		|| !smbbufferputl(b, (d->qid.type & QTDIR) ? 0x10 : 0x80)
		|| !smbbufferputl(b, smbstringlen(p, d->name))
		|| !smbbufferputl(b, 0)
		|| !smbbufferputb(b, 0)
		|| !smbbufferputb(b, 0)
		|| !smbbufferfill(b, 0, 24))
		return 0;
poolcheck(mainmem);
	*nameoffsetp = smbbufferwriteoffset(b);
	if (!smbbufferputstring(b, p, 0, d->name) || !smbbufferalignl2(b, 2))
		return 0;
poolcheck(mainmem);
	return smbbufferfixuprelativeinclusivel(b, fixup);
}
コード例 #2
0
ファイル: smbtrans2find.c プロジェクト: AustenConrad/plan-9
static int
standardflatten(SmbSession *s, SmbBuffer *b, Dir *d, ulong *nameoffsetp)
{
	ushort mdate, mtime;
	ushort adate, atime;
	ushort fnlfixupoffset;

	smbplan9time2datetime(d->mtime, s->tzoff, &mdate, &mtime);
	smbplan9time2datetime(d->atime, s->tzoff, &adate, &atime);
	if (!smbbufferputs(b, mdate)
		|| !smbbufferputs(b, mtime)
		|| !smbbufferputs(b, adate)
		|| !smbbufferputs(b, atime)
		|| !smbbufferputs(b, mdate)
		|| !smbbufferputs(b, mtime)
		|| !smbbufferputl(b, d->length)
		|| !smbbufferputl(b, 512)			// ha
		|| !smbbufferputs(b, (d->qid.type & QTDIR) ? 0x10 : 0))
		return 0;
	fnlfixupoffset = smbbufferwriteoffset(b);
	if (!smbbufferputs(b, 0))
		return 0;
	*nameoffsetp = smbbufferwriteoffset(b);
	if (!smbbufferputstring(b, &s->peerinfo, 0, d->name))
		return 0;
	return smbbufferfixuprelatives(b, fnlfixupoffset);
}
コード例 #3
0
ファイル: smbrap2.c プロジェクト: bhanug/harvey
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;
}
コード例 #4
0
ファイル: smbrap2.c プロジェクト: bhanug/harvey
static int
serverinfoput(SmbBuffer *b, uint16_t level, void *data)
{
	SmbServerInfo *si = data;
	if (!smbbufferputstrn(b, si->name, 16, 1))
		return 0;
	if (level > 0) {
		if (!smbbufferputb(b, si->vmaj)
			|| !smbbufferputb(b, si->vmin)
			|| !smbbufferputl(b, si->stype)
			|| !smbbufferputl(b, 0))
			return 0;
	}
	if (level > 1)
		return 0;
	return 1;
}
コード例 #5
0
ファイル: smbrap2.c プロジェクト: bhanug/harvey
static int
shareinfoput(SmbBuffer *b, uint16_t level, void *data)
{
	SmbService *serv = data;
	if (!smbbufferputstrn(b, serv->name, 13, 0))
		return 0;
	if (level > 0) {
		if (!smbbufferputb(b, 0)
			|| !smbbufferputs(b, serv->stype)
			|| !smbbufferputl(b, 0))
			return 0;
	}
	if (level > 1) {
		if (!smbbufferputs(b, 7)
			|| !smbbufferputs(b, -1)
			|| !smbbufferputs(b, serv->ref)
			|| !smbbufferputl(b, 0)
			|| !smbbufferfill(b, 0, 10))
			return 0;
	}
	if (level > 2)
		return 0;
	return 1;
}
コード例 #6
0
ファイル: smbtrans2find.c プロジェクト: AustenConrad/plan-9
static void
populate(SmbSession *s, SmbDirCache *dc, Reprog *r, ushort informationlevel, ushort flags, ushort scount,
	ushort *ep, ulong *nameoffsetp)
{
	ushort e;
	ulong nameoffset;
	e = 0;
	nameoffset = 0;
	while (dc->i < dc->n && e < scount) {
		ulong backup;
		int rv;
		
		if (!smbmatch(dc->buf[dc->i].name, r)) {
			dc->i++;
			continue;
		}
		rv = 0;
		backup = smbbufferwriteoffset(s->transaction.out.data);
		switch (informationlevel) {
		case SMB_INFO_STANDARD:
			if (flags & SMB_FIND_RETURN_RESUME_KEYS) {
				if (!smbbufferputl(s->transaction.out.data, dc->i)) {
					rv = 0;
					break;
				}
			}
			rv = standardflatten(s, s->transaction.out.data, dc->buf + dc->i, &nameoffset);
			break;
		case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
			rv = findbothflatten(s->transaction.out.data, &s->peerinfo, dc->buf + dc->i, dc->i, &nameoffset);
			break;
		}
		if (rv == 0) {
			smbbufferwritebackup(s->transaction.out.data, backup);
			break;
		}
		dc->i++;
		e++;
	}
	*ep = e;
	*nameoffsetp = nameoffset;
}
コード例 #7
0
ファイル: smbnegotiate.c プロジェクト: 99years/plan9
SmbProcessResult
smbnegotiate(SmbSession *s, SmbHeader *h, uchar *, SmbBuffer *b)
{
	ushort index;
	int i;
	uchar bufferformat;

	if (!smbcheckwordcount("negotiate", h, 0))
		return SmbProcessResultFormat;
	if (s->state != SmbSessionNeedNegotiate) {
		/* this acts as a complete session reset */
		smblogprint(-1, "smbnegotiate: called when already negotiated\n");
		return SmbProcessResultUnimp;
	}
	i = 0;
	index = 0xffff;
	while (smbbuffergetb(b, &bufferformat)) {
		char *s;
		if (bufferformat != 0x02) {
			smblogprint(-1, "smbnegotiate: unrecognised buffer format 0x%.2ux\n", bufferformat);
			return SmbProcessResultFormat;
		}
		if (!smbbuffergetstr(b, 0, &s)) {
			smblogprint(-1, "smbnegotiate: no null found\n");
			return SmbProcessResultFormat;
		}
		smblogprint(h->command, "smbnegotiate: '%s'\n", s);
		if (index == 0xffff && strcmp(s, "NT LM 0.12") == 0)
			index = i;
		i++;
		free(s);
	}
	if (index != 0xffff) {
		Tm *tm;
		ulong capabilities;
		ulong bytecountfixupoffset;

		h->wordcount = 17;
		if (!smbbufferputheader(s->response, h, nil)
			|| !smbbufferputs(s->response, index)
			|| !smbbufferputb(s->response, 3)			/* user security, encrypted */
			|| !smbbufferputs(s->response, 1)			/* max mux */
			|| !smbbufferputs(s->response, 1)			/* max vc */
			|| !smbbufferputl(s->response, smbglobals.maxreceive)		/* max buffer size */
			|| !smbbufferputl(s->response, 0x10000)		/* max raw */
			|| !smbbufferputl(s->response, threadid()))	/* session key */
			goto die;
		/* <= Win2k insist upon this being set to ensure that they observe the prototol (!) */
		capabilities = CAP_NT_SMBS;
		if (smbglobals.unicode)
			capabilities |= CAP_UNICODE;
		tm = localtime(time(nil));
		s->tzoff = tm->tzoff;
		if (!smbbufferputl(s->response, capabilities)
			|| !smbbufferputv(s->response, nsec() / 100 + (vlong)10000000 * 11644473600LL)
			|| !smbbufferputs(s->response, -s->tzoff / 60)
			|| !smbbufferputb(s->response, 8))	/* crypt len */
			goto die;
		bytecountfixupoffset = smbbufferwriteoffset(s->response);
		if (!smbbufferputs(s->response, 0))
			goto die;
		s->cs = auth_challenge("proto=mschap role=server");
		if (s->cs == nil) {
			smblogprint(h->command, "smbnegotiate: couldn't get mschap challenge\n");
			return SmbProcessResultMisc;
		}
		if (s->cs->nchal != 8) {
			smblogprint(h->command, "smbnegotiate: nchal %d\n", s->cs->nchal);
			return SmbProcessResultMisc;
		}
		if (!smbbufferputbytes(s->response, s->cs->chal, s->cs->nchal)
			|| !smbbufferputstring(s->response, nil, SMB_STRING_UNICODE, smbglobals.primarydomain)
			|| !smbbufferfixuprelatives(s->response, bytecountfixupoffset))
			goto die;
	}
	else {
		h->wordcount = 1;
		if (!smbbufferputheader(s->response, h, nil)
			|| !smbbufferputs(s->response, index)
			|| !smbbufferputs(s->response, 0))
			goto die;
	}
	s->state = SmbSessionNeedSetup;
	return SmbProcessResultReply;
die:
	return SmbProcessResultDie;
}
コード例 #8
0
ファイル: smbresponse.c プロジェクト: 99years/plan9
int
smbresponseputl(SmbSession *s, ulong l)
{
	return smbbufferputl(s->response, l);
}
コード例 #9
0
ファイル: smbtrans2client.c プロジェクト: AustenConrad/plan-9
int
smbclienttrans2findfirst2(SmbClient *c, ushort searchcount, char *filename,
	ushort *sidp, ushort *searchcountp, ushort *endofsearchp,SmbFindFileBothDirectoryInfo *ip, char **errmsgp)
{
	int rv;
	ushort setup;
	SmbBuffer *inparam;
	SmbBuffer *outparam;
	SmbBuffer *outdata;
	SmbHeader rh;
	setup = SMB_TRANS2_FIND_FIRST2;
	inparam = smbbuffernew(512);
	smbbufferputs(inparam, 0x16);
	smbbufferputs(inparam, searchcount);
	smbbufferputs(inparam, 7);
	smbbufferputs(inparam, SMB_FIND_FILE_BOTH_DIRECTORY_INFO);
	smbbufferputl(inparam, 0);
	smbbufferputstring(inparam, &c->peerinfo, 0, filename);
	outparam = smbbuffernew(10);
	outdata = smbbuffernew(65535);
	rv = smbclienttrans2(c, 1, &setup, inparam, outparam, outdata, &rh, errmsgp);
	smbbufferfree(&inparam);
	if (rv) {
		ushort eaerroroffset, lastnameoffset;
		ulong nextentry;
		int i;

		if (!smbbuffergets(outparam, sidp)
			|| !smbbuffergets(outparam, searchcountp)
			|| !smbbuffergets(outparam, endofsearchp)
			|| !smbbuffergets(outparam, &eaerroroffset)
			|| !smbbuffergets(outparam, &lastnameoffset)) {
			smbstringprint(errmsgp, "smbclienttrans2findfirst2: not enough parameters returned");
			rv = 0;
			goto done;
		}
		nextentry = 0;
smblogprint(-1, "returned data:\n");
smblogdata(-1, smblogprint, smbbufferreadpointer(outdata), smbbufferreadspace(outdata), 256);
		for (i = 0; i < *searchcountp; i++) {
			SmbFindFileBothDirectoryInfo *info = ip + i;
			ulong neo, filenamelength, easize;
			uchar shortnamelength;
			if (i && !smbbufferreadskipto(outdata, nextentry)) {
			underflow:
				smbstringprint(errmsgp, "smbclientrans2findfirst2: not enough data returned");
				rv = 0;
				goto done;
			}
			if (!smbbuffergetl(outdata, &neo))
				goto underflow;
			nextentry = smbbufferreadoffset(outdata) + neo - 4;
print("neo 0x%.8lux\n", neo);
			if (!smbbuffergetl(outdata, &info->fileindex)
				|| !smbbuffergetv(outdata, &info->creationtime)
				|| !smbbuffergetv(outdata, &info->lastaccesstime)
				|| !smbbuffergetv(outdata, &info->lastwritetime)
				|| !smbbuffergetv(outdata, &info->changetime)
				|| !smbbuffergetv(outdata, &info->endoffile)
				|| !smbbuffergetv(outdata, &info->allocationsize))
				goto underflow;
print("got here\n");
			if (!smbbuffergetl(outdata, &info->extfileattributes)
				|| !smbbuffergetl(outdata, &filenamelength)
				|| !smbbuffergetl(outdata, &easize)
				|| !smbbuffergetb(outdata, &shortnamelength)
				|| !smbbuffergetbytes(outdata, nil, 1)
				|| !smbbuffergetbytes(outdata, nil, 24)
				|| !smbbuffergetstring(outdata, &rh, SMB_STRING_REVPATH, &info->filename))
				goto underflow;
print("got here as well\n");
		}
	}
done:
	smbbufferfree(&outparam);
	smbbufferfree(&outdata);
	return rv;
}
コード例 #10
0
ファイル: smbcomwrite.c プロジェクト: CoryXie/nix-os
SmbProcessResult
smbcomwriteandx(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b)
{
	uchar andxcommand;
	ushort andxoffset;
	ulong andxoffsetfixup;
	SmbTree *t;
	SmbFile *f;
	ushort dataoff, fid, count;
	vlong offset;
	long nb;

	if (h->wordcount != 12 && h->wordcount != 14)
		return SmbProcessResultFormat;

	andxcommand = *pdata++;				// andx command
	pdata++;					// reserved 
	andxoffset = smbnhgets(pdata); pdata += 2;	// andx offset
	fid = smbnhgets(pdata); pdata += 2;		// fid
	offset = smbnhgetl(pdata); pdata += 4;		// offset in file
	pdata += 4;					// timeout
	pdata += 2;					// write mode
	pdata += 2;					// (Remaining) bytes waiting to be written
	pdata += 2;					// Reserved
	count = smbnhgets(pdata); pdata += 2;		// LSBs of length
	dataoff = smbnhgets(pdata); pdata += 2;		// offset to data in packet
	if (dataoff + count > smbbufferwriteoffset(b))
		return SmbProcessResultFormat;
	if(h->wordcount == 14)
		offset |= (vlong)smbnhgetl(pdata)<<32;

	smblogprint(SMB_COM_WRITE_ANDX, "smbcomwriteandx: fid 0x%.4ux count 0x%.4ux offset 0x%.llux\n",
		fid, count, offset);


	t = smbidmapfind(s->tidmap, h->tid);
	if (t == nil) {
		smbseterror(s, ERRSRV, ERRinvtid);
		return SmbProcessResultError;
	}
	f = smbidmapfind(s->fidmap, fid);
	if (f == nil) {
		smbseterror(s, ERRDOS, ERRbadfid);
		return SmbProcessResultError;
	}

	if (!f->ioallowed) {
		smbseterror(s, ERRDOS, ERRbadaccess);
		return SmbProcessResultError;
	}

	seek(f->fd, offset, 0);
	nb = write(f->fd, smbbufferpointer(b, dataoff), count);
	if (nb < 0) {
		smbseterror(s, ERRDOS, ERRnoaccess);
		return SmbProcessResultError;
	}

	h->wordcount = 6;
	if (!smbbufferputandxheader(s->response, h, &s->peerinfo, andxcommand, &andxoffsetfixup))
		return SmbProcessResultMisc;

	if (!smbbufferputs(s->response, nb)			// Count
		|| !smbbufferputs(s->response, 0)		// Available
		|| !smbbufferputl(s->response, 0)		// Reserved
		|| !smbbufferputs(s->response, 0))		// byte count in reply
		return SmbProcessResultMisc;

	if (andxcommand != SMB_COM_NO_ANDX_COMMAND)
		return smbchaincommand(s, h, andxoffsetfixup, andxcommand, andxoffset, b);

	return SmbProcessResultReply;
}
コード例 #11
0
ファイル: smbtransaction.c プロジェクト: Requaos/harvey
static int
_transactionencodeprimary(SmbTransaction *t, uint8_t cmd, SmbHeader *h,
			  SmbPeerInfo *p, SmbBuffer *ob,
	uint8_t *wordcountp, uint16_t *bytecountp, char **errmsgp)
{
	SmbHeader mh;
	uint32_t countsfixupoffset, bytecountfixupoffset;
	int x;
	mh = *h;
	*wordcountp = mh.wordcount = 14 + t->in.scount;
	mh.flags &= ~SMB_FLAGS_SERVER_TO_REDIR;
	mh.command = cmd;
	if (!smbbufferputheader(ob, &mh, p)) {
	toosmall:
		smbstringprint(errmsgp, "output buffer too small");
		return 0;
	}
	if (t->in.tpcount > 65535 || t->in.tdcount > 65535 || t->in.maxpcount > 65535 || t->in.maxdcount > 65535) {
		smbstringprint(errmsgp, "counts too big");
		return 0;
	}
	if (!smbbufferputs(ob, t->in.tpcount)
		|| !smbbufferputs(ob, t->in.tdcount)
		|| !smbbufferputs(ob, t->in.maxpcount)
		|| !smbbufferputs(ob, t->in.maxdcount)
		|| !smbbufferputb(ob, t->in.maxscount)
		|| !smbbufferputb(ob, 0)
		|| !smbbufferputs(ob, t->in.flags)
		|| !smbbufferputl(ob, 0)
		|| !smbbufferputs(ob, 0))
		goto toosmall;
	countsfixupoffset = smbbufferwriteoffset(ob);
	if (!smbbufferputs(ob, 0)
		|| !smbbufferputs(ob, 0)
		|| !smbbufferputs(ob, 0)
		|| !smbbufferputs(ob, 0))
		goto toosmall;
	if (!smbbufferputb(ob, t->in.scount)
		|| !smbbufferputb(ob, 0))
		goto toosmall;
	for (x = 0; x < t->in.scount; x++)
		if (!smbbufferputs(ob, t->in.setup[x]))
			goto toosmall;
	bytecountfixupoffset = smbbufferwriteoffset(ob);
	if (!smbbufferputs(ob, 0))
		goto toosmall;
	smbbufferwritelimit(ob, smbbufferwriteoffset(ob) + 65535);
	if (!smbbufferputstring(ob, p, SMB_STRING_UPCASE, t->in.name))
		goto toosmall;
	if (t->in.pcount < t->in.tpcount) {
		uint32_t align = smbbufferwriteoffset(ob) & 1;
		uint32_t pthistime;
		pthistime = smbbufferwritespace(ob) - align;
		if (pthistime > t->in.tpcount - t->in.pcount)
			pthistime = t->in.tpcount - t->in.pcount;
		if (pthistime > 65535)
			pthistime = 65535;
		if (smbbufferwriteoffset(ob) > 65535)
			pthistime = 0;
		if (pthistime) {
			assert(smbbufferalignl2(ob, 0));
			assert(smbbufferoffsetputs(ob, countsfixupoffset, pthistime));
			assert(smbbufferoffsetputs(ob, countsfixupoffset + 2, smbbufferwriteoffset(ob)));
			assert(smbbufferputbytes(ob, t->in.parameters + t->in.pcount, pthistime));
		}
		t->in.pcount += pthistime;
	}
	if (t->in.dcount < t->in.tdcount) {
		uint32_t align = smbbufferwriteoffset(ob) & 1;
		uint32_t dthistime;
		dthistime = smbbufferwritespace(ob) - align;
		if (dthistime > t->in.tdcount - t->in.dcount)
			dthistime = t->in.tdcount - t->in.dcount;
		if (dthistime > 65535)
			dthistime = 65535;
		if (smbbufferwriteoffset(ob) > 65535)
			dthistime = 0;
		if (dthistime) {
			assert(smbbufferalignl2(ob, 0));
			assert(smbbufferoffsetputs(ob, countsfixupoffset + 4, dthistime));
			assert(smbbufferoffsetputs(ob, countsfixupoffset + 6, smbbufferwriteoffset(ob)));
			assert(smbbufferputbytes(ob, t->in.data + t->in.dcount, dthistime));
		}
		t->in.dcount += dthistime;
	}
	*bytecountp = smbbufferwriteoffset(ob) - bytecountfixupoffset - 2;
	assert(smbbufferoffsetputs(ob, bytecountfixupoffset, *bytecountp));
	return 1;
}
コード例 #12
0
ファイル: smbrap2client.c プロジェクト: Requaos/harvey
int
smbnetserverenum2(SmbClient *c, uint32_t stype, char *domain,
		  int *entriesp,
		  SmbRapServerInfo1 **sip, char **errmsgp)
{
	int rv;
	uint16_t ec, entries, total, converter;
	SmbRapServerInfo1 *si = nil;
	SmbBuffer *ipb = smbbuffernew(512);
	SmbBuffer *odb = smbbuffernew(65535);
	SmbBuffer *opb = smbbuffernew(8);
	smbbufferputs(ipb, 104);
	smbbufferputstring(ipb, nil, SMB_STRING_ASCII, "WrLehDz");
	smbbufferputstring(ipb, nil, SMB_STRING_ASCII, "B16BBDz");
	smbbufferputs(ipb, 1);
	smbbufferputs(ipb, smbbufferwritespace(odb));
	smbbufferputl(ipb, stype);
	smbbufferputstring(ipb, nil, SMB_STRING_ASCII, domain);
	rv = !smbclientrap(c, ipb, opb, odb, errmsgp);
	smbbufferfree(&ipb);
	if (rv == 0) {
		char *remark, *eremark;
		int remarkspace;
		int i;
		if (!smbbuffergets(opb, &ec)
			|| !smbbuffergets(opb, &converter)
			|| !smbbuffergets(opb, &entries)
			|| !smbbuffergets(opb, &total)) {
			smbstringprint(errmsgp, "smbnetserverenum2: not enough return parameters");
			rv = -1;
			goto done;
		}
		if (ec != 0) {
			rv = ec;
			goto done;
		}
		if (smbbufferreadspace(odb) < entries * 26) {
			smbstringprint(errmsgp, "smbnetserverenum2: not enough return data");
			rv = -1;
			goto done;
		}
		remarkspace = smbbufferreadspace(odb) - entries * 26;
		si = smbemalloc(entries * sizeof(SmbRapServerInfo1) + remarkspace);
		remark = (char *)&si[entries];
		eremark = remark + remarkspace;
		for (i = 0; i < entries; i++) {
			uint32_t offset;
			int remarklen;
			assert(smbbuffergetbytes(odb, si[i].name, 16));
			assert(smbbuffergetb(odb, &si[i].vmaj));
			assert(smbbuffergetb(odb, &si[i].vmin));
			assert(smbbuffergetl(odb, &si[i].type));
			assert(smbbuffergetl(odb, &offset));
			offset -= converter;
			if (!smbbufferoffsetcopystr(odb, offset, remark, eremark - remark, &remarklen)) {
				smbstringprint(errmsgp, "smbnetserverenum2: invalid string offset");
				rv = -1;
				goto done;
			}
			si[i].remark = remark;
			remark += remarklen;
		}
		*sip = si;
		si = nil;
		*entriesp = entries;
	}
	else
		rv = -1;	
done:
	free(si);
	smbbufferfree(&opb);
	smbbufferfree(&odb);
	return rv;
}