r5555: current with 3.0 tree as of r5548; getting ready for 3.0.12pre1
[Samba.git] / source / client / mount.cifs.c
blobd648629f9c31fd59b0f117db3a0d33f8954f8c12
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 <sys/types.h>
28 #include <sys/mount.h>
29 #include <sys/stat.h>
30 #include <sys/utsname.h>
31 #include <sys/socket.h>
32 #include <arpa/inet.h>
33 #include <getopt.h>
34 #include <errno.h>
35 #include <netdb.h>
36 #include <string.h>
37 #include <mntent.h>
38 #include <fcntl.h>
40 #define MOUNT_CIFS_VERSION_MAJOR "1"
41 #define MOUNT_CIFS_VERSION_MINOR "5"
43 #ifndef MOUNT_CIFS_VENDOR_SUFFIX
44 #define MOUNT_CIFS_VENDOR_SUFFIX ""
45 #endif
47 #ifndef MS_MOVE
48 #define MS_MOVE 8192
49 #endif
51 char * thisprogram;
52 int verboseflag = 0;
53 static int got_password = 0;
54 static int got_user = 0;
55 static int got_domain = 0;
56 static int got_ip = 0;
57 static int got_unc = 0;
58 static int got_uid = 0;
59 static int got_gid = 0;
60 static int free_share_name = 0;
61 static char * user_name = NULL;
62 char * mountpassword = NULL;
65 /* BB finish BB
67 cifs_umount
68 open nofollow - avoid symlink exposure?
69 get owner of dir see if matches self or if root
70 call system(umount argv) etc.
72 BB end finish BB */
74 static void mount_cifs_usage(void)
76 printf("\nUsage: %s <remotetarget> <dir> -o <options>\n", thisprogram);
77 printf("\nMount the remote target, specified as a UNC name,");
78 printf(" to a local directory.\n\nOptions:\n");
79 printf("\tuser=<arg>\n\tpass=<arg>\n\tdom=<arg>\n");
80 printf("\nLess commonly used options:");
81 printf("\n\tcredentials=<filename>,guest,perm,noperm,setuids,nosetuids,\n\trw,ro,sep=<char>,iocharset=<codepage>,suid,nosuid,exec,noexec");
82 printf("\n\nOptions not needed for servers supporting CIFS Unix extensions (e.g. most Samba versions):");
83 printf("\n\tuid=<uid>,gid=<gid>,dir_mode=<mode>,file_mode=<mode>");
84 printf("\n\nRarely used options:");
85 printf("\n\tport=<tcpport>,rsize=<size>,wsize=<size>,unc=<unc_name>,ip=<ip_address>,dev,nodev");
86 printf("\n\nOptions are described in more detail in the manual page");
87 printf("\n\tman 8 mount.cifs\n");
88 printf("\nTo display the version number of the mount helper:");
89 printf("\n\t%s -V\n",thisprogram);
91 if(mountpassword) {
92 memset(mountpassword,0,64);
93 free(mountpassword);
95 exit(1);
98 /* caller frees username if necessary */
99 static char * getusername(void) {
100 char *username = NULL;
101 struct passwd *password = getpwuid(getuid());
103 if (password) {
104 username = password->pw_name;
106 return username;
109 char * parse_cifs_url(char * unc_name)
111 printf("\nMounting cifs URL not implemented yet. Attempt to mount %s\n",unc_name);
112 return NULL;
115 static int open_cred_file(char * file_name)
117 char * line_buf;
118 char * temp_val;
119 FILE * fs;
120 int i, length;
121 fs = fopen(file_name,"r");
122 if(fs == NULL)
123 return errno;
124 line_buf = malloc(4096);
125 if(line_buf == NULL)
126 return -ENOMEM;
128 while(fgets(line_buf,4096,fs)) {
129 /* parse line from credential file */
131 /* eat leading white space */
132 for(i=0;i<4086;i++) {
133 if((line_buf[i] != ' ') && (line_buf[i] != '\t'))
134 break;
135 /* if whitespace - skip past it */
137 if (strncasecmp("username",line_buf+i,8) == 0) {
138 temp_val = strchr(line_buf + i,'=');
139 if(temp_val) {
140 /* go past equals sign */
141 temp_val++;
142 for(length = 0;length<4087;length++) {
143 if(temp_val[length] == '\n')
144 break;
146 if(length > 4086) {
147 printf("mount.cifs failed due to malformed username in credentials file");
148 memset(line_buf,0,4096);
149 if(mountpassword) {
150 memset(mountpassword,0,64);
152 exit(1);
153 } else {
154 got_user = 1;
155 user_name = calloc(1 + length,1);
156 /* BB adding free of user_name string before exit,
157 not really necessary but would be cleaner */
158 strncpy(user_name,temp_val, length);
161 } else if (strncasecmp("password",line_buf+i,8) == 0) {
162 temp_val = strchr(line_buf+i,'=');
163 if(temp_val) {
164 /* go past equals sign */
165 temp_val++;
166 for(length = 0;length<65;length++) {
167 if(temp_val[length] == '\n')
168 break;
170 if(length > 64) {
171 printf("mount.cifs failed: password in credentials file too long\n");
172 memset(line_buf,0, 4096);
173 if(mountpassword) {
174 memset(mountpassword,0,64);
176 exit(1);
177 } else {
178 if(mountpassword == NULL) {
179 mountpassword = calloc(65,1);
180 } else
181 memset(mountpassword,0,64);
182 if(mountpassword) {
183 /* BB add handling for commas in password here */
184 strncpy(mountpassword,temp_val,length);
185 got_password = 1;
191 fclose(fs);
192 if(line_buf) {
193 memset(line_buf,0,4096);
194 free(line_buf);
196 return 0;
199 static int get_password_from_file(int file_descript, char * filename)
201 int rc = 0;
202 int i;
203 char c;
205 if(mountpassword == NULL)
206 mountpassword = calloc(65,1);
207 else
208 memset(mountpassword, 0, 64);
210 if(filename != NULL) {
211 file_descript = open(filename, O_RDONLY);
212 if(file_descript < 0) {
213 printf("mount.cifs failed. %s attempting to open password file %s\n",
214 strerror(errno),filename);
215 exit(1);
218 /* else file already open and fd provided */
220 for(i=0;i<64;i++) {
221 rc = read(file_descript,&c,1);
222 if(rc < 0) {
223 printf("mount.cifs failed. Error %s reading password file\n",strerror(errno));
224 memset(mountpassword,0,64);
225 if(filename != NULL)
226 close(file_descript);
227 exit(1);
228 } else if(rc == 0) {
229 if(mountpassword[0] == 0) {
230 if(verboseflag)
231 printf("\nWarning: null password used since cifs password file empty");
233 break;
234 } else /* read valid character */ {
235 if((c == 0) || (c == '\n')) {
236 break;
237 } else
238 mountpassword[i] = c;
241 if((i == 64) && (verboseflag)) {
242 printf("\nWarning: password longer than 64 characters specified in cifs password file");
244 got_password = 1;
245 if(filename != NULL) {
246 close(file_descript);
249 return rc;
252 static int parse_options(char * options, int * filesys_flags)
254 char * data;
255 char * percent_char = NULL;
256 char * value = NULL;
257 char * next_keyword = NULL;
258 int rc = 0;
260 if (!options)
261 return 1;
262 else
263 data = options;
265 if(verboseflag)
266 printf("\n parsing options: %s", options);
268 /* while ((data = strsep(&options, ",")) != NULL) { */
269 while(data != NULL) {
270 /* check if ends with trailing comma */
271 if(*data == 0)
272 break;
274 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
275 /* data = next keyword */
276 /* value = next value ie stuff after equal sign */
278 next_keyword = strchr(data,',');
280 /* temporarily null terminate end of keyword=value pair */
281 if(next_keyword)
282 *next_keyword = 0;
284 /* if (!*data)
285 continue; */
287 /* temporarily null terminate keyword to make keyword and value distinct */
288 if ((value = strchr(data, '=')) != NULL) {
289 *value = '\0';
290 value++;
293 if (strncmp(data, "users",5) == 0) {
294 if(!value || !*value) {
295 strncpy(data,",,,,,",5);
297 } else if (strncmp(data, "user", 4) == 0) {
298 if (!value || !*value) {
299 if(data[4] == '\0') {
300 if(verboseflag)
301 printf("\nskipping empty user mount parameter\n");
302 /* remove the parm since it would otherwise be confusing
303 to the kernel code which would think it was a real username */
304 data[0] = ',';
305 data[1] = ',';
306 data[2] = ',';
307 data[3] = ',';
308 /* BB remove it from mount line so as not to confuse kernel code */
309 } else {
310 printf("username specified with no parameter\n");
311 return 1; /* needs_arg; */
313 } else {
314 if (strnlen(value, 260) < 260) {
315 got_user=1;
316 percent_char = strchr(value,'%');
317 if(percent_char) {
318 *percent_char = ',';
319 if(mountpassword == NULL)
320 mountpassword = calloc(65,1);
321 if(mountpassword) {
322 if(got_password)
323 printf("\nmount.cifs warning - password specified twice\n");
324 got_password = 1;
325 percent_char++;
326 strncpy(mountpassword, percent_char,64);
327 /* remove password from username */
328 while(*percent_char != 0) {
329 *percent_char = ',';
330 percent_char++;
334 } else {
335 printf("username too long\n");
336 return 1;
339 } else if (strncmp(data, "pass", 4) == 0) {
340 if (!value || !*value) {
341 if(got_password) {
342 printf("\npassword specified twice, ignoring second\n");
343 } else
344 got_password = 1;
345 } else if (strnlen(value, 17) < 17) {
346 if(got_password)
347 printf("\nmount.cifs warning - password specified twice\n");
348 got_password = 1;
349 } else {
350 printf("password too long\n");
351 return 1;
353 } else if (strncmp(data, "ip", 2) == 0) {
354 if (!value || !*value) {
355 printf("target ip address argument missing");
356 } else if (strnlen(value, 35) < 35) {
357 if(verboseflag)
358 printf("ip address %s override specified\n",value);
359 got_ip = 1;
360 } else {
361 printf("ip address too long\n");
362 return 1;
364 } else if ((strncmp(data, "unc", 3) == 0)
365 || (strncmp(data, "target", 6) == 0)
366 || (strncmp(data, "path", 4) == 0)) {
367 if (!value || !*value) {
368 printf("invalid path to network resource\n");
369 return 1; /* needs_arg; */
370 } else if(strnlen(value,5) < 5) {
371 printf("UNC name too short");
374 if (strnlen(value, 300) < 300) {
375 got_unc = 1;
376 if (strncmp(value, "//", 2) == 0) {
377 if(got_unc)
378 printf("unc name specified twice, ignoring second\n");
379 else
380 got_unc = 1;
381 } else if (strncmp(value, "\\\\", 2) != 0) {
382 printf("UNC Path does not begin with // or \\\\ \n");
383 return 1;
384 } else {
385 if(got_unc)
386 printf("unc name specified twice, ignoring second\n");
387 else
388 got_unc = 1;
390 } else {
391 printf("CIFS: UNC name too long\n");
392 return 1;
394 } else if ((strncmp(data, "domain", 3) == 0)
395 || (strncmp(data, "workgroup", 5) == 0)) {
396 if (!value || !*value) {
397 printf("CIFS: invalid domain name\n");
398 return 1; /* needs_arg; */
400 if (strnlen(value, 65) < 65) {
401 got_domain = 1;
402 } else {
403 printf("domain name too long\n");
404 return 1;
406 } else if (strncmp(data, "cred", 4) == 0) {
407 if (value && *value) {
408 rc = open_cred_file(value);
409 if(rc) {
410 printf("error %d opening credential file %s\n",rc, value);
411 return 1;
413 } else {
414 printf("invalid credential file name specified\n");
415 return 1;
417 } else if (strncmp(data, "uid", 3) == 0) {
418 if (value && *value) {
419 got_uid = 1;
421 } else if (strncmp(data, "gid", 3) == 0) {
422 if (value && *value) {
423 got_gid = 1;
425 /* fmask and dmask synonyms for people used to smbfs syntax */
426 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
427 if (!value || !*value) {
428 printf ("Option '%s' requires a numerical argument\n", data);
429 return 1;
432 if (value[0] != '0') {
433 printf ("WARNING: '%s' not expressed in octal.\n", data);
436 if (strcmp (data, "fmask") == 0) {
437 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
438 data = "file_mode"; /* BB fix this */
440 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
441 if (!value || !*value) {
442 printf ("Option '%s' requires a numerical argument\n", data);
443 return 1;
446 if (value[0] != '0') {
447 printf ("WARNING: '%s' not expressed in octal.\n", data);
450 if (strcmp (data, "dmask") == 0) {
451 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
452 data = "dir_mode";
454 /* the following eight mount options should be
455 stripped out from what is passed into the kernel
456 since these eight options are best passed as the
457 mount flags rather than redundantly to the kernel
458 and could generate spurious warnings depending on the
459 level of the corresponding cifs vfs kernel code */
460 } else if (strncmp(data, "nosuid", 6) == 0) {
461 *filesys_flags |= MS_NOSUID;
462 } else if (strncmp(data, "suid", 4) == 0) {
463 *filesys_flags &= ~MS_NOSUID;
464 } else if (strncmp(data, "nodev", 5) == 0) {
465 *filesys_flags |= MS_NODEV;
466 } else if (strncmp(data, "dev", 3) == 0) {
467 *filesys_flags &= ~MS_NODEV;
468 } else if (strncmp(data, "noexec", 6) == 0) {
469 *filesys_flags |= MS_NOEXEC;
470 } else if (strncmp(data, "exec", 4) == 0) {
471 *filesys_flags &= ~MS_NOEXEC;
472 } else if (strncmp(data, "guest", 5) == 0) {
473 got_password=1;
474 /* remove the parm since it would otherwise be logged by kern */
475 data[0] = ',';
476 data[1] = ',';
477 data[2] = ',';
478 data[3] = ',';
479 data[4] = ',';
480 } else if (strncmp(data, "ro", 2) == 0) {
481 *filesys_flags |= MS_RDONLY;
482 } else if (strncmp(data, "rw", 2) == 0) {
483 *filesys_flags &= ~MS_RDONLY;
484 } /* else if (strnicmp(data, "port", 4) == 0) {
485 if (value && *value) {
486 vol->port =
487 simple_strtoul(value, &value, 0);
489 } else if (strnicmp(data, "rsize", 5) == 0) {
490 if (value && *value) {
491 vol->rsize =
492 simple_strtoul(value, &value, 0);
494 } else if (strnicmp(data, "wsize", 5) == 0) {
495 if (value && *value) {
496 vol->wsize =
497 simple_strtoul(value, &value, 0);
499 } else if (strnicmp(data, "version", 3) == 0) {
500 } else {
501 printf("CIFS: Unknown mount option %s\n",data);
502 } */ /* nothing to do on those four mount options above.
503 Just pass to kernel and ignore them here */
505 /* move to next option */
506 data = next_keyword+1;
508 /* put overwritten equals sign back */
509 if(value) {
510 value--;
511 *value = '=';
514 /* put previous overwritten comma back */
515 if(next_keyword)
516 *next_keyword = ',';
517 else
518 data = NULL;
520 return 0;
523 /* Note that caller frees the returned buffer if necessary */
524 char * parse_server(char ** punc_name)
526 char * unc_name = *punc_name;
527 int length = strnlen(unc_name,1024);
528 char * share;
529 char * ipaddress_string = NULL;
530 struct hostent * host_entry;
531 struct in_addr server_ipaddr;
532 int rc;
534 if(length > 1023) {
535 printf("mount error: UNC name too long");
536 return NULL;
538 if (strncasecmp("cifs://",unc_name,7) == 0)
539 return parse_cifs_url(unc_name+7);
540 if (strncasecmp("smb://",unc_name,6) == 0) {
541 return parse_cifs_url(unc_name+6);
544 if(length < 3) {
545 /* BB add code to find DFS root here */
546 printf("\nMounting the DFS root for domain not implemented yet");
547 return NULL;
548 } else {
549 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
550 /* check for nfs syntax ie server:share */
551 share = strchr(unc_name,':');
552 if(share) {
553 free_share_name = 1;
554 *punc_name = malloc(length+3);
555 *share = '/';
556 strncpy((*punc_name)+2,unc_name,length);
557 unc_name = *punc_name;
558 unc_name[length+2] = 0;
559 goto continue_unc_parsing;
560 } else {
561 printf("mount error: improperly formatted UNC name.");
562 printf(" %s does not begin with \\\\ or //\n",unc_name);
563 return NULL;
565 } else {
566 continue_unc_parsing:
567 unc_name[0] = '/';
568 unc_name[1] = '/';
569 unc_name += 2;
570 if ((share = strchr(unc_name, '/')) ||
571 (share = strchr(unc_name,'\\'))) {
572 *share = 0; /* temporarily terminate the string */
573 share += 1;
574 if(got_ip == 0) {
575 host_entry = gethostbyname(unc_name);
577 *(share - 1) = '/'; /* put the slash back */
578 if(got_ip) {
579 if(verboseflag)
580 printf("ip address specified explicitly\n");
581 return NULL;
583 if(host_entry == NULL) {
584 printf("mount error: could not find target server. TCP name %s not found ", unc_name);
585 printf(" rc = %d\n",rc);
586 return NULL;
587 } else {
588 /* BB should we pass an alternate version of the share name as Unicode */
589 /* BB what about ipv6? BB */
590 /* BB add retries with alternate servers in list */
592 memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
594 ipaddress_string = inet_ntoa(server_ipaddr);
595 if(ipaddress_string == NULL) {
596 printf("mount error: could not get valid ip address for target server\n");
597 return NULL;
599 return ipaddress_string;
601 } else {
602 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
603 printf("Mounting the DFS root for a particular server not implemented yet\n");
604 return NULL;
610 static struct option longopts[] = {
611 { "all", 0, NULL, 'a' },
612 { "help",0, NULL, 'h' },
613 { "move",0, NULL, 'm' },
614 { "bind",0, NULL, 'b' },
615 { "read-only", 0, NULL, 'r' },
616 { "ro", 0, NULL, 'r' },
617 { "verbose", 0, NULL, 'v' },
618 { "version", 0, NULL, 'V' },
619 { "read-write", 0, NULL, 'w' },
620 { "rw", 0, NULL, 'w' },
621 { "options", 1, NULL, 'o' },
622 { "type", 1, NULL, 't' },
623 { "rsize",1, NULL, 'R' },
624 { "wsize",1, NULL, 'W' },
625 { "uid", 1, NULL, '1'},
626 { "gid", 1, NULL, '2'},
627 { "user",1,NULL,'u'},
628 { "username",1,NULL,'u'},
629 { "dom",1,NULL,'d'},
630 { "domain",1,NULL,'d'},
631 { "password",1,NULL,'p'},
632 { "pass",1,NULL,'p'},
633 { "credentials",1,NULL,'c'},
634 { "port",1,NULL,'P'},
635 /* { "uuid",1,NULL,'U'}, */ /* BB unimplemented */
636 { NULL, 0, NULL, 0 }
639 int main(int argc, char ** argv)
641 int c;
642 int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
643 char * orgoptions = NULL;
644 char * share_name = NULL;
645 char * domain_name = NULL;
646 char * ipaddr = NULL;
647 char * uuid = NULL;
648 char * mountpoint;
649 char * options;
650 char * resolved_path;
651 char * temp;
652 int rc;
653 int rsize = 0;
654 int wsize = 0;
655 int nomtab = 0;
656 int uid = 0;
657 int gid = 0;
658 int optlen = 0;
659 int orgoptlen = 0;
660 struct stat statbuf;
661 struct utsname sysinfo;
662 struct mntent mountent;
663 FILE * pmntfile;
665 /* setlocale(LC_ALL, "");
666 bindtextdomain(PACKAGE, LOCALEDIR);
667 textdomain(PACKAGE); */
669 if(argc && argv) {
670 thisprogram = argv[0];
672 if(thisprogram == NULL)
673 thisprogram = "mount.cifs";
675 uname(&sysinfo);
676 /* BB add workstation name and domain and pass down */
678 /* #ifdef _GNU_SOURCE
679 printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
680 #endif */
682 share_name = argv[1];
683 mountpoint = argv[2];
685 /* add sharename in opts string as unc= parm */
687 while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
688 longopts, NULL)) != -1) {
689 switch (c) {
690 /* No code to do the following options yet */
691 /* case 'l':
692 list_with_volumelabel = 1;
693 break;
694 case 'L':
695 volumelabel = optarg;
696 break; */
697 /* case 'a':
698 ++mount_all;
699 break; */
701 case '?':
702 case 'h': /* help */
703 mount_cifs_usage ();
704 exit(1);
705 case 'n':
706 ++nomtab;
707 break;
708 case 'b':
709 flags |= MS_BIND;
710 break;
711 case 'm':
712 flags |= MS_MOVE;
713 break;
714 case 'o':
715 orgoptions = strdup(optarg);
716 break;
717 case 'r': /* mount readonly */
718 flags |= MS_RDONLY;
719 break;
720 case 'U':
721 uuid = optarg;
722 break;
723 case 'v':
724 ++verboseflag;
725 break;
726 case 'V':
727 printf ("mount.cifs version: %s.%s%s\n",
728 MOUNT_CIFS_VERSION_MAJOR,
729 MOUNT_CIFS_VERSION_MINOR,
730 MOUNT_CIFS_VENDOR_SUFFIX);
731 if(mountpassword) {
732 memset(mountpassword,0,64);
734 exit (0);
735 case 'w':
736 flags &= ~MS_RDONLY;
737 break;
738 case 'R':
739 rsize = atoi(optarg) ;
740 break;
741 case 'W':
742 wsize = atoi(optarg);
743 break;
744 case '1':
745 uid = atoi(optarg);
746 break;
747 case '2':
748 gid = atoi(optarg);
749 break;
750 case 'u':
751 got_user = 1;
752 user_name = optarg;
753 break;
754 case 'd':
755 domain_name = optarg;
756 break;
757 case 'p':
758 if(mountpassword == NULL)
759 mountpassword = calloc(65,1);
760 if(mountpassword) {
761 got_password = 1;
762 strncpy(mountpassword,optarg,64);
764 break;
765 case 'S':
766 get_password_from_file(0 /* stdin */,NULL);
767 break;
768 case 't':
769 break;
770 default:
771 printf("unknown mount option %c\n",c);
772 mount_cifs_usage();
773 exit(1);
777 if(argc < 3)
778 mount_cifs_usage();
780 if (getenv("PASSWD")) {
781 if(mountpassword == NULL)
782 mountpassword = calloc(65,1);
783 if(mountpassword) {
784 strncpy(mountpassword,getenv("PASSWD"),64);
785 got_password = 1;
787 } else if (getenv("PASSWD_FD")) {
788 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
789 } else if (getenv("PASSWD_FILE")) {
790 get_password_from_file(0, getenv("PASSWD_FILE"));
793 if (orgoptions && parse_options(orgoptions, &flags))
794 return -1;
796 ipaddr = parse_server(&share_name);
797 if((ipaddr == NULL) && (got_ip == 0)) {
798 printf("No ip address specified and hostname not found\n");
799 return -1;
803 /* BB save off path and pop after mount returns? */
804 resolved_path = malloc(PATH_MAX+1);
805 if(resolved_path) {
806 /* Note that if we can not canonicalize the name, we get
807 another chance to see if it is valid when we chdir to it */
808 if (realpath(mountpoint, resolved_path)) {
809 mountpoint = resolved_path;
812 if(chdir(mountpoint)) {
813 printf("mount error: can not change directory into mount target %s\n",mountpoint);
814 return -1;
817 if(stat (".", &statbuf)) {
818 printf("mount error: mount point %s does not exist\n",mountpoint);
819 return -1;
822 if (S_ISDIR(statbuf.st_mode) == 0) {
823 printf("mount error: mount point %s is not a directory\n",mountpoint);
824 return -1;
827 if((getuid() != 0) && (geteuid() == 0)) {
828 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
829 #ifndef CIFS_ALLOW_USR_SUID
830 /* Do not allow user mounts to control suid flag
831 for mount unless explicitly built that way */
832 flags |= MS_NOSUID | MS_NODEV;
833 #endif
834 } else {
835 printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n");
836 return -1;
840 if(got_user == 0)
841 user_name = getusername();
843 if(got_password == 0) {
844 mountpassword = getpass("Password: "); /* BB obsolete */
845 got_password = 1;
847 /* FIXME launch daemon (handles dfs name resolution and credential change)
848 remember to clear parms and overwrite password field before launching */
849 if(orgoptions) {
850 optlen = strlen(orgoptions);
851 orgoptlen = optlen;
852 } else
853 optlen = 0;
854 if(share_name)
855 optlen += strlen(share_name) + 4;
856 if(user_name)
857 optlen += strlen(user_name) + 6;
858 if(ipaddr)
859 optlen += strlen(ipaddr) + 4;
860 if(mountpassword)
861 optlen += strlen(mountpassword) + 6;
862 options = malloc(optlen + 10);
864 if(options == NULL) {
865 printf("Could not allocate memory for mount options\n");
866 return -1;
870 options[0] = 0;
871 strncat(options,"unc=",4);
872 strcat(options,share_name);
873 /* scan backwards and reverse direction of slash */
874 temp = strrchr(options, '/');
875 if(temp > options + 6)
876 *temp = '\\';
877 if(ipaddr) {
878 strncat(options,",ip=",4);
879 strcat(options,ipaddr);
881 if(user_name) {
882 strncat(options,",user=",6);
883 strcat(options,user_name);
885 if(mountpassword) {
886 strncat(options,",pass=",6);
887 strcat(options,mountpassword);
889 strncat(options,",ver=",5);
890 strcat(options,MOUNT_CIFS_VERSION_MAJOR);
892 if(orgoptions) {
893 strcat(options,",");
894 strcat(options,orgoptions);
896 if(verboseflag)
897 printf("\nmount.cifs kernel mount options %s \n",options);
898 if(mount(share_name, mountpoint, "cifs", flags, options)) {
899 /* remember to kill daemon on error */
900 switch (errno) {
901 case 0:
902 printf("mount failed but no error number set\n");
903 break;
904 case ENODEV:
905 printf("mount error: cifs filesystem not supported by the system\n");
906 break;
907 default:
908 printf("mount error %d = %s\n",errno,strerror(errno));
910 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
911 if(mountpassword) {
912 memset(mountpassword,0,64);
914 return -1;
915 } else {
916 pmntfile = setmntent(MOUNTED, "a+");
917 if(pmntfile) {
918 mountent.mnt_fsname = share_name;
919 mountent.mnt_dir = mountpoint;
920 mountent.mnt_type = "cifs";
921 mountent.mnt_opts = malloc(220);
922 if(mountent.mnt_opts) {
923 char * mount_user = getusername();
924 memset(mountent.mnt_opts,0,200);
925 if(flags & MS_RDONLY)
926 strcat(mountent.mnt_opts,"ro");
927 else
928 strcat(mountent.mnt_opts,"rw");
929 if(flags & MS_MANDLOCK)
930 strcat(mountent.mnt_opts,",mand");
931 else
932 strcat(mountent.mnt_opts,",nomand");
933 if(flags & MS_NOEXEC)
934 strcat(mountent.mnt_opts,",noexec");
935 if(flags & MS_NOSUID)
936 strcat(mountent.mnt_opts,",nosuid");
937 if(flags & MS_NODEV)
938 strcat(mountent.mnt_opts,",nodev");
939 if(flags & MS_SYNCHRONOUS)
940 strcat(mountent.mnt_opts,",synch");
941 if(mount_user) {
942 if(getuid() != 0) {
943 strcat(mountent.mnt_opts,",user=");
944 strcat(mountent.mnt_opts,mount_user);
946 free(mount_user);
949 mountent.mnt_freq = 0;
950 mountent.mnt_passno = 0;
951 rc = addmntent(pmntfile,&mountent);
952 endmntent(pmntfile);
953 if(mountent.mnt_opts)
954 free(mountent.mnt_opts);
955 } else {
956 printf("could not update mount table\n");
959 if(mountpassword) {
960 memset(mountpassword,0,64);
961 free(mountpassword);
964 if(options) {
965 memset(options,0,optlen);
966 free(options);
969 if(orgoptions) {
970 memset(orgoptions,0,orgoptlen);
971 free(orgoptions);
973 if(resolved_path) {
974 free(resolved_path);
977 if(free_share_name) {
978 free(share_name);
980 return 0;