Пример #1
0
SmbProcessResult
smbcomtreeconnectandx(SmbSession *s, SmbHeader *h, uint8_t *pdata,
                      SmbBuffer *b)
{
    uint8_t andxcommand;
    uint16_t andxoffset;
    char *path = nil;
    char *service = nil;
    uint16_t flags;
    uint16_t passwordlength;
//	ushort bytecount;
    uint8_t errclass;
    uint16_t error;
    SmbService *serv;
    SmbTree *tree;
    uint32_t andxfixupoffset, bytecountfixup;
    SmbProcessResult pr;

    if (!smbcheckwordcount("comtreeconnectandx", h, 4)) {
fmtfail:
        pr = SmbProcessResultFormat;
        goto done;
    }

    switch (s->state) {
    case SmbSessionNeedNegotiate:
        smblogprint(-1, "smbcomtreeconnectandx: called when negotiate expected\n");
        return SmbProcessResultUnimp;
    case SmbSessionNeedSetup:
        smbseterror(s, ERRDOS, ERRbadpw);
        return SmbProcessResultError;
    }

    andxcommand = *pdata++;
    switch (andxcommand) {
    case SMB_COM_OPEN:
    case SMB_COM_CREATE_NEW:
    case SMB_COM_DELETE_DIRECTORY:
    case SMB_COM_FIND_UNIQUE:
    case SMB_COM_CHECK_DIRECTORY:
    case SMB_COM_GET_PRINT_QUEUE:
    case SMB_COM_TRANSACTION:
    case SMB_COM_SET_INFORMATION:
    case SMB_COM_OPEN_ANDX:
    case SMB_COM_CREATE_DIRECTORY:
    case SMB_COM_FIND:
    case SMB_COM_RENAME:
    case SMB_COM_QUERY_INFORMATION:
    case SMB_COM_OPEN_PRINT_FILE:
    case SMB_COM_NO_ANDX_COMMAND:
    case SMB_COM_NT_RENAME:
    case SMB_COM_CREATE:
    case SMB_COM_DELETE:
    case SMB_COM_COPY:
        break;
    default:
        smblogprint(h->command, "smbcomtreeconnectandx: invalid andxcommand %s (0x%.2ux)\n",
                    smboptable[andxcommand].name, andxcommand);
        goto fmtfail;
    }
    pdata++;
    andxoffset = smbnhgets(pdata);
    pdata += 2;
    flags = smbnhgets(pdata);
    pdata += 2;
    passwordlength = smbnhgets(pdata); //pdata += 2;
//	bytecount = smbnhgets(pdata); pdata += 2;
    smblogprint(h->command, "passwordlength: %ud\n", passwordlength);
    smblogprint(h->command, "flags: 0x%.4ux\n", flags);
    if (!smbbuffergetbytes(b, nil, passwordlength)) {
        smblogprint(h->command, "smbcomtreeconnectandx: not enough bytes for password\n");
        goto fmtfail;
    }
    smblogprint(h->command, "offset %lud limit %lud\n", smbbufferreadoffset(b), smbbufferwriteoffset(b));
    if (!smbbuffergetstring(b, h, SMB_STRING_PATH, &path)
            || !smbbuffergetstr(b, 0, &service)) {
        smblogprint(h->command, "smbcomtreeconnectandx: not enough bytes for strings\n");
        goto fmtfail;
    }
    smblogprint(h->command, "path: %s\n", path);
    smblogprint(h->command, "service: %s\n", service);
    if (flags & 1)
        smbtreedisconnectbyid(s, h->tid);
    serv = smbservicefind(s, path, service, &errclass, &error);
    if (serv == nil) {
        pr = SmbProcessResultError;
        smbseterror(s, errclass, error);
        goto done;
    }
    tree = smbtreeconnect(s, serv);
    h->tid = tree->id;
    h->wordcount = 3;
    if (!smbresponseputandxheader(s, h, andxcommand, &andxfixupoffset)
            || !smbresponseputs(s, 1)) {
misc:
        pr = SmbProcessResultMisc;
        goto done;
    }
    bytecountfixup = smbresponseoffset(s);
    if (!smbresponseputs(s, 0)
            || !smbresponseputstr(s, serv->type)
            || !smbresponseputstring(s, 1, s9p2000))
        goto misc;
    if (!smbbufferfixuprelatives(s->response, bytecountfixup))
        goto misc;
    if (andxcommand != SMB_COM_NO_ANDX_COMMAND) {
        pr = smbchaincommand(s, h, andxfixupoffset, andxcommand, andxoffset, b);
    }
    else
        pr = SmbProcessResultReply;
done:
    free(path);
    free(service);
    return pr;
}
SmbProcessResult
smbcomsessionsetupandx(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b)
{
	uchar andxcommand;
	ushort andxoffset;
	ulong andxfixupoffset;
	ushort vcnumber;
	ulong sessionkey;
	ushort caseinsensitivepasswordlength;
	ushort casesensitivepasswordlength;
	ushort bytecountfixup, offset;
	uchar *mschapreply;
	AuthInfo *ai;
	char *sp;
	SmbProcessResult pr;
	char *accountname = nil;
	char *primarydomain = nil;
	char *nativeos = nil;
	char *nativelanman = nil;

	if (!smbcheckwordcount("comsessionsetupandx", h, 13)) {
	fmtfail:
		pr = SmbProcessResultFormat;
		goto done;
	}

	andxcommand = *pdata++;
	switch (andxcommand) {
	case SMB_COM_TREE_CONNECT_ANDX:
	case SMB_COM_OPEN_ANDX:
	case SMB_COM_CREATE_NEW:
	case SMB_COM_DELETE:
	case SMB_COM_FIND:
	case SMB_COM_COPY:
	case SMB_COM_NT_RENAME:
	case SMB_COM_QUERY_INFORMATION:
	case SMB_COM_NO_ANDX_COMMAND:
	case SMB_COM_OPEN:
	case SMB_COM_CREATE:
	case SMB_COM_CREATE_DIRECTORY:
	case SMB_COM_DELETE_DIRECTORY:
	case SMB_COM_FIND_UNIQUE:
	case SMB_COM_RENAME:
	case SMB_COM_CHECK_DIRECTORY:
	case SMB_COM_SET_INFORMATION:
	case SMB_COM_OPEN_PRINT_FILE:
		break;
	default:
		smblogprint(h->command, "smbcomsessionsetupandx: invalid andxcommand %s (0x%.2ux)\n",
			smboptable[andxcommand].name, andxcommand);
		goto fmtfail;
	}
	pdata++;
	andxoffset = smbnhgets(pdata); pdata += 2;
	s->peerinfo.maxlen = smbnhgets(pdata); pdata += 2;
	smbresponseinit(s, s->peerinfo.maxlen);
	s->client.maxmpxcount = smbnhgets(pdata); pdata += 2;
	vcnumber = smbnhgets(pdata); pdata += 2;
	sessionkey = smbnhgetl(pdata); pdata += 4;
	caseinsensitivepasswordlength = smbnhgets(pdata); pdata += 2;
	casesensitivepasswordlength = smbnhgets(pdata); pdata += 2;
	pdata += 4;
	s->peerinfo.capabilities = smbnhgetl(pdata); /*pdata += 4;*/
smbloglock();
smblogprint(h->command, "andxcommand: %s offset %ud\n", smboptable[andxcommand].name, andxoffset);
smblogprint(h->command, "client.maxbuffersize: %ud\n", s->peerinfo.maxlen);
smblogprint(h->command, "client.maxmpxcount: %ud\n", s->client.maxmpxcount);
smblogprint(h->command, "vcnumber: %ud\n", vcnumber);
smblogprint(h->command, "sessionkey: 0x%.8lux\n", sessionkey);
smblogprint(h->command, "caseinsensitivepasswordlength: %ud\n", caseinsensitivepasswordlength);
smblogprint(h->command, "casesensitivepasswordlength: %ud\n", casesensitivepasswordlength);
smblogprint(h->command, "clientcapabilities: 0x%.8lux\n", s->peerinfo.capabilities);
smblogunlock();

	mschapreply = smbbufferreadpointer(b);

	if (!smbbuffergetbytes(b, nil, caseinsensitivepasswordlength + casesensitivepasswordlength)) {
		smblogprint(h->command, "smbcomsessionsetupandx: not enough bdata for passwords\n");
		goto fmtfail;
	}
	if (!smbbuffergetstring(b, h, 0, &accountname)
		|| !smbbuffergetstring(b, h, 0, &primarydomain)
		|| !smbbuffergetstring(b, h, 0, &nativeos)
		|| !smbbuffergetstring(b, h, 0, &nativelanman)) {
		smblogprint(h->command, "smbcomsessionsetupandx: not enough bytes for strings\n");
		goto fmtfail;
	}

	for (sp = accountname; *sp; sp++)
		*sp = tolower(*sp);

smblogprint(h->command, "account: %s\n", accountname);
smblogprint(h->command, "primarydomain: %s\n", primarydomain);
smblogprint(h->command, "nativeos: %s\n", nativeos);
smblogprint(h->command, "nativelanman: %s\n", nativelanman);

	if (s->client.accountname && accountname[0] && strcmp(s->client.accountname, accountname) != 0) {
		smblogprint(h->command, "smbcomsessionsetupandx: more than one user on VC (before %s, now %s)\n",
			s->client.accountname, accountname);
		smbseterror(s, ERRSRV, ERRtoomanyuids);
	errordone:
		pr = SmbProcessResultError;
		goto done;
	}

	if (s->client.accountname == nil) {
		/* first time */
		if (accountname[0] == 0) {
			smbseterror(s, ERRSRV, ERRbaduid);
			goto errordone;
		}
		if ((casesensitivepasswordlength != 24 || caseinsensitivepasswordlength != 24)) {
			smblogprint(h->command,
				"smbcomsessionsetupandx: case sensitive/insensitive password length not 24\n");
			smbseterror(s, ERRSRV, ERRbadpw);
			goto errordone;
		}
		memcpy(&s->client.mschapreply, mschapreply, sizeof(s->client.mschapreply));
		if(s->cs == nil){
			smbseterror(s, ERRSRV, ERRerror);
			goto errordone;
		}
		s->cs->user = accountname;
		s->cs->resp = &s->client.mschapreply;
		s->cs->nresp = sizeof(MSchapreply);
		ai = auth_response(s->cs);
		if (ai == nil) {
			smblogprint(h->command, "authentication failed\n");
			smbseterror(s, ERRSRV, ERRbadpw);
			goto errordone;
		}
		smblogprint(h->command, "authentication succeeded\n");
		if (auth_chuid(ai, nil) < 0) {
			smblogprint(h->command, "smbcomsessionsetupandx: chuid failed: %r\n");
			auth_freeAI(ai);
		miscerror:
			pr = SmbProcessResultMisc;
			goto done;
		}
		auth_freeAI(ai);
		h->uid = 1;
		s->client.accountname = accountname;
		s->client.primarydomain = primarydomain;
		s->client.nativeos = nativeos;
		s->client.nativelanman = nativelanman;
		accountname = nil;
		primarydomain = nil;
		nativeos = nil;
		nativelanman = nil;
	}
	else {
		if (caseinsensitivepasswordlength == 24 && casesensitivepasswordlength == 24
			&& memcmp(&s->client.mschapreply, mschapreply, sizeof(MSchapreply)) != 0) {
			smblogprint(h->command, "second time authentication failed\n");
			smbseterror(s, ERRSRV, ERRbadpw);
			goto errordone;
		}
	}

	/* CIFS says 4 with or without extended security, samba/ms says 3 without */
	h->wordcount = 3;
	if (!smbresponseputandxheader(s, h, andxcommand, &andxfixupoffset))
		goto miscerror;
	if (!smbresponseputs(s, 0))
		goto miscerror;
	bytecountfixup = smbresponseoffset(s);
	if (!smbresponseputs(s, 0))
		goto miscerror;
	if (!smbresponseputstring(s, 1, smbglobals.nativeos)
		|| !smbresponseputstring(s, 1, smbglobals.serverinfo.nativelanman)
		|| !smbresponseputstring(s, 1, smbglobals.primarydomain))
		goto miscerror;
	offset = smbresponseoffset(s);
	smbresponseoffsetputs(s, bytecountfixup, offset - bytecountfixup - 2);
	s->state = SmbSessionEstablished;
	if (andxcommand != SMB_COM_NO_ANDX_COMMAND)
		pr = smbchaincommand(s, h, andxfixupoffset, andxcommand, andxoffset, b);
	else
		pr = SmbProcessResultReply;
done:
	free(accountname);
	free(primarydomain);
	free(nativeos);
	free(nativelanman);
	return pr;
}