r5896: Fix cifs mounts to handle commas embedded in prompted password, and password...
authorSteve French <sfrench@samba.org>
Sat, 19 Mar 2005 05:00:57 +0000 (05:00 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 15:56:07 +0000 (10:56 -0500)
Fix cifs mounts to handle domain name and user name in username field (in form domain\user)
(This used to be commit d98417b2cfd9f3748eabc9df64cf30b2bd8bc338)

source3/client/mount.cifs.c

index 7b30b98fa7b30d454b4e813131e7cb785cf20253..0ebb52a96bad406e79c6db0e68cb5eb07cb3b269 100755 (executable)
@@ -1,6 +1,6 @@
 /* 
    Mount helper utility for Linux CIFS VFS (virtual filesystem) client
-   Copyright (C) 2003 Steve French  (sfrench@us.ibm.com)
+   Copyright (C) 2003,2005 Steve French  (sfrench@us.ibm.com)
 
    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
@@ -39,7 +39,7 @@
 #include <fcntl.h>
 
 #define MOUNT_CIFS_VERSION_MAJOR "1"
-#define MOUNT_CIFS_VERSION_MINOR "6"
+#define MOUNT_CIFS_VERSION_MINOR "7"
 
 #ifndef MOUNT_CIFS_VENDOR_SUFFIX
 #define MOUNT_CIFS_VENDOR_SUFFIX ""
@@ -60,7 +60,8 @@ static int got_uid = 0;
 static int got_gid = 0;
 static int free_share_name = 0;
 static char * user_name = NULL;
-char * mountpassword = NULL;
+static char * mountpassword = NULL;
+static char * domain_name = NULL;
 
 
 /* BB finish BB
@@ -72,6 +73,9 @@ char * mountpassword = NULL;
                 
 BB end finish BB */
 
+static char * check_for_domain(char **);
+
+
 static void mount_cifs_usage(void)
 {
        printf("\nUsage:  %s <remotetarget> <dir> -o <options>\n", thisprogram);
@@ -107,7 +111,7 @@ static char * getusername(void) {
        return username;
 }
 
-char * parse_cifs_url(char * unc_name)
+static char * parse_cifs_url(char * unc_name)
 {
        printf("\nMounting cifs URL not implemented yet. Attempt to mount %s\n",unc_name);
        return NULL;
@@ -264,7 +268,9 @@ static int parse_options(char * options, int * filesys_flags)
                data = options;
 
        if(verboseflag)
-               printf("\n parsing options: %s", options);
+               printf("parsing options: %s\n", options);
+
+       /* BB fixme check for separator override BB */
 
 /* while ((data = strsep(&options, ",")) != NULL) { */
        while(data != NULL) {
@@ -276,15 +282,12 @@ static int parse_options(char * options, int * filesys_flags)
                /* data  = next keyword */
                /* value = next value ie stuff after equal sign */
 
-               next_keyword = strchr(data,',');
+               next_keyword = strchr(data,','); /* BB handle sep= */
        
                /* temporarily null terminate end of keyword=value pair */
                if(next_keyword)
                        *next_keyword = 0;
 
-               /* if (!*data)
-                       continue; */
-               
                /* temporarily null terminate keyword to make keyword and value distinct */
                if ((value = strchr(data, '=')) != NULL) {
                        *value = '\0';
@@ -298,6 +301,7 @@ static int parse_options(char * options, int * filesys_flags)
                } else if (strncmp(data, "user_xattr",10) == 0) {
                   /* do nothing - need to skip so not parsed as user name */
                } else if (strncmp(data, "user", 4) == 0) {
+
                        if (!value || !*value) {
                                if(data[4] == '\0') {
                                        if(verboseflag)
@@ -308,7 +312,6 @@ static int parse_options(char * options, int * filesys_flags)
                                                data[1] = ',';
                                                data[2] = ',';
                                                data[3] = ',';
-                                       /* BB remove it from mount line so as not to confuse kernel code */
                                } else {
                                        printf("username specified with no parameter\n");
                                        return 1;       /* needs_arg; */
@@ -334,6 +337,13 @@ static int parse_options(char * options, int * filesys_flags)
                                                        }
                                                }
                                        }
+                                       /* this is only case in which the user
+                                       name buf is not malloc - so we have to
+                                       check for domain name embedded within
+                                       the user name here since the later
+                                       call to check_for_domain will not be
+                                       invoked */
+                                       domain_name = check_for_domain(&value);
                                } else {
                                        printf("username too long\n");
                                        return 1;
@@ -516,15 +526,136 @@ static int parse_options(char * options, int * filesys_flags)
        
                /* put previous overwritten comma back */
                if(next_keyword)
-                       *next_keyword = ',';
+                       *next_keyword = ','; /* BB handle sep= */
                else
                        data = NULL;
        }
        return 0;
 }
 
+/* replace all (one or more) commas with double commas */
+static void check_for_comma(char ** ppasswrd)
+{
+       char *new_pass_buf;
+       char *pass;
+       int i,j;
+       int number_of_commas = 0;
+       int len = strlen(*ppasswrd);
+
+       if(ppasswrd == NULL)
+               return;
+       else 
+               (pass = *ppasswrd);
+
+       for(i=0;i<len;i++)  {
+               if(pass[i] == ',')
+                       number_of_commas++;
+       }
+
+       if(number_of_commas == 0)
+               return;
+       if(number_of_commas > 64) {
+               /* would otherwise overflow the mount options buffer */
+               printf("\nInvalid password. Password contains too many commas.\n");
+               return;
+       }
+
+       new_pass_buf = malloc(len+number_of_commas+1);
+       if(new_pass_buf == NULL)
+               return;
+
+       for(i=0,j=0;i<len;i++,j++) {
+               new_pass_buf[j] = pass[i];
+               if(pass[i] == ',') {
+                       j++;
+                       new_pass_buf[j] = pass[i];
+               }
+       }
+       new_pass_buf[len+number_of_commas] = 0;
+
+       free(*ppasswrd);
+       *ppasswrd = new_pass_buf;
+       
+       return;
+}
+
+/* Usernames can not have backslash in them and we use
+   [BB check if usernames can have forward slash in them BB] 
+   backslash as domain\user separator character
+*/
+static char * check_for_domain(char **ppuser)
+{
+       char * original_string;
+       char * usernm;
+       char * domainnm;
+       int    original_len;
+       int    len;
+       int    i;
+
+       if(ppuser == NULL)
+               return NULL;
+
+       original_string = *ppuser;
+
+       if (original_string == NULL)
+               return NULL;
+       
+       original_len = strlen(original_string);
+
+       usernm = strchr(*ppuser,'/');
+       if (usernm == NULL) {
+               usernm = strchr(*ppuser,'\\');
+               if (usernm == NULL)
+                       return NULL;
+       }
+
+       if(got_domain) {
+               printf("Domain name specified twice. Username probably malformed\n");
+               return NULL;
+       }
+
+       usernm[0] = 0;
+       domainnm = *ppuser;
+       if (domainnm[0] != 0) {
+               got_domain = 1;
+       } else {
+               printf("null domain\n");
+       }
+       len = strlen(domainnm);
+       /* reset domainm to new buffer, and copy
+       domain name into it */
+       domainnm = malloc(len+1);
+       if(domainnm == NULL)
+               return NULL;
+
+       strcpy(domainnm,*ppuser);
+
+/*     move_string(*ppuser, usernm+1) */
+       len = strlen(usernm+1);
+       printf("\nlen %d original_len %d\n",len, original_len);
+
+       if(len >= original_len) {
+               /* should not happen */
+               return domainnm;
+       }
+
+       for(i=0;i<original_len;i++) {
+               if(i<len)
+                       original_string[i] = usernm[i+1];
+               else /* stuff with commas to remove last parm */
+                       original_string[i] = ',';
+       }
+
+       /* BB add check for more than one slash? 
+         strchr(*ppuser,'/');
+         strchr(*ppuser,'\\') 
+       */
+       
+       return domainnm;
+}
+
 /* Note that caller frees the returned buffer if necessary */
-char * parse_server(char ** punc_name)
+static char * parse_server(char ** punc_name)
 {
        char * unc_name = *punc_name;
        int length = strnlen(unc_name,1024);
@@ -756,7 +887,7 @@ int main(int argc, char ** argv)
                        user_name = optarg;
                        break;
                case 'd':
-                       domain_name = optarg;
+                       domain_name = optarg; /* BB fix this - currently ignored */
                        break;
                case 'p':
                        if(mountpassword == NULL)
@@ -841,8 +972,10 @@ int main(int argc, char ** argv)
                }
        }
 
-       if(got_user == 0)
+       if(got_user == 0) {
                user_name = getusername();
+               got_user = 1;
+       }
        
        if(got_password == 0) {
                mountpassword = getpass("Password: "); /* BB obsolete */
@@ -864,7 +997,7 @@ mount_retry:
                optlen += strlen(ipaddr) + 4;
        if(mountpassword)
                optlen += strlen(mountpassword) + 6;
-       options = malloc(optlen + 10);
+       options = malloc(optlen + 10 + 64 /* space for commas in password */ + 8 /* space for domain=  , domain name itself was counted as part of the length username string above */);
 
        if(options == NULL) {
                printf("Could not allocate memory for mount options\n");
@@ -882,15 +1015,30 @@ mount_retry:
        if(ipaddr) {
                strncat(options,",ip=",4);
                strcat(options,ipaddr);
-       } 
+       }
+
        if(user_name) {
+               /* check for syntax like user=domain\user */
+               domain_name = check_for_domain(&user_name);
                strncat(options,",user=",6);
                strcat(options,user_name);
        } 
+       if(retry == 0)
+               if(domain_name) { 
+                       /* extra length accounted for in option string above */
+                       strncat(options,",domain=",8);
+                       strcat(options,domain_name);
+               }
        if(mountpassword) {
+               /* Commas have to be doubled, or else they will
+               look like the parameter separator */
+/*             if(sep is not set)*/
+               if(retry == 0)
+                       check_for_comma(&mountpassword);
                strncat(options,",pass=",6);
                strcat(options,mountpassword);
        }
+
        strncat(options,",ver=",5);
        strcat(options,MOUNT_CIFS_VERSION_MAJOR);
 
@@ -978,7 +1126,8 @@ mount_retry:
                }
        }
        if(mountpassword) {
-               memset(mountpassword,0,64);
+               int len = strlen(mountpassword);
+               memset(mountpassword,0,len);
                free(mountpassword);
        }