2 Mount helper utility for Linux CIFS VFS (virtual filesystem) client
3 Copyright (C) 2003,2005 Steve French (sfrench@us.ibm.com)
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
28 #include <sys/types.h>
29 #include <sys/mount.h>
31 #include <sys/utsname.h>
32 #include <sys/socket.h>
33 #include <arpa/inet.h>
42 #define MOUNT_CIFS_VERSION_MAJOR "1"
43 #define MOUNT_CIFS_VERSION_MINOR "11"
45 #ifndef MOUNT_CIFS_VENDOR_SUFFIX
47 #include "include/version.h"
48 #ifdef SAMBA_VERSION_VENDOR_SUFFIX
49 #define MOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING"-"SAMBA_VERSION_VENDOR_SUFFIX
51 #define MOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING
52 #endif /* SAMBA_VERSION_OFFICIAL_STRING and SAMBA_VERSION_VENDOR_SUFFIX */
54 #define MOUNT_CIFS_VENDOR_SUFFIX ""
55 #endif /* _SAMBA_BUILD_ */
56 #endif /* MOUNT_CIFS_VENDOR_SUFFIX */
66 #define CONST_DISCARD(type, ptr) ((type) ((void *) (ptr)))
68 const char *thisprogram;
70 static int got_password = 0;
71 static int got_user = 0;
72 static int got_domain = 0;
73 static int got_ip = 0;
74 static int got_unc = 0;
75 static int got_uid = 0;
76 static int got_gid = 0;
77 static int free_share_name = 0;
78 static char * user_name = NULL;
79 static char * mountpassword = NULL;
80 char * domain_name = NULL;
81 char * prefixpath = NULL;
83 /* glibc doesn't have strlcpy, strlcat. Ensure we do. JRA. We
84 * don't link to libreplace so need them here. */
86 /* like strncpy but does not 0 fill the buffer and always null
87 * terminates. bufsize is the size of the destination buffer */
88 size_t strlcpy(char *d, const char *s, size_t bufsize)
90 size_t len = strlen(s);
92 if (bufsize <= 0) return 0;
93 if (len >= bufsize) len = bufsize-1;
99 /* like strncat but does not 0 fill the buffer and always null
100 * terminates. bufsize is the length of the buffer, which should
101 * be one more than the maximum resulting string length */
102 size_t strlcat(char *d, const char *s, size_t bufsize)
104 size_t len1 = strlen(d);
105 size_t len2 = strlen(s);
106 size_t ret = len1 + len2;
108 if (len1+len2 >= bufsize) {
109 len2 = bufsize - (len1+1);
112 memcpy(d+len1, s, len2);
121 open nofollow - avoid symlink exposure?
122 get owner of dir see if matches self or if root
123 call system(umount argv) etc.
127 static char * check_for_domain(char **);
130 static void mount_cifs_usage(void)
132 printf("\nUsage: %s <remotetarget> <dir> -o <options>\n", thisprogram);
133 printf("\nMount the remote target, specified as a UNC name,");
134 printf(" to a local directory.\n\nOptions:\n");
135 printf("\tuser=<arg>\n\tpass=<arg>\n\tdom=<arg>\n");
136 printf("\nLess commonly used options:");
137 printf("\n\tcredentials=<filename>,guest,perm,noperm,setuids,nosetuids,rw,ro,");
138 printf("\n\tsep=<char>,iocharset=<codepage>,suid,nosuid,exec,noexec,serverino,");
139 printf("\n\tmapchars,nomapchars,nolock,servernetbiosname=<SRV_RFC1001NAME>");
140 printf("\n\tdirectio,nounix,cifsacl,sec=<authentication mechanism>,sign");
141 printf("\n\nOptions not needed for servers supporting CIFS Unix extensions");
142 printf("\n\t(e.g. unneeded for mounts to most Samba versions):");
143 printf("\n\tuid=<uid>,gid=<gid>,dir_mode=<mode>,file_mode=<mode>,sfu");
144 printf("\n\nRarely used options:");
145 printf("\n\tport=<tcpport>,rsize=<size>,wsize=<size>,unc=<unc_name>,ip=<ip_address>,");
146 printf("\n\tdev,nodev,nouser_xattr,netbiosname=<OUR_RFC1001NAME>,hard,soft,intr,");
147 printf("\n\tnointr,ignorecase,noposixpaths,noacl,prefixpath=<path>,nobrl");
148 printf("\n\tin6_addr");
149 printf("\n\nOptions are described in more detail in the manual page");
150 printf("\n\tman 8 mount.cifs\n");
151 printf("\nTo display the version number of the mount helper:");
152 printf("\n\t%s -V\n",thisprogram);
155 memset(mountpassword,0,64);
161 /* caller frees username if necessary */
162 static char * getusername(void) {
163 char *username = NULL;
164 struct passwd *password = getpwuid(getuid());
167 username = password->pw_name;
172 static char * parse_cifs_url(char * unc_name)
174 printf("\nMounting cifs URL not implemented yet. Attempt to mount %s\n",unc_name);
178 static int open_cred_file(char * file_name)
184 fs = fopen(file_name,"r");
187 line_buf = (char *)malloc(4096);
188 if(line_buf == NULL) {
193 while(fgets(line_buf,4096,fs)) {
194 /* parse line from credential file */
196 /* eat leading white space */
197 for(i=0;i<4086;i++) {
198 if((line_buf[i] != ' ') && (line_buf[i] != '\t'))
200 /* if whitespace - skip past it */
202 if (strncasecmp("username",line_buf+i,8) == 0) {
203 temp_val = strchr(line_buf + i,'=');
205 /* go past equals sign */
207 for(length = 0;length<4087;length++) {
208 if ((temp_val[length] == '\n')
209 || (temp_val[length] == '\0')) {
214 printf("mount.cifs failed due to malformed username in credentials file");
215 memset(line_buf,0,4096);
217 memset(mountpassword,0,64);
222 user_name = (char *)calloc(1 + length,1);
223 /* BB adding free of user_name string before exit,
224 not really necessary but would be cleaner */
225 strncpy(user_name,temp_val, length);
228 } else if (strncasecmp("password",line_buf+i,8) == 0) {
229 temp_val = strchr(line_buf+i,'=');
231 /* go past equals sign */
233 for(length = 0;length<65;length++) {
234 if(temp_val[length] == '\n' || temp_val[length] == '\0')
238 printf("mount.cifs failed: password in credentials file too long\n");
239 memset(line_buf,0, 4096);
241 memset(mountpassword,0,64);
245 if(mountpassword == NULL) {
246 mountpassword = (char *)calloc(65,1);
248 memset(mountpassword,0,64);
250 strncpy(mountpassword,temp_val,length);
255 } else if (strncasecmp("domain",line_buf+i,6) == 0) {
256 temp_val = strchr(line_buf+i,'=');
258 /* go past equals sign */
261 printf("\nDomain %s\n",temp_val);
262 for(length = 0;length<65;length++) {
263 if(temp_val[length] == '\n' || temp_val[length] == '\0')
267 printf("mount.cifs failed: domain in credentials file too long\n");
269 memset(mountpassword,0,64);
273 if(domain_name == NULL) {
274 domain_name = (char *)calloc(65,1);
276 memset(domain_name,0,64);
278 strncpy(domain_name,temp_val,length);
288 memset(line_buf,0,4096);
294 static int get_password_from_file(int file_descript, char * filename)
300 if(mountpassword == NULL)
301 mountpassword = (char *)calloc(65,1);
303 memset(mountpassword, 0, 64);
305 if (mountpassword == NULL) {
306 printf("malloc failed\n");
310 if(filename != NULL) {
311 file_descript = open(filename, O_RDONLY);
312 if(file_descript < 0) {
313 printf("mount.cifs failed. %s attempting to open password file %s\n",
314 strerror(errno),filename);
318 /* else file already open and fd provided */
321 rc = read(file_descript,&c,1);
323 printf("mount.cifs failed. Error %s reading password file\n",strerror(errno));
324 memset(mountpassword,0,64);
326 close(file_descript);
329 if(mountpassword[0] == 0) {
331 printf("\nWarning: null password used since cifs password file empty");
334 } else /* read valid character */ {
335 if((c == 0) || (c == '\n')) {
338 mountpassword[i] = c;
341 if((i == 64) && (verboseflag)) {
342 printf("\nWarning: password longer than 64 characters specified in cifs password file");
345 if(filename != NULL) {
346 close(file_descript);
352 static int parse_options(char ** optionsp, int * filesys_flags)
355 char * percent_char = NULL;
357 char * next_keyword = NULL;
365 if (!optionsp || !*optionsp)
370 printf("parsing options: %s\n", data);
372 /* BB fixme check for separator override BB */
376 snprintf(user,sizeof(user),"%u",getuid());
378 snprintf(group,sizeof(group),"%u",getgid());
381 /* while ((data = strsep(&options, ",")) != NULL) { */
382 while(data != NULL) {
383 /* check if ends with trailing comma */
387 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
388 /* data = next keyword */
389 /* value = next value ie stuff after equal sign */
391 next_keyword = strchr(data,','); /* BB handle sep= */
393 /* temporarily null terminate end of keyword=value pair */
397 /* temporarily null terminate keyword to make keyword and value distinct */
398 if ((value = strchr(data, '=')) != NULL) {
403 if (strncmp(data, "users",5) == 0) {
404 if(!value || !*value) {
407 } else if (strncmp(data, "user_xattr",10) == 0) {
408 /* do nothing - need to skip so not parsed as user name */
409 } else if (strncmp(data, "user", 4) == 0) {
411 if (!value || !*value) {
412 if(data[4] == '\0') {
414 printf("\nskipping empty user mount parameter\n");
415 /* remove the parm since it would otherwise be confusing
416 to the kernel code which would think it was a real username */
419 printf("username specified with no parameter\n");
420 return 1; /* needs_arg; */
423 if (strnlen(value, 260) < 260) {
425 percent_char = strchr(value,'%');
428 if(mountpassword == NULL)
429 mountpassword = (char *)calloc(65,1);
432 printf("\nmount.cifs warning - password specified twice\n");
435 strncpy(mountpassword, percent_char,64);
436 /* remove password from username */
437 while(*percent_char != 0) {
443 /* this is only case in which the user
444 name buf is not malloc - so we have to
445 check for domain name embedded within
446 the user name here since the later
447 call to check_for_domain will not be
449 domain_name = check_for_domain(&value);
451 printf("username too long\n");
455 } else if (strncmp(data, "pass", 4) == 0) {
456 if (!value || !*value) {
458 printf("\npassword specified twice, ignoring second\n");
461 } else if (strnlen(value, 17) < 17) {
463 printf("\nmount.cifs warning - password specified twice\n");
466 printf("password too long\n");
469 } else if (strncmp(data, "sec", 3) == 0) {
471 if (!strcmp(value, "none"))
474 } else if (strncmp(data, "ip", 2) == 0) {
475 if (!value || !*value) {
476 printf("target ip address argument missing");
477 } else if (strnlen(value, 35) < 35) {
479 printf("ip address %s override specified\n",value);
482 printf("ip address too long\n");
485 } else if ((strncmp(data, "unc", 3) == 0)
486 || (strncmp(data, "target", 6) == 0)
487 || (strncmp(data, "path", 4) == 0)) {
488 if (!value || !*value) {
489 printf("invalid path to network resource\n");
490 return 1; /* needs_arg; */
491 } else if(strnlen(value,5) < 5) {
492 printf("UNC name too short");
495 if (strnlen(value, 300) < 300) {
497 if (strncmp(value, "//", 2) == 0) {
499 printf("unc name specified twice, ignoring second\n");
502 } else if (strncmp(value, "\\\\", 2) != 0) {
503 printf("UNC Path does not begin with // or \\\\ \n");
507 printf("unc name specified twice, ignoring second\n");
512 printf("CIFS: UNC name too long\n");
515 } else if ((strncmp(data, "domain", 3) == 0)
516 || (strncmp(data, "workgroup", 5) == 0)) {
517 if (!value || !*value) {
518 printf("CIFS: invalid domain name\n");
519 return 1; /* needs_arg; */
521 if (strnlen(value, 65) < 65) {
524 printf("domain name too long\n");
527 } else if (strncmp(data, "cred", 4) == 0) {
528 if (value && *value) {
529 rc = open_cred_file(value);
531 printf("error %d opening credential file %s\n",rc, value);
535 printf("invalid credential file name specified\n");
538 } else if (strncmp(data, "uid", 3) == 0) {
539 if (value && *value) {
541 if (!isdigit(*value)) {
544 if (!(pw = getpwnam(value))) {
545 printf("bad user name \"%s\"\n", value);
548 snprintf(user, sizeof(user), "%u", pw->pw_uid);
550 strlcpy(user,value,sizeof(user));
554 } else if (strncmp(data, "gid", 3) == 0) {
555 if (value && *value) {
557 if (!isdigit(*value)) {
560 if (!(gr = getgrnam(value))) {
561 printf("bad group name \"%s\"\n", value);
564 snprintf(group, sizeof(group), "%u", gr->gr_gid);
566 strlcpy(group,value,sizeof(group));
570 /* fmask and dmask synonyms for people used to smbfs syntax */
571 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
572 if (!value || !*value) {
573 printf ("Option '%s' requires a numerical argument\n", data);
577 if (value[0] != '0') {
578 printf ("WARNING: '%s' not expressed in octal.\n", data);
581 if (strcmp (data, "fmask") == 0) {
582 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
583 data = "file_mode"; /* BB fix this */
585 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
586 if (!value || !*value) {
587 printf ("Option '%s' requires a numerical argument\n", data);
591 if (value[0] != '0') {
592 printf ("WARNING: '%s' not expressed in octal.\n", data);
595 if (strcmp (data, "dmask") == 0) {
596 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
599 /* the following eight mount options should be
600 stripped out from what is passed into the kernel
601 since these eight options are best passed as the
602 mount flags rather than redundantly to the kernel
603 and could generate spurious warnings depending on the
604 level of the corresponding cifs vfs kernel code */
605 } else if (strncmp(data, "nosuid", 6) == 0) {
606 *filesys_flags |= MS_NOSUID;
607 } else if (strncmp(data, "suid", 4) == 0) {
608 *filesys_flags &= ~MS_NOSUID;
609 } else if (strncmp(data, "nodev", 5) == 0) {
610 *filesys_flags |= MS_NODEV;
611 } else if ((strncmp(data, "nobrl", 5) == 0) ||
612 (strncmp(data, "nolock", 6) == 0)) {
613 *filesys_flags &= ~MS_MANDLOCK;
614 } else if (strncmp(data, "dev", 3) == 0) {
615 *filesys_flags &= ~MS_NODEV;
616 } else if (strncmp(data, "noexec", 6) == 0) {
617 *filesys_flags |= MS_NOEXEC;
618 } else if (strncmp(data, "exec", 4) == 0) {
619 *filesys_flags &= ~MS_NOEXEC;
620 } else if (strncmp(data, "guest", 5) == 0) {
622 } else if (strncmp(data, "ro", 2) == 0) {
623 *filesys_flags |= MS_RDONLY;
624 } else if (strncmp(data, "rw", 2) == 0) {
625 *filesys_flags &= ~MS_RDONLY;
626 } else if (strncmp(data, "remount", 7) == 0) {
627 *filesys_flags |= MS_REMOUNT;
628 } /* else if (strnicmp(data, "port", 4) == 0) {
629 if (value && *value) {
631 simple_strtoul(value, &value, 0);
633 } else if (strnicmp(data, "rsize", 5) == 0) {
634 if (value && *value) {
636 simple_strtoul(value, &value, 0);
638 } else if (strnicmp(data, "wsize", 5) == 0) {
639 if (value && *value) {
641 simple_strtoul(value, &value, 0);
643 } else if (strnicmp(data, "version", 3) == 0) {
645 printf("CIFS: Unknown mount option %s\n",data);
646 } */ /* nothing to do on those four mount options above.
647 Just pass to kernel and ignore them here */
649 /* Copy (possibly modified) option to out */
650 word_len = strlen(data);
652 word_len += 1 + strlen(value);
654 out = (char *)realloc(out, out_len + word_len + 2);
661 strlcat(out, ",", out_len + word_len + 2);
666 snprintf(out + out_len, word_len + 1, "%s=%s", data, value);
668 snprintf(out + out_len, word_len + 1, "%s", data);
669 out_len = strlen(out);
675 /* special-case the uid and gid */
677 word_len = strlen(user);
679 out = (char *)realloc(out, out_len + word_len + 6);
686 strlcat(out, ",", out_len + word_len + 6);
689 snprintf(out + out_len, word_len + 5, "uid=%s", user);
690 out_len = strlen(out);
693 word_len = strlen(group);
695 out = (char *)realloc(out, out_len + 1 + word_len + 6);
702 strlcat(out, ",", out_len + word_len + 6);
705 snprintf(out + out_len, word_len + 5, "gid=%s", group);
706 out_len = strlen(out);
714 /* replace all (one or more) commas with double commas */
715 static void check_for_comma(char ** ppasswrd)
720 int number_of_commas = 0;
735 if(number_of_commas == 0)
737 if(number_of_commas > 64) {
738 /* would otherwise overflow the mount options buffer */
739 printf("\nInvalid password. Password contains too many commas.\n");
743 new_pass_buf = (char *)malloc(len+number_of_commas+1);
744 if(new_pass_buf == NULL)
747 for(i=0,j=0;i<len;i++,j++) {
748 new_pass_buf[j] = pass[i];
751 new_pass_buf[j] = pass[i];
754 new_pass_buf[len+number_of_commas] = 0;
757 *ppasswrd = new_pass_buf;
762 /* Usernames can not have backslash in them and we use
763 [BB check if usernames can have forward slash in them BB]
764 backslash as domain\user separator character
766 static char * check_for_domain(char **ppuser)
768 char * original_string;
778 original_string = *ppuser;
780 if (original_string == NULL)
783 original_len = strlen(original_string);
785 usernm = strchr(*ppuser,'/');
786 if (usernm == NULL) {
787 usernm = strchr(*ppuser,'\\');
793 printf("Domain name specified twice. Username probably malformed\n");
799 if (domainnm[0] != 0) {
802 printf("null domain\n");
804 len = strlen(domainnm);
805 /* reset domainm to new buffer, and copy
806 domain name into it */
807 domainnm = (char *)malloc(len+1);
811 strlcpy(domainnm,*ppuser,len+1);
813 /* move_string(*ppuser, usernm+1) */
814 len = strlen(usernm+1);
816 if(len >= original_len) {
817 /* should not happen */
821 for(i=0;i<original_len;i++) {
823 original_string[i] = usernm[i+1];
824 else /* stuff with commas to remove last parm */
825 original_string[i] = ',';
828 /* BB add check for more than one slash?
836 /* Note that caller frees the returned buffer if necessary */
837 static char * parse_server(char ** punc_name)
839 char * unc_name = *punc_name;
840 int length = strnlen(unc_name,1024);
842 char * ipaddress_string = NULL;
843 struct hostent * host_entry = NULL;
844 struct in_addr server_ipaddr;
847 printf("mount error: UNC name too long");
850 if (strncasecmp("cifs://",unc_name,7) == 0)
851 return parse_cifs_url(unc_name+7);
852 if (strncasecmp("smb://",unc_name,6) == 0) {
853 return parse_cifs_url(unc_name+6);
857 /* BB add code to find DFS root here */
858 printf("\nMounting the DFS root for domain not implemented yet\n");
861 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
862 /* check for nfs syntax ie server:share */
863 share = strchr(unc_name,':');
866 *punc_name = (char *)malloc(length+3);
867 if(*punc_name == NULL) {
868 /* put the original string back if
870 *punc_name = unc_name;
875 strncpy((*punc_name)+2,unc_name,length);
876 unc_name = *punc_name;
877 unc_name[length+2] = 0;
878 goto continue_unc_parsing;
880 printf("mount error: improperly formatted UNC name.");
881 printf(" %s does not begin with \\\\ or //\n",unc_name);
885 continue_unc_parsing:
889 if ((share = strchr(unc_name, '/')) ||
890 (share = strchr(unc_name,'\\'))) {
891 *share = 0; /* temporarily terminate the string */
894 host_entry = gethostbyname(unc_name);
896 *(share - 1) = '/'; /* put the slash back */
897 if ((prefixpath = strchr(share, '/'))) {
898 *prefixpath = 0; /* permanently terminate the string */
899 if (!strlen(++prefixpath))
900 prefixpath = NULL; /* this needs to be done explicitly */
904 printf("ip address specified explicitly\n");
907 if(host_entry == NULL) {
908 printf("mount error: could not find target server. TCP name %s not found\n", unc_name);
911 /* BB should we pass an alternate version of the share name as Unicode */
912 /* BB what about ipv6? BB */
913 /* BB add retries with alternate servers in list */
915 memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
917 ipaddress_string = inet_ntoa(server_ipaddr);
918 if(ipaddress_string == NULL) {
919 printf("mount error: could not get valid ip address for target server\n");
922 return ipaddress_string;
925 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
926 printf("Mounting the DFS root for a particular server not implemented yet\n");
933 static struct option longopts[] = {
934 { "all", 0, NULL, 'a' },
935 { "help",0, NULL, 'h' },
936 { "move",0, NULL, 'm' },
937 { "bind",0, NULL, 'b' },
938 { "read-only", 0, NULL, 'r' },
939 { "ro", 0, NULL, 'r' },
940 { "verbose", 0, NULL, 'v' },
941 { "version", 0, NULL, 'V' },
942 { "read-write", 0, NULL, 'w' },
943 { "rw", 0, NULL, 'w' },
944 { "options", 1, NULL, 'o' },
945 { "type", 1, NULL, 't' },
946 { "rsize",1, NULL, 'R' },
947 { "wsize",1, NULL, 'W' },
948 { "uid", 1, NULL, '1'},
949 { "gid", 1, NULL, '2'},
950 { "user",1,NULL,'u'},
951 { "username",1,NULL,'u'},
953 { "domain",1,NULL,'d'},
954 { "password",1,NULL,'p'},
955 { "pass",1,NULL,'p'},
956 { "credentials",1,NULL,'c'},
957 { "port",1,NULL,'P'},
958 /* { "uuid",1,NULL,'U'}, */ /* BB unimplemented */
962 int main(int argc, char ** argv)
965 int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
966 char * orgoptions = NULL;
967 char * share_name = NULL;
968 char * ipaddr = NULL;
970 char * mountpoint = NULL;
971 char * options = NULL;
972 char * resolved_path = NULL;
982 size_t options_size = 0;
983 int retry = 0; /* set when we have to retry mount with uppercase */
985 struct utsname sysinfo;
986 struct mntent mountent;
989 /* setlocale(LC_ALL, "");
990 bindtextdomain(PACKAGE, LOCALEDIR);
991 textdomain(PACKAGE); */
994 thisprogram = argv[0];
1000 if(thisprogram == NULL)
1001 thisprogram = "mount.cifs";
1004 /* BB add workstation name and domain and pass down */
1006 /* #ifdef _GNU_SOURCE
1007 printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
1010 share_name = argv[1];
1011 mountpoint = argv[2];
1014 /* add sharename in opts string as unc= parm */
1016 while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
1017 longopts, NULL)) != -1) {
1019 /* No code to do the following options yet */
1021 list_with_volumelabel = 1;
1024 volumelabel = optarg;
1031 case 'h': /* help */
1032 mount_cifs_usage ();
1042 "option 'b' (MS_BIND) not supported\n");
1050 "option 'm' (MS_MOVE) not supported\n");
1054 orgoptions = strdup(optarg);
1056 case 'r': /* mount readonly */
1066 printf ("mount.cifs version: %s.%s%s\n",
1067 MOUNT_CIFS_VERSION_MAJOR,
1068 MOUNT_CIFS_VERSION_MINOR,
1069 MOUNT_CIFS_VENDOR_SUFFIX);
1071 memset(mountpassword,0,64);
1075 flags &= ~MS_RDONLY;
1078 rsize = atoi(optarg) ;
1081 wsize = atoi(optarg);
1084 if (isdigit(*optarg)) {
1087 uid = strtoul(optarg, &ep, 10);
1089 printf("bad uid value \"%s\"\n", optarg);
1095 if (!(pw = getpwnam(optarg))) {
1096 printf("bad user name \"%s\"\n", optarg);
1104 if (isdigit(*optarg)) {
1107 gid = strtoul(optarg, &ep, 10);
1109 printf("bad gid value \"%s\"\n", optarg);
1115 if (!(gr = getgrnam(optarg))) {
1116 printf("bad user name \"%s\"\n", optarg);
1128 domain_name = optarg; /* BB fix this - currently ignored */
1132 if(mountpassword == NULL)
1133 mountpassword = (char *)calloc(65,1);
1136 strncpy(mountpassword,optarg,64);
1140 get_password_from_file(0 /* stdin */,NULL);
1145 printf("unknown mount option %c\n",c);
1151 if((argc < 3) || (share_name == NULL) || (mountpoint == NULL)) {
1156 if (getenv("PASSWD")) {
1157 if(mountpassword == NULL)
1158 mountpassword = (char *)calloc(65,1);
1160 strncpy(mountpassword,getenv("PASSWD"),64);
1163 } else if (getenv("PASSWD_FD")) {
1164 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
1165 } else if (getenv("PASSWD_FILE")) {
1166 get_password_from_file(0, getenv("PASSWD_FILE"));
1169 if (orgoptions && parse_options(&orgoptions, &flags)) {
1173 ipaddr = parse_server(&share_name);
1174 if((ipaddr == NULL) && (got_ip == 0)) {
1175 printf("No ip address specified and hostname not found\n");
1180 /* BB save off path and pop after mount returns? */
1181 resolved_path = (char *)malloc(PATH_MAX+1);
1183 /* Note that if we can not canonicalize the name, we get
1184 another chance to see if it is valid when we chdir to it */
1185 if (realpath(mountpoint, resolved_path)) {
1186 mountpoint = resolved_path;
1189 if(chdir(mountpoint)) {
1190 printf("mount error: can not change directory into mount target %s\n",mountpoint);
1195 if(stat (".", &statbuf)) {
1196 printf("mount error: mount point %s does not exist\n",mountpoint);
1201 if (S_ISDIR(statbuf.st_mode) == 0) {
1202 printf("mount error: mount point %s is not a directory\n",mountpoint);
1207 if((getuid() != 0) && (geteuid() == 0)) {
1208 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
1209 #ifndef CIFS_ALLOW_USR_SUID
1210 /* Do not allow user mounts to control suid flag
1211 for mount unless explicitly built that way */
1212 flags |= MS_NOSUID | MS_NODEV;
1215 printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n");
1221 user_name = getusername();
1225 if(got_password == 0) {
1226 mountpassword = getpass("Password: "); /* BB obsolete */
1229 /* FIXME launch daemon (handles dfs name resolution and credential change)
1230 remember to clear parms and overwrite password field before launching */
1233 optlen = strlen(orgoptions);
1238 optlen += strlen(share_name) + 4;
1240 printf("No server share name specified\n");
1241 printf("\nMounting the DFS root for server not implemented yet\n");
1245 optlen += strlen(user_name) + 6;
1247 optlen += strlen(ipaddr) + 4;
1249 optlen += strlen(mountpassword) + 6;
1252 options_size = optlen + 10 + 64;
1253 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 */);
1255 if(options == NULL) {
1256 printf("Could not allocate memory for mount options\n");
1261 strlcpy(options,"unc=",options_size);
1262 strlcat(options,share_name,options_size);
1263 /* scan backwards and reverse direction of slash */
1264 temp = strrchr(options, '/');
1265 if(temp > options + 6)
1268 strlcat(options,",ip=",options_size);
1269 strlcat(options,ipaddr,options_size);
1273 /* check for syntax like user=domain\user */
1275 domain_name = check_for_domain(&user_name);
1276 strlcat(options,",user=",options_size);
1277 strlcat(options,user_name,options_size);
1281 /* extra length accounted for in option string above */
1282 strlcat(options,",domain=",options_size);
1283 strlcat(options,domain_name,options_size);
1287 /* Commas have to be doubled, or else they will
1288 look like the parameter separator */
1289 /* if(sep is not set)*/
1291 check_for_comma(&mountpassword);
1292 strlcat(options,",pass=",options_size);
1293 strlcat(options,mountpassword,options_size);
1296 strlcat(options,",ver=",options_size);
1297 strlcat(options,MOUNT_CIFS_VERSION_MAJOR,options_size);
1300 strlcat(options,",",options_size);
1301 strlcat(options,orgoptions,options_size);
1304 strlcat(options,",prefixpath=",options_size);
1305 strlcat(options,prefixpath,options_size); /* no need to cat the / */
1308 printf("\nmount.cifs kernel mount options %s \n",options);
1309 if(mount(share_name, mountpoint, "cifs", flags, options)) {
1310 /* remember to kill daemon on error */
1315 printf("mount failed but no error number set\n");
1318 printf("mount error: cifs filesystem not supported by the system\n");
1324 while (*tmp && !(((unsigned char)tmp[0]) & 0x80)) {
1325 *tmp = toupper((unsigned char)*tmp);
1329 printf("retrying with upper case share name\n");
1334 printf("mount error %d = %s\n",errno,strerror(errno));
1336 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
1340 pmntfile = setmntent(MOUNTED, "a+");
1342 mountent.mnt_fsname = share_name;
1343 mountent.mnt_dir = mountpoint;
1344 mountent.mnt_type = CONST_DISCARD(char *,"cifs");
1345 mountent.mnt_opts = (char *)malloc(220);
1346 if(mountent.mnt_opts) {
1347 char * mount_user = getusername();
1348 memset(mountent.mnt_opts,0,200);
1349 if(flags & MS_RDONLY)
1350 strlcat(mountent.mnt_opts,"ro",220);
1352 strlcat(mountent.mnt_opts,"rw",220);
1353 if(flags & MS_MANDLOCK)
1354 strlcat(mountent.mnt_opts,",mand",220);
1355 if(flags & MS_NOEXEC)
1356 strlcat(mountent.mnt_opts,",noexec",220);
1357 if(flags & MS_NOSUID)
1358 strlcat(mountent.mnt_opts,",nosuid",220);
1359 if(flags & MS_NODEV)
1360 strlcat(mountent.mnt_opts,",nodev",220);
1361 if(flags & MS_SYNCHRONOUS)
1362 strlcat(mountent.mnt_opts,",synch",220);
1365 strlcat(mountent.mnt_opts,",user=",220);
1366 strlcat(mountent.mnt_opts,mount_user,220);
1368 /* free(mount_user); do not free static mem */
1371 mountent.mnt_freq = 0;
1372 mountent.mnt_passno = 0;
1373 rc = addmntent(pmntfile,&mountent);
1374 endmntent(pmntfile);
1375 if(mountent.mnt_opts)
1376 free(mountent.mnt_opts);
1378 printf("could not update mount table\n");
1384 int len = strlen(mountpassword);
1385 memset(mountpassword,0,len);
1386 free(mountpassword);
1390 memset(options,0,optlen);
1395 memset(orgoptions,0,orgoptlen);
1399 free(resolved_path);
1402 if(free_share_name) {