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')) {
220 printf("mount.cifs failed due to malformed username in credentials file");
221 memset(line_buf,0,4096);
225 user_name = (char *)calloc(1 + length,1);
226 /* BB adding free of user_name string before exit,
227 not really necessary but would be cleaner */
228 strlcpy(user_name,temp_val, length+1);
231 } else if (strncasecmp("password",line_buf+i,8) == 0) {
232 temp_val = strchr(line_buf+i,'=');
234 /* go past equals sign */
236 for(length = 0;length<MOUNT_PASSWD_SIZE+1;length++) {
237 if ((temp_val[length] == '\n')
238 || (temp_val[length] == '\0')) {
239 temp_val[length] = '\0';
243 if(length > MOUNT_PASSWD_SIZE) {
244 printf("mount.cifs failed: password in credentials file too long\n");
245 memset(line_buf,0, 4096);
248 if(mountpassword == NULL) {
249 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
251 memset(mountpassword,0,MOUNT_PASSWD_SIZE);
253 strlcpy(mountpassword,temp_val,MOUNT_PASSWD_SIZE+1);
258 } else if (strncasecmp("domain",line_buf+i,6) == 0) {
259 temp_val = strchr(line_buf+i,'=');
261 /* go past equals sign */
264 printf("\nDomain %s\n",temp_val);
265 for(length = 0;length<DOMAIN_SIZE+1;length++) {
266 if ((temp_val[length] == '\n')
267 || (temp_val[length] == '\0')) {
268 temp_val[length] = '\0';
272 if(length > DOMAIN_SIZE) {
273 printf("mount.cifs failed: domain in credentials file too long\n");
276 if(domain_name == NULL) {
277 domain_name = (char *)calloc(DOMAIN_SIZE+1,1);
279 memset(domain_name,0,DOMAIN_SIZE);
281 strlcpy(domain_name,temp_val,DOMAIN_SIZE+1);
294 static int get_password_from_file(int file_descript, char * filename)
300 if(mountpassword == NULL)
301 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
303 memset(mountpassword, 0, MOUNT_PASSWD_SIZE);
305 if (mountpassword == NULL) {
306 printf("malloc failed\n");
310 if(filename != NULL) {
311 file_descript = open(filename, O_RDONLY);
312 if(file_descript < 0) {
313 printf("mount.cifs failed. %s attempting to open password file %s\n",
314 strerror(errno),filename);
318 /* else file already open and fd provided */
320 for(i=0;i<MOUNT_PASSWD_SIZE;i++) {
321 rc = read(file_descript,&c,1);
323 printf("mount.cifs failed. Error %s reading password file\n",strerror(errno));
325 close(file_descript);
328 if(mountpassword[0] == 0) {
330 printf("\nWarning: null password used since cifs password file empty");
333 } else /* read valid character */ {
334 if((c == 0) || (c == '\n')) {
337 mountpassword[i] = c;
340 if((i == MOUNT_PASSWD_SIZE) && (verboseflag)) {
341 printf("\nWarning: password longer than %d characters specified in cifs password file",
345 if(filename != NULL) {
346 close(file_descript);
352 static int parse_options(char ** optionsp, int * filesys_flags)
355 char * percent_char = NULL;
357 char * next_keyword = NULL;
365 if (!optionsp || !*optionsp)
370 printf("parsing options: %s\n", data);
372 /* BB fixme check for separator override BB */
376 snprintf(user,sizeof(user),"%u",getuid());
378 snprintf(group,sizeof(group),"%u",getgid());
381 /* while ((data = strsep(&options, ",")) != NULL) { */
382 while(data != NULL) {
383 /* check if ends with trailing comma */
387 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
388 /* data = next keyword */
389 /* value = next value ie stuff after equal sign */
391 next_keyword = strchr(data,','); /* BB handle sep= */
393 /* temporarily null terminate end of keyword=value pair */
397 /* temporarily null terminate keyword to make keyword and value distinct */
398 if ((value = strchr(data, '=')) != NULL) {
403 if (strncmp(data, "users",5) == 0) {
404 if(!value || !*value) {
407 } else if (strncmp(data, "user_xattr",10) == 0) {
408 /* do nothing - need to skip so not parsed as user name */
409 } else if (strncmp(data, "user", 4) == 0) {
411 if (!value || !*value) {
412 if(data[4] == '\0') {
414 printf("\nskipping empty user mount parameter\n");
415 /* remove the parm since it would otherwise be confusing
416 to the kernel code which would think it was a real username */
419 printf("username specified with no parameter\n");
420 return 1; /* needs_arg; */
423 if (strnlen(value, 260) < 260) {
425 percent_char = strchr(value,'%');
428 if(mountpassword == NULL)
429 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
432 printf("\nmount.cifs warning - password specified twice\n");
435 strlcpy(mountpassword, percent_char,MOUNT_PASSWD_SIZE+1);
436 /* remove password from username */
437 while(*percent_char != 0) {
443 /* this is only case in which the user
444 name buf is not malloc - so we have to
445 check for domain name embedded within
446 the user name here since the later
447 call to check_for_domain will not be
449 domain_name = check_for_domain(&value);
451 printf("username too long\n");
455 } else if (strncmp(data, "pass", 4) == 0) {
456 if (!value || !*value) {
458 printf("\npassword specified twice, ignoring second\n");
461 } else if (strnlen(value, 17) < 17) {
463 printf("\nmount.cifs warning - password specified twice\n");
466 printf("password too long\n");
469 } else if (strncmp(data, "sec", 3) == 0) {
471 if (!strcmp(value, "none"))
474 } else if (strncmp(data, "ip", 2) == 0) {
475 if (!value || !*value) {
476 printf("target ip address argument missing");
477 } else if (strnlen(value, 35) < 35) {
479 printf("ip address %s override specified\n",value);
482 printf("ip address too long\n");
485 } else if ((strncmp(data, "unc", 3) == 0)
486 || (strncmp(data, "target", 6) == 0)
487 || (strncmp(data, "path", 4) == 0)) {
488 if (!value || !*value) {
489 printf("invalid path to network resource\n");
490 return 1; /* needs_arg; */
491 } else if(strnlen(value,5) < 5) {
492 printf("UNC name too short");
495 if (strnlen(value, 300) < 300) {
497 if (strncmp(value, "//", 2) == 0) {
499 printf("unc name specified twice, ignoring second\n");
502 } else if (strncmp(value, "\\\\", 2) != 0) {
503 printf("UNC Path does not begin with // or \\\\ \n");
507 printf("unc name specified twice, ignoring second\n");
512 printf("CIFS: UNC name too long\n");
515 } else if ((strncmp(data, "domain", 3) == 0)
516 || (strncmp(data, "workgroup", 5) == 0)) {
517 if (!value || !*value) {
518 printf("CIFS: invalid domain name\n");
519 return 1; /* needs_arg; */
521 if (strnlen(value, DOMAIN_SIZE+1) < DOMAIN_SIZE+1) {
524 printf("domain name too long\n");
527 } else if (strncmp(data, "cred", 4) == 0) {
528 if (value && *value) {
529 rc = open_cred_file(value);
531 printf("error %d opening credential file %s\n",rc, value);
535 printf("invalid credential file name specified\n");
538 } else if (strncmp(data, "uid", 3) == 0) {
539 if (value && *value) {
541 if (!isdigit(*value)) {
544 if (!(pw = getpwnam(value))) {
545 printf("bad user name \"%s\"\n", value);
548 snprintf(user, sizeof(user), "%u", pw->pw_uid);
550 strlcpy(user,value,sizeof(user));
554 } else if (strncmp(data, "gid", 3) == 0) {
555 if (value && *value) {
557 if (!isdigit(*value)) {
560 if (!(gr = getgrnam(value))) {
561 printf("bad group name \"%s\"\n", value);
564 snprintf(group, sizeof(group), "%u", gr->gr_gid);
566 strlcpy(group,value,sizeof(group));
570 /* fmask and dmask synonyms for people used to smbfs syntax */
571 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
572 if (!value || !*value) {
573 printf ("Option '%s' requires a numerical argument\n", data);
577 if (value[0] != '0') {
578 printf ("WARNING: '%s' not expressed in octal.\n", data);
581 if (strcmp (data, "fmask") == 0) {
582 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
583 data = "file_mode"; /* BB fix this */
585 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
586 if (!value || !*value) {
587 printf ("Option '%s' requires a numerical argument\n", data);
591 if (value[0] != '0') {
592 printf ("WARNING: '%s' not expressed in octal.\n", data);
595 if (strcmp (data, "dmask") == 0) {
596 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
599 /* the following eight mount options should be
600 stripped out from what is passed into the kernel
601 since these eight options are best passed as the
602 mount flags rather than redundantly to the kernel
603 and could generate spurious warnings depending on the
604 level of the corresponding cifs vfs kernel code */
605 } else if (strncmp(data, "nosuid", 6) == 0) {
606 *filesys_flags |= MS_NOSUID;
607 } else if (strncmp(data, "suid", 4) == 0) {
608 *filesys_flags &= ~MS_NOSUID;
609 } else if (strncmp(data, "nodev", 5) == 0) {
610 *filesys_flags |= MS_NODEV;
611 } else if ((strncmp(data, "nobrl", 5) == 0) ||
612 (strncmp(data, "nolock", 6) == 0)) {
613 *filesys_flags &= ~MS_MANDLOCK;
614 } else if (strncmp(data, "dev", 3) == 0) {
615 *filesys_flags &= ~MS_NODEV;
616 } else if (strncmp(data, "noexec", 6) == 0) {
617 *filesys_flags |= MS_NOEXEC;
618 } else if (strncmp(data, "exec", 4) == 0) {
619 *filesys_flags &= ~MS_NOEXEC;
620 } else if (strncmp(data, "guest", 5) == 0) {
622 } else if (strncmp(data, "ro", 2) == 0) {
623 *filesys_flags |= MS_RDONLY;
624 } else if (strncmp(data, "rw", 2) == 0) {
625 *filesys_flags &= ~MS_RDONLY;
626 } else if (strncmp(data, "remount", 7) == 0) {
627 *filesys_flags |= MS_REMOUNT;
628 } /* else if (strnicmp(data, "port", 4) == 0) {
629 if (value && *value) {
631 simple_strtoul(value, &value, 0);
633 } else if (strnicmp(data, "rsize", 5) == 0) {
634 if (value && *value) {
636 simple_strtoul(value, &value, 0);
638 } else if (strnicmp(data, "wsize", 5) == 0) {
639 if (value && *value) {
641 simple_strtoul(value, &value, 0);
643 } else if (strnicmp(data, "version", 3) == 0) {
645 printf("CIFS: Unknown mount option %s\n",data);
646 } */ /* nothing to do on those four mount options above.
647 Just pass to kernel and ignore them here */
649 /* Copy (possibly modified) option to out */
650 word_len = strlen(data);
652 word_len += 1 + strlen(value);
654 out = (char *)realloc(out, out_len + word_len + 2);
661 strlcat(out, ",", out_len + word_len + 2);
666 snprintf(out + out_len, word_len + 1, "%s=%s", data, value);
668 snprintf(out + out_len, word_len + 1, "%s", data);
669 out_len = strlen(out);
675 /* special-case the uid and gid */
677 word_len = strlen(user);
679 out = (char *)realloc(out, out_len + word_len + 6);
686 strlcat(out, ",", out_len + word_len + 6);
689 snprintf(out + out_len, word_len + 5, "uid=%s", user);
690 out_len = strlen(out);
693 word_len = strlen(group);
695 out = (char *)realloc(out, out_len + 1 + word_len + 6);
702 strlcat(out, ",", out_len + word_len + 6);
705 snprintf(out + out_len, word_len + 5, "gid=%s", group);
706 out_len = strlen(out);
709 SAFE_FREE(*optionsp);
714 /* replace all (one or more) commas with double commas */
715 static void check_for_comma(char ** ppasswrd)
720 int number_of_commas = 0;
735 if(number_of_commas == 0)
737 if(number_of_commas > MOUNT_PASSWD_SIZE) {
738 /* would otherwise overflow the mount options buffer */
739 printf("\nInvalid password. Password contains too many commas.\n");
743 new_pass_buf = (char *)malloc(len+number_of_commas+1);
744 if(new_pass_buf == NULL)
747 for(i=0,j=0;i<len;i++,j++) {
748 new_pass_buf[j] = pass[i];
751 new_pass_buf[j] = pass[i];
754 new_pass_buf[len+number_of_commas] = 0;
756 SAFE_FREE(*ppasswrd);
757 *ppasswrd = new_pass_buf;
762 /* Usernames can not have backslash in them and we use
763 [BB check if usernames can have forward slash in them BB]
764 backslash as domain\user separator character
766 static char * check_for_domain(char **ppuser)
768 char * original_string;
778 original_string = *ppuser;
780 if (original_string == NULL)
783 original_len = strlen(original_string);
785 usernm = strchr(*ppuser,'/');
786 if (usernm == NULL) {
787 usernm = strchr(*ppuser,'\\');
793 printf("Domain name specified twice. Username probably malformed\n");
799 if (domainnm[0] != 0) {
802 printf("null domain\n");
804 len = strlen(domainnm);
805 /* reset domainm to new buffer, and copy
806 domain name into it */
807 domainnm = (char *)malloc(len+1);
811 strlcpy(domainnm,*ppuser,len+1);
813 /* move_string(*ppuser, usernm+1) */
814 len = strlen(usernm+1);
816 if(len >= original_len) {
817 /* should not happen */
821 for(i=0;i<original_len;i++) {
823 original_string[i] = usernm[i+1];
824 else /* stuff with commas to remove last parm */
825 original_string[i] = ',';
828 /* BB add check for more than one slash?
836 /* replace all occurances of "from" in a string with "to" */
837 static void replace_char(char *string, char from, char to, int maxlen)
839 char *lastchar = string + maxlen;
841 string = strchr(string, from);
844 if (string >= lastchar)
850 /* Note that caller frees the returned buffer if necessary */
851 static char * parse_server(char ** punc_name)
853 char * unc_name = *punc_name;
854 int length = strnlen(unc_name, MAX_UNC_LEN);
856 char * ipaddress_string = NULL;
857 struct hostent * host_entry = NULL;
858 struct in_addr server_ipaddr;
860 if(length > (MAX_UNC_LEN - 1)) {
861 printf("mount error: UNC name too long");
864 if (strncasecmp("cifs://",unc_name,7) == 0)
865 return parse_cifs_url(unc_name+7);
866 if (strncasecmp("smb://",unc_name,6) == 0) {
867 return parse_cifs_url(unc_name+6);
871 /* BB add code to find DFS root here */
872 printf("\nMounting the DFS root for domain not implemented yet\n");
875 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
876 /* check for nfs syntax ie server:share */
877 share = strchr(unc_name,':');
879 *punc_name = (char *)malloc(length+3);
880 if(*punc_name == NULL) {
881 /* put the original string back if
883 *punc_name = unc_name;
887 strlcpy((*punc_name)+2,unc_name,length+1);
889 unc_name = *punc_name;
890 unc_name[length+2] = 0;
891 goto continue_unc_parsing;
893 printf("mount error: improperly formatted UNC name.");
894 printf(" %s does not begin with \\\\ or //\n",unc_name);
898 continue_unc_parsing:
903 /* allow for either delimiter between host and sharename */
904 if ((share = strpbrk(unc_name, "/\\"))) {
905 *share = 0; /* temporarily terminate the string */
908 host_entry = gethostbyname(unc_name);
910 *(share - 1) = '/'; /* put delimiter back */
912 /* we don't convert the prefixpath delimiters since '\\' is a valid char in posix paths */
913 if ((prefixpath = strpbrk(share, "/\\"))) {
914 *prefixpath = 0; /* permanently terminate the string */
915 if (!strlen(++prefixpath))
916 prefixpath = NULL; /* this needs to be done explicitly */
920 printf("ip address specified explicitly\n");
923 if(host_entry == NULL) {
924 printf("mount error: could not find target server. TCP name %s not found\n", unc_name);
927 /* BB should we pass an alternate version of the share name as Unicode */
928 /* BB what about ipv6? BB */
929 /* BB add retries with alternate servers in list */
931 memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
933 ipaddress_string = inet_ntoa(server_ipaddr);
934 if(ipaddress_string == NULL) {
935 printf("mount error: could not get valid ip address for target server\n");
938 return ipaddress_string;
941 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
942 printf("Mounting the DFS root for a particular server not implemented yet\n");
949 static struct option longopts[] = {
950 { "all", 0, NULL, 'a' },
951 { "help",0, NULL, 'h' },
952 { "move",0, NULL, 'm' },
953 { "bind",0, NULL, 'b' },
954 { "read-only", 0, NULL, 'r' },
955 { "ro", 0, NULL, 'r' },
956 { "verbose", 0, NULL, 'v' },
957 { "version", 0, NULL, 'V' },
958 { "read-write", 0, NULL, 'w' },
959 { "rw", 0, NULL, 'w' },
960 { "options", 1, NULL, 'o' },
961 { "type", 1, NULL, 't' },
962 { "rsize",1, NULL, 'R' },
963 { "wsize",1, NULL, 'W' },
964 { "uid", 1, NULL, '1'},
965 { "gid", 1, NULL, '2'},
966 { "user",1,NULL,'u'},
967 { "username",1,NULL,'u'},
969 { "domain",1,NULL,'d'},
970 { "password",1,NULL,'p'},
971 { "pass",1,NULL,'p'},
972 { "credentials",1,NULL,'c'},
973 { "port",1,NULL,'P'},
974 /* { "uuid",1,NULL,'U'}, */ /* BB unimplemented */
978 /* convert a string to uppercase. return false if the string
979 * wasn't ASCII or was a NULL ptr */
981 uppercase_string(char *string)
987 /* check for unicode */
988 if ((unsigned char) string[0] & 0x80)
990 *string = toupper((unsigned char) *string);
997 int main(int argc, char ** argv)
1000 int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
1001 char * orgoptions = NULL;
1002 char * share_name = NULL;
1003 char * ipaddr = NULL;
1005 char * mountpoint = NULL;
1006 char * options = NULL;
1007 char * resolved_path = NULL;
1018 size_t options_size = 0;
1019 int retry = 0; /* set when we have to retry mount with uppercase */
1020 struct stat statbuf;
1021 struct utsname sysinfo;
1022 struct mntent mountent;
1025 /* setlocale(LC_ALL, "");
1026 bindtextdomain(PACKAGE, LOCALEDIR);
1027 textdomain(PACKAGE); */
1030 thisprogram = argv[0];
1036 if(thisprogram == NULL)
1037 thisprogram = "mount.cifs";
1040 /* BB add workstation name and domain and pass down */
1042 /* #ifdef _GNU_SOURCE
1043 printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
1047 share_name = strndup(argv[1], MAX_UNC_LEN);
1048 if (share_name == NULL) {
1049 fprintf(stderr, "%s: %s", argv[0], strerror(ENOMEM));
1052 mountpoint = argv[2];
1058 /* add sharename in opts string as unc= parm */
1060 while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
1061 longopts, NULL)) != -1) {
1063 /* No code to do the following options yet */
1065 list_with_volumelabel = 1;
1068 volumelabel = optarg;
1075 case 'h': /* help */
1076 mount_cifs_usage ();
1086 "option 'b' (MS_BIND) not supported\n");
1094 "option 'm' (MS_MOVE) not supported\n");
1098 orgoptions = strdup(optarg);
1100 case 'r': /* mount readonly */
1110 printf ("mount.cifs version: %s.%s%s\n",
1111 MOUNT_CIFS_VERSION_MAJOR,
1112 MOUNT_CIFS_VERSION_MINOR,
1113 MOUNT_CIFS_VENDOR_SUFFIX);
1116 flags &= ~MS_RDONLY;
1119 rsize = atoi(optarg) ;
1122 wsize = atoi(optarg);
1125 if (isdigit(*optarg)) {
1128 uid = strtoul(optarg, &ep, 10);
1130 printf("bad uid value \"%s\"\n", optarg);
1136 if (!(pw = getpwnam(optarg))) {
1137 printf("bad user name \"%s\"\n", optarg);
1145 if (isdigit(*optarg)) {
1148 gid = strtoul(optarg, &ep, 10);
1150 printf("bad gid value \"%s\"\n", optarg);
1156 if (!(gr = getgrnam(optarg))) {
1157 printf("bad user name \"%s\"\n", optarg);
1169 domain_name = optarg; /* BB fix this - currently ignored */
1173 if(mountpassword == NULL)
1174 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
1177 strlcpy(mountpassword,optarg,MOUNT_PASSWD_SIZE+1);
1181 get_password_from_file(0 /* stdin */,NULL);
1186 printf("unknown mount option %c\n",c);
1192 if((argc < 3) || (dev_name == NULL) || (mountpoint == NULL)) {
1197 if (getenv("PASSWD")) {
1198 if(mountpassword == NULL)
1199 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
1201 strlcpy(mountpassword,getenv("PASSWD"),MOUNT_PASSWD_SIZE+1);
1204 } else if (getenv("PASSWD_FD")) {
1205 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
1206 } else if (getenv("PASSWD_FILE")) {
1207 get_password_from_file(0, getenv("PASSWD_FILE"));
1210 if (orgoptions && parse_options(&orgoptions, &flags)) {
1214 ipaddr = parse_server(&share_name);
1215 if((ipaddr == NULL) && (got_ip == 0)) {
1216 printf("No ip address specified and hostname not found\n");
1221 /* BB save off path and pop after mount returns? */
1222 resolved_path = (char *)malloc(PATH_MAX+1);
1224 /* Note that if we can not canonicalize the name, we get
1225 another chance to see if it is valid when we chdir to it */
1226 if (realpath(mountpoint, resolved_path)) {
1227 mountpoint = resolved_path;
1230 if(chdir(mountpoint)) {
1231 printf("mount error: can not change directory into mount target %s\n",mountpoint);
1236 if(stat (".", &statbuf)) {
1237 printf("mount error: mount point %s does not exist\n",mountpoint);
1242 if (S_ISDIR(statbuf.st_mode) == 0) {
1243 printf("mount error: mount point %s is not a directory\n",mountpoint);
1248 if((getuid() != 0) && (geteuid() == 0)) {
1249 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
1250 #ifndef CIFS_ALLOW_USR_SUID
1251 /* Do not allow user mounts to control suid flag
1252 for mount unless explicitly built that way */
1253 flags |= MS_NOSUID | MS_NODEV;
1256 printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n");
1262 user_name = getusername();
1266 if(got_password == 0) {
1267 char *tmp_pass = getpass("Password: "); /* BB obsolete sys call but
1268 no good replacement yet. */
1269 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
1270 if (!tmp_pass || !mountpassword) {
1271 printf("Password not entered, exiting\n");
1274 strlcpy(mountpassword, tmp_pass, MOUNT_PASSWD_SIZE+1);
1277 /* FIXME launch daemon (handles dfs name resolution and credential change)
1278 remember to clear parms and overwrite password field before launching */
1281 optlen = strlen(orgoptions);
1286 optlen += strlen(share_name) + 4;
1288 printf("No server share name specified\n");
1289 printf("\nMounting the DFS root for server not implemented yet\n");
1293 optlen += strlen(user_name) + 6;
1295 optlen += strlen(ipaddr) + 4;
1297 optlen += strlen(mountpassword) + 6;
1299 options_size = optlen + 10 + DOMAIN_SIZE;
1300 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 */);
1302 if(options == NULL) {
1303 printf("Could not allocate memory for mount options\n");
1308 strlcpy(options,"unc=",options_size);
1309 strlcat(options,share_name,options_size);
1310 /* scan backwards and reverse direction of slash */
1311 temp = strrchr(options, '/');
1312 if(temp > options + 6)
1315 strlcat(options,",ip=",options_size);
1316 strlcat(options,ipaddr,options_size);
1320 /* check for syntax like user=domain\user */
1322 domain_name = check_for_domain(&user_name);
1323 strlcat(options,",user=",options_size);
1324 strlcat(options,user_name,options_size);
1328 /* extra length accounted for in option string above */
1329 strlcat(options,",domain=",options_size);
1330 strlcat(options,domain_name,options_size);
1334 /* Commas have to be doubled, or else they will
1335 look like the parameter separator */
1336 /* if(sep is not set)*/
1338 check_for_comma(&mountpassword);
1339 strlcat(options,",pass=",options_size);
1340 strlcat(options,mountpassword,options_size);
1343 strlcat(options,",ver=",options_size);
1344 strlcat(options,MOUNT_CIFS_VERSION_MAJOR,options_size);
1347 strlcat(options,",",options_size);
1348 strlcat(options,orgoptions,options_size);
1351 strlcat(options,",prefixpath=",options_size);
1352 strlcat(options,prefixpath,options_size); /* no need to cat the / */
1355 printf("\nmount.cifs kernel mount options %s \n",options);
1357 /* convert all '\\' to '/' in share portion so that /proc/mounts looks pretty */
1358 replace_char(dev_name, '\\', '/', strlen(share_name));
1360 if(mount(dev_name, mountpoint, "cifs", flags, options)) {
1361 /* remember to kill daemon on error */
1364 printf("mount failed but no error number set\n");
1367 printf("mount error: cifs filesystem not supported by the system\n");
1372 if (uppercase_string(dev_name) &&
1373 uppercase_string(share_name) &&
1374 uppercase_string(prefixpath)) {
1375 printf("retrying with upper case share name\n");
1380 printf("mount error %d = %s\n",errno,strerror(errno));
1382 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
1386 pmntfile = setmntent(MOUNTED, "a+");
1388 mountent.mnt_fsname = dev_name;
1389 mountent.mnt_dir = mountpoint;
1390 mountent.mnt_type = CONST_DISCARD(char *,"cifs");
1391 mountent.mnt_opts = (char *)malloc(220);
1392 if(mountent.mnt_opts) {
1393 char * mount_user = getusername();
1394 memset(mountent.mnt_opts,0,200);
1395 if(flags & MS_RDONLY)
1396 strlcat(mountent.mnt_opts,"ro",220);
1398 strlcat(mountent.mnt_opts,"rw",220);
1399 if(flags & MS_MANDLOCK)
1400 strlcat(mountent.mnt_opts,",mand",220);
1401 if(flags & MS_NOEXEC)
1402 strlcat(mountent.mnt_opts,",noexec",220);
1403 if(flags & MS_NOSUID)
1404 strlcat(mountent.mnt_opts,",nosuid",220);
1405 if(flags & MS_NODEV)
1406 strlcat(mountent.mnt_opts,",nodev",220);
1407 if(flags & MS_SYNCHRONOUS)
1408 strlcat(mountent.mnt_opts,",synch",220);
1411 strlcat(mountent.mnt_opts,",user=",220);
1412 strlcat(mountent.mnt_opts,mount_user,220);
1414 /* free(mount_user); do not free static mem */
1417 mountent.mnt_freq = 0;
1418 mountent.mnt_passno = 0;
1419 rc = addmntent(pmntfile,&mountent);
1420 endmntent(pmntfile);
1421 SAFE_FREE(mountent.mnt_opts);
1423 printf("could not update mount table\n");
1429 int len = strlen(mountpassword);
1430 memset(mountpassword,0,len);
1431 SAFE_FREE(mountpassword);
1435 SAFE_FREE(orgoptions);
1436 SAFE_FREE(resolved_path);
1437 SAFE_FREE(share_name);