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>
41 #define MOUNT_CIFS_VERSION_MAJOR "1"
42 #define MOUNT_CIFS_VERSION_MINOR "10"
44 #ifndef MOUNT_CIFS_VENDOR_SUFFIX
46 #include "include/version.h"
47 #ifdef SAMBA_VERSION_VENDOR_SUFFIX
48 #define MOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING"-"SAMBA_VERSION_VENDOR_SUFFIX
50 #define MOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING
51 #endif /* SAMBA_VERSION_OFFICIAL_STRING and SAMBA_VERSION_VENDOR_SUFFIX */
53 #define MOUNT_CIFS_VENDOR_SUFFIX ""
54 #endif /* _SAMBA_BUILD_ */
55 #endif /* MOUNT_CIFS_VENDOR_SUFFIX */
65 #define CONST_DISCARD(type, ptr) ((type) ((void *) (ptr)))
67 const char *thisprogram;
69 static int got_password = 0;
70 static int got_user = 0;
71 static int got_domain = 0;
72 static int got_ip = 0;
73 static int got_unc = 0;
74 static int got_uid = 0;
75 static int got_gid = 0;
76 static int free_share_name = 0;
77 static char * user_name = NULL;
78 static char * mountpassword = NULL;
79 char * domain_name = NULL;
80 char * prefixpath = NULL;
82 /* glibc doesn't have strlcpy, strlcat. Ensure we do. JRA. We
83 * don't link to libreplace so need them here. */
85 /* like strncpy but does not 0 fill the buffer and always null
86 * terminates. bufsize is the size of the destination buffer */
87 size_t strlcpy(char *d, const char *s, size_t bufsize)
89 size_t len = strlen(s);
91 if (bufsize <= 0) return 0;
92 if (len >= bufsize) len = bufsize-1;
98 /* like strncat but does not 0 fill the buffer and always null
99 * terminates. bufsize is the length of the buffer, which should
100 * be one more than the maximum resulting string length */
101 size_t strlcat(char *d, const char *s, size_t bufsize)
103 size_t len1 = strlen(d);
104 size_t len2 = strlen(s);
105 size_t ret = len1 + len2;
107 if (len1+len2 >= bufsize) {
108 len2 = bufsize - (len1+1);
111 memcpy(d+len1, s, len2);
120 open nofollow - avoid symlink exposure?
121 get owner of dir see if matches self or if root
122 call system(umount argv) etc.
126 static char * check_for_domain(char **);
129 static void mount_cifs_usage(void)
131 printf("\nUsage: %s <remotetarget> <dir> -o <options>\n", thisprogram);
132 printf("\nMount the remote target, specified as a UNC name,");
133 printf(" to a local directory.\n\nOptions:\n");
134 printf("\tuser=<arg>\n\tpass=<arg>\n\tdom=<arg>\n");
135 printf("\nLess commonly used options:");
136 printf("\n\tcredentials=<filename>,guest,perm,noperm,setuids,nosetuids,rw,ro,");
137 printf("\n\tsep=<char>,iocharset=<codepage>,suid,nosuid,exec,noexec,serverino,");
138 printf("\n\tdirectio,mapchars,nomapchars,nolock,servernetbiosname=<SRV_RFC1001NAME>");
139 printf("\n\nOptions not needed for servers supporting CIFS Unix extensions");
140 printf("\n\t(e.g. unneeded for mounts to most Samba versions):");
141 printf("\n\tuid=<uid>,gid=<gid>,dir_mode=<mode>,file_mode=<mode>,sfu");
142 printf("\n\nRarely used options:");
143 printf("\n\tport=<tcpport>,rsize=<size>,wsize=<size>,unc=<unc_name>,ip=<ip_address>,");
144 printf("\n\tdev,nodev,nouser_xattr,netbiosname=<OUR_RFC1001NAME>,hard,soft,intr,");
145 printf("\n\tnointr,ignorecase,noposixpaths,noacl");
146 printf("\n\nOptions are described in more detail in the manual page");
147 printf("\n\tman 8 mount.cifs\n");
148 printf("\nTo display the version number of the mount helper:");
149 printf("\n\t%s -V\n",thisprogram);
152 memset(mountpassword,0,64);
158 /* caller frees username if necessary */
159 static char * getusername(void) {
160 char *username = NULL;
161 struct passwd *password = getpwuid(getuid());
164 username = password->pw_name;
169 static char * parse_cifs_url(char * unc_name)
171 printf("\nMounting cifs URL not implemented yet. Attempt to mount %s\n",unc_name);
175 static int open_cred_file(char * file_name)
181 fs = fopen(file_name,"r");
184 line_buf = (char *)malloc(4096);
185 if(line_buf == NULL) {
190 while(fgets(line_buf,4096,fs)) {
191 /* parse line from credential file */
193 /* eat leading white space */
194 for(i=0;i<4086;i++) {
195 if((line_buf[i] != ' ') && (line_buf[i] != '\t'))
197 /* if whitespace - skip past it */
199 if (strncasecmp("username",line_buf+i,8) == 0) {
200 temp_val = strchr(line_buf + i,'=');
202 /* go past equals sign */
204 for(length = 0;length<4087;length++) {
205 if(temp_val[length] == '\n')
209 printf("mount.cifs failed due to malformed username in credentials file");
210 memset(line_buf,0,4096);
212 memset(mountpassword,0,64);
217 user_name = (char *)calloc(1 + length,1);
218 /* BB adding free of user_name string before exit,
219 not really necessary but would be cleaner */
220 strncpy(user_name,temp_val, length);
223 } else if (strncasecmp("password",line_buf+i,8) == 0) {
224 temp_val = strchr(line_buf+i,'=');
226 /* go past equals sign */
228 for(length = 0;length<65;length++) {
229 if(temp_val[length] == '\n')
233 printf("mount.cifs failed: password in credentials file too long\n");
234 memset(line_buf,0, 4096);
236 memset(mountpassword,0,64);
240 if(mountpassword == NULL) {
241 mountpassword = (char *)calloc(65,1);
243 memset(mountpassword,0,64);
245 strncpy(mountpassword,temp_val,length);
250 } else if (strncasecmp("domain",line_buf+i,6) == 0) {
251 temp_val = strchr(line_buf+i,'=');
253 /* go past equals sign */
256 printf("\nDomain %s\n",temp_val);
257 for(length = 0;length<65;length++) {
258 if(temp_val[length] == '\n')
262 printf("mount.cifs failed: domain in credentials file too long\n");
264 memset(mountpassword,0,64);
268 if(domain_name == NULL) {
269 domain_name = (char *)calloc(65,1);
271 memset(domain_name,0,64);
273 strncpy(domain_name,temp_val,length);
283 memset(line_buf,0,4096);
289 static int get_password_from_file(int file_descript, char * filename)
295 if(mountpassword == NULL)
296 mountpassword = (char *)calloc(65,1);
298 memset(mountpassword, 0, 64);
300 if (mountpassword == NULL) {
301 printf("malloc failed\n");
305 if(filename != NULL) {
306 file_descript = open(filename, O_RDONLY);
307 if(file_descript < 0) {
308 printf("mount.cifs failed. %s attempting to open password file %s\n",
309 strerror(errno),filename);
313 /* else file already open and fd provided */
316 rc = read(file_descript,&c,1);
318 printf("mount.cifs failed. Error %s reading password file\n",strerror(errno));
319 memset(mountpassword,0,64);
321 close(file_descript);
324 if(mountpassword[0] == 0) {
326 printf("\nWarning: null password used since cifs password file empty");
329 } else /* read valid character */ {
330 if((c == 0) || (c == '\n')) {
333 mountpassword[i] = c;
336 if((i == 64) && (verboseflag)) {
337 printf("\nWarning: password longer than 64 characters specified in cifs password file");
340 if(filename != NULL) {
341 close(file_descript);
347 static int parse_options(char ** optionsp, int * filesys_flags)
350 char * percent_char = NULL;
352 char * next_keyword = NULL;
360 if (!optionsp || !*optionsp)
365 printf("parsing options: %s\n", data);
367 /* BB fixme check for separator override BB */
371 snprintf(user,sizeof(user),"%u",getuid());
373 snprintf(group,sizeof(group),"%u",getgid());
376 /* while ((data = strsep(&options, ",")) != NULL) { */
377 while(data != NULL) {
378 /* check if ends with trailing comma */
382 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
383 /* data = next keyword */
384 /* value = next value ie stuff after equal sign */
386 next_keyword = strchr(data,','); /* BB handle sep= */
388 /* temporarily null terminate end of keyword=value pair */
392 /* temporarily null terminate keyword to make keyword and value distinct */
393 if ((value = strchr(data, '=')) != NULL) {
398 if (strncmp(data, "users",5) == 0) {
399 if(!value || !*value) {
402 } else if (strncmp(data, "user_xattr",10) == 0) {
403 /* do nothing - need to skip so not parsed as user name */
404 } else if (strncmp(data, "user", 4) == 0) {
406 if (!value || !*value) {
407 if(data[4] == '\0') {
409 printf("\nskipping empty user mount parameter\n");
410 /* remove the parm since it would otherwise be confusing
411 to the kernel code which would think it was a real username */
414 printf("username specified with no parameter\n");
415 return 1; /* needs_arg; */
418 if (strnlen(value, 260) < 260) {
420 percent_char = strchr(value,'%');
423 if(mountpassword == NULL)
424 mountpassword = (char *)calloc(65,1);
427 printf("\nmount.cifs warning - password specified twice\n");
430 strncpy(mountpassword, percent_char,64);
431 /* remove password from username */
432 while(*percent_char != 0) {
438 /* this is only case in which the user
439 name buf is not malloc - so we have to
440 check for domain name embedded within
441 the user name here since the later
442 call to check_for_domain will not be
444 domain_name = check_for_domain(&value);
446 printf("username too long\n");
450 } else if (strncmp(data, "pass", 4) == 0) {
451 if (!value || !*value) {
453 printf("\npassword specified twice, ignoring second\n");
456 } else if (strnlen(value, 17) < 17) {
458 printf("\nmount.cifs warning - password specified twice\n");
461 printf("password too long\n");
464 } else if (strncmp(data, "sec", 3) == 0) {
466 if (!strcmp(value, "none"))
469 } else if (strncmp(data, "ip", 2) == 0) {
470 if (!value || !*value) {
471 printf("target ip address argument missing");
472 } else if (strnlen(value, 35) < 35) {
474 printf("ip address %s override specified\n",value);
477 printf("ip address too long\n");
480 } else if ((strncmp(data, "unc", 3) == 0)
481 || (strncmp(data, "target", 6) == 0)
482 || (strncmp(data, "path", 4) == 0)) {
483 if (!value || !*value) {
484 printf("invalid path to network resource\n");
485 return 1; /* needs_arg; */
486 } else if(strnlen(value,5) < 5) {
487 printf("UNC name too short");
490 if (strnlen(value, 300) < 300) {
492 if (strncmp(value, "//", 2) == 0) {
494 printf("unc name specified twice, ignoring second\n");
497 } else if (strncmp(value, "\\\\", 2) != 0) {
498 printf("UNC Path does not begin with // or \\\\ \n");
502 printf("unc name specified twice, ignoring second\n");
507 printf("CIFS: UNC name too long\n");
510 } else if ((strncmp(data, "domain", 3) == 0)
511 || (strncmp(data, "workgroup", 5) == 0)) {
512 if (!value || !*value) {
513 printf("CIFS: invalid domain name\n");
514 return 1; /* needs_arg; */
516 if (strnlen(value, 65) < 65) {
519 printf("domain name too long\n");
522 } else if (strncmp(data, "cred", 4) == 0) {
523 if (value && *value) {
524 rc = open_cred_file(value);
526 printf("error %d opening credential file %s\n",rc, value);
530 printf("invalid credential file name specified\n");
533 } else if (strncmp(data, "uid", 3) == 0) {
534 if (value && *value) {
536 if (!isdigit(*value)) {
539 if (!(pw = getpwnam(value))) {
540 printf("bad user name \"%s\"\n", value);
543 snprintf(user, sizeof(user), "%u", pw->pw_uid);
545 strlcpy(user,value,sizeof(user));
549 } else if (strncmp(data, "gid", 3) == 0) {
550 if (value && *value) {
552 if (!isdigit(*value)) {
555 if (!(gr = getgrnam(value))) {
556 printf("bad group name \"%s\"\n", value);
559 snprintf(group, sizeof(group), "%u", gr->gr_gid);
561 strlcpy(group,value,sizeof(group));
565 /* fmask and dmask synonyms for people used to smbfs syntax */
566 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
567 if (!value || !*value) {
568 printf ("Option '%s' requires a numerical argument\n", data);
572 if (value[0] != '0') {
573 printf ("WARNING: '%s' not expressed in octal.\n", data);
576 if (strcmp (data, "fmask") == 0) {
577 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
578 data = "file_mode"; /* BB fix this */
580 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
581 if (!value || !*value) {
582 printf ("Option '%s' requires a numerical argument\n", data);
586 if (value[0] != '0') {
587 printf ("WARNING: '%s' not expressed in octal.\n", data);
590 if (strcmp (data, "dmask") == 0) {
591 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
594 /* the following eight mount options should be
595 stripped out from what is passed into the kernel
596 since these eight options are best passed as the
597 mount flags rather than redundantly to the kernel
598 and could generate spurious warnings depending on the
599 level of the corresponding cifs vfs kernel code */
600 } else if (strncmp(data, "nosuid", 6) == 0) {
601 *filesys_flags |= MS_NOSUID;
602 } else if (strncmp(data, "suid", 4) == 0) {
603 *filesys_flags &= ~MS_NOSUID;
604 } else if (strncmp(data, "nodev", 5) == 0) {
605 *filesys_flags |= MS_NODEV;
606 } else if ((strncmp(data, "nobrl", 5) == 0) ||
607 (strncmp(data, "nolock", 6) == 0)) {
608 *filesys_flags &= ~MS_MANDLOCK;
609 } else if (strncmp(data, "dev", 3) == 0) {
610 *filesys_flags &= ~MS_NODEV;
611 } else if (strncmp(data, "noexec", 6) == 0) {
612 *filesys_flags |= MS_NOEXEC;
613 } else if (strncmp(data, "exec", 4) == 0) {
614 *filesys_flags &= ~MS_NOEXEC;
615 } else if (strncmp(data, "guest", 5) == 0) {
617 } else if (strncmp(data, "ro", 2) == 0) {
618 *filesys_flags |= MS_RDONLY;
619 } else if (strncmp(data, "rw", 2) == 0) {
620 *filesys_flags &= ~MS_RDONLY;
621 } else if (strncmp(data, "remount", 7) == 0) {
622 *filesys_flags |= MS_REMOUNT;
623 } /* else if (strnicmp(data, "port", 4) == 0) {
624 if (value && *value) {
626 simple_strtoul(value, &value, 0);
628 } else if (strnicmp(data, "rsize", 5) == 0) {
629 if (value && *value) {
631 simple_strtoul(value, &value, 0);
633 } else if (strnicmp(data, "wsize", 5) == 0) {
634 if (value && *value) {
636 simple_strtoul(value, &value, 0);
638 } else if (strnicmp(data, "version", 3) == 0) {
640 printf("CIFS: Unknown mount option %s\n",data);
641 } */ /* nothing to do on those four mount options above.
642 Just pass to kernel and ignore them here */
644 /* Copy (possibly modified) option to out */
645 word_len = strlen(data);
647 word_len += 1 + strlen(value);
649 out = (char *)realloc(out, out_len + word_len + 2);
656 strlcat(out, ",", out_len + word_len + 2);
661 snprintf(out + out_len, word_len + 1, "%s=%s", data, value);
663 snprintf(out + out_len, word_len + 1, "%s", data);
664 out_len = strlen(out);
670 /* special-case the uid and gid */
672 word_len = strlen(user);
674 out = (char *)realloc(out, out_len + word_len + 6);
681 strlcat(out, ",", out_len + word_len + 6);
684 snprintf(out + out_len, word_len + 5, "uid=%s", user);
685 out_len = strlen(out);
688 word_len = strlen(group);
690 out = (char *)realloc(out, out_len + 1 + word_len + 6);
697 strlcat(out, ",", out_len + word_len + 6);
700 snprintf(out + out_len, word_len + 5, "gid=%s", group);
701 out_len = strlen(out);
709 /* replace all (one or more) commas with double commas */
710 static void check_for_comma(char ** ppasswrd)
715 int number_of_commas = 0;
730 if(number_of_commas == 0)
732 if(number_of_commas > 64) {
733 /* would otherwise overflow the mount options buffer */
734 printf("\nInvalid password. Password contains too many commas.\n");
738 new_pass_buf = (char *)malloc(len+number_of_commas+1);
739 if(new_pass_buf == NULL)
742 for(i=0,j=0;i<len;i++,j++) {
743 new_pass_buf[j] = pass[i];
746 new_pass_buf[j] = pass[i];
749 new_pass_buf[len+number_of_commas] = 0;
752 *ppasswrd = new_pass_buf;
757 /* Usernames can not have backslash in them and we use
758 [BB check if usernames can have forward slash in them BB]
759 backslash as domain\user separator character
761 static char * check_for_domain(char **ppuser)
763 char * original_string;
773 original_string = *ppuser;
775 if (original_string == NULL)
778 original_len = strlen(original_string);
780 usernm = strchr(*ppuser,'/');
781 if (usernm == NULL) {
782 usernm = strchr(*ppuser,'\\');
788 printf("Domain name specified twice. Username probably malformed\n");
794 if (domainnm[0] != 0) {
797 printf("null domain\n");
799 len = strlen(domainnm);
800 /* reset domainm to new buffer, and copy
801 domain name into it */
802 domainnm = (char *)malloc(len+1);
806 strlcpy(domainnm,*ppuser,len+1);
808 /* move_string(*ppuser, usernm+1) */
809 len = strlen(usernm+1);
811 if(len >= original_len) {
812 /* should not happen */
816 for(i=0;i<original_len;i++) {
818 original_string[i] = usernm[i+1];
819 else /* stuff with commas to remove last parm */
820 original_string[i] = ',';
823 /* BB add check for more than one slash?
831 /* Note that caller frees the returned buffer if necessary */
832 static char * parse_server(char ** punc_name)
834 char * unc_name = *punc_name;
835 int length = strnlen(unc_name,1024);
837 char * ipaddress_string = NULL;
838 struct hostent * host_entry = NULL;
839 struct in_addr server_ipaddr;
842 printf("mount error: UNC name too long");
845 if (strncasecmp("cifs://",unc_name,7) == 0)
846 return parse_cifs_url(unc_name+7);
847 if (strncasecmp("smb://",unc_name,6) == 0) {
848 return parse_cifs_url(unc_name+6);
852 /* BB add code to find DFS root here */
853 printf("\nMounting the DFS root for domain not implemented yet\n");
856 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
857 /* check for nfs syntax ie server:share */
858 share = strchr(unc_name,':');
861 *punc_name = (char *)malloc(length+3);
862 if(*punc_name == NULL) {
863 /* put the original string back if
865 *punc_name = unc_name;
870 strncpy((*punc_name)+2,unc_name,length);
871 unc_name = *punc_name;
872 unc_name[length+2] = 0;
873 goto continue_unc_parsing;
875 printf("mount error: improperly formatted UNC name.");
876 printf(" %s does not begin with \\\\ or //\n",unc_name);
880 continue_unc_parsing:
884 if ((share = strchr(unc_name, '/')) ||
885 (share = strchr(unc_name,'\\'))) {
886 *share = 0; /* temporarily terminate the string */
889 host_entry = gethostbyname(unc_name);
891 *(share - 1) = '/'; /* put the slash back */
892 if ((prefixpath = strchr(share, '/'))) {
893 *prefixpath = 0; /* permanently terminate the string */
894 if (!strlen(++prefixpath))
895 prefixpath = NULL; /* this needs to be done explicitly */
899 printf("ip address specified explicitly\n");
902 if(host_entry == NULL) {
903 printf("mount error: could not find target server. TCP name %s not found\n", unc_name);
906 /* BB should we pass an alternate version of the share name as Unicode */
907 /* BB what about ipv6? BB */
908 /* BB add retries with alternate servers in list */
910 memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
912 ipaddress_string = inet_ntoa(server_ipaddr);
913 if(ipaddress_string == NULL) {
914 printf("mount error: could not get valid ip address for target server\n");
917 return ipaddress_string;
920 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
921 printf("Mounting the DFS root for a particular server not implemented yet\n");
928 static struct option longopts[] = {
929 { "all", 0, NULL, 'a' },
930 { "help",0, NULL, 'h' },
931 { "move",0, NULL, 'm' },
932 { "bind",0, NULL, 'b' },
933 { "read-only", 0, NULL, 'r' },
934 { "ro", 0, NULL, 'r' },
935 { "verbose", 0, NULL, 'v' },
936 { "version", 0, NULL, 'V' },
937 { "read-write", 0, NULL, 'w' },
938 { "rw", 0, NULL, 'w' },
939 { "options", 1, NULL, 'o' },
940 { "type", 1, NULL, 't' },
941 { "rsize",1, NULL, 'R' },
942 { "wsize",1, NULL, 'W' },
943 { "uid", 1, NULL, '1'},
944 { "gid", 1, NULL, '2'},
945 { "user",1,NULL,'u'},
946 { "username",1,NULL,'u'},
948 { "domain",1,NULL,'d'},
949 { "password",1,NULL,'p'},
950 { "pass",1,NULL,'p'},
951 { "credentials",1,NULL,'c'},
952 { "port",1,NULL,'P'},
953 /* { "uuid",1,NULL,'U'}, */ /* BB unimplemented */
957 int main(int argc, char ** argv)
960 int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
961 char * orgoptions = NULL;
962 char * share_name = NULL;
963 char * ipaddr = NULL;
965 char * mountpoint = NULL;
966 char * options = NULL;
967 char * resolved_path = NULL;
977 size_t options_size = 0;
978 int retry = 0; /* set when we have to retry mount with uppercase */
980 struct utsname sysinfo;
981 struct mntent mountent;
984 /* setlocale(LC_ALL, "");
985 bindtextdomain(PACKAGE, LOCALEDIR);
986 textdomain(PACKAGE); */
989 thisprogram = argv[0];
995 if(thisprogram == NULL)
996 thisprogram = "mount.cifs";
999 /* BB add workstation name and domain and pass down */
1001 /* #ifdef _GNU_SOURCE
1002 printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
1005 share_name = argv[1];
1006 mountpoint = argv[2];
1009 /* add sharename in opts string as unc= parm */
1011 while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
1012 longopts, NULL)) != -1) {
1014 /* No code to do the following options yet */
1016 list_with_volumelabel = 1;
1019 volumelabel = optarg;
1026 case 'h': /* help */
1027 mount_cifs_usage ();
1037 "option 'b' (MS_BIND) not supported\n");
1045 "option 'm' (MS_MOVE) not supported\n");
1049 orgoptions = strdup(optarg);
1051 case 'r': /* mount readonly */
1061 printf ("mount.cifs version: %s.%s%s\n",
1062 MOUNT_CIFS_VERSION_MAJOR,
1063 MOUNT_CIFS_VERSION_MINOR,
1064 MOUNT_CIFS_VENDOR_SUFFIX);
1066 memset(mountpassword,0,64);
1070 flags &= ~MS_RDONLY;
1073 rsize = atoi(optarg) ;
1076 wsize = atoi(optarg);
1079 if (isdigit(*optarg)) {
1082 uid = strtoul(optarg, &ep, 10);
1084 printf("bad uid value \"%s\"\n", optarg);
1090 if (!(pw = getpwnam(optarg))) {
1091 printf("bad user name \"%s\"\n", optarg);
1099 if (isdigit(*optarg)) {
1102 gid = strtoul(optarg, &ep, 10);
1104 printf("bad gid value \"%s\"\n", optarg);
1110 if (!(gr = getgrnam(optarg))) {
1111 printf("bad user name \"%s\"\n", optarg);
1123 domain_name = optarg; /* BB fix this - currently ignored */
1127 if(mountpassword == NULL)
1128 mountpassword = (char *)calloc(65,1);
1131 strncpy(mountpassword,optarg,64);
1135 get_password_from_file(0 /* stdin */,NULL);
1140 printf("unknown mount option %c\n",c);
1146 if((argc < 3) || (share_name == NULL) || (mountpoint == NULL)) {
1151 if (getenv("PASSWD")) {
1152 if(mountpassword == NULL)
1153 mountpassword = (char *)calloc(65,1);
1155 strncpy(mountpassword,getenv("PASSWD"),64);
1158 } else if (getenv("PASSWD_FD")) {
1159 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
1160 } else if (getenv("PASSWD_FILE")) {
1161 get_password_from_file(0, getenv("PASSWD_FILE"));
1164 if (orgoptions && parse_options(&orgoptions, &flags)) {
1168 ipaddr = parse_server(&share_name);
1169 if((ipaddr == NULL) && (got_ip == 0)) {
1170 printf("No ip address specified and hostname not found\n");
1175 /* BB save off path and pop after mount returns? */
1176 resolved_path = (char *)malloc(PATH_MAX+1);
1178 /* Note that if we can not canonicalize the name, we get
1179 another chance to see if it is valid when we chdir to it */
1180 if (realpath(mountpoint, resolved_path)) {
1181 mountpoint = resolved_path;
1184 if(chdir(mountpoint)) {
1185 printf("mount error: can not change directory into mount target %s\n",mountpoint);
1190 if(stat (".", &statbuf)) {
1191 printf("mount error: mount point %s does not exist\n",mountpoint);
1196 if (S_ISDIR(statbuf.st_mode) == 0) {
1197 printf("mount error: mount point %s is not a directory\n",mountpoint);
1202 if((getuid() != 0) && (geteuid() == 0)) {
1203 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
1204 #ifndef CIFS_ALLOW_USR_SUID
1205 /* Do not allow user mounts to control suid flag
1206 for mount unless explicitly built that way */
1207 flags |= MS_NOSUID | MS_NODEV;
1210 printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n");
1216 user_name = getusername();
1220 if(got_password == 0) {
1221 mountpassword = getpass("Password: "); /* BB obsolete */
1224 /* FIXME launch daemon (handles dfs name resolution and credential change)
1225 remember to clear parms and overwrite password field before launching */
1228 optlen = strlen(orgoptions);
1233 optlen += strlen(share_name) + 4;
1235 printf("No server share name specified\n");
1236 printf("\nMounting the DFS root for server not implemented yet\n");
1240 optlen += strlen(user_name) + 6;
1242 optlen += strlen(ipaddr) + 4;
1244 optlen += strlen(mountpassword) + 6;
1247 options_size = optlen + 10 + 64;
1248 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 */);
1250 if(options == NULL) {
1251 printf("Could not allocate memory for mount options\n");
1256 strlcpy(options,"unc=",options_size);
1257 strlcat(options,share_name,options_size);
1258 /* scan backwards and reverse direction of slash */
1259 temp = strrchr(options, '/');
1260 if(temp > options + 6)
1263 strlcat(options,",ip=",options_size);
1264 strlcat(options,ipaddr,options_size);
1268 /* check for syntax like user=domain\user */
1270 domain_name = check_for_domain(&user_name);
1271 strlcat(options,",user=",options_size);
1272 strlcat(options,user_name,options_size);
1276 /* extra length accounted for in option string above */
1277 strlcat(options,",domain=",options_size);
1278 strlcat(options,domain_name,options_size);
1282 /* Commas have to be doubled, or else they will
1283 look like the parameter separator */
1284 /* if(sep is not set)*/
1286 check_for_comma(&mountpassword);
1287 strlcat(options,",pass=",options_size);
1288 strlcat(options,mountpassword,options_size);
1291 strlcat(options,",ver=",options_size);
1292 strlcat(options,MOUNT_CIFS_VERSION_MAJOR,options_size);
1295 strlcat(options,",",options_size);
1296 strlcat(options,orgoptions,options_size);
1299 strlcat(options,",prefixpath=",options_size);
1300 strlcat(options,prefixpath,options_size); /* no need to cat the / */
1303 printf("\nmount.cifs kernel mount options %s \n",options);
1304 if(mount(share_name, mountpoint, "cifs", flags, options)) {
1305 /* remember to kill daemon on error */
1310 printf("mount failed but no error number set\n");
1313 printf("mount error: cifs filesystem not supported by the system\n");
1319 while (*tmp && !(((unsigned char)tmp[0]) & 0x80)) {
1320 *tmp = toupper((unsigned char)*tmp);
1324 printf("retrying with upper case share name\n");
1329 printf("mount error %d = %s\n",errno,strerror(errno));
1331 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
1335 pmntfile = setmntent(MOUNTED, "a+");
1337 mountent.mnt_fsname = share_name;
1338 mountent.mnt_dir = mountpoint;
1339 mountent.mnt_type = CONST_DISCARD(char *,"cifs");
1340 mountent.mnt_opts = (char *)malloc(220);
1341 if(mountent.mnt_opts) {
1342 char * mount_user = getusername();
1343 memset(mountent.mnt_opts,0,200);
1344 if(flags & MS_RDONLY)
1345 strlcat(mountent.mnt_opts,"ro",220);
1347 strlcat(mountent.mnt_opts,"rw",220);
1348 if(flags & MS_MANDLOCK)
1349 strlcat(mountent.mnt_opts,",mand",220);
1350 if(flags & MS_NOEXEC)
1351 strlcat(mountent.mnt_opts,",noexec",220);
1352 if(flags & MS_NOSUID)
1353 strlcat(mountent.mnt_opts,",nosuid",220);
1354 if(flags & MS_NODEV)
1355 strlcat(mountent.mnt_opts,",nodev",220);
1356 if(flags & MS_SYNCHRONOUS)
1357 strlcat(mountent.mnt_opts,",synch",220);
1360 strlcat(mountent.mnt_opts,",user=",220);
1361 strlcat(mountent.mnt_opts,mount_user,220);
1363 /* free(mount_user); do not free static mem */
1366 mountent.mnt_freq = 0;
1367 mountent.mnt_passno = 0;
1368 rc = addmntent(pmntfile,&mountent);
1369 endmntent(pmntfile);
1370 if(mountent.mnt_opts)
1371 free(mountent.mnt_opts);
1373 printf("could not update mount table\n");
1379 int len = strlen(mountpassword);
1380 memset(mountpassword,0,len);
1381 free(mountpassword);
1385 memset(options,0,optlen);
1390 memset(orgoptions,0,orgoptlen);
1394 free(resolved_path);
1397 if(free_share_name) {