static int init_smb_response(struct smb_response* sr,unsigned char* in_response_to,size_t size) { if (size<200) size=200; sr->buf=malloc(sr->allocated=size); if (!sr->buf) return -1; sr->used=netbiosheadersize+smbheadersize; uint32_pack_big(sr->buf,32); // size field in NMB header byte_copy(sr->buf+netbiosheadersize,smbheadersize-8, "\xffSMB" // magic "x" // smb command, filled in later; ofs 4 "\x00\x00\x00\x00" // STATUS_SUCCESS "\x80" // Flags: response+case sensitive "\x41\xc0" // Flags2: unicode+long names allowed "\x00\x00" // Process ID High: 0 "\x00\x00\x00\x00\x00\x00\x00\x00" // Signature "\x00\x00" // Reserved ); // TID, PID, UID, MID; ofs 24 sr->buf[netbiosheadersize+4]=in_response_to[4]; uint16_pack(sr->buf+netbiosheadersize+24,uint16_read((char*)in_response_to+24)); uint16_pack(sr->buf+netbiosheadersize+26,uint16_read((char*)in_response_to+26)); uint16_pack(sr->buf+netbiosheadersize+28,0); uint16_pack(sr->buf+netbiosheadersize+30,uint16_read((char*)in_response_to+30)); sr->andxtypeofs=netbiosheadersize+4; return 0; }
static int smb_handle_echo(unsigned char* c,size_t len,struct smb_response* sr) { uint16 nmemb,membsize; char* buf; size_t i; if (len<2*1 || c[0] != 1) return -1; /* word count for this message is always 1 */ nmemb=uint16_read((char*)c+1); membsize=uint16_read((char*)c+3); if (nmemb*membsize>1024) return -1; buf=alloca(nmemb*membsize+3); buf[0]=0; uint16_pack(buf+1,nmemb*membsize); for (i=0; i<nmemb; ++i) byte_copy(buf+3+i*membsize,membsize,c+5); return add_smb_response(sr,buf,nmemb*membsize+3,0x2b); }
static int validate_smb_packet(unsigned char* pkt,unsigned long len) { /* we actually received len bytes from the wire, so pkt+len does not * overflow; we got len bytes, because the netbios header said there * were that many bytes in the packet. */ unsigned char* x; /* demand that we have at least a full smbheader and wordcount */ if (len>=smbheadersize+1 && byte_equal(pkt,4,"\xffSMB")) { /* signature needs to be there */ x=(unsigned char*)pkt+smbheadersize; if (x[0] > 100) return -1; /* see that x + sizeof(word_count) + word_count*2 + * sizeof(byte_count) is inside the packet */ if (!range_arrayinbuf(pkt,len,x+3,*x,2)) return -1; /* now we know the word count is ok, but is the byte count? */ { size_t bytecountofs=1+*x*2; size_t bytecount; bytecount=uint16_read((const char*)x+bytecountofs); if (bytecount>len || x+bytecountofs+2+bytecount>pkt+len) return -1; } if (!hasandx(pkt[4])) return 0; for (;;) { size_t bytecount; /* see that x + sizeof(word_count) + word_count*2 + * sizeof(byte_count) is inside the packet */ if (!range_arrayinbuf(pkt,len,x+3,*x,2)) return -1; /* we know that the byte count is within the packet */ /* read it and check whether it's ok, too */ bytecount=uint16_read((const char*)x+1+*x*2); if (!range_arrayinbuf(pkt,len,x+3+bytecount,*x,2)) return -1; if (x[1]==0xff) return 0; { uint16_t next=uint16_read((char*)x+3); if (pkt+next < x+1+x[0]*2+2+bytecount) return -1; /* can't point backwards */ x=pkt+next; } if (!range_bufinbuf(pkt,len,(char*)x,5)) return -1; } } else return -1; return 0; }
static int smb_handle_negotiate_request(unsigned char* c,size_t len,struct smb_response* sr) { size_t i,j,k; int ack; const char nr[2*17+100*2]= "\x11" // word count 17 "xx" // dialect index; ofs 1 "\x02" // security mode, for NT: plaintext passwords XOR unicode #if 0 "\x02\x00" // Max Mpx Count 2 "\x01\x00" // Max VCs 1 #else "\x10\x00" // Max Mpx Count 16 "\x10\x00" // Max VCs 16 #endif "\x04\x41\x00\x00" // Max Buffer Size (16644, like XP) "\x00\x00\x01\x00" // Max Raw Buffer (65536, like XP) "\x01\x02\x03\x04" // Session Key "\x5e\x40\x00\x00" // Capabilities, the bare minimum "xxxxxxxx" // system time; ofs 24 "xx" // server time zone; ofs 32 "\x00" // key len "xx" // byte count; ofs 35 ; // workgroup name; ofs 37 char* x; if (len<3) return -1; j=uint16_read((char*)c+1); if (len<3+j) return -1; ack=-1; for (k=0,i=3; i<3+j; ++k) { if (c[i]!=2) return -1; if (str_equal((char*)c+i+1,"NT LM 0.12")) { ack=k; break; } i+=2+str_len((char*)c+i+1); } if (ack==-1) return -1; // wrong dialect if (!(x=add_smb_response2(sr,nr,38+wglen16,0x72))) return -1; uint16_pack(x+1,ack); { struct timeval t; unsigned long long ntdate; gettimeofday(&t,&tz); ntdate=10000000ll * ( t.tv_sec + 11644473600ll ) + t.tv_usec * 10ll; uint32_pack(x+24,ntdate&0xffffffff); uint32_pack(x+24+4,ntdate>>32); uint16_pack(x+32,tz.tz_minuteswest); } uint16_pack(x+35,wglen16); byte_copy(x+37,wglen16,workgroup_utf16); return 0; }
/* returns number of converted chars in dest, including \0, or 0 on error */ static size_t utf16tolatin1(char* dest,size_t dsize,uint16_t* src,size_t ssize) { size_t i; size_t max=dsize; if (ssize/2<max) max=ssize/2; for (i=0; i<max; ++i) { uint16_t x=uint16_read((char*)&src[i]); if (x>0xff) return 0; dest[i]=x; } if (i==dsize) return 0; dest[i]=0; return i+1; }
uint64 elf_get_value(void* elf, void* ptr, unsigned off32, unsigned size32, unsigned off64, unsigned size64) { uint8* base = elf; uint8* p = ptr; unsigned off, size; uint64 ret = 0; if(ELF_32(base)) { off = off32; size = size32; } else { off = off64; size = size64; } switch(size) { case 8: ret = uint64_read((const char*)&p[off]); break; case 4: ret = uint32_read((const char*)&p[off]); break; case 2: ret = uint16_read((const char*)&p[off]); break; case 1: ret = p[off]; break; } return ret; }
static int smb_handle_OpenAndX(struct http_data* h,unsigned char* c,size_t len,uint32_t pid,struct smb_response* sr) { static const char nr[34]= "\x0f" // word count 15 "\xff" // AndXCommand "\x00" // Reserved "w1" // AndXOffset; ofs 3 "w2" // FID; ofs 5 "\x00\x00" // file attributes; normal file "u1__" // ctime; ofs 9 "u2__" // file size; ofs 13 "\x00\x00" // granted access: read, compatibility mode, caching permitted "\x00\x00" // file type: disk file or directory "\x00\x00" // ipc state "\x01\x00" // action: file existed and was opened "\x00\x00\x00\x00" // server FID (?!?) "\x00\x00" // reserved "\x00\x00" // byte count 0 ; if (len<2*15 || c[0]!=15) return -1; /* see if it is an open for reading */ if ((c[7]&7) || ((c[17]&3)!=1)) { /* we only support read access */ // printf("non-read-access requested: %x %x!\n",c[7],c[17]); set_smb_error(sr,ERROR_ACCESS_DENIED,0x2d); return 0; } /* now look at file name */ { size_t fnlen=uint16_read((char*)c+31); uint16_t* remotefilename=(uint16_t*)(c+34); struct stat ss; struct handle* hdl; int fd; char* x; if (fnlen%2) --fnlen; if (fnlen>2046 || ((uintptr_t)remotefilename%2)) return -1; hdl=alloc_handle(&h->h); if (!hdl) { // printf("could not open file handle!"); set_smb_error(sr,STATUS_TOO_MANY_OPENED_FILES,0x2d); return 0; } fd=smb_open(h,remotefilename,fnlen,&ss,WANT_OPEN); if (fd==-1) { set_smb_error(sr,ERROR_OBJECT_NAME_NOT_FOUND,0x2d); close_handle(hdl); return 0; } hdl->fd=fd; hdl->pid=pid; hdl->size=ss.st_size; hdl->cur=0; hdl->filename=malloc(fnlen+2); if (hdl->filename) { memcpy(hdl->filename+1,remotefilename,fnlen); hdl->filename[0]=fnlen; } { size_t oldlen=sr->used; if (!(x=add_smb_response2(sr,nr,15*2+3,0x2d))) return -1; uint16_pack(x+OFS16(nr,"w1"),oldlen+15*2+3); } uint16_pack(x+OFS16(nr,"w2"),hdl->handle); uint32_pack(x+OFS16(nr,"u1"),ss.st_mtime); uint32_pack(x+OFS16(nr,"u2"),ss.st_size); } return 0; }