Tidyup to ensure '\n' is treated identically in all
[samba.git] / source / client / mount.cifs.c
old mode 100755 (executable)
new mode 100644 (file)
index 5aa6056..c42375b
@@ -1,10 +1,11 @@
 /* 
    Mount helper utility for Linux CIFS VFS (virtual filesystem) client
 /* 
    Mount helper utility for Linux CIFS VFS (virtual filesystem) client
-   Copyright (C) 2003 Steve French  (sfrench@us.ibm.com)
+   Copyright (C) 2003,2008 Steve French  (sfrench@us.ibm.com)
+   Copyright (C) 2008 Jeremy Allison (jra@samba.org)
 
    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
 
    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,
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
@@ -13,8 +14,7 @@
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    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/>.  */
 
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE
 
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE
@@ -24,6 +24,7 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <pwd.h>
+#include <grp.h>
 #include <ctype.h>
 #include <sys/types.h>
 #include <sys/mount.h>
 #include <ctype.h>
 #include <sys/types.h>
 #include <sys/mount.h>
 #include <string.h>
 #include <mntent.h>
 #include <fcntl.h>
 #include <string.h>
 #include <mntent.h>
 #include <fcntl.h>
+#include <limits.h>
 
 #define MOUNT_CIFS_VERSION_MAJOR "1"
 
 #define MOUNT_CIFS_VERSION_MAJOR "1"
-#define MOUNT_CIFS_VERSION_MINOR "6"
+#define MOUNT_CIFS_VERSION_MINOR "11"
 
 #ifndef MOUNT_CIFS_VENDOR_SUFFIX
 
 #ifndef MOUNT_CIFS_VENDOR_SUFFIX
-#define MOUNT_CIFS_VENDOR_SUFFIX ""
-#endif
+ #ifdef _SAMBA_BUILD_
+  #include "include/version.h"
+  #ifdef SAMBA_VERSION_VENDOR_SUFFIX
+   #define MOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING"-"SAMBA_VERSION_VENDOR_SUFFIX
+  #else
+   #define MOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING
+  #endif /* SAMBA_VERSION_OFFICIAL_STRING and SAMBA_VERSION_VENDOR_SUFFIX */
+ #else
+   #define MOUNT_CIFS_VENDOR_SUFFIX ""
+ #endif /* _SAMBA_BUILD_ */
+#endif /* MOUNT_CIFS_VENDOR_SUFFIX */
 
 #ifndef MS_MOVE 
 #define MS_MOVE 8192 
 #endif 
 
 
 #ifndef MS_MOVE 
 #define MS_MOVE 8192 
 #endif 
 
-char * thisprogram;
+#ifndef MS_BIND
+#define MS_BIND 4096
+#endif
+
+#define MAX_UNC_LEN 1024
+
+#define CONST_DISCARD(type, ptr)      ((type) ((void *) (ptr)))
+
+#ifndef SAFE_FREE
+#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
+#endif
+
+#define MOUNT_PASSWD_SIZE 64
+#define DOMAIN_SIZE 64
+
+const char *thisprogram;
 int verboseflag = 0;
 static int got_password = 0;
 static int got_user = 0;
 int verboseflag = 0;
 static int got_password = 0;
 static int got_user = 0;
@@ -58,10 +84,45 @@ static int got_ip = 0;
 static int got_unc = 0;
 static int got_uid = 0;
 static int got_gid = 0;
 static int got_unc = 0;
 static int got_uid = 0;
 static int got_gid = 0;
-static int free_share_name = 0;
 static char * user_name = NULL;
 static char * user_name = NULL;
-char * mountpassword = NULL;
+static char * mountpassword = NULL;
+char * domain_name = NULL;
+char * prefixpath = NULL;
+
+/* glibc doesn't have strlcpy, strlcat. Ensure we do. JRA. We
+ * don't link to libreplace so need them here. */
+
+/* like strncpy but does not 0 fill the buffer and always null
+ *    terminates. bufsize is the size of the destination buffer */
+size_t strlcpy(char *d, const char *s, size_t bufsize)
+{
+       size_t len = strlen(s);
+       size_t ret = len;
+       if (bufsize <= 0) return 0;
+       if (len >= bufsize) len = bufsize-1;
+       memcpy(d, s, len);
+       d[len] = 0;
+       return ret;
+}
 
 
+/* like strncat but does not 0 fill the buffer and always null
+ *    terminates. bufsize is the length of the buffer, which should
+ *       be one more than the maximum resulting string length */
+size_t strlcat(char *d, const char *s, size_t bufsize)
+{
+       size_t len1 = strlen(d);
+       size_t len2 = strlen(s);
+       size_t ret = len1 + len2;
+
+       if (len1+len2 >= bufsize) {
+               len2 = bufsize - (len1+1);
+       }
+       if (len2 > 0) {
+               memcpy(d+len1, s, len2);
+               d[len1+len2] = 0;
+       }
+       return ret;
+}
 
 /* BB finish BB
 
 
 /* BB finish BB
 
@@ -72,6 +133,9 @@ char * mountpassword = NULL;
                 
 BB end finish BB */
 
                 
 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);
 static void mount_cifs_usage(void)
 {
        printf("\nUsage:  %s <remotetarget> <dir> -o <options>\n", thisprogram);
@@ -79,20 +143,24 @@ static void mount_cifs_usage(void)
        printf(" to a local directory.\n\nOptions:\n");
        printf("\tuser=<arg>\n\tpass=<arg>\n\tdom=<arg>\n");
        printf("\nLess commonly used options:");
        printf(" to a local directory.\n\nOptions:\n");
        printf("\tuser=<arg>\n\tpass=<arg>\n\tdom=<arg>\n");
        printf("\nLess commonly used options:");
-       printf("\n\tcredentials=<filename>,guest,perm,noperm,setuids,nosetuids,\n\trw,ro,sep=<char>,iocharset=<codepage>,suid,nosuid,exec,noexec");
-       printf("\n\nOptions not needed for servers supporting CIFS Unix extensions (e.g. most Samba versions):");
-       printf("\n\tuid=<uid>,gid=<gid>,dir_mode=<mode>,file_mode=<mode>");
+       printf("\n\tcredentials=<filename>,guest,perm,noperm,setuids,nosetuids,rw,ro,");
+       printf("\n\tsep=<char>,iocharset=<codepage>,suid,nosuid,exec,noexec,serverino,");
+       printf("\n\tmapchars,nomapchars,nolock,servernetbiosname=<SRV_RFC1001NAME>");
+       printf("\n\tdirectio,nounix,cifsacl,sec=<authentication mechanism>,sign");
+       printf("\n\nOptions not needed for servers supporting CIFS Unix extensions");
+       printf("\n\t(e.g. unneeded for mounts to most Samba versions):");
+       printf("\n\tuid=<uid>,gid=<gid>,dir_mode=<mode>,file_mode=<mode>,sfu");
        printf("\n\nRarely used options:");
        printf("\n\nRarely used options:");
-       printf("\n\tport=<tcpport>,rsize=<size>,wsize=<size>,unc=<unc_name>,ip=<ip_address>,dev,nodev");
+       printf("\n\tport=<tcpport>,rsize=<size>,wsize=<size>,unc=<unc_name>,ip=<ip_address>,");
+       printf("\n\tdev,nodev,nouser_xattr,netbiosname=<OUR_RFC1001NAME>,hard,soft,intr,");
+       printf("\n\tnointr,ignorecase,noposixpaths,noacl,prefixpath=<path>,nobrl");
+       printf("\n\tin6_addr");
        printf("\n\nOptions are described in more detail in the manual page");
        printf("\n\tman 8 mount.cifs\n");
        printf("\nTo display the version number of the mount helper:");
        printf("\n\t%s -V\n",thisprogram);
 
        printf("\n\nOptions are described in more detail in the manual page");
        printf("\n\tman 8 mount.cifs\n");
        printf("\nTo display the version number of the mount helper:");
        printf("\n\t%s -V\n",thisprogram);
 
-       if(mountpassword) {
-               memset(mountpassword,0,64);
-               free(mountpassword);
-       }
+       SAFE_FREE(mountpassword);
        exit(1);
 }
 
        exit(1);
 }
 
