Fix bug 2319.
authoridra <idra@0c0555d6-39d7-0310-84fc-f1cc0bd64818>
Sat, 16 Jun 2007 18:54:13 +0000 (18:54 +0000)
committeridra <idra@0c0555d6-39d7-0310-84fc-f1cc0bd64818>
Sat, 16 Jun 2007 18:54:13 +0000 (18:54 +0000)
Got report this is all ok form a tester. Close a loong
standing bug preventing people to freely use any character
in their password when printing via cups were involved.

git-svn-id: svn+ssh://svn.samba.org/data/svn/samba/branches/SAMBA_3_0@23524 0c0555d6-39d7-0310-84fc-f1cc0bd64818

source/client/smbspool.c

index 5783cbe..89863cc 100644 (file)
@@ -47,6 +47,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,8 +63,9 @@ 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 */
@@ -152,19 +154,24 @@ 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
+    if ((tmp2 = strchr_m(tmp, ':')) != NULL) {
+      *tmp2++ = '\0';
+      password = uri_unescape_alloc(tmp2);
+    } else {
       password = null_str;
+    }
+    username = uri_unescape_alloc(tmp);
   }
   else
   {
@@ -173,16 +180,18 @@ static int                smb_print(struct cli_state *, char *, FILE *);
     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...
@@ -190,12 +199,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)
   {
@@ -203,7 +215,7 @@ static int          smb_print(struct cli_state *, char *, FILE *);
 
     port=atoi(sep);
   }
-  else
+  else 
        port=0;
        
  
@@ -588,3 +600,38 @@ smb_print(struct cli_state *cli,   /* I - SMB connection */
   else
     return (0);
 }
+
+static char *uri_unescape_alloc(const char *uritok)
+{
+       char *t, *ret;
+       const char *p;
+       long int val;
+       char eval[3];
+
+       ret = (char *)SMB_MALLOC(strlen(uritok)+1);
+
+       if (!ret) return NULL;
+
+       eval[2] = '\0';
+
+       for (p = uritok, t = ret; *p; p++, t++) {
+               if (*p == '%') { /* unescape hex */
+                       p++;
+                       eval[0] = *p;
+                       p++;
+                       eval[1] = *p;
+                       val = strtol(eval, NULL, 16);
+                       if ((val == LONG_MIN || val == LONG_MAX) && errno == ERANGE) {
+                               SAFE_FREE(ret);
+                               return NULL;
+                       }
+                       *t = (char)val;
+               } else {
+                       *t = *p;
+               }
+       }
+
+       *t = '\0'; /*terminate*/
+
+       return ret;
+}