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 2 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, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
29 #include <sys/types.h>
30 #include <sys/mount.h>
32 #include <sys/utsname.h>
33 #include <sys/socket.h>
34 #include <arpa/inet.h>
42 #define MOUNT_CIFS_VERSION_MAJOR "1"
43 #define MOUNT_CIFS_VERSION_MINOR "10"
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\tdirectio,mapchars,nomapchars,nolock,servernetbiosname=<SRV_RFC1001NAME>");
140 printf("\n\nOptions not needed for servers supporting CIFS Unix extensions");
141 printf("\n\t(e.g. unneeded for mounts to most Samba versions):");
142 printf("\n\tuid=<uid>,gid=<gid>,dir_mode=<mode>,file_mode=<mode>,sfu");
143 printf("\n\nRarely used options:");
144 printf("\n\tport=<tcpport>,rsize=<size>,wsize=<size>,unc=<unc_name>,ip=<ip_address>,");
145 printf("\n\tdev,nodev,nouser_xattr,netbiosname=<OUR_RFC1001NAME>,hard,soft,intr,");
146 printf("\n\tnointr,ignorecase,noposixpaths,noacl");
147 printf("\n\nOptions are described in more detail in the manual page");
148 printf("\n\tman 8 mount.cifs\n");
149 printf("\nTo display the version number of the mount helper:");
150 printf("\n\t%s -V\n",thisprogram);
153 memset(mountpassword,0,64);
159 /* caller frees username if necessary */
160 static char * getusername(void) {
161 char *username = NULL;
162 struct passwd *password = getpwuid(getuid());
165 username = password->pw_name;
170 static char * parse_cifs_url(char * unc_name)
172 printf("\nMounting cifs URL not implemented yet. Attempt to mount %s\n",unc_name);
176 static int open_cred_file(char * file_name)
182 fs = fopen(file_name,"r");
185 line_buf = (char *)malloc(4096);
186 if(line_buf == NULL) {
191 while(fgets(line_buf,4096,fs)) {
192 /* parse line from credential file */
194 /* eat leading white space */
195 for(i=0;i<4086;i++) {
196 if((line_buf[i] != ' ') && (line_buf[i] != '\t'))
198 /* if whitespace - skip past it */
200 if (strncasecmp("username",line_buf+i,8) == 0) {
201 temp_val = strchr(line_buf + i,'=');
203 /* go past equals sign */
205 for(length = 0;length<4087;length++) {
206 if(temp_val[length] == '\n')
210 printf("mount.cifs failed due to malformed username in credentials file");
211 memset(line_buf,0,4096);
213 memset(mountpassword,0,64);
218 user_name = (char *)calloc(1 + length,1);
219 /* BB adding free of user_name string before exit,
220 not really necessary but would be cleaner */
221 strncpy(user_name,temp_val, length);
224 } else if (strncasecmp("password",line_buf+i,8) == 0) {
225 temp_val = strchr(line_buf+i,'=');
227 /* go past equals sign */
229 for(length = 0;length<65;length++) {
230 if(temp_val[length] == '\n')
234 printf("mount.cifs failed: password in credentials file too long\n");
235 memset(line_buf,0, 4096);
237 memset(mountpassword,0,64);
241 if(mountpassword == NULL) {
242 mountpassword = (char *)calloc(65,1);
244 memset(mountpassword,0,64);
246 strncpy(mountpassword,temp_val,length);
251 } else if (strncasecmp("domain",line_buf+i,6) == 0) {
252 temp_val = strchr(line_buf+i,'=');
254 /* go past equals sign */
257 printf("\nDomain %s\n",temp_val);
258 for(length = 0;length<65;length++) {
259 if(temp_val[length] == '\n')
263 printf("mount.cifs failed: domain in credentials file too long\n");
265 memset(mountpassword,0,64);
269 if(domain_name == NULL) {
270 domain_name = (char *)calloc(65,1);
272 memset(domain_name,0,64);
274 strncpy(domain_name,temp_val,length);
284 memset(line_buf,0,4096);
290 static int get_password_from_file(int file_descript, char * filename)
296 if(mountpassword == NULL)
297 mountpassword = (char *)calloc(65,1);
299 memset(mountpassword, 0, 64);
301 if (mountpassword == NULL) {
302 printf("malloc failed\n");
306 if(filename != NULL) {
307 file_descript = open(filename, O_RDONLY);
308 if(file_descript < 0) {
309 printf("mount.cifs failed. %s attempting to open password file %s\n",
310 strerror(errno),filename);
314 /* else file already open and fd provided */
317 rc = read(file_descript,&c,1);
319 printf("mount.cifs failed. Error %s reading password file\n",strerror(errno));
320 memset(mountpassword,0,64);
322 close(file_descript);
325 if(mountpassword[0] == 0) {
327 printf("\nWarning: null password used since cifs password file empty");
330 } else /* read valid character */ {
331 if((c == 0) || (c == '\n')) {
334 mountpassword[i] = c;
337 if((i == 64) && (verboseflag)) {
338 printf("\nWarning: password longer than 64 characters specified in cifs password file");
341 if(filename != NULL) {
342 close(file_descript);
348 static int parse_options(char ** optionsp, int * filesys_flags)
351 char * percent_char = NULL;
353 char * next_keyword = NULL;
361 if (!optionsp || !*optionsp)
366 printf("parsing options: %s\n", data);
368 /* BB fixme check for separator override BB */
372 snprintf(user,sizeof(user),"%u",getuid());
374 snprintf(group,sizeof(group),"%u",getgid());
377 /* while ((data = strsep(&options, ",")) != NULL) { */
378 while(data != NULL) {
379 /* check if ends with trailing comma */
383 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
384 /* data = next keyword */
385 /* value = next value ie stuff after equal sign */
387 next_keyword = strchr(data,','); /* BB handle sep= */
389 /* temporarily null terminate end of keyword=value pair */
393 /* temporarily null terminate keyword to make keyword and value distinct */
394 if ((value = strchr(data, '=')) != NULL) {
399 if (strncmp(data, "users",5) == 0) {
400 if(!value || !*value) {
403 } else if (strncmp(data, "user_xattr",10) == 0) {
404 /* do nothing - need to skip so not parsed as user name */
405 } else if (strncmp(data, "user", 4) == 0) {
407 if (!value || !*value) {
408 if(data[4] == '\0') {
410 printf("\nskipping empty user mount parameter\n");
411 /* remove the parm since it would otherwise be confusing
412 to the kernel code which would think it was a real username */
415 printf("username specified with no parameter\n");
416 return 1; /* needs_arg; */
419 if (strnlen(value, 260) < 260) {
421 percent_char = strchr(value,'%');
424 if(mountpassword == NULL)
425 mountpassword = (char *)calloc(65,1);
428 printf("\nmount.cifs warning - password specified twice\n");
431 strncpy(mountpassword, percent_char,64);
432 /* remove password from username */
433 while(*percent_char != 0) {
439 /* this is only case in which the user
440 name buf is not malloc - so we have to
441 check for domain name embedded within
442 the user name here since the later
443 call to check_for_domain will not be
445 domain_name = check_for_domain(&value);
447 printf("username too long\n");
451 } else if (strncmp(data, "pass", 4) == 0) {
452 if (!value || !*value) {
454 printf("\npassword specified twice, ignoring second\n");
457 } else if (strnlen(value, 17) < 17) {
459 printf("\nmount.cifs warning - password specified twice\n");
462 printf("password too long\n");
465 } else if (strncmp(data, "sec", 3) == 0) {
467 if (!strcmp(value, "none"))
470 } else if (strncmp(data, "ip", 2) == 0) {
471 if (!value || !*value) {
472 printf("target ip address argument missing");
473 } else if (strnlen(value, 35) < 35) {
475 printf("ip address %s override specified\n",value);
478 printf("ip address too long\n");
481 } else if ((strncmp(data, "unc", 3) == 0)
482 || (strncmp(data, "target", 6) == 0)
483 || (strncmp(data, "path", 4) == 0)) {
484 if (!value || !*value) {
485 printf("invalid path to network resource\n");
486 return 1; /* needs_arg; */
487 } else if(strnlen(value,5) < 5) {
488 printf("UNC name too short");
491 if (strnlen(value, 300) < 300) {
493 if (strncmp(value, "//", 2) == 0) {
495 printf("unc name specified twice, ignoring second\n");
498 } else if (strncmp(value, "\\\\", 2) != 0) {
499 printf("UNC Path does not begin with // or \\\\ \n");
503 printf("unc name specified twice, ignoring second\n");
508 printf("CIFS: UNC name too long\n");
511 } else if ((strncmp(data, "domain", 3) == 0)
512 || (strncmp(data, "workgroup", 5) == 0)) {
513 if (!value || !*value) {
514 printf("CIFS: invalid domain name\n");
515 return 1; /* needs_arg; */
517 if (strnlen(value, 65) < 65) {
520 printf("domain name too long\n");
523 } else if (strncmp(data, "cred", 4) == 0) {
524 if (value && *value) {
525 rc = open_cred_file(value);
527 printf("error %d opening credential file %s\n",rc, value);
531 printf("invalid credential file name specified\n");
534 } else if (strncmp(data, "uid", 3) == 0) {
535 if (value && *value) {
537 if (!isdigit(*value)) {
540 if (!(pw = getpwnam(value))) {
541 printf("bad user name \"%s\"\n", value);
544 snprintf(user, sizeof(user), "%u", pw->pw_uid);
547 strlcpy(user,value,sizeof(user));
551 } else if (strncmp(data, "gid", 3) == 0) {
552 if (value && *value) {
554 if (!isdigit(*value)) {
557 if (!(gr = getgrnam(value))) {
558 printf("bad group name \"%s\"\n", value);
561 snprintf(group, sizeof(group), "%u", gr->gr_gid);
564 strlcpy(group,value,sizeof(group));
568 /* fmask and dmask synonyms for people used to smbfs syntax */
569 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
570 if (!value || !*value) {
571 printf ("Option '%s' requires a numerical argument\n", data);
575 if (value[0] != '0') {
576 printf ("WARNING: '%s' not expressed in octal.\n", data);
579 if (strcmp (data, "fmask") == 0) {
580 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
581 data = "file_mode"; /* BB fix this */
583 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
584 if (!value || !*value) {
585 printf ("Option '%s' requires a numerical argument\n", data);
589 if (value[0] != '0') {
590 printf ("WARNING: '%s' not expressed in octal.\n", data);
593 if (strcmp (data, "dmask") == 0) {
594 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
597 /* the following eight mount options should be
598 stripped out from what is passed into the kernel
599 since these eight options are best passed as the
600 mount flags rather than redundantly to the kernel
601 and could generate spurious warnings depending on the
602 level of the corresponding cifs vfs kernel code */
603 } else if (strncmp(data, "nosuid", 6) == 0) {
604 *filesys_flags |= MS_NOSUID;
605 } else if (strncmp(data, "suid", 4) == 0) {
606 *filesys_flags &= ~MS_NOSUID;
607 } else if (strncmp(data, "nodev", 5) == 0) {
608 *filesys_flags |= MS_NODEV;
609 } else if ((strncmp(data, "nobrl", 5) == 0) ||
610 (strncmp(data, "nolock", 6) == 0)) {
611 *filesys_flags &= ~MS_MANDLOCK;
612 } else if (strncmp(data, "dev", 3) == 0) {
613 *filesys_flags &= ~MS_NODEV;
614 } else if (strncmp(data, "noexec", 6) == 0) {
615 *filesys_flags |= MS_NOEXEC;
616 } else if (strncmp(data, "exec", 4) == 0) {
617 *filesys_flags &= ~MS_NOEXEC;
618 } else if (strncmp(data, "guest", 5) == 0) {
620 } else if (strncmp(data, "ro", 2) == 0) {
621 *filesys_flags |= MS_RDONLY;
622 } else if (strncmp(data, "rw", 2) == 0) {
623 *filesys_flags &= ~MS_RDONLY;
624 } else if (strncmp(data, "remount", 7) == 0) {
625 *filesys_flags |= MS_REMOUNT;
626 } /* else if (strnicmp(data, "port", 4) == 0) {
627 if (value && *value) {
629 simple_strtoul(value, &value, 0);
631 } else if (strnicmp(data, "rsize", 5) == 0) {
632 if (value && *value) {
634 simple_strtoul(value, &value, 0);
636 } else if (strnicmp(data, "wsize", 5) == 0) {
637 if (value && *value) {
639 simple_strtoul(value, &value, 0);
641 } else if (strnicmp(data, "version", 3) == 0) {
643 printf("CIFS: Unknown mount option %s\n",data);
644 } */ /* nothing to do on those four mount options above.
645 Just pass to kernel and ignore them here */
647 /* Copy (possibly modified) option to out */
648 word_len = strlen(data);
650 word_len += 1 + strlen(value);
652 out = (char *)realloc(out, out_len + word_len + 2);
659 strlcat(out, ",", out_len + word_len + 2);
664 snprintf(out + out_len, word_len + 1, "%s=%s", data, value);
666 snprintf(out + out_len, word_len + 1, "%s", data);
667 out_len = strlen(out);
673 /* special-case the uid and gid */
675 word_len = strlen(user);
677 out = (char *)realloc(out, out_len + word_len + 6);
684 strlcat(out, ",", out_len + word_len + 6);
687 snprintf(out + out_len, word_len + 5, "uid=%s", user);
688 out_len = strlen(out);
691 word_len = strlen(group);
693 out = (char *)realloc(out, out_len + 1 + word_len + 6);
700 strlcat(out, ",", out_len + word_len + 6);
703 snprintf(out + out_len, word_len + 5, "gid=%s", group);
704 out_len = strlen(out);
712 /* replace all (one or more) commas with double commas */
713 static void check_for_comma(char ** ppasswrd)
718 int number_of_commas = 0;
733 if(number_of_commas == 0)
735 if(number_of_commas > 64) {
736 /* would otherwise overflow the mount options buffer */
737 printf("\nInvalid password. Password contains too many commas.\n");
741 new_pass_buf = (char *)malloc(len+number_of_commas+1);
742 if(new_pass_buf == NULL)
745 for(i=0,j=0;i<len;i++,j++) {
746 new_pass_buf[j] = pass[i];
749 new_pass_buf[j] = pass[i];
752 new_pass_buf[len+number_of_commas] = 0;
755 *ppasswrd = new_pass_buf;
760 /* Usernames can not have backslash in them and we use
761 [BB check if usernames can have forward slash in them BB]
762 backslash as domain\user separator character
764 static char * check_for_domain(char **ppuser)
766 char * original_string;
776 original_string = *ppuser;
778 if (original_string == NULL)
781 original_len = strlen(original_string);
783 usernm = strchr(*ppuser,'/');
784 if (usernm == NULL) {
785 usernm = strchr(*ppuser,'\\');
791 printf("Domain name specified twice. Username probably malformed\n");
797 if (domainnm[0] != 0) {
800 printf("null domain\n");
802 len = strlen(domainnm);
803 /* reset domainm to new buffer, and copy
804 domain name into it */
805 domainnm = (char *)malloc(len+1);
809 strlcpy(domainnm,*ppuser,len+1);
811 /* move_string(*ppuser, usernm+1) */
812 len = strlen(usernm+1);
814 if(len >= original_len) {
815 /* should not happen */
819 for(i=0;i<original_len;i++) {
821 original_string[i] = usernm[i+1];
822 else /* stuff with commas to remove last parm */
823 original_string[i] = ',';
826 /* BB add check for more than one slash?
834 /* Note that caller frees the returned buffer if necessary */
835 static char * parse_server(char ** punc_name)
837 char * unc_name = *punc_name;
838 int length = strnlen(unc_name,1024);
840 char * ipaddress_string = NULL;
841 struct hostent * host_entry = NULL;
842 struct in_addr server_ipaddr;
845 printf("mount error: UNC name too long");
848 if (strncasecmp("cifs://",unc_name,7) == 0)
849 return parse_cifs_url(unc_name+7);
850 if (strncasecmp("smb://",unc_name,6) == 0) {
851 return parse_cifs_url(unc_name+6);
855 /* BB add code to find DFS root here */
856 printf("\nMounting the DFS root for domain not implemented yet\n");
859 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
860 /* check for nfs syntax ie server:share */
861 share = strchr(unc_name,':');
864 *punc_name = (char *)malloc(length+3);
865 if(*punc_name == NULL) {
866 /* put the original string back if
868 *punc_name = unc_name;
873 strncpy((*punc_name)+2,unc_name,length);
874 unc_name = *punc_name;
875 unc_name[length+2] = 0;
876 goto continue_unc_parsing;
878 printf("mount error: improperly formatted UNC name.");
879 printf(" %s does not begin with \\\\ or //\n",unc_name);
883 continue_unc_parsing:
887 if ((share = strchr(unc_name, '/')) ||
888 (share = strchr(unc_name,'\\'))) {
889 *share = 0; /* temporarily terminate the string */
892 host_entry = gethostbyname(unc_name);
894 *(share - 1) = '/'; /* put the slash back */
895 if ((prefixpath = strchr(share, '/'))) {
896 *prefixpath = 0; /* permanently terminate the string */
897 if (!strlen(++prefixpath))
898 prefixpath = NULL; /* this needs to be done explicitly */
902 printf("ip address specified explicitly\n");
905 if(host_entry == NULL) {
906 printf("mount error: could not find target server. TCP name %s not found\n", unc_name);
909 /* BB should we pass an alternate version of the share name as Unicode */
910 /* BB what about ipv6? BB */
911 /* BB add retries with alternate servers in list */
913 memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
915 ipaddress_string = inet_ntoa(server_ipaddr);
916 if(ipaddress_string == NULL) {
917 printf("mount error: could not get valid ip address for target server\n");
920 return ipaddress_string;
923 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
924 printf("Mounting the DFS root for a particular server not implemented yet\n");
931 static struct option longopts[] = {
932 { "all", 0, NULL, 'a' },
933 { "help",0, NULL, 'h' },
934 { "move",0, NULL, 'm' },
935 { "bind",0, NULL, 'b' },
936 { "read-only", 0, NULL, 'r' },
937 { "ro", 0, NULL, 'r' },
938 { "verbose", 0, NULL, 'v' },
939 { "version", 0, NULL, 'V' },
940 { "read-write", 0, NULL, 'w' },
941 { "rw", 0, NULL, 'w' },
942 { "options", 1, NULL, 'o' },
943 { "type", 1, NULL, 't' },
944 { "rsize",1, NULL, 'R' },
945 { "wsize",1, NULL, 'W' },
946 { "uid", 1, NULL, '1'},
947 { "gid", 1, NULL, '2'},
948 { "user",1,NULL,'u'},
949 { "username",1,NULL,'u'},
951 { "domain",1,NULL,'d'},
952 { "password",1,NULL,'p'},
953 { "pass",1,NULL,'p'},
954 { "credentials",1,NULL,'c'},
955 { "port",1,NULL,'P'},
956 /* { "uuid",1,NULL,'U'}, */ /* BB unimplemented */
960 int main(int argc, char ** argv)
963 int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
964 char * orgoptions = NULL;
965 char * share_name = NULL;
966 char * ipaddr = NULL;
968 char * mountpoint = NULL;
969 char * options = NULL;
970 char * resolved_path = NULL;
980 size_t options_size = 0;
981 int retry = 0; /* set when we have to retry mount with uppercase */
983 struct utsname sysinfo;
984 struct mntent mountent;
987 /* setlocale(LC_ALL, "");
988 bindtextdomain(PACKAGE, LOCALEDIR);
989 textdomain(PACKAGE); */
992 thisprogram = argv[0];
998 if(thisprogram == NULL)
999 thisprogram = "mount.cifs";
1002 /* BB add workstation name and domain and pass down */
1004 /* #ifdef _GNU_SOURCE
1005 printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
1008 share_name = argv[1];
1009 mountpoint = argv[2];
1012 /* add sharename in opts string as unc= parm */
1014 while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
1015 longopts, NULL)) != -1) {
1017 /* No code to do the following options yet */
1019 list_with_volumelabel = 1;
1022 volumelabel = optarg;
1029 case 'h': /* help */
1030 mount_cifs_usage ();
1040 "option 'b' (MS_BIND) not supported\n");
1048 "option 'm' (MS_MOVE) not supported\n");
1052 orgoptions = strdup(optarg);
1054 case 'r': /* mount readonly */
1064 printf ("mount.cifs version: %s.%s%s\n",
1065 MOUNT_CIFS_VERSION_MAJOR,
1066 MOUNT_CIFS_VERSION_MINOR,
1067 MOUNT_CIFS_VENDOR_SUFFIX);
1069 memset(mountpassword,0,64);
1073 flags &= ~MS_RDONLY;
1076 rsize = atoi(optarg) ;
1079 wsize = atoi(optarg);
1082 if (isdigit(*optarg)) {
1085 uid = strtoul(optarg, &ep, 10);
1087 printf("bad uid value \"%s\"\n", optarg);
1093 if (!(pw = getpwnam(optarg))) {
1094 printf("bad user name \"%s\"\n", optarg);
1102 if (isdigit(*optarg)) {
1105 gid = strtoul(optarg, &ep, 10);
1107 printf("bad gid value \"%s\"\n", optarg);
1113 if (!(gr = getgrnam(optarg))) {
1114 printf("bad user name \"%s\"\n", optarg);
1126 domain_name = optarg; /* BB fix this - currently ignored */
1130 if(mountpassword == NULL)
1131 mountpassword = (char *)calloc(65,1);
1134 strncpy(mountpassword,optarg,64);
1138 get_password_from_file(0 /* stdin */,NULL);
1143 printf("unknown mount option %c\n",c);
1149 if((argc < 3) || (share_name == NULL) || (mountpoint == NULL)) {
1154 if (getenv("PASSWD")) {
1155 if(mountpassword == NULL)
1156 mountpassword = (char *)calloc(65,1);
1158 strncpy(mountpassword,getenv("PASSWD"),64);
1161 } else if (getenv("PASSWD_FD")) {
1162 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
1163 } else if (getenv("PASSWD_FILE")) {
1164 get_password_from_file(0, getenv("PASSWD_FILE"));
1167 if (orgoptions && parse_options(&orgoptions, &flags)) {
1171 ipaddr = parse_server(&share_name);
1172 if((ipaddr == NULL) && (got_ip == 0)) {
1173 printf("No ip address specified and hostname not found\n");
1178 /* BB save off path and pop after mount returns? */
1179 resolved_path = (char *)malloc(PATH_MAX+1);
1181 /* Note that if we can not canonicalize the name, we get
1182 another chance to see if it is valid when we chdir to it */
1183 if (realpath(mountpoint, resolved_path)) {
1184 mountpoint = resolved_path;
1187 if(chdir(mountpoint)) {
1188 printf("mount error: can not change directory into mount target %s\n",mountpoint);
1193 if(stat (".", &statbuf)) {
1194 printf("mount error: mount point %s does not exist\n",mountpoint);
1199 if (S_ISDIR(statbuf.st_mode) == 0) {
1200 printf("mount error: mount point %s is not a directory\n",mountpoint);
1205 if((getuid() != 0) && (geteuid() == 0)) {
1206 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
1207 #ifndef CIFS_ALLOW_USR_SUID
1208 /* Do not allow user mounts to control suid flag
1209 for mount unless explicitly built that way */
1210 flags |= MS_NOSUID | MS_NODEV;
1213 printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n");
1219 user_name = getusername();
1223 if(got_password == 0) {
1224 mountpassword = getpass("Password: "); /* BB obsolete */
1227 /* FIXME launch daemon (handles dfs name resolution and credential change)
1228 remember to clear parms and overwrite password field before launching */
1231 optlen = strlen(orgoptions);
1236 optlen += strlen(share_name) + 4;
1238 printf("No server share name specified\n");
1239 printf("\nMounting the DFS root for server not implemented yet\n");
1243 optlen += strlen(user_name) + 6;
1245 optlen += strlen(ipaddr) + 4;
1247 optlen += strlen(mountpassword) + 6;
1250 options_size = optlen + 10 + 64;
1251 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 */);
1253 if(options == NULL) {
1254 printf("Could not allocate memory for mount options\n");
1259 strlcpy(options,"unc=",options_size);
1260 strlcat(options,share_name,options_size);
1261 /* scan backwards and reverse direction of slash */
1262 temp = strrchr(options, '/');
1263 if(temp > options + 6)
1266 strlcat(options,",ip=",options_size);
1267 strlcat(options,ipaddr,options_size);
1271 /* check for syntax like user=domain\user */
1273 domain_name = check_for_domain(&user_name);
1274 strlcat(options,",user=",options_size);
1275 strlcat(options,user_name,options_size);
1279 /* extra length accounted for in option string above */
1280 strlcat(options,",domain=",options_size);
1281 strlcat(options,domain_name,options_size);
1285 /* Commas have to be doubled, or else they will
1286 look like the parameter separator */
1287 /* if(sep is not set)*/
1289 check_for_comma(&mountpassword);
1290 strlcat(options,",pass=",options_size);
1291 strlcat(options,mountpassword,options_size);
1294 strlcat(options,",ver=",options_size);
1295 strlcat(options,MOUNT_CIFS_VERSION_MAJOR,options_size);
1298 strlcat(options,",",options_size);
1299 strlcat(options,orgoptions,options_size);
1302 strlcat(options,",prefixpath=",options_size);
1303 strlcat(options,prefixpath,options_size); /* no need to cat the / */
1306 printf("\nmount.cifs kernel mount options %s \n",options);
1307 if(mount(share_name, mountpoint, "cifs", flags, options)) {
1308 /* remember to kill daemon on error */
1313 printf("mount failed but no error number set\n");
1316 printf("mount error: cifs filesystem not supported by the system\n");
1322 while (*tmp && !(((unsigned char)tmp[0]) & 0x80)) {
1323 *tmp = toupper((unsigned char)*tmp);
1327 printf("retrying with upper case share name\n");
1332 printf("mount error %d = %s\n",errno,strerror(errno));
1334 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
1338 pmntfile = setmntent(MOUNTED, "a+");
1340 mountent.mnt_fsname = share_name;
1341 mountent.mnt_dir = mountpoint;
1342 mountent.mnt_type = CONST_DISCARD(char *,"cifs");
1343 mountent.mnt_opts = (char *)malloc(220);
1344 if(mountent.mnt_opts) {
1345 char * mount_user = getusername();
1346 memset(mountent.mnt_opts,0,200);
1347 if(flags & MS_RDONLY)
1348 strlcat(mountent.mnt_opts,"ro",220);
1350 strlcat(mountent.mnt_opts,"rw",220);
1351 if(flags & MS_MANDLOCK)
1352 strlcat(mountent.mnt_opts,",mand",220);
1353 if(flags & MS_NOEXEC)
1354 strlcat(mountent.mnt_opts,",noexec",220);
1355 if(flags & MS_NOSUID)
1356 strlcat(mountent.mnt_opts,",nosuid",220);
1357 if(flags & MS_NODEV)
1358 strlcat(mountent.mnt_opts,",nodev",220);
1359 if(flags & MS_SYNCHRONOUS)
1360 strlcat(mountent.mnt_opts,",synch",220);
1363 strlcat(mountent.mnt_opts,",user=",220);
1364 strlcat(mountent.mnt_opts,mount_user,220);
1366 /* free(mount_user); do not free static mem */
1369 mountent.mnt_freq = 0;
1370 mountent.mnt_passno = 0;
1371 rc = addmntent(pmntfile,&mountent);
1372 endmntent(pmntfile);
1373 if(mountent.mnt_opts)
1374 free(mountent.mnt_opts);
1376 printf("could not update mount table\n");
1382 int len = strlen(mountpassword);
1383 memset(mountpassword,0,len);
1384 free(mountpassword);
1388 memset(options,0,optlen);
1393 memset(orgoptions,0,orgoptlen);
1397 free(resolved_path);
1400 if(free_share_name) {