home *** CD-ROM | disk | FTP | other *** search
Wrap
/* Unix SMB/Netbios implementation. Version 1.8. Copyright (C) Andrew Tridgell 1994 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "includes.h" /* default to using LANMAN1 */ #ifndef LANMAN1 #define LANMAN1 1 #endif /* default to using LANMAN2 */ #ifndef LANMAN2 #define LANMAN2 1 #endif #ifndef REGISTER #define REGISTER 0 #endif pstring cur_dir = "\\"; pstring cd_path = ""; pstring service=""; pstring desthost=""; pstring myname = ""; pstring password = ""; pstring username=""; BOOL got_pass = False; BOOL connect_as_printer = False; BOOL connect_as_ipc = False; time_t newer_than = 0; extern struct in_addr myip; extern pstring debugf; extern int DEBUGLEVEL; BOOL translation = False; int cnum = 0; int pid = 0; int gid = 0; int uid = 0; int mid = 0; int myumask = 0755; int max_xmit = BUFFER_SIZE; extern BOOL NeedSwap; extern pstring scope; BOOL prompt = True; int printmode = 1; BOOL recurse = False; BOOL lowercase = False; BOOL have_ip = False; struct in_addr dest_ip; #define SEPARATORS " \t\n\r" BOOL abort_mget = True; extern int Protocol; BOOL readbraw_supported = False; BOOL writebraw_supported = False; time_t servertime = 0; pstring fileselection = ""; extern file_info def_finfo; /* timing globals */ int get_total_size = 0; int get_total_time_ms = 0; int put_total_size = 0; int put_total_time_ms = 0; #ifdef KANJI int term_code = SJIS_CODE; #define CNV_LANG(s) (term_code == EUC_CODE?sj_to_euc(s):s) #define CNV_INPUT(s) (term_code == EUC_CODE?euc_to_sj(s):s) #else #define CNV_LANG(s) s #define CNV_INPUT(s) s #endif /**************************************************************************** setup basics in a outgoing packet ****************************************************************************/ void setup_pkt(char *outbuf) { SSVAL(outbuf,smb_pid,pid); SSVAL(outbuf,smb_uid,uid); SSVAL(outbuf,smb_mid,mid); if (Protocol > PROTOCOL_CORE) { CVAL(outbuf,smb_flg) = 0x8; SSVAL(outbuf,smb_flg2,0x3); } } /**************************************************************************** write to a local file with CR/LF->LF translation if appropriate. return the number taken from the buffer. This may not equal the number written. ****************************************************************************/ int writefile(int f, char *b, int n) { int i; if (!translation) return(write(f,b,n)); i = 0; while (i < n) { if (*b == '\r' && (i<(n-1)) && *(b+1) == '\n') { b++;i++; } if (write(f, b, 1) != 1) { break; } b++; i++; } return(i); } /**************************************************************************** read from a file with LF->CR/LF translation if appropriate. return the number read. read approx n bytes. ****************************************************************************/ int readfile(char *b, int size, int n, FILE *f) { int i; char c; if (!translation || (size != 1)) return(fread(b,size,n,f)); i = 0; while (i < n) { if ((c = getc(f)) == EOF) { break; } if (c == '\n') /* change all LFs to CR/LF */ { b[i++] = '\r'; } b[i++] = c; } return(i); } /**************************************************************************** read from a file with print translation. return the number read. read approx n bytes. ****************************************************************************/ int printread(FILE *f,char *b,int n) { int i; i = readfile(b,1, n-1,f); if (feof(f) && i>0) b[i++] = '\014'; return(i); } /**************************************************************************** show an finfo struct ****************************************************************************/ void show_finfo(file_info *finfo) { DEBUG(3,("name=%s\nmode=0x%x\nsize=%d\n", CNV_LANG(finfo->name), finfo->mode, finfo->size)); DEBUG(3,("mtime=%s",asctime(LocalTime(&finfo->mtime,LOCAL_TO_GMT)))); DEBUG(3,("atime=%s",asctime(LocalTime(&finfo->atime,LOCAL_TO_GMT)))); DEBUG(3,("ctime=%s",asctime(LocalTime(&finfo->ctime,LOCAL_TO_GMT)))); DEBUG(3,("%x %x %x\n",finfo->mtime,finfo->atime,finfo->ctime)); } /**************************************************************************** check for existance of a dir ****************************************************************************/ void test_getattr(char *path) { pstring inbuf,outbuf; char *p; memset(outbuf,0,smb_size); set_message(outbuf,0,2 + strlen(path),True); CVAL(outbuf,smb_com) = SMBgetatr; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); p = smb_buf(outbuf); *p++ = 4; strcpy(p,path); send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0) DEBUG(2,("getatr: %s\n",smb_errstr(inbuf))); else { DEBUG(0,("attr 0x%X time %d size %d\n", (int)CVAL(inbuf,smb_vwv0), SVAL(inbuf,smb_vwv1), SVAL(inbuf,smb_vwv3))); } } /**************************************************************************** check for existance of a dir ****************************************************************************/ BOOL chkpath(char *path,BOOL report) { pstring inbuf,outbuf; char *p; memset(outbuf,0,smb_size); set_message(outbuf,0,4 + strlen(path),True); CVAL(outbuf,smb_com) = SMBchkpth; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); p = smb_buf(outbuf); *p++ = 4; strcpy(p,path); send_smb(outbuf); receive_smb(inbuf,0); if (report && CVAL(inbuf,smb_rcls) != 0) DEBUG(2,("chkpath: %s\n",smb_errstr(inbuf))); return(CVAL(inbuf,smb_rcls) == 0); } /**************************************************************************** check the space on a device ****************************************************************************/ void do_dskattr(void) { pstring inbuf,outbuf; memset(outbuf,0,smb_size); set_message(outbuf,0,0,True); CVAL(outbuf,smb_com) = SMBdskattr; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); send_smb(outbuf); receive_smb(inbuf,0); DEBUG(0,("\n\t\t%d blocks of size %d. %d blocks available\n", SVAL(inbuf,smb_vwv0), SVAL(inbuf,smb_vwv2), SVAL(inbuf,smb_vwv3))); } /**************************************************************************** change directory ****************************************************************************/ void cmd_cd(char *inbuf,char *outbuf ) { char *p; pstring saved_dir; p = strtok(NULL,SEPARATORS); if (p) { pstring dname; /* Save the current directory in case the new directory is invalid */ strcpy(saved_dir, cur_dir); if (*p == '\\') strcpy(cur_dir,p); else strcat(cur_dir,p); dos_clean_name(cur_dir); strcpy(dname,cur_dir); strcat(cur_dir,"\\"); dos_clean_name(cur_dir); if (!strequal(cur_dir,"\\")) if (!chkpath(dname,True)) strcpy(cur_dir,saved_dir); } else DEBUG(0,("Current directory is %s\n",CNV_LANG(cur_dir))); strcpy(cd_path,cur_dir); } /**************************************************************************** display info about a file ****************************************************************************/ void display_finfo(file_info *finfo) { DEBUG(0,(" %-30s%7.7s%10d %s", CNV_LANG(finfo->name), attrib_string(finfo->mode), finfo->size, asctime(LocalTime(&finfo->mtime,0)))); } /**************************************************************************** act on the files in a dir listing ****************************************************************************/ void dir_action(char *inbuf,char *outbuf,int attribute,file_info *finfo,BOOL recurse_dir,void (*fn)(),BOOL longdir) { if (!((finfo->mode & aDIR) == 0 && *fileselection && !mask_match(finfo->name,fileselection,False,False,True)) && !(recurse_dir && (strequal(finfo->name,".") || strequal(finfo->name,"..")))) { if (recurse_dir && (finfo->mode & aDIR)) { pstring mask2; pstring sav_dir; strcpy(sav_dir,cur_dir); strcat(cur_dir,finfo->name); strcat(cur_dir,"\\"); strcpy(mask2,cur_dir); if (!fn) DEBUG(0,("\n%s\n",CNV_LANG(cur_dir))); if (longdir) { strcat(mask2,"*"); do_long_dir(inbuf,outbuf,mask2,attribute,fn,True); } else { strcat(mask2,"*.*"); do_dir(inbuf,outbuf,mask2,attribute,fn,True); } strcpy(cur_dir,sav_dir); } else { if (fn && (newer_than==0 || finfo->mtime >= newer_than || finfo->mode & aDIR)) fn(finfo); } } } /**************************************************************************** do a directory listing, calling fn on each file found ****************************************************************************/ void do_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir) { if (Protocol >= PROTOCOL_LANMAN2) { if (do_long_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir) > 0) return; } expand_mask(Mask,False); do_short_dir(inbuf,outbuf,Mask,attribute,fn,recurse_dir); return; } /**************************************************************************** do a directory listing, calling fn on each file found ****************************************************************************/ int do_short_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir) { char *p; int received = 0; BOOL first = True; char status[21]; int num_asked = (max_xmit - 100)/DIR_STRUCT_SIZE; int num_received = 0; int i; char *dirlist = NULL; pstring mask; file_info finfo = def_finfo; strcpy(mask,Mask); while (1) { memset(outbuf,0,smb_size); if (first) set_message(outbuf,2,5 + strlen(mask),True); else set_message(outbuf,2,5 + 21,True); #if FFIRST if (Protocol >= PROTOCOL_LANMAN1) CVAL(outbuf,smb_com) = SMBffirst; else #endif CVAL(outbuf,smb_com) = SMBsearch; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); SSVAL(outbuf,smb_vwv0,num_asked); SSVAL(outbuf,smb_vwv1,attribute); p = smb_buf(outbuf); *p++ = 4; if (first) strcpy(p,mask); else strcpy(p,""); p += strlen(p) + 1; *p++ = 5; if (first) SSVAL(p,0,0); else { SSVAL(p,0,21); p += 2; memcpy(p,status,21); } send_smb(outbuf); receive_smb(inbuf,0); received = SVAL(inbuf,smb_vwv0); DEBUG(5,("dir received %d\n",received)); DEBUG(6,("errstr=%s\n",smb_errstr(inbuf))); if (received <= 0) break; first = False; dirlist = Realloc(dirlist,(num_received + received)*DIR_STRUCT_SIZE); if (!dirlist) return 0; p = smb_buf(inbuf) + 3; memcpy(dirlist+num_received*DIR_STRUCT_SIZE, p,received*DIR_STRUCT_SIZE); memcpy(status,p + ((received-1)*DIR_STRUCT_SIZE),21); num_received += received; if (CVAL(inbuf,smb_rcls) != 0) break; } #if FFIRST if (!first && Protocol >= PROTOCOL_LANMAN1) { memset(outbuf,0,smb_size); CVAL(outbuf,smb_com) = SMBfclose; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); p = smb_buf(outbuf); *p++ = 4; strcpy(p,""); p += strlen(p) + 1; *p++ = 5; SSVAL(p,0,21); p += 2; memcpy(p,status,21); send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0) DEBUG(0,("Error closing search: %s\n",smb_errstr(inbuf))); } #endif if (!fn) for (p=dirlist,i=0;i<num_received;i++) { p += interpret_short_filename(p,&finfo); display_finfo(&finfo); } for (p=dirlist,i=0;i<num_received;i++) { p += interpret_short_filename(p,&finfo); dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,False); } if (dirlist) free(dirlist); return(num_received); } /**************************************************************************** receive a SMB trans2 response allocating the necessary memory ****************************************************************************/ BOOL receive_trans2_response(char *inbuf,int *data_len,int *param_len, char **data,char **param) { int total_data=0; int total_param=0; *data_len = *param_len = 0; receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0) return(False); /* parse out the lengths */ total_data = SVAL(inbuf,smb_tdrcnt); total_param = SVAL(inbuf,smb_tprcnt); /* allocate it */ *data = Realloc(*data,total_data); *param = Realloc(*param,total_param); while (1) { memcpy(*data + *data_len,smb_base(inbuf) + SVAL(inbuf,smb_droff), SVAL(inbuf,smb_drcnt)); memcpy(*param + *param_len,smb_base(inbuf) + SVAL(inbuf,smb_proff), SVAL(inbuf,smb_prcnt)); *data_len += SVAL(inbuf,smb_drcnt); *param_len += SVAL(inbuf,smb_prcnt); /* parse out the total lengths again - they can shrink! */ total_data = SVAL(inbuf,smb_tdrcnt); total_param = SVAL(inbuf,smb_tprcnt); if (total_data <= *data_len && total_param <= *param_len) break; receive_smb(inbuf,0); } return(True); } /**************************************************************************** do a directory listing, calling fn on each file found. Use the TRANSACT2 call for long filenames ****************************************************************************/ int do_long_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir) { int max_matches = 512; int info_level = 1; /* NT uses 260, OS/2 uses 2. Both accept 1. */ char *p; pstring mask; file_info finfo; int i; char *dirlist = NULL; int dirlist_len = 0; int total_received = 0; BOOL First = True; char *resp_data=NULL; char *resp_param=NULL; int resp_data_len = 0; int resp_param_len=0; int ff_resume_key = 0; int ff_searchcount=0; int ff_eos=0; int ff_lastname=0; int ff_dir_handle=0; int loop_count = 0; strcpy(mask,Mask); while (ff_eos == 0) { loop_count++; if (loop_count > 200) { DEBUG(0,("ERROR: Looping in FIND_NEXT??\n")); break; } memset(outbuf,0,smb_setup); set_message(outbuf,15,5 + 12 + strlen(mask)+1,True); CVAL(outbuf,smb_com) = SMBtrans2; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); SSVAL(outbuf,smb_tpscnt,12 + strlen(mask)+1); SSVAL(outbuf,smb_tdscnt,0); SSVAL(outbuf,smb_mprcnt,10); SSVAL(outbuf,smb_mdrcnt,0xFFFF); SSVAL(outbuf,smb_msrcnt,0); SSVAL(outbuf,smb_flags,0); SIVAL(outbuf,smb_timeout,0); SSVAL(outbuf,smb_pscnt,SVAL(outbuf,smb_tpscnt)); SSVAL(outbuf,smb_psoff,((smb_buf(outbuf)+3) - outbuf)-4); SSVAL(outbuf,smb_dscnt,0); SSVAL(outbuf,smb_dsoff,0); SSVAL(outbuf,smb_suwcnt,1); if (First) SSVAL(outbuf,smb_setup0,TRANSACT2_FINDFIRST); else SSVAL(outbuf,smb_setup0,TRANSACT2_FINDNEXT); p = smb_buf(outbuf); *p++ = 0; /* put in a null smb_name */ *p++ = 'D'; *p++ = ' '; /* this was added because OS/2 does it */ if (First) { SSVAL(p,0,attribute); /* attribute */ SSVAL(p,2,max_matches); /* max count */ SSVAL(p,4,8+4+2); /* resume required + close on end + continue */ SSVAL(p,6,info_level); SIVAL(p,8,0); p += 12; strcpy(p,mask); p += strlen(mask); *p++ = 0; *p++ = 0; } else { DEBUG(5,("hand=0x%X resume=%d ff_lastname=%d mask=%s\n", ff_dir_handle,ff_resume_key,ff_lastname,mask)); SSVAL(p,0,ff_dir_handle); SSVAL(p,2,max_matches); /* max count */ SSVAL(p,4,info_level); SIVAL(p,6,ff_resume_key); /* ff_resume_key */ SSVAL(p,10,12); /* resume required + close on end + continue */ p += 12; strcpy(p,mask); *p++ = 0; *p++ = 0; } send_smb(outbuf); receive_trans2_response(inbuf, &resp_data_len,&resp_param_len, &resp_data,&resp_param); if (CVAL(inbuf,smb_rcls) != 0) { DEBUG(3,("FIND%s gave %s\n",First?"FIRST":"NEXT",smb_errstr(inbuf))); break; } /* parse out some important return info */ p = resp_param; if (First) { ff_dir_handle = SVAL(p,0); ff_searchcount = SVAL(p,2); ff_eos = SVAL(p,4); ff_lastname = SVAL(p,8); } else { ff_searchcount = SVAL(p,0); ff_eos = SVAL(p,2); ff_lastname = SVAL(p,6); } if (ff_searchcount == 0) break; /* point to the data bytes */ p = resp_data; /* we might need the lastname for continuations */ if (ff_lastname > 0) { switch(info_level) { case 260: ff_resume_key =0; strcpy(mask,p+ff_lastname+94); break; case 1: strcpy(mask,p + ff_lastname + 1); ff_resume_key = 0; break; } } else strcpy(mask,""); /* and add them to the dirlist pool */ dirlist = Realloc(dirlist,dirlist_len + resp_data_len); if (!dirlist) { DEBUG(0,("Failed to expand dirlist\n")); break; } /* put in a length for the last entry, to ensure we can chain entries into the next packet */ { char *p2; for (p2=p,i=0;i<(ff_searchcount-1);i++) p2 += interpret_long_filename(info_level,p2,NULL); SSVAL(p2,0,resp_data_len - (int)(p2 - p)); } /* grab the data for later use */ memcpy(dirlist+dirlist_len,p,resp_data_len); dirlist_len += resp_data_len; total_received += ff_searchcount; if (resp_data) free(resp_data); resp_data = NULL; if (resp_param) free(resp_param); resp_param = NULL; DEBUG(3,("received %d entries (eos=%d resume=%d)\n", ff_searchcount,ff_eos,ff_resume_key)); First = False; } if (!fn) for (p=dirlist,i=0;i<total_received;i++) { p += interpret_long_filename(info_level,p,&finfo); display_finfo(&finfo); } for (p=dirlist,i=0;i<total_received;i++) { p += interpret_long_filename(info_level,p,&finfo); dir_action(inbuf,outbuf,attribute,&finfo,recurse_dir,fn,True); } /* free up the dirlist buffer */ if (dirlist) free(dirlist); return(total_received); } /**************************************************************************** get a directory listing ****************************************************************************/ void cmd_dir(char *inbuf,char *outbuf) { int attribute = aDIR | aSYSTEM | aHIDDEN; pstring mask; char *p; strcpy(mask,cur_dir); if(mask[strlen(mask)-1]!='\\') strcat(mask,"\\"); p = strtok(NULL,SEPARATORS); if (p) { if (*p == '\\') strcpy(mask,p); else strcat(mask,p); } else strcat(mask,"*.*"); if (Protocol < PROTOCOL_LANMAN2) expand_mask(mask,True); do_dir(inbuf,outbuf,mask,attribute,NULL,recurse); do_dskattr(); } /**************************************************************************** list lots of info about a file ****************************************************************************/ void do_ldir(file_info *finfo) { char *inbuf,*outbuf; char *p; pstring rname; pstring SMB_NAME=""; if (Protocol < PROTOCOL_LANMAN2) { DEBUG(0,("%20.20s mode=0x%x uid=%d gid=%d size=%10d %s %s %s", CNV_LANG(finfo->name), finfo->mode, finfo->uid, finfo->gid, finfo->size, asctime(LocalTime(&finfo->ctime,LOCAL_TO_GMT)), asctime(LocalTime(&finfo->atime,LOCAL_TO_GMT)), asctime(LocalTime(&finfo->mtime,LOCAL_TO_GMT)))); return; } inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); if (!inbuf || !outbuf) { DEBUG(0,("out of memory\n")); return; } strcpy(rname,cur_dir); strcat(rname,finfo->name); memset(outbuf,0,smb_setup); set_message(outbuf,15,6 + strlen(rname)+1+strlen(SMB_NAME)+1,True); CVAL(outbuf,smb_com) = SMBtrans2; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); SSVAL(outbuf,smb_tpscnt,6+strlen(rname)+1); SSVAL(outbuf,smb_tdscnt,0); SSVAL(outbuf,smb_mprcnt,1024); /* XXXXX need to get this right */ SSVAL(outbuf,smb_mdrcnt,1024); /* XXXXX need to get this right */ SSVAL(outbuf,smb_msrcnt,0); SSVAL(outbuf,smb_flags,0); SIVAL(outbuf,smb_timeout,0); SSVAL(outbuf,smb_pscnt,SVAL(outbuf,smb_tpscnt)); SSVAL(outbuf,smb_psoff,((smb_buf(outbuf)+strlen(SMB_NAME)+1) - outbuf)-4); SSVAL(outbuf,smb_dscnt,0); SSVAL(outbuf,smb_dsoff,SVAL(outbuf,smb_psoff) + SVAL(outbuf,smb_pscnt)); SSVAL(outbuf,smb_suwcnt,1); SSVAL(outbuf,smb_setup0,TRANSACT2_QPATHINFO); /* what the hell is smb_name ?? */ strcpy(smb_buf(outbuf),SMB_NAME); p = smb_buf(outbuf)+strlen(SMB_NAME)+1; { int i; for (i=2;i<3;i++) { SSVAL(p,0,i); /* is 3 the right level?? */ strcpy(p+6,rname); send_smb(outbuf); receive_smb(inbuf,0); DEBUG(3,("qpath: prcnt=%d drcnt=%d\n", SVAL(inbuf,smb_prcnt),SVAL(inbuf,smb_drcnt))); } } if (CVAL(inbuf,smb_rcls) != 0) DEBUG(0,("Qpathinfo failed %s\n", smb_errstr(inbuf))); else DEBUG(3,("Qpathinfo succeeded\n")); free(inbuf);free(outbuf); } /**************************************************************************** get a file from rname to lname ****************************************************************************/ void do_get(char *rname,char *lname,file_info *finfo1) { int handle=0,fnum; uint32 nread=0; char *p; BOOL newhandle = False; char *inbuf,*outbuf; file_info finfo; BOOL close_done = False; struct timeval tp_start; gettimeofday(&tp_start,NULL); if (finfo1) finfo = *finfo1; else finfo = def_finfo; if (lowercase) strlower(lname); inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); if (!inbuf || !outbuf) { DEBUG(0,("out of memory\n")); return; } memset(outbuf,0,smb_size); set_message(outbuf,2,2 + strlen(rname),True); CVAL(outbuf,smb_com) = SMBopen; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); SSVAL(outbuf,smb_vwv0,0); SSVAL(outbuf,smb_vwv1,aSYSTEM | aHIDDEN); p = smb_buf(outbuf); *p++ = 4; strcpy(p,rname); dos_clean_name(rname); if(!strcmp(lname,"-")) handle = fileno(stdout); else { handle = creat(lname,0644); newhandle = True; } if (handle < 0) { DEBUG(0,("Error opening local file %s\n",lname)); free(inbuf);free(outbuf); return; } send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0) { DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),CNV_LANG(rname))); if(newhandle) close(handle); free(inbuf);free(outbuf); return; } strcpy(finfo.name,rname); if (!finfo1) { finfo.mode = SVAL(inbuf,smb_vwv1); finfo.size = IVAL(inbuf,smb_vwv4); finfo.mtime = IVAL(inbuf,smb_vwv2); finfo.atime = finfo.ctime = finfo.mtime; } DEBUG(3,("file %s attrib 0x%X\n",CNV_LANG(finfo.name),finfo.mode)); fnum = SVAL(inbuf,smb_vwv0); DEBUG(2,("getting file %s of size %d bytes as %s ", CNV_LANG(finfo.name), finfo.size, lname)); while (nread < finfo.size && !close_done) { char *dataptr; int datalen; DEBUG(3,("nread=%d\n",nread)); /* 3 possible read types. readbraw if a large block is required. readX + close if not much left and read if neither is supported */ if (Protocol >= PROTOCOL_LANMAN1) { char *p=NULL; if ((finfo.size - nread) < (max_xmit - (2*smb_size + 13*sizeof(WORD) + 300))) close_done = True; DEBUG(4,("Using readX+close\n")); /* use readX + close */ memset(outbuf,0,smb_size); set_message(outbuf,10,0,True); CVAL(outbuf,smb_com) = SMBreadX; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); if (close_done) { CVAL(outbuf,smb_vwv0) = SMBclose; SSVAL(outbuf,smb_vwv1,PTR_DIFF(smb_buf(outbuf),outbuf) - 4); } else CVAL(outbuf,smb_vwv0) = 0xFF; SSVAL(outbuf,smb_vwv2,fnum); SIVAL(outbuf,smb_vwv3,nread); SSVAL(outbuf,smb_vwv5,MIN(max_xmit-200,finfo.size - nread)); SSVAL(outbuf,smb_vwv6,0); SIVAL(outbuf,smb_vwv7,0); SSVAL(outbuf,smb_vwv9,MIN(0xFFFF,finfo.size-nread)); if (close_done) { p = smb_buf(outbuf); memset(p,0,9); CVAL(p,0) = 3; SSVAL(p,1,fnum); SIVAL(p,3,finfo.mtime); /* now set the total packet length */ smb_setlen(outbuf,smb_len(outbuf)+9); } send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0) { DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf))); break; } if (Protocol < PROTOCOL_LANMAN2 && SVAL(inbuf,smb_vwv0) != SMBclose) { /* NOTE: WfWg sometimes just ignores the chained command! This seems to break the spec? */ DEBUG(3,("Rejected chained close?\n")); close_done = False; } datalen = SVAL(inbuf,smb_vwv5); dataptr = inbuf + 4 + SVAL(inbuf,smb_vwv6); } else if (readbraw_supported) { static int readbraw_size = 0xFFFF; extern int Client; memset(outbuf,0,smb_size); set_message(outbuf,8,0,True); CVAL(outbuf,smb_com) = SMBreadbraw; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); SSVAL(outbuf,smb_vwv0,fnum); SIVAL(outbuf,smb_vwv1,nread); SSVAL(outbuf,smb_vwv3,MIN(finfo.size-nread,readbraw_size)); SSVAL(outbuf,smb_vwv4,0); SIVALS(outbuf,smb_vwv5,-1); send_smb(outbuf); /* Now read the raw data into the buffer and write it */ if(read_smb_length(Client,inbuf,0) == -1) { DEBUG(0,("Failed to read length in readbraw\n")); exit(1); } log_in(inbuf,4); /* Even though this is not an smb message, smb_len returns the generic length of an smb message */ datalen = smb_len(inbuf); if (datalen == 0) { /* we got a readbraw error */ DEBUG(4,("readbraw error - reducing size\n")); readbraw_size = (readbraw_size * 9) / 10; if (readbraw_size < max_xmit) { DEBUG(0,("disabling readbraw\n")); readbraw_supported = False; } continue; } if(!read_data(Client,inbuf,datalen)) { DEBUG(0,("Failed to read data in readbraw\n")); exit(1); } log_in(inbuf,datalen); dataptr = inbuf; } else { /* use plain read */ memset(outbuf,0,smb_size); set_message(outbuf,5,0,True); CVAL(outbuf,smb_com) = SMBread; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); SSVAL(outbuf,smb_vwv0,fnum); SSVAL(outbuf,smb_vwv1,MIN(max_xmit-200,finfo.size - nread)); SIVAL(outbuf,smb_vwv2,nread); SSVAL(outbuf,smb_vwv4,finfo.size - nread); send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0) { DEBUG(0,("Error %s reading remote file\n",smb_errstr(inbuf))); break; } datalen = SVAL(inbuf,smb_vwv0); dataptr = smb_buf(inbuf) + 3; } if (writefile(handle,dataptr,datalen) != datalen) { DEBUG(0,("Error writing local file\n")); break; } nread += datalen; if (nread == 0) { DEBUG(0,("Error reading file %s. Got 0 bytes\n",CNV_LANG(rname))); break; } } if (!close_done) { memset(outbuf,0,smb_size); set_message(outbuf,3,0,True); CVAL(outbuf,smb_com) = SMBclose; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); SSVAL(outbuf,smb_vwv0,fnum); SIVAL(outbuf,smb_vwv1,finfo.mtime); send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0) { DEBUG(0,("Error %s closing remote file\n",smb_errstr(inbuf))); if(newhandle) close(handle); free(inbuf);free(outbuf); return; } } if(newhandle) close(handle); { struct timeval tp_end; int this_time; gettimeofday(&tp_end,NULL); this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000; get_total_time_ms += this_time; get_total_size += finfo.size; DEBUG(2,("(%g kb/s) (average %g kb/s)\n", finfo.size / (1.024*this_time), get_total_size / (1.024*get_total_time_ms))); } free(inbuf);free(outbuf); } /**************************************************************************** get a file ****************************************************************************/ void cmd_get(void) { pstring lname; pstring rname; char *p; strcpy(rname,cur_dir); strcat(rname,"\\"); p = strtok(NULL,SEPARATORS); if (!p) { DEBUG(0,("get <filename>\n")); return; } strcat(rname,p); dos_clean_name(rname); strcpy(lname,p); p = strtok(NULL,SEPARATORS); if (p) strcpy(lname,p); do_get(rname,lname,NULL); } /**************************************************************************** do a mget operation on one file ****************************************************************************/ void do_mget(file_info *finfo) { pstring rname; pstring quest; if (strequal(finfo->name,".") || strequal(finfo->name,"..")) return; if (abort_mget) { DEBUG(0,("mget aborted\n")); return; } if (finfo->mode & aDIR) sprintf(quest,"Get directory %s? ",CNV_LANG(finfo->name)); else sprintf(quest,"Get file %s? ",CNV_LANG(finfo->name)); if (prompt && !yesno(quest)) return; if (finfo->mode & aDIR) { pstring saved_curdir; pstring mget_mask; char *inbuf,*outbuf; inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); if (!inbuf || !outbuf) { DEBUG(0,("out of memory\n")); return; } strcpy(saved_curdir,cur_dir); strcat(cur_dir,finfo->name); strcat(cur_dir,"\\"); unix_format(finfo->name); { if (lowercase) strlower(finfo->name); if (!directory_exist(finfo->name) && mkdir(finfo->name,0777) != 0) { DEBUG(0,("failed to create directory %s\n",CNV_LANG(finfo->name))); strcpy(cur_dir,saved_curdir); free(inbuf);free(outbuf); return; } if (chdir(finfo->name) != 0) { DEBUG(0,("failed to chdir to directory %s\n",CNV_LANG(finfo->name))); strcpy(cur_dir,saved_curdir); free(inbuf);free(outbuf); return; } } strcpy(mget_mask,cur_dir); strcat(mget_mask,"*.*"); do_dir((char *)inbuf,(char *)outbuf, mget_mask,aSYSTEM | aHIDDEN | aDIR,do_mget,False); chdir(".."); strcpy(cur_dir,saved_curdir); free(inbuf);free(outbuf); } else { strcpy(rname,cur_dir); strcat(rname,finfo->name); do_get(rname,finfo->name,finfo); } } /**************************************************************************** do a mget command ****************************************************************************/ void cmd_mget(char *inbuf,char *outbuf) { int attribute = aSYSTEM | aHIDDEN; pstring mget_mask=""; char *p; if (recurse) attribute |= aDIR; abort_mget = False; while ((p = strtok(NULL,SEPARATORS))) { strcpy(mget_mask,cur_dir); if(mget_mask[strlen(mget_mask)-1]!='\\') strcat(mget_mask,"\\"); if (*p == '\\') strcpy(mget_mask,p); else strcat(mget_mask,p); } do_dir((char *)inbuf,(char *)outbuf,mget_mask,attribute,do_mget,False); } /**************************************************************************** make a directory of name "name" ****************************************************************************/ BOOL do_mkdir(char *name) { char *p; char *inbuf,*outbuf; inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); if (!inbuf || !outbuf) { DEBUG(0,("out of memory\n")); return False; } memset(outbuf,0,smb_size); set_message(outbuf,0,2 + strlen(name),True); CVAL(outbuf,smb_com) = SMBmkdir; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); p = smb_buf(outbuf); *p++ = 4; strcpy(p,name); send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0) { DEBUG(0,("%s making remote directory %s\n", smb_errstr(inbuf),CNV_LANG(name))); free(inbuf);free(outbuf); return(False); } free(inbuf);free(outbuf); return(True); } /**************************************************************************** set the attributes and date of a file ****************************************************************************/ BOOL do_setattr(file_info *finfo) { char *p; char *inbuf,*outbuf; pstring name; strcpy(name,finfo->name); strcpy(finfo->name,"\\"); strcat(finfo->name,name); inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); if (!inbuf || !outbuf) { DEBUG(0,("out of memory\n")); return False; } memset(outbuf,0,smb_size); set_message(outbuf,8,4 + strlen(finfo->name),True); CVAL(outbuf,smb_com) = SMBsetatr; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); SSVAL(outbuf,smb_vwv0,finfo->mode); SIVAL(outbuf,smb_vwv1,finfo->mtime); p = smb_buf(outbuf); *p++ = 4; strcpy(p,finfo->name); p += (strlen(finfo->name)+1); *p++ = 4; *p++ = 0; send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0) { DEBUG(0,("%s setting attributes on file %s\n", smb_errstr(inbuf),CNV_LANG(finfo->name))); free(inbuf);free(outbuf); return(False); } free(inbuf);free(outbuf); return(True); } /**************************************************************************** make a directory ****************************************************************************/ void cmd_mkdir(char *inbuf,char *outbuf) { pstring mask; char *p; strcpy(mask,cur_dir); p = strtok(NULL,SEPARATORS); if (!p) { if (!recurse) DEBUG(0,("mkdir <dirname>\n")); return; } strcat(mask,p); if (recurse) { pstring ddir; pstring ddir2 = ""; strcpy(ddir,mask); trim_string(ddir,".",NULL); p = strtok(ddir,"/\\"); while (p) { strcat(ddir2,p); if (!chkpath(ddir2,False)) { do_mkdir(ddir2); } strcat(ddir2,"\\"); p = strtok(NULL,"/\\"); } } else do_mkdir(mask); } /**************************************************************************** put a single file ****************************************************************************/ void do_put(char *rname,char *lname,file_info *finfo) { int fnum; FILE *f; int nread=0; char *p; char *inbuf,*outbuf; time_t close_time = finfo->mtime - TimeDiff(); struct timeval tp_start; gettimeofday(&tp_start,NULL); inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); if (!inbuf || !outbuf) { DEBUG(0,("out of memory\n")); return; } memset(outbuf,0,smb_size); set_message(outbuf,3,2 + strlen(rname),True); if (finfo->mtime == 0 || finfo->mtime == -1) { finfo->mtime = finfo->atime = finfo->ctime = time(NULL) + GMT_TO_LOCAL*TimeDiff(); } CVAL(outbuf,smb_com) = SMBcreate; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); SSVAL(outbuf,smb_vwv0,finfo->mode); SIVAL(outbuf,smb_vwv1,finfo->mtime); p = smb_buf(outbuf); *p++ = 4; strcpy(p,rname); send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0) { DEBUG(0,("%s opening remote file %s\n",smb_errstr(inbuf),CNV_LANG(rname))); free(inbuf);free(outbuf); return; } f = fopen(lname,"r"); if (!f) { DEBUG(0,("Error opening local file %s\n",lname)); free(inbuf);free(outbuf); return; } fnum = SVAL(inbuf,smb_vwv0); if (finfo->size < 0) finfo->size = file_size(lname); DEBUG(1,("putting file %s of size %d bytes as %s ",lname,finfo->size,CNV_LANG(rname))); while (nread < finfo->size) { int n = (max_xmit-200); n = MIN(n,finfo->size - nread); memset(outbuf,0,smb_size); set_message(outbuf,5,n + 3,True); if ((n = readfile(smb_buf(outbuf)+3,1,n,f)) < 1) { DEBUG(0,("Error reading local file\n")); break; } set_message(outbuf,5,n + 3,False); CVAL(outbuf,smb_com) = SMBwrite; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); SSVAL(outbuf,smb_vwv0,fnum); SSVAL(outbuf,smb_vwv1,n); SIVAL(outbuf,smb_vwv2,nread); SSVAL(outbuf,smb_vwv4,finfo->size - nread); CVAL(smb_buf(outbuf),0) = 1; SSVAL(smb_buf(outbuf),1,n); send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0) { DEBUG(0,("%s writing remote file\n",smb_errstr(inbuf))); break; } if (n != SVAL(inbuf,smb_vwv0)) { DEBUG(0,("Error: only wrote %d bytes\n",nread + SVAL(inbuf,smb_vwv0))); break; } nread += n; } memset(outbuf,0,smb_size); set_message(outbuf,3,0,True); CVAL(outbuf,smb_com) = SMBclose; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); SSVAL(outbuf,smb_vwv0,fnum); SIVAL(outbuf,smb_vwv1,close_time); DEBUG(3,("Setting date to %s (0x%X)", asctime(LocalTime(&finfo->mtime,LOCAL_TO_GMT)), finfo->mtime)); send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0) { DEBUG(0,("%s closing remote file %s\n",smb_errstr(inbuf),CNV_LANG(rname))); fclose(f); free(inbuf);free(outbuf); return; } fclose(f); free(inbuf);free(outbuf); { struct timeval tp_end; int this_time; gettimeofday(&tp_end,NULL); this_time = (tp_end.tv_sec - tp_start.tv_sec)*1000 + (tp_end.tv_usec - tp_start.tv_usec)/1000; put_total_time_ms += this_time; put_total_size += finfo->size; DEBUG(2,("(%g kb/s) (average %g kb/s)\n", finfo->size / (1.024*this_time), put_total_size / (1.024*put_total_time_ms))); } } /**************************************************************************** fudge a single file ****************************************************************************/ void do_fudge(file_info *finfo) { int fnum; char *p; char *inbuf,*outbuf; time_t old_mtime; static time_t sane_date = 0; { pstring n2; strcpy(n2,finfo->name); strcpy(finfo->name,cur_dir); strcat(finfo->name,n2); } if (sane_date == 0) { sane_date = start_of_month(); } if (sane_unix_date(finfo->mtime)) return; DEBUG(2,("Fixing insane date on file %s %s",CNV_LANG(finfo->name), asctime(LocalTime(&finfo->mtime,LOCAL_TO_GMT)))); finfo->mtime = sane_date; inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); if (!inbuf || !outbuf) { DEBUG(0,("out of memory\n")); return; } memset(outbuf,0,smb_size); set_message(outbuf,2,2 + strlen(finfo->name),True); CVAL(outbuf,smb_com) = SMBopen; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); SSVAL(outbuf,smb_vwv0,0); SSVAL(outbuf,smb_vwv1,0); p = smb_buf(outbuf); *p++ = 4; strcpy(p,finfo->name); dos_clean_name(finfo->name); send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0) { DEBUG(0,("Error %s opening remote file %s\n",smb_errstr(inbuf), CNV_LANG(finfo->name))); free(inbuf);free(outbuf); return; } fnum = SVAL(inbuf,smb_vwv0); old_mtime = IVAL(inbuf,smb_vwv2); if (sane_unix_date(old_mtime)) { finfo->mtime = old_mtime; DEBUG(2,("Already sane date on file %s %s",CNV_LANG(finfo->name), asctime(LocalTime(&finfo->mtime,LOCAL_TO_GMT)))); } memset(outbuf,0,smb_size); set_message(outbuf,3,0,True); CVAL(outbuf,smb_com) = SMBclose; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); SSVAL(outbuf,smb_vwv0,fnum); SIVAL(outbuf,smb_vwv1,finfo->mtime); send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0) { DEBUG(0,("Error %s closing remote file\n",smb_errstr(inbuf))); free(inbuf);free(outbuf); return; } free(inbuf);free(outbuf); } /**************************************************************************** fudge dates ****************************************************************************/ void cmd_fudge(char *inbuf,char *outbuf) { int attribute = aDIR | aSYSTEM | aHIDDEN; pstring mask; char *p; strcpy(mask,cur_dir); if(mask[strlen(mask)-1]!='\\') strcat(mask,"\\"); p = strtok(NULL,SEPARATORS); if (p) { if (*p == '\\') strcpy(mask,p); else strcat(mask,p); } else strcat(mask,"*.*"); do_dir(inbuf,outbuf,mask,attribute,do_fudge,recurse); } /**************************************************************************** put a file ****************************************************************************/ void cmd_put(void) { pstring lname; pstring rname; char *p; file_info finfo = def_finfo; strcpy(rname,cur_dir); strcat(rname,"\\"); p = strtok(NULL,SEPARATORS); if (!p) { DEBUG(0,("put <filename>\n")); return; } strcpy(lname,p); p = strtok(NULL,SEPARATORS); if (p) strcat(rname,p); else strcat(rname,lname); dos_clean_name(rname); /* let the remote side decide the date */ finfo.mtime = -1; do_put(rname,lname,&finfo); } /**************************************************************************** seek in a directory/file list until you get something that doesn't start with the specified name ****************************************************************************/ BOOL seek_list(FILE *f,char *name) { pstring s; while (!feof(f)) { if (fscanf(f,"%s",s) != 1) return(False); trim_string(s,"./",NULL); if (strncmp(s,name,strlen(name)) != 0) { strcpy(name,s); return(True); } } return(False); } /**************************************************************************** set the file selection mask ****************************************************************************/ void cmd_select(void) { char *p = strtok(NULL,SEPARATORS); if (p) strcpy(fileselection,p); else strcpy(fileselection,""); } /**************************************************************************** mput some files ****************************************************************************/ void cmd_mput(void) { pstring lname; pstring rname; file_info finfo = def_finfo; char *p; while ((p = strtok(NULL,SEPARATORS))) { pstring cmd; pstring tmpnam; FILE *f; sprintf(tmpnam,"/tmp/ls.smb.%d",getpid()); if (recurse) sprintf(cmd,"find . -name \"%s\" -print > %s",p,tmpnam); else sprintf(cmd,"/bin/ls %s > %s",p,tmpnam); system(cmd); f = fopen(tmpnam,"r"); if (!f) continue; while (!feof(f)) { pstring quest; if (fscanf(f,"%s",lname) != 1) break; trim_string(lname,"./",NULL); again: /* check if it's a directory */ if (directory_exist(lname)) { if (!recurse) continue; sprintf(quest,"Put directory %s? ",lname); if (prompt && !yesno(quest)) { strcat(lname,"/"); if (!seek_list(f,lname)) break; goto again; } strcpy(rname,cur_dir); strcat(rname,lname); if (!do_mkdir(rname)) { strcat(lname,"/"); if (!seek_list(f,lname)) break; goto again; } continue; } else { sprintf(quest,"Put file %s? ",lname); if (prompt && !yesno(quest)) continue; strcpy(rname,cur_dir); strcat(rname,lname); } dos_format(rname); /* null size so do_put knows to ignore it */ finfo.size = -1; /* let the remote side decide the date */ finfo.mtime = -1; do_put(rname,lname,&finfo); } fclose(f); unlink(tmpnam); } } /**************************************************************************** print a file ****************************************************************************/ void cmd_print(char *inbuf,char *outbuf ) { int fnum; FILE *f = NULL; uint32 nread=0; pstring lname; pstring rname; char *p; p = strtok(NULL,SEPARATORS); if (!p) { DEBUG(0,("print <filename>\n")); return; } strcpy(lname,p); strcpy(rname,lname); p = strrchr(rname,'/'); if (p) { pstring tname; strcpy(tname,p+1); strcpy(rname,tname); } if (strlen(rname) > 14) rname[14] = 0; if (strequal(lname,"-")) { f = stdin; strcpy(rname,"stdin"); } dos_clean_name(rname); memset(outbuf,0,smb_size); set_message(outbuf,2,2 + strlen(rname),True); CVAL(outbuf,smb_com) = SMBsplopen; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); SSVAL(outbuf,smb_vwv0,0); SSVAL(outbuf,smb_vwv1,printmode); p = smb_buf(outbuf); *p++ = 4; strcpy(p,rname); send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0) { DEBUG(0,("%s opening printer for %s\n",smb_errstr(inbuf),CNV_LANG(rname))); return; } if (!f) f = fopen(lname,"r"); if (!f) { DEBUG(0,("Error opening local file %s\n",lname)); return; } fnum = SVAL(inbuf,smb_vwv0); DEBUG(1,("printing file %s as %s\n",lname,CNV_LANG(rname))); while (!feof(f)) { int n; memset(outbuf,0,smb_size); set_message(outbuf,1,3,True); /* for some strange reason the OS/2 print server can't handle large packets when printing. weird */ n = MIN(1024,max_xmit-(smb_len(outbuf)+4)); #if 0 if (first) { n = 0; first = False; } else #endif { if (translation) n = printread(f,smb_buf(outbuf)+3,(int)(0.95*n)); else n = readfile(smb_buf(outbuf)+3,1,n,f); if (n <= 0) { DEBUG(0,("read gave %d\n",n)); break; } } smb_setlen(outbuf,smb_len(outbuf) + n); CVAL(outbuf,smb_com) = SMBsplwr; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); SSVAL(outbuf,smb_vwv0,fnum); SSVAL(outbuf,smb_vwv1,n+3); CVAL(smb_buf(outbuf),0) = 1; SSVAL(smb_buf(outbuf),1,n); send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0) { DEBUG(0,("%s printing remote file\n",smb_errstr(inbuf))); break; } nread += n; } DEBUG(2,("%d bytes printed\n",nread)); memset(outbuf,0,smb_size); set_message(outbuf,1,0,True); CVAL(outbuf,smb_com) = SMBsplclose; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); SSVAL(outbuf,smb_vwv0,fnum); send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0) { DEBUG(0,("%s closing print file\n",smb_errstr(inbuf))); if (f != stdin) fclose(f); return; } if (f != stdin) fclose(f); } /**************************************************************************** print a file ****************************************************************************/ void cmd_queue(char *inbuf,char *outbuf ) { int count; char *p; memset(outbuf,0,smb_size); set_message(outbuf,2,0,True); CVAL(outbuf,smb_com) = SMBsplretq; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); SSVAL(outbuf,smb_vwv0,32); /* a max of 20 entries is to be shown */ SSVAL(outbuf,smb_vwv1,0); /* the index into the queue */ send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0) { DEBUG(0,("%s obtaining print queue\n",smb_errstr(inbuf))); return; } count = SVAL(inbuf,smb_vwv0); p = smb_buf(inbuf) + 3; if (count <= 0) { DEBUG(0,("No entries in the print queue\n")); return; } { char status[20]; DEBUG(0,("Job Name Size Status\n")); while (count--) { switch (CVAL(p,4)) { case 0x01: sprintf(status,"held or stopped"); break; case 0x02: sprintf(status,"printing"); break; case 0x03: sprintf(status,"awaiting print"); break; case 0x04: sprintf(status,"in intercept"); break; case 0x05: sprintf(status,"file had error"); break; case 0x06: sprintf(status,"printer error"); break; default: sprintf(status,"unknown"); break; } DEBUG(0,("%-6d %-16.16s %-9d %s\n", SVAL(p,5),p+12,IVAL(p,7),status)); p += 28; } } } /**************************************************************************** delete some files ****************************************************************************/ void do_del(file_info *finfo) { char *p; char *inbuf,*outbuf; pstring mask; strcpy(mask,cur_dir); strcat(mask,finfo->name); if (finfo->mode & aDIR) return; inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); if (!inbuf || !outbuf) { DEBUG(0,("out of memory\n")); return; } memset(outbuf,0,smb_size); set_message(outbuf,1,2 + strlen(mask),True); CVAL(outbuf,smb_com) = SMBunlink; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); SSVAL(outbuf,smb_vwv0,0); p = smb_buf(outbuf); *p++ = 4; strcpy(p,mask); send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0) DEBUG(0,("%s deleting remote file %s\n",smb_errstr(inbuf),CNV_LANG(mask))); free(inbuf);free(outbuf); } /**************************************************************************** delete some files ****************************************************************************/ void cmd_del(char *inbuf,char *outbuf ) { pstring mask; char *p; int attribute = aSYSTEM | aHIDDEN; if (recurse) attribute |= aDIR; strcpy(mask,cur_dir); p = strtok(NULL,SEPARATORS); if (!p) { DEBUG(0,("del <filename>\n")); return; } strcat(mask,p); do_dir((char *)inbuf,(char *)outbuf,mask,attribute,do_del,False); } /**************************************************************************** remove a directory ****************************************************************************/ void cmd_rmdir(char *inbuf,char *outbuf ) { pstring mask; char *p; strcpy(mask,cur_dir); p = strtok(NULL,SEPARATORS); if (!p) { DEBUG(0,("rmdir <dirname>\n")); return; } strcat(mask,p); memset(outbuf,0,smb_size); set_message(outbuf,0,2 + strlen(mask),True); CVAL(outbuf,smb_com) = SMBrmdir; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); p = smb_buf(outbuf); *p++ = 4; strcpy(p,mask); send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0) { DEBUG(0,("%s removing remote directory file %s\n",smb_errstr(inbuf),CNV_LANG(mask))); return; } } /**************************************************************************** toggle the prompt flag ****************************************************************************/ void cmd_prompt(void) { prompt = !prompt; DEBUG(2,("prompting is now %s\n",prompt?"on":"off")); } /**************************************************************************** set the newer than time ****************************************************************************/ void cmd_newer(void) { char *p = strtok(NULL,SEPARATORS); struct stat sbuf; if (p && (stat(p,&sbuf) == 0)) { newer_than = sbuf.st_mtime + GMT_TO_LOCAL*TimeDiff(); DEBUG(1,("Getting files newer than %s",asctime(LocalTime(&newer_than,0)))); } else newer_than = 0; if (p && newer_than == 0) DEBUG(0,("Error setting newer-than time\n")); } /**************************************************************************** toggle the lowercaseflag ****************************************************************************/ void cmd_lowercase(void) { lowercase = !lowercase; DEBUG(2,("filename lowercasing is now %s\n",lowercase?"on":"off")); } /**************************************************************************** toggle the recurse flag ****************************************************************************/ void cmd_recurse(void) { recurse = !recurse; DEBUG(2,("directory recursion is now %s\n",recurse?"on":"off")); } /**************************************************************************** toggle the translate flag ****************************************************************************/ void cmd_translate(void) { translation = !translation; DEBUG(2,("CR/LF<->LF and print text translation now %s\n", translation?"on":"off")); } /**************************************************************************** do a printmode command ****************************************************************************/ void cmd_printmode(void) { char *p; pstring mode; p = strtok(NULL,SEPARATORS); if (p) { if (strequal(p,"text")) printmode = 0; else { if (strequal(p,"graphics")) printmode = 1; else printmode = atoi(p); } } switch(printmode) { case 0: strcpy(mode,"text"); break; case 1: strcpy(mode,"graphics"); break; default: sprintf(mode,"%d",printmode); break; } DEBUG(2,("the printmode is now %s\n",mode)); } /**************************************************************************** do the lcd command ****************************************************************************/ void cmd_lcd(void) { char *p; pstring d; p = strtok(NULL,SEPARATORS); if (p) chdir(p); DEBUG(2,("the local directory is now %s\n",GetWd(d))); } /**************************************************************************** send a login command ****************************************************************************/ BOOL send_login(char *inbuf,char *outbuf,BOOL use_setup) { int sesskey=0; struct { int prot; char *name; } prots[] = { {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"}, {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"}, #if LANMAN1 {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"}, {PROTOCOL_LANMAN1,"LANMAN1.0"}, #endif #if LANMAN2 {PROTOCOL_LANMAN2,"LM1.2X002"}, #endif {-1,NULL} }; char *pass = NULL; pstring dev = "A:"; char *p; int len = 4; int numprots; if (connect_as_printer) strcpy(dev,"LPT1:"); if (connect_as_ipc) strcpy(dev,"IPC"); /* send a session request (RFC 8002) */ CVAL(outbuf,0) = 0x81; /* put in the destination name */ p = outbuf+len; name_mangle(desthost,p); len += name_len(p); /* and my name */ p = outbuf+len; name_mangle(myname,p); len += name_len(p); /* setup the packet length */ /* We can't use smb_setlen here as it assumes a data packet and will trample over the name data we have copied in (by adding 0xFF 'S' 'M' 'B' at offsets 4 - 7 */ SSVAL(outbuf,2,len); BSWP(outbuf+2,2); if (len >= (1 << 16)) CVAL(outbuf,1) |= 1; send_smb(outbuf); DEBUG(5,("Sent session request\n")); receive_smb(inbuf,0); if (CVAL(inbuf,0) != 0x82) { int ecode = CVAL(inbuf,4); DEBUG(0,("Session request failed (%d,%d) with myname=%s destname=%s\n", CVAL(inbuf,0),ecode,myname,desthost)); switch (ecode) { case 0x80: DEBUG(0,("Not listening on called name\n")); DEBUG(0,("Try to connect to another name (instead of %s)\n",desthost)); DEBUG(0,("You may find the -I option useful for this\n")); break; case 0x81: DEBUG(0,("Not listening for calling name\n")); DEBUG(0,("Try to connect as another name (instead of %s)\n",myname)); DEBUG(0,("You may find the -n option useful for this\n")); break; case 0x82: DEBUG(0,("Called name not present\n")); DEBUG(0,("Try to connect to another name (instead of %s)\n",desthost)); DEBUG(0,("You may find the -I option useful for this\n")); break; case 0x83: DEBUG(0,("Called name present, but insufficient resources\n")); DEBUG(0,("Perhaps you should try again later?\n")); break; case 0x8F: DEBUG(0,("Unspecified error 0x%X\n",ecode)); DEBUG(0,("Your server software is being unfriendly\n")); break; } return(False); } memset(outbuf,0,smb_size); /* setup the protocol strings */ { int plength; char *p; for (numprots=0,plength=0;prots[numprots].name;numprots++) plength += strlen(prots[numprots].name)+2; set_message(outbuf,0,plength,True); p = smb_buf(outbuf); for (numprots=0;prots[numprots].name;numprots++) { *p++ = 2; strcpy(p,prots[numprots].name); p += strlen(p) + 1; } } CVAL(outbuf,smb_com) = SMBnegprot; setup_pkt(outbuf); CVAL(smb_buf(outbuf),0) = 2; send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0 || ((int)SVAL(inbuf,smb_vwv0) >= numprots)) { DEBUG(0,("SMBnegprot failed. myname=%s destname=%s - %s \n", myname,desthost,smb_errstr(inbuf))); return(False); } max_xmit = MIN(max_xmit,(int)SVAL(inbuf,smb_vwv2)); DEBUG(3,("Sec mode %d\n",SVAL(inbuf,smb_vwv1))); DEBUG(3,("max xmt %d\n",SVAL(inbuf,smb_vwv2))); DEBUG(3,("max mux %d\n",SVAL(inbuf,smb_vwv3))); DEBUG(3,("max vcs %d\n",SVAL(inbuf,smb_vwv4))); DEBUG(3,("max blk %d\n",SVAL(inbuf,smb_vwv5))); DEBUG(3,("time zone %d\n",SVAL(inbuf,smb_vwv10))); sesskey = IVAL(inbuf,smb_vwv6); servertime = make_unix_date(inbuf+smb_vwv8); DEBUG(3,("Got %d byte crypt key\n",strlen(smb_buf(inbuf)))); DEBUG(3,("Chose protocol [%s]\n",prots[SVAL(inbuf,smb_vwv0)].name)); Protocol = prots[SVAL(inbuf,smb_vwv0)].prot; if (Protocol >= PROTOCOL_COREPLUS) { readbraw_supported = ((SVAL(inbuf,smb_vwv5) & 0x1) != 0); writebraw_supported = ((SVAL(inbuf,smb_vwv5) & 0x2) != 0); } if (Protocol >= PROTOCOL_LANMAN1) { DEBUG(1,("Server time is %sTimezone is UTC%+d\n", asctime(LocalTime(&servertime,0)), -(int16)SVAL(inbuf,smb_vwv10)/60)); } if (got_pass) pass = password; else pass = (char *)getpass("Password: "); if (Protocol >= PROTOCOL_LANMAN1 && use_setup) { /* send a session setup command */ memset(outbuf,0,smb_size); set_message(outbuf,10,2 + strlen(username) + strlen(pass),True); CVAL(outbuf,smb_com) = SMBsesssetupX; setup_pkt(outbuf); CVAL(outbuf,smb_vwv0) = 0xFF; SSVAL(outbuf,smb_vwv2,max_xmit); SSVAL(outbuf,smb_vwv3,2); SSVAL(outbuf,smb_vwv4,getpid()); SIVAL(outbuf,smb_vwv5,sesskey); SSVAL(outbuf,smb_vwv7,strlen(pass)+1); p = smb_buf(outbuf); strcpy(p,pass); p += strlen(pass)+1; strcpy(p,username); send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0) { DEBUG(0,("Session setup failed for username=%s myname=%s destname=%s %s\n", username,myname,desthost,smb_errstr(inbuf))); DEBUG(0,("You might find the -U or -n options useful\n")); DEBUG(0,("Sometimes you have to use `-n USERNAME' (particularly with OS/2)\n")); DEBUG(0,("Some servers also insist on uppercase-only passwords\n")); return(False); } /* use the returned uid from now on */ if (SVAL(inbuf,smb_uid) != uid) DEBUG(3,("Server gave us a UID of %d. We gave %d\n", SVAL(inbuf,smb_uid),uid)); uid = SVAL(inbuf,smb_uid); } /* now we've got a connection - send a tcon message */ memset(outbuf,0,smb_size); #if 0 if (Protocol >= PROTOCOL_LANMAN1) strcpy(pass,""); #endif if (strncmp(service,"\\\\",2) != 0) { DEBUG(0,("\nWarning: Your service name doesn't start with \\\\. This is probably incorrect.\n")); DEBUG(0,("Perhaps try replacing each \\ with \\\\ on the command line?\n\n")); } again: set_message(outbuf,0,6 + strlen(service) + strlen(pass) + strlen(dev),True); CVAL(outbuf,smb_com) = SMBtcon; setup_pkt(outbuf); p = smb_buf(outbuf); *p++ = 4; strcpy(p,service); p += strlen(p) + 1; *p++ = 4; strcpy(p,pass); p += strlen(p) + 1; *p++ = 4; strcpy(p,dev); send_smb(outbuf); receive_smb(inbuf,0); /* trying again with a blank password */ if (CVAL(inbuf,smb_rcls) != 0 && strlen(pass) > 0 && Protocol >= PROTOCOL_LANMAN1) { DEBUG(0,("first SMBtcon failed, trying again. %s\n",smb_errstr(inbuf))); strcpy(pass,""); goto again; } if (CVAL(inbuf,smb_rcls) != 0) { DEBUG(0,("SMBtcon failed. %s\n",smb_errstr(inbuf))); DEBUG(0,("Perhaps you are using the wrong sharename, username or password?\n")); DEBUG(0,("Some servers insist that these be in uppercase\n")); return(False); } max_xmit = SVAL(inbuf,smb_vwv0); max_xmit = MIN(max_xmit,BUFFER_SIZE-4); if (max_xmit <= 0) max_xmit = BUFFER_SIZE - 4; cnum = SVAL(inbuf,smb_vwv1); DEBUG(3,("Connected with cnum=%d max_xmit=%d\n",cnum,max_xmit)); /* wipe out the password from memory */ if (got_pass) memset(password,0,strlen(password)); return True; } /**************************************************************************** send a logout command ****************************************************************************/ void send_logout(char *inbuf,char *outbuf ) { set_message(outbuf,0,0,True); CVAL(outbuf,smb_com) = SMBtdis; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0) { DEBUG(0,("SMBtdis failed %s\n",smb_errstr(inbuf))); } #if 0 set_message(outbuf,0,0,True); CVAL(outbuf,smb_com) = SMBexit; setup_pkt(outbuf); send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) != 0) { DEBUG(0,("SMBexit failed %s\n",smb_errstr(inbuf))); } #endif #ifdef STATS stats_report(); #endif exit(0); } /**************************************************************************** try and browse available connections on a host ****************************************************************************/ void browse_host() { char *p; char *params; char *inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); char *outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); if ((inbuf == NULL) || (outbuf == NULL)) return; memset(outbuf,0,smb_size); if (!send_login(inbuf,outbuf,True)) return; /* now send a SMBtrans command with api RNetShareEnum */ memset(outbuf,0,smb_size); set_message(outbuf,14,0,True); CVAL(outbuf,smb_com) = SMBtrans; SSVAL(outbuf,smb_tid,cnum); setup_pkt(outbuf); SSVAL(outbuf,smb_vwv1,0); /* data count */ SSVAL(outbuf,smb_vwv2,1024); /* mprcnt */ SSVAL(outbuf,smb_vwv3,4096); /* mdrcnt */ SSVAL(outbuf,smb_vwv4,10); /* msrcnt */ SSVAL(outbuf,smb_vwv5,0); /* flags */ SSVAL(outbuf,smb_vwv11,0); /* dscnt */ SSVAL(outbuf,smb_vwv12,0); /* dsoff */ CVAL(outbuf,smb_vwv13) = 0; /* suwcnt */ p = smb_buf(outbuf); strcpy(p,"\\PIPE\\LANMAN"); params = skip_string(p,1); SSVAL(params,0,0); /* RNetShareEnum */ p = params+2; strcpy(p,"WrLeh"); p = skip_string(p,1); strcpy(p,"B13BWz"); p = skip_string(p,1); SSVAL(p,0,1); SSVAL(p,2,SVAL(outbuf,smb_vwv3)); p += 4; set_message(outbuf,14,PTR_DIFF(p,smb_buf(outbuf)),False); SSVAL(outbuf,smb_vwv0,PTR_DIFF(p,params)); /* param count */ SSVAL(outbuf,smb_vwv9,SVAL(outbuf,smb_vwv0)); /* pscnt */ SSVAL(outbuf,smb_vwv10,PTR_DIFF(params,outbuf)-4); /* psoff */ send_smb(outbuf); receive_smb(inbuf,0); if (CVAL(inbuf,smb_rcls) == 0) { int ofs_param = SVAL(inbuf,smb_vwv4); int ofs_data = SVAL(inbuf,smb_vwv7); char *param = inbuf+4 + ofs_param; char *data = inbuf+4 + ofs_data; int count=SVAL(param,4); int converter=SVAL(param,2); int i; p = data; if (count > 0) { printf("\n\tSharename Type Comment\n"); printf("\t--------- ---- -------\n"); } for (i=0;i<count;i++) { char *sname = p; int type = SVAL(p,14); int comment_offset = IVAL(p,16) & 0xFFFF; fstring typestr=""; switch (type) { case 0: strcpy(typestr,"Disk"); break; case 1: strcpy(typestr,"Printer"); break; case 2: strcpy(typestr,"Device"); break; case 3: strcpy(typestr,"IPC"); break; } printf("\t%-15.15s%-10.10s%s\n", sname, typestr, comment_offset?data+comment_offset-converter:""); p += 20; } } send_logout(inbuf,outbuf); } void cmd_help(); /* This defines the commands supported by this client */ struct { char *name; void (*fn)(); char *description; } commands[] = { {"ls",cmd_dir,"<mask> list the contents of the current directory"}, {"dir",cmd_dir,"<mask> list the contents of the current directory"}, {"lcd",cmd_lcd,"[directory] change/report the local current working directory"}, {"cd",cmd_cd,"[directory] change/report the remote directory"}, {"get",cmd_get,"<remote name> [local name] get a file"}, {"mget",cmd_mget,"<mask> get all the matching files"}, {"put",cmd_put,"<local name> [remote name] put a file"}, {"mput",cmd_mput,"<mask> put all matching files"}, {"mask",cmd_select,"<mask> mask all filenames against this"}, {"del",cmd_del,"<mask> delete all matching files"}, {"rm",cmd_del,"<mask> delete all matching files"}, {"mkdir",cmd_mkdir,"<directory> make a directory"}, {"md",cmd_mkdir,"<directory> make a directory"}, {"rmdir",cmd_rmdir,"<directory> remove a directory"}, {"rd",cmd_rmdir,"<directory> remove a directory"}, {"prompt",cmd_prompt,"toggle prompting for filenames for mget and mput"}, {"recurse",cmd_recurse,"toggle directory recursion for mget and mput"}, {"translate",cmd_translate,"toggle text translation for printing"}, {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get"}, {"print",cmd_print,"<file name> print a file"}, {"printmode",cmd_printmode,"<graphics or text> set the print mode"}, {"queue",cmd_queue,"show the print queue"}, {"quit",send_logout,"logoff the server"}, {"exit",send_logout,"logoff the server"}, {"newer",cmd_newer,"<file> only mget files newer than the specified local file"}, {"help",cmd_help,"[command] give help on a command"}, {"?",cmd_help,"[command] give help on a command"}, {"!",NULL,"run a shell command on the local system"}, {"",NULL,NULL} }; /**************************************************************************** help ****************************************************************************/ void cmd_help(void) { int i=0; char *p; p = strtok(NULL,SEPARATORS); if (p) { while (commands[i].description) { if (strequal(commands[i].name,p)) DEBUG(0,("HELP %s:\n\t%s\n\n",commands[i].name,commands[i].description)); i++; } } else while (commands[i].description) { DEBUG(0,("%s\n",commands[i].name)); i++; } } /**************************************************************************** open the client sockets ****************************************************************************/ BOOL open_sockets(int port ) { char *host; pstring service2; extern int Client; strupper(service); strcpy(service2,service); host = strtok(service2,"\\/"); strcpy(desthost,host); DEBUG(3,("Opening sockets\n")); if (*myname == 0) { get_myname(myname,NULL); strupper(myname); } if (!have_ip) { struct hostent *hp; if ((hp = Get_Hostbyname(host)) == 0) { DEBUG(0,("Get_Hostbyname: Unknown host %s.\n",host)); return False; } memcpy((char *)&dest_ip,(char *)hp->h_addr,4); } Client = open_socket_out(&dest_ip, port); if (Client == -1) return False; DEBUG(3,("Connected\n")); { int one=1; setsockopt(Client,SOL_SOCKET,SO_KEEPALIVE,(char *)&one,sizeof(one)); } DEBUG(3,("Sockets open\n")); return True; } /**************************************************************************** wait for keyboard activity, swallowing network packets ****************************************************************************/ #ifdef CLIX char wait_keyboard(char *buffer) #else void wait_keyboard(char *buffer) #endif { fd_set fds; int selrtn; struct timeval timeout; #ifdef CLIX int delay = 0; #endif while (1) { extern int Client; FD_ZERO(&fds); FD_SET(Client,&fds); #ifndef CLIX FD_SET(fileno(stdin),&fds); #endif do { #ifdef CLIX timeout.tv_sec = 0; #else timeout.tv_sec = 20; #endif timeout.tv_usec = 0; selrtn = select(255,SELECT_CAST &fds,NULL,NULL,&timeout); } while(selrtn < 0 && errno == EINTR); #ifndef CLIX if (FD_ISSET(fileno(stdin),&fds)) return; #else { char ch; int f_flags; int readret; f_flags = fcntl(fileno(stdin), F_GETFL, 0); fcntl( fileno(stdin), F_SETFL, f_flags | O_NONBLOCK); readret = read( fileno(stdin), &ch, 1); fcntl(fileno(stdin), F_SETFL, f_flags); if (readret == -1) { if (errno != EAGAIN) { /* should crash here */ DEBUG(1,("readchar stdin failed\n")); } } else if (readret != 0) { return ch; } } #endif if (FD_ISSET(Client,&fds)) receive_smb(buffer,0); #ifdef CLIX delay++; if (delay > 100000) { delay = 0; chkpath("\\",False); } #else chkpath("\\",False); #endif } } #if 0 /**************************************************************************** wait for keyboard activity, swallowing network packets ****************************************************************************/ void wait_keyboard(char *buffer) { fd_set fds; int selrtn; struct timeval timeout; while (1) { extern int Client; FD_ZERO(&fds); FD_SET(Client,&fds); FD_SET(fileno(stdin),&fds); do { timeout.tv_sec = 20; timeout.tv_usec = 0; selrtn = select(255,SELECT_CAST &fds,NULL,NULL,&timeout); } while(selrtn < 0 && errno == EINTR); if (FD_ISSET(fileno(stdin),&fds)) return; if (FD_ISSET(Client,&fds)) receive_smb(buffer,0); chkpath("\\",False); } } #endif /**************************************************************************** try and register my own netbios name with a unicast ****************************************************************************/ void register_myname(void) { name_struct name; name.valid = True; strcpy(name.name,myname); strupper(name.name); strcpy(name.flags,""); name.ip = myip; name.ttl = 0; name.nb_flags = 0; register_name(&name,&dest_ip,NULL); } /**************************************************************************** process commands from the client ****************************************************************************/ void process(void ) { pstring line; char *InBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); char *OutBuffer = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN); if ((InBuffer == NULL) || (OutBuffer == NULL)) return; memset(OutBuffer,0,smb_size); #if REGISTER register_myname(); #endif if (!send_login(InBuffer,OutBuffer,True)) return; while (!feof(stdin)) { char *tok; int i; BOOL found = False; memset(OutBuffer,0,smb_size); /* display a prompt */ DEBUG(1,("smb: %s> ", CNV_LANG(cur_dir))); #ifdef CLIX line[0] = wait_keyboard(InBuffer); /* this might not be such a good idea... */ if ( line[0] == EOF) break; #else wait_keyboard(InBuffer); #endif /* and get a response */ #ifdef CLIX fgets( &line[1],999, stdin); #else if (!fgets(line,1000,stdin)) #endif break; { pstring line2; strcpy (line2, CNV_INPUT(line)); strcpy (line, line2); } /* special case - first char is ! */ if (*line == '!') { system(line + 1); continue; } /* and get the first part of the command */ tok = strtok(line,SEPARATORS); i = 0; while (commands[i].fn != NULL) { if (strequal(commands[i].name,tok)) { found = True; commands[i].fn(InBuffer,OutBuffer); } i++; } if (!found && tok) DEBUG(0,("%s: command not found\n",CNV_LANG(tok))); } memset(OutBuffer,0,smb_size); send_logout(InBuffer,OutBuffer); } /**************************************************************************** usage on the program ****************************************************************************/ void usage(char *pname) { #ifdef KANJI DEBUG(0,("Usage: %s service <password> [-p port] [-d debuglevel] [-l log] [-e]\n", pname)); #else DEBUG(0,("Usage: %s service <password> [-p port] [-d debuglevel] [-l log]\n",pname)); #endif /* KANJI */ DEBUG(0,("Version %s\n",VERSION)); DEBUG(0,("\t-p port listen on the specified port\n")); DEBUG(0,("\t-d debuglevel set the debuglevel\n")); DEBUG(0,("\t-l log basename. Basename for log/debug files\n")); DEBUG(0,("\t-n netbios name. Use this name as my netbios name\n")); DEBUG(0,("\t-N don't ask for a password\n")); DEBUG(0,("\t-P connect to service as a printer\n")); DEBUG(0,("\t-L host get a list of shares available on a host\n")); DEBUG(0,("\t-I dest IP use this IP to connect to\n")); DEBUG(0,("\t-E write messages to stderr instead of stdout\n")); DEBUG(0,("\t-U username set the network username\n")); #ifdef KANJI DEBUG(0,("\t-e terminal output code to EUC\n")); #endif /* KANJI */ DEBUG(0,("\n")); } /**************************************************************************** main program ****************************************************************************/ int main(int argc,char *argv[]) { char *pname = argv[0]; int port = 139; int opt; extern FILE *dbf; extern char *optarg; pstring query_host=""; DEBUGLEVEL = 2; dbf = stdout; pid = getpid(); uid = getuid(); gid = getgid(); mid = pid + 100; myumask = umask(0); umask(myumask); if (getenv("USER")) { strcpy(username,getenv("USER")); strupper(username); } if (*username == 0 && getenv("LOGNAME")) { strcpy(username,getenv("LOGNAME")); strupper(username); } if (argc < 2) { usage(pname); exit(0); } if (*argv[1] != '-') { strcpy(service,argv[1]); argc--; argv++; if (count_chars(service,'\\') < 3) { usage(pname); printf("\n%s: Not enough '\\' characters in service\n",service); exit(0); } if (count_chars(service,'\\') > 3) { usage(pname); printf("\n%s: Too many '\\' characters in service\n",service); exit(0); } if (argc > 1 && (*argv[1] != '-')) { got_pass = True; strcpy(password,argv[1]); memset(argv[1],'X',strlen(argv[1])); argc--; argv++; } } #ifdef KANJI while ((opt = getopt (argc, argv, "i:Nn:d:Pp:l:hI:EeB:U:L:")) != EOF) #else while ((opt = getopt (argc, argv, "i:Nn:d:Pp:l:hI:EB:U:L:")) != EOF) #endif /* KANJI */ switch (opt) { case 'i': strcpy(scope,optarg); break; case 'L': got_pass = True; strcpy(query_host,optarg); break; case 'U': { char *p; strcpy(username,optarg); if ((p=strchr(username,'%'))) { *p = 0; strcpy(password,p+1); got_pass = True; memset(strchr(optarg,'%')+1,'X',strlen(password)); } } break; case 'E': dbf = stderr; break; case 'I': { unsigned long a = interpret_addr(optarg); memcpy((char *)&dest_ip,(char *)&a,sizeof(a)); have_ip = True; } break; case 'n': strcpy(myname,optarg); break; case 'N': got_pass = True; break; case 'P': connect_as_printer = True; break; case 'd': if (*optarg == 'A') DEBUGLEVEL = 10000; else DEBUGLEVEL = atoi(optarg); break; case 'l': sprintf(debugf,"%s.client",optarg); break; case 'p': port = atoi(optarg); break; case 'h': usage(pname); exit(0); break; #ifdef KANJI case 'e': term_code = EUC_CODE; break; #endif /* KANJI */ default: usage(pname); exit(1); } if (!*query_host && !*service) { usage(pname); exit(1); } NeedSwap = big_endian(); DEBUG(3,("%s client started (version %s)\n",timestring(),VERSION)); if (DEBUGLEVEL > 100) { extern FILE *login,*logout; pstring fname; sprintf(fname,"%s.in",debugf); login = fopen(fname,"w"); if (login) chmod(fname,0600); sprintf(fname,"%s.out",debugf); logout = fopen(fname,"w"); if (logout) chmod(fname,0600); } get_machine_info(); #if 0 /* Read the broadcast address from the interface */ get_broadcast(&myip,&bcast_ip,&Netmask); #endif get_myname(*myname?NULL:myname,&myip); strupper(myname); if (*query_host) { sprintf(service,"\\\\%s\\IPC$",query_host); strupper(service); connect_as_ipc = True; if (open_sockets(port)) browse_host(); close_sockets(); return(0); } if (open_sockets(port)) { process(); close_sockets(); } return(0); } /* error code stuff - put together by Merik Karman merik@blackadder.dsh.oz.au */ typedef struct { char *name; int code; char *message; } err_code_struct; /* Dos Error Messages */ err_code_struct dos_msgs[] = { {"ERRbadfunc",1,"Invalid function."}, {"ERRbadfile",2,"File not found."}, {"ERRbadpath",3,"Directory invalid."}, {"ERRnofids",4,"No file descriptors available"}, {"ERRnoaccess",5,"Access denied."}, {"ERRbadfid",6,"Invalid file handle."}, {"ERRbadmcb",7,"Memory control blocks destroyed."}, {"ERRnomem",8,"Insufficient server memory to perform the requested function."}, {"ERRbadmem",9,"Invalid memory block address."}, {"ERRbadenv",10,"Invalid environment."}, {"ERRbadformat",11,"Invalid format."}, {"ERRbadaccess",12,"Invalid open mode."}, {"ERRbaddata",13,"Invalid data."}, {"ERR",14,"reserved."}, {"ERRbaddrive",15,"Invalid drive specified."}, {"ERRremcd",16,"A Delete Directory request attempted to remove the server's current directory."}, {"ERRdiffdevice",17,"Not same device."}, {"ERRnofiles",18,"A File Search command can find no more files matching the specified criteria."}, {"ERRbadshare",32,"The sharing mode specified for an Open conflicts with existing FIDs on the file."}, {"ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."}, {"ERRfilexists",80,"The file named in a Create Directory, Make New File or Link request already exists."}, {"ERRbadpipe",230,"Pipe invalid."}, {"ERRpipebusy",231,"All instances of the requested pipe are busy."}, {"ERRpipeclosing",232,"Pipe close in progress."}, {"ERRnotconnected",233,"No process on other end of pipe."}, {"ERRmoredata",234,"There is more data to be returned."}, {NULL,-1,NULL}}; /* Server Error Messages */ err_code_struct server_msgs[] = { {"ERRerror",1,"Non-specific error code."}, {"ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."}, {"ERRbadtype",3,"reserved."}, {"ERRaccess",4,"The requester does not have the necessary access rights within the specified context for the requested function. The context is defined by the TID or the UID."}, {"ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."}, {"ERRinvnetname",6,"Invalid network name in tree connect."}, {"ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or non-printer request made to printer connection."}, {"ERRqfull",49,"Print queue full (files) -- returned by open print file."}, {"ERRqtoobig",50,"Print queue full -- no space."}, {"ERRqeof",51,"EOF on print queue dump."}, {"ERRinvpfid",52,"Invalid print file FID."}, {"ERRsmbcmd",64,"The server did not recognize the command received."}, {"ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."}, {"ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid combination of values."}, {"ERRreserved",68,"reserved."}, {"ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute."}, {"ERRreserved",70,"reserved."}, {"ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."}, {"ERRpaused",81,"Server is paused. (reserved for messaging)"}, {"ERRmsgoff",82,"Not receiving messages. (reserved for messaging)."}, {"ERRnoroom",83,"No room to buffer message. (reserved for messaging)."}, {"ERRrmuns",87,"Too many remote user names. (reserved for messaging)."}, {"ERRtimeout",88,"Operation timed out."}, {"ERRnoresource",89,"No resources currently available for request."}, {"ERRtoomanyuids",90,"Too many UIDs active on this session."}, {"ERRbaduid",91,"The UID is not known as a valid ID on this session."}, {"ERRusempx",250,"Temp unable to support Raw, use MPX mode."}, {"ERRusestd",251,"Temp unable to support Raw, use standard read/write."}, {"ERRcontmpx",252,"Continue in MPX mode."}, {"ERRreserved",253,"reserved."}, {"ERRreserved",254,"reserved."}, {"ERRnosupport",0xFFFF,"Function not supported."}, {NULL,-1,NULL}}; /* Hard Error Messages */ err_code_struct hard_msgs[] = { {"ERRnowrite",19,"Attempt to write on write-protected diskette."}, {"ERRbadunit",20,"Unknown unit."}, {"ERRnotready",21,"Drive not ready."}, {"ERRbadcmd",22,"Unknown command."}, {"ERRdata",23,"Data error (CRC)."}, {"ERRbadreq",24,"Bad request structure length."}, {"ERRseek",25 ,"Seek error."}, {"ERRbadmedia",26,"Unknown media type."}, {"ERRbadsector",27,"Sector not found."}, {"ERRnopaper",28,"Printer out of paper."}, {"ERRwrite",29,"Write fault."}, {"ERRread",30,"Read fault."}, {"ERRgeneral",31,"General failure."}, {"ERRbadshare",32,"A open conflicts with an existing open."}, {"ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."}, {"ERRwrongdisk",34,"The wrong disk was found in a drive."}, {"ERRFCBUnavail",35,"No FCBs are available to process request."}, {"ERRsharebufexc",36,"A sharing buffer has been exceeded."}, {NULL,-1,NULL}}; struct { int code; char *class; err_code_struct *err_msgs; } err_classes[] = { {0,"SUCCESS",NULL}, {0x01,"ERRDOS",dos_msgs}, {0x02,"ERRSRV",server_msgs}, {0x03,"ERRHRD",hard_msgs}, {0x04,"ERRXOS",NULL}, {0xE1,"ERRRMX1",NULL}, {0xE2,"ERRRMX2",NULL}, {0xE3,"ERRRMX3",NULL}, {0xFF,"ERRCMD",NULL}, {-1,NULL,NULL}}; /**************************************************************************** return a SMB error string from a SMB buffer ****************************************************************************/ char *smb_errstr(char *inbuf) { static pstring ret; int class = CVAL(inbuf,smb_rcls); int num = SVAL(inbuf,smb_err); int i,j; for (i=0;err_classes[i].class;i++) if (err_classes[i].code == class) { if (err_classes[i].err_msgs) { err_code_struct *err = err_classes[i].err_msgs; for (j=0;err[j].name;j++) if (num == err[j].code) { if (DEBUGLEVEL > 0) sprintf(ret,"%s - %s (%s)",err_classes[i].class, err[j].name,err[j].message); else sprintf(ret,"%s - %s",err_classes[i].class,err[j].name); return ret; } } sprintf(ret,"%s - %d",err_classes[i].class,num); return ret; } sprintf(ret,"ERROR: Unknown error (%d,%d)",class,num); return(ret); }