From 25b483dfc3ef63852e811587742e6d22756ce462 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 5 Jan 2004 22:18:44 +0000 Subject: cifs mount helper merge (This used to be commit 865fcdcb85d47eeff854f4df0aba0c0f3452bdd9) --- source3/client/mount.cifs.c | 676 +++++++++++++++++++++++++++++--------------- 1 file changed, 450 insertions(+), 226 deletions(-) (limited to 'source3') diff --git a/source3/client/mount.cifs.c b/source3/client/mount.cifs.c index 71639d6f34..8c23cc2212 100755 --- a/source3/client/mount.cifs.c +++ b/source3/client/mount.cifs.c @@ -1,6 +1,27 @@ +/* + Mount helper utility for Linux CIFS VFS (virtual filesystem) client + Copyright (C) 2003 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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. */ + +#ifndef _GNU_SOURCE #define _GNU_SOURCE +#endif #include +#include #include #include #include @@ -14,10 +35,14 @@ #include #include #include +#include -#define MOUNT_CIFS_VERSION "1" +#define MOUNT_CIFS_VERSION_MAJOR "1" +#define MOUNT_CIFS_VERSION_MINOR "0" -extern char *getusername(void); +#ifndef MOUNT_CIFS_VENDOR_SUFFIX +#define MOUNT_CIFS_VENDOR_SUFFIX "" +#endif char * thisprogram; int verboseflag = 0; @@ -41,17 +66,20 @@ char * mountpassword = NULL; BB end finish BB */ -void mount_cifs_usage() +static void mount_cifs_usage(void) { - printf("\nUsage: %s remotetarget dir\n", thisprogram); - printf("\nMount the remotetarget, specified as either a UNC name or "); - printf(" CIFS URL, to the local directory, dir.\n"); - + printf("\nUsage: %s -o \n", thisprogram); + printf("\nMount the remote target, specified as a UNC name,"); + printf(" to a local directory.\n"); + if(mountpassword) { + memset(mountpassword,0,64); + free(mountpassword); + } exit(1); } /* caller frees username if necessary */ -char * getusername() { +static char * getusername(void) { char *username = NULL; struct passwd *password = getpwuid(getuid()); @@ -61,25 +89,185 @@ char * getusername() { return username; } -char * parse_cifs_url(unc_name) +char * parse_cifs_url(char * unc_name) { printf("\ncifs url %s\n",unc_name); + return NULL; +} + +static int open_cred_file(char * file_name) +{ + char * line_buf; + char * temp_val; + FILE * fs; + int i, length; + fs = fopen(file_name,"r"); + if(fs == NULL) + return errno; + line_buf = malloc(4096); + if(line_buf == NULL) + return -ENOMEM; + + while(fgets(line_buf,4096,fs)) { + /* parse line from credential file */ + + /* eat leading white space */ + for(i=0;i<4096;i++) { + if(line_buf[i] == '\0') + break; + else if((line_buf[i] != ' ') && (line_buf[i] != '\t')) + break; + line_buf++; + } + + if (strncasecmp("username",line_buf,8) == 0) { + temp_val = strchr(line_buf + i,'='); + if(temp_val) { + /* go past equals sign */ + temp_val++; + length = strlen(temp_val); + if(length > 4086) { + printf("cifs.mount 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; + user_name = calloc(1 + length,1); + /* BB adding free of user_name string before exit, + not really necessary but would be cleaner */ + strncpy(user_name,temp_val, length); + } + } + } else if (strncasecmp("password",line_buf,8) == 0) { + temp_val = strchr(line_buf+i,'='); + if(temp_val) { + /* go past equals sign */ + temp_val++; + length = strlen(temp_val); + if(length > 64) { + printf("cifs.mount 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) { + mountpassword = calloc(65,1); + } + if(mountpassword) { + strncpy(mountpassword,temp_val,64); + got_password = 1; + } + } + } + } + } + fclose(fs); + if(line_buf) { + memset(line_buf,0,4096); + free(line_buf); + } + return 0; } -int parse_options(char * options) +static int get_password_from_file(int file_descript, char * filename) +{ + int rc = 0; + int i; + char c; + + if(mountpassword == NULL) + mountpassword = calloc(65,1); + else + memset(mountpassword, 0, 64); + + if(filename != NULL) { + file_descript = open(filename, O_RDONLY); + if(file_descript < 0) { + printf("cifs.mount failed. %s attempting to open password file %s\n", + strerror(errno),filename); + exit(1); + } + } + /* else file already open and fd provided */ + + for(i=0;i<64;i++) { + rc = read(file_descript,&c,1); + if(rc < 0) { + printf("cifs.mount failed. Error %s reading password file\n",strerror(errno)); + memset(mountpassword,0,64); + if(filename != NULL) + close(file_descript); + exit(1); + } else if(rc == 0) { + if(mountpassword[0] == 0) { + if(verboseflag) + printf("\nWarning: null password used since cifs password file empty"); + } + break; + } else /* read valid character */ { + if((c == 0) || (c == '\n')) { + break; + } else + mountpassword[i] = c; + } + } + if((i == 64) && (verboseflag)) { + printf("\nWarning: password longer than 64 characters specified in cifs password file"); + } + got_password = 1; + if(filename != NULL) { + close(file_descript); + } + + return rc; +} + +static int parse_options(char * options) { char * data; + char * percent_char = 0; char * value = 0; + char * next_keyword = 0; + int rc = 0; if (!options) return 1; + else + data = options; + + if(verboseflag) + printf("\n parsing options: %s", options); - while ((data = strsep(&options, ",")) != NULL) { - if (!*data) - continue; +/* while ((data = strsep(&options, ",")) != NULL) { */ + while(data != NULL) { + /* check if ends with trailing comma */ + if(*data == 0) + break; + + /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */ + /* data = next keyword */ + /* value = next value ie stuff after equal sign */ + + next_keyword = strchr(data,','); + + /* 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'; + *value = '\0'; + value++; } + if (strncmp(data, "user", 4) == 0) { if (!value || !*value) { printf("invalid or missing username\n"); @@ -87,113 +275,142 @@ int parse_options(char * options) } if (strnlen(value, 260) < 260) { got_user=1; - /* BB add check for format user%pass */ - /* if(strchr(username%passw) got_password = 1) */ + percent_char = strchr(value,'%'); + if(percent_char) { + *percent_char = ','; + if(mountpassword == NULL) + mountpassword = calloc(65,1); + if(mountpassword) { + if(got_password) + printf("\ncifs.mount warning - password specified twice\n"); + got_password = 1; + percent_char++; + strncpy(mountpassword, percent_char,64); + /* remove password from username */ + while(*percent_char != 0) { + *percent_char = ','; + percent_char++; + } + } + } } else { printf("username too long\n"); return 1; } - } else if (strncmp(data, "pass", 4) == 0) { - if (!value || !*value) { - if(got_password) { - printf("password specified twice, ignoring second\n"); - } else + } else if (strncmp(data, "pass", 4) == 0) { + if (!value || !*value) { + if(got_password) { + printf("\npassword specified twice, ignoring second\n"); + } else + got_password = 1; + } else if (strnlen(value, 17) < 17) { + if(got_password) + printf("\ncifs.mount warning - password specified twice\n"); got_password = 1; - } else if (strnlen(value, 17) < 17) { - got_password = 1; - } else { - printf("password too long\n"); - return 1; - } - } else if (strncmp(data, "ip", 2) == 0) { - if (!value || !*value) { - printf("target ip address argument missing"); - } else if (strnlen(value, 35) < 35) { - got_ip = 1; - } else { - printf("ip address too long\n"); - return 1; - } - } else if ((strncmp(data, "unc", 3) == 0) + } else { + printf("password too long\n"); + return 1; + } + } else if (strncmp(data, "ip", 2) == 0) { + if (!value || !*value) { + printf("target ip address argument missing"); + } else if (strnlen(value, 35) < 35) { + got_ip = 1; + } else { + printf("ip address too long\n"); + return 1; + } + } else if ((strncmp(data, "unc", 3) == 0) || (strncmp(data, "target", 6) == 0) || (strncmp(data, "path", 4) == 0)) { - if (!value || !*value) { - printf("invalid path to network resource\n"); - return 1; /* needs_arg; */ - } else if(strnlen(value,5) < 5) { - printf("UNC name too short"); - } + if (!value || !*value) { + printf("invalid path to network resource\n"); + return 1; /* needs_arg; */ + } else if(strnlen(value,5) < 5) { + printf("UNC name too short"); + } - if (strnlen(value, 300) < 300) { - got_unc = 1; - if (strncmp(value, "//", 2) == 0) { - if(got_unc) - printf("unc name specified twice, ignoring second\n"); - else - got_unc = 1; - } else if (strncmp(value, "\\\\", 2) != 0) { - printf("UNC Path does not begin with // or \\\\ \n"); + if (strnlen(value, 300) < 300) { + got_unc = 1; + if (strncmp(value, "//", 2) == 0) { + if(got_unc) + printf("unc name specified twice, ignoring second\n"); + else + got_unc = 1; + } else if (strncmp(value, "\\\\", 2) != 0) { + printf("UNC Path does not begin with // or \\\\ \n"); + return 1; + } else { + if(got_unc) + printf("unc name specified twice, ignoring second\n"); + else + got_unc = 1; + } + } else { + printf("CIFS: UNC name too long\n"); return 1; + } + } else if ((strncmp(data, "domain", 3) == 0) + || (strncmp(data, "workgroup", 5) == 0)) { + if (!value || !*value) { + printf("CIFS: invalid domain name\n"); + return 1; /* needs_arg; */ + } + if (strnlen(value, 65) < 65) { + got_domain = 1; } else { - if(got_unc) - printf("unc name specified twice, ignoring second\n"); - else - got_unc = 1; + printf("domain name too long\n"); + return 1; + } + } else if (strncmp(data, "cred", 4) == 0) { + if (value && *value) { + rc = open_cred_file(value); + if(rc) { + printf("error %d opening credential file %s",rc, value); + return 1; + } + } else { + printf("invalid credential file name specified\n"); + return 1; + } + } else if (strncmp(data, "uid", 3) == 0) { + if (value && *value) { + got_uid = 1; + } + } else if (strncmp(data, "gid", 3) == 0) { + if (value && *value) { + got_gid = 1; } - } else { - printf("CIFS: UNC name too long\n"); - return 1; - } - } else if ((strncmp(data, "domain", 3) == 0) - || (strncmp(data, "workgroup", 5) == 0)) { - if (!value || !*value) { - printf("CIFS: invalid domain name\n"); - return 1; /* needs_arg; */ - } - if (strnlen(value, 65) < 65) { - got_domain = 1; - } else { - printf("domain name too long\n"); - return 1; - } - } else if (strncmp(data, "uid", 3) == 0) { - if (value && *value) { - got_uid = 1; - } - } else if (strncmp(data, "gid", 3) == 0) { - if (value && *value) { - got_gid = 1; - } /* fmask and dmask synonyms for people used to smbfs syntax */ - } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) { - if (!value || !*value) { - printf ("Option '%s' requires a numerical argument\n", data); - return 1; - } + } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) { + if (!value || !*value) { + printf ("Option '%s' requires a numerical argument\n", data); + return 1; + } - if (value[0] != '0') { - printf ("WARNING: '%s' not expressed in octal.\n", data); - } + if (value[0] != '0') { + printf ("WARNING: '%s' not expressed in octal.\n", data); + } + + if (strcmp (data, "fmask") == 0) { + printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n"); + data = "file_mode"; + } + } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) { + if (!value || !*value) { + printf ("Option '%s' requires a numerical argument\n", data); + return 1; + } + + if (value[0] != '0') { + printf ("WARNING: '%s' not expressed in octal.\n", data); + } - if (strcmp (data, "fmask") == 0) { - printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n"); - data = "file_mode"; - } - } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) { - if (!value || !*value) { - printf ("Option '%s' requires a numerical argument\n", data); - return 1; - } - - if (value[0] != '0') { - printf ("WARNING: '%s' not expressed in octal.\n", data); - } - - if (strcmp (data, "dmask") == 0) { - printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n"); - data = "dir_mode"; - } - } /* else if (strnicmp(data, "port", 4) == 0) { + if (strcmp (data, "dmask") == 0) { + printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n"); + data = "dir_mode"; + } + } /* else if (strnicmp(data, "port", 4) == 0) { if (value && *value) { vol->port = simple_strtoul(value, &value, 0); @@ -214,6 +431,22 @@ int parse_options(char * options) } else printf("CIFS: Unknown mount option %s\n",data); */ + + /* move to next option */ + data = next_keyword+1; + + /* put overwritten equals sign back */ + if(value) { + value--; + *value = '='; + } + + /* put previous overwritten comma back */ + if(next_keyword) + *next_keyword = ','; + else + data = 0; + } return 0; } @@ -226,8 +459,7 @@ char * parse_server(char * unc_name) char * ipaddress_string = NULL; struct hostent * host_entry; struct in_addr server_ipaddr; - int rc,j; - char temp[64]; + int rc; if(length > 1023) { printf("mount error: UNC name too long"); @@ -244,7 +476,6 @@ char * parse_server(char * unc_name) printf("\nMounting the DFS root for domain not implemented yet"); return 0; } else { - /* BB add support for \\\\ not just // */ if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) { printf("mount error: improperly formatted UNC name."); printf(" %s does not begin with \\\\ or //\n",unc_name); @@ -300,21 +531,19 @@ static struct option longopts[] = { { "rw", 0, 0, 'w' }, { "options", 1, 0, 'o' }, { "types", 1, 0, 't' }, - { "replace", 0, 0, 129 }, - { "after", 0, 0, 130 }, - { "before", 0, 0, 131 }, - { "over", 0, 0, 132 }, - { "move", 0, 0, 133 }, - { "rsize",1, 0, 136 }, - { "wsize",1, 0, 137 }, - { "uid", 1, 0, 138}, - { "gid", 1, 0, 139}, + { "rsize",1, 0, 'R' }, + { "wsize",1, 0, 'W' }, + { "uid", 1, 0, '1'}, + { "gid", 1, 0, '2'}, { "uuid",1,0,'U' }, - { "user",1,0,140}, - { "username",1,0,140}, - { "dom",1,0,141}, - { "domain",1,0,141}, - { "password",1,0,142}, + { "user",1,0,'u'}, + { "username",1,0,'u'}, + { "dom",1,0,'d'}, + { "domain",1,0,'d'}, + { "password",1,0,'p'}, + { "pass",1,0,'p'}, + { "credentials",1,0,'c'}, + { "port",1,0,'P'}, { NULL, 0, 0, 0 } }; @@ -330,13 +559,14 @@ int main(int argc, char ** argv) char * mountpoint; char * options; char * temp; - int rc,i; + int rc; int rsize = 0; int wsize = 0; int nomtab = 0; int uid = 0; int gid = 0; int optlen = 0; + int orgoptlen = 0; struct stat statbuf; struct utsname sysinfo; struct mntent mountent; @@ -354,56 +584,40 @@ int main(int argc, char ** argv) uname(&sysinfo); /* BB add workstation name and domain and pass down */ -/*#ifdef _GNU_SOURCE - printf(" node: %s machine: %s\n", sysinfo.nodename,sysinfo.machine); -#endif*/ - if(argc < 3) - mount_cifs_usage(); + +/* #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]; + /* add sharename in opts string as unc= parm */ while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsU:vVwt:", longopts, NULL)) != -1) { switch (c) { -/* case 'a': - ++mount_all; - break; - case 'f': - ++fake; - break; - case 'F': - ++optfork; - break; */ - case 'h': /* help */ - mount_cifs_usage (); - break; -/* case 'i': - external_allowed = 0; - break; - case 'l': +/* No code to do the following options yet */ +/* case 'l': list_with_volumelabel = 1; break; case 'L': volumelabel = optarg; break; */ - case 'n': - ++nomtab; - break; - case 'o': - if (orgoptions) { - orgoptions = strcat(orgoptions, ","); - orgoptions = strcat(orgoptions,optarg); - } else - orgoptions = strdup(optarg); - break; +/* case 'a': + ++mount_all; + break; */ -/* case 'O': - if (test_opts) - test_opts = xstrconcat3(test_opts, ",", optarg); - else - test_opts = xstrdup(optarg); - break;*/ + case '?': + case 'h': /* help */ + mount_cifs_usage (); + exit(1); + case 'n': + ++nomtab; + break; + case 'o': + orgoptions = strdup(optarg); + break; case 'r': /* mount readonly */ flags |= MS_RDONLY; break; @@ -413,68 +627,78 @@ int main(int argc, char ** argv) case 'v': ++verboseflag; break; -/* case 'V': - printf ("mount: %s\n", version); - exit (0);*/ + case 'V': + printf ("mount.cifs version: %s.%s%s\n", + 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; break; -/* case 0: - break; - - case 128: - mounttype = MS_BIND; - break; - case 129: - mounttype = MS_REPLACE; - break; - case 130: - mounttype = MS_AFTER; - break; - case 131: - mounttype = MS_BEFORE; - break; - case 132: - mounttype = MS_OVER; - break; - case 133: - mounttype = MS_MOVE; - break; - case 135: - mounttype = (MS_BIND | MS_REC); - break; */ - case 136: + case 'R': rsize = atoi(optarg) ; break; - case 137: + case 'W': wsize = atoi(optarg); break; - case 138: + case '1': uid = atoi(optarg); break; - case 139: + case '2': gid = atoi(optarg); break; - case 140: + case 'u': got_user = 1; user_name = optarg; break; - case 141: + case 'd': domain_name = optarg; break; - case 142: - got_password = 1; - mountpassword = optarg; + case 'p': + if(mountpassword == NULL) + mountpassword = calloc(65,1); + if(mountpassword) { + got_password = 1; + strncpy(mountpassword,optarg,64); + } + break; + case 't': break; - case '?': default: - mount_cifs_usage (); + printf("unknown mount option %c\n",c); + mount_cifs_usage(); + exit(1); } } - /* canonicalize the path in argv[1]? */ + if(argc < 3) + mount_cifs_usage(); + + if (getenv("PASSWD")) { + if(mountpassword == NULL) + mountpassword = calloc(65,1); + if(mountpassword) { + strncpy(mountpassword,getenv("PASSWD"),64); + got_password = 1; + } + } else if (getenv("PASSWD_FD")) { + get_password_from_file(atoi(getenv("PASSWD_FD")),NULL); + } else if (getenv("PASSWD_FILE")) { + get_password_from_file(0, getenv("PASSWD_FILE")); + } + + ipaddr = parse_server(share_name); + + if (orgoptions && parse_options(orgoptions)) + return 1; + + /* BB save off path and pop after mount returns? */ + /* BB canonicalize the path in argv[1]? */ - /* BB save off path and pop after mount returns */ if(chdir(mountpoint)) { printf("mount error: can not change directory into mount target %s\n",mountpoint); } @@ -498,36 +722,18 @@ int main(int argc, char ** argv) } } - ipaddr = parse_server(share_name); -/* if(share_name == NULL) - return 1; */ - if (orgoptions && parse_options(strdup(orgoptions))) - return 1; - if(got_user == 0) user_name = getusername(); -/* check username for user%password format */ - if(got_password == 0) { - if (getenv("PASSWD")) { - mountpassword = malloc(33); - if(mountpassword) { - strncpy(mountpassword,getenv("PASSWD"),32); - got_password = 1; - } -/* } else if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) { - get_password_file(); - got_password = 1;*/ /* BB add missing function */ - } else { - mountpassword = getpass("Password: "); /* BB obsolete */ - got_password = 1; - } + mountpassword = getpass("Password: "); /* BB obsolete */ + got_password = 1; } /* FIXME launch daemon (handles dfs name resolution and credential change) remember to clear parms and overwrite password field before launching */ if(orgoptions) { optlen = strlen(orgoptions); + orgoptlen = optlen; } else optlen = 0; if(share_name) @@ -560,19 +766,20 @@ int main(int argc, char ** argv) strcat(options,mountpassword); } strncat(options,",ver=",5); - strcat(options,MOUNT_CIFS_VERSION); + strcat(options,MOUNT_CIFS_VERSION_MAJOR); if(orgoptions) { strcat(options,","); strcat(options,orgoptions); } - /* printf("\noptions %s \n",options);*/ + if(verboseflag) + printf("\ncifs.mount kernel mount options %s \n",options); if(mount(share_name, mountpoint, "cifs", flags, options)) { /* remember to kill daemon on error */ switch (errno) { case 0: printf("mount failed but no error number set\n"); - return 0; + break; case ENODEV: printf("mount error: cifs filesystem not supported by the system\n"); break; @@ -580,6 +787,9 @@ int main(int argc, char ** argv) 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; } else { pmntfile = setmntent(MOUNTED, "a+"); @@ -596,6 +806,20 @@ int main(int argc, char ** argv) printf("could not update mount table\n"); } } + if(mountpassword) { + memset(mountpassword,0,64); + free(mountpassword); + } + + if(options) { + memset(options,0,optlen); + free(options); + } + + if(orgoptions) { + memset(orgoptions,0,orgoptlen); + free(orgoptions); + } return 0; } -- cgit