port cifsmount to buildroot-ng
[openwrt/svn-archive/archive.git] / utils / cifsmount / mount.cifs.c
1 /*
2 Mount helper utility for Linux CIFS VFS (virtual filesystem) client
3 Copyright (C) 2003 Steve French (sfrench@us.ibm.com)
4
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.
9
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.
14
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. */
18
19 #ifndef _GNU_SOURCE
20 #define _GNU_SOURCE
21 #endif
22
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>
39
40 #define MOUNT_CIFS_VERSION_MAJOR "1"
41 #define MOUNT_CIFS_VERSION_MINOR "5"
42
43 #ifndef MOUNT_CIFS_VENDOR_SUFFIX
44 #define MOUNT_CIFS_VENDOR_SUFFIX ""
45 #endif
46
47 #ifndef MS_MOVE
48 #define MS_MOVE 8192
49 #endif
50
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;
63
64
65 /* BB finish BB
66
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.
71
72 BB end finish BB */
73
74 static void mount_cifs_usage(void)
75 {
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);
90
91 if(mountpassword) {
92 memset(mountpassword,0,64);
93 free(mountpassword);
94 }
95 exit(1);
96 }
97
98 /* caller frees username if necessary */
99 static char * getusername(void) {
100 char *username = NULL;
101 struct passwd *password = getpwuid(getuid());
102
103 if (password) {
104 username = password->pw_name;
105 }
106 return username;
107 }
108
109 char * parse_cifs_url(char * unc_name)
110 {
111 printf("\nMounting cifs URL not implemented yet. Attempt to mount %s\n",unc_name);
112 return NULL;
113 }
114
115 static int open_cred_file(char * file_name)
116 {
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;
127
128 while(fgets(line_buf,4096,fs)) {
129 /* parse line from credential file */
130
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 */
136 }
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;
145 }
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);
151 }
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);
159 }
160 }
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;
169 }
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);
175 }
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;
186 }
187 }
188 }
189 }
190 }
191 fclose(fs);
192 if(line_buf) {
193 memset(line_buf,0,4096);
194 free(line_buf);
195 }
196 return 0;
197 }
198
199 static int get_password_from_file(int file_descript, char * filename)
200 {
201 int rc = 0;
202 int i;
203 char c;
204
205 if(mountpassword == NULL)
206 mountpassword = calloc(65,1);
207 else
208 memset(mountpassword, 0, 64);
209
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);
216 }
217 }
218 /* else file already open and fd provided */
219
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");
232 }
233 break;
234 } else /* read valid character */ {
235 if((c == 0) || (c == '\n')) {
236 break;
237 } else
238 mountpassword[i] = c;
239 }
240 }
241 if((i == 64) && (verboseflag)) {
242 printf("\nWarning: password longer than 64 characters specified in cifs password file");
243 }
244 got_password = 1;
245 if(filename != NULL) {
246 close(file_descript);
247 }
248
249 return rc;
250 }
251
252 static int parse_options(char * options, int * filesys_flags)
253 {
254 char * data;
255 char * percent_char = NULL;
256 char * value = NULL;
257 char * next_keyword = NULL;
258 int rc = 0;
259
260 if (!options)
261 return 1;
262 else
263 data = options;
264
265 if(verboseflag)
266 printf("\n parsing options: %s", options);
267
268 /* while ((data = strsep(&options, ",")) != NULL) { */
269 while(data != NULL) {
270 /* check if ends with trailing comma */
271 if(*data == 0)
272 break;
273
274 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
275 /* data = next keyword */
276 /* value = next value ie stuff after equal sign */
277
278 next_keyword = strchr(data,',');
279
280 /* temporarily null terminate end of keyword=value pair */
281 if(next_keyword)
282 *next_keyword = 0;
283
284 /* if (!*data)
285 continue; */
286
287 /* temporarily null terminate keyword to make keyword and value distinct */
288 if ((value = strchr(data, '=')) != NULL) {
289 *value = '\0';
290 value++;
291 }
292
293 if (strncmp(data, "user", 4) == 0) {
294 if (!value || !*value) {
295 if(data[4] == '\0') {
296 if(verboseflag)
297 printf("\nskipping empty user mount parameter\n");
298 /* remove the parm since it would otherwise be confusing
299 to the kernel code which would think it was a real username */
300 data[0] = ',';
301 data[1] = ',';
302 data[2] = ',';
303 data[3] = ',';
304 /* BB remove it from mount line so as not to confuse kernel code */
305 } else {
306 printf("username specified with no parameter\n");
307 return 1; /* needs_arg; */
308 }
309 } else {
310 if (strnlen(value, 260) < 260) {
311 got_user=1;
312 percent_char = strchr(value,'%');
313 if(percent_char) {
314 *percent_char = ',';
315 if(mountpassword == NULL)
316 mountpassword = calloc(65,1);
317 if(mountpassword) {
318 if(got_password)
319 printf("\nmount.cifs warning - password specified twice\n");
320 got_password = 1;
321 percent_char++;
322 strncpy(mountpassword, percent_char,64);
323 /* remove password from username */
324 while(*percent_char != 0) {
325 *percent_char = ',';
326 percent_char++;
327 }
328 }
329 }
330 } else {
331 printf("username too long\n");
332 return 1;
333 }
334 }
335 } else if (strncmp(data, "pass", 4) == 0) {
336 if (!value || !*value) {
337 if(got_password) {
338 printf("\npassword specified twice, ignoring second\n");
339 } else
340 got_password = 1;
341 } else if (strnlen(value, 17) < 17) {
342 if(got_password)
343 printf("\nmount.cifs warning - password specified twice\n");
344 got_password = 1;
345 } else {
346 printf("password too long\n");
347 return 1;
348 }
349 } else if (strncmp(data, "ip", 2) == 0) {
350 if (!value || !*value) {
351 printf("target ip address argument missing");
352 } else if (strnlen(value, 35) < 35) {
353 if(verboseflag)
354 printf("ip address %s override specified\n",value);
355 got_ip = 1;
356 } else {
357 printf("ip address too long\n");
358 return 1;
359 }
360 } else if ((strncmp(data, "unc", 3) == 0)
361 || (strncmp(data, "target", 6) == 0)
362 || (strncmp(data, "path", 4) == 0)) {
363 if (!value || !*value) {
364 printf("invalid path to network resource\n");
365 return 1; /* needs_arg; */
366 } else if(strnlen(value,5) < 5) {
367 printf("UNC name too short");
368 }
369
370 if (strnlen(value, 300) < 300) {
371 got_unc = 1;
372 if (strncmp(value, "//", 2) == 0) {
373 if(got_unc)
374 printf("unc name specified twice, ignoring second\n");
375 else
376 got_unc = 1;
377 } else if (strncmp(value, "\\\\", 2) != 0) {
378 printf("UNC Path does not begin with // or \\\\ \n");
379 return 1;
380 } else {
381 if(got_unc)
382 printf("unc name specified twice, ignoring second\n");
383 else
384 got_unc = 1;
385 }
386 } else {
387 printf("CIFS: UNC name too long\n");
388 return 1;
389 }
390 } else if ((strncmp(data, "domain", 3) == 0)
391 || (strncmp(data, "workgroup", 5) == 0)) {
392 if (!value || !*value) {
393 printf("CIFS: invalid domain name\n");
394 return 1; /* needs_arg; */
395 }
396 if (strnlen(value, 65) < 65) {
397 got_domain = 1;
398 } else {
399 printf("domain name too long\n");
400 return 1;
401 }
402 } else if (strncmp(data, "cred", 4) == 0) {
403 if (value && *value) {
404 rc = open_cred_file(value);
405 if(rc) {
406 printf("error %d opening credential file %s\n",rc, value);
407 return 1;
408 }
409 } else {
410 printf("invalid credential file name specified\n");
411 return 1;
412 }
413 } else if (strncmp(data, "uid", 3) == 0) {
414 if (value && *value) {
415 got_uid = 1;
416 }
417 } else if (strncmp(data, "gid", 3) == 0) {
418 if (value && *value) {
419 got_gid = 1;
420 }
421 /* fmask and dmask synonyms for people used to smbfs syntax */
422 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
423 if (!value || !*value) {
424 printf ("Option '%s' requires a numerical argument\n", data);
425 return 1;
426 }
427
428 if (value[0] != '0') {
429 printf ("WARNING: '%s' not expressed in octal.\n", data);
430 }
431
432 if (strcmp (data, "fmask") == 0) {
433 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
434 data = "file_mode"; /* BB fix this */
435 }
436 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
437 if (!value || !*value) {
438 printf ("Option '%s' requires a numerical argument\n", data);
439 return 1;
440 }
441
442 if (value[0] != '0') {
443 printf ("WARNING: '%s' not expressed in octal.\n", data);
444 }
445
446 if (strcmp (data, "dmask") == 0) {
447 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
448 data = "dir_mode";
449 }
450 /* the following eight mount options should be
451 stripped out from what is passed into the kernel
452 since these eight options are best passed as the
453 mount flags rather than redundantly to the kernel
454 and could generate spurious warnings depending on the
455 level of the corresponding cifs vfs kernel code */
456 } else if (strncmp(data, "nosuid", 6) == 0) {
457 *filesys_flags |= MS_NOSUID;
458 } else if (strncmp(data, "suid", 4) == 0) {
459 *filesys_flags &= ~MS_NOSUID;
460 } else if (strncmp(data, "nodev", 5) == 0) {
461 *filesys_flags |= MS_NODEV;
462 } else if (strncmp(data, "dev", 3) == 0) {
463 *filesys_flags &= ~MS_NODEV;
464 } else if (strncmp(data, "noexec", 6) == 0) {
465 *filesys_flags |= MS_NOEXEC;
466 } else if (strncmp(data, "exec", 4) == 0) {
467 *filesys_flags &= ~MS_NOEXEC;
468 } else if (strncmp(data, "guest", 5) == 0) {
469 got_password=1;
470 } else if (strncmp(data, "ro", 2) == 0) {
471 *filesys_flags |= MS_RDONLY;
472 } else if (strncmp(data, "rw", 2) == 0) {
473 *filesys_flags &= ~MS_RDONLY;
474 } /* else if (strnicmp(data, "port", 4) == 0) {
475 if (value && *value) {
476 vol->port =
477 simple_strtoul(value, &value, 0);
478 }
479 } else if (strnicmp(data, "rsize", 5) == 0) {
480 if (value && *value) {
481 vol->rsize =
482 simple_strtoul(value, &value, 0);
483 }
484 } else if (strnicmp(data, "wsize", 5) == 0) {
485 if (value && *value) {
486 vol->wsize =
487 simple_strtoul(value, &value, 0);
488 }
489 } else if (strnicmp(data, "version", 3) == 0) {
490 } else {
491 printf("CIFS: Unknown mount option %s\n",data);
492 } */ /* nothing to do on those four mount options above.
493 Just pass to kernel and ignore them here */
494
495 /* move to next option */
496 data = next_keyword+1;
497
498 /* put overwritten equals sign back */
499 if(value) {
500 value--;
501 *value = '=';
502 }
503
504 /* put previous overwritten comma back */
505 if(next_keyword)
506 *next_keyword = ',';
507 else
508 data = NULL;
509 }
510 return 0;
511 }
512
513 /* Note that caller frees the returned buffer if necessary */
514 char * parse_server(char ** punc_name)
515 {
516 char * unc_name = *punc_name;
517 int length = strnlen(unc_name,1024);
518 char * share;
519 char * ipaddress_string = NULL;
520 struct hostent * host_entry;
521 struct in_addr server_ipaddr;
522 int rc;
523
524 if(length > 1023) {
525 printf("mount error: UNC name too long");
526 return NULL;
527 }
528 if (strncasecmp("cifs://",unc_name,7) == 0)
529 return parse_cifs_url(unc_name+7);
530 if (strncasecmp("smb://",unc_name,6) == 0) {
531 return parse_cifs_url(unc_name+6);
532 }
533
534 if(length < 3) {
535 /* BB add code to find DFS root here */
536 printf("\nMounting the DFS root for domain not implemented yet");
537 return NULL;
538 } else {
539 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
540 /* check for nfs syntax ie server:share */
541 share = strchr(unc_name,':');
542 if(share) {
543 free_share_name = 1;
544 *punc_name = malloc(length+3);
545 *share = '/';
546 strncpy((*punc_name)+2,unc_name,length);
547 unc_name = *punc_name;
548 unc_name[length+2] = 0;
549 goto continue_unc_parsing;
550 } else {
551 printf("mount error: improperly formatted UNC name.");
552 printf(" %s does not begin with \\\\ or //\n",unc_name);
553 return NULL;
554 }
555 } else {
556 continue_unc_parsing:
557 unc_name[0] = '/';
558 unc_name[1] = '/';
559 unc_name += 2;
560 if ((share = strchr(unc_name, '/')) ||
561 (share = strchr(unc_name,'\\'))) {
562 *share = 0; /* temporarily terminate the string */
563 share += 1;
564 if(got_ip == 0) {
565 host_entry = gethostbyname(unc_name);
566 }
567 *(share - 1) = '/'; /* put the slash back */
568 if(got_ip) {
569 if(verboseflag)
570 printf("ip address specified explicitly\n");
571 return NULL;
572 }
573 if(host_entry == NULL) {
574 printf("mount error: could not find target server. TCP name %s not found ", unc_name);
575 printf(" rc = %d\n",rc);
576 return NULL;
577 } else {
578 /* BB should we pass an alternate version of the share name as Unicode */
579 /* BB what about ipv6? BB */
580 /* BB add retries with alternate servers in list */
581
582 memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
583
584 ipaddress_string = inet_ntoa(server_ipaddr);
585 if(ipaddress_string == NULL) {
586 printf("mount error: could not get valid ip address for target server\n");
587 return NULL;
588 }
589 return ipaddress_string;
590 }
591 } else {
592 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
593 printf("Mounting the DFS root for a particular server not implemented yet\n");
594 return NULL;
595 }
596 }
597 }
598 }
599
600 static struct option longopts[] = {
601 { "all", 0, NULL, 'a' },
602 { "help",0, NULL, 'h' },
603 { "move",0, NULL, 'm' },
604 { "bind",0, NULL, 'b' },
605 { "read-only", 0, NULL, 'r' },
606 { "ro", 0, NULL, 'r' },
607 { "verbose", 0, NULL, 'v' },
608 { "version", 0, NULL, 'V' },
609 { "read-write", 0, NULL, 'w' },
610 { "rw", 0, NULL, 'w' },
611 { "options", 1, NULL, 'o' },
612 { "type", 1, NULL, 't' },
613 { "rsize",1, NULL, 'R' },
614 { "wsize",1, NULL, 'W' },
615 { "uid", 1, NULL, '1'},
616 { "gid", 1, NULL, '2'},
617 { "user",1,NULL,'u'},
618 { "username",1,NULL,'u'},
619 { "dom",1,NULL,'d'},
620 { "domain",1,NULL,'d'},
621 { "password",1,NULL,'p'},
622 { "pass",1,NULL,'p'},
623 { "credentials",1,NULL,'c'},
624 { "port",1,NULL,'P'},
625 /* { "uuid",1,NULL,'U'}, */ /* BB unimplemented */
626 { NULL, 0, NULL, 0 }
627 };
628
629 int main(int argc, char ** argv)
630 {
631 int c;
632 int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
633 char * orgoptions = NULL;
634 char * share_name = NULL;
635 char * domain_name = NULL;
636 char * ipaddr = NULL;
637 char * uuid = NULL;
638 char * mountpoint;
639 char * options;
640 char * resolved_path;
641 char * temp;
642 int rc;
643 int rsize = 0;
644 int wsize = 0;
645 int nomtab = 0;
646 int uid = 0;
647 int gid = 0;
648 int optlen = 0;
649 int orgoptlen = 0;
650 struct stat statbuf;
651 struct utsname sysinfo;
652 struct mntent mountent;
653 FILE * pmntfile;
654
655 /* setlocale(LC_ALL, "");
656 bindtextdomain(PACKAGE, LOCALEDIR);
657 textdomain(PACKAGE); */
658
659 if(argc && argv) {
660 thisprogram = argv[0];
661 }
662 if(thisprogram == NULL)
663 thisprogram = "mount.cifs";
664
665 uname(&sysinfo);
666 /* BB add workstation name and domain and pass down */
667
668 /* #ifdef _GNU_SOURCE
669 printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
670 #endif */
671
672 share_name = argv[1];
673 mountpoint = argv[2];
674
675 /* add sharename in opts string as unc= parm */
676
677 while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
678 longopts, NULL)) != -1) {
679 switch (c) {
680 /* No code to do the following options yet */
681 /* case 'l':
682 list_with_volumelabel = 1;
683 break;
684 case 'L':
685 volumelabel = optarg;
686 break; */
687 /* case 'a':
688 ++mount_all;
689 break; */
690
691 case '?':
692 case 'h': /* help */
693 mount_cifs_usage ();
694 exit(1);
695 case 'n':
696 ++nomtab;
697 break;
698 case 'b':
699 flags |= MS_BIND;
700 break;
701 case 'm':
702 flags |= MS_MOVE;
703 break;
704 case 'o':
705 orgoptions = strdup(optarg);
706 break;
707 case 'r': /* mount readonly */
708 flags |= MS_RDONLY;
709 break;
710 case 'U':
711 uuid = optarg;
712 break;
713 case 'v':
714 ++verboseflag;
715 break;
716 case 'V':
717 printf ("mount.cifs version: %s.%s%s\n",
718 MOUNT_CIFS_VERSION_MAJOR,
719 MOUNT_CIFS_VERSION_MINOR,
720 MOUNT_CIFS_VENDOR_SUFFIX);
721 if(mountpassword) {
722 memset(mountpassword,0,64);
723 }
724 exit (0);
725 case 'w':
726 flags &= ~MS_RDONLY;
727 break;
728 case 'R':
729 rsize = atoi(optarg) ;
730 break;
731 case 'W':
732 wsize = atoi(optarg);
733 break;
734 case '1':
735 uid = atoi(optarg);
736 break;
737 case '2':
738 gid = atoi(optarg);
739 break;
740 case 'u':
741 got_user = 1;
742 user_name = optarg;
743 break;
744 case 'd':
745 domain_name = optarg;
746 break;
747 case 'p':
748 if(mountpassword == NULL)
749 mountpassword = calloc(65,1);
750 if(mountpassword) {
751 got_password = 1;
752 strncpy(mountpassword,optarg,64);
753 }
754 break;
755 case 'S':
756 get_password_from_file(0 /* stdin */,NULL);
757 break;
758 case 't':
759 break;
760 default:
761 printf("unknown mount option %c\n",c);
762 mount_cifs_usage();
763 exit(1);
764 }
765 }
766
767 if(argc < 3)
768 mount_cifs_usage();
769
770 if (getenv("PASSWD")) {
771 if(mountpassword == NULL)
772 mountpassword = calloc(65,1);
773 if(mountpassword) {
774 strncpy(mountpassword,getenv("PASSWD"),64);
775 got_password = 1;
776 }
777 } else if (getenv("PASSWD_FD")) {
778 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
779 } else if (getenv("PASSWD_FILE")) {
780 get_password_from_file(0, getenv("PASSWD_FILE"));
781 }
782
783 if (orgoptions && parse_options(orgoptions, &flags))
784 return -1;
785
786 ipaddr = parse_server(&share_name);
787 if((ipaddr == NULL) && (got_ip == 0)) {
788 printf("No ip address specified and hostname not found\n");
789 return -1;
790 }
791
792
793 /* BB save off path and pop after mount returns? */
794 resolved_path = malloc(PATH_MAX+1);
795 if(resolved_path) {
796 /* Note that if we can not canonicalize the name, we get
797 another chance to see if it is valid when we chdir to it */
798 if (realpath(mountpoint, resolved_path)) {
799 mountpoint = resolved_path;
800 }
801 }
802 if(chdir(mountpoint)) {
803 printf("mount error: can not change directory into mount target %s\n",mountpoint);
804 return -1;
805 }
806
807 if(stat (".", &statbuf)) {
808 printf("mount error: mount point %s does not exist\n",mountpoint);
809 return -1;
810 }
811
812 if (S_ISDIR(statbuf.st_mode) == 0) {
813 printf("mount error: mount point %s is not a directory\n",mountpoint);
814 return -1;
815 }
816
817 if((getuid() != 0) && (geteuid() == 0)) {
818 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
819 #ifndef CIFS_ALLOW_USR_SUID
820 /* Do not allow user mounts to control suid flag
821 for mount unless explicitly built that way */
822 flags |= MS_NOSUID | MS_NODEV;
823 #endif
824 } else {
825 printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n");
826 return -1;
827 }
828 }
829
830 if(got_user == 0)
831 user_name = getusername();
832
833 if(got_password == 0) {
834 mountpassword = getpass("Password: "); /* BB obsolete */
835 got_password = 1;
836 }
837 /* FIXME launch daemon (handles dfs name resolution and credential change)
838 remember to clear parms and overwrite password field before launching */
839 if(orgoptions) {
840 optlen = strlen(orgoptions);
841 orgoptlen = optlen;
842 } else
843 optlen = 0;
844 if(share_name)
845 optlen += strlen(share_name) + 4;
846 if(user_name)
847 optlen += strlen(user_name) + 6;
848 if(ipaddr)
849 optlen += strlen(ipaddr) + 4;
850 if(mountpassword)
851 optlen += strlen(mountpassword) + 6;
852 options = malloc(optlen + 10);
853
854 if(options == NULL) {
855 printf("Could not allocate memory for mount options\n");
856 return -1;
857 }
858
859
860 options[0] = 0;
861 strncat(options,"unc=",4);
862 strcat(options,share_name);
863 /* scan backwards and reverse direction of slash */
864 temp = strrchr(options, '/');
865 if(temp > options + 6)
866 *temp = '\\';
867 if(ipaddr) {
868 strncat(options,",ip=",4);
869 strcat(options,ipaddr);
870 }
871 if(user_name) {
872 strncat(options,",user=",6);
873 strcat(options,user_name);
874 }
875 if(mountpassword) {
876 strncat(options,",pass=",6);
877 strcat(options,mountpassword);
878 }
879 strncat(options,",ver=",5);
880 strcat(options,MOUNT_CIFS_VERSION_MAJOR);
881
882 if(orgoptions) {
883 strcat(options,",");
884 strcat(options,orgoptions);
885 }
886 if(verboseflag)
887 printf("\nmount.cifs kernel mount options %s \n",options);
888 if(mount(share_name, mountpoint, "cifs", flags, options)) {
889 /* remember to kill daemon on error */
890 switch (errno) {
891 case 0:
892 printf("mount failed but no error number set\n");
893 break;
894 case ENODEV:
895 printf("mount error: cifs filesystem not supported by the system\n");
896 break;
897 default:
898 printf("mount error %d = %s\n",errno,strerror(errno));
899 }
900 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
901 if(mountpassword) {
902 memset(mountpassword,0,64);
903 }
904 return -1;
905 } else {
906 pmntfile = setmntent(MOUNTED, "a+");
907 if(pmntfile) {
908 mountent.mnt_fsname = share_name;
909 mountent.mnt_dir = mountpoint;
910 mountent.mnt_type = "cifs";
911 mountent.mnt_opts = malloc(220);
912 if(mountent.mnt_opts) {
913 char * mount_user = getusername();
914 memset(mountent.mnt_opts,0,200);
915 if(flags & MS_RDONLY)
916 strcat(mountent.mnt_opts,"ro");
917 else
918 strcat(mountent.mnt_opts,"rw");
919 if(flags & MS_MANDLOCK)
920 strcat(mountent.mnt_opts,",mand");
921 else
922 strcat(mountent.mnt_opts,",nomand");
923 if(flags & MS_NOEXEC)
924 strcat(mountent.mnt_opts,",noexec");
925 if(flags & MS_NOSUID)
926 strcat(mountent.mnt_opts,",nosuid");
927 if(flags & MS_NODEV)
928 strcat(mountent.mnt_opts,",nodev");
929 if(flags & MS_SYNCHRONOUS)
930 strcat(mountent.mnt_opts,",synch");
931 if(mount_user) {
932 if(getuid() != 0) {
933 strcat(mountent.mnt_opts,",user=");
934 strcat(mountent.mnt_opts,mount_user);
935 }
936 free(mount_user);
937 }
938 }
939 mountent.mnt_freq = 0;
940 mountent.mnt_passno = 0;
941 rc = addmntent(pmntfile,&mountent);
942 endmntent(pmntfile);
943 if(mountent.mnt_opts)
944 free(mountent.mnt_opts);
945 } else {
946 printf("could not update mount table\n");
947 }
948 }
949 if(mountpassword) {
950 memset(mountpassword,0,64);
951 free(mountpassword);
952 }
953
954 if(options) {
955 memset(options,0,optlen);
956 free(options);
957 }
958
959 if(orgoptions) {
960 memset(orgoptions,0,orgoptlen);
961 free(orgoptions);
962 }
963 if(resolved_path) {
964 free(resolved_path);
965 }
966
967 if(free_share_name) {
968 free(share_name);
969 }
970 return 0;
971 }
972