@@ -107,7 +175,7 @@ static char * getusername(void) {
        return username;
 }
 
        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;
 {
        printf("\nMounting cifs URL not implemented yet. Attempt to mount %s\n",unc_name);
        return NULL;
@@ -122,9 +190,11 @@ static int open_cred_file(char * file_name)
        fs = fopen(file_name,"r");
        if(fs == NULL)
                return errno;
        fs = fopen(file_name,"r");
        if(fs == NULL)
                return errno;
-       line_buf = malloc(4096);
-       if(line_buf == NULL)
+       line_buf = (char *)malloc(4096);
+       if(line_buf == NULL) {
+               fclose(fs);
                return -ENOMEM;
                return -ENOMEM;
+       }
 
        while(fgets(line_buf,4096,fs)) {
                /* parse line from credential file */
 
        while(fgets(line_buf,4096,fs)) {
                /* parse line from credential file */
@@ -141,22 +211,22 @@ static int open_cred_file(char * file_name)
                                /* go past equals sign */
                                temp_val++;
                                for(length = 0;length<4087;length++) {
                                /* go past equals sign */
                                temp_val++;
                                for(length = 0;length<4087;length++) {
-                                       if(temp_val[length] == '\n')
+                                       if ((temp_val[length] == '\n')
+                                           || (temp_val[length] == '\0')) {
+                                               temp_val[length] = '\0';
                                                break;
                                                break;
+                                       }
                                }
                                if(length > 4086) {
                                        printf("mount.cifs failed due to malformed username in credentials file");
                                        memset(line_buf,0,4096);
                                }
                                if(length > 4086) {
                                        printf("mount.cifs failed due to malformed username in credentials file");
                                        memset(line_buf,0,4096);
-                                       if(mountpassword) {
-                                               memset(mountpassword,0,64);
-                                       }
                                        exit(1);
                                } else {
                                        got_user = 1;
                                        exit(1);
                                } else {
                                        got_user = 1;
-                                       user_name = calloc(1 + length,1);
+                                       user_name = (char *)calloc(1 + length,1);
                                        /* BB adding free of user_name string before exit,
                                                not really necessary but would be cleaner */
                                        /* BB adding free of user_name string before exit,
                                                not really necessary but would be cleaner */
-                                       strncpy(user_name,temp_val, length);
+                                       strlcpy(user_name,temp_val, length+1);
                                }
                        }
                } else if (strncasecmp("password",line_buf+i,8) == 0) {
                                }
                        }
                } else if (strncasecmp("password",line_buf+i,8) == 0) {
@@ -164,36 +234,61 @@ static int open_cred_file(char * file_name)
                        if(temp_val) {
                                /* go past equals sign */
                                temp_val++;
                        if(temp_val) {
                                /* go past equals sign */
                                temp_val++;
-                               for(length = 0;length<65;length++) {
-                                       if(temp_val[length] == '\n')
+                               for(length = 0;length<MOUNT_PASSWD_SIZE+1;length++) {
+                                       if ((temp_val[length] == '\n')
+                                           || (temp_val[length] == '\0')) {
+                                               temp_val[length] = '\0';
                                                break;
                                                break;
+                                       }
                                }
                                }
-                               if(length > 64) {
+                               if(length > MOUNT_PASSWD_SIZE) {
                                        printf("mount.cifs failed: password in credentials file too long\n");
                                        memset(line_buf,0, 4096);
                                        printf("mount.cifs failed: password in credentials file too long\n");
                                        memset(line_buf,0, 4096);
-                                       if(mountpassword) {
-                                               memset(mountpassword,0,64);
-                                       }
                                        exit(1);
                                } else {
                                        if(mountpassword == NULL) {
                                        exit(1);
                                } else {
                                        if(mountpassword == NULL) {
-                                               mountpassword = calloc(65,1);
+                                               mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
                                        } else
                                        } else
-                                               memset(mountpassword,0,64);
+                                               memset(mountpassword,0,MOUNT_PASSWD_SIZE);
                                        if(mountpassword) {
                                        if(mountpassword) {
-                                               /* BB add handling for commas in password here */
-                                               strncpy(mountpassword,temp_val,length);
+                                               strlcpy(mountpassword,temp_val,MOUNT_PASSWD_SIZE+1);
                                                got_password = 1;
                                        }
                                }
                        }
                                                got_password = 1;
                                        }
                                }
                        }
-               }
+                } else if (strncasecmp("domain",line_buf+i,6) == 0) {
+                        temp_val = strchr(line_buf+i,'=');
+                        if(temp_val) {
+                                /* go past equals sign */
+                                temp_val++;
+                               if(verboseflag)
+                                       printf("\nDomain %s\n",temp_val);
+                                for(length = 0;length<DOMAIN_SIZE+1;length++) {
+                                       if ((temp_val[length] == '\n')
+                                           || (temp_val[length] == '\0')) {
+                                               temp_val[length] = '\0';
+                                               break;
+                                       }
+                                }
+                                if(length > DOMAIN_SIZE) {
+                                        printf("mount.cifs failed: domain in credentials file too long\n");
+                                        exit(1);
+                                } else {
+                                        if(domain_name == NULL) {
+                                                domain_name = (char *)calloc(DOMAIN_SIZE+1,1);
+                                        } else
+                                                memset(domain_name,0,DOMAIN_SIZE);
+                                        if(domain_name) {
+                                                strlcpy(domain_name,temp_val,DOMAIN_SIZE+1);
+                                                got_domain = 1;
+                                        }
+                                }
+                        }
+                }
+
        }
        fclose(fs);
        }
        fclose(fs);
-       if(line_buf) {
-               memset(line_buf,0,4096);
-               free(line_buf);
-       }
+       SAFE_FREE(line_buf);
        return 0;
 }
 
        return 0;
 }
 
