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 */
60 #include "include/config.h"
71 #define MAX_UNC_LEN 1024
73 #define CONST_DISCARD(type, ptr) ((type) ((void *) (ptr)))
76 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
79 #define MOUNT_PASSWD_SIZE 64
80 #define DOMAIN_SIZE 64
82 /* exit status - bits below are ORed */
83 #define EX_USAGE 1 /* incorrect invocation or permission */
84 #define EX_SYSERR 2 /* out of memory, cannot fork, ... */
85 #define EX_SOFTWARE 4 /* internal mount bug or wrong version */
86 #define EX_USER 8 /* user interrupt */
87 #define EX_FILEIO 16 /* problems writing, locking, ... mtab/fstab */
88 #define EX_FAIL 32 /* mount failure */
89 #define EX_SOMEOK 64 /* some mount succeeded */
91 const char *thisprogram;
93 static int got_password = 0;
94 static int got_user = 0;
95 static int got_domain = 0;
96 static int got_ip = 0;
97 static int got_unc = 0;
98 static int got_uid = 0;
99 static int got_gid = 0;
100 static char * user_name = NULL;
101 static char * mountpassword = NULL;
102 char * domain_name = NULL;
103 char * prefixpath = NULL;
105 /* glibc doesn't have strlcpy, strlcat. Ensure we do. JRA. We
106 * don't link to libreplace so need them here. */
108 /* like strncpy but does not 0 fill the buffer and always null
109 * terminates. bufsize is the size of the destination buffer */
112 static size_t strlcpy(char *d, const char *s, size_t bufsize)
114 size_t len = strlen(s);
116 if (bufsize <= 0) return 0;
117 if (len >= bufsize) len = bufsize-1;
124 /* like strncat but does not 0 fill the buffer and always null
125 * terminates. bufsize is the length of the buffer, which should
126 * be one more than the maximum resulting string length */
129 static size_t strlcat(char *d, const char *s, size_t bufsize)
131 size_t len1 = strlen(d);
132 size_t len2 = strlen(s);
133 size_t ret = len1 + len2;
135 if (len1+len2 >= bufsize) {
136 if (bufsize < (len1+1)) {
139 len2 = bufsize - (len1+1);
142 memcpy(d+len1, s, len2);
152 open nofollow - avoid symlink exposure?
153 get owner of dir see if matches self or if root
154 call system(umount argv) etc.
158 static char * check_for_domain(char **);
161 static void mount_cifs_usage(void)
163 printf("\nUsage: %s <remotetarget> <dir> -o <options>\n", thisprogram);
164 printf("\nMount the remote target, specified as a UNC name,");
165 printf(" to a local directory.\n\nOptions:\n");
166 printf("\tuser=<arg>\n\tpass=<arg>\n\tdom=<arg>\n");
167 printf("\nLess commonly used options:");
168 printf("\n\tcredentials=<filename>,guest,perm,noperm,setuids,nosetuids,rw,ro,");
169 printf("\n\tsep=<char>,iocharset=<codepage>,suid,nosuid,exec,noexec,serverino,");
170 printf("\n\tmapchars,nomapchars,nolock,servernetbiosname=<SRV_RFC1001NAME>");
171 printf("\n\tdirectio,nounix,cifsacl,sec=<authentication mechanism>,sign");
172 printf("\n\nOptions not needed for servers supporting CIFS Unix extensions");
173 printf("\n\t(e.g. unneeded for mounts to most Samba versions):");
174 printf("\n\tuid=<uid>,gid=<gid>,dir_mode=<mode>,file_mode=<mode>,sfu");
175 printf("\n\nRarely used options:");
176 printf("\n\tport=<tcpport>,rsize=<size>,wsize=<size>,unc=<unc_name>,ip=<ip_address>,");
177 printf("\n\tdev,nodev,nouser_xattr,netbiosname=<OUR_RFC1001NAME>,hard,soft,intr,");
178 printf("\n\tnointr,ignorecase,noposixpaths,noacl,prefixpath=<path>,nobrl");
179 printf("\n\tin6_addr");
180 printf("\n\nOptions are described in more detail in the manual page");
181 printf("\n\tman 8 mount.cifs\n");
182 printf("\nTo display the version number of the mount helper:");
183 printf("\n\t%s -V\n",thisprogram);
185 SAFE_FREE(mountpassword);
189 /* caller frees username if necessary */
190 static char * getusername(void) {
191 char *username = NULL;
192 struct passwd *password = getpwuid(getuid());
195 username = password->pw_name;
200 static char * parse_cifs_url(char * unc_name)
202 printf("\nMounting cifs URL not implemented yet. Attempt to mount %s\n",unc_name);
206 static int open_cred_file(char * file_name)
212 fs = fopen(file_name,"r");
215 line_buf = (char *)malloc(4096);
216 if(line_buf == NULL) {
221 while(fgets(line_buf,4096,fs)) {
222 /* parse line from credential file */
224 /* eat leading white space */
225 for(i=0;i<4086;i++) {
226 if((line_buf[i] != ' ') && (line_buf[i] != '\t'))
228 /* if whitespace - skip past it */
230 if (strncasecmp("username",line_buf+i,8) == 0) {
231 temp_val = strchr(line_buf + i,'=');
233 /* go past equals sign */
235 for(length = 0;length<4087;length++) {
236 if ((temp_val[length] == '\n')
237 || (temp_val[length] == '\0')) {
238 temp_val[length] = '\0';
243 printf("mount.cifs failed due to malformed username in credentials file");
244 memset(line_buf,0,4096);
248 user_name = (char *)calloc(1 + length,1);
249 /* BB adding free of user_name string before exit,
250 not really necessary but would be cleaner */
251 strlcpy(user_name,temp_val, length+1);
254 } else if (strncasecmp("password",line_buf+i,8) == 0) {
255 temp_val = strchr(line_buf+i,'=');
257 /* go past equals sign */
259 for(length = 0;length<MOUNT_PASSWD_SIZE+1;length++) {
260 if ((temp_val[length] == '\n')
261 || (temp_val[length] == '\0')) {
262 temp_val[length] = '\0';
266 if(length > MOUNT_PASSWD_SIZE) {
267 printf("mount.cifs failed: password in credentials file too long\n");
268 memset(line_buf,0, 4096);
271 if(mountpassword == NULL) {
272 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
274 memset(mountpassword,0,MOUNT_PASSWD_SIZE);
276 strlcpy(mountpassword,temp_val,MOUNT_PASSWD_SIZE+1);
281 } else if (strncasecmp("domain",line_buf+i,6) == 0) {
282 temp_val = strchr(line_buf+i,'=');
284 /* go past equals sign */
287 printf("\nDomain %s\n",temp_val);
288 for(length = 0;length<DOMAIN_SIZE+1;length++) {
289 if ((temp_val[length] == '\n')
290 || (temp_val[length] == '\0')) {
291 temp_val[length] = '\0';
295 if(length > DOMAIN_SIZE) {
296 printf("mount.cifs failed: domain in credentials file too long\n");
299 if(domain_name == NULL) {
300 domain_name = (char *)calloc(DOMAIN_SIZE+1,1);
302 memset(domain_name,0,DOMAIN_SIZE);
304 strlcpy(domain_name,temp_val,DOMAIN_SIZE+1);
317 static int get_password_from_file(int file_descript, char * filename)
323 if(mountpassword == NULL)
324 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
326 memset(mountpassword, 0, MOUNT_PASSWD_SIZE);
328 if (mountpassword == NULL) {
329 printf("malloc failed\n");
333 if(filename != NULL) {
334 file_descript = open(filename, O_RDONLY);
335 if(file_descript < 0) {
336 printf("mount.cifs failed. %s attempting to open password file %s\n",
337 strerror(errno),filename);
341 /* else file already open and fd provided */
343 for(i=0;i<MOUNT_PASSWD_SIZE;i++) {
344 rc = read(file_descript,&c,1);
346 printf("mount.cifs failed. Error %s reading password file\n",strerror(errno));
348 close(file_descript);
351 if(mountpassword[0] == 0) {
353 printf("\nWarning: null password used since cifs password file empty");
356 } else /* read valid character */ {
357 if((c == 0) || (c == '\n')) {
358 mountpassword[i] = '\0';
361 mountpassword[i] = c;
364 if((i == MOUNT_PASSWD_SIZE) && (verboseflag)) {
365 printf("\nWarning: password longer than %d characters specified in cifs password file",
369 if(filename != NULL) {
370 close(file_descript);
376 static int parse_options(char ** optionsp, int * filesys_flags)
379 char * percent_char = NULL;
381 char * next_keyword = NULL;
389 if (!optionsp || !*optionsp)
394 printf("parsing options: %s\n", data);
396 /* BB fixme check for separator override BB */
400 snprintf(user,sizeof(user),"%u",getuid());
402 snprintf(group,sizeof(group),"%u",getgid());
405 /* while ((data = strsep(&options, ",")) != NULL) { */
406 while(data != NULL) {
407 /* check if ends with trailing comma */
411 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
412 /* data = next keyword */
413 /* value = next value ie stuff after equal sign */
415 next_keyword = strchr(data,','); /* BB handle sep= */
417 /* temporarily null terminate end of keyword=value pair */
421 /* temporarily null terminate keyword to make keyword and value distinct */
422 if ((value = strchr(data, '=')) != NULL) {
427 if (strncmp(data, "users",5) == 0) {
428 if(!value || !*value) {
431 } else if (strncmp(data, "user_xattr",10) == 0) {
432 /* do nothing - need to skip so not parsed as user name */
433 } else if (strncmp(data, "user", 4) == 0) {
435 if (!value || !*value) {
436 if(data[4] == '\0') {
438 printf("\nskipping empty user mount parameter\n");
439 /* remove the parm since it would otherwise be confusing
440 to the kernel code which would think it was a real username */
443 printf("username specified with no parameter\n");
445 return 1; /* needs_arg; */
448 if (strnlen(value, 260) < 260) {
450 percent_char = strchr(value,'%');
453 if(mountpassword == NULL)
454 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
457 printf("\nmount.cifs warning - password specified twice\n");
460 strlcpy(mountpassword, percent_char,MOUNT_PASSWD_SIZE+1);
461 /* remove password from username */
462 while(*percent_char != 0) {
468 /* this is only case in which the user
469 name buf is not malloc - so we have to
470 check for domain name embedded within
471 the user name here since the later
472 call to check_for_domain will not be
474 domain_name = check_for_domain(&value);
476 printf("username too long\n");
481 } else if (strncmp(data, "pass", 4) == 0) {
482 if (!value || !*value) {
484 printf("\npassword specified twice, ignoring second\n");
487 } else if (strnlen(value, 17) < 17) {
489 printf("\nmount.cifs warning - password specified twice\n");
492 printf("password too long\n");
496 } else if (strncmp(data, "sec", 3) == 0) {
498 if (!strncmp(value, "none", 4) ||
499 !strncmp(value, "krb5", 4))
502 } else if (strncmp(data, "ip", 2) == 0) {
503 if (!value || !*value) {
504 printf("target ip address argument missing");
505 } else if (strnlen(value, 35) < 35) {
507 printf("ip address %s override specified\n",value);
510 printf("ip address too long\n");
514 } else if ((strncmp(data, "unc", 3) == 0)
515 || (strncmp(data, "target", 6) == 0)
516 || (strncmp(data, "path", 4) == 0)) {
517 if (!value || !*value) {
518 printf("invalid path to network resource\n");
520 return 1; /* needs_arg; */
521 } else if(strnlen(value,5) < 5) {
522 printf("UNC name too short");
525 if (strnlen(value, 300) < 300) {
527 if (strncmp(value, "//", 2) == 0) {
529 printf("unc name specified twice, ignoring second\n");
532 } else if (strncmp(value, "\\\\", 2) != 0) {
533 printf("UNC Path does not begin with // or \\\\ \n");
538 printf("unc name specified twice, ignoring second\n");
543 printf("CIFS: UNC name too long\n");
547 } else if ((strncmp(data, "dom" /* domain */, 3) == 0)
548 || (strncmp(data, "workg", 5) == 0)) {
549 /* note this allows for synonyms of "domain"
550 such as "DOM" and "dom" and "workgroup"
551 and "WORKGRP" etc. */
552 if (!value || !*value) {
553 printf("CIFS: invalid domain name\n");
555 return 1; /* needs_arg; */
557 if (strnlen(value, DOMAIN_SIZE+1) < DOMAIN_SIZE+1) {
560 printf("domain name too long\n");
564 } else if (strncmp(data, "cred", 4) == 0) {
565 if (value && *value) {
566 rc = open_cred_file(value);
568 printf("error %d (%s) opening credential file %s\n",
569 rc, strerror(rc), value);
574 printf("invalid credential file name specified\n");
578 } else if (strncmp(data, "uid", 3) == 0) {
579 if (value && *value) {
581 if (!isdigit(*value)) {
584 if (!(pw = getpwnam(value))) {
585 printf("bad user name \"%s\"\n", value);
588 snprintf(user, sizeof(user), "%u", pw->pw_uid);
590 strlcpy(user,value,sizeof(user));
594 } else if (strncmp(data, "gid", 3) == 0) {
595 if (value && *value) {
597 if (!isdigit(*value)) {
600 if (!(gr = getgrnam(value))) {
601 printf("bad group name \"%s\"\n", value);
604 snprintf(group, sizeof(group), "%u", gr->gr_gid);
606 strlcpy(group,value,sizeof(group));
610 /* fmask and dmask synonyms for people used to smbfs syntax */
611 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
612 if (!value || !*value) {
613 printf ("Option '%s' requires a numerical argument\n", data);
618 if (value[0] != '0') {
619 printf ("WARNING: '%s' not expressed in octal.\n", data);
622 if (strcmp (data, "fmask") == 0) {
623 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
624 data = "file_mode"; /* BB fix this */
626 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
627 if (!value || !*value) {
628 printf ("Option '%s' requires a numerical argument\n", data);
633 if (value[0] != '0') {
634 printf ("WARNING: '%s' not expressed in octal.\n", data);
637 if (strcmp (data, "dmask") == 0) {
638 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
641 /* the following eight mount options should be
642 stripped out from what is passed into the kernel
643 since these eight options are best passed as the
644 mount flags rather than redundantly to the kernel
645 and could generate spurious warnings depending on the
646 level of the corresponding cifs vfs kernel code */
647 } else if (strncmp(data, "nosuid", 6) == 0) {
648 *filesys_flags |= MS_NOSUID;
649 } else if (strncmp(data, "suid", 4) == 0) {
650 *filesys_flags &= ~MS_NOSUID;
651 } else if (strncmp(data, "nodev", 5) == 0) {
652 *filesys_flags |= MS_NODEV;
653 } else if ((strncmp(data, "nobrl", 5) == 0) ||
654 (strncmp(data, "nolock", 6) == 0)) {
655 *filesys_flags &= ~MS_MANDLOCK;
656 } else if (strncmp(data, "dev", 3) == 0) {
657 *filesys_flags &= ~MS_NODEV;
658 } else if (strncmp(data, "noexec", 6) == 0) {
659 *filesys_flags |= MS_NOEXEC;
660 } else if (strncmp(data, "exec", 4) == 0) {
661 *filesys_flags &= ~MS_NOEXEC;
662 } else if (strncmp(data, "guest", 5) == 0) {
664 } else if (strncmp(data, "ro", 2) == 0) {
665 *filesys_flags |= MS_RDONLY;
666 } else if (strncmp(data, "rw", 2) == 0) {
667 *filesys_flags &= ~MS_RDONLY;
668 } else if (strncmp(data, "remount", 7) == 0) {
669 *filesys_flags |= MS_REMOUNT;
670 } /* else if (strnicmp(data, "port", 4) == 0) {
671 if (value && *value) {
673 simple_strtoul(value, &value, 0);
675 } else if (strnicmp(data, "rsize", 5) == 0) {
676 if (value && *value) {
678 simple_strtoul(value, &value, 0);
680 } else if (strnicmp(data, "wsize", 5) == 0) {
681 if (value && *value) {
683 simple_strtoul(value, &value, 0);
685 } else if (strnicmp(data, "version", 3) == 0) {
687 printf("CIFS: Unknown mount option %s\n",data);
688 } */ /* nothing to do on those four mount options above.
689 Just pass to kernel and ignore them here */
691 /* Copy (possibly modified) option to out */
692 word_len = strlen(data);
694 word_len += 1 + strlen(value);
696 out = (char *)realloc(out, out_len + word_len + 2);
703 strlcat(out, ",", out_len + word_len + 2);
708 snprintf(out + out_len, word_len + 1, "%s=%s", data, value);
710 snprintf(out + out_len, word_len + 1, "%s", data);
711 out_len = strlen(out);
717 /* special-case the uid and gid */
719 word_len = strlen(user);
721 out = (char *)realloc(out, out_len + word_len + 6);
728 strlcat(out, ",", out_len + word_len + 6);
731 snprintf(out + out_len, word_len + 5, "uid=%s", user);
732 out_len = strlen(out);
735 word_len = strlen(group);
737 out = (char *)realloc(out, out_len + 1 + word_len + 6);
744 strlcat(out, ",", out_len + word_len + 6);
747 snprintf(out + out_len, word_len + 5, "gid=%s", group);
748 out_len = strlen(out);
751 SAFE_FREE(*optionsp);
756 /* replace all (one or more) commas with double commas */
757 static void check_for_comma(char ** ppasswrd)
762 int number_of_commas = 0;
777 if(number_of_commas == 0)
779 if(number_of_commas > MOUNT_PASSWD_SIZE) {
780 /* would otherwise overflow the mount options buffer */
781 printf("\nInvalid password. Password contains too many commas.\n");
785 new_pass_buf = (char *)malloc(len+number_of_commas+1);
786 if(new_pass_buf == NULL)
789 for(i=0,j=0;i<len;i++,j++) {
790 new_pass_buf[j] = pass[i];
793 new_pass_buf[j] = pass[i];
796 new_pass_buf[len+number_of_commas] = 0;
798 SAFE_FREE(*ppasswrd);
799 *ppasswrd = new_pass_buf;
804 /* Usernames can not have backslash in them and we use
805 [BB check if usernames can have forward slash in them BB]
806 backslash as domain\user separator character
808 static char * check_for_domain(char **ppuser)
810 char * original_string;
820 original_string = *ppuser;
822 if (original_string == NULL)
825 original_len = strlen(original_string);
827 usernm = strchr(*ppuser,'/');
828 if (usernm == NULL) {
829 usernm = strchr(*ppuser,'\\');
835 printf("Domain name specified twice. Username probably malformed\n");
841 if (domainnm[0] != 0) {
844 printf("null domain\n");
846 len = strlen(domainnm);
847 /* reset domainm to new buffer, and copy
848 domain name into it */
849 domainnm = (char *)malloc(len+1);
853 strlcpy(domainnm,*ppuser,len+1);
855 /* move_string(*ppuser, usernm+1) */
856 len = strlen(usernm+1);
858 if(len >= original_len) {
859 /* should not happen */
863 for(i=0;i<original_len;i++) {
865 original_string[i] = usernm[i+1];
866 else /* stuff with commas to remove last parm */
867 original_string[i] = ',';
870 /* BB add check for more than one slash?
878 /* replace all occurances of "from" in a string with "to" */
879 static void replace_char(char *string, char from, char to, int maxlen)
881 char *lastchar = string + maxlen;
883 string = strchr(string, from);
886 if (string >= lastchar)
892 /* Note that caller frees the returned buffer if necessary */
893 static char * parse_server(char ** punc_name)
895 char * unc_name = *punc_name;
896 int length = strnlen(unc_name, MAX_UNC_LEN);
898 char * ipaddress_string = NULL;
899 struct hostent * host_entry = NULL;
900 struct in_addr server_ipaddr;
902 if(length > (MAX_UNC_LEN - 1)) {
903 printf("mount error: UNC name too long");
906 if (strncasecmp("cifs://",unc_name,7) == 0)
907 return parse_cifs_url(unc_name+7);
908 if (strncasecmp("smb://",unc_name,6) == 0) {
909 return parse_cifs_url(unc_name+6);
913 /* BB add code to find DFS root here */
914 printf("\nMounting the DFS root for domain not implemented yet\n");
917 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
918 /* check for nfs syntax ie server:share */
919 share = strchr(unc_name,':');
921 *punc_name = (char *)malloc(length+3);
922 if(*punc_name == NULL) {
923 /* put the original string back if
925 *punc_name = unc_name;
929 strlcpy((*punc_name)+2,unc_name,length+1);
931 unc_name = *punc_name;
932 unc_name[length+2] = 0;
933 goto continue_unc_parsing;
935 printf("mount error: improperly formatted UNC name.");
936 printf(" %s does not begin with \\\\ or //\n",unc_name);
940 continue_unc_parsing:
945 /* allow for either delimiter between host and sharename */
946 if ((share = strpbrk(unc_name, "/\\"))) {
947 *share = 0; /* temporarily terminate the string */
950 host_entry = gethostbyname(unc_name);
952 *(share - 1) = '/'; /* put delimiter back */
954 /* we don't convert the prefixpath delimiters since '\\' is a valid char in posix paths */
955 if ((prefixpath = strpbrk(share, "/\\"))) {
956 *prefixpath = 0; /* permanently terminate the string */
957 if (!strlen(++prefixpath))
958 prefixpath = NULL; /* this needs to be done explicitly */
962 printf("ip address specified explicitly\n");
965 if(host_entry == NULL) {
966 printf("mount error: could not find target server. TCP name %s not found\n", unc_name);
969 /* BB should we pass an alternate version of the share name as Unicode */
970 /* BB what about ipv6? BB */
971 /* BB add retries with alternate servers in list */
973 memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
975 ipaddress_string = inet_ntoa(server_ipaddr);
976 if(ipaddress_string == NULL) {
977 printf("mount error: could not get valid ip address for target server\n");
980 return ipaddress_string;
983 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
984 printf("Mounting the DFS root for a particular server not implemented yet\n");
991 static struct option longopts[] = {
992 { "all", 0, NULL, 'a' },
993 { "help",0, NULL, 'h' },
994 { "move",0, NULL, 'm' },
995 { "bind",0, NULL, 'b' },
996 { "read-only", 0, NULL, 'r' },
997 { "ro", 0, NULL, 'r' },
998 { "verbose", 0, NULL, 'v' },
999 { "version", 0, NULL, 'V' },
1000 { "read-write", 0, NULL, 'w' },
1001 { "rw", 0, NULL, 'w' },
1002 { "options", 1, NULL, 'o' },
1003 { "type", 1, NULL, 't' },
1004 { "rsize",1, NULL, 'R' },
1005 { "wsize",1, NULL, 'W' },
1006 { "uid", 1, NULL, '1'},
1007 { "gid", 1, NULL, '2'},
1008 { "user",1,NULL,'u'},
1009 { "username",1,NULL,'u'},
1010 { "dom",1,NULL,'d'},
1011 { "domain",1,NULL,'d'},
1012 { "password",1,NULL,'p'},
1013 { "pass",1,NULL,'p'},
1014 { "credentials",1,NULL,'c'},
1015 { "port",1,NULL,'P'},
1016 /* { "uuid",1,NULL,'U'}, */ /* BB unimplemented */
1017 { NULL, 0, NULL, 0 }
1020 /* convert a string to uppercase. return false if the string
1021 * wasn't ASCII. Return success on a NULL ptr */
1023 uppercase_string(char *string)
1029 /* check for unicode */
1030 if ((unsigned char) string[0] & 0x80)
1032 *string = toupper((unsigned char) *string);
1039 int main(int argc, char ** argv)
1042 int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
1043 char * orgoptions = NULL;
1044 char * share_name = NULL;
1045 char * ipaddr = NULL;
1047 char * mountpoint = NULL;
1048 char * options = NULL;
1049 char * resolved_path = NULL;
1060 size_t options_size = 0;
1061 int retry = 0; /* set when we have to retry mount with uppercase */
1062 struct stat statbuf;
1063 struct utsname sysinfo;
1064 struct mntent mountent;
1067 /* setlocale(LC_ALL, "");
1068 bindtextdomain(PACKAGE, LOCALEDIR);
1069 textdomain(PACKAGE); */
1072 thisprogram = argv[0];
1078 if(thisprogram == NULL)
1079 thisprogram = "mount.cifs";
1082 /* BB add workstation name and domain and pass down */
1084 /* #ifdef _GNU_SOURCE
1085 printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
1089 share_name = strndup(argv[1], MAX_UNC_LEN);
1090 if (share_name == NULL) {
1091 fprintf(stderr, "%s: %s", argv[0], strerror(ENOMEM));
1094 mountpoint = argv[2];
1100 /* add sharename in opts string as unc= parm */
1102 while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
1103 longopts, NULL)) != -1) {
1105 /* No code to do the following options yet */
1107 list_with_volumelabel = 1;
1110 volumelabel = optarg;
1117 case 'h': /* help */
1118 mount_cifs_usage ();
1128 "option 'b' (MS_BIND) not supported\n");
1136 "option 'm' (MS_MOVE) not supported\n");
1140 orgoptions = strdup(optarg);
1142 case 'r': /* mount readonly */
1152 printf ("mount.cifs version: %s.%s%s\n",
1153 MOUNT_CIFS_VERSION_MAJOR,
1154 MOUNT_CIFS_VERSION_MINOR,
1155 MOUNT_CIFS_VENDOR_SUFFIX);
1158 flags &= ~MS_RDONLY;
1161 rsize = atoi(optarg) ;
1164 wsize = atoi(optarg);
1167 if (isdigit(*optarg)) {
1170 uid = strtoul(optarg, &ep, 10);
1172 printf("bad uid value \"%s\"\n", optarg);
1178 if (!(pw = getpwnam(optarg))) {
1179 printf("bad user name \"%s\"\n", optarg);
1187 if (isdigit(*optarg)) {
1190 gid = strtoul(optarg, &ep, 10);
1192 printf("bad gid value \"%s\"\n", optarg);
1198 if (!(gr = getgrnam(optarg))) {
1199 printf("bad user name \"%s\"\n", optarg);
1211 domain_name = optarg; /* BB fix this - currently ignored */
1215 if(mountpassword == NULL)
1216 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
1219 strlcpy(mountpassword,optarg,MOUNT_PASSWD_SIZE+1);
1223 get_password_from_file(0 /* stdin */,NULL);
1228 printf("unknown mount option %c\n",c);
1234 if((argc < 3) || (dev_name == NULL) || (mountpoint == NULL)) {
1239 if (getenv("PASSWD")) {
1240 if(mountpassword == NULL)
1241 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
1243 strlcpy(mountpassword,getenv("PASSWD"),MOUNT_PASSWD_SIZE+1);
1246 } else if (getenv("PASSWD_FD")) {
1247 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
1248 } else if (getenv("PASSWD_FILE")) {
1249 get_password_from_file(0, getenv("PASSWD_FILE"));
1252 if (orgoptions && parse_options(&orgoptions, &flags)) {
1256 ipaddr = parse_server(&share_name);
1257 if((ipaddr == NULL) && (got_ip == 0)) {
1258 printf("No ip address specified and hostname not found\n");
1263 /* BB save off path and pop after mount returns? */
1264 resolved_path = (char *)malloc(PATH_MAX+1);
1266 /* Note that if we can not canonicalize the name, we get
1267 another chance to see if it is valid when we chdir to it */
1268 if (realpath(mountpoint, resolved_path)) {
1269 mountpoint = resolved_path;
1272 if(chdir(mountpoint)) {
1273 printf("mount error: can not change directory into mount target %s\n",mountpoint);
1278 if(stat (".", &statbuf)) {
1279 printf("mount error: mount point %s does not exist\n",mountpoint);
1284 if (S_ISDIR(statbuf.st_mode) == 0) {
1285 printf("mount error: mount point %s is not a directory\n",mountpoint);
1290 if((getuid() != 0) && (geteuid() == 0)) {
1291 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
1292 #ifndef CIFS_ALLOW_USR_SUID
1293 /* Do not allow user mounts to control suid flag
1294 for mount unless explicitly built that way */
1295 flags |= MS_NOSUID | MS_NODEV;
1298 printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n");
1304 user_name = getusername();
1308 if(got_password == 0) {
1309 char *tmp_pass = getpass("Password: "); /* BB obsolete sys call but
1310 no good replacement yet. */
1311 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
1312 if (!tmp_pass || !mountpassword) {
1313 printf("Password not entered, exiting\n");
1316 strlcpy(mountpassword, tmp_pass, MOUNT_PASSWD_SIZE+1);
1319 /* FIXME launch daemon (handles dfs name resolution and credential change)
1320 remember to clear parms and overwrite password field before launching */
1323 optlen = strlen(orgoptions);
1328 optlen += strlen(share_name) + 4;
1330 printf("No server share name specified\n");
1331 printf("\nMounting the DFS root for server not implemented yet\n");
1335 optlen += strlen(user_name) + 6;
1337 optlen += strlen(ipaddr) + 4;
1339 optlen += strlen(mountpassword) + 6;
1341 options_size = optlen + 10 + DOMAIN_SIZE;
1342 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 */);
1344 if(options == NULL) {
1345 printf("Could not allocate memory for mount options\n");
1350 strlcpy(options,"unc=",options_size);
1351 strlcat(options,share_name,options_size);
1352 /* scan backwards and reverse direction of slash */
1353 temp = strrchr(options, '/');
1354 if(temp > options + 6)
1357 strlcat(options,",ip=",options_size);
1358 strlcat(options,ipaddr,options_size);
1362 /* check for syntax like user=domain\user */
1364 domain_name = check_for_domain(&user_name);
1365 strlcat(options,",user=",options_size);
1366 strlcat(options,user_name,options_size);
1370 /* extra length accounted for in option string above */
1371 strlcat(options,",domain=",options_size);
1372 strlcat(options,domain_name,options_size);
1376 /* Commas have to be doubled, or else they will
1377 look like the parameter separator */
1378 /* if(sep is not set)*/
1380 check_for_comma(&mountpassword);
1381 strlcat(options,",pass=",options_size);
1382 strlcat(options,mountpassword,options_size);
1385 strlcat(options,",ver=",options_size);
1386 strlcat(options,MOUNT_CIFS_VERSION_MAJOR,options_size);
1389 strlcat(options,",",options_size);
1390 strlcat(options,orgoptions,options_size);
1393 strlcat(options,",prefixpath=",options_size);
1394 strlcat(options,prefixpath,options_size); /* no need to cat the / */
1397 printf("\nmount.cifs kernel mount options %s \n",options);
1399 /* convert all '\\' to '/' in share portion so that /proc/mounts looks pretty */
1400 replace_char(dev_name, '\\', '/', strlen(share_name));
1402 if(mount(dev_name, mountpoint, "cifs", flags, options)) {
1403 /* remember to kill daemon on error */
1406 printf("mount failed but no error number set\n");
1409 printf("mount error: cifs filesystem not supported by the system\n");
1414 if (uppercase_string(dev_name) &&
1415 uppercase_string(share_name) &&
1416 uppercase_string(prefixpath)) {
1417 printf("retrying with upper case share name\n");
1422 printf("mount error %d = %s\n",errno,strerror(errno));
1424 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
1427 pmntfile = setmntent(MOUNTED, "a+");
1429 mountent.mnt_fsname = dev_name;
1430 mountent.mnt_dir = mountpoint;
1431 mountent.mnt_type = CONST_DISCARD(char *,"cifs");
1432 mountent.mnt_opts = (char *)malloc(220);
1433 if(mountent.mnt_opts) {
1434 char * mount_user = getusername();
1435 memset(mountent.mnt_opts,0,200);
1436 if(flags & MS_RDONLY)
1437 strlcat(mountent.mnt_opts,"ro",220);
1439 strlcat(mountent.mnt_opts,"rw",220);
1440 if(flags & MS_MANDLOCK)
1441 strlcat(mountent.mnt_opts,",mand",220);
1442 if(flags & MS_NOEXEC)
1443 strlcat(mountent.mnt_opts,",noexec",220);
1444 if(flags & MS_NOSUID)
1445 strlcat(mountent.mnt_opts,",nosuid",220);
1446 if(flags & MS_NODEV)
1447 strlcat(mountent.mnt_opts,",nodev",220);
1448 if(flags & MS_SYNCHRONOUS)
1449 strlcat(mountent.mnt_opts,",synch",220);
1452 strlcat(mountent.mnt_opts,",user=",220);
1453 strlcat(mountent.mnt_opts,mount_user,220);
1455 /* free(mount_user); do not free static mem */
1458 mountent.mnt_freq = 0;
1459 mountent.mnt_passno = 0;
1460 rc = addmntent(pmntfile,&mountent);
1461 endmntent(pmntfile);
1462 SAFE_FREE(mountent.mnt_opts);
1466 printf("could not update mount table\n");
1472 int len = strlen(mountpassword);
1473 memset(mountpassword,0,len);
1474 SAFE_FREE(mountpassword);
1478 SAFE_FREE(orgoptions);
1479 SAFE_FREE(resolved_path);
1480 SAFE_FREE(share_name);