home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 July & August / Pcwk78a98.iso / Wtestowe / Clico / UNIX / SAMBA / SOURCE / SAMBA.TAR / samba-1.9.17 / source / clientutil.c < prev    next >
C/C++ Source or Header  |  1997-07-31  |  30KB  |  1,028 lines

  1. /* 
  2.    Unix SMB/Netbios implementation.
  3.    Version 1.9.
  4.    SMB client
  5.    Copyright (C) Andrew Tridgell 1994-1997
  6.    
  7.    This program is free software; you can redistribute it and/or modify
  8.    it under the terms of the GNU General Public License as published by
  9.    the Free Software Foundation; either version 2 of the License, or
  10.    (at your option) any later version.
  11.    
  12.    This program is distributed in the hope that it will be useful,
  13.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.    GNU General Public License for more details.
  16.    
  17.    You should have received a copy of the GNU General Public License
  18.    along with this program; if not, write to the Free Software
  19.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21.  
  22. #ifdef SYSLOG
  23. #undef SYSLOG
  24. #endif
  25.  
  26. #include "includes.h"
  27.  
  28. #ifndef REGISTER
  29. #define REGISTER 0
  30. #endif
  31.  
  32. pstring service="";
  33. pstring desthost="";
  34. extern pstring myname;
  35. pstring password = "";
  36. pstring username="";
  37. pstring workgroup=WORKGROUP;
  38. BOOL got_pass = False;
  39. BOOL connect_as_printer = False;
  40. BOOL connect_as_ipc = False;
  41.  
  42. char cryptkey[8];
  43. BOOL doencrypt=False;
  44.  
  45. extern pstring user_socket_options;
  46.  
  47. /* 30 second timeout on most commands */
  48. #define CLIENT_TIMEOUT (30*1000)
  49. #define SHORT_TIMEOUT (5*1000)
  50.  
  51. int name_type = 0x20;
  52.  
  53. int max_protocol = PROTOCOL_NT1;
  54.  
  55. BOOL readbraw_supported = False;
  56. BOOL writebraw_supported = False;
  57.  
  58. extern int DEBUGLEVEL;
  59.  
  60. int cnum = 0;
  61. int pid = 0;
  62. int gid = 0;
  63. int uid = 0;
  64. int mid = 0;
  65.  
  66. int max_xmit = BUFFER_SIZE;
  67.  
  68. BOOL have_ip = False;
  69.  
  70. struct in_addr dest_ip;
  71.  
  72. extern int Protocol;
  73.  
  74. extern int Client;
  75.  
  76.  
  77. /****************************************************************************
  78. setup basics in a outgoing packet
  79. ****************************************************************************/
  80. void cli_setup_pkt(char *outbuf)
  81. {
  82.   SSVAL(outbuf,smb_pid,pid);
  83.   SSVAL(outbuf,smb_uid,uid);
  84.   SSVAL(outbuf,smb_mid,mid);
  85.   if (Protocol > PROTOCOL_CORE)
  86.     {
  87.       SCVAL(outbuf,smb_flg,0x8);
  88.       SSVAL(outbuf,smb_flg2,0x1);
  89.     }
  90. }
  91.  
  92. /****************************************************************************
  93.   receive a SMB trans or trans2 response allocating the necessary memory
  94.   ****************************************************************************/
  95. BOOL cli_receive_trans_response(char *inbuf,int trans,int *data_len,
  96.                 int *param_len, char **data,char **param)
  97. {
  98.   int total_data=0;
  99.   int total_param=0;
  100.   int this_data,this_param;
  101.  
  102.   *data_len = *param_len = 0;
  103.  
  104.   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
  105.   show_msg(inbuf);
  106.  
  107.   /* sanity check */
  108.   if (CVAL(inbuf,smb_com) != trans)
  109.     {
  110.       DEBUG(0,("Expected %s response, got command 0x%02x\n",
  111.            trans==SMBtrans?"SMBtrans":"SMBtrans2", CVAL(inbuf,smb_com)));
  112.       return(False);
  113.     }
  114.   if (CVAL(inbuf,smb_rcls) != 0)
  115.     return(False);
  116.  
  117.   /* parse out the lengths */
  118.   total_data = SVAL(inbuf,smb_tdrcnt);
  119.   total_param = SVAL(inbuf,smb_tprcnt);
  120.  
  121.   /* allocate it */
  122.   *data = Realloc(*data,total_data);
  123.   *param = Realloc(*param,total_param);
  124.  
  125.   while (1)
  126.     {
  127.       this_data = SVAL(inbuf,smb_drcnt);
  128.       this_param = SVAL(inbuf,smb_prcnt);
  129.       if (this_data)
  130.     memcpy(*data + SVAL(inbuf,smb_drdisp),
  131.            smb_base(inbuf) + SVAL(inbuf,smb_droff),
  132.            this_data);
  133.       if (this_param)
  134.     memcpy(*param + SVAL(inbuf,smb_prdisp),
  135.            smb_base(inbuf) + SVAL(inbuf,smb_proff),
  136.            this_param);
  137.       *data_len += this_data;
  138.       *param_len += this_param;
  139.  
  140.       /* parse out the total lengths again - they can shrink! */
  141.       total_data = SVAL(inbuf,smb_tdrcnt);
  142.       total_param = SVAL(inbuf,smb_tprcnt);
  143.  
  144.       if (total_data <= *data_len && total_param <= *param_len)
  145.     break;
  146.  
  147.       receive_smb(Client,inbuf,CLIENT_TIMEOUT);
  148.       show_msg(inbuf);
  149.  
  150.       /* sanity check */
  151.       if (CVAL(inbuf,smb_com) != trans)
  152.     {
  153.       DEBUG(0,("Expected %s response, got command 0x%02x\n",
  154.            trans==SMBtrans?"SMBtrans":"SMBtrans2", CVAL(inbuf,smb_com)));
  155.       return(False);
  156.     }
  157.       if (CVAL(inbuf,smb_rcls) != 0)
  158.       return(False);
  159.     }
  160.   
  161.   return(True);
  162. }
  163.  
  164. /****************************************************************************
  165. send a session request
  166. ****************************************************************************/
  167. BOOL cli_send_session_request(char *inbuf, char *outbuf)
  168. {
  169.   fstring dest;
  170.   char *p;
  171.   int len = 4;
  172.   /* send a session request (RFC 8002) */
  173.  
  174.   strcpy(dest,desthost);
  175.   p = strchr(dest,'.');
  176.   if (p) *p = 0;
  177.  
  178.   /* put in the destination name */
  179.   p = outbuf+len;
  180.   name_mangle(dest,p,name_type);
  181.   len += name_len(p);
  182.  
  183.   /* and my name */
  184.   p = outbuf+len;
  185.   name_mangle(myname,p,0);
  186.   len += name_len(p);
  187.  
  188.   /* setup the packet length */
  189.   _smb_setlen(outbuf,len);
  190.   CVAL(outbuf,0) = 0x81;
  191.  
  192.   send_smb(Client,outbuf);
  193.   DEBUG(5,("Sent session request\n"));
  194.  
  195.   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
  196.  
  197.   if (CVAL(inbuf,0) == 0x84) /* C. Hoch  9/14/95 Start */
  198.     {
  199.       /* For information, here is the response structure.
  200.        * We do the byte-twiddling to for portability.
  201.        struct RetargetResponse{
  202.        unsigned char type;
  203.        unsigned char flags;
  204.        int16 length;
  205.        int32 ip_addr;
  206.        int16 port;
  207.        };
  208.        */
  209.       extern int Client;
  210.       int port = (CVAL(inbuf,8)<<8)+CVAL(inbuf,9);
  211.       /* SESSION RETARGET */
  212.       putip((char *)&dest_ip,inbuf+4);
  213.  
  214.       close_sockets();
  215.       Client = open_socket_out(SOCK_STREAM, &dest_ip, port, SHORT_CONNECT_TIMEOUT);
  216.       if (Client == -1)
  217.         return False;
  218.  
  219.       DEBUG(5,("Retargeted\n"));
  220.  
  221.       set_socket_options(Client,user_socket_options);
  222.  
  223.       /* Try again */
  224.       return cli_send_session_request(inbuf,outbuf);
  225.     } /* C. Hoch 9/14/95 End */
  226.  
  227.  
  228.   if (CVAL(inbuf,0) != 0x82)
  229.     {
  230.       int ecode = CVAL(inbuf,4);
  231.       DEBUG(0,("Session request failed (%d,%d) with myname=%s destname=%s\n",
  232.            CVAL(inbuf,0),ecode,myname,desthost));
  233.       switch (ecode)
  234.     {
  235.     case 0x80: 
  236.       DEBUG(0,("Not listening on called name\n")); 
  237.       DEBUG(0,("Try to connect to another name (instead of %s)\n",desthost));
  238.       DEBUG(0,("You may find the -I option useful for this\n"));
  239.       break;
  240.     case 0x81: 
  241.       DEBUG(0,("Not listening for calling name\n")); 
  242.       DEBUG(0,("Try to connect as another name (instead of %s)\n",myname));
  243.       DEBUG(0,("You may find the -n option useful for this\n"));
  244.       break;
  245.     case 0x82: 
  246.       DEBUG(0,("Called name not present\n")); 
  247.       DEBUG(0,("Try to connect to another name (instead of %s)\n",desthost));
  248.       DEBUG(0,("You may find the -I option useful for this\n"));
  249.       break;
  250.     case 0x83: 
  251.       DEBUG(0,("Called name present, but insufficient resources\n")); 
  252.       DEBUG(0,("Perhaps you should try again later?\n")); 
  253.       break;
  254.     default:
  255.       DEBUG(0,("Unspecified error 0x%X\n",ecode)); 
  256.       DEBUG(0,("Your server software is being unfriendly\n"));
  257.       break;      
  258.     }
  259.       return(False);
  260.     }
  261.   return(True);
  262. }
  263.  
  264.  
  265. static  struct {
  266.     int prot;
  267.     char *name;
  268.   }
  269. prots[] = 
  270.     {
  271.       {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
  272.       {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
  273.       {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
  274.       {PROTOCOL_LANMAN1,"LANMAN1.0"},
  275.       {PROTOCOL_LANMAN2,"LM1.2X002"},
  276.       {PROTOCOL_LANMAN2,"Samba"},
  277.       {PROTOCOL_NT1,"NT LM 0.12"},
  278.       {PROTOCOL_NT1,"NT LANMAN 1.0"},
  279.       {-1,NULL}
  280.     };
  281.  
  282. /****************************************************************************
  283. send a login command
  284. ****************************************************************************/
  285. BOOL cli_send_login(char *inbuf, char *outbuf, BOOL start_session, BOOL use_setup)
  286. {
  287.   BOOL was_null = (!inbuf && !outbuf);
  288.   int sesskey=0;
  289.   time_t servertime = 0;
  290.   extern int serverzone;
  291.   int sec_mode=0;
  292.   int crypt_len;
  293.   int max_vcs=0;
  294.   char *pass = NULL;  
  295.   pstring dev;
  296.   char *p;
  297.   int numprots;
  298.  
  299.   if (was_null)
  300.     {
  301.       inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
  302.       outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
  303.     }
  304.  
  305.   strcpy(dev,"A:");
  306.   if (connect_as_printer)
  307.     strcpy(dev,"LPT1:");
  308.   if (connect_as_ipc)
  309.     strcpy(dev,"IPC");
  310.  
  311.  
  312.   if (start_session && !cli_send_session_request(inbuf,outbuf))
  313.     {
  314.       if (was_null)
  315.     {
  316.       free(inbuf);
  317.       free(outbuf);
  318.     }      
  319.       return(False);
  320.     }
  321.  
  322.   bzero(outbuf,smb_size);
  323.  
  324.   /* setup the protocol strings */
  325.   {
  326.     int plength;
  327.  
  328.     for (plength=0,numprots=0;
  329.      prots[numprots].name && prots[numprots].prot<=max_protocol;
  330.      numprots++)
  331.       plength += strlen(prots[numprots].name)+2;
  332.     
  333.     set_message(outbuf,0,plength,True);
  334.  
  335.     p = smb_buf(outbuf);
  336.     for (numprots=0;
  337.      prots[numprots].name && prots[numprots].prot<=max_protocol;
  338.      numprots++)
  339.       {
  340.     *p++ = 2;
  341.     strcpy(p,prots[numprots].name);
  342.     p += strlen(p) + 1;
  343.       }
  344.   }
  345.  
  346.   CVAL(outbuf,smb_com) = SMBnegprot;
  347.   cli_setup_pkt(outbuf);
  348.  
  349.   CVAL(smb_buf(outbuf),0) = 2;
  350.  
  351.   send_smb(Client,outbuf);
  352.   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
  353.  
  354.   show_msg(inbuf);
  355.  
  356.   if (CVAL(inbuf,smb_rcls) != 0 || ((int)SVAL(inbuf,smb_vwv0) >= numprots))
  357.     {
  358.       DEBUG(0,("SMBnegprot failed. myname=%s destname=%s - %s \n",
  359.         myname,desthost,smb_errstr(inbuf)));
  360.       if (was_null)
  361.     {
  362.       free(inbuf);
  363.       free(outbuf);
  364.     }
  365.       return(False);
  366.     }
  367.  
  368.   Protocol = prots[SVAL(inbuf,smb_vwv0)].prot;
  369.  
  370.  
  371.   if (Protocol < PROTOCOL_NT1) {    
  372.     sec_mode = SVAL(inbuf,smb_vwv1);
  373.     max_xmit = SVAL(inbuf,smb_vwv2);
  374.     sesskey = IVAL(inbuf,smb_vwv6);
  375.     serverzone = SVALS(inbuf,smb_vwv10)*60;
  376.     /* this time is converted to GMT by make_unix_date */
  377.     servertime = make_unix_date(inbuf+smb_vwv8);
  378.     if (Protocol >= PROTOCOL_COREPLUS) {
  379.       readbraw_supported = ((SVAL(inbuf,smb_vwv5) & 0x1) != 0);
  380.       writebraw_supported = ((SVAL(inbuf,smb_vwv5) & 0x2) != 0);
  381.     }
  382.     crypt_len = smb_buflen(inbuf);
  383.     memcpy(cryptkey,smb_buf(inbuf),8);
  384.     DEBUG(5,("max mux %d\n",SVAL(inbuf,smb_vwv3)));
  385.     max_vcs = SVAL(inbuf,smb_vwv4); 
  386.     DEBUG(5,("max vcs %d\n",max_vcs)); 
  387.     DEBUG(5,("max blk %d\n",SVAL(inbuf,smb_vwv5)));
  388.   } else {
  389.     /* NT protocol */
  390.     sec_mode = CVAL(inbuf,smb_vwv1);
  391.     max_xmit = IVAL(inbuf,smb_vwv3+1);
  392.     sesskey = IVAL(inbuf,smb_vwv7+1);
  393.     serverzone = SVALS(inbuf,smb_vwv15+1)*60;
  394.     /* this time arrives in real GMT */
  395.     servertime = interpret_long_date(inbuf+smb_vwv11+1);
  396.     crypt_len = CVAL(inbuf,smb_vwv16+1);
  397.     memcpy(cryptkey,smb_buf(inbuf),8);
  398.     if (IVAL(inbuf,smb_vwv9+1) & 1)
  399.       readbraw_supported = writebraw_supported = True;      
  400.     DEBUG(5,("max mux %d\n",SVAL(inbuf,smb_vwv1+1)));
  401.     max_vcs = SVAL(inbuf,smb_vwv2+1); 
  402.     DEBUG(5,("max vcs %d\n",max_vcs));
  403.     DEBUG(5,("max raw %d\n",IVAL(inbuf,smb_vwv5+1)));
  404.     DEBUG(5,("capabilities 0x%x\n",IVAL(inbuf,smb_vwv9+1)));
  405.   }
  406.  
  407.   DEBUG(5,("Sec mode %d\n",SVAL(inbuf,smb_vwv1)));
  408.   DEBUG(5,("max xmt %d\n",max_xmit));
  409.   DEBUG(5,("Got %d byte crypt key\n",crypt_len));
  410.   DEBUG(5,("Chose protocol [%s]\n",prots[SVAL(inbuf,smb_vwv0)].name));
  411.  
  412.   doencrypt = ((sec_mode & 2) != 0);
  413.  
  414.   if (servertime) {
  415.     static BOOL done_time = False;
  416.     if (!done_time) {
  417.       DEBUG(1,("Server time is %sTimezone is UTC%+02.1f\n",
  418.            asctime(LocalTime(&servertime)),
  419.            -(double)(serverzone/3600.0)));
  420.       done_time = True;
  421.     }
  422.   }
  423.  
  424.  get_pass:
  425.  
  426.   if (got_pass)
  427.     pass = password;
  428.   else
  429.     pass = (char *)getpass("Password: ");
  430.  
  431.   if (Protocol >= PROTOCOL_LANMAN1 && use_setup)
  432.     {
  433.       fstring pword;
  434.       int passlen = strlen(pass)+1;
  435.       strcpy(pword,pass);      
  436.  
  437. #ifdef SMB_PASSWD
  438.       if (doencrypt && *pass) {
  439.     DEBUG(5,("Using encrypted passwords\n"));
  440.     passlen = 24;
  441.     SMBencrypt((uchar *)pass,(uchar *)cryptkey,(uchar *)pword);
  442.       }
  443. #else
  444.       doencrypt = False;
  445. #endif
  446.  
  447.       /* if in share level security then don't send a password now */
  448.       if (!(sec_mode & 1)) {strcpy(pword, "");passlen=1;} 
  449.  
  450.       /* send a session setup command */
  451.       bzero(outbuf,smb_size);
  452.  
  453.       if (Protocol < PROTOCOL_NT1) {
  454.     set_message(outbuf,10,1 + strlen(username) + passlen,True);
  455.     CVAL(outbuf,smb_com) = SMBsesssetupX;
  456.     cli_setup_pkt(outbuf);
  457.  
  458.     CVAL(outbuf,smb_vwv0) = 0xFF;
  459.     SSVAL(outbuf,smb_vwv2,max_xmit);
  460.     SSVAL(outbuf,smb_vwv3,2);
  461.     SSVAL(outbuf,smb_vwv4,max_vcs-1);
  462.     SIVAL(outbuf,smb_vwv5,sesskey);
  463.     SSVAL(outbuf,smb_vwv7,passlen);
  464.     p = smb_buf(outbuf);
  465.     memcpy(p,pword,passlen);
  466.     p += passlen;
  467.     strcpy(p,username);
  468.       } else {
  469.     if (!doencrypt) passlen--;
  470.     /* for Win95 */
  471.     set_message(outbuf,13,0,True);
  472.     CVAL(outbuf,smb_com) = SMBsesssetupX;
  473.     cli_setup_pkt(outbuf);
  474.  
  475.     CVAL(outbuf,smb_vwv0) = 0xFF;
  476.     SSVAL(outbuf,smb_vwv2,BUFFER_SIZE);
  477.     SSVAL(outbuf,smb_vwv3,2);
  478.     SSVAL(outbuf,smb_vwv4,getpid());
  479.     SIVAL(outbuf,smb_vwv5,sesskey);
  480.     SSVAL(outbuf,smb_vwv7,passlen);
  481.     SSVAL(outbuf,smb_vwv8,0);
  482.     p = smb_buf(outbuf);
  483.     memcpy(p,pword,passlen); p += SVAL(outbuf,smb_vwv7);
  484.     strcpy(p,username);p = skip_string(p,1);
  485.     strcpy(p,workgroup);p = skip_string(p,1);
  486.     strcpy(p,"Unix");p = skip_string(p,1);
  487.     strcpy(p,"Samba");p = skip_string(p,1);
  488.     set_message(outbuf,13,PTR_DIFF(p,smb_buf(outbuf)),False);
  489.       }
  490.  
  491.       send_smb(Client,outbuf);
  492.       receive_smb(Client,inbuf,CLIENT_TIMEOUT);
  493.  
  494.       show_msg(inbuf);
  495.  
  496.       if (CVAL(inbuf,smb_rcls) != 0)
  497.     {
  498.       if (! *pass &&
  499.           ((CVAL(inbuf,smb_rcls) == ERRDOS && 
  500.         SVAL(inbuf,smb_err) == ERRnoaccess) ||
  501.            (CVAL(inbuf,smb_rcls) == ERRSRV && 
  502.         SVAL(inbuf,smb_err) == ERRbadpw)))
  503.         {
  504.           got_pass = False;
  505.           DEBUG(5,("resending login\n"));
  506.           goto get_pass;
  507.         }
  508.           
  509.       DEBUG(0,("Session setup failed for username=%s myname=%s destname=%s   %s\n",
  510.         username,myname,desthost,smb_errstr(inbuf)));
  511.       DEBUG(0,("You might find the -U or -n options useful\n"));
  512.       DEBUG(0,("Sometimes you have to use `-n USERNAME' (particularly with OS/2)\n"));
  513.       DEBUG(0,("Some servers also insist on uppercase-only passwords\n"));
  514.       if (was_null)
  515.         {
  516.           free(inbuf);
  517.           free(outbuf);
  518.         }
  519.       return(False);
  520.     }
  521.  
  522.       if (Protocol >= PROTOCOL_NT1) {
  523.     char *domain,*os,*lanman;
  524.     p = smb_buf(inbuf);
  525.     os = p;
  526.     lanman = skip_string(os,1);
  527.     domain = skip_string(lanman,1);
  528.     if (*domain || *os || *lanman)
  529.       DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",domain,os,lanman));
  530.       }
  531.  
  532.       /* use the returned uid from now on */
  533.       if (SVAL(inbuf,smb_uid) != uid)
  534.     DEBUG(5,("Server gave us a UID of %d. We gave %d\n",
  535.           SVAL(inbuf,smb_uid),uid));
  536.       uid = SVAL(inbuf,smb_uid);
  537.     }
  538.  
  539.   /* now we've got a connection - send a tcon message */
  540.   bzero(outbuf,smb_size);
  541.  
  542.   if (strncmp(service,"\\\\",2) != 0)
  543.     {
  544.       DEBUG(0,("\nWarning: Your service name doesn't start with \\\\. This is probably incorrect.\n"));
  545.       DEBUG(0,("Perhaps try replacing each \\ with \\\\ on the command line?\n\n"));
  546.     }
  547.  
  548.  
  549.  again2:
  550.  
  551.   {
  552.     int passlen = strlen(pass)+1;
  553.     fstring pword;
  554.     strcpy(pword,pass);
  555.  
  556. #ifdef SMB_PASSWD
  557.     if (doencrypt && *pass) {
  558.       passlen=24;
  559.       SMBencrypt((uchar *)pass,(uchar *)cryptkey,(uchar *)pword);      
  560.     }
  561. #endif
  562.  
  563.     /* if in user level security then don't send a password now */
  564.     if ((sec_mode & 1)) {
  565.       strcpy(pword, ""); passlen=1; 
  566.     }
  567.  
  568.     set_message(outbuf,4,2 + strlen(service) + passlen + strlen(dev),True);
  569.     CVAL(outbuf,smb_com) = SMBtconX;
  570.     cli_setup_pkt(outbuf);
  571.  
  572.     SSVAL(outbuf,smb_vwv0,0xFF);
  573.     SSVAL(outbuf,smb_vwv3,passlen);
  574.  
  575.     p = smb_buf(outbuf);
  576.     memcpy(p,pword,passlen);
  577.     p += passlen;
  578.     strcpy(p,service);
  579.     p = skip_string(p,1);
  580.     strcpy(p,dev);
  581.   }
  582.  
  583.   send_smb(Client,outbuf);
  584.   receive_smb(Client,inbuf,CLIENT_TIMEOUT);
  585.  
  586.   /* trying again with a blank password */
  587.   if (CVAL(inbuf,smb_rcls) != 0 && 
  588.       (int)strlen(pass) > 0 && 
  589.       !doencrypt &&
  590.       Protocol >= PROTOCOL_LANMAN1)
  591.     {
  592.       DEBUG(2,("first SMBtconX failed, trying again. %s\n",smb_errstr(inbuf)));
  593.       strcpy(pass,"");
  594.       goto again2;
  595.     }  
  596.  
  597.   if (CVAL(inbuf,smb_rcls) != 0)
  598.     {
  599.       DEBUG(0,("SMBtconX failed. %s\n",smb_errstr(inbuf)));
  600.       DEBUG(0,("Perhaps you are using the wrong sharename, username or password?\n"));
  601.       DEBUG(0,("Some servers insist that these be in uppercase\n"));
  602.       if (was_null)
  603.     {
  604.       free(inbuf);
  605.       free(outbuf);
  606.     }
  607.       return(False);
  608.     }
  609.   
  610.  
  611.   max_xmit = MIN(max_xmit,BUFFER_SIZE-4);
  612.   if (max_xmit <= 0)
  613.     max_xmit = BUFFER_SIZE - 4;
  614.  
  615.   cnum = SVAL(inbuf,smb_tid);
  616.  
  617.   DEBUG(5,("Connected with cnum=%d max_xmit=%d\n",cnum,max_xmit));
  618.  
  619.   if (was_null)
  620.     {
  621.       free(inbuf);
  622.       free(outbuf);
  623.     }
  624.   return True;
  625. }
  626.  
  627.  
  628. /****************************************************************************
  629. send a logout command
  630. ****************************************************************************/
  631. void cli_send_logout(void)
  632. {
  633.   pstring inbuf,outbuf;
  634.  
  635.   bzero(outbuf,smb_size);
  636.   set_message(outbuf,0,0,True);
  637.   CVAL(outbuf,smb_com) = SMBtdis;
  638.   SSVAL(outbuf,smb_tid,cnum);
  639.   cli_setup_pkt(outbuf);
  640.  
  641.   send_smb(Client,outbuf);
  642.   receive_smb(Client,inbuf,SHORT_TIMEOUT);
  643.  
  644.   if (CVAL(inbuf,smb_rcls) != 0)
  645.     {
  646.       DEBUG(0,("SMBtdis failed %s\n",smb_errstr(inbuf)));
  647.     }
  648.  
  649.   
  650. #ifdef STATS
  651.   stats_report();
  652. #endif
  653.   exit(0);
  654. }
  655.  
  656.  
  657.  
  658. /****************************************************************************
  659. call a remote api
  660. ****************************************************************************/
  661. BOOL cli_call_api(int prcnt,int drcnt,int mprcnt,int mdrcnt,int *rprcnt,
  662.           int *rdrcnt, char *param,char *data, char **rparam,char **rdata)
  663. {
  664.   static char *inbuf=NULL;
  665.   static char *outbuf=NULL;
  666.  
  667.   if (!inbuf) inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
  668.   if (!outbuf) outbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
  669.  
  670.   cli_send_trans_request(outbuf,SMBtrans,"\\PIPE\\LANMAN",0,0,
  671.              data,param,NULL,
  672.              drcnt,prcnt,0,
  673.              mdrcnt,mprcnt,0);
  674.  
  675.   return (cli_receive_trans_response(inbuf,SMBtrans,
  676.                      rdrcnt,rprcnt,
  677.                      rdata,rparam));
  678. }
  679.  
  680. /****************************************************************************
  681.   send a SMB trans or trans2 request
  682.   ****************************************************************************/
  683. BOOL cli_send_trans_request(char *outbuf, int trans, char *name, int fid, int flags,
  684.             char *data,char *param,uint16 *setup, int ldata,int lparam,
  685.             int lsetup,int mdata,int mparam,int msetup)
  686. {
  687.   int i;
  688.   int this_ldata,this_lparam;
  689.   int tot_data=0,tot_param=0;
  690.   char *outdata,*outparam;
  691.   pstring inbuf;
  692.   char *p;
  693.  
  694.   this_lparam = MIN(lparam,max_xmit - (500+lsetup*SIZEOFWORD)); /* hack */
  695.   this_ldata = MIN(ldata,max_xmit - (500+lsetup*SIZEOFWORD+this_lparam));
  696.  
  697.   bzero(outbuf,smb_size);
  698.   set_message(outbuf,14+lsetup,0,True);
  699.   CVAL(outbuf,smb_com) = trans;
  700.   SSVAL(outbuf,smb_tid,cnum);
  701.   cli_setup_pkt(outbuf);
  702.  
  703.   outparam = smb_buf(outbuf)+(trans==SMBtrans ? strlen(name)+1 : 3);
  704.   outdata = outparam+this_lparam;
  705.  
  706.   /* primary request */
  707.   SSVAL(outbuf,smb_tpscnt,lparam);    /* tpscnt */
  708.   SSVAL(outbuf,smb_tdscnt,ldata);    /* tdscnt */
  709.   SSVAL(outbuf,smb_mprcnt,mparam);    /* mprcnt */
  710.   SSVAL(outbuf,smb_mdrcnt,mdata);    /* mdrcnt */
  711.   SCVAL(outbuf,smb_msrcnt,msetup);    /* msrcnt */
  712.   SSVAL(outbuf,smb_flags,flags);    /* flags */
  713.   SIVAL(outbuf,smb_timeout,0);        /* timeout */
  714.   SSVAL(outbuf,smb_pscnt,this_lparam);    /* pscnt */
  715.   SSVAL(outbuf,smb_psoff,smb_offset(outparam,outbuf)); /* psoff */
  716.   SSVAL(outbuf,smb_dscnt,this_ldata);    /* dscnt */
  717.   SSVAL(outbuf,smb_dsoff,smb_offset(outdata,outbuf)); /* dsoff */
  718.   SCVAL(outbuf,smb_suwcnt,lsetup);    /* suwcnt */
  719.   for (i=0;i<lsetup;i++)        /* setup[] */
  720.     SSVAL(outbuf,smb_setup+i*SIZEOFWORD,setup[i]);
  721.   p = smb_buf(outbuf);
  722.   if (trans==SMBtrans)
  723.     strcpy(p,name);            /* name[] */
  724.   else
  725.     {
  726.       *p++ = 0;                /* put in a null smb_name */
  727.       *p++ = 'D'; *p++ = ' ';        /* this was added because OS/2 does it */
  728.     }
  729.   if (this_lparam)            /* param[] */
  730.     memcpy(outparam,param,this_lparam);
  731.   if (this_ldata)            /* data[] */
  732.     memcpy(outdata,data,this_ldata);
  733.   set_message(outbuf,14+lsetup,        /* wcnt, bcc */
  734.           PTR_DIFF(outdata+this_ldata,smb_buf(outbuf)),False);
  735.  
  736.   show_msg(outbuf);
  737.   send_smb(Client,outbuf);
  738.  
  739.   if (this_ldata < ldata || this_lparam < lparam)
  740.     {
  741.       /* receive interim response */
  742.       if (!receive_smb(Client,inbuf,SHORT_TIMEOUT) || CVAL(inbuf,smb_rcls) != 0)
  743.     {
  744.       DEBUG(0,("%s request failed (%s)\n",
  745.                trans==SMBtrans?"SMBtrans":"SMBtrans2", smb_errstr(inbuf)));
  746.       return(False);
  747.     }      
  748.  
  749.       tot_data = this_ldata;
  750.       tot_param = this_lparam;
  751.  
  752.       while (tot_data < ldata || tot_param < lparam)
  753.     {
  754.       this_lparam = MIN(lparam-tot_param,max_xmit - 500); /* hack */
  755.       this_ldata = MIN(ldata-tot_data,max_xmit - (500+this_lparam));
  756.  
  757.       set_message(outbuf,trans==SMBtrans?8:9,0,True);
  758.       CVAL(outbuf,smb_com) = trans==SMBtrans ? SMBtranss : SMBtranss2;
  759.  
  760.       outparam = smb_buf(outbuf);
  761.       outdata = outparam+this_lparam;
  762.  
  763.       /* secondary request */
  764.       SSVAL(outbuf,smb_tpscnt,lparam);    /* tpscnt */
  765.       SSVAL(outbuf,smb_tdscnt,ldata);    /* tdscnt */
  766.       SSVAL(outbuf,smb_spscnt,this_lparam);    /* pscnt */
  767.       SSVAL(outbuf,smb_spsoff,smb_offset(outparam,outbuf)); /* psoff */
  768.       SSVAL(outbuf,smb_spsdisp,tot_param);    /* psdisp */
  769.       SSVAL(outbuf,smb_sdscnt,this_ldata);    /* dscnt */
  770.       SSVAL(outbuf,smb_sdsoff,smb_offset(outdata,outbuf)); /* dsoff */
  771.       SSVAL(outbuf,smb_sdsdisp,tot_data);    /* dsdisp */
  772.       if (trans==SMBtrans2)
  773.         SSVAL(outbuf,smb_sfid,fid);        /* fid */
  774.       if (this_lparam)            /* param[] */
  775.         memcpy(outparam,param,this_lparam);
  776.       if (this_ldata)            /* data[] */
  777.         memcpy(outdata,data,this_ldata);
  778.       set_message(outbuf,trans==SMBtrans?8:9, /* wcnt, bcc */
  779.               PTR_DIFF(outdata+this_ldata,smb_buf(outbuf)),False);
  780.  
  781.       show_msg(outbuf);
  782.       send_smb(Client,outbuf);
  783.  
  784.       tot_data += this_ldata;
  785.       tot_param += this_lparam;
  786.     }
  787.     }
  788.  
  789.     return(True);
  790. }
  791.  
  792.  
  793. /****************************************************************************
  794. open the client sockets
  795. ****************************************************************************/
  796. BOOL cli_open_sockets(int port)
  797. {
  798.   static int last_port;
  799.   char *host;
  800.   pstring service2;
  801.   extern int Client;
  802.  
  803.   if (port == 0) port=last_port;
  804.   last_port=port;
  805.  
  806.   strupper(service);
  807.  
  808.   if (*desthost)
  809.     {
  810.       host = desthost;
  811.     }
  812.   else
  813.     {
  814.       strcpy(service2,service);
  815.       host = strtok(service2,"\\/");
  816.       strcpy(desthost,host);
  817.     }
  818.  
  819.   DEBUG(5,("Opening sockets\n"));
  820.  
  821.   if (*myname == 0)
  822.     get_myname(myname,NULL);
  823.   strupper(myname);
  824.  
  825.   if (!have_ip)
  826.     {
  827.       struct hostent *hp;
  828.  
  829.       if ((hp = Get_Hostbyname(host)) == 0) 
  830.     {
  831.       DEBUG(0,("Get_Hostbyname: Unknown host %s.\n",host));
  832.       return False;
  833.     }
  834.  
  835.       putip((char *)&dest_ip,(char *)hp->h_addr);
  836.     }
  837.  
  838.   Client = open_socket_out(SOCK_STREAM, &dest_ip, port, SHORT_CONNECT_TIMEOUT);
  839.   if (Client == -1)
  840.     return False;
  841.  
  842.   DEBUG(5,("Connected\n"));
  843.  
  844.   set_socket_options(Client,user_socket_options);  
  845.  
  846.   return True;
  847. }
  848.  
  849. /****************************************************************************
  850. close and open the connection again
  851. ****************************************************************************/
  852. BOOL cli_reopen_connection(char *inbuf,char *outbuf)
  853. {
  854.   static int open_count=0;
  855.  
  856.   open_count++;
  857.  
  858.   if (open_count>5) return(False);
  859.  
  860.   DEBUG(1,("Trying to re-open connection\n"));
  861.  
  862.   set_message(outbuf,0,0,True);
  863.   SCVAL(outbuf,smb_com,SMBtdis);
  864.   SSVAL(outbuf,smb_tid,cnum);
  865.   cli_setup_pkt(outbuf);
  866.  
  867.   send_smb(Client,outbuf);
  868.   receive_smb(Client,inbuf,SHORT_TIMEOUT);
  869.  
  870.   close_sockets();
  871.   if (!cli_open_sockets(0)) return(False);
  872.  
  873.   return(cli_send_login(inbuf,outbuf,True,True));
  874. }
  875.  
  876. /* error code stuff - put together by Merik Karman
  877.    merik@blackadder.dsh.oz.au */
  878.  
  879. typedef struct
  880. {
  881.   char *name;
  882.   int code;
  883.   char *message;
  884. } err_code_struct;
  885.  
  886. /* Dos Error Messages */
  887. err_code_struct dos_msgs[] = {
  888.   {"ERRbadfunc",1,"Invalid function."},
  889.   {"ERRbadfile",2,"File not found."},
  890.   {"ERRbadpath",3,"Directory invalid."},
  891.   {"ERRnofids",4,"No file descriptors available"},
  892.   {"ERRnoaccess",5,"Access denied."},
  893.   {"ERRbadfid",6,"Invalid file handle."},
  894.   {"ERRbadmcb",7,"Memory control blocks destroyed."},
  895.   {"ERRnomem",8,"Insufficient server memory to perform the requested function."},
  896.   {"ERRbadmem",9,"Invalid memory block address."},
  897.   {"ERRbadenv",10,"Invalid environment."},
  898.   {"ERRbadformat",11,"Invalid format."},
  899.   {"ERRbadaccess",12,"Invalid open mode."},
  900.   {"ERRbaddata",13,"Invalid data."},
  901.   {"ERR",14,"reserved."},
  902.   {"ERRbaddrive",15,"Invalid drive specified."},
  903.   {"ERRremcd",16,"A Delete Directory request attempted  to  remove  the  server's  current directory."},
  904.   {"ERRdiffdevice",17,"Not same device."},
  905.   {"ERRnofiles",18,"A File Search command can find no more files matching the specified criteria."},
  906.   {"ERRbadshare",32,"The sharing mode specified for an Open conflicts with existing  FIDs  on the file."},
  907.   {"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."},
  908.   {"ERRfilexists",80,"The file named in a Create Directory, Make  New  File  or  Link  request already exists."},
  909.   {"ERRbadpipe",230,"Pipe invalid."},
  910.   {"ERRpipebusy",231,"All instances of the requested pipe are busy."},
  911.   {"ERRpipeclosing",232,"Pipe close in progress."},
  912.   {"ERRnotconnected",233,"No process on other end of pipe."},
  913.   {"ERRmoredata",234,"There is more data to be returned."},
  914.   {NULL,-1,NULL}};
  915.  
  916. /* Server Error Messages */
  917. err_code_struct server_msgs[] = {
  918.   {"ERRerror",1,"Non-specific error code."},
  919.   {"ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."},
  920.   {"ERRbadtype",3,"reserved."},
  921.   {"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."},
  922.   {"ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."},
  923.   {"ERRinvnetname",6,"Invalid network name in tree connect."},
  924.   {"ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or  non-printer request made to printer connection."},
  925.   {"ERRqfull",49,"Print queue full (files) -- returned by open print file."},
  926.   {"ERRqtoobig",50,"Print queue full -- no space."},
  927.   {"ERRqeof",51,"EOF on print queue dump."},
  928.   {"ERRinvpfid",52,"Invalid print file FID."},
  929.   {"ERRsmbcmd",64,"The server did not recognize the command received."},
  930.   {"ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."},
  931.   {"ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid  combination of values."},
  932.   {"ERRreserved",68,"reserved."},
  933.   {"ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination.  The server cannot set the requested attribute."},
  934.   {"ERRreserved",70,"reserved."},
  935.   {"ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."},
  936.   {"ERRpaused",81,"Server is paused."},
  937.   {"ERRmsgoff",82,"Not receiving messages."},
  938.   {"ERRnoroom",83,"No room to buffer message."},
  939.   {"ERRrmuns",87,"Too many remote user names."},
  940.   {"ERRtimeout",88,"Operation timed out."},
  941.   {"ERRnoresource",89,"No resources currently available for request."},
  942.   {"ERRtoomanyuids",90,"Too many UIDs active on this session."},
  943.   {"ERRbaduid",91,"The UID is not known as a valid ID on this session."},
  944.   {"ERRusempx",250,"Temp unable to support Raw, use MPX mode."},
  945.   {"ERRusestd",251,"Temp unable to support Raw, use standard read/write."},
  946.   {"ERRcontmpx",252,"Continue in MPX mode."},
  947.   {"ERRreserved",253,"reserved."},
  948.   {"ERRreserved",254,"reserved."},
  949.   {"ERRnosupport",0xFFFF,"Function not supported."},
  950.   {NULL,-1,NULL}};
  951.  
  952. /* Hard Error Messages */
  953. err_code_struct hard_msgs[] = {
  954.   {"ERRnowrite",19,"Attempt to write on write-protected diskette."},
  955.   {"ERRbadunit",20,"Unknown unit."},
  956.   {"ERRnotready",21,"Drive not ready."},
  957.   {"ERRbadcmd",22,"Unknown command."},
  958.   {"ERRdata",23,"Data error (CRC)."},
  959.   {"ERRbadreq",24,"Bad request structure length."},
  960.   {"ERRseek",25 ,"Seek error."},
  961.   {"ERRbadmedia",26,"Unknown media type."},
  962.   {"ERRbadsector",27,"Sector not found."},
  963.   {"ERRnopaper",28,"Printer out of paper."},
  964.   {"ERRwrite",29,"Write fault."},
  965.   {"ERRread",30,"Read fault."},
  966.   {"ERRgeneral",31,"General failure."},
  967.   {"ERRbadshare",32,"A open conflicts with an existing open."},
  968.   {"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."},
  969.   {"ERRwrongdisk",34,"The wrong disk was found in a drive."},
  970.   {"ERRFCBUnavail",35,"No FCBs are available to process request."},
  971.   {"ERRsharebufexc",36,"A sharing buffer has been exceeded."},
  972.   {NULL,-1,NULL}};
  973.  
  974.  
  975. struct
  976. {
  977.   int code;
  978.   char *class;
  979.   err_code_struct *err_msgs;
  980. } err_classes[] = { 
  981.   {0,"SUCCESS",NULL},
  982.   {0x01,"ERRDOS",dos_msgs},
  983.   {0x02,"ERRSRV",server_msgs},
  984.   {0x03,"ERRHRD",hard_msgs},
  985.   {0x04,"ERRXOS",NULL},
  986.   {0xE1,"ERRRMX1",NULL},
  987.   {0xE2,"ERRRMX2",NULL},
  988.   {0xE3,"ERRRMX3",NULL},
  989.   {0xFF,"ERRCMD",NULL},
  990.   {-1,NULL,NULL}};
  991.  
  992.  
  993. /****************************************************************************
  994. return a SMB error string from a SMB buffer
  995. ****************************************************************************/
  996. char *smb_errstr(char *inbuf)
  997. {
  998.   static pstring ret;
  999.   int class = CVAL(inbuf,smb_rcls);
  1000.   int num = SVAL(inbuf,smb_err);
  1001.   int i,j;
  1002.  
  1003.   for (i=0;err_classes[i].class;i++)
  1004.     if (err_classes[i].code == class)
  1005.       {
  1006.     if (err_classes[i].err_msgs)
  1007.       {
  1008.         err_code_struct *err = err_classes[i].err_msgs;
  1009.         for (j=0;err[j].name;j++)
  1010.           if (num == err[j].code)
  1011.         {
  1012.           if (DEBUGLEVEL > 0)
  1013.             sprintf(ret,"%s - %s (%s)",err_classes[i].class,
  1014.                 err[j].name,err[j].message);
  1015.           else
  1016.             sprintf(ret,"%s - %s",err_classes[i].class,err[j].name);
  1017.           return ret;
  1018.         }
  1019.       }
  1020.  
  1021.     sprintf(ret,"%s - %d",err_classes[i].class,num);
  1022.     return ret;
  1023.       }
  1024.   
  1025.   sprintf(ret,"ERROR: Unknown error (%d,%d)",class,num);
  1026.   return(ret);
  1027. }
  1028.