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')
235 || (temp_val[length] == '\0')) {
240 printf("mount.cifs failed: password in credentials file too long\n");
241 memset(line_buf,0, 4096);
243 memset(mountpassword,0,64);
247 if(mountpassword == NULL) {
248 mountpassword = (char *)calloc(65,1);
250 memset(mountpassword,0,64);
252 strncpy(mountpassword,temp_val,length);
257 } else if (strncasecmp("domain",line_buf+i,6) == 0) {
258 temp_val = strchr(line_buf+i,'=');
260 /* go past equals sign */
263 printf("\nDomain %s\n",temp_val);
264 for(length = 0;length<65;length++) {
265 if ((temp_val[length] == '\n')
266 || (temp_val[length] == '\0')) {
271 printf("mount.cifs failed: domain in credentials file too long\n");
273 memset(mountpassword,0,64);
277 if(domain_name == NULL) {
278 domain_name = (char *)calloc(65,1);
280 memset(domain_name,0,64);
282 strncpy(domain_name,temp_val,length);
292 memset(line_buf,0,4096);
298 static int get_password_from_file(int file_descript, char * filename)
304 if(mountpassword == NULL)
305 mountpassword = (char *)calloc(65,1);
307 memset(mountpassword, 0, 64);
309 if (mountpassword == NULL) {
310 printf("malloc failed\n");
314 if(filename != NULL) {
315 file_descript = open(filename, O_RDONLY);
316 if(file_descript < 0) {
317 printf("mount.cifs failed. %s attempting to open password file %s\n",
318 strerror(errno),filename);
322 /* else file already open and fd provided */
325 rc = read(file_descript,&c,1);
327 printf("mount.cifs failed. Error %s reading password file\n",strerror(errno));
328 memset(mountpassword,0,64);
330 close(file_descript);
333 if(mountpassword[0] == 0) {
335 printf("\nWarning: null password used since cifs password file empty");
338 } else /* read valid character */ {
339 if((c == 0) || (c == '\n')) {
342 mountpassword[i] = c;
345 if((i == 64) && (verboseflag)) {
346 printf("\nWarning: password longer than 64 characters specified in cifs password file");
349 if(filename != NULL) {
350 close(file_descript);
356 static int parse_options(char ** optionsp, int * filesys_flags)
359 char * percent_char = NULL;
361 char * next_keyword = NULL;
369 if (!optionsp || !*optionsp)
374 printf("parsing options: %s\n", data);
376 /* BB fixme check for separator override BB */
380 snprintf(user,sizeof(user),"%u",getuid());
382 snprintf(group,sizeof(group),"%u",getgid());
385 /* while ((data = strsep(&options, ",")) != NULL) { */
386 while(data != NULL) {
387 /* check if ends with trailing comma */
391 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
392 /* data = next keyword */
393 /* value = next value ie stuff after equal sign */
395 next_keyword = strchr(data,','); /* BB handle sep= */
397 /* temporarily null terminate end of keyword=value pair */
401 /* temporarily null terminate keyword to make keyword and value distinct */
402 if ((value = strchr(data, '=')) != NULL) {
407 if (strncmp(data, "users",5) == 0) {
408 if(!value || !*value) {
411 } else if (strncmp(data, "user_xattr",10) == 0) {
412 /* do nothing - need to skip so not parsed as user name */
413 } else if (strncmp(data, "user", 4) == 0) {
415 if (!value || !*value) {
416 if(data[4] == '\0') {
418 printf("\nskipping empty user mount parameter\n");
419 /* remove the parm since it would otherwise be confusing
420 to the kernel code which would think it was a real username */
423 printf("username specified with no parameter\n");
424 return 1; /* needs_arg; */
427 if (strnlen(value, 260) < 260) {
429 percent_char = strchr(value,'%');
432 if(mountpassword == NULL)
433 mountpassword = (char *)calloc(65,1);
436 printf("\nmount.cifs warning - password specified twice\n");
439 strncpy(mountpassword, percent_char,64);
440 /* remove password from username */
441 while(*percent_char != 0) {
447 /* this is only case in which the user
448 name buf is not malloc - so we have to
449 check for domain name embedded within
450 the user name here since the later
451 call to check_for_domain will not be
453 domain_name = check_for_domain(&value);
455 printf("username too long\n");
459 } else if (strncmp(data, "pass", 4) == 0) {
460 if (!value || !*value) {
462 printf("\npassword specified twice, ignoring second\n");
465 } else if (strnlen(value, 17) < 17) {
467 printf("\nmount.cifs warning - password specified twice\n");
470 printf("password too long\n");
473 } else if (strncmp(data, "sec", 3) == 0) {
475 if (!strcmp(value, "none"))
478 } else if (strncmp(data, "ip", 2) == 0) {
479 if (!value || !*value) {
480 printf("target ip address argument missing");
481 } else if (strnlen(value, 35) < 35) {
483 printf("ip address %s override specified\n",value);
486 printf("ip address too long\n");
489 } else if ((strncmp(data, "unc", 3) == 0)
490 || (strncmp(data, "target", 6) == 0)
491 || (strncmp(data, "path", 4) == 0)) {
492 if (!value || !*value) {
493 printf("invalid path to network resource\n");
494 return 1; /* needs_arg; */
495 } else if(strnlen(value,5) < 5) {
496 printf("UNC name too short");
499 if (strnlen(value, 300) < 300) {
501 if (strncmp(value, "//", 2) == 0) {
503 printf("unc name specified twice, ignoring second\n");
506 } else if (strncmp(value, "\\\\", 2) != 0) {
507 printf("UNC Path does not begin with // or \\\\ \n");
511 printf("unc name specified twice, ignoring second\n");
516 printf("CIFS: UNC name too long\n");
519 } else if ((strncmp(data, "domain", 3) == 0)
520 || (strncmp(data, "workgroup", 5) == 0)) {
521 if (!value || !*value) {
522 printf("CIFS: invalid domain name\n");
523 return 1; /* needs_arg; */
525 if (strnlen(value, 65) < 65) {
528 printf("domain name too long\n");
531 } else if (strncmp(data, "cred", 4) == 0) {
532 if (value && *value) {
533 rc = open_cred_file(value);
535 printf("error %d opening credential file %s\n",rc, value);
539 printf("invalid credential file name specified\n");
542 } else if (strncmp(data, "uid", 3) == 0) {
543 if (value && *value) {
545 if (!isdigit(*value)) {
548 if (!(pw = getpwnam(value))) {
549 printf("bad user name \"%s\"\n", value);
552 snprintf(user, sizeof(user), "%u", pw->pw_uid);
554 strlcpy(user,value,sizeof(user));
558 } else if (strncmp(data, "gid", 3) == 0) {
559 if (value && *value) {
561 if (!isdigit(*value)) {
564 if (!(gr = getgrnam(value))) {
565 printf("bad group name \"%s\"\n", value);
568 snprintf(group, sizeof(group), "%u", gr->gr_gid);
570 strlcpy(group,value,sizeof(group));
574 /* fmask and dmask synonyms for people used to smbfs syntax */
575 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
576 if (!value || !*value) {
577 printf ("Option '%s' requires a numerical argument\n", data);
581 if (value[0] != '0') {
582 printf ("WARNING: '%s' not expressed in octal.\n", data);
585 if (strcmp (data, "fmask") == 0) {
586 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
587 data = "file_mode"; /* BB fix this */
589 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
590 if (!value || !*value) {
591 printf ("Option '%s' requires a numerical argument\n", data);
595 if (value[0] != '0') {
596 printf ("WARNING: '%s' not expressed in octal.\n", data);
599 if (strcmp (data, "dmask") == 0) {
600 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
603 /* the following eight mount options should be
604 stripped out from what is passed into the kernel
605 since these eight options are best passed as the
606 mount flags rather than redundantly to the kernel
607 and could generate spurious warnings depending on the
608 level of the corresponding cifs vfs kernel code */
609 } else if (strncmp(data, "nosuid", 6) == 0) {
610 *filesys_flags |= MS_NOSUID;
611 } else if (strncmp(data, "suid", 4) == 0) {
612 *filesys_flags &= ~MS_NOSUID;
613 } else if (strncmp(data, "nodev", 5) == 0) {
614 *filesys_flags |= MS_NODEV;
615 } else if ((strncmp(data, "nobrl", 5) == 0) ||
616 (strncmp(data, "nolock", 6) == 0)) {
617 *filesys_flags &= ~MS_MANDLOCK;
618 } else if (strncmp(data, "dev", 3) == 0) {
619 *filesys_flags &= ~MS_NODEV;
620 } else if (strncmp(data, "noexec", 6) == 0) {
621 *filesys_flags |= MS_NOEXEC;
622 } else if (strncmp(data, "exec", 4) == 0) {
623 *filesys_flags &= ~MS_NOEXEC;
624 } else if (strncmp(data, "guest", 5) == 0) {
626 } else if (strncmp(data, "ro", 2) == 0) {
627 *filesys_flags |= MS_RDONLY;
628 } else if (strncmp(data, "rw", 2) == 0) {
629 *filesys_flags &= ~MS_RDONLY;
630 } else if (strncmp(data, "remount", 7) == 0) {
631 *filesys_flags |= MS_REMOUNT;
632 } /* else if (strnicmp(data, "port", 4) == 0) {
633 if (value && *value) {
635 simple_strtoul(value, &value, 0);
637 } else if (strnicmp(data, "rsize", 5) == 0) {
638 if (value && *value) {
640 simple_strtoul(value, &value, 0);
642 } else if (strnicmp(data, "wsize", 5) == 0) {
643 if (value && *value) {
645 simple_strtoul(value, &value, 0);
647 } else if (strnicmp(data, "version", 3) == 0) {
649 printf("CIFS: Unknown mount option %s\n",data);
650 } */ /* nothing to do on those four mount options above.
651 Just pass to kernel and ignore them here */
653 /* Copy (possibly modified) option to out */
654 word_len = strlen(data);
656 word_len += 1 + strlen(value);
658 out = (char *)realloc(out, out_len + word_len + 2);
665 strlcat(out, ",", out_len + word_len + 2);
670 snprintf(out + out_len, word_len + 1, "%s=%s", data, value);
672 snprintf(out + out_len, word_len + 1, "%s", data);
673 out_len = strlen(out);
679 /* special-case the uid and gid */
681 word_len = strlen(user);
683 out = (char *)realloc(out, out_len + word_len + 6);
690 strlcat(out, ",", out_len + word_len + 6);
693 snprintf(out + out_len, word_len + 5, "uid=%s", user);
694 out_len = strlen(out);
697 word_len = strlen(group);
699 out = (char *)realloc(out, out_len + 1 + word_len + 6);
706 strlcat(out, ",", out_len + word_len + 6);
709 snprintf(out + out_len, word_len + 5, "gid=%s", group);
710 out_len = strlen(out);
718 /* replace all (one or more) commas with double commas */
719 static void check_for_comma(char ** ppasswrd)
724 int number_of_commas = 0;
739 if(number_of_commas == 0)
741 if(number_of_commas > 64) {
742 /* would otherwise overflow the mount options buffer */
743 printf("\nInvalid password. Password contains too many commas.\n");
747 new_pass_buf = (char *)malloc(len+number_of_commas+1);
748 if(new_pass_buf == NULL)
751 for(i=0,j=0;i<len;i++,j++) {
752 new_pass_buf[j] = pass[i];
755 new_pass_buf[j] = pass[i];
758 new_pass_buf[len+number_of_commas] = 0;
761 *ppasswrd = new_pass_buf;
766 /* Usernames can not have backslash in them and we use
767 [BB check if usernames can have forward slash in them BB]
768 backslash as domain\user separator character
770 static char * check_for_domain(char **ppuser)
772 char * original_string;
782 original_string = *ppuser;
784 if (original_string == NULL)
787 original_len = strlen(original_string);
789 usernm = strchr(*ppuser,'/');
790 if (usernm == NULL) {
791 usernm = strchr(*ppuser,'\\');
797 printf("Domain name specified twice. Username probably malformed\n");
803 if (domainnm[0] != 0) {
806 printf("null domain\n");
808 len = strlen(domainnm);
809 /* reset domainm to new buffer, and copy
810 domain name into it */
811 domainnm = (char *)malloc(len+1);
815 strlcpy(domainnm,*ppuser,len+1);
817 /* move_string(*ppuser, usernm+1) */
818 len = strlen(usernm+1);
820 if(len >= original_len) {
821 /* should not happen */
825 for(i=0;i<original_len;i++) {
827 original_string[i] = usernm[i+1];
828 else /* stuff with commas to remove last parm */
829 original_string[i] = ',';
832 /* BB add check for more than one slash?
840 /* Note that caller frees the returned buffer if necessary */
841 static char * parse_server(char ** punc_name)
843 char * unc_name = *punc_name;
844 int length = strnlen(unc_name,1024);
846 char * ipaddress_string = NULL;
847 struct hostent * host_entry = NULL;
848 struct in_addr server_ipaddr;
851 printf("mount error: UNC name too long");
854 if (strncasecmp("cifs://",unc_name,7) == 0)
855 return parse_cifs_url(unc_name+7);
856 if (strncasecmp("smb://",unc_name,6) == 0) {
857 return parse_cifs_url(unc_name+6);
861 /* BB add code to find DFS root here */
862 printf("\nMounting the DFS root for domain not implemented yet\n");
865 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
866 /* check for nfs syntax ie server:share */
867 share = strchr(unc_name,':');
870 *punc_name = (char *)malloc(length+3);
871 if(*punc_name == NULL) {
872 /* put the original string back if
874 *punc_name = unc_name;
879 strncpy((*punc_name)+2,unc_name,length);
880 unc_name = *punc_name;
881 unc_name[length+2] = 0;
882 goto continue_unc_parsing;
884 printf("mount error: improperly formatted UNC name.");
885 printf(" %s does not begin with \\\\ or //\n",unc_name);
889 continue_unc_parsing:
893 if ((share = strchr(unc_name, '/')) ||
894 (share = strchr(unc_name,'\\'))) {
895 *share = 0; /* temporarily terminate the string */
898 host_entry = gethostbyname(unc_name);
900 *(share - 1) = '/'; /* put the slash back */
901 if ((prefixpath = strchr(share, '/'))) {
902 *prefixpath = 0; /* permanently terminate the string */
903 if (!strlen(++prefixpath))
904 prefixpath = NULL; /* this needs to be done explicitly */
908 printf("ip address specified explicitly\n");
911 if(host_entry == NULL) {
912 printf("mount error: could not find target server. TCP name %s not found\n", unc_name);
915 /* BB should we pass an alternate version of the share name as Unicode */
916 /* BB what about ipv6? BB */
917 /* BB add retries with alternate servers in list */
919 memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
921 ipaddress_string = inet_ntoa(server_ipaddr);
922 if(ipaddress_string == NULL) {
923 printf("mount error: could not get valid ip address for target server\n");
926 return ipaddress_string;
929 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
930 printf("Mounting the DFS root for a particular server not implemented yet\n");
937 static struct option longopts[] = {
938 { "all", 0, NULL, 'a' },
939 { "help",0, NULL, 'h' },
940 { "move",0, NULL, 'm' },
941 { "bind",0, NULL, 'b' },
942 { "read-only", 0, NULL, 'r' },
943 { "ro", 0, NULL, 'r' },
944 { "verbose", 0, NULL, 'v' },
945 { "version", 0, NULL, 'V' },
946 { "read-write", 0, NULL, 'w' },
947 { "rw", 0, NULL, 'w' },
948 { "options", 1, NULL, 'o' },
949 { "type", 1, NULL, 't' },
950 { "rsize",1, NULL, 'R' },
951 { "wsize",1, NULL, 'W' },
952 { "uid", 1, NULL, '1'},
953 { "gid", 1, NULL, '2'},
954 { "user",1,NULL,'u'},
955 { "username",1,NULL,'u'},
957 { "domain",1,NULL,'d'},
958 { "password",1,NULL,'p'},
959 { "pass",1,NULL,'p'},
960 { "credentials",1,NULL,'c'},
961 { "port",1,NULL,'P'},
962 /* { "uuid",1,NULL,'U'}, */ /* BB unimplemented */
966 int main(int argc, char ** argv)
969 int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
970 char * orgoptions = NULL;
971 char * share_name = NULL;
972 char * ipaddr = NULL;
974 char * mountpoint = NULL;
975 char * options = NULL;
976 char * resolved_path = NULL;
986 size_t options_size = 0;
987 int retry = 0; /* set when we have to retry mount with uppercase */
989 struct utsname sysinfo;
990 struct mntent mountent;
993 /* setlocale(LC_ALL, "");
994 bindtextdomain(PACKAGE, LOCALEDIR);
995 textdomain(PACKAGE); */
998 thisprogram = argv[0];
1004 if(thisprogram == NULL)
1005 thisprogram = "mount.cifs";
1008 /* BB add workstation name and domain and pass down */
1010 /* #ifdef _GNU_SOURCE
1011 printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
1014 share_name = argv[1];
1015 mountpoint = argv[2];
1018 /* add sharename in opts string as unc= parm */
1020 while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
1021 longopts, NULL)) != -1) {
1023 /* No code to do the following options yet */
1025 list_with_volumelabel = 1;
1028 volumelabel = optarg;
1035 case 'h': /* help */
1036 mount_cifs_usage ();
1046 "option 'b' (MS_BIND) not supported\n");
1054 "option 'm' (MS_MOVE) not supported\n");
1058 orgoptions = strdup(optarg);
1060 case 'r': /* mount readonly */
1070 printf ("mount.cifs version: %s.%s%s\n",
1071 MOUNT_CIFS_VERSION_MAJOR,
1072 MOUNT_CIFS_VERSION_MINOR,
1073 MOUNT_CIFS_VENDOR_SUFFIX);
1075 memset(mountpassword,0,64);
1079 flags &= ~MS_RDONLY;
1082 rsize = atoi(optarg) ;
1085 wsize = atoi(optarg);
1088 if (isdigit(*optarg)) {
1091 uid = strtoul(optarg, &ep, 10);
1093 printf("bad uid value \"%s\"\n", optarg);
1099 if (!(pw = getpwnam(optarg))) {
1100 printf("bad user name \"%s\"\n", optarg);
1108 if (isdigit(*optarg)) {
1111 gid = strtoul(optarg, &ep, 10);
1113 printf("bad gid value \"%s\"\n", optarg);
1119 if (!(gr = getgrnam(optarg))) {
1120 printf("bad user name \"%s\"\n", optarg);
1132 domain_name = optarg; /* BB fix this - currently ignored */
1136 if(mountpassword == NULL)
1137 mountpassword = (char *)calloc(65,1);
1140 strncpy(mountpassword,optarg,64);
1144 get_password_from_file(0 /* stdin */,NULL);
1149 printf("unknown mount option %c\n",c);
1155 if((argc < 3) || (share_name == NULL) || (mountpoint == NULL)) {
1160 if (getenv("PASSWD")) {
1161 if(mountpassword == NULL)
1162 mountpassword = (char *)calloc(65,1);
1164 strncpy(mountpassword,getenv("PASSWD"),64);
1167 } else if (getenv("PASSWD_FD")) {
1168 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
1169 } else if (getenv("PASSWD_FILE")) {
1170 get_password_from_file(0, getenv("PASSWD_FILE"));
1173 if (orgoptions && parse_options(&orgoptions, &flags)) {
1177 ipaddr = parse_server(&share_name);
1178 if((ipaddr == NULL) && (got_ip == 0)) {
1179 printf("No ip address specified and hostname not found\n");
1184 /* BB save off path and pop after mount returns? */
1185 resolved_path = (char *)malloc(PATH_MAX+1);
1187 /* Note that if we can not canonicalize the name, we get
1188 another chance to see if it is valid when we chdir to it */
1189 if (realpath(mountpoint, resolved_path)) {
1190 mountpoint = resolved_path;
1193 if(chdir(mountpoint)) {
1194 printf("mount error: can not change directory into mount target %s\n",mountpoint);
1199 if(stat (".", &statbuf)) {
1200 printf("mount error: mount point %s does not exist\n",mountpoint);
1205 if (S_ISDIR(statbuf.st_mode) == 0) {
1206 printf("mount error: mount point %s is not a directory\n",mountpoint);
1211 if((getuid() != 0) && (geteuid() == 0)) {
1212 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
1213 #ifndef CIFS_ALLOW_USR_SUID
1214 /* Do not allow user mounts to control suid flag
1215 for mount unless explicitly built that way */
1216 flags |= MS_NOSUID | MS_NODEV;
1219 printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n");
1225 user_name = getusername();
1229 if(got_password == 0) {
1230 mountpassword = getpass("Password: "); /* BB obsolete */
1233 /* FIXME launch daemon (handles dfs name resolution and credential change)
1234 remember to clear parms and overwrite password field before launching */
1237 optlen = strlen(orgoptions);
1242 optlen += strlen(share_name) + 4;
1244 printf("No server share name specified\n");
1245 printf("\nMounting the DFS root for server not implemented yet\n");
1249 optlen += strlen(user_name) + 6;
1251 optlen += strlen(ipaddr) + 4;
1253 optlen += strlen(mountpassword) + 6;
1256 options_size = optlen + 10 + 64;
1257 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 */);
1259 if(options == NULL) {
1260 printf("Could not allocate memory for mount options\n");
1265 strlcpy(options,"unc=",options_size);
1266 strlcat(options,share_name,options_size);
1267 /* scan backwards and reverse direction of slash */
1268 temp = strrchr(options, '/');
1269 if(temp > options + 6)
1272 strlcat(options,",ip=",options_size);
1273 strlcat(options,ipaddr,options_size);
1277 /* check for syntax like user=domain\user */
1279 domain_name = check_for_domain(&user_name);
1280 strlcat(options,",user=",options_size);
1281 strlcat(options,user_name,options_size);
1285 /* extra length accounted for in option string above */
1286 strlcat(options,",domain=",options_size);
1287 strlcat(options,domain_name,options_size);
1291 /* Commas have to be doubled, or else they will
1292 look like the parameter separator */
1293 /* if(sep is not set)*/
1295 check_for_comma(&mountpassword);
1296 strlcat(options,",pass=",options_size);
1297 strlcat(options,mountpassword,options_size);
1300 strlcat(options,",ver=",options_size);
1301 strlcat(options,MOUNT_CIFS_VERSION_MAJOR,options_size);
1304 strlcat(options,",",options_size);
1305 strlcat(options,orgoptions,options_size);
1308 strlcat(options,",prefixpath=",options_size);
1309 strlcat(options,prefixpath,options_size); /* no need to cat the / */
1312 printf("\nmount.cifs kernel mount options %s \n",options);
1313 if(mount(share_name, mountpoint, "cifs", flags, options)) {
1314 /* remember to kill daemon on error */
1319 printf("mount failed but no error number set\n");
1322 printf("mount error: cifs filesystem not supported by the system\n");
1328 while (*tmp && !(((unsigned char)tmp[0]) & 0x80)) {
1329 *tmp = toupper((unsigned char)*tmp);
1333 printf("retrying with upper case share name\n");
1338 printf("mount error %d = %s\n",errno,strerror(errno));
1340 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
1344 pmntfile = setmntent(MOUNTED, "a+");
1346 mountent.mnt_fsname = share_name;
1347 mountent.mnt_dir = mountpoint;
1348 mountent.mnt_type = CONST_DISCARD(char *,"cifs");
1349 mountent.mnt_opts = (char *)malloc(220);
1350 if(mountent.mnt_opts) {
1351 char * mount_user = getusername();
1352 memset(mountent.mnt_opts,0,200);
1353 if(flags & MS_RDONLY)
1354 strlcat(mountent.mnt_opts,"ro",220);
1356 strlcat(mountent.mnt_opts,"rw",220);
1357 if(flags & MS_MANDLOCK)
1358 strlcat(mountent.mnt_opts,",mand",220);
1359 if(flags & MS_NOEXEC)
1360 strlcat(mountent.mnt_opts,",noexec",220);
1361 if(flags & MS_NOSUID)
1362 strlcat(mountent.mnt_opts,",nosuid",220);
1363 if(flags & MS_NODEV)
1364 strlcat(mountent.mnt_opts,",nodev",220);
1365 if(flags & MS_SYNCHRONOUS)
1366 strlcat(mountent.mnt_opts,",synch",220);
1369 strlcat(mountent.mnt_opts,",user=",220);
1370 strlcat(mountent.mnt_opts,mount_user,220);
1372 /* free(mount_user); do not free static mem */
1375 mountent.mnt_freq = 0;
1376 mountent.mnt_passno = 0;
1377 rc = addmntent(pmntfile,&mountent);
1378 endmntent(pmntfile);
1379 if(mountent.mnt_opts)
1380 free(mountent.mnt_opts);
1382 printf("could not update mount table\n");
1388 int len = strlen(mountpassword);
1389 memset(mountpassword,0,len);
1390 free(mountpassword);
1394 memset(options,0,optlen);
1399 memset(orgoptions,0,orgoptlen);
1403 free(resolved_path);
1406 if(free_share_name) {