r23784: use the GPLv3 boilerplate as recommended by the FSF and the license text
[tprouty/samba.git] / source / client / smbspool.c
index b1c17a26fcd9dd8578a9a7f705feea270d1e62f6..f0c31c550056ba361519df06936f8df41edcf089 100644 (file)
@@ -8,7 +8,7 @@
    
    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
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    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.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 
-#define PW_MAX_BUF_SIZE          sysconf(_SC_GETPW_R_SIZE_MAX)
 #define TICKET_CC_DIR            "/tmp"
 #define CC_PREFIX                "krb5cc_" /* prefix of the ticket cache */
 #define CC_MAX_FILE_LEN          24   
 #define CC_MAX_FILE_PATH_LEN     (sizeof(TICKET_CC_DIR)-1)+ CC_MAX_FILE_LEN+2   
 #define OVERWRITE                1   
 #define KRB5CCNAME               "KRB5CCNAME"
+#define MAX_RETRY_CONNECT        3
 
 
 /*
@@ -47,6 +46,7 @@ static void           list_devices(void);
 static struct cli_state *smb_complete_connection(const char *, const char *,int , const char *, const char *, const char *, const char *, int);
 static struct cli_state        *smb_connect(const char *, const char *, int, const char *, const char *, const char *, const char *);
 static int             smb_print(struct cli_state *, char *, FILE *);
+static char *          uri_unescape_alloc(const char *);
 
 
 /*
@@ -62,14 +62,20 @@ static int          smb_print(struct cli_state *, char *, FILE *);
   int          port;           /* Port number */
   char         uri[1024],      /* URI */
                *sep,           /* Pointer to separator */
+               *tmp, *tmp2,    /* Temp pointers to do escaping */
                *password;      /* Password */
-  const char   *username,      /* Username */
+  char         *username,      /* Username */
                *server,        /* Server name */
                *printer;       /* Printer name */
   const char   *workgroup;     /* Workgroup */
   FILE         *fp;            /* File to print */
   int          status=0;               /* Status of LPD job */
   struct cli_state *cli;       /* SMB interface */
