r14127: Remove coverity warning on mount.cifs.c
[Samba/nascimento.git] / source3 / client / mount.cifs.c
blob23a74d34fad2fe5398be2c93e621b5716db6a7fd
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 #define CONST_DISCARD(type, ptr) ((type) ((void *) (ptr)))
64 const char *thisprogram;
65 int verboseflag = 0;
66 static int got_password = 0;
67 static int got_user = 0;
68 static int got_domain = 0;
69 static int got_ip = 0;
70 static int got_unc = 0;
71 static int got_uid = 0;
72 static int got_gid = 0;
73 static int free_share_name = 0;
74 static char * user_name = NULL;
75 static char * mountpassword = NULL;
76 char * domain_name = NULL;
79 /* BB finish BB
81 cifs_umount
82 open nofollow - avoid symlink exposure?
83 get owner of dir see if matches self or if root
84 call system(umount argv) etc.
86 BB end finish BB */
88 static char * check_for_domain(char **);
91 static void mount_cifs_usage(void)
93 printf("\nUsage: %s <remotetarget> <dir> -o <options>\n", thisprogram);
94 printf("\nMount the remote target, specified as a UNC name,");
95 printf(" to a local directory.\n\nOptions:\n");
96 printf("\tuser=<arg>\n\tpass=<arg>\n\tdom=<arg>\n");
97 printf("\nLess commonly used options:");
98 printf("\n\tcredentials=<filename>,guest,perm,noperm,setuids,nosetuids,rw,ro,");
99 printf("\n\tsep=<char>,iocharset=<codepage>,suid,nosuid,exec,noexec,serverino,");
100 printf("\n\tdirectio,mapchars,nomapchars,nolock,servernetbiosname=<SRV_RFC1001NAME>");
101 printf("\n\nOptions not needed for servers supporting CIFS Unix extensions");
102 printf("\n\t(e.g. unneeded for mounts to most Samba versions):");
103 printf("\n\tuid=<uid>,gid=<gid>,dir_mode=<mode>,file_mode=<mode>,sfu");
104 printf("\n\nRarely used options:");
105 printf("\n\tport=<tcpport>,rsize=<size>,wsize=<size>,unc=<unc_name>,ip=<ip_address>,");
106 printf("\n\tdev,nodev,nouser_xattr,netbiosname=<OUR_RFC1001NAME>,hard,soft,intr,");
107 printf("\n\tnointr,ignorecase,noposixpaths,noacl");
108 printf("\n\nOptions are described in more detail in the manual page");
109 printf("\n\tman 8 mount.cifs\n");
110 printf("\nTo display the version number of the mount helper:");
111 printf("\n\t%s -V\n",thisprogram);
113 if(mountpassword) {
114 memset(mountpassword,0,64);
115 free(mountpassword);
117 exit(1);
120 /* caller frees username if necessary */
121 static char * getusername(void) {
122 char *username = NULL;
123 struct passwd *password = getpwuid(getuid());
125 if (password) {
126 username = password->pw_name;
128 return username;
131 static char * parse_cifs_url(char * unc_name)
133 printf("\nMounting cifs URL not implemented yet. Attempt to mount %s\n",unc_name);
134 return NULL;
137 static int open_cred_file(char * file_name)
139 char * line_buf;
140 char * temp_val;
141 FILE * fs;
142 int i, length;
143 fs = fopen(file_name,"r");
144 if(fs == NULL)
145 return errno;
146 line_buf = malloc(4096);
147 if(line_buf == NULL) {
148 fclose(fs);
149 return -ENOMEM;
152 while(fgets(line_buf,4096,fs)) {
153 /* parse line from credential file */
155 /* eat leading white space */
156 for(i=0;i<4086;i++) {
157 if((line_buf[i] != ' ') && (line_buf[i] != '\t'))
158 break;
159 /* if whitespace - skip past it */
161 if (strncasecmp("username",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<4087;length++) {
167 if(temp_val[length] == '\n')
168 break;
170 if(length > 4086) {
171 printf("mount.cifs failed due to malformed username in credentials file");
172 memset(line_buf,0,4096);
173 if(mountpassword) {
174 memset(mountpassword,0,64);
176 exit(1);
177 } else {
178 got_user = 1;
179 user_name = calloc(1 + length,1);
180 /* BB adding free of user_name string before exit,
181 not really necessary but would be cleaner */
182 strncpy(user_name,temp_val, length);
185 } else if (strncasecmp("password",line_buf+i,8) == 0) {
186 temp_val = strchr(line_buf+i,'=');
187 if(temp_val) {
188 /* go past equals sign */
189 temp_val++;
190 for(length = 0;length<65;length++) {
191 if(temp_val[length] == '\n')
192 break;
194 if(length > 64) {
195 printf("mount.cifs failed: password in credentials file too long\n");
196 memset(line_buf,0, 4096);
197 if(mountpassword) {
198 memset(mountpassword,0,64);
200 exit(1);
201 } else {
202 if(mountpassword == NULL) {
203 mountpassword = calloc(65,1);
204 } else
205 memset(mountpassword,0,64);
206 if(mountpassword) {
207 strncpy(mountpassword,temp_val,length);
208 got_password = 1;
212 } else if (strncasecmp("domain",line_buf+i,6) == 0) {
213 temp_val = strchr(line_buf+i,'=');
214 if(temp_val) {
215 /* go past equals sign */
216 temp_val++;
217 if(verboseflag)
218 printf("\nDomain %s\n",temp_val);
219 for(length = 0;length<65;length++) {
220 if(temp_val[length] == '\n')
221 break;
223 if(length > 64) {
224 printf("mount.cifs failed: domain in credentials file too long\n");
225 if(mountpassword) {
226 memset(mountpassword,0,64);
228 exit(1);
229 } else {
230 if(domain_name == NULL) {
231 domain_name = calloc(65,1);
232 } else
233 memset(domain_name,0,64);
234 if(domain_name) {
235 strncpy(domain_name,temp_val,length);
236 got_domain = 1;
243 fclose(fs);
244 if(line_buf) {
245 memset(line_buf,0,4096);
246 free(line_buf);
248 return 0;
251 static int get_password_from_file(int file_descript, char * filename)
253 int rc = 0;
254 int i;
255 char c;
257 if(mountpassword == NULL)
258 mountpassword = calloc(65,1);
259 else
260 memset(mountpassword, 0, 64);
262 if(filename != NULL) {
263 file_descript = open(filename, O_RDONLY);
264 if(file_descript < 0) {
265 printf("mount.cifs failed. %s attempting to open password file %s\n",
266 strerror(errno),filename);
267 exit(1);
270 /* else file already open and fd provided */
272 for(i=0;i<64;i++) {
273 rc = read(file_descript,&c,1);
274 if(rc < 0) {
275 printf("mount.cifs failed. Error %s reading password file\n",strerror(errno));
276 memset(mountpassword,0,64);
277 if(filename != NULL)
278 close(file_descript);
279 exit(1);
280 } else if(rc == 0) {
281 if(mountpassword[0] == 0) {
282 if(verboseflag)
283 printf("\nWarning: null password used since cifs password file empty");
285 break;
286 } else /* read valid character */ {
287 if((c == 0) || (c == '\n')) {
288 break;
289 } else
290 mountpassword[i] = c;
293 if((i == 64) && (verboseflag)) {
294 printf("\nWarning: password longer than 64 characters specified in cifs password file");
296 got_password = 1;
297 if(filename != NULL) {
298 close(file_descript);
301 return rc;
304 static int parse_options(char ** optionsp, int * filesys_flags)
306 const char * data;
307 char * percent_char = NULL;
308 char * value = NULL;
309 char * next_keyword = NULL;
310 char * out = NULL;
311 int out_len = 0;
312 int word_len;
313 int rc = 0;
315 if (!optionsp || !*optionsp)
316 return 1;
317 data = *optionsp;
319 if(verboseflag)
320 printf("parsing options: %s\n", data);
322 /* BB fixme check for separator override BB */
324 /* while ((data = strsep(&options, ",")) != NULL) { */
325 while(data != NULL) {
326 /* check if ends with trailing comma */
327 if(*data == 0)
328 break;
330 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
331 /* data = next keyword */
332 /* value = next value ie stuff after equal sign */
334 next_keyword = strchr(data,','); /* BB handle sep= */
336 /* temporarily null terminate end of keyword=value pair */
337 if(next_keyword)
338 *next_keyword++ = 0;
340 /* temporarily null terminate keyword to make keyword and value distinct */
341 if ((value = strchr(data, '=')) != NULL) {
342 *value = '\0';
343 value++;
346 if (strncmp(data, "users",5) == 0) {
347 if(!value || !*value) {
348 goto nocopy;
350 } else if (strncmp(data, "user_xattr",10) == 0) {
351 /* do nothing - need to skip so not parsed as user name */
352 } else if (strncmp(data, "user", 4) == 0) {
354 if (!value || !*value) {
355 if(data[4] == '\0') {
356 if(verboseflag)
357 printf("\nskipping empty user mount parameter\n");
358 /* remove the parm since it would otherwise be confusing
359 to the kernel code which would think it was a real username */
360 goto nocopy;
361 } else {
362 printf("username specified with no parameter\n");
363 return 1; /* needs_arg; */
365 } else {
366 if (strnlen(value, 260) < 260) {
367 got_user=1;
368 percent_char = strchr(value,'%');
369 if(percent_char) {
370 *percent_char = ',';
371 if(mountpassword == NULL)
372 mountpassword = calloc(65,1);
373 if(mountpassword) {
374 if(got_password)
375 printf("\nmount.cifs warning - password specified twice\n");
376 got_password = 1;
377 percent_char++;
378 strncpy(mountpassword, percent_char,64);
379 /* remove password from username */
380 while(*percent_char != 0) {
381 *percent_char = ',';
382 percent_char++;
386 /* this is only case in which the user
387 name buf is not malloc - so we have to
388 check for domain name embedded within
389 the user name here since the later
390 call to check_for_domain will not be
391 invoked */
392 domain_name = check_for_domain(&value);
393 } else {
394 printf("username too long\n");
395 return 1;
398 } else if (strncmp(data, "pass", 4) == 0) {
399 if (!value || !*value) {
400 if(got_password) {
401 printf("\npassword specified twice, ignoring second\n");
402 } else
403 got_password = 1;
404 } else if (strnlen(value, 17) < 17) {
405 if(got_password)
406 printf("\nmount.cifs warning - password specified twice\n");
407 got_password = 1;
408 } else {
409 printf("password too long\n");
410 return 1;
412 } else if (strncmp(data, "ip", 2) == 0) {
413 if (!value || !*value) {
414 printf("target ip address argument missing");
415 } else if (strnlen(value, 35) < 35) {
416 if(verboseflag)
417 printf("ip address %s override specified\n",value);
418 got_ip = 1;
419 } else {
420 printf("ip address too long\n");
421 return 1;
423 } else if ((strncmp(data, "unc", 3) == 0)
424 || (strncmp(data, "target", 6) == 0)
425 || (strncmp(data, "path", 4) == 0)) {
426 if (!value || !*value) {
427 printf("invalid path to network resource\n");
428 return 1; /* needs_arg; */
429 } else if(strnlen(value,5) < 5) {
430 printf("UNC name too short");
433 if (strnlen(value, 300) < 300) {
434 got_unc = 1;
435 if (strncmp(value, "//", 2) == 0) {
436 if(got_unc)
437 printf("unc name specified twice, ignoring second\n");
438 else
439 got_unc = 1;
440 } else if (strncmp(value, "\\\\", 2) != 0) {
441 printf("UNC Path does not begin with // or \\\\ \n");
442 return 1;
443 } else {
444 if(got_unc)
445 printf("unc name specified twice, ignoring second\n");
446 else
447 got_unc = 1;
449 } else {
450 printf("CIFS: UNC name too long\n");
451 return 1;
453 } else if ((strncmp(data, "domain", 3) == 0)
454 || (strncmp(data, "workgroup", 5) == 0)) {
455 if (!value || !*value) {
456 printf("CIFS: invalid domain name\n");
457 return 1; /* needs_arg; */
459 if (strnlen(value, 65) < 65) {
460 got_domain = 1;
461 } else {
462 printf("domain name too long\n");
463 return 1;
465 } else if (strncmp(data, "cred", 4) == 0) {
466 if (value && *value) {
467 rc = open_cred_file(value);
468 if(rc) {
469 printf("error %d opening credential file %s\n",rc, value);
470 return 1;
472 } else {
473 printf("invalid credential file name specified\n");
474 return 1;
476 } else if (strncmp(data, "uid", 3) == 0) {
477 if (value && *value) {
478 got_uid = 1;
479 if (!isdigit(*value)) {
480 struct passwd *pw;
481 static char temp[32];
483 if (!(pw = getpwnam(value))) {
484 printf("bad user name \"%s\"\n", value);
485 exit(1);
487 sprintf(temp, "%u", pw->pw_uid);
488 value = temp;
489 endpwent();
492 } else if (strncmp(data, "gid", 3) == 0) {
493 if (value && *value) {
494 got_gid = 1;
495 if (!isdigit(*value)) {
496 struct group *gr;
497 static char temp[32];
499 if (!(gr = getgrnam(value))) {
500 printf("bad group name \"%s\"\n", value);
501 exit(1);
503 sprintf(temp, "%u", gr->gr_gid);
504 value = temp;
505 endpwent();
508 /* fmask and dmask synonyms for people used to smbfs syntax */
509 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
510 if (!value || !*value) {
511 printf ("Option '%s' requires a numerical argument\n", data);
512 return 1;
515 if (value[0] != '0') {
516 printf ("WARNING: '%s' not expressed in octal.\n", data);
519 if (strcmp (data, "fmask") == 0) {
520 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
521 data = "file_mode"; /* BB fix this */
523 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
524 if (!value || !*value) {
525 printf ("Option '%s' requires a numerical argument\n", data);
526 return 1;
529 if (value[0] != '0') {
530 printf ("WARNING: '%s' not expressed in octal.\n", data);
533 if (strcmp (data, "dmask") == 0) {
534 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
535 data = "dir_mode";
537 /* the following eight mount options should be
538 stripped out from what is passed into the kernel
539 since these eight options are best passed as the
540 mount flags rather than redundantly to the kernel
541 and could generate spurious warnings depending on the
542 level of the corresponding cifs vfs kernel code */
543 } else if (strncmp(data, "nosuid", 6) == 0) {
544 *filesys_flags |= MS_NOSUID;
545 } else if (strncmp(data, "suid", 4) == 0) {
546 *filesys_flags &= ~MS_NOSUID;
547 } else if (strncmp(data, "nodev", 5) == 0) {
548 *filesys_flags |= MS_NODEV;
549 } else if ((strncmp(data, "nobrl", 5) == 0) ||
550 (strncmp(data, "nolock", 6) == 0)) {
551 *filesys_flags &= ~MS_MANDLOCK;
552 } else if (strncmp(data, "dev", 3) == 0) {
553 *filesys_flags &= ~MS_NODEV;
554 } else if (strncmp(data, "noexec", 6) == 0) {
555 *filesys_flags |= MS_NOEXEC;
556 } else if (strncmp(data, "exec", 4) == 0) {
557 *filesys_flags &= ~MS_NOEXEC;
558 } else if (strncmp(data, "guest", 5) == 0) {
559 got_password=1;
560 /* remove the parm since it would otherwise be logged by kern */
561 goto nocopy;
562 } else if (strncmp(data, "ro", 2) == 0) {
563 *filesys_flags |= MS_RDONLY;
564 } else if (strncmp(data, "rw", 2) == 0) {
565 *filesys_flags &= ~MS_RDONLY;
566 } else if (strncmp(data, "remount", 7) == 0) {
567 *filesys_flags |= MS_REMOUNT;
568 } /* else if (strnicmp(data, "port", 4) == 0) {
569 if (value && *value) {
570 vol->port =
571 simple_strtoul(value, &value, 0);
573 } else if (strnicmp(data, "rsize", 5) == 0) {
574 if (value && *value) {
575 vol->rsize =
576 simple_strtoul(value, &value, 0);
578 } else if (strnicmp(data, "wsize", 5) == 0) {
579 if (value && *value) {
580 vol->wsize =
581 simple_strtoul(value, &value, 0);
583 } else if (strnicmp(data, "version", 3) == 0) {
584 } else {
585 printf("CIFS: Unknown mount option %s\n",data);
586 } */ /* nothing to do on those four mount options above.
587 Just pass to kernel and ignore them here */
589 /* Copy (possibly modified) option to out */
590 word_len = strlen(data);
591 if (value)
592 word_len += 1 + strlen(value);
594 out = realloc(out, out_len + word_len + 2);
595 if (out == NULL) {
596 perror("malloc");
597 exit(1);
600 if (out_len)
601 out[out_len++] = ',';
602 if (value)
603 sprintf(out + out_len, "%s=%s", data, value);
604 else
605 sprintf(out + out_len, "%s", data);
606 out_len = strlen(out);
608 nocopy:
609 data = next_keyword;
611 *optionsp = out;
612 return 0;
615 /* replace all (one or more) commas with double commas */
616 static void check_for_comma(char ** ppasswrd)
618 char *new_pass_buf;
619 char *pass;
620 int i,j;
621 int number_of_commas = 0;
622 int len;
624 if(ppasswrd == NULL)
625 return;
626 else
627 (pass = *ppasswrd);
629 len = strlen(pass);
631 for(i=0;i<len;i++) {
632 if(pass[i] == ',')
633 number_of_commas++;
636 if(number_of_commas == 0)
637 return;
638 if(number_of_commas > 64) {
639 /* would otherwise overflow the mount options buffer */
640 printf("\nInvalid password. Password contains too many commas.\n");
641 return;
644 new_pass_buf = malloc(len+number_of_commas+1);
645 if(new_pass_buf == NULL)
646 return;
648 for(i=0,j=0;i<len;i++,j++) {
649 new_pass_buf[j] = pass[i];
650 if(pass[i] == ',') {
651 j++;
652 new_pass_buf[j] = pass[i];
655 new_pass_buf[len+number_of_commas] = 0;
657 free(*ppasswrd);
658 *ppasswrd = new_pass_buf;
660 return;
663 /* Usernames can not have backslash in them and we use
664 [BB check if usernames can have forward slash in them BB]
665 backslash as domain\user separator character
667 static char * check_for_domain(char **ppuser)
669 char * original_string;
670 char * usernm;
671 char * domainnm;
672 int original_len;
673 int len;
674 int i;
676 if(ppuser == NULL)
677 return NULL;
679 original_string = *ppuser;
681 if (original_string == NULL)
682 return NULL;
684 original_len = strlen(original_string);
686 usernm = strchr(*ppuser,'/');
687 if (usernm == NULL) {
688 usernm = strchr(*ppuser,'\\');
689 if (usernm == NULL)
690 return NULL;
693 if(got_domain) {
694 printf("Domain name specified twice. Username probably malformed\n");
695 return NULL;
698 usernm[0] = 0;
699 domainnm = *ppuser;
700 if (domainnm[0] != 0) {
701 got_domain = 1;
702 } else {
703 printf("null domain\n");
705 len = strlen(domainnm);
706 /* reset domainm to new buffer, and copy
707 domain name into it */
708 domainnm = malloc(len+1);
709 if(domainnm == NULL)
710 return NULL;
712 strcpy(domainnm,*ppuser);
714 /* move_string(*ppuser, usernm+1) */
715 len = strlen(usernm+1);
717 if(len >= original_len) {
718 /* should not happen */
719 return domainnm;
722 for(i=0;i<original_len;i++) {
723 if(i<len)
724 original_string[i] = usernm[i+1];
725 else /* stuff with commas to remove last parm */
726 original_string[i] = ',';
729 /* BB add check for more than one slash?
730 strchr(*ppuser,'/');
731 strchr(*ppuser,'\\')
734 return domainnm;
737 /* Note that caller frees the returned buffer if necessary */
738 static char * parse_server(char ** punc_name)
740 char * unc_name = *punc_name;
741 int length = strnlen(unc_name,1024);
742 char * share;
743 char * ipaddress_string = NULL;
744 struct hostent * host_entry = NULL;
745 struct in_addr server_ipaddr;
747 if(length > 1023) {
748 printf("mount error: UNC name too long");
749 return NULL;
751 if (strncasecmp("cifs://",unc_name,7) == 0)
752 return parse_cifs_url(unc_name+7);
753 if (strncasecmp("smb://",unc_name,6) == 0) {
754 return parse_cifs_url(unc_name+6);
757 if(length < 3) {
758 /* BB add code to find DFS root here */
759 printf("\nMounting the DFS root for domain not implemented yet\n");
760 return NULL;
761 } else {
762 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
763 /* check for nfs syntax ie server:share */
764 share = strchr(unc_name,':');
765 if(share) {
766 free_share_name = 1;
767 *punc_name = malloc(length+3);
768 if(*punc_name == NULL) {
769 /* put the original string back if
770 no memory left */
771 *punc_name = unc_name;
772 return NULL;
775 *share = '/';
776 strncpy((*punc_name)+2,unc_name,length);
777 unc_name = *punc_name;
778 unc_name[length+2] = 0;
779 goto continue_unc_parsing;
780 } else {
781 printf("mount error: improperly formatted UNC name.");
782 printf(" %s does not begin with \\\\ or //\n",unc_name);
783 return NULL;
785 } else {
786 continue_unc_parsing:
787 unc_name[0] = '/';
788 unc_name[1] = '/';
789 unc_name += 2;
790 if ((share = strchr(unc_name, '/')) ||
791 (share = strchr(unc_name,'\\'))) {
792 *share = 0; /* temporarily terminate the string */
793 share += 1;
794 if(got_ip == 0) {
795 host_entry = gethostbyname(unc_name);
797 *(share - 1) = '/'; /* put the slash back */
798 if(got_ip) {
799 if(verboseflag)
800 printf("ip address specified explicitly\n");
801 return NULL;
803 if(host_entry == NULL) {
804 printf("mount error: could not find target server. TCP name %s not found\n", unc_name);
805 return NULL;
806 } else {
807 /* BB should we pass an alternate version of the share name as Unicode */
808 /* BB what about ipv6? BB */
809 /* BB add retries with alternate servers in list */
811 memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
813 ipaddress_string = inet_ntoa(server_ipaddr);
814 if(ipaddress_string == NULL) {
815 printf("mount error: could not get valid ip address for target server\n");
816 return NULL;
818 return ipaddress_string;
820 } else {
821 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
822 printf("Mounting the DFS root for a particular server not implemented yet\n");
823 return NULL;
829 static struct option longopts[] = {
830 { "all", 0, NULL, 'a' },
831 { "help",0, NULL, 'h' },
832 { "move",0, NULL, 'm' },
833 { "bind",0, NULL, 'b' },
834 { "read-only", 0, NULL, 'r' },
835 { "ro", 0, NULL, 'r' },
836 { "verbose", 0, NULL, 'v' },
837 { "version", 0, NULL, 'V' },
838 { "read-write", 0, NULL, 'w' },
839 { "rw", 0, NULL, 'w' },
840 { "options", 1, NULL, 'o' },
841 { "type", 1, NULL, 't' },
842 { "rsize",1, NULL, 'R' },
843 { "wsize",1, NULL, 'W' },
844 { "uid", 1, NULL, '1'},
845 { "gid", 1, NULL, '2'},
846 { "user",1,NULL,'u'},
847 { "username",1,NULL,'u'},
848 { "dom",1,NULL,'d'},
849 { "domain",1,NULL,'d'},
850 { "password",1,NULL,'p'},
851 { "pass",1,NULL,'p'},
852 { "credentials",1,NULL,'c'},
853 { "port",1,NULL,'P'},
854 /* { "uuid",1,NULL,'U'}, */ /* BB unimplemented */
855 { NULL, 0, NULL, 0 }
858 int main(int argc, char ** argv)
860 int c;
861 int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
862 char * orgoptions = NULL;
863 char * share_name = NULL;
864 char * ipaddr = NULL;
865 char * uuid = NULL;
866 char * mountpoint = NULL;
867 char * options;
868 char * resolved_path;
869 char * temp;
870 int rc;
871 int rsize = 0;
872 int wsize = 0;
873 int nomtab = 0;
874 int uid = 0;
875 int gid = 0;
876 int optlen = 0;
877 int orgoptlen = 0;
878 int retry = 0; /* set when we have to retry mount with uppercase */
879 struct stat statbuf;
880 struct utsname sysinfo;
881 struct mntent mountent;
882 FILE * pmntfile;
884 /* setlocale(LC_ALL, "");
885 bindtextdomain(PACKAGE, LOCALEDIR);
886 textdomain(PACKAGE); */
888 if(argc && argv) {
889 thisprogram = argv[0];
890 } else {
891 mount_cifs_usage();
892 exit(1);
895 if(thisprogram == NULL)
896 thisprogram = "mount.cifs";
898 uname(&sysinfo);
899 /* BB add workstation name and domain and pass down */
901 /* #ifdef _GNU_SOURCE
902 printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
903 #endif */
904 if(argc > 2) {
905 share_name = argv[1];
906 mountpoint = argv[2];
909 /* add sharename in opts string as unc= parm */
911 while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
912 longopts, NULL)) != -1) {
913 switch (c) {
914 /* No code to do the following options yet */
915 /* case 'l':
916 list_with_volumelabel = 1;
917 break;
918 case 'L':
919 volumelabel = optarg;
920 break; */
921 /* case 'a':
922 ++mount_all;
923 break; */
925 case '?':
926 case 'h': /* help */
927 mount_cifs_usage ();
928 exit(1);
929 case 'n':
930 ++nomtab;
931 break;
932 case 'b':
933 flags |= MS_BIND;
934 break;
935 case 'm':
936 flags |= MS_MOVE;
937 break;
938 case 'o':
939 orgoptions = strdup(optarg);
940 break;
941 case 'r': /* mount readonly */
942 flags |= MS_RDONLY;
943 break;
944 case 'U':
945 uuid = optarg;
946 break;
947 case 'v':
948 ++verboseflag;
949 break;
950 case 'V':
951 printf ("mount.cifs version: %s.%s%s\n",
952 MOUNT_CIFS_VERSION_MAJOR,
953 MOUNT_CIFS_VERSION_MINOR,
954 MOUNT_CIFS_VENDOR_SUFFIX);
955 if(mountpassword) {
956 memset(mountpassword,0,64);
958 exit (0);
959 case 'w':
960 flags &= ~MS_RDONLY;
961 break;
962 case 'R':
963 rsize = atoi(optarg) ;
964 break;
965 case 'W':
966 wsize = atoi(optarg);
967 break;
968 case '1':
969 if (isdigit(*optarg)) {
970 char *ep;
972 uid = strtoul(optarg, &ep, 10);
973 if (*ep) {
974 printf("bad uid value \"%s\"\n", optarg);
975 exit(1);
977 } else {
978 struct passwd *pw;
980 if (!(pw = getpwnam(optarg))) {
981 printf("bad user name \"%s\"\n", optarg);
982 exit(1);
984 uid = pw->pw_uid;
985 endpwent();
987 break;
988 case '2':
989 if (isdigit(*optarg)) {
990 char *ep;
992 gid = strtoul(optarg, &ep, 10);
993 if (*ep) {
994 printf("bad gid value \"%s\"\n", optarg);
995 exit(1);
997 } else {
998 struct group *gr;
1000 if (!(gr = getgrnam(optarg))) {
1001 printf("bad user name \"%s\"\n", optarg);
1002 exit(1);
1004 gid = gr->gr_gid;
1005 endpwent();
1007 break;
1008 case 'u':
1009 got_user = 1;
1010 user_name = optarg;
1011 break;
1012 case 'd':
1013 domain_name = optarg; /* BB fix this - currently ignored */
1014 got_domain = 1;
1015 break;
1016 case 'p':
1017 if(mountpassword == NULL)
1018 mountpassword = calloc(65,1);
1019 if(mountpassword) {
1020 got_password = 1;
1021 strncpy(mountpassword,optarg,64);
1023 break;
1024 case 'S':
1025 get_password_from_file(0 /* stdin */,NULL);
1026 break;
1027 case 't':
1028 break;
1029 default:
1030 printf("unknown mount option %c\n",c);
1031 mount_cifs_usage();
1032 exit(1);
1036 if((argc < 3) || (share_name == NULL) || (mountpoint == NULL)) {
1037 mount_cifs_usage();
1038 exit(1);
1041 if (getenv("PASSWD")) {
1042 if(mountpassword == NULL)
1043 mountpassword = calloc(65,1);
1044 if(mountpassword) {
1045 strncpy(mountpassword,getenv("PASSWD"),64);
1046 got_password = 1;
1048 } else if (getenv("PASSWD_FD")) {
1049 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
1050 } else if (getenv("PASSWD_FILE")) {
1051 get_password_from_file(0, getenv("PASSWD_FILE"));
1054 if (orgoptions && parse_options(&orgoptions, &flags))
1055 return -1;
1056 ipaddr = parse_server(&share_name);
1057 if((ipaddr == NULL) && (got_ip == 0)) {
1058 printf("No ip address specified and hostname not found\n");
1059 return -1;
1062 /* BB save off path and pop after mount returns? */
1063 resolved_path = malloc(PATH_MAX+1);
1064 if(resolved_path) {
1065 /* Note that if we can not canonicalize the name, we get
1066 another chance to see if it is valid when we chdir to it */
1067 if (realpath(mountpoint, resolved_path)) {
1068 mountpoint = resolved_path;
1071 if(chdir(mountpoint)) {
1072 printf("mount error: can not change directory into mount target %s\n",mountpoint);
1073 return -1;
1076 if(stat (".", &statbuf)) {
1077 printf("mount error: mount point %s does not exist\n",mountpoint);
1078 return -1;
1081 if (S_ISDIR(statbuf.st_mode) == 0) {
1082 printf("mount error: mount point %s is not a directory\n",mountpoint);
1083 return -1;
1086 if((getuid() != 0) && (geteuid() == 0)) {
1087 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
1088 #ifndef CIFS_ALLOW_USR_SUID
1089 /* Do not allow user mounts to control suid flag
1090 for mount unless explicitly built that way */
1091 flags |= MS_NOSUID | MS_NODEV;
1092 #endif
1093 } else {
1094 printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n");
1095 return -1;
1099 if(got_user == 0) {
1100 user_name = getusername();
1101 got_user = 1;
1104 if(got_password == 0) {
1105 mountpassword = getpass("Password: "); /* BB obsolete */
1106 got_password = 1;
1108 /* FIXME launch daemon (handles dfs name resolution and credential change)
1109 remember to clear parms and overwrite password field before launching */
1110 mount_retry:
1111 if(orgoptions) {
1112 optlen = strlen(orgoptions);
1113 orgoptlen = optlen;
1114 } else
1115 optlen = 0;
1116 if(share_name)
1117 optlen += strlen(share_name) + 4;
1118 else {
1119 printf("No server share name specified\n");
1120 printf("\nMounting the DFS root for server not implemented yet\n");
1121 exit(1);
1123 if(user_name)
1124 optlen += strlen(user_name) + 6;
1125 if(ipaddr)
1126 optlen += strlen(ipaddr) + 4;
1127 if(mountpassword)
1128 optlen += strlen(mountpassword) + 6;
1129 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 */);
1131 if(options == NULL) {
1132 printf("Could not allocate memory for mount options\n");
1133 return -1;
1137 options[0] = 0;
1138 strncat(options,"unc=",4);
1139 strcat(options,share_name);
1140 /* scan backwards and reverse direction of slash */
1141 temp = strrchr(options, '/');
1142 if(temp > options + 6)
1143 *temp = '\\';
1144 if(ipaddr) {
1145 strncat(options,",ip=",4);
1146 strcat(options,ipaddr);
1149 if(user_name) {
1150 /* check for syntax like user=domain\user */
1151 if(got_domain == 0)
1152 domain_name = check_for_domain(&user_name);
1153 strncat(options,",user=",6);
1154 strcat(options,user_name);
1156 if(retry == 0) {
1157 if(domain_name) {
1158 /* extra length accounted for in option string above */
1159 strncat(options,",domain=",8);
1160 strcat(options,domain_name);
1163 if(mountpassword) {
1164 /* Commas have to be doubled, or else they will
1165 look like the parameter separator */
1166 /* if(sep is not set)*/
1167 if(retry == 0)
1168 check_for_comma(&mountpassword);
1169 strncat(options,",pass=",6);
1170 strcat(options,mountpassword);
1173 strncat(options,",ver=",5);
1174 strcat(options,MOUNT_CIFS_VERSION_MAJOR);
1176 if(orgoptions) {
1177 strcat(options,",");
1178 strcat(options,orgoptions);
1180 if(verboseflag)
1181 printf("\nmount.cifs kernel mount options %s \n",options);
1182 if(mount(share_name, mountpoint, "cifs", flags, options)) {
1183 /* remember to kill daemon on error */
1184 char * tmp;
1186 switch (errno) {
1187 case 0:
1188 printf("mount failed but no error number set\n");
1189 break;
1190 case ENODEV:
1191 printf("mount error: cifs filesystem not supported by the system\n");
1192 break;
1193 case ENXIO:
1194 if(retry == 0) {
1195 retry = 1;
1196 tmp = share_name;
1197 while (*tmp && !(((unsigned char)tmp[0]) & 0x80)) {
1198 *tmp = toupper((unsigned char)*tmp);
1199 tmp++;
1201 if(!*tmp) {
1202 printf("retrying with upper case share name\n");
1203 goto mount_retry;
1206 default:
1208 printf("mount error %d = %s\n",errno,strerror(errno));
1210 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
1211 if(mountpassword) {
1212 memset(mountpassword,0,64);
1214 return -1;
1215 } else {
1216 pmntfile = setmntent(MOUNTED, "a+");
1217 if(pmntfile) {
1218 mountent.mnt_fsname = share_name;
1219 mountent.mnt_dir = mountpoint;
1220 mountent.mnt_type = CONST_DISCARD(char *,"cifs");
1221 mountent.mnt_opts = malloc(220);
1222 if(mountent.mnt_opts) {
1223 char * mount_user = getusername();
1224 memset(mountent.mnt_opts,0,200);
1225 if(flags & MS_RDONLY)
1226 strcat(mountent.mnt_opts,"ro");
1227 else
1228 strcat(mountent.mnt_opts,"rw");
1229 if(flags & MS_MANDLOCK)
1230 strcat(mountent.mnt_opts,",mand");
1231 if(flags & MS_NOEXEC)
1232 strcat(mountent.mnt_opts,",noexec");
1233 if(flags & MS_NOSUID)
1234 strcat(mountent.mnt_opts,",nosuid");
1235 if(flags & MS_NODEV)
1236 strcat(mountent.mnt_opts,",nodev");
1237 if(flags & MS_SYNCHRONOUS)
1238 strcat(mountent.mnt_opts,",synch");
1239 if(mount_user) {
1240 if(getuid() != 0) {
1241 strcat(mountent.mnt_opts,",user=");
1242 strcat(mountent.mnt_opts,mount_user);
1244 free(mount_user);
1247 mountent.mnt_freq = 0;
1248 mountent.mnt_passno = 0;
1249 rc = addmntent(pmntfile,&mountent);
1250 endmntent(pmntfile);
1251 if(mountent.mnt_opts)
1252 free(mountent.mnt_opts);
1253 } else {
1254 printf("could not update mount table\n");
1257 if(mountpassword) {
1258 int len = strlen(mountpassword);
1259 memset(mountpassword,0,len);
1260 free(mountpassword);
1263 if(options) {
1264 memset(options,0,optlen);
1265 free(options);
1268 if(orgoptions) {
1269 memset(orgoptions,0,orgoptlen);
1270 free(orgoptions);
1272 if(resolved_path) {
1273 free(resolved_path);
1276 if(free_share_name) {
1277 free(share_name);
1279 return 0;