r10391: * setting version to 3.0.20a
[Samba.git] / source / client / mount.cifs.c
blob0c3b0b321e803f90d8eca0c863668888f93b2413
1 /*
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. */
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 "9"
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 static char * mountpassword = NULL;
64 char * domain_name = NULL;
67 /* BB finish BB
69 cifs_umount
70 open nofollow - avoid symlink exposure?
71 get owner of dir see if matches self or if root
72 call system(umount argv) etc.
74 BB end finish BB */
76 static char * check_for_domain(char **);
79 static void mount_cifs_usage(void)
81 printf("\nUsage: %s <remotetarget> <dir> -o <options>\n", thisprogram);
82 printf("\nMount the remote target, specified as a UNC name,");
83 printf(" to a local directory.\n\nOptions:\n");
84 printf("\tuser=<arg>\n\tpass=<arg>\n\tdom=<arg>\n");
85 printf("\nLess commonly used options:");
86 printf("\n\tcredentials=<filename>,guest,perm,noperm,setuids,nosetuids,rw,ro,\n\tsep=<char>,iocharset=<codepage>,suid,nosuid,exec,noexec,serverino,\n\tdirectio,mapchars,nomapchars");
87 printf("\n\nOptions not needed for servers supporting CIFS Unix extensions\n\t(e.g. most Samba versions):");
88 printf("\n\tuid=<uid>,gid=<gid>,dir_mode=<mode>,file_mode=<mode>");
89 printf("\n\nRarely used options:");
90 printf("\n\tport=<tcpport>,rsize=<size>,wsize=<size>,unc=<unc_name>,ip=<ip_address>,\n\tdev,nodev,nouser_xattr,netbiosname,hard,soft,intr,nointr,noacl");
91 printf("\n\nOptions are described in more detail in the manual page");
92 printf("\n\tman 8 mount.cifs\n");
93 printf("\nTo display the version number of the mount helper:");
94 printf("\n\t%s -V\n",thisprogram);
96 if(mountpassword) {
97 memset(mountpassword,0,64);
98 free(mountpassword);
100 exit(1);
103 /* caller frees username if necessary */
104 static char * getusername(void) {
105 char *username = NULL;
106 struct passwd *password = getpwuid(getuid());
108 if (password) {
109 username = password->pw_name;
111 return username;
114 static char * parse_cifs_url(char * unc_name)
116 printf("\nMounting cifs URL not implemented yet. Attempt to mount %s\n",unc_name);
117 return NULL;
120 static int open_cred_file(char * file_name)
122 char * line_buf;
123 char * temp_val;
124 FILE * fs;
125 int i, length;
126 fs = fopen(file_name,"r");
127 if(fs == NULL)
128 return errno;
129 line_buf = malloc(4096);
130 if(line_buf == NULL) {
131 fclose(fs);
132 return -ENOMEM;
135 while(fgets(line_buf,4096,fs)) {
136 /* parse line from credential file */
138 /* eat leading white space */
139 for(i=0;i<4086;i++) {
140 if((line_buf[i] != ' ') && (line_buf[i] != '\t'))
141 break;
142 /* if whitespace - skip past it */
144 if (strncasecmp("username",line_buf+i,8) == 0) {
145 temp_val = strchr(line_buf + i,'=');
146 if(temp_val) {
147 /* go past equals sign */
148 temp_val++;
149 for(length = 0;length<4087;length++) {
150 if(temp_val[length] == '\n')
151 break;
153 if(length > 4086) {
154 printf("mount.cifs failed due to malformed username in credentials file");
155 memset(line_buf,0,4096);
156 if(mountpassword) {
157 memset(mountpassword,0,64);
159 exit(1);
160 } else {
161 got_user = 1;
162 user_name = calloc(1 + length,1);
163 /* BB adding free of user_name string before exit,
164 not really necessary but would be cleaner */
165 strncpy(user_name,temp_val, length);
168 } else if (strncasecmp("password",line_buf+i,8) == 0) {
169 temp_val = strchr(line_buf+i,'=');
170 if(temp_val) {
171 /* go past equals sign */
172 temp_val++;
173 for(length = 0;length<65;length++) {
174 if(temp_val[length] == '\n')
175 break;
177 if(length > 64) {
178 printf("mount.cifs failed: password in credentials file too long\n");
179 memset(line_buf,0, 4096);
180 if(mountpassword) {
181 memset(mountpassword,0,64);
183 exit(1);
184 } else {
185 if(mountpassword == NULL) {
186 mountpassword = calloc(65,1);
187 } else
188 memset(mountpassword,0,64);
189 if(mountpassword) {
190 strncpy(mountpassword,temp_val,length);
191 got_password = 1;
195 } else if (strncasecmp("domain",line_buf+i,6) == 0) {
196 temp_val = strchr(line_buf+i,'=');
197 if(temp_val) {
198 /* go past equals sign */
199 temp_val++;
200 if(verboseflag)
201 printf("\nDomain %s\n",temp_val);
202 for(length = 0;length<65;length++) {
203 if(temp_val[length] == '\n')
204 break;
206 if(length > 64) {
207 printf("mount.cifs failed: domain in credentials file too long\n");
208 if(mountpassword) {
209 memset(mountpassword,0,64);
211 exit(1);
212 } else {
213 if(domain_name == NULL) {
214 domain_name = calloc(65,1);
215 } else
216 memset(domain_name,0,64);
217 if(domain_name) {
218 strncpy(domain_name,temp_val,length);
219 got_domain = 1;
226 fclose(fs);
227 if(line_buf) {
228 memset(line_buf,0,4096);
229 free(line_buf);
231 return 0;
234 static int get_password_from_file(int file_descript, char * filename)
236 int rc = 0;
237 int i;
238 char c;
240 if(mountpassword == NULL)
241 mountpassword = calloc(65,1);
242 else
243 memset(mountpassword, 0, 64);
245 if(filename != NULL) {
246 file_descript = open(filename, O_RDONLY);
247 if(file_descript < 0) {
248 printf("mount.cifs failed. %s attempting to open password file %s\n",
249 strerror(errno),filename);
250 exit(1);
253 /* else file already open and fd provided */
255 for(i=0;i<64;i++) {
256 rc = read(file_descript,&c,1);
257 if(rc < 0) {
258 printf("mount.cifs failed. Error %s reading password file\n",strerror(errno));
259 memset(mountpassword,0,64);
260 if(filename != NULL)
261 close(file_descript);
262 exit(1);
263 } else if(rc == 0) {
264 if(mountpassword[0] == 0) {
265 if(verboseflag)
266 printf("\nWarning: null password used since cifs password file empty");
268 break;
269 } else /* read valid character */ {
270 if((c == 0) || (c == '\n')) {
271 break;
272 } else
273 mountpassword[i] = c;
276 if((i == 64) && (verboseflag)) {
277 printf("\nWarning: password longer than 64 characters specified in cifs password file");
279 got_password = 1;
280 if(filename != NULL) {
281 close(file_descript);
284 return rc;
287 static int parse_options(char * options, int * filesys_flags)
289 char * data;
290 char * percent_char = NULL;
291 char * value = NULL;
292 char * next_keyword = NULL;
293 int rc = 0;
295 if (!options)
296 return 1;
297 else
298 data = options;
300 if(verboseflag)
301 printf("parsing options: %s\n", options);
303 /* BB fixme check for separator override BB */
305 /* while ((data = strsep(&options, ",")) != NULL) { */
306 while(data != NULL) {
307 /* check if ends with trailing comma */
308 if(*data == 0)
309 break;
311 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
312 /* data = next keyword */
313 /* value = next value ie stuff after equal sign */
315 next_keyword = strchr(data,','); /* BB handle sep= */
317 /* temporarily null terminate end of keyword=value pair */
318 if(next_keyword)
319 *next_keyword = 0;
321 /* temporarily null terminate keyword to make keyword and value distinct */
322 if ((value = strchr(data, '=')) != NULL) {
323 *value = '\0';
324 value++;
327 if (strncmp(data, "users",5) == 0) {
328 if(!value || !*value) {
329 strncpy(data,",,,,,",5);
331 } else if (strncmp(data, "user_xattr",10) == 0) {
332 /* do nothing - need to skip so not parsed as user name */
333 } else if (strncmp(data, "user", 4) == 0) {
335 if (!value || !*value) {
336 if(data[4] == '\0') {
337 if(verboseflag)
338 printf("\nskipping empty user mount parameter\n");
339 /* remove the parm since it would otherwise be confusing
340 to the kernel code which would think it was a real username */
341 data[0] = ',';
342 data[1] = ',';
343 data[2] = ',';
344 data[3] = ',';
345 } else {
346 printf("username specified with no parameter\n");
347 return 1; /* needs_arg; */
349 } else {
350 if (strnlen(value, 260) < 260) {
351 got_user=1;
352 percent_char = strchr(value,'%');
353 if(percent_char) {
354 *percent_char = ',';
355 if(mountpassword == NULL)
356 mountpassword = calloc(65,1);
357 if(mountpassword) {
358 if(got_password)
359 printf("\nmount.cifs warning - password specified twice\n");
360 got_password = 1;
361 percent_char++;
362 strncpy(mountpassword, percent_char,64);
363 /* remove password from username */
364 while(*percent_char != 0) {
365 *percent_char = ',';
366 percent_char++;
370 /* this is only case in which the user
371 name buf is not malloc - so we have to
372 check for domain name embedded within
373 the user name here since the later
374 call to check_for_domain will not be
375 invoked */
376 domain_name = check_for_domain(&value);
377 } else {
378 printf("username too long\n");
379 return 1;
382 } else if (strncmp(data, "pass", 4) == 0) {
383 if (!value || !*value) {
384 if(got_password) {
385 printf("\npassword specified twice, ignoring second\n");
386 } else
387 got_password = 1;
388 } else if (strnlen(value, 17) < 17) {
389 if(got_password)
390 printf("\nmount.cifs warning - password specified twice\n");
391 got_password = 1;
392 } else {
393 printf("password too long\n");
394 return 1;
396 } else if (strncmp(data, "ip", 2) == 0) {
397 if (!value || !*value) {
398 printf("target ip address argument missing");
399 } else if (strnlen(value, 35) < 35) {
400 if(verboseflag)
401 printf("ip address %s override specified\n",value);
402 got_ip = 1;
403 } else {
404 printf("ip address too long\n");
405 return 1;
407 } else if ((strncmp(data, "unc", 3) == 0)
408 || (strncmp(data, "target", 6) == 0)
409 || (strncmp(data, "path", 4) == 0)) {
410 if (!value || !*value) {
411 printf("invalid path to network resource\n");
412 return 1; /* needs_arg; */
413 } else if(strnlen(value,5) < 5) {
414 printf("UNC name too short");
417 if (strnlen(value, 300) < 300) {
418 got_unc = 1;
419 if (strncmp(value, "//", 2) == 0) {
420 if(got_unc)
421 printf("unc name specified twice, ignoring second\n");
422 else
423 got_unc = 1;
424 } else if (strncmp(value, "\\\\", 2) != 0) {
425 printf("UNC Path does not begin with // or \\\\ \n");
426 return 1;
427 } else {
428 if(got_unc)
429 printf("unc name specified twice, ignoring second\n");
430 else
431 got_unc = 1;
433 } else {
434 printf("CIFS: UNC name too long\n");
435 return 1;
437 } else if ((strncmp(data, "domain", 3) == 0)
438 || (strncmp(data, "workgroup", 5) == 0)) {
439 if (!value || !*value) {
440 printf("CIFS: invalid domain name\n");
441 return 1; /* needs_arg; */
443 if (strnlen(value, 65) < 65) {
444 got_domain = 1;
445 } else {
446 printf("domain name too long\n");
447 return 1;
449 } else if (strncmp(data, "cred", 4) == 0) {
450 if (value && *value) {
451 rc = open_cred_file(value);
452 if(rc) {
453 printf("error %d opening credential file %s\n",rc, value);
454 return 1;
456 } else {
457 printf("invalid credential file name specified\n");
458 return 1;
460 } else if (strncmp(data, "uid", 3) == 0) {
461 if (value && *value) {
462 got_uid = 1;
464 } else if (strncmp(data, "gid", 3) == 0) {
465 if (value && *value) {
466 got_gid = 1;
468 /* fmask and dmask synonyms for people used to smbfs syntax */
469 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
470 if (!value || !*value) {
471 printf ("Option '%s' requires a numerical argument\n", data);
472 return 1;
475 if (value[0] != '0') {
476 printf ("WARNING: '%s' not expressed in octal.\n", data);
479 if (strcmp (data, "fmask") == 0) {
480 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
481 data = "file_mode"; /* BB fix this */
483 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
484 if (!value || !*value) {
485 printf ("Option '%s' requires a numerical argument\n", data);
486 return 1;
489 if (value[0] != '0') {
490 printf ("WARNING: '%s' not expressed in octal.\n", data);
493 if (strcmp (data, "dmask") == 0) {
494 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
495 data = "dir_mode";
497 /* the following eight mount options should be
498 stripped out from what is passed into the kernel
499 since these eight options are best passed as the
500 mount flags rather than redundantly to the kernel
501 and could generate spurious warnings depending on the
502 level of the corresponding cifs vfs kernel code */
503 } else if (strncmp(data, "nosuid", 6) == 0) {
504 *filesys_flags |= MS_NOSUID;
505 } else if (strncmp(data, "suid", 4) == 0) {
506 *filesys_flags &= ~MS_NOSUID;
507 } else if (strncmp(data, "nodev", 5) == 0) {
508 *filesys_flags |= MS_NODEV;
509 } else if (strncmp(data, "dev", 3) == 0) {
510 *filesys_flags &= ~MS_NODEV;
511 } else if (strncmp(data, "noexec", 6) == 0) {
512 *filesys_flags |= MS_NOEXEC;
513 } else if (strncmp(data, "exec", 4) == 0) {
514 *filesys_flags &= ~MS_NOEXEC;
515 } else if (strncmp(data, "guest", 5) == 0) {
516 got_password=1;
517 /* remove the parm since it would otherwise be logged by kern */
518 data[0] = ',';
519 data[1] = ',';
520 data[2] = ',';
521 data[3] = ',';
522 data[4] = ',';
523 } else if (strncmp(data, "ro", 2) == 0) {
524 *filesys_flags |= MS_RDONLY;
525 } else if (strncmp(data, "rw", 2) == 0) {
526 *filesys_flags &= ~MS_RDONLY;
527 } else if (strncmp(data, "remount", 7) == 0) {
528 *filesys_flags |= MS_REMOUNT;
529 } /* else if (strnicmp(data, "port", 4) == 0) {
530 if (value && *value) {
531 vol->port =
532 simple_strtoul(value, &value, 0);
534 } else if (strnicmp(data, "rsize", 5) == 0) {
535 if (value && *value) {
536 vol->rsize =
537 simple_strtoul(value, &value, 0);
539 } else if (strnicmp(data, "wsize", 5) == 0) {
540 if (value && *value) {
541 vol->wsize =
542 simple_strtoul(value, &value, 0);
544 } else if (strnicmp(data, "version", 3) == 0) {
545 } else {
546 printf("CIFS: Unknown mount option %s\n",data);
547 } */ /* nothing to do on those four mount options above.
548 Just pass to kernel and ignore them here */
550 /* move to next option */
551 data = next_keyword+1;
553 /* put overwritten equals sign back */
554 if(value) {
555 value--;
556 *value = '=';
559 /* put previous overwritten comma back */
560 if(next_keyword)
561 *next_keyword = ','; /* BB handle sep= */
562 else
563 data = NULL;
565 return 0;
568 /* replace all (one or more) commas with double commas */
569 static void check_for_comma(char ** ppasswrd)
571 char *new_pass_buf;
572 char *pass;
573 int i,j;
574 int number_of_commas = 0;
575 int len;
577 if(ppasswrd == NULL)
578 return;
579 else
580 (pass = *ppasswrd);
582 len = strlen(pass);
584 for(i=0;i<len;i++) {
585 if(pass[i] == ',')
586 number_of_commas++;
589 if(number_of_commas == 0)
590 return;
591 if(number_of_commas > 64) {
592 /* would otherwise overflow the mount options buffer */
593 printf("\nInvalid password. Password contains too many commas.\n");
594 return;
597 new_pass_buf = malloc(len+number_of_commas+1);
598 if(new_pass_buf == NULL)
599 return;
601 for(i=0,j=0;i<len;i++,j++) {
602 new_pass_buf[j] = pass[i];
603 if(pass[i] == ',') {
604 j++;
605 new_pass_buf[j] = pass[i];
608 new_pass_buf[len+number_of_commas] = 0;
610 free(*ppasswrd);
611 *ppasswrd = new_pass_buf;
613 return;
616 /* Usernames can not have backslash in them and we use
617 [BB check if usernames can have forward slash in them BB]
618 backslash as domain\user separator character
620 static char * check_for_domain(char **ppuser)
622 char * original_string;
623 char * usernm;
624 char * domainnm;
625 int original_len;
626 int len;
627 int i;
629 if(ppuser == NULL)
630 return NULL;
632 original_string = *ppuser;
634 if (original_string == NULL)
635 return NULL;
637 original_len = strlen(original_string);
639 usernm = strchr(*ppuser,'/');
640 if (usernm == NULL) {
641 usernm = strchr(*ppuser,'\\');
642 if (usernm == NULL)
643 return NULL;
646 if(got_domain) {
647 printf("Domain name specified twice. Username probably malformed\n");
648 return NULL;
651 usernm[0] = 0;
652 domainnm = *ppuser;
653 if (domainnm[0] != 0) {
654 got_domain = 1;
655 } else {
656 printf("null domain\n");
658 len = strlen(domainnm);
659 /* reset domainm to new buffer, and copy
660 domain name into it */
661 domainnm = malloc(len+1);
662 if(domainnm == NULL)
663 return NULL;
665 strcpy(domainnm,*ppuser);
667 /* move_string(*ppuser, usernm+1) */
668 len = strlen(usernm+1);
670 if(len >= original_len) {
671 /* should not happen */
672 return domainnm;
675 for(i=0;i<original_len;i++) {
676 if(i<len)
677 original_string[i] = usernm[i+1];
678 else /* stuff with commas to remove last parm */
679 original_string[i] = ',';
682 /* BB add check for more than one slash?
683 strchr(*ppuser,'/');
684 strchr(*ppuser,'\\')
687 return domainnm;
690 /* Note that caller frees the returned buffer if necessary */
691 static char * parse_server(char ** punc_name)
693 char * unc_name = *punc_name;
694 int length = strnlen(unc_name,1024);
695 char * share;
696 char * ipaddress_string = NULL;
697 struct hostent * host_entry;
698 struct in_addr server_ipaddr;
700 if(length > 1023) {
701 printf("mount error: UNC name too long");
702 return NULL;
704 if (strncasecmp("cifs://",unc_name,7) == 0)
705 return parse_cifs_url(unc_name+7);
706 if (strncasecmp("smb://",unc_name,6) == 0) {
707 return parse_cifs_url(unc_name+6);
710 if(length < 3) {
711 /* BB add code to find DFS root here */
712 printf("\nMounting the DFS root for domain not implemented yet");
713 return NULL;
714 } else {
715 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
716 /* check for nfs syntax ie server:share */
717 share = strchr(unc_name,':');
718 if(share) {
719 free_share_name = 1;
720 *punc_name = malloc(length+3);
721 if(*punc_name == NULL) {
722 /* put the original string back if
723 no memory left */
724 *punc_name = unc_name;
725 return NULL;
728 *share = '/';
729 strncpy((*punc_name)+2,unc_name,length);
730 unc_name = *punc_name;
731 unc_name[length+2] = 0;
732 goto continue_unc_parsing;
733 } else {
734 printf("mount error: improperly formatted UNC name.");
735 printf(" %s does not begin with \\\\ or //\n",unc_name);
736 return NULL;
738 } else {
739 continue_unc_parsing:
740 unc_name[0] = '/';
741 unc_name[1] = '/';
742 unc_name += 2;
743 if ((share = strchr(unc_name, '/')) ||
744 (share = strchr(unc_name,'\\'))) {
745 *share = 0; /* temporarily terminate the string */
746 share += 1;
747 if(got_ip == 0) {
748 host_entry = gethostbyname(unc_name);
750 *(share - 1) = '/'; /* put the slash back */
751 if(got_ip) {
752 if(verboseflag)
753 printf("ip address specified explicitly\n");
754 return NULL;
756 if(host_entry == NULL) {
757 printf("mount error: could not find target server. TCP name %s not found\n", unc_name);
758 return NULL;
759 } else {
760 /* BB should we pass an alternate version of the share name as Unicode */
761 /* BB what about ipv6? BB */
762 /* BB add retries with alternate servers in list */
764 memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
766 ipaddress_string = inet_ntoa(server_ipaddr);
767 if(ipaddress_string == NULL) {
768 printf("mount error: could not get valid ip address for target server\n");
769 return NULL;
771 return ipaddress_string;
773 } else {
774 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
775 printf("Mounting the DFS root for a particular server not implemented yet\n");
776 return NULL;
782 static struct option longopts[] = {
783 { "all", 0, NULL, 'a' },
784 { "help",0, NULL, 'h' },
785 { "move",0, NULL, 'm' },
786 { "bind",0, NULL, 'b' },
787 { "read-only", 0, NULL, 'r' },
788 { "ro", 0, NULL, 'r' },
789 { "verbose", 0, NULL, 'v' },
790 { "version", 0, NULL, 'V' },
791 { "read-write", 0, NULL, 'w' },
792 { "rw", 0, NULL, 'w' },
793 { "options", 1, NULL, 'o' },
794 { "type", 1, NULL, 't' },
795 { "rsize",1, NULL, 'R' },
796 { "wsize",1, NULL, 'W' },
797 { "uid", 1, NULL, '1'},
798 { "gid", 1, NULL, '2'},
799 { "user",1,NULL,'u'},
800 { "username",1,NULL,'u'},
801 { "dom",1,NULL,'d'},
802 { "domain",1,NULL,'d'},
803 { "password",1,NULL,'p'},
804 { "pass",1,NULL,'p'},
805 { "credentials",1,NULL,'c'},
806 { "port",1,NULL,'P'},
807 /* { "uuid",1,NULL,'U'}, */ /* BB unimplemented */
808 { NULL, 0, NULL, 0 }
811 int main(int argc, char ** argv)
813 int c;
814 int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
815 char * orgoptions = NULL;
816 char * share_name = NULL;
817 char * ipaddr = NULL;
818 char * uuid = NULL;
819 char * mountpoint;
820 char * options;
821 char * resolved_path;
822 char * temp;
823 int rc;
824 int rsize = 0;
825 int wsize = 0;
826 int nomtab = 0;
827 int uid = 0;
828 int gid = 0;
829 int optlen = 0;
830 int orgoptlen = 0;
831 int retry = 0; /* set when we have to retry mount with uppercase */
832 struct stat statbuf;
833 struct utsname sysinfo;
834 struct mntent mountent;
835 FILE * pmntfile;
837 /* setlocale(LC_ALL, "");
838 bindtextdomain(PACKAGE, LOCALEDIR);
839 textdomain(PACKAGE); */
841 if(argc && argv) {
842 thisprogram = argv[0];
844 if(thisprogram == NULL)
845 thisprogram = "mount.cifs";
847 uname(&sysinfo);
848 /* BB add workstation name and domain and pass down */
850 /* #ifdef _GNU_SOURCE
851 printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
852 #endif */
854 share_name = argv[1];
855 mountpoint = argv[2];
857 /* add sharename in opts string as unc= parm */
859 while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
860 longopts, NULL)) != -1) {
861 switch (c) {
862 /* No code to do the following options yet */
863 /* case 'l':
864 list_with_volumelabel = 1;
865 break;
866 case 'L':
867 volumelabel = optarg;
868 break; */
869 /* case 'a':
870 ++mount_all;
871 break; */
873 case '?':
874 case 'h': /* help */
875 mount_cifs_usage ();
876 exit(1);
877 case 'n':
878 ++nomtab;
879 break;
880 case 'b':
881 flags |= MS_BIND;
882 break;
883 case 'm':
884 flags |= MS_MOVE;
885 break;
886 case 'o':
887 orgoptions = strdup(optarg);
888 break;
889 case 'r': /* mount readonly */
890 flags |= MS_RDONLY;
891 break;
892 case 'U':
893 uuid = optarg;
894 break;
895 case 'v':
896 ++verboseflag;
897 break;
898 case 'V':
899 printf ("mount.cifs version: %s.%s%s\n",
900 MOUNT_CIFS_VERSION_MAJOR,
901 MOUNT_CIFS_VERSION_MINOR,
902 MOUNT_CIFS_VENDOR_SUFFIX);
903 if(mountpassword) {
904 memset(mountpassword,0,64);
906 exit (0);
907 case 'w':
908 flags &= ~MS_RDONLY;
909 break;
910 case 'R':
911 rsize = atoi(optarg) ;
912 break;
913 case 'W':
914 wsize = atoi(optarg);
915 break;
916 case '1':
917 uid = atoi(optarg);
918 break;
919 case '2':
920 gid = atoi(optarg);
921 break;
922 case 'u':
923 got_user = 1;
924 user_name = optarg;
925 break;
926 case 'd':
927 domain_name = optarg; /* BB fix this - currently ignored */
928 got_domain = 1;
929 break;
930 case 'p':
931 if(mountpassword == NULL)
932 mountpassword = calloc(65,1);
933 if(mountpassword) {
934 got_password = 1;
935 strncpy(mountpassword,optarg,64);
937 break;
938 case 'S':
939 get_password_from_file(0 /* stdin */,NULL);
940 break;
941 case 't':
942 break;
943 default:
944 printf("unknown mount option %c\n",c);
945 mount_cifs_usage();
946 exit(1);
950 if(argc < 3)
951 mount_cifs_usage();
953 if (getenv("PASSWD")) {
954 if(mountpassword == NULL)
955 mountpassword = calloc(65,1);
956 if(mountpassword) {
957 strncpy(mountpassword,getenv("PASSWD"),64);
958 got_password = 1;
960 } else if (getenv("PASSWD_FD")) {
961 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
962 } else if (getenv("PASSWD_FILE")) {
963 get_password_from_file(0, getenv("PASSWD_FILE"));
966 if (orgoptions && parse_options(orgoptions, &flags))
967 return -1;
968 ipaddr = parse_server(&share_name);
969 if((ipaddr == NULL) && (got_ip == 0)) {
970 printf("No ip address specified and hostname not found\n");
971 return -1;
974 /* BB save off path and pop after mount returns? */
975 resolved_path = malloc(PATH_MAX+1);
976 if(resolved_path) {
977 /* Note that if we can not canonicalize the name, we get
978 another chance to see if it is valid when we chdir to it */
979 if (realpath(mountpoint, resolved_path)) {
980 mountpoint = resolved_path;
983 if(chdir(mountpoint)) {
984 printf("mount error: can not change directory into mount target %s\n",mountpoint);
985 return -1;
988 if(stat (".", &statbuf)) {
989 printf("mount error: mount point %s does not exist\n",mountpoint);
990 return -1;
993 if (S_ISDIR(statbuf.st_mode) == 0) {
994 printf("mount error: mount point %s is not a directory\n",mountpoint);
995 return -1;
998 if((getuid() != 0) && (geteuid() == 0)) {
999 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
1000 #ifndef CIFS_ALLOW_USR_SUID
1001 /* Do not allow user mounts to control suid flag
1002 for mount unless explicitly built that way */
1003 flags |= MS_NOSUID | MS_NODEV;
1004 #endif
1005 } else {
1006 printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n");
1007 return -1;
1011 if(got_user == 0) {
1012 user_name = getusername();
1013 got_user = 1;
1016 if(got_password == 0) {
1017 mountpassword = getpass("Password: "); /* BB obsolete */
1018 got_password = 1;
1020 /* FIXME launch daemon (handles dfs name resolution and credential change)
1021 remember to clear parms and overwrite password field before launching */
1022 mount_retry:
1023 if(orgoptions) {
1024 optlen = strlen(orgoptions);
1025 orgoptlen = optlen;
1026 } else
1027 optlen = 0;
1028 if(share_name)
1029 optlen += strlen(share_name) + 4;
1030 else {
1031 printf("No server share name specified\n");
1033 if(user_name)
1034 optlen += strlen(user_name) + 6;
1035 if(ipaddr)
1036 optlen += strlen(ipaddr) + 4;
1037 if(mountpassword)
1038 optlen += strlen(mountpassword) + 6;
1039 options = 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 */);
1041 if(options == NULL) {
1042 printf("Could not allocate memory for mount options\n");
1043 return -1;
1047 options[0] = 0;
1048 strncat(options,"unc=",4);
1049 strcat(options,share_name);
1050 /* scan backwards and reverse direction of slash */
1051 temp = strrchr(options, '/');
1052 if(temp > options + 6)
1053 *temp = '\\';
1054 if(ipaddr) {
1055 strncat(options,",ip=",4);
1056 strcat(options,ipaddr);
1059 if(user_name) {
1060 /* check for syntax like user=domain\user */
1061 if(got_domain == 0)
1062 domain_name = check_for_domain(&user_name);
1063 strncat(options,",user=",6);
1064 strcat(options,user_name);
1066 if(retry == 0) {
1067 if(domain_name) {
1068 /* extra length accounted for in option string above */
1069 strncat(options,",domain=",8);
1070 strcat(options,domain_name);
1073 if(mountpassword) {
1074 /* Commas have to be doubled, or else they will
1075 look like the parameter separator */
1076 /* if(sep is not set)*/
1077 if(retry == 0)
1078 check_for_comma(&mountpassword);
1079 strncat(options,",pass=",6);
1080 strcat(options,mountpassword);
1083 strncat(options,",ver=",5);
1084 strcat(options,MOUNT_CIFS_VERSION_MAJOR);
1086 if(orgoptions) {
1087 strcat(options,",");
1088 strcat(options,orgoptions);
1090 if(verboseflag)
1091 printf("\nmount.cifs kernel mount options %s \n",options);
1092 if(mount(share_name, mountpoint, "cifs", flags, options)) {
1093 /* remember to kill daemon on error */
1094 char * tmp;
1096 switch (errno) {
1097 case 0:
1098 printf("mount failed but no error number set\n");
1099 break;
1100 case ENODEV:
1101 printf("mount error: cifs filesystem not supported by the system\n");
1102 break;
1103 case ENXIO:
1104 if(retry == 0) {
1105 retry = 1;
1106 tmp = share_name;
1107 while (*tmp && !(((unsigned char)tmp[0]) & 0x80)) {
1108 *tmp = toupper((unsigned char)*tmp);
1109 tmp++;
1111 if(!*tmp) {
1112 printf("retrying with upper case share name\n");
1113 goto mount_retry;
1116 default:
1118 printf("mount error %d = %s\n",errno,strerror(errno));
1120 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
1121 if(mountpassword) {
1122 memset(mountpassword,0,64);
1124 return -1;
1125 } else {
1126 pmntfile = setmntent(MOUNTED, "a+");
1127 if(pmntfile) {
1128 mountent.mnt_fsname = share_name;
1129 mountent.mnt_dir = mountpoint;
1130 mountent.mnt_type = "cifs";
1131 mountent.mnt_opts = malloc(220);
1132 if(mountent.mnt_opts) {
1133 char * mount_user = getusername();
1134 memset(mountent.mnt_opts,0,200);
1135 if(flags & MS_RDONLY)
1136 strcat(mountent.mnt_opts,"ro");
1137 else
1138 strcat(mountent.mnt_opts,"rw");
1139 if(flags & MS_MANDLOCK)
1140 strcat(mountent.mnt_opts,",mand");
1141 else
1142 strcat(mountent.mnt_opts,",nomand");
1143 if(flags & MS_NOEXEC)
1144 strcat(mountent.mnt_opts,",noexec");
1145 if(flags & MS_NOSUID)
1146 strcat(mountent.mnt_opts,",nosuid");
1147 if(flags & MS_NODEV)
1148 strcat(mountent.mnt_opts,",nodev");
1149 if(flags & MS_SYNCHRONOUS)
1150 strcat(mountent.mnt_opts,",synch");
1151 if(mount_user) {
1152 if(getuid() != 0) {
1153 strcat(mountent.mnt_opts,",user=");
1154 strcat(mountent.mnt_opts,mount_user);
1156 free(mount_user);
1159 mountent.mnt_freq = 0;
1160 mountent.mnt_passno = 0;
1161 rc = addmntent(pmntfile,&mountent);
1162 endmntent(pmntfile);
1163 if(mountent.mnt_opts)
1164 free(mountent.mnt_opts);
1165 } else {
1166 printf("could not update mount table\n");
1169 if(mountpassword) {
1170 int len = strlen(mountpassword);
1171 memset(mountpassword,0,len);
1172 free(mountpassword);
1175 if(options) {
1176 memset(options,0,optlen);
1177 free(options);
1180 if(orgoptions) {
1181 memset(orgoptions,0,orgoptlen);
1182 free(orgoptions);
1184 if(resolved_path) {
1185 free(resolved_path);
1188 if(free_share_name) {
1189 free(share_name);
1191 return 0;