static int smb_handle_SessionSetupAndX(unsigned char* pkt,unsigned long len,struct smb_response* sr) { const char nr[]= "\x03" // Word Count 3 "\xff" // AndXCommand "\x00" // Reserved "xx" // AndXOffset; ofs 3 "\x01\x00" // Action: logged in as GUEST "xx" // Byte Count; ofs 7 "\x00" // bizarre padding byte "U\x00n\x00i\x00x\x00\x00\x00" // "Unix" "G\x00""a\x00t\x00l\x00i\x00n\x00g\x00 \x00"; size_t i,payloadlen; char* x; if (len<2*13 || pkt[0] != 13) return -1; /* word count for this message is always 13 */ payloadlen=sizeof("Unix_" RELEASE)*2 + wglen16 + 1; if (!(x=add_smb_response2(sr,nr,8+payloadlen,0x73))) return -1; uint16_pack(x+3,sr->used+2*3+payloadlen); uint16_pack(x+7,payloadlen); /* should be zero filled already so we only write the even bytes */ for (i=0; i<sizeof(RELEASE)-sizeof("Gatling ")+1; ++i) { x[8+2+(sizeof("Unix_Gatling")+i)*2]=VERSION[i]; x[8+2+(sizeof("Unix_Gatling")+i)*2+1]=0; } byte_copy(x+8+2+(sizeof("Unix_Gatling")+i)*2,wglen16+2,workgroup_utf16); return 0; }
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_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; }
char *generate_answer(stralloc *answer, uint32 uid, char *lip, uint16 lport, char *rip, uint16 rport) { char *problem = "ok"; char *x; char buf[5]; stralloc out = {0}; stralloc tmp = {0}; stralloc key = {0}; /* get key from enviroment */ x = env_get("KEY"); if (!x) { problem = "$KEY not set"; strerr_warn1("didentd warning: $KEY not set using 'snakeoilkey'", NULL); x = "snakeoilkey"; } /* initialize rijndael with $KEY */ stralloc_copys(&key, x); txtparse(&key); pad(&key, 32); rijndaelKeySched(6, 8, key.s); /* build answer */ stralloc_cats(answer, " : USERID : OTHER : "); uint32_pack(buf, uid); stralloc_catb(&tmp, buf, 4); uint16_pack(buf, lport); stralloc_catb(&tmp, buf, 2); uint16_pack(buf, rport); stralloc_catb(&tmp, buf, 2); uint32_pack(buf, time(NULL)); stralloc_catb(&tmp, buf, 4); stralloc_catb(&tmp, lip, 4); stralloc_catb(&tmp, rip, 8); /* encrypt last part of answer with rijndael */ rijndaelEncrypt(tmp.s); stralloc_readyplus(&out, 32); base64encode(out.s, tmp.s, 24); stralloc_catb(answer, out.s, 32); stralloc_cats(answer, "\r\n"); stralloc_0(answer); return problem; }
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 add_smb_response(struct smb_response* sr,const char* buf,size_t size,unsigned char type) { if (sr->allocated+size<size) return -1; // check int overflow if (sr->used+size>sr->allocated) { size_t n=sr->allocated+size; void* x; n=((n-1)|0xfff)+1; // round up to multiple of 0x1000 if (!n) return -1; // check int overflow x=realloc(sr->buf,n); if (!x) return -1; sr->buf=x; sr->allocated=n; } sr->buf[sr->andxtypeofs]=type; if (sr->andxtypeofs!=netbiosheadersize+4) uint16_pack(sr->buf+sr->andxtypeofs+2,sr->used-netbiosheadersize); byte_copy(sr->buf+sr->used,size,buf); sr->andxtypeofs=sr->used+1; sr->used+=size; if (sr->used%2) sr->buf[++sr->used]=0; uint32_pack_big(sr->buf,sr->used-4); // update netbios size field return 0; }
int main(int argc,char **argv) { long long pos; long long len; long long u; long long r; long long i; long long k; long long recent; long long nextaction; long long timeout; struct pollfd *q; struct pollfd *watch8; struct pollfd *watchtochild; struct pollfd *watchfromchild; signal(SIGPIPE,SIG_IGN); if (!argv[0]) die_usage(0); for (;;) { char *x; if (!argv[1]) break; if (argv[1][0] != '-') break; x = *++argv; if (x[0] == '-' && x[1] == 0) break; if (x[0] == '-' && x[1] == '-' && x[2] == 0) break; while (*++x) { if (*x == 'q') { flagverbose = 0; continue; } if (*x == 'Q') { flagverbose = 1; continue; } if (*x == 'v') { if (flagverbose == 2) flagverbose = 3; else flagverbose = 2; continue; } if (*x == 'c') { flagserver = 0; wantping = 2; continue; } if (*x == 'C') { flagserver = 0; wantping = 1; continue; } if (*x == 's') { flagserver = 1; wantping = 0; continue; } die_usage(0); } } if (!*++argv) die_usage("missing prog"); for (;;) { r = open_read("/dev/null"); if (r == -1) die_fatal("unable to open /dev/null",0,0); if (r > 9) { close(r); break; } } if (open_pipe(tochild) == -1) die_fatal("unable to create pipe",0,0); if (open_pipe(fromchild) == -1) die_fatal("unable to create pipe",0,0); blocking_enable(tochild[0]); blocking_enable(fromchild[1]); child = fork(); if (child == -1) die_fatal("unable to fork",0,0); if (child == 0) { close(8); close(9); if (flagserver) { close(0); if (dup(tochild[0]) != 0) die_fatal("unable to dup",0,0); close(1); if (dup(fromchild[1]) != 1) die_fatal("unable to dup",0,0); } else { close(6); if (dup(tochild[0]) != 6) die_fatal("unable to dup",0,0); close(7); if (dup(fromchild[1]) != 7) die_fatal("unable to dup",0,0); } signal(SIGPIPE,SIG_DFL); execvp(*argv,argv); die_fatal("unable to run",*argv,0); } close(tochild[0]); close(fromchild[1]); recent = nanoseconds(); lastspeedadjustment = recent; if (flagserver) maxblocklen = 1024; for (;;) { if (sendeofacked) if (receivewritten == receivetotalbytes) if (receiveeof) if (tochild[1] < 0) break; /* XXX: to re-ack should enter a TIME-WAIT state here */ q = p; watch8 = q; if (watch8) { q->fd = 8; q->events = POLLIN; ++q; } watchtochild = q; if (tochild[1] < 0) watchtochild = 0; if (receivewritten >= receivebytes) watchtochild = 0; if (watchtochild) { q->fd = tochild[1]; q->events = POLLOUT; ++q; } watchfromchild = q; if (sendeof) watchfromchild = 0; if (sendbytes + 4096 > sizeof sendbuf) watchfromchild = 0; if (watchfromchild) { q->fd = fromchild[0]; q->events = POLLIN; ++q; } nextaction = recent + 60000000000LL; if (wantping == 1) nextaction = recent + 1000000000; if (wantping == 2) nextaction = 0; if (blocknum < OUTGOING) if (!(sendeof ? sendeofprocessed : sendprocessed >= sendbytes)) if (nextaction > lastblocktime + nsecperblock) nextaction = lastblocktime + nsecperblock; if (earliestblocktime) { long long nextretry = earliestblocktime + rtt_timeout; if (nextretry < lastblocktime + nsecperblock) nextretry = lastblocktime + nsecperblock; if (nextretry < nextaction) nextaction = nextretry; } if (messagenum) if (!watchtochild) nextaction = 0; if (nextaction <= recent) timeout = 0; else timeout = (nextaction - recent) / 1000000 + 1; /* XXX */ if (childdied) timeout = 10; pollret = poll(p,q - p,timeout); if (pollret < 0) { watch8 = 0; watchtochild = 0; watchfromchild = 0; } else { if (watch8) if (!watch8->revents) watch8 = 0; if (watchtochild) if (!watchtochild->revents) watchtochild = 0; if (watchfromchild) if (!watchfromchild->revents) watchfromchild = 0; } /* XXX */ if (childdied && !pollret) { if (childdied++ > 999) goto finish; } /* XXX: keepalives */ do { /* try receiving data from child: */ if (!watchfromchild) break; if (sendeof) break; if (sendbytes + 4096 > sizeof sendbuf) break; pos = (sendacked & (sizeof sendbuf - 1)) + sendbytes; if (pos < sizeof sendbuf) { r = read(fromchild[0],sendbuf + pos,sizeof sendbuf - pos); } else { r = read(fromchild[0],sendbuf + pos - sizeof sendbuf,sizeof sendbuf - sendbytes); } if (r == -1) if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) break; if (r < 0) { sendeof = 4096; break; } if (r == 0) { sendeof = 2048; break; } sendbytes += r; if (sendbytes >= 1152921504606846976LL) die_internalerror(); } while(0); recent = nanoseconds(); do { /* try re-sending an old block: */ if (recent < lastblocktime + nsecperblock) break; if (earliestblocktime == 0) break; if (recent < earliestblocktime + rtt_timeout) break; for (i = 0;i < blocknum;++i) { pos = (blockfirst + i) & (OUTGOING - 1); if (blocktime[pos] == earliestblocktime) { if (recent > lastpanic + 4 * rtt_timeout) { nsecperblock *= 2; lastpanic = recent; lastedge = recent; } goto sendblock; } } } while(0); do { /* try sending a new block: */ if (recent < lastblocktime + nsecperblock) break; if (blocknum >= OUTGOING) break; if (!wantping) if (sendeof ? sendeofprocessed : sendprocessed >= sendbytes) break; /* XXX: if any Nagle-type processing is desired, do it here */ pos = (blockfirst + blocknum) & (OUTGOING - 1); ++blocknum; blockpos[pos] = sendacked + sendprocessed; blocklen[pos] = sendbytes - sendprocessed; if (blocklen[pos] > maxblocklen) blocklen[pos] = maxblocklen; if ((blockpos[pos] & (sizeof sendbuf - 1)) + blocklen[pos] > sizeof sendbuf) blocklen[pos] = sizeof sendbuf - (blockpos[pos] & (sizeof sendbuf - 1)); /* XXX: or could have the full block in post-buffer space */ sendprocessed += blocklen[pos]; blockeof[pos] = 0; if (sendprocessed == sendbytes) { blockeof[pos] = sendeof; if (sendeof) sendeofprocessed = 1; } blocktransmissions[pos] = 0; sendblock: blocktransmissions[pos] += 1; blocktime[pos] = recent; blockid[pos] = nextmessageid; if (!++nextmessageid) ++nextmessageid; /* constraints: u multiple of 16; u >= 16; u <= 1088; u >= 48 + blocklen[pos] */ u = 64 + blocklen[pos]; if (u <= 192) u = 192; else if (u <= 320) u = 320; else if (u <= 576) u = 576; else if (u <= 1088) u = 1088; else die_internalerror(); if (blocklen[pos] < 0 || blocklen[pos] > 1024) die_internalerror(); byte_zero(buf + 8,u); buf[7] = u / 16; uint32_pack(buf + 8,blockid[pos]); /* XXX: include any acknowledgments that have piled up */ uint16_pack(buf + 46,blockeof[pos] | (crypto_uint16) blocklen[pos]); uint64_pack(buf + 48,blockpos[pos]); byte_copy(buf + 8 + u - blocklen[pos],blocklen[pos],sendbuf + (blockpos[pos] & (sizeof sendbuf - 1))); if (writeall(9,buf + 7,u + 1) == -1) die_fatal("unable to write descriptor 9",0,0); lastblocktime = recent; wantping = 0; earliestblocktime_compute(); } while(0); do { /* try receiving messages: */ if (!watch8) break; r = read(8,buf,sizeof buf); if (r == -1) if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) break; if (r == 0) die_badmessage(); if (r < 0) die_fatal("unable to read from file descriptor 8",0,0); for (k = 0;k < r;++k) { messagetodo[messagetodolen++] = buf[k]; u = 16 * (unsigned long long) messagetodo[0]; if (u < 16) die_badmessage(); if (u > 1088) die_badmessage(); if (messagetodolen == 1 + u) { if (messagenum < INCOMING) { pos = (messagefirst + messagenum) & (INCOMING - 1); messagelen[pos] = messagetodo[0]; byte_copy(message[pos],u,messagetodo + 1); ++messagenum; } else { ; /* drop tail */ } messagetodolen = 0; } } } while(0); do { /* try processing a message: */ if (!messagenum) break; if (tochild[1] >= 0 && receivewritten < receivebytes) break; maxblocklen = 1024; pos = messagefirst & (INCOMING - 1); len = 16 * (unsigned long long) messagelen[pos]; do { /* handle this message if it's comprehensible: */ unsigned long long D; unsigned long long SF; unsigned long long startbyte; unsigned long long stopbyte; crypto_uint32 id; long long i; if (len < 48) break; if (len > 1088) break; id = uint32_unpack(message[pos] + 4); for (i = 0;i < blocknum;++i) { k = (blockfirst + i) & (OUTGOING - 1); if (blockid[k] == id) { rtt = recent - blocktime[k]; if (!rtt_average) { nsecperblock = rtt; rtt_average = rtt; rtt_deviation = rtt / 2; rtt_highwater = rtt; rtt_lowwater = rtt; } /* Jacobson's retransmission timeout calculation: */ rtt_delta = rtt - rtt_average; rtt_average += rtt_delta / 8; if (rtt_delta < 0) rtt_delta = -rtt_delta; rtt_delta -= rtt_deviation; rtt_deviation += rtt_delta / 4; rtt_timeout = rtt_average + 4 * rtt_deviation; /* adjust for delayed acks with anti-spiking: */ rtt_timeout += 8 * nsecperblock; /* recognizing top and bottom of congestion cycle: */ rtt_delta = rtt - rtt_highwater; rtt_highwater += rtt_delta / 1024; rtt_delta = rtt - rtt_lowwater; if (rtt_delta > 0) rtt_lowwater += rtt_delta / 8192; else rtt_lowwater += rtt_delta / 256; if (rtt_average > rtt_highwater + 5000000) rtt_seenrecenthigh = 1; else if (rtt_average < rtt_lowwater) rtt_seenrecentlow = 1; if (recent >= lastspeedadjustment + 16 * nsecperblock) { if (recent - lastspeedadjustment > 10000000000LL) { nsecperblock = 1000000000; /* slow restart */ nsecperblock += randommod(nsecperblock / 8); } lastspeedadjustment = recent; if (nsecperblock >= 131072) { /* additive increase: adjust 1/N by a constant c */ /* rtt-fair additive increase: adjust 1/N by a constant c every nanosecond */ /* approximation: adjust 1/N by cN every N nanoseconds */ /* i.e., N <- 1/(1/N + cN) = N/(1 + cN^2) every N nanoseconds */ if (nsecperblock < 16777216) { /* N/(1+cN^2) approx N - cN^3 */ u = nsecperblock / 131072; nsecperblock -= u * u * u; } else { double d = nsecperblock; nsecperblock = d/(1 + d*d / 2251799813685248.0); } } if (rtt_phase == 0) { if (rtt_seenolderhigh) { rtt_phase = 1; lastedge = recent; nsecperblock += randommod(nsecperblock / 4); } } else { if (rtt_seenolderlow) { rtt_phase = 0; } } rtt_seenolderhigh = rtt_seenrecenthigh; rtt_seenolderlow = rtt_seenrecentlow; rtt_seenrecenthigh = 0; rtt_seenrecentlow = 0; } do { if (recent - lastedge < 60000000000LL) { if (recent < lastdoubling + 4 * nsecperblock + 64 * rtt_timeout + 5000000000LL) break; } else { if (recent < lastdoubling + 4 * nsecperblock + 2 * rtt_timeout) break; } if (nsecperblock <= 65535) break; nsecperblock /= 2; lastdoubling = recent; if (lastedge) lastedge = recent; } while(0); } } stopbyte = uint64_unpack(message[pos] + 8); acknowledged(0,stopbyte); startbyte = stopbyte + (unsigned long long) uint32_unpack(message[pos] + 16); stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 20); acknowledged(startbyte,stopbyte); startbyte = stopbyte + (unsigned long long) uint16_unpack(message[pos] + 22); stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 24); acknowledged(startbyte,stopbyte); startbyte = stopbyte + (unsigned long long) uint16_unpack(message[pos] + 26); stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 28); acknowledged(startbyte,stopbyte); startbyte = stopbyte + (unsigned long long) uint16_unpack(message[pos] + 30); stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 32); acknowledged(startbyte,stopbyte); startbyte = stopbyte + (unsigned long long) uint16_unpack(message[pos] + 34); stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 36); acknowledged(startbyte,stopbyte); D = uint16_unpack(message[pos] + 38); SF = D & (2048 + 4096); D -= SF; if (D > 1024) break; if (48 + D > len) break; startbyte = uint64_unpack(message[pos] + 40); stopbyte = startbyte + D; if (stopbyte > receivewritten + sizeof receivebuf) { break; /* of course, flow control would avoid this case */ } if (SF) { receiveeof = SF; receivetotalbytes = stopbyte; } for (k = 0;k < D;++k) { unsigned char ch = message[pos][len - D + k]; unsigned long long where = startbyte + k; if (where >= receivewritten && where < receivewritten + sizeof receivebuf) { receivevalid[where & (sizeof receivebuf - 1)] = 1; receivebuf[where & (sizeof receivebuf - 1)] = ch; } } for (;;) { if (receivebytes >= receivewritten + sizeof receivebuf) break; if (!receivevalid[receivebytes & (sizeof receivebuf - 1)]) break; ++receivebytes; } if (!uint32_unpack(message[pos])) break; /* never acknowledge a pure acknowledgment */ /* XXX: delay acknowledgments */ u = 192; byte_zero(buf + 8,u); buf[7] = u / 16; byte_copy(buf + 12,4,message[pos]); if (receiveeof && receivebytes == receivetotalbytes) { uint64_pack(buf + 16,receivebytes + 1); } else uint64_pack(buf + 16,receivebytes); /* XXX: incorporate selective acknowledgments */ if (writeall(9,buf + 7,u + 1) == -1) die_fatal("unable to write descriptor 9",0,0); } while(0); ++messagefirst; --messagenum; } while(0); do { /* try sending data to child: */ if (!watchtochild) break; if (tochild[1] < 0) { receivewritten = receivebytes; break; } if (receivewritten >= receivebytes) break; pos = receivewritten & (sizeof receivebuf - 1); len = receivebytes - receivewritten; if (pos + len > sizeof receivebuf) len = sizeof receivebuf - pos; r = write(tochild[1],receivebuf + pos,len); if (r == -1) if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) break; if (r <= 0) { close(tochild[1]); tochild[1] = -1; break; } byte_zero(receivevalid + pos,r); receivewritten += r; } while(0); do { /* try closing pipe to child: */ if (!receiveeof) break; if (receivewritten < receivetotalbytes) break; if (tochild[1] < 0) break; if (receiveeof == 4096) ; /* XXX: UNIX doesn't provide a way to signal an error through a pipe */ close(tochild[1]); tochild[1] = -1; } while(0); /* XXX */ if (!childdied){ if (waitpid(child,&childstatus, WNOHANG) > 0) { close(tochild[1]); tochild[1] = -1; childdied = 1; } } } if (!childdied) { do { r = waitpid(child,&childstatus,0); } while (r == -1 && errno == EINTR); } finish: if (!WIFEXITED(childstatus)) { errno = 0; die_fatal("process killed by signal",0,0); } return WEXITSTATUS(childstatus); }
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; }