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 CONST_DISCARD(type, ptr) ((type) ((void *) (ptr)))
68 const char *thisprogram;
70 static int got_password = 0;
71 static int got_user = 0;
72 static int got_domain = 0;
73 static int got_ip = 0;
74 static int got_unc = 0;
75 static int got_uid = 0;
76 static int got_gid = 0;
77 static int free_share_name = 0;
78 static char * user_name = NULL;
79 static char * mountpassword = NULL;
80 char * domain_name = NULL;
81 char * prefixpath = NULL;
87 open nofollow - avoid symlink exposure?
88 get owner of dir see if matches self or if root
89 call system(umount argv) etc.
93 static char * check_for_domain(char **);
96 static void mount_cifs_usage(void)
98 printf("\nUsage: %s <remotetarget> <dir> -o <options>\n", thisprogram);
99 printf("\nMount the remote target, specified as a UNC name,");
100 printf(" to a local directory.\n\nOptions:\n");
101 printf("\tuser=<arg>\n\tpass=<arg>\n\tdom=<arg>\n");
102 printf("\nLess commonly used options:");
103 printf("\n\tcredentials=<filename>,guest,perm,noperm,setuids,nosetuids,rw,ro,");
104 printf("\n\tsep=<char>,iocharset=<codepage>,suid,nosuid,exec,noexec,serverino,");
105 printf("\n\tdirectio,mapchars,nomapchars,nolock,servernetbiosname=<SRV_RFC1001NAME>");
106 printf("\n\nOptions not needed for servers supporting CIFS Unix extensions");
107 printf("\n\t(e.g. unneeded for mounts to most Samba versions):");
108 printf("\n\tuid=<uid>,gid=<gid>,dir_mode=<mode>,file_mode=<mode>,sfu");
109 printf("\n\nRarely used options:");
110 printf("\n\tport=<tcpport>,rsize=<size>,wsize=<size>,unc=<unc_name>,ip=<ip_address>,");
111 printf("\n\tdev,nodev,nouser_xattr,netbiosname=<OUR_RFC1001NAME>,hard,soft,intr,");
112 printf("\n\tnointr,ignorecase,noposixpaths,noacl");
113 printf("\n\nOptions are described in more detail in the manual page");
114 printf("\n\tman 8 mount.cifs\n");
115 printf("\nTo display the version number of the mount helper:");
116 printf("\n\t%s -V\n",thisprogram);
119 memset(mountpassword,0,64);
125 /* caller frees username if necessary */
126 static char * getusername(void) {
127 char *username = NULL;
128 struct passwd *password = getpwuid(getuid());
131 username = password->pw_name;
136 static char * parse_cifs_url(char * unc_name)
138 printf("\nMounting cifs URL not implemented yet. Attempt to mount %s\n",unc_name);
142 static int open_cred_file(char * file_name)
148 fs = fopen(file_name,"r");
151 line_buf = (char *)malloc(4096);
152 if(line_buf == NULL) {
157 while(fgets(line_buf,4096,fs)) {
158 /* parse line from credential file */
160 /* eat leading white space */
161 for(i=0;i<4086;i++) {
162 if((line_buf[i] != ' ') && (line_buf[i] != '\t'))
164 /* if whitespace - skip past it */
166 if (strncasecmp("username",line_buf+i,8) == 0) {
167 temp_val = strchr(line_buf + i,'=');
169 /* go past equals sign */
171 for(length = 0;length<4087;length++) {
172 if(temp_val[length] == '\n')
176 printf("mount.cifs failed due to malformed username in credentials file");
177 memset(line_buf,0,4096);
179 memset(mountpassword,0,64);
184 user_name = (char *)calloc(1 + length,1);
185 /* BB adding free of user_name string before exit,
186 not really necessary but would be cleaner */
187 strncpy(user_name,temp_val, length);
190 } else if (strncasecmp("password",line_buf+i,8) == 0) {
191 temp_val = strchr(line_buf+i,'=');
193 /* go past equals sign */
195 for(length = 0;length<65;length++) {
196 if(temp_val[length] == '\n')
200 printf("mount.cifs failed: password in credentials file too long\n");
201 memset(line_buf,0, 4096);
203 memset(mountpassword,0,64);
207 if(mountpassword == NULL) {
208 mountpassword = (char *)calloc(65,1);
210 memset(mountpassword,0,64);
212 strncpy(mountpassword,temp_val,length);
217 } else if (strncasecmp("domain",line_buf+i,6) == 0) {
218 temp_val = strchr(line_buf+i,'=');
220 /* go past equals sign */
223 printf("\nDomain %s\n",temp_val);
224 for(length = 0;length<65;length++) {
225 if(temp_val[length] == '\n')
229 printf("mount.cifs failed: domain in credentials file too long\n");
231 memset(mountpassword,0,64);
235 if(domain_name == NULL) {
236 domain_name = (char *)calloc(65,1);
238 memset(domain_name,0,64);
240 strncpy(domain_name,temp_val,length);
250 memset(line_buf,0,4096);
256 static int get_password_from_file(int file_descript, char * filename)
262 if(mountpassword == NULL)
263 mountpassword = (char *)calloc(65,1);
265 memset(mountpassword, 0, 64);
267 if (mountpassword == NULL) {
268 printf("malloc failed\n");
272 if(filename != NULL) {
273 file_descript = open(filename, O_RDONLY);
274 if(file_descript < 0) {
275 printf("mount.cifs failed. %s attempting to open password file %s\n",
276 strerror(errno),filename);
280 /* else file already open and fd provided */
283 rc = read(file_descript,&c,1);
285 printf("mount.cifs failed. Error %s reading password file\n",strerror(errno));
286 memset(mountpassword,0,64);
288 close(file_descript);
291 if(mountpassword[0] == 0) {
293 printf("\nWarning: null password used since cifs password file empty");
296 } else /* read valid character */ {
297 if((c == 0) || (c == '\n')) {
300 mountpassword[i] = c;
303 if((i == 64) && (verboseflag)) {
304 printf("\nWarning: password longer than 64 characters specified in cifs password file");
307 if(filename != NULL) {
308 close(file_descript);
314 static int parse_options(char ** optionsp, int * filesys_flags)
317 char * percent_char = NULL;
319 char * next_keyword = NULL;
325 if (!optionsp || !*optionsp)
330 printf("parsing options: %s\n", data);
332 /* BB fixme check for separator override BB */
334 /* while ((data = strsep(&options, ",")) != NULL) { */
335 while(data != NULL) {
336 /* check if ends with trailing comma */
340 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
341 /* data = next keyword */
342 /* value = next value ie stuff after equal sign */
344 next_keyword = strchr(data,','); /* BB handle sep= */
346 /* temporarily null terminate end of keyword=value pair */
350 /* temporarily null terminate keyword to make keyword and value distinct */
351 if ((value = strchr(data, '=')) != NULL) {
356 if (strncmp(data, "users",5) == 0) {
357 if(!value || !*value) {
360 } else if (strncmp(data, "user_xattr",10) == 0) {
361 /* do nothing - need to skip so not parsed as user name */
362 } else if (strncmp(data, "user", 4) == 0) {
364 if (!value || !*value) {
365 if(data[4] == '\0') {
367 printf("\nskipping empty user mount parameter\n");
368 /* remove the parm since it would otherwise be confusing
369 to the kernel code which would think it was a real username */
372 printf("username specified with no parameter\n");
373 return 1; /* needs_arg; */
376 if (strnlen(value, 260) < 260) {
378 percent_char = strchr(value,'%');
381 if(mountpassword == NULL)
382 mountpassword = (char *)calloc(65,1);
385 printf("\nmount.cifs warning - password specified twice\n");
388 strncpy(mountpassword, percent_char,64);
389 /* remove password from username */
390 while(*percent_char != 0) {
396 /* this is only case in which the user
397 name buf is not malloc - so we have to
398 check for domain name embedded within
399 the user name here since the later
400 call to check_for_domain will not be
402 domain_name = check_for_domain(&value);
404 printf("username too long\n");
408 } else if (strncmp(data, "pass", 4) == 0) {
409 if (!value || !*value) {
411 printf("\npassword specified twice, ignoring second\n");
414 } else if (strnlen(value, 17) < 17) {
416 printf("\nmount.cifs warning - password specified twice\n");
419 printf("password too long\n");
422 } else if (strncmp(data, "sec", 3) == 0) {
424 if (!strcmp(value, "none"))
427 } else if (strncmp(data, "ip", 2) == 0) {
428 if (!value || !*value) {
429 printf("target ip address argument missing");
430 } else if (strnlen(value, 35) < 35) {
432 printf("ip address %s override specified\n",value);
435 printf("ip address too long\n");
438 } else if ((strncmp(data, "unc", 3) == 0)
439 || (strncmp(data, "target", 6) == 0)
440 || (strncmp(data, "path", 4) == 0)) {
441 if (!value || !*value) {
442 printf("invalid path to network resource\n");
443 return 1; /* needs_arg; */
444 } else if(strnlen(value,5) < 5) {
445 printf("UNC name too short");
448 if (strnlen(value, 300) < 300) {
450 if (strncmp(value, "//", 2) == 0) {
452 printf("unc name specified twice, ignoring second\n");
455 } else if (strncmp(value, "\\\\", 2) != 0) {
456 printf("UNC Path does not begin with // or \\\\ \n");
460 printf("unc name specified twice, ignoring second\n");
465 printf("CIFS: UNC name too long\n");
468 } else if ((strncmp(data, "domain", 3) == 0)
469 || (strncmp(data, "workgroup", 5) == 0)) {
470 if (!value || !*value) {
471 printf("CIFS: invalid domain name\n");
472 return 1; /* needs_arg; */
474 if (strnlen(value, 65) < 65) {
477 printf("domain name too long\n");
480 } else if (strncmp(data, "cred", 4) == 0) {
481 if (value && *value) {
482 rc = open_cred_file(value);
484 printf("error %d opening credential file %s\n",rc, value);
488 printf("invalid credential file name specified\n");
491 } else if (strncmp(data, "uid", 3) == 0) {
492 if (value && *value) {
494 if (!isdigit(*value)) {
496 static char temp[32];
498 if (!(pw = getpwnam(value))) {
499 printf("bad user name \"%s\"\n", value);
502 sprintf(temp, "%u", pw->pw_uid);
507 } else if (strncmp(data, "gid", 3) == 0) {
508 if (value && *value) {
510 if (!isdigit(*value)) {
512 static char temp[32];
514 if (!(gr = getgrnam(value))) {
515 printf("bad group name \"%s\"\n", value);
518 sprintf(temp, "%u", gr->gr_gid);
523 /* fmask and dmask synonyms for people used to smbfs syntax */
524 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
525 if (!value || !*value) {
526 printf ("Option '%s' requires a numerical argument\n", data);
530 if (value[0] != '0') {
531 printf ("WARNING: '%s' not expressed in octal.\n", data);
534 if (strcmp (data, "fmask") == 0) {
535 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
536 data = "file_mode"; /* BB fix this */
538 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
539 if (!value || !*value) {
540 printf ("Option '%s' requires a numerical argument\n", data);
544 if (value[0] != '0') {
545 printf ("WARNING: '%s' not expressed in octal.\n", data);
548 if (strcmp (data, "dmask") == 0) {
549 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
552 /* the following eight mount options should be
553 stripped out from what is passed into the kernel
554 since these eight options are best passed as the
555 mount flags rather than redundantly to the kernel
556 and could generate spurious warnings depending on the
557 level of the corresponding cifs vfs kernel code */
558 } else if (strncmp(data, "nosuid", 6) == 0) {
559 *filesys_flags |= MS_NOSUID;
560 } else if (strncmp(data, "suid", 4) == 0) {
561 *filesys_flags &= ~MS_NOSUID;
562 } else if (strncmp(data, "nodev", 5) == 0) {
563 *filesys_flags |= MS_NODEV;
564 } else if ((strncmp(data, "nobrl", 5) == 0) ||
565 (strncmp(data, "nolock", 6) == 0)) {
566 *filesys_flags &= ~MS_MANDLOCK;
567 } else if (strncmp(data, "dev", 3) == 0) {
568 *filesys_flags &= ~MS_NODEV;
569 } else if (strncmp(data, "noexec", 6) == 0) {
570 *filesys_flags |= MS_NOEXEC;
571 } else if (strncmp(data, "exec", 4) == 0) {
572 *filesys_flags &= ~MS_NOEXEC;
573 } else if (strncmp(data, "guest", 5) == 0) {
575 } else if (strncmp(data, "ro", 2) == 0) {
576 *filesys_flags |= MS_RDONLY;
577 } else if (strncmp(data, "rw", 2) == 0) {
578 *filesys_flags &= ~MS_RDONLY;
579 } else if (strncmp(data, "remount", 7) == 0) {
580 *filesys_flags |= MS_REMOUNT;
581 } /* else if (strnicmp(data, "port", 4) == 0) {
582 if (value && *value) {
584 simple_strtoul(value, &value, 0);
586 } else if (strnicmp(data, "rsize", 5) == 0) {
587 if (value && *value) {
589 simple_strtoul(value, &value, 0);
591 } else if (strnicmp(data, "wsize", 5) == 0) {
592 if (value && *value) {
594 simple_strtoul(value, &value, 0);
596 } else if (strnicmp(data, "version", 3) == 0) {
598 printf("CIFS: Unknown mount option %s\n",data);
599 } */ /* nothing to do on those four mount options above.
600 Just pass to kernel and ignore them here */
602 /* Copy (possibly modified) option to out */
603 word_len = strlen(data);
605 word_len += 1 + strlen(value);
607 out = (char *)realloc(out, out_len + word_len + 2);
614 out[out_len++] = ',';
616 sprintf(out + out_len, "%s=%s", data, value);
618 sprintf(out + out_len, "%s", data);
619 out_len = strlen(out);
629 /* replace all (one or more) commas with double commas */
630 static void check_for_comma(char ** ppasswrd)
635 int number_of_commas = 0;
650 if(number_of_commas == 0)
652 if(number_of_commas > 64) {
653 /* would otherwise overflow the mount options buffer */
654 printf("\nInvalid password. Password contains too many commas.\n");
658 new_pass_buf = (char *)malloc(len+number_of_commas+1);
659 if(new_pass_buf == NULL)
662 for(i=0,j=0;i<len;i++,j++) {
663 new_pass_buf[j] = pass[i];
666 new_pass_buf[j] = pass[i];
669 new_pass_buf[len+number_of_commas] = 0;
672 *ppasswrd = new_pass_buf;
677 /* Usernames can not have backslash in them and we use
678 [BB check if usernames can have forward slash in them BB]
679 backslash as domain\user separator character
681 static char * check_for_domain(char **ppuser)
683 char * original_string;
693 original_string = *ppuser;
695 if (original_string == NULL)
698 original_len = strlen(original_string);
700 usernm = strchr(*ppuser,'/');
701 if (usernm == NULL) {
702 usernm = strchr(*ppuser,'\\');
708 printf("Domain name specified twice. Username probably malformed\n");
714 if (domainnm[0] != 0) {
717 printf("null domain\n");
719 len = strlen(domainnm);
720 /* reset domainm to new buffer, and copy
721 domain name into it */
722 domainnm = (char *)malloc(len+1);
726 strcpy(domainnm,*ppuser);
728 /* move_string(*ppuser, usernm+1) */
729 len = strlen(usernm+1);
731 if(len >= original_len) {
732 /* should not happen */
736 for(i=0;i<original_len;i++) {
738 original_string[i] = usernm[i+1];
739 else /* stuff with commas to remove last parm */
740 original_string[i] = ',';
743 /* BB add check for more than one slash?
751 /* Note that caller frees the returned buffer if necessary */
752 static char * parse_server(char ** punc_name)
754 char * unc_name = *punc_name;
755 int length = strnlen(unc_name,1024);
757 char * ipaddress_string = NULL;
758 struct hostent * host_entry = NULL;
759 struct in_addr server_ipaddr;
762 printf("mount error: UNC name too long");
765 if (strncasecmp("cifs://",unc_name,7) == 0)
766 return parse_cifs_url(unc_name+7);
767 if (strncasecmp("smb://",unc_name,6) == 0) {
768 return parse_cifs_url(unc_name+6);
772 /* BB add code to find DFS root here */
773 printf("\nMounting the DFS root for domain not implemented yet\n");
776 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
777 /* check for nfs syntax ie server:share */
778 share = strchr(unc_name,':');
781 *punc_name = (char *)malloc(length+3);
782 if(*punc_name == NULL) {
783 /* put the original string back if
785 *punc_name = unc_name;
790 strncpy((*punc_name)+2,unc_name,length);
791 unc_name = *punc_name;
792 unc_name[length+2] = 0;
793 goto continue_unc_parsing;
795 printf("mount error: improperly formatted UNC name.");
796 printf(" %s does not begin with \\\\ or //\n",unc_name);
800 continue_unc_parsing:
804 if ((share = strchr(unc_name, '/')) ||
805 (share = strchr(unc_name,'\\'))) {
806 *share = 0; /* temporarily terminate the string */
809 host_entry = gethostbyname(unc_name);
811 *(share - 1) = '/'; /* put the slash back */
812 if ((prefixpath = strchr(share, '/'))) {
813 *prefixpath = 0; /* permanently terminate the string */
814 if (!strlen(++prefixpath))
815 prefixpath = NULL; /* this needs to be done explicitly */
819 printf("ip address specified explicitly\n");
822 if(host_entry == NULL) {
823 printf("mount error: could not find target server. TCP name %s not found\n", unc_name);
826 /* BB should we pass an alternate version of the share name as Unicode */
827 /* BB what about ipv6? BB */
828 /* BB add retries with alternate servers in list */
830 memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
832 ipaddress_string = inet_ntoa(server_ipaddr);
833 if(ipaddress_string == NULL) {
834 printf("mount error: could not get valid ip address for target server\n");
837 return ipaddress_string;
840 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
841 printf("Mounting the DFS root for a particular server not implemented yet\n");
848 static struct option longopts[] = {
849 { "all", 0, NULL, 'a' },
850 { "help",0, NULL, 'h' },
851 { "move",0, NULL, 'm' },
852 { "bind",0, NULL, 'b' },
853 { "read-only", 0, NULL, 'r' },
854 { "ro", 0, NULL, 'r' },
855 { "verbose", 0, NULL, 'v' },
856 { "version", 0, NULL, 'V' },
857 { "read-write", 0, NULL, 'w' },
858 { "rw", 0, NULL, 'w' },
859 { "options", 1, NULL, 'o' },
860 { "type", 1, NULL, 't' },
861 { "rsize",1, NULL, 'R' },
862 { "wsize",1, NULL, 'W' },
863 { "uid", 1, NULL, '1'},
864 { "gid", 1, NULL, '2'},
865 { "user",1,NULL,'u'},
866 { "username",1,NULL,'u'},
868 { "domain",1,NULL,'d'},
869 { "password",1,NULL,'p'},
870 { "pass",1,NULL,'p'},
871 { "credentials",1,NULL,'c'},
872 { "port",1,NULL,'P'},
873 /* { "uuid",1,NULL,'U'}, */ /* BB unimplemented */
877 int main(int argc, char ** argv)
880 int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
881 char * orgoptions = NULL;
882 char * share_name = NULL;
883 char * ipaddr = NULL;
885 char * mountpoint = NULL;
886 char * options = NULL;
887 char * resolved_path = NULL;
897 int retry = 0; /* set when we have to retry mount with uppercase */
899 struct utsname sysinfo;
900 struct mntent mountent;
903 /* setlocale(LC_ALL, "");
904 bindtextdomain(PACKAGE, LOCALEDIR);
905 textdomain(PACKAGE); */
908 thisprogram = argv[0];
914 if(thisprogram == NULL)
915 thisprogram = "mount.cifs";
918 /* BB add workstation name and domain and pass down */
920 /* #ifdef _GNU_SOURCE
921 printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
924 share_name = argv[1];
925 mountpoint = argv[2];
928 /* add sharename in opts string as unc= parm */
930 while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
931 longopts, NULL)) != -1) {
933 /* No code to do the following options yet */
935 list_with_volumelabel = 1;
938 volumelabel = optarg;
956 "option 'b' (MS_BIND) not supported\n");
964 "option 'm' (MS_MOVE) not supported\n");
968 orgoptions = strdup(optarg);
970 case 'r': /* mount readonly */
980 printf ("mount.cifs version: %s.%s%s\n",
981 MOUNT_CIFS_VERSION_MAJOR,
982 MOUNT_CIFS_VERSION_MINOR,
983 MOUNT_CIFS_VENDOR_SUFFIX);
985 memset(mountpassword,0,64);
992 rsize = atoi(optarg) ;
995 wsize = atoi(optarg);
998 if (isdigit(*optarg)) {
1001 uid = strtoul(optarg, &ep, 10);
1003 printf("bad uid value \"%s\"\n", optarg);
1009 if (!(pw = getpwnam(optarg))) {
1010 printf("bad user name \"%s\"\n", optarg);
1018 if (isdigit(*optarg)) {
1021 gid = strtoul(optarg, &ep, 10);
1023 printf("bad gid value \"%s\"\n", optarg);
1029 if (!(gr = getgrnam(optarg))) {
1030 printf("bad user name \"%s\"\n", optarg);
1042 domain_name = optarg; /* BB fix this - currently ignored */
1046 if(mountpassword == NULL)
1047 mountpassword = (char *)calloc(65,1);
1050 strncpy(mountpassword,optarg,64);
1054 get_password_from_file(0 /* stdin */,NULL);
1059 printf("unknown mount option %c\n",c);
1065 if((argc < 3) || (share_name == NULL) || (mountpoint == NULL)) {
1070 if (getenv("PASSWD")) {
1071 if(mountpassword == NULL)
1072 mountpassword = (char *)calloc(65,1);
1074 strncpy(mountpassword,getenv("PASSWD"),64);
1077 } else if (getenv("PASSWD_FD")) {
1078 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
1079 } else if (getenv("PASSWD_FILE")) {
1080 get_password_from_file(0, getenv("PASSWD_FILE"));
1083 if (orgoptions && parse_options(&orgoptions, &flags)) {
1087 ipaddr = parse_server(&share_name);
1088 if((ipaddr == NULL) && (got_ip == 0)) {
1089 printf("No ip address specified and hostname not found\n");
1094 /* BB save off path and pop after mount returns? */
1095 resolved_path = (char *)malloc(PATH_MAX+1);
1097 /* Note that if we can not canonicalize the name, we get
1098 another chance to see if it is valid when we chdir to it */
1099 if (realpath(mountpoint, resolved_path)) {
1100 mountpoint = resolved_path;
1103 if(chdir(mountpoint)) {
1104 printf("mount error: can not change directory into mount target %s\n",mountpoint);
1109 if(stat (".", &statbuf)) {
1110 printf("mount error: mount point %s does not exist\n",mountpoint);
1115 if (S_ISDIR(statbuf.st_mode) == 0) {
1116 printf("mount error: mount point %s is not a directory\n",mountpoint);
1121 if((getuid() != 0) && (geteuid() == 0)) {
1122 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
1123 #ifndef CIFS_ALLOW_USR_SUID
1124 /* Do not allow user mounts to control suid flag
1125 for mount unless explicitly built that way */
1126 flags |= MS_NOSUID | MS_NODEV;
1129 printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n");
1135 user_name = getusername();
1139 if(got_password == 0) {
1140 mountpassword = getpass("Password: "); /* BB obsolete */
1143 /* FIXME launch daemon (handles dfs name resolution and credential change)
1144 remember to clear parms and overwrite password field before launching */
1147 optlen = strlen(orgoptions);
1152 optlen += strlen(share_name) + 4;
1154 printf("No server share name specified\n");
1155 printf("\nMounting the DFS root for server not implemented yet\n");
1159 optlen += strlen(user_name) + 6;
1161 optlen += strlen(ipaddr) + 4;
1163 optlen += strlen(mountpassword) + 6;
1166 options = (char *)malloc(optlen + 10 + 64 /* space for commas in password */ + 8 /* space for domain= , domain name itself was counted as part of the length username string above */);
1168 if(options == NULL) {
1169 printf("Could not allocate memory for mount options\n");
1175 strncat(options,"unc=",4);
1176 strcat(options,share_name);
1177 /* scan backwards and reverse direction of slash */
1178 temp = strrchr(options, '/');
1179 if(temp > options + 6)
1182 strncat(options,",ip=",4);
1183 strcat(options,ipaddr);
1187 /* check for syntax like user=domain\user */
1189 domain_name = check_for_domain(&user_name);
1190 strncat(options,",user=",6);
1191 strcat(options,user_name);
1195 /* extra length accounted for in option string above */
1196 strncat(options,",domain=",8);
1197 strcat(options,domain_name);
1201 /* Commas have to be doubled, or else they will
1202 look like the parameter separator */
1203 /* if(sep is not set)*/
1205 check_for_comma(&mountpassword);
1206 strncat(options,",pass=",6);
1207 strcat(options,mountpassword);
1210 strncat(options,",ver=",5);
1211 strcat(options,MOUNT_CIFS_VERSION_MAJOR);
1214 strcat(options,",");
1215 strcat(options,orgoptions);
1218 strncat(options,",prefixpath=",12);
1219 strcat(options,prefixpath); /* no need to cat the / */
1222 printf("\nmount.cifs kernel mount options %s \n",options);
1223 if(mount(share_name, mountpoint, "cifs", flags, options)) {
1224 /* remember to kill daemon on error */
1229 printf("mount failed but no error number set\n");
1232 printf("mount error: cifs filesystem not supported by the system\n");
1238 while (*tmp && !(((unsigned char)tmp[0]) & 0x80)) {
1239 *tmp = toupper((unsigned char)*tmp);
1243 printf("retrying with upper case share name\n");
1248 printf("mount error %d = %s\n",errno,strerror(errno));
1250 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
1254 pmntfile = setmntent(MOUNTED, "a+");
1256 mountent.mnt_fsname = share_name;
1257 mountent.mnt_dir = mountpoint;
1258 mountent.mnt_type = CONST_DISCARD(char *,"cifs");
1259 mountent.mnt_opts = (char *)malloc(220);
1260 if(mountent.mnt_opts) {
1261 char * mount_user = getusername();
1262 memset(mountent.mnt_opts,0,200);
1263 if(flags & MS_RDONLY)
1264 strcat(mountent.mnt_opts,"ro");
1266 strcat(mountent.mnt_opts,"rw");
1267 if(flags & MS_MANDLOCK)
1268 strcat(mountent.mnt_opts,",mand");
1269 if(flags & MS_NOEXEC)
1270 strcat(mountent.mnt_opts,",noexec");
1271 if(flags & MS_NOSUID)
1272 strcat(mountent.mnt_opts,",nosuid");
1273 if(flags & MS_NODEV)
1274 strcat(mountent.mnt_opts,",nodev");
1275 if(flags & MS_SYNCHRONOUS)
1276 strcat(mountent.mnt_opts,",synch");
1279 strcat(mountent.mnt_opts,",user=");
1280 strcat(mountent.mnt_opts,mount_user);
1282 /* free(mount_user); do not free static mem */
1285 mountent.mnt_freq = 0;
1286 mountent.mnt_passno = 0;
1287 rc = addmntent(pmntfile,&mountent);
1288 endmntent(pmntfile);
1289 if(mountent.mnt_opts)
1290 free(mountent.mnt_opts);
1292 printf("could not update mount table\n");
1298 int len = strlen(mountpassword);
1299 memset(mountpassword,0,len);
1300 free(mountpassword);
1304 memset(options,0,optlen);
1309 memset(orgoptions,0,orgoptlen);
1313 free(resolved_path);
1316 if(free_share_name) {