@@ -204,9 +299,14 @@ static int get_password_from_file(int file_descript, char * filename)
        char c;
 
        if(mountpassword == NULL)
        char c;
 
        if(mountpassword == NULL)
-               mountpassword = calloc(65,1);
+               mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
        else 
        else 
-               memset(mountpassword, 0, 64);
+               memset(mountpassword, 0, MOUNT_PASSWD_SIZE);
+
+       if (mountpassword == NULL) {
+               printf("malloc failed\n");
+               exit(1);
+       }
 
        if(filename != NULL) {
                file_descript = open(filename, O_RDONLY);
 
        if(filename != NULL) {
                file_descript = open(filename, O_RDONLY);
@@ -218,11 +318,10 @@ static int get_password_from_file(int file_descript, char * filename)
        }
        /* else file already open and fd provided */
 
        }
        /* else file already open and fd provided */
 
-       for(i=0;i<64;i++) {
+       for(i=0;i<MOUNT_PASSWD_SIZE;i++) {
                rc = read(file_descript,&c,1);
                if(rc < 0) {
                        printf("mount.cifs failed. Error %s reading password file\n",strerror(errno));
                rc = read(file_descript,&c,1);
                if(rc < 0) {
                        printf("mount.cifs failed. Error %s reading password file\n",strerror(errno));
-                       memset(mountpassword,0,64);
                        if(filename != NULL)
                                close(file_descript);
                        exit(1);
                        if(filename != NULL)
                                close(file_descript);
                        exit(1);
@@ -234,13 +333,15 @@ static int get_password_from_file(int file_descript, char * filename)
                        break;
                } else /* read valid character */ {
                        if((c == 0) || (c == '\n')) {
                        break;
                } else /* read valid character */ {
                        if((c == 0) || (c == '\n')) {
+                               mountpassword[i] = '\0';
                                break;
                        } else 
                                mountpassword[i] = c;
                }
        }
                                break;
                        } else 
                                mountpassword[i] = c;
                }
        }
-       if((i == 64) && (verboseflag)) {
-               printf("\nWarning: password longer than 64 characters specified in cifs password file");
+       if((i == MOUNT_PASSWD_SIZE) && (verboseflag)) {
+               printf("\nWarning: password longer than %d characters specified in cifs password file",
+                       MOUNT_PASSWD_SIZE);
        }
        got_password = 1;
        if(filename != NULL) {
        }
        got_password = 1;
        if(filename != NULL) {
@@ -250,21 +351,34 @@ static int get_password_from_file(int file_descript, char * filename)
        return rc;
 }
 
        return rc;
 }
 
