2 Mount helper utility for Linux CIFS VFS (virtual filesystem) client
3 Copyright (C) 2003,2005 Steve French (sfrench@us.ibm.com)
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
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>
42 #define MOUNT_CIFS_VERSION_MAJOR "1"
43 #define MOUNT_CIFS_VERSION_MINOR "10"
45 #ifndef MOUNT_CIFS_VENDOR_SUFFIX
47 #include "include/version.h"
48 #ifdef SAMBA_VERSION_VENDOR_SUFFIX
49 #define MOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING"-"SAMBA_VERSION_VENDOR_SUFFIX
51 #define MOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING
52 #endif /* SAMBA_VERSION_OFFICIAL_STRING and SAMBA_VERSION_VENDOR_SUFFIX */
54 #define MOUNT_CIFS_VENDOR_SUFFIX ""
55 #endif /* _SAMBA_BUILD_ */
56 #endif /* MOUNT_CIFS_VENDOR_SUFFIX */
66 #define MAX_UNC_LEN 1024
68 #define CONST_DISCARD(type, ptr) ((type) ((void *) (ptr)))
70 const char *thisprogram;
72 static int got_password = 0;
73 static int got_user = 0;
74 static int got_domain = 0;
75 static int got_ip = 0;
76 static int got_unc = 0;
77 static int got_uid = 0;
78 static int got_gid = 0;
79 static char * user_name = NULL;
80 static char * mountpassword = NULL;
81 char * domain_name = NULL;
82 char * prefixpath = NULL;
84 /* glibc doesn't have strlcpy, strlcat. Ensure we do. JRA. We
85 * don't link to libreplace so need them here. */
87 /* like strncpy but does not 0 fill the buffer and always null
88 * terminates. bufsize is the size of the destination buffer */
89 size_t strlcpy(char *d, const char *s, size_t bufsize)
91 size_t len = strlen(s);
93 if (bufsize <= 0) return 0;
94 if (len >= bufsize) len = bufsize-1;
100 /* like strncat but does not 0 fill the buffer and always null
101 * terminates. bufsize is the length of the buffer, which should
102 * be one more than the maximum resulting string length */
103 size_t strlcat(char *d, const char *s, size_t bufsize)
105 size_t len1 = strlen(d);
106 size_t len2 = strlen(s);
107 size_t ret = len1 + len2;
109 if (len1+len2 >= bufsize) {
110 len2 = bufsize - (len1+1);
113 memcpy(d+len1, s, len2);
122 open nofollow - avoid symlink exposure?
123 get owner of dir see if matches self or if root
124 call system(umount argv) etc.
128 static char * check_for_domain(char **);
131 static void mount_cifs_usage(void)
133 printf("\nUsage: %s <remotetarget> <dir> -o <options>\n", thisprogram);
134 printf("\nMount the remote target, specified as a UNC name,");
135 printf(" to a local directory.\n\nOptions:\n");
136 printf("\tuser=<arg>\n\tpass=<arg>\n\tdom=<arg>\n");
137 printf("\nLess commonly used options:");
138 printf("\n\tcredentials=<filename>,guest,perm,noperm,setuids,nosetuids,rw,ro,");
139 printf("\n\tsep=<char>,iocharset=<codepage>,suid,nosuid,exec,noexec,serverino,");
140 printf("\n\tdirectio,mapchars,nomapchars,nolock,servernetbiosname=<SRV_RFC1001NAME>");
141 printf("\n\nOptions not needed for servers supporting CIFS Unix extensions");
142 printf("\n\t(e.g. unneeded for mounts to most Samba versions):");
143 printf("\n\tuid=<uid>,gid=<gid>,dir_mode=<mode>,file_mode=<mode>,sfu");
144 printf("\n\nRarely used options:");
145 printf("\n\tport=<tcpport>,rsize=<size>,wsize=<size>,unc=<unc_name>,ip=<ip_address>,");
146 printf("\n\tdev,nodev,nouser_xattr,netbiosname=<OUR_RFC1001NAME>,hard,soft,intr,");
147 printf("\n\tnointr,ignorecase,noposixpaths,noacl");
148 printf("\n\nOptions are described in more detail in the manual page");
149 printf("\n\tman 8 mount.cifs\n");
150 printf("\nTo display the version number of the mount helper:");
151 printf("\n\t%s -V\n",thisprogram);
154 memset(mountpassword,0,64);
160 /* caller frees username if necessary */
161 static char * getusername(void) {
162 char *username = NULL;
163 struct passwd *password = getpwuid(getuid());
166 username = password->pw_name;
171 static char * parse_cifs_url(char * unc_name)
173 printf("\nMounting cifs URL not implemented yet. Attempt to mount %s\n",unc_name);
177 static int open_cred_file(char * file_name)
183 fs = fopen(file_name,"r");
186 line_buf = (char *)malloc(4096);
187 if(line_buf == NULL) {
192 while(fgets(line_buf,4096,fs)) {
193 /* parse line from credential file */
195 /* eat leading white space */
196 for(i=0;i<4086;i++) {
197 if((line_buf[i] != ' ') && (line_buf[i] != '\t'))
199 /* if whitespace - skip past it */
201 if (strncasecmp("username",line_buf+i,8) == 0) {
202 temp_val = strchr(line_buf + i,'=');
204 /* go past equals sign */
206 for(length = 0;length<4087;length++) {
207 if(temp_val[length] == '\n')
211 printf("mount.cifs failed due to malformed username in credentials file");
212 memset(line_buf,0,4096);
214 memset(mountpassword,0,64);
219 user_name = (char *)calloc(1 + length,1);
220 /* BB adding free of user_name string before exit,
221 not really necessary but would be cleaner */
222 strncpy(user_name,temp_val, length);
225 } else if (strncasecmp("password",line_buf+i,8) == 0) {
226 temp_val = strchr(line_buf+i,'=');
228 /* go past equals sign */
230 for(length = 0;length<65;length++) {
231 if(temp_val[length] == '\n')
235 printf("mount.cifs failed: password in credentials file too long\n");
236 memset(line_buf,0, 4096);
238 memset(mountpassword,0,64);
242 if(mountpassword == NULL) {
243 mountpassword = (char *)calloc(65,1);
245 memset(mountpassword,0,64);
247 strncpy(mountpassword,temp_val,length);
252 } else if (strncasecmp("domain",line_buf+i,6) == 0) {
253 temp_val = strchr(line_buf+i,'=');
255 /* go past equals sign */
258 printf("\nDomain %s\n",temp_val);
259 for(length = 0;length<65;length++) {
260 if(temp_val[length] == '\n')
264 printf("mount.cifs failed: domain in credentials file too long\n");
266 memset(mountpassword,0,64);
270 if(domain_name == NULL) {
271 domain_name = (char *)calloc(65,1);
273 memset(domain_name,0,64);
275 strncpy(domain_name,temp_val,length);
285 memset(line_buf,0,4096);
291 static int get_password_from_file(int file_descript, char * filename)
297 if(mountpassword == NULL)
298 mountpassword = (char *)calloc(65,1);
300 memset(mountpassword, 0, 64);
302 if (mountpassword == NULL) {
303 printf("malloc failed\n");
307 if(filename != NULL) {
308 file_descript = open(filename, O_RDONLY);
309 if(file_descript < 0) {
310 printf("mount.cifs failed. %s attempting to open password file %s\n",
311 strerror(errno),filename);
315 /* else file already open and fd provided */
318 rc = read(file_descript,&c,1);
320 printf("mount.cifs failed. Error %s reading password file\n",strerror(errno));
321 memset(mountpassword,0,64);
323 close(file_descript);
326 if(mountpassword[0] == 0) {
328 printf("\nWarning: null password used since cifs password file empty");
331 } else /* read valid character */ {
332 if((c == 0) || (c == '\n')) {
335 mountpassword[i] = c;
338 if((i == 64) && (verboseflag)) {
339 printf("\nWarning: password longer than 64 characters specified in cifs password file");
342 if(filename != NULL) {
343 close(file_descript);
349 static int parse_options(char ** optionsp, int * filesys_flags)
352 char * percent_char = NULL;
354 char * next_keyword = NULL;
362 if (!optionsp || !*optionsp)
367 printf("parsing options: %s\n", data);
369 /* BB fixme check for separator override BB */
373 snprintf(user,sizeof(user),"%u",getuid());
375 snprintf(group,sizeof(group),"%u",getgid());
378 /* while ((data = strsep(&options, ",")) != NULL) { */
379 while(data != NULL) {
380 /* check if ends with trailing comma */
384 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
385 /* data = next keyword */
386 /* value = next value ie stuff after equal sign */
388 next_keyword = strchr(data,','); /* BB handle sep= */
390 /* temporarily null terminate end of keyword=value pair */
394 /* temporarily null terminate keyword to make keyword and value distinct */
395 if ((value = strchr(data, '=')) != NULL) {
400 if (strncmp(data, "users",5) == 0) {
401 if(!value || !*value) {
404 } else if (strncmp(data, "user_xattr",10) == 0) {
405 /* do nothing - need to skip so not parsed as user name */
406 } else if (strncmp(data, "user", 4) == 0) {
408 if (!value || !*value) {
409 if(data[4] == '\0') {
411 printf("\nskipping empty user mount parameter\n");
412 /* remove the parm since it would otherwise be confusing
413 to the kernel code which would think it was a real username */
416 printf("username specified with no parameter\n");
417 return 1; /* needs_arg; */
420 if (strnlen(value, 260) < 260) {
422 percent_char = strchr(value,'%');
425 if(mountpassword == NULL)
426 mountpassword = (char *)calloc(65,1);
429 printf("\nmount.cifs warning - password specified twice\n");
432 strncpy(mountpassword, percent_char,64);
433 /* remove password from username */
434 while(*percent_char != 0) {
440 /* this is only case in which the user
441 name buf is not malloc - so we have to
442 check for domain name embedded within
443 the user name here since the later
444 call to check_for_domain will not be
446 domain_name = check_for_domain(&value);
448 printf("username too long\n");
452 } else if (strncmp(data, "pass", 4) == 0) {
453 if (!value || !*value) {
455 printf("\npassword specified twice, ignoring second\n");
458 } else if (strnlen(value, 17) < 17) {
460 printf("\nmount.cifs warning - password specified twice\n");
463 printf("password too long\n");
466 } else if (strncmp(data, "sec", 3) == 0) {
468 if (!strcmp(value, "none"))
471 } else if (strncmp(data, "ip", 2) == 0) {
472 if (!value || !*value) {
473 printf("target ip address argument missing");
474 } else if (strnlen(value, 35) < 35) {
476 printf("ip address %s override specified\n",value);
479 printf("ip address too long\n");
482 } else if ((strncmp(data, "unc", 3) == 0)
483 || (strncmp(data, "target", 6) == 0)
484 || (strncmp(data, "path", 4) == 0)) {
485 if (!value || !*value) {
486 printf("invalid path to network resource\n");
487 return 1; /* needs_arg; */
488 } else if(strnlen(value,5) < 5) {
489 printf("UNC name too short");
492 if (strnlen(value, 300) < 300) {
494 if (strncmp(value, "//", 2) == 0) {
496 printf("unc name specified twice, ignoring second\n");
499 } else if (strncmp(value, "\\\\", 2) != 0) {
500 printf("UNC Path does not begin with // or \\\\ \n");
504 printf("unc name specified twice, ignoring second\n");
509 printf("CIFS: UNC name too long\n");
512 } else if ((strncmp(data, "domain", 3) == 0)
513 || (strncmp(data, "workgroup", 5) == 0)) {
514 if (!value || !*value) {
515 printf("CIFS: invalid domain name\n");
516 return 1; /* needs_arg; */
518 if (strnlen(value, 65) < 65) {
521 printf("domain name too long\n");
524 } else if (strncmp(data, "cred", 4) == 0) {
525 if (value && *value) {
526 rc = open_cred_file(value);
528 printf("error %d opening credential file %s\n",rc, value);
532 printf("invalid credential file name specified\n");
535 } else if (strncmp(data, "uid", 3) == 0) {
536 if (value && *value) {
538 if (!isdigit(*value)) {
541 if (!(pw = getpwnam(value))) {
542 printf("bad user name \"%s\"\n", value);
545 snprintf(user, sizeof(user), "%u", pw->pw_uid);
547 strlcpy(user,value,sizeof(user));
551 } else if (strncmp(data, "gid", 3) == 0) {
552 if (value && *value) {
554 if (!isdigit(*value)) {
557 if (!(gr = getgrnam(value))) {
558 printf("bad group name \"%s\"\n", value);
561 snprintf(group, sizeof(group), "%u", gr->gr_gid);
563 strlcpy(group,value,sizeof(group));
567 /* fmask and dmask synonyms for people used to smbfs syntax */
568 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
569 if (!value || !*value) {
570 printf ("Option '%s' requires a numerical argument\n", data);
574 if (value[0] != '0') {
575 printf ("WARNING: '%s' not expressed in octal.\n", data);
578 if (strcmp (data, "fmask") == 0) {
579 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
580 data = "file_mode"; /* BB fix this */
582 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
583 if (!value || !*value) {
584 printf ("Option '%s' requires a numerical argument\n", data);
588 if (value[0] != '0') {
589 printf ("WARNING: '%s' not expressed in octal.\n", data);
592 if (strcmp (data, "dmask") == 0) {
593 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
596 /* the following eight mount options should be
597 stripped out from what is passed into the kernel
598 since these eight options are best passed as the
599 mount flags rather than redundantly to the kernel
600 and could generate spurious warnings depending on the
601 level of the corresponding cifs vfs kernel code */
602 } else if (strncmp(data, "nosuid", 6) == 0) {
603 *filesys_flags |= MS_NOSUID;
604 } else if (strncmp(data, "suid", 4) == 0) {
605 *filesys_flags &= ~MS_NOSUID;
606 } else if (strncmp(data, "nodev", 5) == 0) {
607 *filesys_flags |= MS_NODEV;
608 } else if ((strncmp(data, "nobrl", 5) == 0) ||
609 (strncmp(data, "nolock", 6) == 0)) {
610 *filesys_flags &= ~MS_MANDLOCK;
611 } else if (strncmp(data, "dev", 3) == 0) {
612 *filesys_flags &= ~MS_NODEV;
613 } else if (strncmp(data, "noexec", 6) == 0) {
614 *filesys_flags |= MS_NOEXEC;
615 } else if (strncmp(data, "exec", 4) == 0) {
616 *filesys_flags &= ~MS_NOEXEC;
617 } else if (strncmp(data, "guest", 5) == 0) {
619 } else if (strncmp(data, "ro", 2) == 0) {
620 *filesys_flags |= MS_RDONLY;
621 } else if (strncmp(data, "rw", 2) == 0) {
622 *filesys_flags &= ~MS_RDONLY;
623 } else if (strncmp(data, "remount", 7) == 0) {
624 *filesys_flags |= MS_REMOUNT;
625 } /* else if (strnicmp(data, "port", 4) == 0) {
626 if (value && *value) {
628 simple_strtoul(value, &value, 0);
630 } else if (strnicmp(data, "rsize", 5) == 0) {
631 if (value && *value) {
633 simple_strtoul(value, &value, 0);
635 } else if (strnicmp(data, "wsize", 5) == 0) {
636 if (value && *value) {
638 simple_strtoul(value, &value, 0);
640 } else if (strnicmp(data, "version", 3) == 0) {
642 printf("CIFS: Unknown mount option %s\n",data);
643 } */ /* nothing to do on those four mount options above.
644 Just pass to kernel and ignore them here */
646 /* Copy (possibly modified) option to out */
647 word_len = strlen(data);
649 word_len += 1 + strlen(value);
651 out = (char *)realloc(out, out_len + word_len + 2);
658 strlcat(out, ",", out_len + word_len + 2);
663 snprintf(out + out_len, word_len + 1, "%s=%s", data, value);
665 snprintf(out + out_len, word_len + 1, "%s", data);
666 out_len = strlen(out);
672 /* special-case the uid and gid */
674 word_len = strlen(user);
676 out = (char *)realloc(out, out_len + word_len + 6);
683 strlcat(out, ",", out_len + word_len + 6);
686 snprintf(out + out_len, word_len + 5, "uid=%s", user);
687 out_len = strlen(out);
690 word_len = strlen(group);
692 out = (char *)realloc(out, out_len + 1 + word_len + 6);
699 strlcat(out, ",", out_len + word_len + 6);
702 snprintf(out + out_len, word_len + 5, "gid=%s", group);
703 out_len = strlen(out);
711 /* replace all (one or more) commas with double commas */
712 static void check_for_comma(char ** ppasswrd)
717 int number_of_commas = 0;
732 if(number_of_commas == 0)
734 if(number_of_commas > 64) {
735 /* would otherwise overflow the mount options buffer */
736 printf("\nInvalid password. Password contains too many commas.\n");
740 new_pass_buf = (char *)malloc(len+number_of_commas+1);
741 if(new_pass_buf == NULL)
744 for(i=0,j=0;i<len;i++,j++) {
745 new_pass_buf[j] = pass[i];
748 new_pass_buf[j] = pass[i];
751 new_pass_buf[len+number_of_commas] = 0;
754 *ppasswrd = new_pass_buf;
759 /* Usernames can not have backslash in them and we use
760 [BB check if usernames can have forward slash in them BB]
761 backslash as domain\user separator character
763 static char * check_for_domain(char **ppuser)
765 char * original_string;
775 original_string = *ppuser;
777 if (original_string == NULL)
780 original_len = strlen(original_string);
782 usernm = strchr(*ppuser,'/');
783 if (usernm == NULL) {
784 usernm = strchr(*ppuser,'\\');
790 printf("Domain name specified twice. Username probably malformed\n");
796 if (domainnm[0] != 0) {
799 printf("null domain\n");
801 len = strlen(domainnm);
802 /* reset domainm to new buffer, and copy
803 domain name into it */
804 domainnm = (char *)malloc(len+1);
808 strlcpy(domainnm,*ppuser,len+1);
810 /* move_string(*ppuser, usernm+1) */
811 len = strlen(usernm+1);
813 if(len >= original_len) {
814 /* should not happen */
818 for(i=0;i<original_len;i++) {
820 original_string[i] = usernm[i+1];
821 else /* stuff with commas to remove last parm */
822 original_string[i] = ',';
825 /* BB add check for more than one slash?
833 /* replace all occurances of "from" in a string with "to" */
834 static void replace_char(char *string, char from, char to)
837 string = strchr(string, from);
843 /* Note that caller frees the returned buffer if necessary */
844 static char * parse_server(char ** punc_name)
846 char * unc_name = *punc_name;
847 int length = strnlen(unc_name, MAX_UNC_LEN);
849 char * ipaddress_string = NULL;
850 struct hostent * host_entry = NULL;
851 struct in_addr server_ipaddr;
853 if(length > (MAX_UNC_LEN - 1)) {
854 printf("mount error: UNC name too long");
857 if (strncasecmp("cifs://",unc_name,7) == 0)
858 return parse_cifs_url(unc_name+7);
859 if (strncasecmp("smb://",unc_name,6) == 0) {
860 return parse_cifs_url(unc_name+6);
864 /* BB add code to find DFS root here */
865 printf("\nMounting the DFS root for domain not implemented yet\n");
868 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
869 /* check for nfs syntax ie server:share */
870 share = strchr(unc_name,':');
872 *punc_name = (char *)malloc(length+3);
873 if(*punc_name == NULL) {
874 /* put the original string back if
876 *punc_name = unc_name;
880 strncpy((*punc_name)+2,unc_name,length);
882 unc_name = *punc_name;
883 unc_name[length+2] = 0;
884 goto continue_unc_parsing;
886 printf("mount error: improperly formatted UNC name.");
887 printf(" %s does not begin with \\\\ or //\n",unc_name);
891 continue_unc_parsing:
896 /* convert any '/' in unc to '\\' */
897 replace_char(unc_name, '/', '\\');
899 if ((share = strchr(unc_name,'\\'))) {
900 *share = 0; /* temporarily terminate the string */
903 host_entry = gethostbyname(unc_name);
905 *(share - 1) = '\\'; /* put delimiter back */
906 if ((prefixpath = strchr(share, '\\'))) {
907 *prefixpath = 0; /* permanently terminate the string */
908 if (!strlen(++prefixpath))
909 prefixpath = NULL; /* this needs to be done explicitly */
913 printf("ip address specified explicitly\n");
916 if(host_entry == NULL) {
917 printf("mount error: could not find target server. TCP name %s not found\n", unc_name);
920 /* BB should we pass an alternate version of the share name as Unicode */
921 /* BB what about ipv6? BB */
922 /* BB add retries with alternate servers in list */
924 memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
926 ipaddress_string = inet_ntoa(server_ipaddr);
927 if(ipaddress_string == NULL) {
928 printf("mount error: could not get valid ip address for target server\n");
931 return ipaddress_string;
934 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
935 printf("Mounting the DFS root for a particular server not implemented yet\n");
942 static struct option longopts[] = {
943 { "all", 0, NULL, 'a' },
944 { "help",0, NULL, 'h' },
945 { "move",0, NULL, 'm' },
946 { "bind",0, NULL, 'b' },
947 { "read-only", 0, NULL, 'r' },
948 { "ro", 0, NULL, 'r' },
949 { "verbose", 0, NULL, 'v' },
950 { "version", 0, NULL, 'V' },
951 { "read-write", 0, NULL, 'w' },
952 { "rw", 0, NULL, 'w' },
953 { "options", 1, NULL, 'o' },
954 { "type", 1, NULL, 't' },
955 { "rsize",1, NULL, 'R' },
956 { "wsize",1, NULL, 'W' },
957 { "uid", 1, NULL, '1'},
958 { "gid", 1, NULL, '2'},
959 { "user",1,NULL,'u'},
960 { "username",1,NULL,'u'},
962 { "domain",1,NULL,'d'},
963 { "password",1,NULL,'p'},
964 { "pass",1,NULL,'p'},
965 { "credentials",1,NULL,'c'},
966 { "port",1,NULL,'P'},
967 /* { "uuid",1,NULL,'U'}, */ /* BB unimplemented */
971 /* convert a string to uppercase. return false if the string
972 * wasn't ASCII or was a NULL ptr */
974 uppercase_string(char *string)
980 /* check for unicode */
981 if ((unsigned char) string[0] & 0x80)
983 *string = toupper((unsigned char) *string);
990 int main(int argc, char ** argv)
993 int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
994 char * orgoptions = NULL;
995 char * share_name = NULL;
996 char * ipaddr = NULL;
998 char * mountpoint = NULL;
999 char * options = NULL;
1000 char * resolved_path = NULL;
1011 size_t options_size = 0;
1012 int retry = 0; /* set when we have to retry mount with uppercase */
1013 struct stat statbuf;
1014 struct utsname sysinfo;
1015 struct mntent mountent;
1018 /* setlocale(LC_ALL, "");
1019 bindtextdomain(PACKAGE, LOCALEDIR);
1020 textdomain(PACKAGE); */
1023 thisprogram = argv[0];
1029 if(thisprogram == NULL)
1030 thisprogram = "mount.cifs";
1033 /* BB add workstation name and domain and pass down */
1035 /* #ifdef _GNU_SOURCE
1036 printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
1040 share_name = strndup(argv[1], MAX_UNC_LEN);
1041 if (share_name == NULL) {
1042 fprintf(stderr, "%s: %s", argv[0], strerror(ENOMEM));
1045 mountpoint = argv[2];
1051 /* add sharename in opts string as unc= parm */
1053 while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
1054 longopts, NULL)) != -1) {
1056 /* No code to do the following options yet */
1058 list_with_volumelabel = 1;
1061 volumelabel = optarg;
1068 case 'h': /* help */
1069 mount_cifs_usage ();
1079 "option 'b' (MS_BIND) not supported\n");
1087 "option 'm' (MS_MOVE) not supported\n");
1091 orgoptions = strdup(optarg);
1093 case 'r': /* mount readonly */
1103 printf ("mount.cifs version: %s.%s%s\n",
1104 MOUNT_CIFS_VERSION_MAJOR,
1105 MOUNT_CIFS_VERSION_MINOR,
1106 MOUNT_CIFS_VENDOR_SUFFIX);
1108 memset(mountpassword,0,64);
1112 flags &= ~MS_RDONLY;
1115 rsize = atoi(optarg) ;
1118 wsize = atoi(optarg);
1121 if (isdigit(*optarg)) {
1124 uid = strtoul(optarg, &ep, 10);
1126 printf("bad uid value \"%s\"\n", optarg);
1132 if (!(pw = getpwnam(optarg))) {
1133 printf("bad user name \"%s\"\n", optarg);
1141 if (isdigit(*optarg)) {
1144 gid = strtoul(optarg, &ep, 10);
1146 printf("bad gid value \"%s\"\n", optarg);
1152 if (!(gr = getgrnam(optarg))) {
1153 printf("bad user name \"%s\"\n", optarg);
1165 domain_name = optarg; /* BB fix this - currently ignored */
1169 if(mountpassword == NULL)
1170 mountpassword = (char *)calloc(65,1);
1173 strncpy(mountpassword,optarg,64);
1177 get_password_from_file(0 /* stdin */,NULL);
1182 printf("unknown mount option %c\n",c);
1188 if((argc < 3) || (dev_name == NULL) || (mountpoint == NULL)) {
1193 if (getenv("PASSWD")) {
1194 if(mountpassword == NULL)
1195 mountpassword = (char *)calloc(65,1);
1197 strncpy(mountpassword,getenv("PASSWD"),64);
1200 } else if (getenv("PASSWD_FD")) {
1201 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
1202 } else if (getenv("PASSWD_FILE")) {
1203 get_password_from_file(0, getenv("PASSWD_FILE"));
1206 if (orgoptions && parse_options(&orgoptions, &flags)) {
1210 ipaddr = parse_server(&share_name);
1211 if((ipaddr == NULL) && (got_ip == 0)) {
1212 printf("No ip address specified and hostname not found\n");
1217 /* BB save off path and pop after mount returns? */
1218 resolved_path = (char *)malloc(PATH_MAX+1);
1220 /* Note that if we can not canonicalize the name, we get
1221 another chance to see if it is valid when we chdir to it */
1222 if (realpath(mountpoint, resolved_path)) {
1223 mountpoint = resolved_path;
1226 if(chdir(mountpoint)) {
1227 printf("mount error: can not change directory into mount target %s\n",mountpoint);
1232 if(stat (".", &statbuf)) {
1233 printf("mount error: mount point %s does not exist\n",mountpoint);
1238 if (S_ISDIR(statbuf.st_mode) == 0) {
1239 printf("mount error: mount point %s is not a directory\n",mountpoint);
1244 if((getuid() != 0) && (geteuid() == 0)) {
1245 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
1246 #ifndef CIFS_ALLOW_USR_SUID
1247 /* Do not allow user mounts to control suid flag
1248 for mount unless explicitly built that way */
1249 flags |= MS_NOSUID | MS_NODEV;
1252 printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n");
1258 user_name = getusername();
1262 if(got_password == 0) {
1263 mountpassword = getpass("Password: "); /* BB obsolete */
1266 /* FIXME launch daemon (handles dfs name resolution and credential change)
1267 remember to clear parms and overwrite password field before launching */
1270 optlen = strlen(orgoptions);
1275 optlen += strlen(share_name) + 4;
1277 printf("No server share name specified\n");
1278 printf("\nMounting the DFS root for server not implemented yet\n");
1282 optlen += strlen(user_name) + 6;
1284 optlen += strlen(ipaddr) + 4;
1286 optlen += strlen(mountpassword) + 6;
1289 options_size = optlen + 10 + 64;
1290 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 */);
1292 if(options == NULL) {
1293 printf("Could not allocate memory for mount options\n");
1298 strlcpy(options,"unc=",options_size);
1299 strlcat(options,share_name,options_size);
1300 /* scan backwards and reverse direction of slash */
1301 temp = strrchr(options, '/');
1302 if(temp > options + 6)
1305 strlcat(options,",ip=",options_size);
1306 strlcat(options,ipaddr,options_size);
1310 /* check for syntax like user=domain\user */
1312 domain_name = check_for_domain(&user_name);
1313 strlcat(options,",user=",options_size);
1314 strlcat(options,user_name,options_size);
1318 /* extra length accounted for in option string above */
1319 strlcat(options,",domain=",options_size);
1320 strlcat(options,domain_name,options_size);
1324 /* Commas have to be doubled, or else they will
1325 look like the parameter separator */
1326 /* if(sep is not set)*/
1328 check_for_comma(&mountpassword);
1329 strlcat(options,",pass=",options_size);
1330 strlcat(options,mountpassword,options_size);
1333 strlcat(options,",ver=",options_size);
1334 strlcat(options,MOUNT_CIFS_VERSION_MAJOR,options_size);
1337 strlcat(options,",",options_size);
1338 strlcat(options,orgoptions,options_size);
1341 strlcat(options,",prefixpath=",options_size);
1342 strlcat(options,prefixpath,options_size); /* no need to cat the / */
1345 printf("\nmount.cifs kernel mount options %s \n",options);
1347 /* convert all '\\' to '/' so that /proc/mounts looks pretty */
1348 replace_char(dev_name, '\\', '/');
1350 if(mount(dev_name, mountpoint, "cifs", flags, options)) {
1351 /* remember to kill daemon on error */
1354 printf("mount failed but no error number set\n");
1357 printf("mount error: cifs filesystem not supported by the system\n");
1362 if (uppercase_string(dev_name) &&
1363 uppercase_string(share_name) &&
1364 uppercase_string(prefixpath)) {
1365 printf("retrying with upper case share name\n");
1370 printf("mount error %d = %s\n",errno,strerror(errno));
1372 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
1376 pmntfile = setmntent(MOUNTED, "a+");
1378 mountent.mnt_fsname = dev_name;
1379 mountent.mnt_dir = mountpoint;
1380 mountent.mnt_type = CONST_DISCARD(char *,"cifs");
1381 mountent.mnt_opts = (char *)malloc(220);
1382 if(mountent.mnt_opts) {
1383 char * mount_user = getusername();
1384 memset(mountent.mnt_opts,0,200);
1385 if(flags & MS_RDONLY)
1386 strlcat(mountent.mnt_opts,"ro",220);
1388 strlcat(mountent.mnt_opts,"rw",220);
1389 if(flags & MS_MANDLOCK)
1390 strlcat(mountent.mnt_opts,",mand",220);
1391 if(flags & MS_NOEXEC)
1392 strlcat(mountent.mnt_opts,",noexec",220);
1393 if(flags & MS_NOSUID)
1394 strlcat(mountent.mnt_opts,",nosuid",220);
1395 if(flags & MS_NODEV)
1396 strlcat(mountent.mnt_opts,",nodev",220);
1397 if(flags & MS_SYNCHRONOUS)
1398 strlcat(mountent.mnt_opts,",synch",220);
1401 strlcat(mountent.mnt_opts,",user=",220);
1402 strlcat(mountent.mnt_opts,mount_user,220);
1404 /* free(mount_user); do not free static mem */
1407 mountent.mnt_freq = 0;
1408 mountent.mnt_passno = 0;
1409 rc = addmntent(pmntfile,&mountent);
1410 endmntent(pmntfile);
1411 if(mountent.mnt_opts)
1412 free(mountent.mnt_opts);
1414 printf("could not update mount table\n");
1420 int len = strlen(mountpassword);
1421 memset(mountpassword,0,len);
1422 free(mountpassword);
1426 memset(options,0,optlen);
1431 memset(orgoptions,0,orgoptlen);
1435 free(resolved_path);