+  char null_str[1];
+  int tries = 0;
+  const char *dev_uri;
+
+  null_str[0] = '\0';
 
   /* we expect the URI in argv[0]. Detect the case where it is in argv[1] and cope */
   if (argc > 2 && strncmp(argv[0],"smb://", 6) && !strncmp(argv[1],"smb://", 6)) {
@@ -128,8 +134,9 @@ static int          smb_print(struct cli_state *, char *, FILE *);
   * Find the URI...
   */
 
-  if (getenv("DEVICE_URI") != NULL)
-    strncpy(uri, getenv("DEVICE_URI"), sizeof(uri) - 1);
+  dev_uri = getenv("DEVICE_URI");
+  if (dev_uri)
+    strncpy(uri, dev_uri, sizeof(uri) - 1);
   else if (strncmp(argv[0], "smb://", 6) == 0)
     strncpy(uri, argv[0], sizeof(uri) - 1);
   else
@@ -146,37 +153,44 @@ static int                smb_print(struct cli_state *, char *, FILE *);
 
   if ((sep = strrchr_m(uri, '@')) != NULL)
   {
-    username = uri + 6;
+    tmp = uri + 6;
     *sep++ = '\0';
 
+    /* username is in tmp */
+
     server = sep;
 
    /*
     * Extract password as needed...
     */
 
-    if ((password = strchr_m(username, ':')) != NULL)
-      *password++ = '\0';
-    else
-      password = "";
+    if ((tmp2 = strchr_m(tmp, ':')) != NULL) {
+      *tmp2++ = '\0';
+      password = uri_unescape_alloc(tmp2);
+    } else {
+      password = null_str;
+    }
+    username = uri_unescape_alloc(tmp);
   }
   else
   {
-    username = "";
-    password = "";
+    username = null_str;
+    password = null_str;
     server   = uri + 6;
   }
 
-  if ((sep = strchr_m(server, '/')) == NULL)
+  tmp = server;
+
+  if ((sep = strchr_m(tmp, '/')) == NULL)
   {
     fputs("ERROR: Bad URI - need printer name!\n", stderr);
     return (1);
   }
 
   *sep++ = '\0';
-  printer = sep;
+  tmp2 = sep;
 
-  if ((sep = strchr_m(printer, '/')) != NULL)
+  if ((sep = strchr_m(tmp2, '/')) != NULL)
   {
    /*
     * Convert to smb://[username:password@]workgroup/server/printer...
@@ -184,12 +198,15 @@ static int                smb_print(struct cli_state *, char *, FILE *);
 
     *sep++ = '\0';
 
-    workgroup = server;
-    server    = printer;
-    printer   = sep;
+    workgroup = uri_unescape_alloc(tmp);
+    server    = uri_unescape_alloc(tmp2);
+    printer   = uri_unescape_alloc(sep);
   }
-  else
+  else {
     workgroup = NULL;
+    server = uri_unescape_alloc(tmp);
+    printer = uri_unescape_alloc(tmp2);
+  }
   
   if ((sep = strrchr_m(server, ':')) != NULL)
   {
@@ -197,7 +214,7 @@ static int          smb_print(struct cli_state *, char *, FILE *);
 
     port=atoi(sep);
   }
-  else
+  else 
        port=0;
        
  
@@ -209,7 +226,9 @@ static int          smb_print(struct cli_state *, char *, FILE *);
 
   in_client = True;   /* Make sure that we tell lp_load we are */
 
-  if (!lp_load(dyn_CONFIGFILE, True, False, False))
+  load_case_tables();
+
+  if (!lp_load(dyn_CONFIGFILE, True, False, False, True))
   {
     fprintf(stderr, "ERROR: Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE);
     return (1);
@@ -226,17 +245,23 @@ static int                smb_print(struct cli_state *, char *, FILE *);
     {
       if (getenv("CLASS") == NULL)
       {
-        fprintf(stderr, "ERROR: Unable to connect to SAMBA host, will retry in 60 seconds...");
-        sleep (60);
+        fprintf(stderr, "ERROR: Unable to connect to CIFS host, will retry in 60 seconds...\n");
+        sleep (60); /* should just waiting and retrying fix authentication  ??? */
+        tries++;
       }
       else
       {
-        fprintf(stderr, "ERROR: Unable to connect to SAMBA host, trying next printer...");
+        fprintf(stderr, "ERROR: Unable to connect to CIFS host, trying next printer...\n");
         return (1);
       }
     }
   }
-  while (cli == NULL);
+  while ((cli == NULL) && (tries < MAX_RETRY_CONNECT));
+
+  if (cli == NULL) {
+        fprintf(stderr, "ERROR: Unable to connect to CIFS host after (tried %d times)\n", tries);
+        return (1);
+  }
 
  /*
   * Now that we are connected to the server, ignore SIGTERM so that we
@@ -288,15 +313,15 @@ list_devices(void)
 static
 char * get_ticket_cache( uid_t uid )
 {
+  char *ticket_file = NULL;
   SMB_STRUCT_DIR *tcdir;                  /* directory where ticket caches are stored */
   SMB_STRUCT_DIRENT *dirent;   /* directory entry */
   char *filename = NULL;       /* holds file names on the tmp directory */
   SMB_STRUCT_STAT buf;        
   char user_cache_prefix[CC_MAX_FILE_LEN];
   char file_path[CC_MAX_FILE_PATH_LEN];
-  char *ticket_file = NULL;
   time_t t = 0;
-  
+
   snprintf(user_cache_prefix, CC_MAX_FILE_LEN, "%s%d", CC_PREFIX, uid );
   tcdir = sys_opendir( TICKET_CC_DIR );
   if ( tcdir == NULL ) 
@@ -364,9 +389,14 @@ static struct cli_state
     return NULL;      
   }
     
-    
+  /* We pretty much guarentee password must be valid or a pointer
+     to a 0 char. */
+  if (!password) {
+    return NULL;
+  }
+  
   if ( (username) && (*username) && 
-      ((!password) || ((password) && (strlen(password) == 0 ))) && 
+      (strlen(password) == 0 ) && 
        (cli->use_kerberos) ) 
   {
     /* Use kerberos authentication */
@@ -410,9 +440,10 @@ static struct cli_state
   }
    
    
-  if (!cli_session_setup(cli, username, password, strlen(password)+1, 
-                         password, strlen(password)+1,
-                         workgroup)) 
+  if (!NT_STATUS_IS_OK(cli_session_setup(cli, username,
+                                        password, strlen(password)+1, 
+                                        password, strlen(password)+1,
+                                        workgroup)))
   {
     fprintf(stderr,"ERROR: Session setup failed: %s\n", cli_errstr(cli));
     if (NT_STATUS_V(cli_nt_error(cli)) == 
@@ -425,10 +456,10 @@ static struct cli_state
     return NULL;
   }
     
-  if (!cli_send_tconX(cli, share, "?????",password, strlen(password)+1)) 
+  if (!cli_send_tconX(cli, share, "?????", password, strlen(password)+1)) 
   {
+    fprintf(stderr, "ERROR: Tree connect failed (%s)\n", cli_errstr(cli));
     cli_shutdown(cli);
-    fprintf(stderr, "ERROR: Tree connect failed\n" );
     return NULL;
   }
     
@@ -450,6 +481,7 @@ smb_connect(const char *workgroup,    /* I - Workgroup */
 {
   struct cli_state  *cli;    /* New connection */
   pstring    myname;    /* Client name */
+  struct passwd *pwd;
 
  /*
   * Get the names and addresses of the client and server...
@@ -457,15 +489,15 @@ smb_connect(const char *workgroup,    /* I - Workgroup */
 
   get_myname(myname);  
 
-  if ( (username) && ( *username ) && (password) && (*password) ) 
+  /* See if we have a username first.  This is for backwards compatible 
+     behavior with 3.0.14a */
+
+  if ( username &&  *username )
   {
-      /* 
-       * User/password specified in the DEVICE_URI, use those credentials 
-       * to connect to the server 
-       */
       cli = smb_complete_connection(myname, server, port, username, 
                                     password, workgroup, share, 0 );
-      if (cli ) { return cli; }
+      if (cli) 
+        return cli;
   }
   
   /* 
@@ -477,12 +509,24 @@ smb_connect(const char *workgroup,    /* I - Workgroup */
 
   if (cli ) { return cli; }
 
+  /* give a chance for a passwordless NTLMSSP session setup */
+
+  pwd = getpwuid(geteuid());
+  if (pwd == NULL) {
+     return NULL;
+  }
+
+  cli = smb_complete_connection(myname, server, port, pwd->pw_name, "", 
+                                workgroup, share, 0);
+
+  if (cli) { return cli; }
+
   /*
    * last try. Use anonymous authentication
    */
+
   cli = smb_complete_connection(myname, server, port, "", "", 
                                 workgroup, share, 0);
-
   /*
    * Return the new connection...
    */
@@ -555,3 +599,14 @@ smb_print(struct cli_state *cli,   /* I - SMB connection */
   else
     return (0);
 }
+
+static char *uri_unescape_alloc(const char *uritok)
+{
+       char *ret;
+
+       ret = (char *)SMB_STRDUP(uritok);
+       if (!ret) return NULL;
+
+       rfc1738_unescape(ret);
+       return ret;
+}