-static int parse_options(char * options, int * filesys_flags)
+static int parse_options(char ** optionsp, int * filesys_flags)
 {
 {
-       char * data;
+       const char * data;
        char * percent_char = NULL;
        char * value = NULL;
        char * next_keyword = NULL;
        char * percent_char = NULL;
        char * value = NULL;
        char * next_keyword = NULL;
+       char * out = NULL;
+       int out_len = 0;
+       int word_len;
        int rc = 0;
        int rc = 0;
+       char user[32];
+       char group[32];
 
 
-       if (!options)
+       if (!optionsp || !*optionsp)
                return 1;
                return 1;
-       else
-               data = options;
+       data = *optionsp;
 
        if(verboseflag)
 
        if(verboseflag)
-               printf("\n parsing options: %s", options);
+               printf("parsing options: %s\n", data);
+
+       /* BB fixme check for separator override BB */
+
+       if (getuid()) {
+               got_uid = 1;
+               snprintf(user,sizeof(user),"%u",getuid());
+               got_gid = 1;
+               snprintf(group,sizeof(group),"%u",getgid());
+       }
 
 /* while ((data = strsep(&options, ",")) != NULL) { */
        while(data != NULL) {
 
 /* while ((data = strsep(&options, ",")) != NULL) { */
        while(data != NULL) {
@@ -276,15 +390,12 @@ static int parse_options(char * options, int * filesys_flags)
                /* data  = next keyword */
                /* value = next value ie stuff after equal sign */
 
                /* 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)
        
                /* temporarily null terminate end of keyword=value pair */
                if(next_keyword)
-                       *next_keyword = 0;
+                       *next_keyword++ = 0;
 
 
-               /* if (!*data)
-                       continue; */
-               
                /* temporarily null terminate keyword to make keyword and value distinct */
                if ((value = strchr(data, '=')) != NULL) {
                        *value = '\0';
                /* temporarily null terminate keyword to make keyword and value distinct */
                if ((value = strchr(data, '=')) != NULL) {
                        *value = '\0';
@@ -293,20 +404,19 @@ static int parse_options(char * options, int * filesys_flags)
 
                if (strncmp(data, "users",5) == 0) {
                        if(!value || !*value) {
 
                if (strncmp(data, "users",5) == 0) {
                        if(!value || !*value) {
-                               strncpy(data,",,,,,",5);
+                               goto nocopy;
                        }
                        }
+               } 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) {
                } else if (strncmp(data, "user", 4) == 0) {
+
                        if (!value || !*value) {
                                if(data[4] == '\0') {
                                        if(verboseflag)
                                                printf("\nskipping empty user mount parameter\n");
                                        /* remove the parm since it would otherwise be confusing
                                        to the kernel code which would think it was a real username */
                        if (!value || !*value) {
                                if(data[4] == '\0') {
                                        if(verboseflag)
                                                printf("\nskipping empty user mount parameter\n");
                                        /* remove the parm since it would otherwise be confusing
                                        to the kernel code which would think it was a real username */
-                                               data[0] = ',';
-                                               data[1] = ',';
-                                               data[2] = ',';
-                                               data[3] = ',';
-                                       /* BB remove it from mount line so as not to confuse kernel code */
+                                       goto nocopy;
                                } else {
                                        printf("username specified with no parameter\n");
                                        return 1;       /* needs_arg; */
                                } else {
                                        printf("username specified with no parameter\n");
                                        return 1;       /* needs_arg; */
@@ -318,13 +428,13 @@ static int parse_options(char * options, int * filesys_flags)
                                        if(percent_char) {
                                                *percent_char = ',';
                                                if(mountpassword == NULL)
                                        if(percent_char) {
                                                *percent_char = ',';
                                                if(mountpassword == NULL)
-                                                       mountpassword = calloc(65,1);
+                                                       mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
                                                if(mountpassword) {
                                                        if(got_password)
                                                                printf("\nmount.cifs warning - password specified twice\n");
                                                        got_password = 1;
                                                        percent_char++;
                                                if(mountpassword) {
                                                        if(got_password)
                                                                printf("\nmount.cifs warning - password specified twice\n");
                                                        got_password = 1;
                                                        percent_char++;
-                                                       strncpy(mountpassword, percent_char,64);
+                                                       strlcpy(mountpassword, percent_char,MOUNT_PASSWD_SIZE+1);
                                                /*  remove password from username */
                                                        while(*percent_char != 0) {
                                                                *percent_char = ',';
                                                /*  remove password from username */
                                                        while(*percent_char != 0) {
                                                                *percent_char = ',';
@@ -332,6 +442,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;
                                } else {
                                        printf("username too long\n");
                                        return 1;
@@ -351,6 +468,11 @@ static int parse_options(char * options, int * filesys_flags)
                                printf("password too long\n");
                                return 1;
                        }
                                printf("password too long\n");
                                return 1;
                        }
+               } else if (strncmp(data, "sec", 3) == 0) {
+                       if (value) {
+                               if (!strcmp(value, "none"))
+                                       got_password = 1;
+                       }
                } else if (strncmp(data, "ip", 2) == 0) {
                        if (!value || !*value) {
                                printf("target ip address argument missing");
                } else if (strncmp(data, "ip", 2) == 0) {
                        if (!value || !*value) {
                                printf("target ip address argument missing");
@@ -398,7 +520,7 @@ static int parse_options(char * options, int * filesys_flags)
                                printf("CIFS: invalid domain name\n");
                                return 1;       /* needs_arg; */
                        }
                                printf("CIFS: invalid domain name\n");
                                return 1;       /* needs_arg; */
                        }
-                       if (strnlen(value, 65) < 65) {
+                       if (strnlen(value, DOMAIN_SIZE+1) < DOMAIN_SIZE+1) {
                                got_domain = 1;
                        } else {
                                printf("domain name too long\n");
                                got_domain = 1;
                        } else {
                                printf("domain name too long\n");
@@ -418,11 +540,35 @@ static int parse_options(char * options, int * filesys_flags)
                } else if (strncmp(data, "uid", 3) == 0) {
                        if (value && *value) {
                                got_uid = 1;
                } else if (strncmp(data, "uid", 3) == 0) {
                        if (value && *value) {
                                got_uid = 1;
+                               if (!isdigit(*value)) {
+                                       struct passwd *pw;
+
+                                       if (!(pw = getpwnam(value))) {
+                                               printf("bad user name \"%s\"\n", value);
+                                               exit(1);
+                                       }
+                                       snprintf(user, sizeof(user), "%u", pw->pw_uid);
+                               } else {
+                                       strlcpy(user,value,sizeof(user));
+                               }
                        }
                        }
+                       goto nocopy;
                } else if (strncmp(data, "gid", 3) == 0) {
                        if (value && *value) {
                                got_gid = 1;
                } else if (strncmp(data, "gid", 3) == 0) {
                        if (value && *value) {
                                got_gid = 1;
+                               if (!isdigit(*value)) {
+                                       struct group *gr;
+
+                                       if (!(gr = getgrnam(value))) {
+                                               printf("bad group name \"%s\"\n", value);
+                                               exit(1);
+                                       }
+                                       snprintf(group, sizeof(group), "%u", gr->gr_gid);
+                               } else {
+                                       strlcpy(group,value,sizeof(group));
+                               }
                        }
                        }
+                       goto nocopy;
        /* fmask and dmask synonyms for people used to smbfs syntax */
                } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
                        if (!value || !*value) {
        /* fmask and dmask synonyms for people used to smbfs syntax */
                } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
                        if (!value || !*value) {
@@ -464,6 +610,9 @@ static int parse_options(char * options, int * filesys_flags)
                        *filesys_flags &= ~MS_NOSUID;
                } else if (strncmp(data, "nodev", 5) == 0) {
                        *filesys_flags |= MS_NODEV;
                        *filesys_flags &= ~MS_NOSUID;
                } else if (strncmp(data, "nodev", 5) == 0) {
                        *filesys_flags |= MS_NODEV;
+               } else if ((strncmp(data, "nobrl", 5) == 0) || 
+                          (strncmp(data, "nolock", 6) == 0)) {
+                       *filesys_flags &= ~MS_MANDLOCK;
                } else if (strncmp(data, "dev", 3) == 0) {
                        *filesys_flags &= ~MS_NODEV;
                } else if (strncmp(data, "noexec", 6) == 0) {
                } else if (strncmp(data, "dev", 3) == 0) {
                        *filesys_flags &= ~MS_NODEV;
                } else if (strncmp(data, "noexec", 6) == 0) {
@@ -472,16 +621,12 @@ static int parse_options(char * options, int * filesys_flags)
                        *filesys_flags &= ~MS_NOEXEC;
                } else if (strncmp(data, "guest", 5) == 0) {
                        got_password=1;
                        *filesys_flags &= ~MS_NOEXEC;
                } else if (strncmp(data, "guest", 5) == 0) {
                        got_password=1;
-                        /* remove the parm since it would otherwise be logged by kern */
-                       data[0] = ',';
-                        data[1] = ',';
-                        data[2] = ',';
-                       data[3] = ',';
-                       data[4] = ',';
                } else if (strncmp(data, "ro", 2) == 0) {
                        *filesys_flags |= MS_RDONLY;
                } else if (strncmp(data, "rw", 2) == 0) {
                        *filesys_flags &= ~MS_RDONLY;
                } else if (strncmp(data, "ro", 2) == 0) {
                        *filesys_flags |= MS_RDONLY;
                } else if (strncmp(data, "rw", 2) == 0) {
                        *filesys_flags &= ~MS_RDONLY;
+                } else if (strncmp(data, "remount", 7) == 0) {
+                        *filesys_flags |= MS_REMOUNT;
                } /* else if (strnicmp(data, "port", 4) == 0) {
                        if (value && *value) {
                                vol->port =
                } /* else if (strnicmp(data, "port", 4) == 0) {
                        if (value && *value) {
                                vol->port =
@@ -503,36 +648,218 @@ static int parse_options(char * options, int * filesys_flags)
                } */ /* nothing to do on those four mount options above.
                        Just pass to kernel and ignore them here */
 
                } */ /* nothing to do on those four mount options above.
                        Just pass to kernel and ignore them here */
 
-                       /* move to next option */
-               data = next_keyword+1;
+               /* Copy (possibly modified) option to out */
+               word_len = strlen(data);
+               if (value)
+                       word_len += 1 + strlen(value);
 
 
-               /* put overwritten equals sign back */
-               if(value) {
-                       value--;
-                       *value = '=';
+               out = (char *)realloc(out, out_len + word_len + 2);
+               if (out == NULL) {
+                       perror("malloc");
+                       exit(1);
                }
                }
-       
-               /* put previous overwritten comma back */
-               if(next_keyword)
-                       *next_keyword = ',';
+
+               if (out_len) {
+                       strlcat(out, ",", out_len + word_len + 2);
+                       out_len++;
+               }
+
+               if (value)
+                       snprintf(out + out_len, word_len + 1, "%s=%s", data, value);
                else
                else
-                       data = NULL;
+                       snprintf(out + out_len, word_len + 1, "%s", data);
+               out_len = strlen(out);
+
+nocopy:
+               data = next_keyword;
+       }
+
+       /* special-case the uid and gid */
+       if (got_uid) {
+               word_len = strlen(user);
+
+               out = (char *)realloc(out, out_len + word_len + 6);
+               if (out == NULL) {
+                       perror("malloc");
+                       exit(1);
+               }
+
+               if (out_len) {
+                       strlcat(out, ",", out_len + word_len + 6);
+                       out_len++;
+               }
+               snprintf(out + out_len, word_len + 5, "uid=%s", user);
+               out_len = strlen(out);
+       }
+       if (got_gid) {
+               word_len = strlen(group);
+
+               out = (char *)realloc(out, out_len + 1 + word_len + 6);
+               if (out == NULL) {
+               perror("malloc");
+                       exit(1);
+               }
+
+               if (out_len) {
+                       strlcat(out, ",", out_len + word_len + 6);
+                       out_len++;
+               }
+               snprintf(out + out_len, word_len + 5, "gid=%s", group);
+               out_len = strlen(out);
        }
        }
+
+       SAFE_FREE(*optionsp);
+       *optionsp = out;
        return 0;
 }
 
        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;
+
+       if(ppasswrd == NULL)
+               return;
+       else 
+               (pass = *ppasswrd);
+
+       len = strlen(pass);
+
+       for(i=0;i<len;i++)  {
+               if(pass[i] == ',')
+                       number_of_commas++;
+       }
+
+       if(number_of_commas == 0)
+               return;
+       if(number_of_commas > MOUNT_PASSWD_SIZE) {
+               /* would otherwise overflow the mount options buffer */
+               printf("\nInvalid password. Password contains too many commas.\n");
+               return;
+       }
+
+       new_pass_buf = (char *)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;
+
+       SAFE_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 = (char *)malloc(len+1);
+       if(domainnm == NULL)
+               return NULL;
+
+       strlcpy(domainnm,*ppuser,len+1);
+
+/*     move_string(*ppuser, usernm+1) */
+       len = strlen(usernm+1);
+
+       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;
+}
+
+/* replace all occurances of "from" in a string with "to" */
+static void replace_char(char *string, char from, char to, int maxlen)
+{
+       char *lastchar = string + maxlen;
+       while (string) {
+               string = strchr(string, from);
+               if (string) {
+                       *string = to;
+                       if (string >= lastchar)
+                               return;
+               }
+       }
+}
+
 /* Note that caller frees the returned buffer if necessary */
 /* 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;
 {
        char * unc_name = *punc_name;
-       int length = strnlen(unc_name,1024);
+       int length = strnlen(unc_name, MAX_UNC_LEN);
        char * share;
        char * ipaddress_string = NULL;
        char * share;
        char * ipaddress_string = NULL;
-       struct hostent * host_entry;
+       struct hostent * host_entry = NULL;
        struct in_addr server_ipaddr;
        struct in_addr server_ipaddr;
-       int rc;
 
 
-       if(length > 1023) {
+       if(length > (MAX_UNC_LEN - 1)) {
                printf("mount error: UNC name too long");
                return NULL;
        }
                printf("mount error: UNC name too long");
                return NULL;
        }
@@ -544,17 +871,23 @@ char * parse_server(char ** punc_name)
 
        if(length < 3) {
                /* BB add code to find DFS root here */
 
        if(length < 3) {
                /* BB add code to find DFS root here */
-               printf("\nMounting the DFS root for domain not implemented yet");
+               printf("\nMounting the DFS root for domain not implemented yet\n");
                return NULL;
        } else {
                if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
                        /* check for nfs syntax ie server:share */
                        share = strchr(unc_name,':');
                        if(share) {
                return NULL;
        } else {
                if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
                        /* check for nfs syntax ie server:share */
                        share = strchr(unc_name,':');
                        if(share) {
-                               free_share_name = 1;
-                               *punc_name = malloc(length+3);
+                               *punc_name = (char *)malloc(length+3);
+                               if(*punc_name == NULL) {
+                                       /* put the original string back  if 
+                                          no memory left */
+                                       *punc_name = unc_name;
+                                       return NULL;
+                               }
                                *share = '/';
                                *share = '/';
-                               strncpy((*punc_name)+2,unc_name,length);
+                               strlcpy((*punc_name)+2,unc_name,length+1);
+                               SAFE_FREE(unc_name);
                                unc_name = *punc_name;
                                unc_name[length+2] = 0;
                                goto continue_unc_parsing;
                                unc_name = *punc_name;
                                unc_name[length+2] = 0;
                                goto continue_unc_parsing;
@@ -568,22 +901,29 @@ continue_unc_parsing:
                        unc_name[0] = '/';
                        unc_name[1] = '/';
                        unc_name += 2;
                        unc_name[0] = '/';
                        unc_name[1] = '/';
                        unc_name += 2;
-                       if ((share = strchr(unc_name, '/')) || 
-                               (share = strchr(unc_name,'\\'))) {
+
+                       /* allow for either delimiter between host and sharename */
+                       if ((share = strpbrk(unc_name, "/\\"))) {
                                *share = 0;  /* temporarily terminate the string */
                                share += 1;
                                if(got_ip == 0) {
                                        host_entry = gethostbyname(unc_name);
                                }
                                *share = 0;  /* temporarily terminate the string */
                                share += 1;
                                if(got_ip == 0) {
                                        host_entry = gethostbyname(unc_name);
                                }
-                               *(share - 1) = '/'; /* put the slash back */
+                               *(share - 1) = '/'; /* put delimiter back */
+
+                               /* we don't convert the prefixpath delimiters since '\\' is a valid char in posix paths */
+                               if ((prefixpath = strpbrk(share, "/\\"))) {
+                                       *prefixpath = 0;  /* permanently terminate the string */
+                                       if (!strlen(++prefixpath))
+                                               prefixpath = NULL; /* this needs to be done explicitly */
+                               }
                                if(got_ip) {
                                        if(verboseflag)
                                                printf("ip address specified explicitly\n");
                                        return NULL;
                                }
                                if(host_entry == NULL) {
                                if(got_ip) {
                                        if(verboseflag)
                                                printf("ip address specified explicitly\n");
                                        return NULL;
                                }
                                if(host_entry == NULL) {
-                                       printf("mount error: could not find target server. TCP name %s not found ", unc_name);
-                                       printf(" rc = %d\n",rc);
+                                       printf("mount error: could not find target server. TCP name %s not found\n", unc_name);
                                        return NULL;
                                } else {
                                        /* BB should we pass an alternate version of the share name as Unicode */
                                        return NULL;
                                } else {
                                        /* BB should we pass an alternate version of the share name as Unicode */
@@ -637,19 +977,38 @@ static struct option longopts[] = {
        { NULL, 0, NULL, 0 }
 };
 
        { NULL, 0, NULL, 0 }
 };
 
+/* convert a string to uppercase. return false if the string
+ * wasn't ASCII or was a NULL ptr */
+static int
+uppercase_string(char *string)
+{
+       if (!string)
+               return 0;
+
+       while (*string) {
+               /* check for unicode */
+               if ((unsigned char) string[0] & 0x80)
+                       return 0;
+               *string = toupper((unsigned char) *string);
+               string++;
+       }
+
+       return 1;
+}
+
 int main(int argc, char ** argv)
 {
        int c;
        int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
        char * orgoptions = NULL;
        char * share_name = NULL;
 int main(int argc, char ** argv)
 {
        int c;
        int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
        char * orgoptions = NULL;
        char * share_name = NULL;
-       char * domain_name = NULL;
        char * ipaddr = NULL;
        char * uuid = NULL;
        char * ipaddr = NULL;
        char * uuid = NULL;
-       char * mountpoint;
-       char * options;
-       char * resolved_path;
+       char * mountpoint = NULL;
+       char * options = NULL;
+       char * resolved_path = NULL;
        char * temp;
        char * temp;
+       char * dev_name;
        int rc;
        int rsize = 0;
        int wsize = 0;
        int rc;
        int rsize = 0;
        int wsize = 0;
@@ -658,6 +1017,7 @@ int main(int argc, char ** argv)
        int gid = 0;
        int optlen = 0;
        int orgoptlen = 0;
        int gid = 0;
        int optlen = 0;
        int orgoptlen = 0;
+       size_t options_size = 0;
        int retry = 0; /* set when we have to retry mount with uppercase */
        struct stat statbuf;
        struct utsname sysinfo;
        int retry = 0; /* set when we have to retry mount with uppercase */
        struct stat statbuf;
        struct utsname sysinfo;
@@ -670,7 +1030,11 @@ int main(int argc, char ** argv)
 
        if(argc && argv) {
                thisprogram = argv[0];
 
        if(argc && argv) {
                thisprogram = argv[0];
+       } else {
+               mount_cifs_usage();
+               exit(1);
        }
        }
+
        if(thisprogram == NULL)
                thisprogram = "mount.cifs";
 
        if(thisprogram == NULL)
                thisprogram = "mount.cifs";
 
@@ -680,9 +1044,18 @@ int main(int argc, char ** argv)
 /* #ifdef _GNU_SOURCE
        printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
 #endif */
 /* #ifdef _GNU_SOURCE
        printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
 #endif */
-
-       share_name = argv[1];
-       mountpoint = argv[2];
+       if(argc > 2) {
+               dev_name = argv[1];
+               share_name = strndup(argv[1], MAX_UNC_LEN);
+               if (share_name == NULL) {
+                       fprintf(stderr, "%s: %s", argv[0], strerror(ENOMEM));
+                       exit(1);
+               }
+               mountpoint = argv[2];
+       } else {
+               mount_cifs_usage();
+               exit(1);
+       }
 
        /* add sharename in opts string as unc= parm */
 
 
        /* add sharename in opts string as unc= parm */
 
@@ -708,10 +1081,20 @@ int main(int argc, char ** argv)
                    ++nomtab;
                    break;
                case 'b':
                    ++nomtab;
                    break;
                case 'b':
+#ifdef MS_BIND
                        flags |= MS_BIND;
                        flags |= MS_BIND;
+#else
+                       fprintf(stderr,
+                               "option 'b' (MS_BIND) not supported\n");
+#endif
                        break;
                case 'm':
                        break;
                case 'm':
+#ifdef MS_MOVE               
                        flags |= MS_MOVE;
                        flags |= MS_MOVE;
+#else
+                       fprintf(stderr,
+                               "option 'm' (MS_MOVE) not supported\n");
+#endif
                        break;
                case 'o':
                        orgoptions = strdup(optarg);
                        break;
                case 'o':
                        orgoptions = strdup(optarg);
@@ -730,9 +1113,6 @@ int main(int argc, char ** argv)
                        MOUNT_CIFS_VERSION_MAJOR,
                        MOUNT_CIFS_VERSION_MINOR,
                        MOUNT_CIFS_VENDOR_SUFFIX);
                        MOUNT_CIFS_VERSION_MAJOR,
                        MOUNT_CIFS_VERSION_MINOR,
                        MOUNT_CIFS_VENDOR_SUFFIX);
-                       if(mountpassword) {
-                               memset(mountpassword,0,64);
-                       }
                        exit (0);
                case 'w':
                        flags &= ~MS_RDONLY;
                        exit (0);
                case 'w':
                        flags &= ~MS_RDONLY;
@@ -744,24 +1124,59 @@ int main(int argc, char ** argv)
                        wsize = atoi(optarg);
                        break;
                case '1':
                        wsize = atoi(optarg);
                        break;
                case '1':
-                       uid = atoi(optarg);
+                       if (isdigit(*optarg)) {
+                               char *ep;
+
+                               uid = strtoul(optarg, &ep, 10);
+                               if (*ep) {
+                                       printf("bad uid value \"%s\"\n", optarg);
+                                       exit(1);
+                               }
+                       } else {
+                               struct passwd *pw;
+
+                               if (!(pw = getpwnam(optarg))) {
+                                       printf("bad user name \"%s\"\n", optarg);
+                                       exit(1);
+                               }
+                               uid = pw->pw_uid;
+                               endpwent();
+                       }
                        break;
                case '2':
                        break;
                case '2':
-                       gid = atoi(optarg);
+                       if (isdigit(*optarg)) {
+                               char *ep;
+
+                               gid = strtoul(optarg, &ep, 10);
+                               if (*ep) {
+                                       printf("bad gid value \"%s\"\n", optarg);
+                                       exit(1);
+                               }
+                       } else {
+                               struct group *gr;
+
+                               if (!(gr = getgrnam(optarg))) {
+                                       printf("bad user name \"%s\"\n", optarg);
+                                       exit(1);
+                               }
+                               gid = gr->gr_gid;
+                               endpwent();
+                       }
                        break;
                case 'u':
                        got_user = 1;
                        user_name = optarg;
                        break;
                case 'd':
                        break;
                case 'u':
                        got_user = 1;
                        user_name = optarg;
                        break;
                case 'd':
-                       domain_name = optarg;
+                       domain_name = optarg; /* BB fix this - currently ignored */
+                       got_domain = 1;
                        break;
                case 'p':
                        if(mountpassword == NULL)
                        break;
                case 'p':
                        if(mountpassword == NULL)
-                               mountpassword = calloc(65,1);
+                               mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
                        if(mountpassword) {
                                got_password = 1;
                        if(mountpassword) {
                                got_password = 1;
-                               strncpy(mountpassword,optarg,64);
+                               strlcpy(mountpassword,optarg,MOUNT_PASSWD_SIZE+1);
                        }
                        break;
                case 'S':
                        }
                        break;
                case 'S':
@@ -776,14 +1191,16 @@ int main(int argc, char ** argv)
                }
        }
 
                }
        }
 
-       if(argc < 3)
+       if((argc < 3) || (dev_name == NULL) || (mountpoint == NULL)) {
                mount_cifs_usage();
                mount_cifs_usage();
+               exit(1);
+       }
 
        if (getenv("PASSWD")) {
                if(mountpassword == NULL)
 
        if (getenv("PASSWD")) {
                if(mountpassword == NULL)
-                       mountpassword = calloc(65,1);
+                       mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
                if(mountpassword) {
                if(mountpassword) {
-                       strncpy(mountpassword,getenv("PASSWD"),64);
+                       strlcpy(mountpassword,getenv("PASSWD"),MOUNT_PASSWD_SIZE+1);
                        got_password = 1;
                }
        } else if (getenv("PASSWD_FD")) {
                        got_password = 1;
                }
        } else if (getenv("PASSWD_FD")) {
@@ -792,18 +1209,19 @@ int main(int argc, char ** argv)
                get_password_from_file(0, getenv("PASSWD_FILE"));
        }
 
                get_password_from_file(0, getenv("PASSWD_FILE"));
        }
 
-        if (orgoptions && parse_options(orgoptions, &flags))
-                return -1;
-       
+        if (orgoptions && parse_options(&orgoptions, &flags)) {
+                rc = -1;
+               goto mount_exit;
+       }
        ipaddr = parse_server(&share_name);
        if((ipaddr == NULL) && (got_ip == 0)) {
                printf("No ip address specified and hostname not found\n");
        ipaddr = parse_server(&share_name);
        if((ipaddr == NULL) && (got_ip == 0)) {
                printf("No ip address specified and hostname not found\n");
-               return -1;
+               rc = -1;
+               goto mount_exit;
        }
        
        }
        
-
        /* BB save off path and pop after mount returns? */
        /* BB save off path and pop after mount returns? */
-       resolved_path = malloc(PATH_MAX+1);
+       resolved_path = (char *)malloc(PATH_MAX+1);
        if(resolved_path) {
                /* Note that if we can not canonicalize the name, we get
                another chance to see if it is valid when we chdir to it */
        if(resolved_path) {
                /* Note that if we can not canonicalize the name, we get
                another chance to see if it is valid when we chdir to it */
@@ -813,17 +1231,20 @@ int main(int argc, char ** argv)
        }
        if(chdir(mountpoint)) {
                printf("mount error: can not change directory into mount target %s\n",mountpoint);
        }
        if(chdir(mountpoint)) {
                printf("mount error: can not change directory into mount target %s\n",mountpoint);
-               return -1;
+               rc = -1;
+               goto mount_exit;
        }
 
        if(stat (".", &statbuf)) {
                printf("mount error: mount point %s does not exist\n",mountpoint);
        }
 
        if(stat (".", &statbuf)) {
                printf("mount error: mount point %s does not exist\n",mountpoint);
-               return -1;
+               rc = -1;
+               goto mount_exit;
        }
 
        if (S_ISDIR(statbuf.st_mode) == 0) {
                printf("mount error: mount point %s is not a directory\n",mountpoint);
        }
 
        if (S_ISDIR(statbuf.st_mode) == 0) {
                printf("mount error: mount point %s is not a directory\n",mountpoint);
-               return -1;
+               rc = -1;
+               goto mount_exit;
        }
 
        if((getuid() != 0) && (geteuid() == 0)) {
        }
 
        if((getuid() != 0) && (geteuid() == 0)) {
@@ -839,11 +1260,20 @@ int main(int argc, char ** argv)
                }
        }
 
                }
        }
 
-       if(got_user == 0)
+       if(got_user == 0) {
                user_name = getusername();
                user_name = getusername();
+               got_user = 1;
+       }
        
        if(got_password == 0) {
        
        if(got_password == 0) {
-               mountpassword = getpass("Password: "); /* BB obsolete */
+               char *tmp_pass = getpass("Password: "); /* BB obsolete sys call but
+                                                          no good replacement yet. */
+               mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
+               if (!tmp_pass || !mountpassword) {
+                       printf("Password not entered, exiting\n");
+                       return -1;
+               }
+               strlcpy(mountpassword, tmp_pass, MOUNT_PASSWD_SIZE+1);
                got_password = 1;
        }
        /* FIXME launch daemon (handles dfs name resolution and credential change) 
                got_password = 1;
        }
        /* FIXME launch daemon (handles dfs name resolution and credential change) 
@@ -856,52 +1286,81 @@ mount_retry:
                optlen = 0;
        if(share_name)
                optlen += strlen(share_name) + 4;
                optlen = 0;
        if(share_name)
                optlen += strlen(share_name) + 4;
+       else {
+               printf("No server share name specified\n");
+               printf("\nMounting the DFS root for server not implemented yet\n");
+                exit(1);
+       }
        if(user_name)
                optlen += strlen(user_name) + 6;
        if(ipaddr)
                optlen += strlen(ipaddr) + 4;
        if(mountpassword)
                optlen += strlen(mountpassword) + 6;
        if(user_name)
                optlen += strlen(user_name) + 6;
        if(ipaddr)
                optlen += strlen(ipaddr) + 4;
        if(mountpassword)
                optlen += strlen(mountpassword) + 6;
-       options = malloc(optlen + 10);
+       SAFE_FREE(options);
+       options_size = optlen + 10 + DOMAIN_SIZE;
+       options = (char *)malloc(options_size /* 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");
                return -1;
        }
 
        if(options == NULL) {
                printf("Could not allocate memory for mount options\n");
                return -1;
        }
-               
 
        options[0] = 0;
 
        options[0] = 0;
-       strncat(options,"unc=",4);
-       strcat(options,share_name);
+       strlcpy(options,"unc=",options_size);
+       strlcat(options,share_name,options_size);
        /* scan backwards and reverse direction of slash */
        temp = strrchr(options, '/');
        if(temp > options + 6)
                *temp = '\\';
        if(ipaddr) {
        /* scan backwards and reverse direction of slash */
        temp = strrchr(options, '/');
        if(temp > options + 6)
                *temp = '\\';
        if(ipaddr) {
-               strncat(options,",ip=",4);
-               strcat(options,ipaddr);
-       } 
+               strlcat(options,",ip=",options_size);
+               strlcat(options,ipaddr,options_size);
+       }
+
        if(user_name) {
        if(user_name) {
-               strncat(options,",user=",6);
-               strcat(options,user_name);
-       } 
+               /* check for syntax like user=domain\user */
+               if(got_domain == 0)
+                       domain_name = check_for_domain(&user_name);
+               strlcat(options,",user=",options_size);
+               strlcat(options,user_name,options_size);
+       }
+       if(retry == 0) {
+               if(domain_name) {
+                       /* extra length accounted for in option string above */
+                       strlcat(options,",domain=",options_size);
+                       strlcat(options,domain_name,options_size);
+               }
+       }
        if(mountpassword) {
        if(mountpassword) {
-               strncat(options,",pass=",6);
-               strcat(options,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);
+               strlcat(options,",pass=",options_size);
+               strlcat(options,mountpassword,options_size);
        }
        }
-       strncat(options,",ver=",5);
-       strcat(options,MOUNT_CIFS_VERSION_MAJOR);
+
+       strlcat(options,",ver=",options_size);
+       strlcat(options,MOUNT_CIFS_VERSION_MAJOR,options_size);
 
        if(orgoptions) {
 
        if(orgoptions) {
-               strcat(options,",");
-               strcat(options,orgoptions);
+               strlcat(options,",",options_size);
+               strlcat(options,orgoptions,options_size);
+       }
+       if(prefixpath) {
+               strlcat(options,",prefixpath=",options_size);
+               strlcat(options,prefixpath,options_size); /* no need to cat the / */
        }
        if(verboseflag)
                printf("\nmount.cifs kernel mount options %s \n",options);
        }
        if(verboseflag)
                printf("\nmount.cifs kernel mount options %s \n",options);
-       if(mount(share_name, mountpoint, "cifs", flags, options)) {
-       /* remember to kill daemon on error */
-               char * tmp;
 
 
+       /* convert all '\\' to '/' in share portion so that /proc/mounts looks pretty */
+       replace_char(dev_name, '\\', '/', strlen(share_name));
+
+       if(mount(dev_name, mountpoint, "cifs", flags, options)) {
+       /* remember to kill daemon on error */
                switch (errno) {
                case 0:
                        printf("mount failed but no error number set\n");
                switch (errno) {
                case 0:
                        printf("mount failed but no error number set\n");
@@ -912,90 +1371,71 @@ mount_retry:
                case ENXIO:
                        if(retry == 0) {
                                retry = 1;
                case ENXIO:
                        if(retry == 0) {
                                retry = 1;
-                               tmp = share_name;
-                               while (*tmp && !(((unsigned char)tmp[0]) & 0x80)) {
-                                       *tmp = toupper((unsigned char)*tmp);
-                                       tmp++;
-                               }
-                               if(!*tmp) {
+                               if (uppercase_string(dev_name) &&
+                                   uppercase_string(share_name) &&
+                                   uppercase_string(prefixpath)) {
                                        printf("retrying with upper case share name\n");
                                        goto mount_retry;
                                }
                        }
                default:
                                        printf("retrying with upper case share name\n");
                                        goto mount_retry;
                                }
                        }
                default:
-                       
                        printf("mount error %d = %s\n",errno,strerror(errno));
                }
                printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
                        printf("mount error %d = %s\n",errno,strerror(errno));
                }
                printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
-               if(mountpassword) {
-                       memset(mountpassword,0,64);
-               }
-               return -1;
+               rc = -1;
+               goto mount_exit;
        } else {
                pmntfile = setmntent(MOUNTED, "a+");
                if(pmntfile) {
        } else {
                pmntfile = setmntent(MOUNTED, "a+");
                if(pmntfile) {
-                       mountent.mnt_fsname = share_name;
-                       mountent.mnt_dir = mountpoint; 
-                       mountent.mnt_type = "cifs"; 
-                       mountent.mnt_opts = malloc(220);
+                       mountent.mnt_fsname = dev_name;
+                       mountent.mnt_dir = mountpoint;
+                       mountent.mnt_type = CONST_DISCARD(char *,"cifs");
+                       mountent.mnt_opts = (char *)malloc(220);
                        if(mountent.mnt_opts) {
                                char * mount_user = getusername();
                                memset(mountent.mnt_opts,0,200);
                                if(flags & MS_RDONLY)
                        if(mountent.mnt_opts) {
                                char * mount_user = getusername();
                                memset(mountent.mnt_opts,0,200);
                                if(flags & MS_RDONLY)
-                                       strcat(mountent.mnt_opts,"ro");
+                                       strlcat(mountent.mnt_opts,"ro",220);
                                else
                                else
-                                       strcat(mountent.mnt_opts,"rw");
+                                       strlcat(mountent.mnt_opts,"rw",220);
                                if(flags & MS_MANDLOCK)
                                if(flags & MS_MANDLOCK)
-                                       strcat(mountent.mnt_opts,",mand");
-                               else
-                                       strcat(mountent.mnt_opts,",nomand");
+                                       strlcat(mountent.mnt_opts,",mand",220);
                                if(flags & MS_NOEXEC)
                                if(flags & MS_NOEXEC)
-                                       strcat(mountent.mnt_opts,",noexec");
+                                       strlcat(mountent.mnt_opts,",noexec",220);
                                if(flags & MS_NOSUID)
                                if(flags & MS_NOSUID)
-                                       strcat(mountent.mnt_opts,",nosuid");
+                                       strlcat(mountent.mnt_opts,",nosuid",220);
                                if(flags & MS_NODEV)
                                if(flags & MS_NODEV)
-                                       strcat(mountent.mnt_opts,",nodev");
+                                       strlcat(mountent.mnt_opts,",nodev",220);
                                if(flags & MS_SYNCHRONOUS)
                                if(flags & MS_SYNCHRONOUS)
-                                       strcat(mountent.mnt_opts,",synch");
+                                       strlcat(mountent.mnt_opts,",synch",220);
                                if(mount_user) {
                                        if(getuid() != 0) {
                                if(mount_user) {
                                        if(getuid() != 0) {
-                                               strcat(mountent.mnt_opts,",user=");
-                                               strcat(mountent.mnt_opts,mount_user);
+                                               strlcat(mountent.mnt_opts,",user=",220);
+                                               strlcat(mountent.mnt_opts,mount_user,220);
                                        }
                                        }
-                                       free(mount_user);
+                                       /* free(mount_user); do not free static mem */
                                }
                        }
                        mountent.mnt_freq = 0;
                        mountent.mnt_passno = 0;
                        rc = addmntent(pmntfile,&mountent);
                        endmntent(pmntfile);
                                }
                        }
                        mountent.mnt_freq = 0;
                        mountent.mnt_passno = 0;
                        rc = addmntent(pmntfile,&mountent);
                        endmntent(pmntfile);
-                       if(mountent.mnt_opts)
-                               free(mountent.mnt_opts);
+                       SAFE_FREE(mountent.mnt_opts);
                } else {
                    printf("could not update mount table\n");
                }
        }
                } else {
                    printf("could not update mount table\n");
                }
        }
+       rc = 0;
+mount_exit:
        if(mountpassword) {
        if(mountpassword) {
-               memset(mountpassword,0,64);
-               free(mountpassword);
-       }
-
-       if(options) {
-               memset(options,0,optlen);
-               free(options);
-       }
-
-       if(orgoptions) {
-               memset(orgoptions,0,orgoptlen);
-               free(orgoptions);
-       }
-       if(resolved_path) {
-               free(resolved_path);
+               int len = strlen(mountpassword);
+               memset(mountpassword,0,len);
+               SAFE_FREE(mountpassword);
        }
 
        }
 
-       if(free_share_name) {
-               free(share_name);
-               }
-       return 0;
+       SAFE_FREE(options);
+       SAFE_FREE(orgoptions);
+       SAFE_FREE(resolved_path);
+       SAFE_FREE(share_name);
+       return rc;
 }
 }
-