r5739: sync for 3.0.12rc1 (current with SAMBA_3_0 r5738)
[Samba.git] / source / client / mount.cifs.c
blob7b30b98fa7b30d454b4e813131e7cb785cf20253
1 /*
2 Mount helper utility for Linux CIFS VFS (virtual filesystem) client
3 Copyright (C) 2003 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. */
19 #ifndef _GNU_SOURCE
20 #define _GNU_SOURCE
21 #endif
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <unistd.h>
26 #include <pwd.h>
27 #include <ctype.h>
28 #include <sys/types.h>
29 #include <sys/mount.h>
30 #include <sys/stat.h>
31 #include <sys/utsname.h>
32 #include <sys/socket.h>
33 #include <arpa/inet.h>
34 #include <getopt.h>
35 #include <errno.h>
36 #include <netdb.h>
37 #include <string.h>
38 #include <mntent.h>
39 #include <fcntl.h>
41 #define MOUNT_CIFS_VERSION_MAJOR "1"
42 #define MOUNT_CIFS_VERSION_MINOR "6"
44 #ifndef MOUNT_CIFS_VENDOR_SUFFIX
45 #define MOUNT_CIFS_VENDOR_SUFFIX ""
46 #endif
48 #ifndef MS_MOVE
49 #define MS_MOVE 8192
50 #endif
52 char * thisprogram;
53 int verboseflag = 0;
54 static int got_password = 0;
55 static int got_user = 0;
56 static int got_domain = 0;
57 static int got_ip = 0;
58 static int got_unc = 0;
59 static int got_uid = 0;
60 static int got_gid = 0;
61 static int free_share_name = 0;
62 static char * user_name = NULL;
63 char * mountpassword = NULL;
66 /* BB finish BB
68 cifs_umount
69 open nofollow - avoid symlink exposure?
70 get owner of dir see if matches self or if root
71 call system(umount argv) etc.
73 BB end finish BB */
75 static void mount_cifs_usage(void)
77 printf("\nUsage: %s <remotetarget> <dir> -o <options>\n", thisprogram);
78 printf("\nMount the remote target, specified as a UNC name,");
79 printf(" to a local directory.\n\nOptions:\n");
80 printf("\tuser=<arg>\n\tpass=<arg>\n\tdom=<arg>\n");
81 printf("\nLess commonly used options:");
82 printf("\n\tcredentials=<filename>,guest,perm,noperm,setuids,nosetuids,\n\trw,ro,sep=<char>,iocharset=<codepage>,suid,nosuid,exec,noexec,directio");
83 printf("\n\nOptions not needed for servers supporting CIFS Unix extensions (e.g. most Samba versions):");
84 printf("\n\tuid=<uid>,gid=<gid>,dir_mode=<mode>,file_mode=<mode>");
85 printf("\n\nRarely used options:");
86 printf("\n\tport=<tcpport>,rsize=<size>,wsize=<size>,unc=<unc_name>,ip=<ip_address>,dev,nodev");
87 printf("\n\nOptions are described in more detail in the manual page");
88 printf("\n\tman 8 mount.cifs\n");
89 printf("\nTo display the version number of the mount helper:");
90 printf("\n\t%s -V\n",thisprogram);
92 if(mountpassword) {
93 memset(mountpassword,0,64);
94 free(mountpassword);
96 exit(1);
99 /* caller frees username if necessary */
100 static char * getusername(void) {
101 char *username = NULL;
102 struct passwd *password = getpwuid(getuid());
104 if (password) {
105 username = password->pw_name;
107 return username;
110 char * parse_cifs_url(char * unc_name)
112 printf("\nMounting cifs URL not implemented yet. Attempt to mount %s\n",unc_name);
113 return NULL;
116 static int open_cred_file(char * file_name)
118 char * line_buf;
119 char * temp_val;
120 FILE * fs;
121 int i, length;
122 fs = fopen(file_name,"r");
123 if(fs == NULL)
124 return errno;
125 line_buf = malloc(4096);
126 if(line_buf == NULL)
127 return -ENOMEM;
129 while(fgets(line_buf,4096,fs)) {
130 /* parse line from credential file */
132 /* eat leading white space */
133 for(i=0;i<4086;i++) {
134 if((line_buf[i] != ' ') && (line_buf[i] != '\t'))
135 break;
136 /* if whitespace - skip past it */
138 if (strncasecmp("username",line_buf+i,8) == 0) {
139 temp_val = strchr(line_buf + i,'=');
140 if(temp_val) {
141 /* go past equals sign */
142 temp_val++;
143 for(length = 0;length<4087;length++) {
144 if(temp_val[length] == '\n')
145 break;
147 if(length > 4086) {
148 printf("mount.cifs failed due to malformed username in credentials file");
149 memset(line_buf,0,4096);
150 if(mountpassword) {
151 memset(mountpassword,0,64);
153 exit(1);
154 } else {
155 got_user = 1;
156 user_name = calloc(1 + length,1);
157 /* BB adding free of user_name string before exit,
158 not really necessary but would be cleaner */
159 strncpy(user_name,temp_val, length);
162 } else if (strncasecmp("password",line_buf+i,8) == 0) {
163 temp_val = strchr(line_buf+i,'=');
164 if(temp_val) {
165 /* go past equals sign */
166 temp_val++;
167 for(length = 0;length<65;length++) {
168 if(temp_val[length] == '\n')
169 break;
171 if(length > 64) {
172 printf("mount.cifs failed: password in credentials file too long\n");
173 memset(line_buf,0, 4096);
174 if(mountpassword) {
175 memset(mountpassword,0,64);
177 exit(1);
178 } else {
179 if(mountpassword == NULL) {
180 mountpassword = calloc(65,1);
181 } else
182 memset(mountpassword,0,64);
183 if(mountpassword) {
184 /* BB add handling for commas in password here */
185 strncpy(mountpassword,temp_val,length);
186 got_password = 1;
192 fclose(fs);
193 if(line_buf) {
194 memset(line_buf,0,4096);
195 free(line_buf);
197 return 0;
200 static int get_password_from_file(int file_descript, char * filename)
202 int rc = 0;
203 int i;
204 char c;
206 if(mountpassword == NULL)
207 mountpassword = calloc(65,1);
208 else
209 memset(mountpassword, 0, 64);
211 if(filename != NULL) {
212 file_descript = open(filename, O_RDONLY);
213 if(file_descript < 0) {
214 printf("mount.cifs failed. %s attempting to open password file %s\n",
215 strerror(errno),filename);
216 exit(1);
219 /* else file already open and fd provided */
221 for(i=0;i<64;i++) {
222 rc = read(file_descript,&c,1);
223 if(rc < 0) {
224 printf("mount.cifs failed. Error %s reading password file\n",strerror(errno));
225 memset(mountpassword,0,64);
226 if(filename != NULL)
227 close(file_descript);
228 exit(1);
229 } else if(rc == 0) {
230 if(mountpassword[0] == 0) {
231 if(verboseflag)
232 printf("\nWarning: null password used since cifs password file empty");
234 break;
235 } else /* read valid character */ {
236 if((c == 0) || (c == '\n')) {
237 break;
238 } else
239 mountpassword[i] = c;
242 if((i == 64) && (verboseflag)) {
243 printf("\nWarning: password longer than 64 characters specified in cifs password file");
245 got_password = 1;
246 if(filename != NULL) {
247 close(file_descript);
250 return rc;
253 static int parse_options(char * options, int * filesys_flags)
255 char * data;
256 char * percent_char = NULL;
257 char * value = NULL;
258 char * next_keyword = NULL;
259 int rc = 0;
261 if (!options)
262 return 1;
263 else
264 data = options;
266 if(verboseflag)
267 printf("\n parsing options: %s", options);
269 /* while ((data = strsep(&options, ",")) != NULL) { */
270 while(data != NULL) {
271 /* check if ends with trailing comma */
272 if(*data == 0)
273 break;
275 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
276 /* data = next keyword */
277 /* value = next value ie stuff after equal sign */
279 next_keyword = strchr(data,',');
281 /* temporarily null terminate end of keyword=value pair */
282 if(next_keyword)
283 *next_keyword = 0;
285 /* if (!*data)
286 continue; */
288 /* temporarily null terminate keyword to make keyword and value distinct */
289 if ((value = strchr(data, '=')) != NULL) {
290 *value = '\0';
291 value++;
294 if (strncmp(data, "users",5) == 0) {
295 if(!value || !*value) {
296 strncpy(data,",,,,,",5);
298 } else if (strncmp(data, "user_xattr",10) == 0) {
299 /* do nothing - need to skip so not parsed as user name */
300 } else if (strncmp(data, "user", 4) == 0) {
301 if (!value || !*value) {
302 if(data[4] == '\0') {
303 if(verboseflag)
304 printf("\nskipping empty user mount parameter\n");
305 /* remove the parm since it would otherwise be confusing
306 to the kernel code which would think it was a real username */
307 data[0] = ',';
308 data[1] = ',';
309 data[2] = ',';
310 data[3] = ',';
311 /* BB remove it from mount line so as not to confuse kernel code */
312 } else {
313 printf("username specified with no parameter\n");
314 return 1; /* needs_arg; */
316 } else {
317 if (strnlen(value, 260) < 260) {
318 got_user=1;
319 percent_char = strchr(value,'%');
320 if(percent_char) {
321 *percent_char = ',';
322 if(mountpassword == NULL)
323 mountpassword = calloc(65,1);
324 if(mountpassword) {
325 if(got_password)
326 printf("\nmount.cifs warning - password specified twice\n");
327 got_password = 1;
328 percent_char++;
329 strncpy(mountpassword, percent_char,64);
330 /* remove password from username */
331 while(*percent_char != 0) {
332 *percent_char = ',';
333 percent_char++;
337 } else {
338 printf("username too long\n");
339 return 1;
342 } else if (strncmp(data, "pass", 4) == 0) {
343 if (!value || !*value) {
344 if(got_password) {
345 printf("\npassword specified twice, ignoring second\n");
346 } else
347 got_password = 1;
348 } else if (strnlen(value, 17) < 17) {
349 if(got_password)
350 printf("\nmount.cifs warning - password specified twice\n");
351 got_password = 1;
352 } else {
353 printf("password too long\n");
354 return 1;
356 } else if (strncmp(data, "ip", 2) == 0) {
357 if (!value || !*value) {
358 printf("target ip address argument missing");
359 } else if (strnlen(value, 35) < 35) {
360 if(verboseflag)
361 printf("ip address %s override specified\n",value);
362 got_ip = 1;
363 } else {
364 printf("ip address too long\n");
365 return 1;
367 } else if ((strncmp(data, "unc", 3) == 0)
368 || (strncmp(data, "target", 6) == 0)
369 || (strncmp(data, "path", 4) == 0)) {
370 if (!value || !*value) {
371 printf("invalid path to network resource\n");
372 return 1; /* needs_arg; */
373 } else if(strnlen(value,5) < 5) {
374 printf("UNC name too short");
377 if (strnlen(value, 300) < 300) {
378 got_unc = 1;
379 if (strncmp(value, "//", 2) == 0) {
380 if(got_unc)
381 printf("unc name specified twice, ignoring second\n");
382 else
383 got_unc = 1;
384 } else if (strncmp(value, "\\\\", 2) != 0) {
385 printf("UNC Path does not begin with // or \\\\ \n");
386 return 1;
387 } else {
388 if(got_unc)
389 printf("unc name specified twice, ignoring second\n");
390 else
391 got_unc = 1;
393 } else {
394 printf("CIFS: UNC name too long\n");
395 return 1;
397 } else if ((strncmp(data, "domain", 3) == 0)
398 || (strncmp(data, "workgroup", 5) == 0)) {
399 if (!value || !*value) {
400 printf("CIFS: invalid domain name\n");
401 return 1; /* needs_arg; */
403 if (strnlen(value, 65) < 65) {
404 got_domain = 1;
405 } else {
406 printf("domain name too long\n");
407 return 1;
409 } else if (strncmp(data, "cred", 4) == 0) {
410 if (value && *value) {
411 rc = open_cred_file(value);
412 if(rc) {
413 printf("error %d opening credential file %s\n",rc, value);
414 return 1;
416 } else {
417 printf("invalid credential file name specified\n");
418 return 1;
420 } else if (strncmp(data, "uid", 3) == 0) {
421 if (value && *value) {
422 got_uid = 1;
424 } else if (strncmp(data, "gid", 3) == 0) {
425 if (value && *value) {
426 got_gid = 1;
428 /* fmask and dmask synonyms for people used to smbfs syntax */
429 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
430 if (!value || !*value) {
431 printf ("Option '%s' requires a numerical argument\n", data);
432 return 1;
435 if (value[0] != '0') {
436 printf ("WARNING: '%s' not expressed in octal.\n", data);
439 if (strcmp (data, "fmask") == 0) {
440 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
441 data = "file_mode"; /* BB fix this */
443 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
444 if (!value || !*value) {
445 printf ("Option '%s' requires a numerical argument\n", data);
446 return 1;
449 if (value[0] != '0') {
450 printf ("WARNING: '%s' not expressed in octal.\n", data);
453 if (strcmp (data, "dmask") == 0) {
454 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
455 data = "dir_mode";
457 /* the following eight mount options should be
458 stripped out from what is passed into the kernel
459 since these eight options are best passed as the
460 mount flags rather than redundantly to the kernel
461 and could generate spurious warnings depending on the
462 level of the corresponding cifs vfs kernel code */
463 } else if (strncmp(data, "nosuid", 6) == 0) {
464 *filesys_flags |= MS_NOSUID;
465 } else if (strncmp(data, "suid", 4) == 0) {
466 *filesys_flags &= ~MS_NOSUID;
467 } else if (strncmp(data, "nodev", 5) == 0) {
468 *filesys_flags |= MS_NODEV;
469 } else if (strncmp(data, "dev", 3) == 0) {
470 *filesys_flags &= ~MS_NODEV;
471 } else if (strncmp(data, "noexec", 6) == 0) {
472 *filesys_flags |= MS_NOEXEC;
473 } else if (strncmp(data, "exec", 4) == 0) {
474 *filesys_flags &= ~MS_NOEXEC;
475 } else if (strncmp(data, "guest", 5) == 0) {
476 got_password=1;
477 /* remove the parm since it would otherwise be logged by kern */
478 data[0] = ',';
479 data[1] = ',';
480 data[2] = ',';
481 data[3] = ',';
482 data[4] = ',';
483 } else if (strncmp(data, "ro", 2) == 0) {
484 *filesys_flags |= MS_RDONLY;
485 } else if (strncmp(data, "rw", 2) == 0) {
486 *filesys_flags &= ~MS_RDONLY;
487 } /* else if (strnicmp(data, "port", 4) == 0) {
488 if (value && *value) {
489 vol->port =
490 simple_strtoul(value, &value, 0);
492 } else if (strnicmp(data, "rsize", 5) == 0) {
493 if (value && *value) {
494 vol->rsize =
495 simple_strtoul(value, &value, 0);
497 } else if (strnicmp(data, "wsize", 5) == 0) {
498 if (value && *value) {
499 vol->wsize =
500 simple_strtoul(value, &value, 0);
502 } else if (strnicmp(data, "version", 3) == 0) {
503 } else {
504 printf("CIFS: Unknown mount option %s\n",data);
505 } */ /* nothing to do on those four mount options above.
506 Just pass to kernel and ignore them here */
508 /* move to next option */
509 data = next_keyword+1;
511 /* put overwritten equals sign back */
512 if(value) {
513 value--;
514 *value = '=';
517 /* put previous overwritten comma back */
518 if(next_keyword)
519 *next_keyword = ',';
520 else
521 data = NULL;
523 return 0;
526 /* Note that caller frees the returned buffer if necessary */
527 char * parse_server(char ** punc_name)
529 char * unc_name = *punc_name;
530 int length = strnlen(unc_name,1024);
531 char * share;
532 char * ipaddress_string = NULL;
533 struct hostent * host_entry;
534 struct in_addr server_ipaddr;
535 int rc;
537 if(length > 1023) {
538 printf("mount error: UNC name too long");
539 return NULL;
541 if (strncasecmp("cifs://",unc_name,7) == 0)
542 return parse_cifs_url(unc_name+7);
543 if (strncasecmp("smb://",unc_name,6) == 0) {
544 return parse_cifs_url(unc_name+6);
547 if(length < 3) {
548 /* BB add code to find DFS root here */
549 printf("\nMounting the DFS root for domain not implemented yet");
550 return NULL;
551 } else {
552 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
553 /* check for nfs syntax ie server:share */
554 share = strchr(unc_name,':');
555 if(share) {
556 free_share_name = 1;
557 *punc_name = malloc(length+3);
558 *share = '/';
559 strncpy((*punc_name)+2,unc_name,length);
560 unc_name = *punc_name;
561 unc_name[length+2] = 0;
562 goto continue_unc_parsing;
563 } else {
564 printf("mount error: improperly formatted UNC name.");
565 printf(" %s does not begin with \\\\ or //\n",unc_name);
566 return NULL;
568 } else {
569 continue_unc_parsing:
570 unc_name[0] = '/';
571 unc_name[1] = '/';
572 unc_name += 2;
573 if ((share = strchr(unc_name, '/')) ||
574 (share = strchr(unc_name,'\\'))) {
575 *share = 0; /* temporarily terminate the string */
576 share += 1;
577 if(got_ip == 0) {
578 host_entry = gethostbyname(unc_name);
580 *(share - 1) = '/'; /* put the slash back */
581 if(got_ip) {
582 if(verboseflag)
583 printf("ip address specified explicitly\n");
584 return NULL;
586 if(host_entry == NULL) {
587 printf("mount error: could not find target server. TCP name %s not found ", unc_name);
588 printf(" rc = %d\n",rc);
589 return NULL;
590 } else {
591 /* BB should we pass an alternate version of the share name as Unicode */
592 /* BB what about ipv6? BB */
593 /* BB add retries with alternate servers in list */
595 memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
597 ipaddress_string = inet_ntoa(server_ipaddr);
598 if(ipaddress_string == NULL) {
599 printf("mount error: could not get valid ip address for target server\n");
600 return NULL;
602 return ipaddress_string;
604 } else {
605 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
606 printf("Mounting the DFS root for a particular server not implemented yet\n");
607 return NULL;
613 static struct option longopts[] = {
614 { "all", 0, NULL, 'a' },
615 { "help",0, NULL, 'h' },
616 { "move",0, NULL, 'm' },
617 { "bind",0, NULL, 'b' },
618 { "read-only", 0, NULL, 'r' },
619 { "ro", 0, NULL, 'r' },
620 { "verbose", 0, NULL, 'v' },
621 { "version", 0, NULL, 'V' },
622 { "read-write", 0, NULL, 'w' },
623 { "rw", 0, NULL, 'w' },
624 { "options", 1, NULL, 'o' },
625 { "type", 1, NULL, 't' },
626 { "rsize",1, NULL, 'R' },
627 { "wsize",1, NULL, 'W' },
628 { "uid", 1, NULL, '1'},
629 { "gid", 1, NULL, '2'},
630 { "user",1,NULL,'u'},
631 { "username",1,NULL,'u'},
632 { "dom",1,NULL,'d'},
633 { "domain",1,NULL,'d'},
634 { "password",1,NULL,'p'},
635 { "pass",1,NULL,'p'},
636 { "credentials",1,NULL,'c'},
637 { "port",1,NULL,'P'},
638 /* { "uuid",1,NULL,'U'}, */ /* BB unimplemented */
639 { NULL, 0, NULL, 0 }
642 int main(int argc, char ** argv)
644 int c;
645 int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
646 char * orgoptions = NULL;
647 char * share_name = NULL;
648 char * domain_name = NULL;
649 char * ipaddr = NULL;
650 char * uuid = NULL;
651 char * mountpoint;
652 char * options;
653 char * resolved_path;
654 char * temp;
655 int rc;
656 int rsize = 0;
657 int wsize = 0;
658 int nomtab = 0;
659 int uid = 0;
660 int gid = 0;
661 int optlen = 0;
662 int orgoptlen = 0;
663 int retry = 0; /* set when we have to retry mount with uppercase */
664 struct stat statbuf;
665 struct utsname sysinfo;
666 struct mntent mountent;
667 FILE * pmntfile;
669 /* setlocale(LC_ALL, "");
670 bindtextdomain(PACKAGE, LOCALEDIR);
671 textdomain(PACKAGE); */
673 if(argc && argv) {
674 thisprogram = argv[0];
676 if(thisprogram == NULL)
677 thisprogram = "mount.cifs";
679 uname(&sysinfo);
680 /* BB add workstation name and domain and pass down */
682 /* #ifdef _GNU_SOURCE
683 printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
684 #endif */
686 share_name = argv[1];
687 mountpoint = argv[2];
689 /* add sharename in opts string as unc= parm */
691 while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
692 longopts, NULL)) != -1) {
693 switch (c) {
694 /* No code to do the following options yet */
695 /* case 'l':
696 list_with_volumelabel = 1;
697 break;
698 case 'L':
699 volumelabel = optarg;
700 break; */
701 /* case 'a':
702 ++mount_all;
703 break; */
705 case '?':
706 case 'h': /* help */
707 mount_cifs_usage ();
708 exit(1);
709 case 'n':
710 ++nomtab;
711 break;
712 case 'b':
713 flags |= MS_BIND;
714 break;
715 case 'm':
716 flags |= MS_MOVE;
717 break;
718 case 'o':
719 orgoptions = strdup(optarg);
720 break;
721 case 'r': /* mount readonly */
722 flags |= MS_RDONLY;
723 break;
724 case 'U':
725 uuid = optarg;
726 break;
727 case 'v':
728 ++verboseflag;
729 break;
730 case 'V':
731 printf ("mount.cifs version: %s.%s%s\n",
732 MOUNT_CIFS_VERSION_MAJOR,
733 MOUNT_CIFS_VERSION_MINOR,
734 MOUNT_CIFS_VENDOR_SUFFIX);
735 if(mountpassword) {
736 memset(mountpassword,0,64);
738 exit (0);
739 case 'w':
740 flags &= ~MS_RDONLY;
741 break;
742 case 'R':
743 rsize = atoi(optarg) ;
744 break;
745 case 'W':
746 wsize = atoi(optarg);
747 break;
748 case '1':
749 uid = atoi(optarg);
750 break;
751 case '2':
752 gid = atoi(optarg);
753 break;
754 case 'u':
755 got_user = 1;
756 user_name = optarg;
757 break;
758 case 'd':
759 domain_name = optarg;
760 break;
761 case 'p':
762 if(mountpassword == NULL)
763 mountpassword = calloc(65,1);
764 if(mountpassword) {
765 got_password = 1;
766 strncpy(mountpassword,optarg,64);
768 break;
769 case 'S':
770 get_password_from_file(0 /* stdin */,NULL);
771 break;
772 case 't':
773 break;
774 default:
775 printf("unknown mount option %c\n",c);
776 mount_cifs_usage();
777 exit(1);
781 if(argc < 3)
782 mount_cifs_usage();
784 if (getenv("PASSWD")) {
785 if(mountpassword == NULL)
786 mountpassword = calloc(65,1);
787 if(mountpassword) {
788 strncpy(mountpassword,getenv("PASSWD"),64);
789 got_password = 1;
791 } else if (getenv("PASSWD_FD")) {
792 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
793 } else if (getenv("PASSWD_FILE")) {
794 get_password_from_file(0, getenv("PASSWD_FILE"));
797 if (orgoptions && parse_options(orgoptions, &flags))
798 return -1;
800 ipaddr = parse_server(&share_name);
801 if((ipaddr == NULL) && (got_ip == 0)) {
802 printf("No ip address specified and hostname not found\n");
803 return -1;
807 /* BB save off path and pop after mount returns? */
808 resolved_path = malloc(PATH_MAX+1);
809 if(resolved_path) {
810 /* Note that if we can not canonicalize the name, we get
811 another chance to see if it is valid when we chdir to it */
812 if (realpath(mountpoint, resolved_path)) {
813 mountpoint = resolved_path;
816 if(chdir(mountpoint)) {
817 printf("mount error: can not change directory into mount target %s\n",mountpoint);
818 return -1;
821 if(stat (".", &statbuf)) {
822 printf("mount error: mount point %s does not exist\n",mountpoint);
823 return -1;
826 if (S_ISDIR(statbuf.st_mode) == 0) {
827 printf("mount error: mount point %s is not a directory\n",mountpoint);
828 return -1;
831 if((getuid() != 0) && (geteuid() == 0)) {
832 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
833 #ifndef CIFS_ALLOW_USR_SUID
834 /* Do not allow user mounts to control suid flag
835 for mount unless explicitly built that way */
836 flags |= MS_NOSUID | MS_NODEV;
837 #endif
838 } else {
839 printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n");
840 return -1;
844 if(got_user == 0)
845 user_name = getusername();
847 if(got_password == 0) {
848 mountpassword = getpass("Password: "); /* BB obsolete */
849 got_password = 1;
851 /* FIXME launch daemon (handles dfs name resolution and credential change)
852 remember to clear parms and overwrite password field before launching */
853 mount_retry:
854 if(orgoptions) {
855 optlen = strlen(orgoptions);
856 orgoptlen = optlen;
857 } else
858 optlen = 0;
859 if(share_name)
860 optlen += strlen(share_name) + 4;
861 if(user_name)
862 optlen += strlen(user_name) + 6;
863 if(ipaddr)
864 optlen += strlen(ipaddr) + 4;
865 if(mountpassword)
866 optlen += strlen(mountpassword) + 6;
867 options = malloc(optlen + 10);
869 if(options == NULL) {
870 printf("Could not allocate memory for mount options\n");
871 return -1;
875 options[0] = 0;
876 strncat(options,"unc=",4);
877 strcat(options,share_name);
878 /* scan backwards and reverse direction of slash */
879 temp = strrchr(options, '/');
880 if(temp > options + 6)
881 *temp = '\\';
882 if(ipaddr) {
883 strncat(options,",ip=",4);
884 strcat(options,ipaddr);
886 if(user_name) {
887 strncat(options,",user=",6);
888 strcat(options,user_name);
890 if(mountpassword) {
891 strncat(options,",pass=",6);
892 strcat(options,mountpassword);
894 strncat(options,",ver=",5);
895 strcat(options,MOUNT_CIFS_VERSION_MAJOR);
897 if(orgoptions) {
898 strcat(options,",");
899 strcat(options,orgoptions);
901 if(verboseflag)
902 printf("\nmount.cifs kernel mount options %s \n",options);
903 if(mount(share_name, mountpoint, "cifs", flags, options)) {
904 /* remember to kill daemon on error */
905 char * tmp;
907 switch (errno) {
908 case 0:
909 printf("mount failed but no error number set\n");
910 break;
911 case ENODEV:
912 printf("mount error: cifs filesystem not supported by the system\n");
913 break;
914 case ENXIO:
915 if(retry == 0) {
916 retry = 1;
917 tmp = share_name;
918 while (*tmp && !(((unsigned char)tmp[0]) & 0x80)) {
919 *tmp = toupper((unsigned char)*tmp);
920 tmp++;
922 if(!*tmp) {
923 printf("retrying with upper case share name\n");
924 goto mount_retry;
927 default:
929 printf("mount error %d = %s\n",errno,strerror(errno));
931 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
932 if(mountpassword) {
933 memset(mountpassword,0,64);
935 return -1;
936 } else {
937 pmntfile = setmntent(MOUNTED, "a+");
938 if(pmntfile) {
939 mountent.mnt_fsname = share_name;
940 mountent.mnt_dir = mountpoint;
941 mountent.mnt_type = "cifs";
942 mountent.mnt_opts = malloc(220);
943 if(mountent.mnt_opts) {
944 char * mount_user = getusername();
945 memset(mountent.mnt_opts,0,200);
946 if(flags & MS_RDONLY)
947 strcat(mountent.mnt_opts,"ro");
948 else
949 strcat(mountent.mnt_opts,"rw");
950 if(flags & MS_MANDLOCK)
951 strcat(mountent.mnt_opts,",mand");
952 else
953 strcat(mountent.mnt_opts,",nomand");
954 if(flags & MS_NOEXEC)
955 strcat(mountent.mnt_opts,",noexec");
956 if(flags & MS_NOSUID)
957 strcat(mountent.mnt_opts,",nosuid");
958 if(flags & MS_NODEV)
959 strcat(mountent.mnt_opts,",nodev");
960 if(flags & MS_SYNCHRONOUS)
961 strcat(mountent.mnt_opts,",synch");
962 if(mount_user) {
963 if(getuid() != 0) {
964 strcat(mountent.mnt_opts,",user=");
965 strcat(mountent.mnt_opts,mount_user);
967 free(mount_user);
970 mountent.mnt_freq = 0;
971 mountent.mnt_passno = 0;
972 rc = addmntent(pmntfile,&mountent);
973 endmntent(pmntfile);
974 if(mountent.mnt_opts)
975 free(mountent.mnt_opts);
976 } else {
977 printf("could not update mount table\n");
980 if(mountpassword) {
981 memset(mountpassword,0,64);
982 free(mountpassword);
985 if(options) {
986 memset(options,0,optlen);
987 free(options);
990 if(orgoptions) {
991 memset(orgoptions,0,orgoptlen);
992 free(orgoptions);
994 if(resolved_path) {
995 free(resolved_path);
998 if(free_share_name) {
999 free(share_name);
1001 return 0;