2 Mount helper utility for Linux CIFS VFS (virtual filesystem) client
3 Copyright (C) 2003,2008 Steve French (sfrench@us.ibm.com)
4 Copyright (C) 2008 Jeremy Allison (jra@samba.org)
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
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>
43 #define MOUNT_CIFS_VERSION_MAJOR "1"
44 #define MOUNT_CIFS_VERSION_MINOR "11"
46 #ifndef MOUNT_CIFS_VENDOR_SUFFIX
48 #include "include/version.h"
49 #ifdef SAMBA_VERSION_VENDOR_SUFFIX
50 #define MOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING"-"SAMBA_VERSION_VENDOR_SUFFIX
52 #define MOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING
53 #endif /* SAMBA_VERSION_OFFICIAL_STRING and SAMBA_VERSION_VENDOR_SUFFIX */
55 #define MOUNT_CIFS_VENDOR_SUFFIX ""
56 #endif /* _SAMBA_BUILD_ */
57 #endif /* MOUNT_CIFS_VENDOR_SUFFIX */
67 #define MAX_UNC_LEN 1024
69 #define CONST_DISCARD(type, ptr) ((type) ((void *) (ptr)))
72 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
75 #define MOUNT_PASSWD_SIZE 64
76 #define DOMAIN_SIZE 64
78 const char *thisprogram
;
80 static int got_password
= 0;
81 static int got_user
= 0;
82 static int got_domain
= 0;
83 static int got_ip
= 0;
84 static int got_unc
= 0;
85 static int got_uid
= 0;
86 static int got_gid
= 0;
87 static char * user_name
= NULL
;
88 static char * mountpassword
= NULL
;
89 char * domain_name
= NULL
;
90 char * prefixpath
= NULL
;
92 /* glibc doesn't have strlcpy, strlcat. Ensure we do. JRA. We
93 * don't link to libreplace so need them here. */
95 /* like strncpy but does not 0 fill the buffer and always null
96 * terminates. bufsize is the size of the destination buffer */
97 size_t strlcpy(char *d
, const char *s
, size_t bufsize
)
99 size_t len
= strlen(s
);
101 if (bufsize
<= 0) return 0;
102 if (len
>= bufsize
) len
= bufsize
-1;
108 /* like strncat but does not 0 fill the buffer and always null
109 * terminates. bufsize is the length of the buffer, which should
110 * be one more than the maximum resulting string length */
111 size_t strlcat(char *d
, const char *s
, size_t bufsize
)
113 size_t len1
= strlen(d
);
114 size_t len2
= strlen(s
);
115 size_t ret
= len1
+ len2
;
117 if (len1
+len2
>= bufsize
) {
118 len2
= bufsize
- (len1
+1);
121 memcpy(d
+len1
, s
, len2
);
130 open nofollow - avoid symlink exposure?
131 get owner of dir see if matches self or if root
132 call system(umount argv) etc.
136 static char * check_for_domain(char **);
139 static void mount_cifs_usage(void)
141 printf("\nUsage: %s <remotetarget> <dir> -o <options>\n", thisprogram
);
142 printf("\nMount the remote target, specified as a UNC name,");
143 printf(" to a local directory.\n\nOptions:\n");
144 printf("\tuser=<arg>\n\tpass=<arg>\n\tdom=<arg>\n");
145 printf("\nLess commonly used options:");
146 printf("\n\tcredentials=<filename>,guest,perm,noperm,setuids,nosetuids,rw,ro,");
147 printf("\n\tsep=<char>,iocharset=<codepage>,suid,nosuid,exec,noexec,serverino,");
148 printf("\n\tmapchars,nomapchars,nolock,servernetbiosname=<SRV_RFC1001NAME>");
149 printf("\n\tdirectio,nounix,cifsacl,sec=<authentication mechanism>,sign");
150 printf("\n\nOptions not needed for servers supporting CIFS Unix extensions");
151 printf("\n\t(e.g. unneeded for mounts to most Samba versions):");
152 printf("\n\tuid=<uid>,gid=<gid>,dir_mode=<mode>,file_mode=<mode>,sfu");
153 printf("\n\nRarely used options:");
154 printf("\n\tport=<tcpport>,rsize=<size>,wsize=<size>,unc=<unc_name>,ip=<ip_address>,");
155 printf("\n\tdev,nodev,nouser_xattr,netbiosname=<OUR_RFC1001NAME>,hard,soft,intr,");
156 printf("\n\tnointr,ignorecase,noposixpaths,noacl,prefixpath=<path>,nobrl");
157 printf("\n\tin6_addr");
158 printf("\n\nOptions are described in more detail in the manual page");
159 printf("\n\tman 8 mount.cifs\n");
160 printf("\nTo display the version number of the mount helper:");
161 printf("\n\t%s -V\n",thisprogram
);
163 SAFE_FREE(mountpassword
);
167 /* caller frees username if necessary */
168 static char * getusername(void) {
169 char *username
= NULL
;
170 struct passwd
*password
= getpwuid(getuid());
173 username
= password
->pw_name
;
178 static char * parse_cifs_url(char * unc_name
)
180 printf("\nMounting cifs URL not implemented yet. Attempt to mount %s\n",unc_name
);
184 static int open_cred_file(char * file_name
)
190 fs
= fopen(file_name
,"r");
193 line_buf
= (char *)malloc(4096);
194 if(line_buf
== NULL
) {
199 while(fgets(line_buf
,4096,fs
)) {
200 /* parse line from credential file */
202 /* eat leading white space */
203 for(i
=0;i
<4086;i
++) {
204 if((line_buf
[i
] != ' ') && (line_buf
[i
] != '\t'))
206 /* if whitespace - skip past it */
208 if (strncasecmp("username",line_buf
+i
,8) == 0) {
209 temp_val
= strchr(line_buf
+ i
,'=');
211 /* go past equals sign */
213 for(length
= 0;length
<4087;length
++) {
214 if ((temp_val
[length
] == '\n')
215 || (temp_val
[length
] == '\0')) {
216 temp_val
[length
] = '\0';
221 printf("mount.cifs failed due to malformed username in credentials file");
222 memset(line_buf
,0,4096);
226 user_name
= (char *)calloc(1 + length
,1);
227 /* BB adding free of user_name string before exit,
228 not really necessary but would be cleaner */
229 strlcpy(user_name
,temp_val
, length
+1);
232 } else if (strncasecmp("password",line_buf
+i
,8) == 0) {
233 temp_val
= strchr(line_buf
+i
,'=');
235 /* go past equals sign */
237 for(length
= 0;length
<MOUNT_PASSWD_SIZE
+1;length
++) {
238 if ((temp_val
[length
] == '\n')
239 || (temp_val
[length
] == '\0')) {
240 temp_val
[length
] = '\0';
244 if(length
> MOUNT_PASSWD_SIZE
) {
245 printf("mount.cifs failed: password in credentials file too long\n");
246 memset(line_buf
,0, 4096);
249 if(mountpassword
== NULL
) {
250 mountpassword
= (char *)calloc(MOUNT_PASSWD_SIZE
+1,1);
252 memset(mountpassword
,0,MOUNT_PASSWD_SIZE
);
254 strlcpy(mountpassword
,temp_val
,MOUNT_PASSWD_SIZE
+1);
259 } else if (strncasecmp("domain",line_buf
+i
,6) == 0) {
260 temp_val
= strchr(line_buf
+i
,'=');
262 /* go past equals sign */
265 printf("\nDomain %s\n",temp_val
);
266 for(length
= 0;length
<DOMAIN_SIZE
+1;length
++) {
267 if ((temp_val
[length
] == '\n')
268 || (temp_val
[length
] == '\0')) {
269 temp_val
[length
] = '\0';
273 if(length
> DOMAIN_SIZE
) {
274 printf("mount.cifs failed: domain in credentials file too long\n");
277 if(domain_name
== NULL
) {
278 domain_name
= (char *)calloc(DOMAIN_SIZE
+1,1);
280 memset(domain_name
,0,DOMAIN_SIZE
);
282 strlcpy(domain_name
,temp_val
,DOMAIN_SIZE
+1);
295 static int get_password_from_file(int file_descript
, char * filename
)
301 if(mountpassword
== NULL
)
302 mountpassword
= (char *)calloc(MOUNT_PASSWD_SIZE
+1,1);
304 memset(mountpassword
, 0, MOUNT_PASSWD_SIZE
);
306 if (mountpassword
== NULL
) {
307 printf("malloc failed\n");
311 if(filename
!= NULL
) {
312 file_descript
= open(filename
, O_RDONLY
);
313 if(file_descript
< 0) {
314 printf("mount.cifs failed. %s attempting to open password file %s\n",
315 strerror(errno
),filename
);
319 /* else file already open and fd provided */
321 for(i
=0;i
<MOUNT_PASSWD_SIZE
;i
++) {
322 rc
= read(file_descript
,&c
,1);
324 printf("mount.cifs failed. Error %s reading password file\n",strerror(errno
));
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')) {
336 mountpassword
[i
] = '\0';
339 mountpassword
[i
] = c
;
342 if((i
== MOUNT_PASSWD_SIZE
) && (verboseflag
)) {
343 printf("\nWarning: password longer than %d characters specified in cifs password file",
347 if(filename
!= NULL
) {
348 close(file_descript
);
354 static int parse_options(char ** optionsp
, int * filesys_flags
)
357 char * percent_char
= NULL
;
359 char * next_keyword
= NULL
;
367 if (!optionsp
|| !*optionsp
)
372 printf("parsing options: %s\n", data
);
374 /* BB fixme check for separator override BB */
378 snprintf(user
,sizeof(user
),"%u",getuid());
380 snprintf(group
,sizeof(group
),"%u",getgid());
383 /* while ((data = strsep(&options, ",")) != NULL) { */
384 while(data
!= NULL
) {
385 /* check if ends with trailing comma */
389 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
390 /* data = next keyword */
391 /* value = next value ie stuff after equal sign */
393 next_keyword
= strchr(data
,','); /* BB handle sep= */
395 /* temporarily null terminate end of keyword=value pair */
399 /* temporarily null terminate keyword to make keyword and value distinct */
400 if ((value
= strchr(data
, '=')) != NULL
) {
405 if (strncmp(data
, "users",5) == 0) {
406 if(!value
|| !*value
) {
409 } else if (strncmp(data
, "user_xattr",10) == 0) {
410 /* do nothing - need to skip so not parsed as user name */
411 } else if (strncmp(data
, "user", 4) == 0) {
413 if (!value
|| !*value
) {
414 if(data
[4] == '\0') {
416 printf("\nskipping empty user mount parameter\n");
417 /* remove the parm since it would otherwise be confusing
418 to the kernel code which would think it was a real username */
421 printf("username specified with no parameter\n");
422 return 1; /* needs_arg; */
425 if (strnlen(value
, 260) < 260) {
427 percent_char
= strchr(value
,'%');
430 if(mountpassword
== NULL
)
431 mountpassword
= (char *)calloc(MOUNT_PASSWD_SIZE
+1,1);
434 printf("\nmount.cifs warning - password specified twice\n");
437 strlcpy(mountpassword
, percent_char
,MOUNT_PASSWD_SIZE
+1);
438 /* remove password from username */
439 while(*percent_char
!= 0) {
445 /* this is only case in which the user
446 name buf is not malloc - so we have to
447 check for domain name embedded within
448 the user name here since the later
449 call to check_for_domain will not be
451 domain_name
= check_for_domain(&value
);
453 printf("username too long\n");
457 } else if (strncmp(data
, "pass", 4) == 0) {
458 if (!value
|| !*value
) {
460 printf("\npassword specified twice, ignoring second\n");
463 } else if (strnlen(value
, 17) < 17) {
465 printf("\nmount.cifs warning - password specified twice\n");
468 printf("password too long\n");
471 } else if (strncmp(data
, "sec", 3) == 0) {
473 if (!strcmp(value
, "none"))
476 } else if (strncmp(data
, "ip", 2) == 0) {
477 if (!value
|| !*value
) {
478 printf("target ip address argument missing");
479 } else if (strnlen(value
, 35) < 35) {
481 printf("ip address %s override specified\n",value
);
484 printf("ip address too long\n");
487 } else if ((strncmp(data
, "unc", 3) == 0)
488 || (strncmp(data
, "target", 6) == 0)
489 || (strncmp(data
, "path", 4) == 0)) {
490 if (!value
|| !*value
) {
491 printf("invalid path to network resource\n");
492 return 1; /* needs_arg; */
493 } else if(strnlen(value
,5) < 5) {
494 printf("UNC name too short");
497 if (strnlen(value
, 300) < 300) {
499 if (strncmp(value
, "//", 2) == 0) {
501 printf("unc name specified twice, ignoring second\n");
504 } else if (strncmp(value
, "\\\\", 2) != 0) {
505 printf("UNC Path does not begin with // or \\\\ \n");
509 printf("unc name specified twice, ignoring second\n");
514 printf("CIFS: UNC name too long\n");
517 } else if ((strncmp(data
, "domain", 3) == 0)
518 || (strncmp(data
, "workgroup", 5) == 0)) {
519 if (!value
|| !*value
) {
520 printf("CIFS: invalid domain name\n");
521 return 1; /* needs_arg; */
523 if (strnlen(value
, DOMAIN_SIZE
+1) < DOMAIN_SIZE
+1) {
526 printf("domain name too long\n");
529 } else if (strncmp(data
, "cred", 4) == 0) {
530 if (value
&& *value
) {
531 rc
= open_cred_file(value
);
533 printf("error %d opening credential file %s\n",rc
, value
);
537 printf("invalid credential file name specified\n");
540 } else if (strncmp(data
, "uid", 3) == 0) {
541 if (value
&& *value
) {
543 if (!isdigit(*value
)) {
546 if (!(pw
= getpwnam(value
))) {
547 printf("bad user name \"%s\"\n", value
);
550 snprintf(user
, sizeof(user
), "%u", pw
->pw_uid
);
552 strlcpy(user
,value
,sizeof(user
));
556 } else if (strncmp(data
, "gid", 3) == 0) {
557 if (value
&& *value
) {
559 if (!isdigit(*value
)) {
562 if (!(gr
= getgrnam(value
))) {
563 printf("bad group name \"%s\"\n", value
);
566 snprintf(group
, sizeof(group
), "%u", gr
->gr_gid
);
568 strlcpy(group
,value
,sizeof(group
));
572 /* fmask and dmask synonyms for people used to smbfs syntax */
573 } else if (strcmp(data
, "file_mode") == 0 || strcmp(data
, "fmask")==0) {
574 if (!value
|| !*value
) {
575 printf ("Option '%s' requires a numerical argument\n", data
);
579 if (value
[0] != '0') {
580 printf ("WARNING: '%s' not expressed in octal.\n", data
);
583 if (strcmp (data
, "fmask") == 0) {
584 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
585 data
= "file_mode"; /* BB fix this */
587 } else if (strcmp(data
, "dir_mode") == 0 || strcmp(data
, "dmask")==0) {
588 if (!value
|| !*value
) {
589 printf ("Option '%s' requires a numerical argument\n", data
);
593 if (value
[0] != '0') {
594 printf ("WARNING: '%s' not expressed in octal.\n", data
);
597 if (strcmp (data
, "dmask") == 0) {
598 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
601 /* the following eight mount options should be
602 stripped out from what is passed into the kernel
603 since these eight options are best passed as the
604 mount flags rather than redundantly to the kernel
605 and could generate spurious warnings depending on the
606 level of the corresponding cifs vfs kernel code */
607 } else if (strncmp(data
, "nosuid", 6) == 0) {
608 *filesys_flags
|= MS_NOSUID
;
609 } else if (strncmp(data
, "suid", 4) == 0) {
610 *filesys_flags
&= ~MS_NOSUID
;
611 } else if (strncmp(data
, "nodev", 5) == 0) {
612 *filesys_flags
|= MS_NODEV
;
613 } else if ((strncmp(data
, "nobrl", 5) == 0) ||
614 (strncmp(data
, "nolock", 6) == 0)) {
615 *filesys_flags
&= ~MS_MANDLOCK
;
616 } else if (strncmp(data
, "dev", 3) == 0) {
617 *filesys_flags
&= ~MS_NODEV
;
618 } else if (strncmp(data
, "noexec", 6) == 0) {
619 *filesys_flags
|= MS_NOEXEC
;
620 } else if (strncmp(data
, "exec", 4) == 0) {
621 *filesys_flags
&= ~MS_NOEXEC
;
622 } else if (strncmp(data
, "guest", 5) == 0) {
624 } else if (strncmp(data
, "ro", 2) == 0) {
625 *filesys_flags
|= MS_RDONLY
;
626 } else if (strncmp(data
, "rw", 2) == 0) {
627 *filesys_flags
&= ~MS_RDONLY
;
628 } else if (strncmp(data
, "remount", 7) == 0) {
629 *filesys_flags
|= MS_REMOUNT
;
630 } /* else if (strnicmp(data, "port", 4) == 0) {
631 if (value && *value) {
633 simple_strtoul(value, &value, 0);
635 } else if (strnicmp(data, "rsize", 5) == 0) {
636 if (value && *value) {
638 simple_strtoul(value, &value, 0);
640 } else if (strnicmp(data, "wsize", 5) == 0) {
641 if (value && *value) {
643 simple_strtoul(value, &value, 0);
645 } else if (strnicmp(data, "version", 3) == 0) {
647 printf("CIFS: Unknown mount option %s\n",data);
648 } */ /* nothing to do on those four mount options above.
649 Just pass to kernel and ignore them here */
651 /* Copy (possibly modified) option to out */
652 word_len
= strlen(data
);
654 word_len
+= 1 + strlen(value
);
656 out
= (char *)realloc(out
, out_len
+ word_len
+ 2);
663 strlcat(out
, ",", out_len
+ word_len
+ 2);
668 snprintf(out
+ out_len
, word_len
+ 1, "%s=%s", data
, value
);
670 snprintf(out
+ out_len
, word_len
+ 1, "%s", data
);
671 out_len
= strlen(out
);
677 /* special-case the uid and gid */
679 word_len
= strlen(user
);
681 out
= (char *)realloc(out
, out_len
+ word_len
+ 6);
688 strlcat(out
, ",", out_len
+ word_len
+ 6);
691 snprintf(out
+ out_len
, word_len
+ 5, "uid=%s", user
);
692 out_len
= strlen(out
);
695 word_len
= strlen(group
);
697 out
= (char *)realloc(out
, out_len
+ 1 + word_len
+ 6);
704 strlcat(out
, ",", out_len
+ word_len
+ 6);
707 snprintf(out
+ out_len
, word_len
+ 5, "gid=%s", group
);
708 out_len
= strlen(out
);
711 SAFE_FREE(*optionsp
);
716 /* replace all (one or more) commas with double commas */
717 static void check_for_comma(char ** ppasswrd
)
722 int number_of_commas
= 0;
737 if(number_of_commas
== 0)
739 if(number_of_commas
> MOUNT_PASSWD_SIZE
) {
740 /* would otherwise overflow the mount options buffer */
741 printf("\nInvalid password. Password contains too many commas.\n");
745 new_pass_buf
= (char *)malloc(len
+number_of_commas
+1);
746 if(new_pass_buf
== NULL
)
749 for(i
=0,j
=0;i
<len
;i
++,j
++) {
750 new_pass_buf
[j
] = pass
[i
];
753 new_pass_buf
[j
] = pass
[i
];
756 new_pass_buf
[len
+number_of_commas
] = 0;
758 SAFE_FREE(*ppasswrd
);
759 *ppasswrd
= new_pass_buf
;
764 /* Usernames can not have backslash in them and we use
765 [BB check if usernames can have forward slash in them BB]
766 backslash as domain\user separator character
768 static char * check_for_domain(char **ppuser
)
770 char * original_string
;
780 original_string
= *ppuser
;
782 if (original_string
== NULL
)
785 original_len
= strlen(original_string
);
787 usernm
= strchr(*ppuser
,'/');
788 if (usernm
== NULL
) {
789 usernm
= strchr(*ppuser
,'\\');
795 printf("Domain name specified twice. Username probably malformed\n");
801 if (domainnm
[0] != 0) {
804 printf("null domain\n");
806 len
= strlen(domainnm
);
807 /* reset domainm to new buffer, and copy
808 domain name into it */
809 domainnm
= (char *)malloc(len
+1);
813 strlcpy(domainnm
,*ppuser
,len
+1);
815 /* move_string(*ppuser, usernm+1) */
816 len
= strlen(usernm
+1);
818 if(len
>= original_len
) {
819 /* should not happen */
823 for(i
=0;i
<original_len
;i
++) {
825 original_string
[i
] = usernm
[i
+1];
826 else /* stuff with commas to remove last parm */
827 original_string
[i
] = ',';
830 /* BB add check for more than one slash?
838 /* replace all occurances of "from" in a string with "to" */
839 static void replace_char(char *string
, char from
, char to
, int maxlen
)
841 char *lastchar
= string
+ maxlen
;
843 string
= strchr(string
, from
);
846 if (string
>= lastchar
)
852 /* Note that caller frees the returned buffer if necessary */
853 static char * parse_server(char ** punc_name
)
855 char * unc_name
= *punc_name
;
856 int length
= strnlen(unc_name
, MAX_UNC_LEN
);
858 char * ipaddress_string
= NULL
;
859 struct hostent
* host_entry
= NULL
;
860 struct in_addr server_ipaddr
;
862 if(length
> (MAX_UNC_LEN
- 1)) {
863 printf("mount error: UNC name too long");
866 if (strncasecmp("cifs://",unc_name
,7) == 0)
867 return parse_cifs_url(unc_name
+7);
868 if (strncasecmp("smb://",unc_name
,6) == 0) {
869 return parse_cifs_url(unc_name
+6);
873 /* BB add code to find DFS root here */
874 printf("\nMounting the DFS root for domain not implemented yet\n");
877 if(strncmp(unc_name
,"//",2) && strncmp(unc_name
,"\\\\",2)) {
878 /* check for nfs syntax ie server:share */
879 share
= strchr(unc_name
,':');
881 *punc_name
= (char *)malloc(length
+3);
882 if(*punc_name
== NULL
) {
883 /* put the original string back if
885 *punc_name
= unc_name
;
889 strlcpy((*punc_name
)+2,unc_name
,length
+1);
891 unc_name
= *punc_name
;
892 unc_name
[length
+2] = 0;
893 goto continue_unc_parsing
;
895 printf("mount error: improperly formatted UNC name.");
896 printf(" %s does not begin with \\\\ or //\n",unc_name
);
900 continue_unc_parsing
:
905 /* allow for either delimiter between host and sharename */
906 if ((share
= strpbrk(unc_name
, "/\\"))) {
907 *share
= 0; /* temporarily terminate the string */
910 host_entry
= gethostbyname(unc_name
);
912 *(share
- 1) = '/'; /* put delimiter back */
914 /* we don't convert the prefixpath delimiters since '\\' is a valid char in posix paths */
915 if ((prefixpath
= strpbrk(share
, "/\\"))) {
916 *prefixpath
= 0; /* permanently terminate the string */
917 if (!strlen(++prefixpath
))
918 prefixpath
= NULL
; /* this needs to be done explicitly */
922 printf("ip address specified explicitly\n");
925 if(host_entry
== NULL
) {
926 printf("mount error: could not find target server. TCP name %s not found\n", unc_name
);
929 /* BB should we pass an alternate version of the share name as Unicode */
930 /* BB what about ipv6? BB */
931 /* BB add retries with alternate servers in list */
933 memcpy(&server_ipaddr
.s_addr
, host_entry
->h_addr
, 4);
935 ipaddress_string
= inet_ntoa(server_ipaddr
);
936 if(ipaddress_string
== NULL
) {
937 printf("mount error: could not get valid ip address for target server\n");
940 return ipaddress_string
;
943 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
944 printf("Mounting the DFS root for a particular server not implemented yet\n");
951 static struct option longopts
[] = {
952 { "all", 0, NULL
, 'a' },
953 { "help",0, NULL
, 'h' },
954 { "move",0, NULL
, 'm' },
955 { "bind",0, NULL
, 'b' },
956 { "read-only", 0, NULL
, 'r' },
957 { "ro", 0, NULL
, 'r' },
958 { "verbose", 0, NULL
, 'v' },
959 { "version", 0, NULL
, 'V' },
960 { "read-write", 0, NULL
, 'w' },
961 { "rw", 0, NULL
, 'w' },
962 { "options", 1, NULL
, 'o' },
963 { "type", 1, NULL
, 't' },
964 { "rsize",1, NULL
, 'R' },
965 { "wsize",1, NULL
, 'W' },
966 { "uid", 1, NULL
, '1'},
967 { "gid", 1, NULL
, '2'},
968 { "user",1,NULL
,'u'},
969 { "username",1,NULL
,'u'},
971 { "domain",1,NULL
,'d'},
972 { "password",1,NULL
,'p'},
973 { "pass",1,NULL
,'p'},
974 { "credentials",1,NULL
,'c'},
975 { "port",1,NULL
,'P'},
976 /* { "uuid",1,NULL,'U'}, */ /* BB unimplemented */
980 /* convert a string to uppercase. return false if the string
981 * wasn't ASCII or was a NULL ptr */
983 uppercase_string(char *string
)
989 /* check for unicode */
990 if ((unsigned char) string
[0] & 0x80)
992 *string
= toupper((unsigned char) *string
);
999 int main(int argc
, char ** argv
)
1002 int flags
= MS_MANDLOCK
; /* no need to set legacy MS_MGC_VAL */
1003 char * orgoptions
= NULL
;
1004 char * share_name
= NULL
;
1005 char * ipaddr
= NULL
;
1007 char * mountpoint
= NULL
;
1008 char * options
= NULL
;
1009 char * resolved_path
= NULL
;
1020 size_t options_size
= 0;
1021 int retry
= 0; /* set when we have to retry mount with uppercase */
1022 struct stat statbuf
;
1023 struct utsname sysinfo
;
1024 struct mntent mountent
;
1027 /* setlocale(LC_ALL, "");
1028 bindtextdomain(PACKAGE, LOCALEDIR);
1029 textdomain(PACKAGE); */
1032 thisprogram
= argv
[0];
1038 if(thisprogram
== NULL
)
1039 thisprogram
= "mount.cifs";
1042 /* BB add workstation name and domain and pass down */
1044 /* #ifdef _GNU_SOURCE
1045 printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
1049 share_name
= strndup(argv
[1], MAX_UNC_LEN
);
1050 if (share_name
== NULL
) {
1051 fprintf(stderr
, "%s: %s", argv
[0], strerror(ENOMEM
));
1054 mountpoint
= argv
[2];
1060 /* add sharename in opts string as unc= parm */
1062 while ((c
= getopt_long (argc
, argv
, "afFhilL:no:O:rsSU:vVwt:",
1063 longopts
, NULL
)) != -1) {
1065 /* No code to do the following options yet */
1067 list_with_volumelabel = 1;
1070 volumelabel = optarg;
1077 case 'h': /* help */
1078 mount_cifs_usage ();
1088 "option 'b' (MS_BIND) not supported\n");
1096 "option 'm' (MS_MOVE) not supported\n");
1100 orgoptions
= strdup(optarg
);
1102 case 'r': /* mount readonly */
1112 printf ("mount.cifs version: %s.%s%s\n",
1113 MOUNT_CIFS_VERSION_MAJOR
,
1114 MOUNT_CIFS_VERSION_MINOR
,
1115 MOUNT_CIFS_VENDOR_SUFFIX
);
1118 flags
&= ~MS_RDONLY
;
1121 rsize
= atoi(optarg
) ;
1124 wsize
= atoi(optarg
);
1127 if (isdigit(*optarg
)) {
1130 uid
= strtoul(optarg
, &ep
, 10);
1132 printf("bad uid value \"%s\"\n", optarg
);
1138 if (!(pw
= getpwnam(optarg
))) {
1139 printf("bad user name \"%s\"\n", optarg
);
1147 if (isdigit(*optarg
)) {
1150 gid
= strtoul(optarg
, &ep
, 10);
1152 printf("bad gid value \"%s\"\n", optarg
);
1158 if (!(gr
= getgrnam(optarg
))) {
1159 printf("bad user name \"%s\"\n", optarg
);
1171 domain_name
= optarg
; /* BB fix this - currently ignored */
1175 if(mountpassword
== NULL
)
1176 mountpassword
= (char *)calloc(MOUNT_PASSWD_SIZE
+1,1);
1179 strlcpy(mountpassword
,optarg
,MOUNT_PASSWD_SIZE
+1);
1183 get_password_from_file(0 /* stdin */,NULL
);
1188 printf("unknown mount option %c\n",c
);
1194 if((argc
< 3) || (dev_name
== NULL
) || (mountpoint
== NULL
)) {
1199 if (getenv("PASSWD")) {
1200 if(mountpassword
== NULL
)
1201 mountpassword
= (char *)calloc(MOUNT_PASSWD_SIZE
+1,1);
1203 strlcpy(mountpassword
,getenv("PASSWD"),MOUNT_PASSWD_SIZE
+1);
1206 } else if (getenv("PASSWD_FD")) {
1207 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL
);
1208 } else if (getenv("PASSWD_FILE")) {
1209 get_password_from_file(0, getenv("PASSWD_FILE"));
1212 if (orgoptions
&& parse_options(&orgoptions
, &flags
)) {
1216 ipaddr
= parse_server(&share_name
);
1217 if((ipaddr
== NULL
) && (got_ip
== 0)) {
1218 printf("No ip address specified and hostname not found\n");
1223 /* BB save off path and pop after mount returns? */
1224 resolved_path
= (char *)malloc(PATH_MAX
+1);
1226 /* Note that if we can not canonicalize the name, we get
1227 another chance to see if it is valid when we chdir to it */
1228 if (realpath(mountpoint
, resolved_path
)) {
1229 mountpoint
= resolved_path
;
1232 if(chdir(mountpoint
)) {
1233 printf("mount error: can not change directory into mount target %s\n",mountpoint
);
1238 if(stat (".", &statbuf
)) {
1239 printf("mount error: mount point %s does not exist\n",mountpoint
);
1244 if (S_ISDIR(statbuf
.st_mode
) == 0) {
1245 printf("mount error: mount point %s is not a directory\n",mountpoint
);
1250 if((getuid() != 0) && (geteuid() == 0)) {
1251 if((statbuf
.st_uid
== getuid()) && (S_IRWXU
== (statbuf
.st_mode
& S_IRWXU
))) {
1252 #ifndef CIFS_ALLOW_USR_SUID
1253 /* Do not allow user mounts to control suid flag
1254 for mount unless explicitly built that way */
1255 flags
|= MS_NOSUID
| MS_NODEV
;
1258 printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n");
1264 user_name
= getusername();
1268 if(got_password
== 0) {
1269 char *tmp_pass
= getpass("Password: "); /* BB obsolete sys call but
1270 no good replacement yet. */
1271 mountpassword
= (char *)calloc(MOUNT_PASSWD_SIZE
+1,1);
1272 if (!tmp_pass
|| !mountpassword
) {
1273 printf("Password not entered, exiting\n");
1276 strlcpy(mountpassword
, tmp_pass
, MOUNT_PASSWD_SIZE
+1);
1279 /* FIXME launch daemon (handles dfs name resolution and credential change)
1280 remember to clear parms and overwrite password field before launching */
1283 optlen
= strlen(orgoptions
);
1288 optlen
+= strlen(share_name
) + 4;
1290 printf("No server share name specified\n");
1291 printf("\nMounting the DFS root for server not implemented yet\n");
1295 optlen
+= strlen(user_name
) + 6;
1297 optlen
+= strlen(ipaddr
) + 4;
1299 optlen
+= strlen(mountpassword
) + 6;
1301 options_size
= optlen
+ 10 + DOMAIN_SIZE
;
1302 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 */);
1304 if(options
== NULL
) {
1305 printf("Could not allocate memory for mount options\n");
1310 strlcpy(options
,"unc=",options_size
);
1311 strlcat(options
,share_name
,options_size
);
1312 /* scan backwards and reverse direction of slash */
1313 temp
= strrchr(options
, '/');
1314 if(temp
> options
+ 6)
1317 strlcat(options
,",ip=",options_size
);
1318 strlcat(options
,ipaddr
,options_size
);
1322 /* check for syntax like user=domain\user */
1324 domain_name
= check_for_domain(&user_name
);
1325 strlcat(options
,",user=",options_size
);
1326 strlcat(options
,user_name
,options_size
);
1330 /* extra length accounted for in option string above */
1331 strlcat(options
,",domain=",options_size
);
1332 strlcat(options
,domain_name
,options_size
);
1336 /* Commas have to be doubled, or else they will
1337 look like the parameter separator */
1338 /* if(sep is not set)*/
1340 check_for_comma(&mountpassword
);
1341 strlcat(options
,",pass=",options_size
);
1342 strlcat(options
,mountpassword
,options_size
);
1345 strlcat(options
,",ver=",options_size
);
1346 strlcat(options
,MOUNT_CIFS_VERSION_MAJOR
,options_size
);
1349 strlcat(options
,",",options_size
);
1350 strlcat(options
,orgoptions
,options_size
);
1353 strlcat(options
,",prefixpath=",options_size
);
1354 strlcat(options
,prefixpath
,options_size
); /* no need to cat the / */
1357 printf("\nmount.cifs kernel mount options %s \n",options
);
1359 /* convert all '\\' to '/' in share portion so that /proc/mounts looks pretty */
1360 replace_char(dev_name
, '\\', '/', strlen(share_name
));
1362 if(mount(dev_name
, mountpoint
, "cifs", flags
, options
)) {
1363 /* remember to kill daemon on error */
1366 printf("mount failed but no error number set\n");
1369 printf("mount error: cifs filesystem not supported by the system\n");
1374 if (uppercase_string(dev_name
) &&
1375 uppercase_string(share_name
) &&
1376 uppercase_string(prefixpath
)) {
1377 printf("retrying with upper case share name\n");
1382 printf("mount error %d = %s\n",errno
,strerror(errno
));
1384 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
1388 pmntfile
= setmntent(MOUNTED
, "a+");
1390 mountent
.mnt_fsname
= dev_name
;
1391 mountent
.mnt_dir
= mountpoint
;
1392 mountent
.mnt_type
= CONST_DISCARD(char *,"cifs");
1393 mountent
.mnt_opts
= (char *)malloc(220);
1394 if(mountent
.mnt_opts
) {
1395 char * mount_user
= getusername();
1396 memset(mountent
.mnt_opts
,0,200);
1397 if(flags
& MS_RDONLY
)
1398 strlcat(mountent
.mnt_opts
,"ro",220);
1400 strlcat(mountent
.mnt_opts
,"rw",220);
1401 if(flags
& MS_MANDLOCK
)
1402 strlcat(mountent
.mnt_opts
,",mand",220);
1403 if(flags
& MS_NOEXEC
)
1404 strlcat(mountent
.mnt_opts
,",noexec",220);
1405 if(flags
& MS_NOSUID
)
1406 strlcat(mountent
.mnt_opts
,",nosuid",220);
1407 if(flags
& MS_NODEV
)
1408 strlcat(mountent
.mnt_opts
,",nodev",220);
1409 if(flags
& MS_SYNCHRONOUS
)
1410 strlcat(mountent
.mnt_opts
,",synch",220);
1413 strlcat(mountent
.mnt_opts
,",user=",220);
1414 strlcat(mountent
.mnt_opts
,mount_user
,220);
1416 /* free(mount_user); do not free static mem */
1419 mountent
.mnt_freq
= 0;
1420 mountent
.mnt_passno
= 0;
1421 rc
= addmntent(pmntfile
,&mountent
);
1422 endmntent(pmntfile
);
1423 SAFE_FREE(mountent
.mnt_opts
);
1425 printf("could not update mount table\n");
1431 int len
= strlen(mountpassword
);
1432 memset(mountpassword
,0,len
);
1433 SAFE_FREE(mountpassword
);
1437 SAFE_FREE(orgoptions
);
1438 SAFE_FREE(resolved_path
);
1439 SAFE_FREE(share_name
);