r13714: Set MOUNT_CIFS_VENDOR_SUFFIX if _SAMBA_BUILD_ is set to
[Samba/gebeck_regimport.git] / source / client / mount.cifs.c
blobdd765c340637341c2c9e26d8d30df0cb14e6f8ea
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 <grp.h>
28 #include <ctype.h>
29 #include <sys/types.h>
30 #include <sys/mount.h>
31 #include <sys/stat.h>
32 #include <sys/utsname.h>
33 #include <sys/socket.h>
34 #include <arpa/inet.h>
35 #include <getopt.h>
36 #include <errno.h>
37 #include <netdb.h>
38 #include <string.h>
39 #include <mntent.h>
40 #include <fcntl.h>
42 #define MOUNT_CIFS_VERSION_MAJOR "1"
43 #define MOUNT_CIFS_VERSION_MINOR "10"
45 #ifndef MOUNT_CIFS_VENDOR_SUFFIX
46 #ifdef _SAMBA_BUILD_
47 #include "include/version.h"
48 #ifdef SAMBA_VERSION_VENDOR_SUFFIX
49 #define MOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING"-"SAMBA_VERSION_VENDOR_SUFFIX
50 #else
51 #define MOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING
52 #endif /* SAMBA_VERSION_OFFICIAL_STRING and SAMBA_VERSION_VENDOR_SUFFIX */
53 #else
54 #define MOUNT_CIFS_VENDOR_SUFFIX ""
55 #endif /* _SAMBA_BUILD_ */
56 #endif /* MOUNT_CIFS_VENDOR_SUFFIX */
58 #ifndef MS_MOVE
59 #define MS_MOVE 8192
60 #endif
62 char * thisprogram;
63 int verboseflag = 0;
64 static int got_password = 0;
65 static int got_user = 0;
66 static int got_domain = 0;
67 static int got_ip = 0;
68 static int got_unc = 0;
69 static int got_uid = 0;
70 static int got_gid = 0;
71 static int free_share_name = 0;
72 static char * user_name = NULL;
73 static char * mountpassword = NULL;
74 char * domain_name = NULL;
77 /* BB finish BB
79 cifs_umount
80 open nofollow - avoid symlink exposure?
81 get owner of dir see if matches self or if root
82 call system(umount argv) etc.
84 BB end finish BB */
86 static char * check_for_domain(char **);
89 static void mount_cifs_usage(void)
91 printf("\nUsage: %s <remotetarget> <dir> -o <options>\n", thisprogram);
92 printf("\nMount the remote target, specified as a UNC name,");
93 printf(" to a local directory.\n\nOptions:\n");
94 printf("\tuser=<arg>\n\tpass=<arg>\n\tdom=<arg>\n");
95 printf("\nLess commonly used options:");
96 printf("\n\tcredentials=<filename>,guest,perm,noperm,setuids,nosetuids,rw,ro,");
97 printf("\n\tsep=<char>,iocharset=<codepage>,suid,nosuid,exec,noexec,serverino,");
98 printf("\n\tdirectio,mapchars,nomapchars,nolock,servernetbiosname=<SRV_RFC1001NAME>");
99 printf("\n\nOptions not needed for servers supporting CIFS Unix extensions");
100 printf("\n\t(e.g. unneeded for mounts to most Samba versions):");
101 printf("\n\tuid=<uid>,gid=<gid>,dir_mode=<mode>,file_mode=<mode>,sfu");
102 printf("\n\nRarely used options:");
103 printf("\n\tport=<tcpport>,rsize=<size>,wsize=<size>,unc=<unc_name>,ip=<ip_address>,");
104 printf("\n\tdev,nodev,nouser_xattr,netbiosname=<OUR_RFC1001NAME>,hard,soft,intr,");
105 printf("\n\tnointr,ignorecase,noposixpaths,noacl");
106 printf("\n\nOptions are described in more detail in the manual page");
107 printf("\n\tman 8 mount.cifs\n");
108 printf("\nTo display the version number of the mount helper:");
109 printf("\n\t%s -V\n",thisprogram);
111 if(mountpassword) {
112 memset(mountpassword,0,64);
113 free(mountpassword);
115 exit(1);
118 /* caller frees username if necessary */
119 static char * getusername(void) {
120 char *username = NULL;
121 struct passwd *password = getpwuid(getuid());
123 if (password) {
124 username = password->pw_name;
126 return username;
129 static char * parse_cifs_url(char * unc_name)
131 printf("\nMounting cifs URL not implemented yet. Attempt to mount %s\n",unc_name);
132 return NULL;
135 static int open_cred_file(char * file_name)
137 char * line_buf;
138 char * temp_val;
139 FILE * fs;
140 int i, length;
141 fs = fopen(file_name,"r");
142 if(fs == NULL)
143 return errno;
144 line_buf = malloc(4096);
145 if(line_buf == NULL) {
146 fclose(fs);
147 return -ENOMEM;
150 while(fgets(line_buf,4096,fs)) {
151 /* parse line from credential file */
153 /* eat leading white space */
154 for(i=0;i<4086;i++) {
155 if((line_buf[i] != ' ') && (line_buf[i] != '\t'))
156 break;
157 /* if whitespace - skip past it */
159 if (strncasecmp("username",line_buf+i,8) == 0) {
160 temp_val = strchr(line_buf + i,'=');
161 if(temp_val) {
162 /* go past equals sign */
163 temp_val++;
164 for(length = 0;length<4087;length++) {
165 if(temp_val[length] == '\n')
166 break;
168 if(length > 4086) {
169 printf("mount.cifs failed due to malformed username in credentials file");
170 memset(line_buf,0,4096);
171 if(mountpassword) {
172 memset(mountpassword,0,64);
174 exit(1);
175 } else {
176 got_user = 1;
177 user_name = calloc(1 + length,1);
178 /* BB adding free of user_name string before exit,
179 not really necessary but would be cleaner */
180 strncpy(user_name,temp_val, length);
183 } else if (strncasecmp("password",line_buf+i,8) == 0) {
184 temp_val = strchr(line_buf+i,'=');
185 if(temp_val) {
186 /* go past equals sign */
187 temp_val++;
188 for(length = 0;length<65;length++) {
189 if(temp_val[length] == '\n')
190 break;
192 if(length > 64) {
193 printf("mount.cifs failed: password in credentials file too long\n");
194 memset(line_buf,0, 4096);
195 if(mountpassword) {
196 memset(mountpassword,0,64);
198 exit(1);
199 } else {
200 if(mountpassword == NULL) {
201 mountpassword = calloc(65,1);
202 } else
203 memset(mountpassword,0,64);
204 if(mountpassword) {
205 strncpy(mountpassword,temp_val,length);
206 got_password = 1;
210 } else if (strncasecmp("domain",line_buf+i,6) == 0) {
211 temp_val = strchr(line_buf+i,'=');
212 if(temp_val) {
213 /* go past equals sign */
214 temp_val++;
215 if(verboseflag)
216 printf("\nDomain %s\n",temp_val);
217 for(length = 0;length<65;length++) {
218 if(temp_val[length] == '\n')
219 break;
221 if(length > 64) {
222 printf("mount.cifs failed: domain in credentials file too long\n");
223 if(mountpassword) {
224 memset(mountpassword,0,64);
226 exit(1);
227 } else {
228 if(domain_name == NULL) {
229 domain_name = calloc(65,1);
230 } else
231 memset(domain_name,0,64);
232 if(domain_name) {
233 strncpy(domain_name,temp_val,length);
234 got_domain = 1;
241 fclose(fs);
242 if(line_buf) {
243 memset(line_buf,0,4096);
244 free(line_buf);
246 return 0;
249 static int get_password_from_file(int file_descript, char * filename)
251 int rc = 0;
252 int i;
253 char c;
255 if(mountpassword == NULL)
256 mountpassword = calloc(65,1);
257 else
258 memset(mountpassword, 0, 64);
260 if(filename != NULL) {
261 file_descript = open(filename, O_RDONLY);
262 if(file_descript < 0) {
263 printf("mount.cifs failed. %s attempting to open password file %s\n",
264 strerror(errno),filename);
265 exit(1);
268 /* else file already open and fd provided */
270 for(i=0;i<64;i++) {
271 rc = read(file_descript,&c,1);
272 if(rc < 0) {
273 printf("mount.cifs failed. Error %s reading password file\n",strerror(errno));
274 memset(mountpassword,0,64);
275 if(filename != NULL)
276 close(file_descript);
277 exit(1);
278 } else if(rc == 0) {
279 if(mountpassword[0] == 0) {
280 if(verboseflag)
281 printf("\nWarning: null password used since cifs password file empty");
283 break;
284 } else /* read valid character */ {
285 if((c == 0) || (c == '\n')) {
286 break;
287 } else
288 mountpassword[i] = c;
291 if((i == 64) && (verboseflag)) {
292 printf("\nWarning: password longer than 64 characters specified in cifs password file");
294 got_password = 1;
295 if(filename != NULL) {
296 close(file_descript);
299 return rc;
302 static int parse_options(char ** optionsp, int * filesys_flags)
304 char * data;
305 char * percent_char = NULL;
306 char * value = NULL;
307 char * next_keyword = NULL;
308 char * out = NULL;
309 int out_len = 0;
310 int word_len;
311 int rc = 0;
313 if (!optionsp || !*optionsp)
314 return 1;
315 data = *optionsp;
317 if(verboseflag)
318 printf("parsing options: %s\n", data);
320 /* BB fixme check for separator override BB */
322 /* while ((data = strsep(&options, ",")) != NULL) { */
323 while(data != NULL) {
324 /* check if ends with trailing comma */
325 if(*data == 0)
326 break;
328 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
329 /* data = next keyword */
330 /* value = next value ie stuff after equal sign */
332 next_keyword = strchr(data,','); /* BB handle sep= */
334 /* temporarily null terminate end of keyword=value pair */
335 if(next_keyword)
336 *next_keyword++ = 0;
338 /* temporarily null terminate keyword to make keyword and value distinct */
339 if ((value = strchr(data, '=')) != NULL) {
340 *value = '\0';
341 value++;
344 if (strncmp(data, "users",5) == 0) {
345 if(!value || !*value) {
346 goto nocopy;
348 } else if (strncmp(data, "user_xattr",10) == 0) {
349 /* do nothing - need to skip so not parsed as user name */
350 } else if (strncmp(data, "user", 4) == 0) {
352 if (!value || !*value) {
353 if(data[4] == '\0') {
354 if(verboseflag)
355 printf("\nskipping empty user mount parameter\n");
356 /* remove the parm since it would otherwise be confusing
357 to the kernel code which would think it was a real username */
358 goto nocopy;
359 } else {
360 printf("username specified with no parameter\n");
361 return 1; /* needs_arg; */
363 } else {
364 if (strnlen(value, 260) < 260) {
365 got_user=1;
366 percent_char = strchr(value,'%');
367 if(percent_char) {
368 *percent_char = ',';
369 if(mountpassword == NULL)
370 mountpassword = calloc(65,1);
371 if(mountpassword) {
372 if(got_password)
373 printf("\nmount.cifs warning - password specified twice\n");
374 got_password = 1;
375 percent_char++;
376 strncpy(mountpassword, percent_char,64);
377 /* remove password from username */
378 while(*percent_char != 0) {
379 *percent_char = ',';
380 percent_char++;
384 /* this is only case in which the user
385 name buf is not malloc - so we have to
386 check for domain name embedded within
387 the user name here since the later
388 call to check_for_domain will not be
389 invoked */
390 domain_name = check_for_domain(&value);
391 } else {
392 printf("username too long\n");
393 return 1;
396 } else if (strncmp(data, "pass", 4) == 0) {
397 if (!value || !*value) {
398 if(got_password) {
399 printf("\npassword specified twice, ignoring second\n");
400 } else
401 got_password = 1;
402 } else if (strnlen(value, 17) < 17) {
403 if(got_password)
404 printf("\nmount.cifs warning - password specified twice\n");
405 got_password = 1;
406 } else {
407 printf("password too long\n");
408 return 1;
410 } else if (strncmp(data, "ip", 2) == 0) {
411 if (!value || !*value) {
412 printf("target ip address argument missing");
413 } else if (strnlen(value, 35) < 35) {
414 if(verboseflag)
415 printf("ip address %s override specified\n",value);
416 got_ip = 1;
417 } else {
418 printf("ip address too long\n");
419 return 1;
421 } else if ((strncmp(data, "unc", 3) == 0)
422 || (strncmp(data, "target", 6) == 0)
423 || (strncmp(data, "path", 4) == 0)) {
424 if (!value || !*value) {
425 printf("invalid path to network resource\n");
426 return 1; /* needs_arg; */
427 } else if(strnlen(value,5) < 5) {
428 printf("UNC name too short");
431 if (strnlen(value, 300) < 300) {
432 got_unc = 1;
433 if (strncmp(value, "//", 2) == 0) {
434 if(got_unc)
435 printf("unc name specified twice, ignoring second\n");
436 else
437 got_unc = 1;
438 } else if (strncmp(value, "\\\\", 2) != 0) {
439 printf("UNC Path does not begin with // or \\\\ \n");
440 return 1;
441 } else {
442 if(got_unc)
443 printf("unc name specified twice, ignoring second\n");
444 else
445 got_unc = 1;
447 } else {
448 printf("CIFS: UNC name too long\n");
449 return 1;
451 } else if ((strncmp(data, "domain", 3) == 0)
452 || (strncmp(data, "workgroup", 5) == 0)) {
453 if (!value || !*value) {
454 printf("CIFS: invalid domain name\n");
455 return 1; /* needs_arg; */
457 if (strnlen(value, 65) < 65) {
458 got_domain = 1;
459 } else {
460 printf("domain name too long\n");
461 return 1;
463 } else if (strncmp(data, "cred", 4) == 0) {
464 if (value && *value) {
465 rc = open_cred_file(value);
466 if(rc) {
467 printf("error %d opening credential file %s\n",rc, value);
468 return 1;
470 } else {
471 printf("invalid credential file name specified\n");
472 return 1;
474 } else if (strncmp(data, "uid", 3) == 0) {
475 if (value && *value) {
476 got_uid = 1;
477 if (!isdigit(*value)) {
478 struct passwd *pw;
479 static char temp[32];
481 if (!(pw = getpwnam(value))) {
482 printf("bad user name \"%s\"\n", value);
483 exit(1);
485 sprintf(temp, "%u", pw->pw_uid);
486 value = temp;
487 endpwent();
490 } else if (strncmp(data, "gid", 3) == 0) {
491 if (value && *value) {
492 got_gid = 1;
493 if (!isdigit(*value)) {
494 struct group *gr;
495 static char temp[32];
497 if (!(gr = getgrnam(value))) {
498 printf("bad group name \"%s\"\n", value);
499 exit(1);
501 sprintf(temp, "%u", gr->gr_gid);
502 value = temp;
503 endpwent();
506 /* fmask and dmask synonyms for people used to smbfs syntax */
507 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
508 if (!value || !*value) {
509 printf ("Option '%s' requires a numerical argument\n", data);
510 return 1;
513 if (value[0] != '0') {
514 printf ("WARNING: '%s' not expressed in octal.\n", data);
517 if (strcmp (data, "fmask") == 0) {
518 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
519 data = "file_mode"; /* BB fix this */
521 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
522 if (!value || !*value) {
523 printf ("Option '%s' requires a numerical argument\n", data);
524 return 1;
527 if (value[0] != '0') {
528 printf ("WARNING: '%s' not expressed in octal.\n", data);
531 if (strcmp (data, "dmask") == 0) {
532 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
533 data = "dir_mode";
535 /* the following eight mount options should be
536 stripped out from what is passed into the kernel
537 since these eight options are best passed as the
538 mount flags rather than redundantly to the kernel
539 and could generate spurious warnings depending on the
540 level of the corresponding cifs vfs kernel code */
541 } else if (strncmp(data, "nosuid", 6) == 0) {
542 *filesys_flags |= MS_NOSUID;
543 } else if (strncmp(data, "suid", 4) == 0) {
544 *filesys_flags &= ~MS_NOSUID;
545 } else if (strncmp(data, "nodev", 5) == 0) {
546 *filesys_flags |= MS_NODEV;
547 } else if ((strncmp(data, "nobrl", 5) == 0) ||
548 (strncmp(data, "nolock", 6) == 0)) {
549 *filesys_flags &= ~MS_MANDLOCK;
550 } else if (strncmp(data, "dev", 3) == 0) {
551 *filesys_flags &= ~MS_NODEV;
552 } else if (strncmp(data, "noexec", 6) == 0) {
553 *filesys_flags |= MS_NOEXEC;
554 } else if (strncmp(data, "exec", 4) == 0) {
555 *filesys_flags &= ~MS_NOEXEC;
556 } else if (strncmp(data, "guest", 5) == 0) {
557 got_password=1;
558 /* remove the parm since it would otherwise be logged by kern */
559 goto nocopy;
560 } else if (strncmp(data, "ro", 2) == 0) {
561 *filesys_flags |= MS_RDONLY;
562 } else if (strncmp(data, "rw", 2) == 0) {
563 *filesys_flags &= ~MS_RDONLY;
564 } else if (strncmp(data, "remount", 7) == 0) {
565 *filesys_flags |= MS_REMOUNT;
566 } /* else if (strnicmp(data, "port", 4) == 0) {
567 if (value && *value) {
568 vol->port =
569 simple_strtoul(value, &value, 0);
571 } else if (strnicmp(data, "rsize", 5) == 0) {
572 if (value && *value) {
573 vol->rsize =
574 simple_strtoul(value, &value, 0);
576 } else if (strnicmp(data, "wsize", 5) == 0) {
577 if (value && *value) {
578 vol->wsize =
579 simple_strtoul(value, &value, 0);
581 } else if (strnicmp(data, "version", 3) == 0) {
582 } else {
583 printf("CIFS: Unknown mount option %s\n",data);
584 } */ /* nothing to do on those four mount options above.
585 Just pass to kernel and ignore them here */
587 /* Copy (possibly modified) option to out */
588 word_len = strlen(data);
589 if (value)
590 word_len += 1 + strlen(value);
592 out = realloc(out, out_len + word_len + 2);
593 if (out == NULL) {
594 perror("malloc");
595 exit(1);
598 if (out_len)
599 out[out_len++] = ',';
600 if (value)
601 sprintf(out + out_len, "%s=%s", data, value);
602 else
603 sprintf(out + out_len, "%s", data);
604 out_len = strlen(out);
606 nocopy:
607 data = next_keyword;
609 *optionsp = out;
610 return 0;
613 /* replace all (one or more) commas with double commas */
614 static void check_for_comma(char ** ppasswrd)
616 char *new_pass_buf;
617 char *pass;
618 int i,j;
619 int number_of_commas = 0;
620 int len;
622 if(ppasswrd == NULL)
623 return;
624 else
625 (pass = *ppasswrd);
627 len = strlen(pass);
629 for(i=0;i<len;i++) {
630 if(pass[i] == ',')
631 number_of_commas++;
634 if(number_of_commas == 0)
635 return;
636 if(number_of_commas > 64) {
637 /* would otherwise overflow the mount options buffer */
638 printf("\nInvalid password. Password contains too many commas.\n");
639 return;
642 new_pass_buf = malloc(len+number_of_commas+1);
643 if(new_pass_buf == NULL)
644 return;
646 for(i=0,j=0;i<len;i++,j++) {
647 new_pass_buf[j] = pass[i];
648 if(pass[i] == ',') {
649 j++;
650 new_pass_buf[j] = pass[i];
653 new_pass_buf[len+number_of_commas] = 0;
655 free(*ppasswrd);
656 *ppasswrd = new_pass_buf;
658 return;
661 /* Usernames can not have backslash in them and we use
662 [BB check if usernames can have forward slash in them BB]
663 backslash as domain\user separator character
665 static char * check_for_domain(char **ppuser)
667 char * original_string;
668 char * usernm;
669 char * domainnm;
670 int original_len;
671 int len;
672 int i;
674 if(ppuser == NULL)
675 return NULL;
677 original_string = *ppuser;
679 if (original_string == NULL)
680 return NULL;
682 original_len = strlen(original_string);
684 usernm = strchr(*ppuser,'/');
685 if (usernm == NULL) {
686 usernm = strchr(*ppuser,'\\');
687 if (usernm == NULL)
688 return NULL;
691 if(got_domain) {
692 printf("Domain name specified twice. Username probably malformed\n");
693 return NULL;
696 usernm[0] = 0;
697 domainnm = *ppuser;
698 if (domainnm[0] != 0) {
699 got_domain = 1;
700 } else {
701 printf("null domain\n");
703 len = strlen(domainnm);
704 /* reset domainm to new buffer, and copy
705 domain name into it */
706 domainnm = malloc(len+1);
707 if(domainnm == NULL)
708 return NULL;
710 strcpy(domainnm,*ppuser);
712 /* move_string(*ppuser, usernm+1) */
713 len = strlen(usernm+1);
715 if(len >= original_len) {
716 /* should not happen */
717 return domainnm;
720 for(i=0;i<original_len;i++) {
721 if(i<len)
722 original_string[i] = usernm[i+1];
723 else /* stuff with commas to remove last parm */
724 original_string[i] = ',';
727 /* BB add check for more than one slash?
728 strchr(*ppuser,'/');
729 strchr(*ppuser,'\\')
732 return domainnm;
735 /* Note that caller frees the returned buffer if necessary */
736 static char * parse_server(char ** punc_name)
738 char * unc_name = *punc_name;
739 int length = strnlen(unc_name,1024);
740 char * share;
741 char * ipaddress_string = NULL;
742 struct hostent * host_entry = NULL;
743 struct in_addr server_ipaddr;
745 if(length > 1023) {
746 printf("mount error: UNC name too long");
747 return NULL;
749 if (strncasecmp("cifs://",unc_name,7) == 0)
750 return parse_cifs_url(unc_name+7);
751 if (strncasecmp("smb://",unc_name,6) == 0) {
752 return parse_cifs_url(unc_name+6);
755 if(length < 3) {
756 /* BB add code to find DFS root here */
757 printf("\nMounting the DFS root for domain not implemented yet");
758 return NULL;
759 } else {
760 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
761 /* check for nfs syntax ie server:share */
762 share = strchr(unc_name,':');
763 if(share) {
764 free_share_name = 1;
765 *punc_name = malloc(length+3);
766 if(*punc_name == NULL) {
767 /* put the original string back if
768 no memory left */
769 *punc_name = unc_name;
770 return NULL;
773 *share = '/';
774 strncpy((*punc_name)+2,unc_name,length);
775 unc_name = *punc_name;
776 unc_name[length+2] = 0;
777 goto continue_unc_parsing;
778 } else {
779 printf("mount error: improperly formatted UNC name.");
780 printf(" %s does not begin with \\\\ or //\n",unc_name);
781 return NULL;
783 } else {
784 continue_unc_parsing:
785 unc_name[0] = '/';
786 unc_name[1] = '/';
787 unc_name += 2;
788 if ((share = strchr(unc_name, '/')) ||
789 (share = strchr(unc_name,'\\'))) {
790 *share = 0; /* temporarily terminate the string */
791 share += 1;
792 if(got_ip == 0) {
793 host_entry = gethostbyname(unc_name);
795 *(share - 1) = '/'; /* put the slash back */
796 if(got_ip) {
797 if(verboseflag)
798 printf("ip address specified explicitly\n");
799 return NULL;
801 if(host_entry == NULL) {
802 printf("mount error: could not find target server. TCP name %s not found\n", unc_name);
803 return NULL;
804 } else {
805 /* BB should we pass an alternate version of the share name as Unicode */
806 /* BB what about ipv6? BB */
807 /* BB add retries with alternate servers in list */
809 memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
811 ipaddress_string = inet_ntoa(server_ipaddr);
812 if(ipaddress_string == NULL) {
813 printf("mount error: could not get valid ip address for target server\n");
814 return NULL;
816 return ipaddress_string;
818 } else {
819 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
820 printf("Mounting the DFS root for a particular server not implemented yet\n");
821 return NULL;
827 static struct option longopts[] = {
828 { "all", 0, NULL, 'a' },
829 { "help",0, NULL, 'h' },
830 { "move",0, NULL, 'm' },
831 { "bind",0, NULL, 'b' },
832 { "read-only", 0, NULL, 'r' },
833 { "ro", 0, NULL, 'r' },
834 { "verbose", 0, NULL, 'v' },
835 { "version", 0, NULL, 'V' },
836 { "read-write", 0, NULL, 'w' },
837 { "rw", 0, NULL, 'w' },
838 { "options", 1, NULL, 'o' },
839 { "type", 1, NULL, 't' },
840 { "rsize",1, NULL, 'R' },
841 { "wsize",1, NULL, 'W' },
842 { "uid", 1, NULL, '1'},
843 { "gid", 1, NULL, '2'},
844 { "user",1,NULL,'u'},
845 { "username",1,NULL,'u'},
846 { "dom",1,NULL,'d'},
847 { "domain",1,NULL,'d'},
848 { "password",1,NULL,'p'},
849 { "pass",1,NULL,'p'},
850 { "credentials",1,NULL,'c'},
851 { "port",1,NULL,'P'},
852 /* { "uuid",1,NULL,'U'}, */ /* BB unimplemented */
853 { NULL, 0, NULL, 0 }
856 int main(int argc, char ** argv)
858 int c;
859 int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
860 char * orgoptions = NULL;
861 char * share_name = NULL;
862 char * ipaddr = NULL;
863 char * uuid = NULL;
864 char * mountpoint;
865 char * options;
866 char * resolved_path;
867 char * temp;
868 int rc;
869 int rsize = 0;
870 int wsize = 0;
871 int nomtab = 0;
872 int uid = 0;
873 int gid = 0;
874 int optlen = 0;
875 int orgoptlen = 0;
876 int retry = 0; /* set when we have to retry mount with uppercase */
877 struct stat statbuf;
878 struct utsname sysinfo;
879 struct mntent mountent;
880 FILE * pmntfile;
882 /* setlocale(LC_ALL, "");
883 bindtextdomain(PACKAGE, LOCALEDIR);
884 textdomain(PACKAGE); */
886 if(argc && argv) {
887 thisprogram = argv[0];
889 if(thisprogram == NULL)
890 thisprogram = "mount.cifs";
892 uname(&sysinfo);
893 /* BB add workstation name and domain and pass down */
895 /* #ifdef _GNU_SOURCE
896 printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
897 #endif */
899 share_name = argv[1];
900 mountpoint = argv[2];
902 /* add sharename in opts string as unc= parm */
904 while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
905 longopts, NULL)) != -1) {
906 switch (c) {
907 /* No code to do the following options yet */
908 /* case 'l':
909 list_with_volumelabel = 1;
910 break;
911 case 'L':
912 volumelabel = optarg;
913 break; */
914 /* case 'a':
915 ++mount_all;
916 break; */
918 case '?':
919 case 'h': /* help */
920 mount_cifs_usage ();
921 exit(1);
922 case 'n':
923 ++nomtab;
924 break;
925 case 'b':
926 flags |= MS_BIND;
927 break;
928 case 'm':
929 flags |= MS_MOVE;
930 break;
931 case 'o':
932 orgoptions = strdup(optarg);
933 break;
934 case 'r': /* mount readonly */
935 flags |= MS_RDONLY;
936 break;
937 case 'U':
938 uuid = optarg;
939 break;
940 case 'v':
941 ++verboseflag;
942 break;
943 case 'V':
944 printf ("mount.cifs version: %s.%s%s\n",
945 MOUNT_CIFS_VERSION_MAJOR,
946 MOUNT_CIFS_VERSION_MINOR,
947 MOUNT_CIFS_VENDOR_SUFFIX);
948 if(mountpassword) {
949 memset(mountpassword,0,64);
951 exit (0);
952 case 'w':
953 flags &= ~MS_RDONLY;
954 break;
955 case 'R':
956 rsize = atoi(optarg) ;
957 break;
958 case 'W':
959 wsize = atoi(optarg);
960 break;
961 case '1':
962 if (isdigit(*optarg)) {
963 char *ep;
965 uid = strtoul(optarg, &ep, 10);
966 if (*ep) {
967 printf("bad uid value \"%s\"\n", optarg);
968 exit(1);
970 } else {
971 struct passwd *pw;
973 if (!(pw = getpwnam(optarg))) {
974 printf("bad user name \"%s\"\n", optarg);
975 exit(1);
977 uid = pw->pw_uid;
978 endpwent();
980 break;
981 case '2':
982 if (isdigit(*optarg)) {
983 char *ep;
985 gid = strtoul(optarg, &ep, 10);
986 if (*ep) {
987 printf("bad gid value \"%s\"\n", optarg);
988 exit(1);
990 } else {
991 struct group *gr;
993 if (!(gr = getgrnam(optarg))) {
994 printf("bad user name \"%s\"\n", optarg);
995 exit(1);
997 gid = gr->gr_gid;
998 endpwent();
1000 break;
1001 case 'u':
1002 got_user = 1;
1003 user_name = optarg;
1004 break;
1005 case 'd':
1006 domain_name = optarg; /* BB fix this - currently ignored */
1007 got_domain = 1;
1008 break;
1009 case 'p':
1010 if(mountpassword == NULL)
1011 mountpassword = calloc(65,1);
1012 if(mountpassword) {
1013 got_password = 1;
1014 strncpy(mountpassword,optarg,64);
1016 break;
1017 case 'S':
1018 get_password_from_file(0 /* stdin */,NULL);
1019 break;
1020 case 't':
1021 break;
1022 default:
1023 printf("unknown mount option %c\n",c);
1024 mount_cifs_usage();
1025 exit(1);
1029 if(argc < 3)
1030 mount_cifs_usage();
1032 if (getenv("PASSWD")) {
1033 if(mountpassword == NULL)
1034 mountpassword = calloc(65,1);
1035 if(mountpassword) {
1036 strncpy(mountpassword,getenv("PASSWD"),64);
1037 got_password = 1;
1039 } else if (getenv("PASSWD_FD")) {
1040 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
1041 } else if (getenv("PASSWD_FILE")) {
1042 get_password_from_file(0, getenv("PASSWD_FILE"));
1045 if (orgoptions && parse_options(&orgoptions, &flags))
1046 return -1;
1047 ipaddr = parse_server(&share_name);
1048 if((ipaddr == NULL) && (got_ip == 0)) {
1049 printf("No ip address specified and hostname not found\n");
1050 return -1;
1053 /* BB save off path and pop after mount returns? */
1054 resolved_path = malloc(PATH_MAX+1);
1055 if(resolved_path) {
1056 /* Note that if we can not canonicalize the name, we get
1057 another chance to see if it is valid when we chdir to it */
1058 if (realpath(mountpoint, resolved_path)) {
1059 mountpoint = resolved_path;
1062 if(chdir(mountpoint)) {
1063 printf("mount error: can not change directory into mount target %s\n",mountpoint);
1064 return -1;
1067 if(stat (".", &statbuf)) {
1068 printf("mount error: mount point %s does not exist\n",mountpoint);
1069 return -1;
1072 if (S_ISDIR(statbuf.st_mode) == 0) {
1073 printf("mount error: mount point %s is not a directory\n",mountpoint);
1074 return -1;
1077 if((getuid() != 0) && (geteuid() == 0)) {
1078 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
1079 #ifndef CIFS_ALLOW_USR_SUID
1080 /* Do not allow user mounts to control suid flag
1081 for mount unless explicitly built that way */
1082 flags |= MS_NOSUID | MS_NODEV;
1083 #endif
1084 } else {
1085 printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n");
1086 return -1;
1090 if(got_user == 0) {
1091 user_name = getusername();
1092 got_user = 1;
1095 if(got_password == 0) {
1096 mountpassword = getpass("Password: "); /* BB obsolete */
1097 got_password = 1;
1099 /* FIXME launch daemon (handles dfs name resolution and credential change)
1100 remember to clear parms and overwrite password field before launching */
1101 mount_retry:
1102 if(orgoptions) {
1103 optlen = strlen(orgoptions);
1104 orgoptlen = optlen;
1105 } else
1106 optlen = 0;
1107 if(share_name)
1108 optlen += strlen(share_name) + 4;
1109 else {
1110 printf("No server share name specified\n");
1112 if(user_name)
1113 optlen += strlen(user_name) + 6;
1114 if(ipaddr)
1115 optlen += strlen(ipaddr) + 4;
1116 if(mountpassword)
1117 optlen += strlen(mountpassword) + 6;
1118 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 */);
1120 if(options == NULL) {
1121 printf("Could not allocate memory for mount options\n");
1122 return -1;
1126 options[0] = 0;
1127 strncat(options,"unc=",4);
1128 strcat(options,share_name);
1129 /* scan backwards and reverse direction of slash */
1130 temp = strrchr(options, '/');
1131 if(temp > options + 6)
1132 *temp = '\\';
1133 if(ipaddr) {
1134 strncat(options,",ip=",4);
1135 strcat(options,ipaddr);
1138 if(user_name) {
1139 /* check for syntax like user=domain\user */
1140 if(got_domain == 0)
1141 domain_name = check_for_domain(&user_name);
1142 strncat(options,",user=",6);
1143 strcat(options,user_name);
1145 if(retry == 0) {
1146 if(domain_name) {
1147 /* extra length accounted for in option string above */
1148 strncat(options,",domain=",8);
1149 strcat(options,domain_name);
1152 if(mountpassword) {
1153 /* Commas have to be doubled, or else they will
1154 look like the parameter separator */
1155 /* if(sep is not set)*/
1156 if(retry == 0)
1157 check_for_comma(&mountpassword);
1158 strncat(options,",pass=",6);
1159 strcat(options,mountpassword);
1162 strncat(options,",ver=",5);
1163 strcat(options,MOUNT_CIFS_VERSION_MAJOR);
1165 if(orgoptions) {
1166 strcat(options,",");
1167 strcat(options,orgoptions);
1169 if(verboseflag)
1170 printf("\nmount.cifs kernel mount options %s \n",options);
1171 if(mount(share_name, mountpoint, "cifs", flags, options)) {
1172 /* remember to kill daemon on error */
1173 char * tmp;
1175 switch (errno) {
1176 case 0:
1177 printf("mount failed but no error number set\n");
1178 break;
1179 case ENODEV:
1180 printf("mount error: cifs filesystem not supported by the system\n");
1181 break;
1182 case ENXIO:
1183 if(retry == 0) {
1184 retry = 1;
1185 tmp = share_name;
1186 while (*tmp && !(((unsigned char)tmp[0]) & 0x80)) {
1187 *tmp = toupper((unsigned char)*tmp);
1188 tmp++;
1190 if(!*tmp) {
1191 printf("retrying with upper case share name\n");
1192 goto mount_retry;
1195 default:
1197 printf("mount error %d = %s\n",errno,strerror(errno));
1199 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
1200 if(mountpassword) {
1201 memset(mountpassword,0,64);
1203 return -1;
1204 } else {
1205 pmntfile = setmntent(MOUNTED, "a+");
1206 if(pmntfile) {
1207 mountent.mnt_fsname = share_name;
1208 mountent.mnt_dir = mountpoint;
1209 mountent.mnt_type = "cifs";
1210 mountent.mnt_opts = malloc(220);
1211 if(mountent.mnt_opts) {
1212 char * mount_user = getusername();
1213 memset(mountent.mnt_opts,0,200);
1214 if(flags & MS_RDONLY)
1215 strcat(mountent.mnt_opts,"ro");
1216 else
1217 strcat(mountent.mnt_opts,"rw");
1218 if(flags & MS_MANDLOCK)
1219 strcat(mountent.mnt_opts,",mand");
1220 if(flags & MS_NOEXEC)
1221 strcat(mountent.mnt_opts,",noexec");
1222 if(flags & MS_NOSUID)
1223 strcat(mountent.mnt_opts,",nosuid");
1224 if(flags & MS_NODEV)
1225 strcat(mountent.mnt_opts,",nodev");
1226 if(flags & MS_SYNCHRONOUS)
1227 strcat(mountent.mnt_opts,",synch");
1228 if(mount_user) {
1229 if(getuid() != 0) {
1230 strcat(mountent.mnt_opts,",user=");
1231 strcat(mountent.mnt_opts,mount_user);
1233 free(mount_user);
1236 mountent.mnt_freq = 0;
1237 mountent.mnt_passno = 0;
1238 rc = addmntent(pmntfile,&mountent);
1239 endmntent(pmntfile);
1240 if(mountent.mnt_opts)
1241 free(mountent.mnt_opts);
1242 } else {
1243 printf("could not update mount table\n");
1246 if(mountpassword) {
1247 int len = strlen(mountpassword);
1248 memset(mountpassword,0,len);
1249 free(mountpassword);
1252 if(options) {
1253 memset(options,0,optlen);
1254 free(options);
1257 if(orgoptions) {
1258 memset(orgoptions,0,orgoptlen);
1259 free(orgoptions);
1261 if(resolved_path) {
1262 free(resolved_path);
1265 if(free_share_name) {
1266 free(share_name);
1268 return 0;