[GLUE] Rsync SAMBA_3_2_0 SVN r25598 in order to create the v3-2-test branch.
[Samba/gebeck_regimport.git] / source3 / client / mount.cifs.c
blobeb45ae5b4a038ed2ff76a4bce6fd09971e50c1b6
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 3 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, see <http://www.gnu.org/licenses/>. */
18 #ifndef _GNU_SOURCE
19 #define _GNU_SOURCE
20 #endif
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <pwd.h>
26 #include <grp.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 "10"
44 #ifndef MOUNT_CIFS_VENDOR_SUFFIX
45 #ifdef _SAMBA_BUILD_
46 #include "include/version.h"
47 #ifdef SAMBA_VERSION_VENDOR_SUFFIX
48 #define MOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING"-"SAMBA_VERSION_VENDOR_SUFFIX
49 #else
50 #define MOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING
51 #endif /* SAMBA_VERSION_OFFICIAL_STRING and SAMBA_VERSION_VENDOR_SUFFIX */
52 #else
53 #define MOUNT_CIFS_VENDOR_SUFFIX ""
54 #endif /* _SAMBA_BUILD_ */
55 #endif /* MOUNT_CIFS_VENDOR_SUFFIX */
57 #ifndef MS_MOVE
58 #define MS_MOVE 8192
59 #endif
61 #ifndef MS_BIND
62 #define MS_BIND 4096
63 #endif
65 #define CONST_DISCARD(type, ptr) ((type) ((void *) (ptr)))
67 const char *thisprogram;
68 int verboseflag = 0;
69 static int got_password = 0;
70 static int got_user = 0;
71 static int got_domain = 0;
72 static int got_ip = 0;
73 static int got_unc = 0;
74 static int got_uid = 0;
75 static int got_gid = 0;
76 static int free_share_name = 0;
77 static char * user_name = NULL;
78 static char * mountpassword = NULL;
79 char * domain_name = NULL;
80 char * prefixpath = NULL;
83 /* BB finish BB
85 cifs_umount
86 open nofollow - avoid symlink exposure?
87 get owner of dir see if matches self or if root
88 call system(umount argv) etc.
90 BB end finish BB */
92 static char * check_for_domain(char **);
95 static void mount_cifs_usage(void)
97 printf("\nUsage: %s <remotetarget> <dir> -o <options>\n", thisprogram);
98 printf("\nMount the remote target, specified as a UNC name,");
99 printf(" to a local directory.\n\nOptions:\n");
100 printf("\tuser=<arg>\n\tpass=<arg>\n\tdom=<arg>\n");
101 printf("\nLess commonly used options:");
102 printf("\n\tcredentials=<filename>,guest,perm,noperm,setuids,nosetuids,rw,ro,");
103 printf("\n\tsep=<char>,iocharset=<codepage>,suid,nosuid,exec,noexec,serverino,");
104 printf("\n\tdirectio,mapchars,nomapchars,nolock,servernetbiosname=<SRV_RFC1001NAME>");
105 printf("\n\nOptions not needed for servers supporting CIFS Unix extensions");
106 printf("\n\t(e.g. unneeded for mounts to most Samba versions):");
107 printf("\n\tuid=<uid>,gid=<gid>,dir_mode=<mode>,file_mode=<mode>,sfu");
108 printf("\n\nRarely used options:");
109 printf("\n\tport=<tcpport>,rsize=<size>,wsize=<size>,unc=<unc_name>,ip=<ip_address>,");
110 printf("\n\tdev,nodev,nouser_xattr,netbiosname=<OUR_RFC1001NAME>,hard,soft,intr,");
111 printf("\n\tnointr,ignorecase,noposixpaths,noacl");
112 printf("\n\nOptions are described in more detail in the manual page");
113 printf("\n\tman 8 mount.cifs\n");
114 printf("\nTo display the version number of the mount helper:");
115 printf("\n\t%s -V\n",thisprogram);
117 if(mountpassword) {
118 memset(mountpassword,0,64);
119 free(mountpassword);
121 exit(1);
124 /* caller frees username if necessary */
125 static char * getusername(void) {
126 char *username = NULL;
127 struct passwd *password = getpwuid(getuid());
129 if (password) {
130 username = password->pw_name;
132 return username;
135 static char * parse_cifs_url(char * unc_name)
137 printf("\nMounting cifs URL not implemented yet. Attempt to mount %s\n",unc_name);
138 return NULL;
141 static int open_cred_file(char * file_name)
143 char * line_buf;
144 char * temp_val;
145 FILE * fs;
146 int i, length;
147 fs = fopen(file_name,"r");
148 if(fs == NULL)
149 return errno;
150 line_buf = (char *)malloc(4096);
151 if(line_buf == NULL) {
152 fclose(fs);
153 return -ENOMEM;
156 while(fgets(line_buf,4096,fs)) {
157 /* parse line from credential file */
159 /* eat leading white space */
160 for(i=0;i<4086;i++) {
161 if((line_buf[i] != ' ') && (line_buf[i] != '\t'))
162 break;
163 /* if whitespace - skip past it */
165 if (strncasecmp("username",line_buf+i,8) == 0) {
166 temp_val = strchr(line_buf + i,'=');
167 if(temp_val) {
168 /* go past equals sign */
169 temp_val++;
170 for(length = 0;length<4087;length++) {
171 if(temp_val[length] == '\n')
172 break;
174 if(length > 4086) {
175 printf("mount.cifs failed due to malformed username in credentials file");
176 memset(line_buf,0,4096);
177 if(mountpassword) {
178 memset(mountpassword,0,64);
180 exit(1);
181 } else {
182 got_user = 1;
183 user_name = (char *)calloc(1 + length,1);
184 /* BB adding free of user_name string before exit,
185 not really necessary but would be cleaner */
186 strncpy(user_name,temp_val, length);
189 } else if (strncasecmp("password",line_buf+i,8) == 0) {
190 temp_val = strchr(line_buf+i,'=');
191 if(temp_val) {
192 /* go past equals sign */
193 temp_val++;
194 for(length = 0;length<65;length++) {
195 if(temp_val[length] == '\n')
196 break;
198 if(length > 64) {
199 printf("mount.cifs failed: password in credentials file too long\n");
200 memset(line_buf,0, 4096);
201 if(mountpassword) {
202 memset(mountpassword,0,64);
204 exit(1);
205 } else {
206 if(mountpassword == NULL) {
207 mountpassword = (char *)calloc(65,1);
208 } else
209 memset(mountpassword,0,64);
210 if(mountpassword) {
211 strncpy(mountpassword,temp_val,length);
212 got_password = 1;
216 } else if (strncasecmp("domain",line_buf+i,6) == 0) {
217 temp_val = strchr(line_buf+i,'=');
218 if(temp_val) {
219 /* go past equals sign */
220 temp_val++;
221 if(verboseflag)
222 printf("\nDomain %s\n",temp_val);
223 for(length = 0;length<65;length++) {
224 if(temp_val[length] == '\n')
225 break;
227 if(length > 64) {
228 printf("mount.cifs failed: domain in credentials file too long\n");
229 if(mountpassword) {
230 memset(mountpassword,0,64);
232 exit(1);
233 } else {
234 if(domain_name == NULL) {
235 domain_name = (char *)calloc(65,1);
236 } else
237 memset(domain_name,0,64);
238 if(domain_name) {
239 strncpy(domain_name,temp_val,length);
240 got_domain = 1;
247 fclose(fs);
248 if(line_buf) {
249 memset(line_buf,0,4096);
250 free(line_buf);
252 return 0;
255 static int get_password_from_file(int file_descript, char * filename)
257 int rc = 0;
258 int i;
259 char c;
261 if(mountpassword == NULL)
262 mountpassword = (char *)calloc(65,1);
263 else
264 memset(mountpassword, 0, 64);
266 if (mountpassword == NULL) {
267 printf("malloc failed\n");
268 exit(1);
271 if(filename != NULL) {
272 file_descript = open(filename, O_RDONLY);
273 if(file_descript < 0) {
274 printf("mount.cifs failed. %s attempting to open password file %s\n",
275 strerror(errno),filename);
276 exit(1);
279 /* else file already open and fd provided */
281 for(i=0;i<64;i++) {
282 rc = read(file_descript,&c,1);
283 if(rc < 0) {
284 printf("mount.cifs failed. Error %s reading password file\n",strerror(errno));
285 memset(mountpassword,0,64);
286 if(filename != NULL)
287 close(file_descript);
288 exit(1);
289 } else if(rc == 0) {
290 if(mountpassword[0] == 0) {
291 if(verboseflag)
292 printf("\nWarning: null password used since cifs password file empty");
294 break;
295 } else /* read valid character */ {
296 if((c == 0) || (c == '\n')) {
297 break;
298 } else
299 mountpassword[i] = c;
302 if((i == 64) && (verboseflag)) {
303 printf("\nWarning: password longer than 64 characters specified in cifs password file");
305 got_password = 1;
306 if(filename != NULL) {
307 close(file_descript);
310 return rc;
313 static int parse_options(char ** optionsp, int * filesys_flags)
315 const char * data;
316 char * percent_char = NULL;
317 char * value = NULL;
318 char * next_keyword = NULL;
319 char * out = NULL;
320 int out_len = 0;
321 int word_len;
322 int rc = 0;
324 if (!optionsp || !*optionsp)
325 return 1;
326 data = *optionsp;
328 if(verboseflag)
329 printf("parsing options: %s\n", data);
331 /* BB fixme check for separator override BB */
333 /* while ((data = strsep(&options, ",")) != NULL) { */
334 while(data != NULL) {
335 /* check if ends with trailing comma */
336 if(*data == 0)
337 break;
339 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
340 /* data = next keyword */
341 /* value = next value ie stuff after equal sign */
343 next_keyword = strchr(data,','); /* BB handle sep= */
345 /* temporarily null terminate end of keyword=value pair */
346 if(next_keyword)
347 *next_keyword++ = 0;
349 /* temporarily null terminate keyword to make keyword and value distinct */
350 if ((value = strchr(data, '=')) != NULL) {
351 *value = '\0';
352 value++;
355 if (strncmp(data, "users",5) == 0) {
356 if(!value || !*value) {
357 goto nocopy;
359 } else if (strncmp(data, "user_xattr",10) == 0) {
360 /* do nothing - need to skip so not parsed as user name */
361 } else if (strncmp(data, "user", 4) == 0) {
363 if (!value || !*value) {
364 if(data[4] == '\0') {
365 if(verboseflag)
366 printf("\nskipping empty user mount parameter\n");
367 /* remove the parm since it would otherwise be confusing
368 to the kernel code which would think it was a real username */
369 goto nocopy;
370 } else {
371 printf("username specified with no parameter\n");
372 return 1; /* needs_arg; */
374 } else {
375 if (strnlen(value, 260) < 260) {
376 got_user=1;
377 percent_char = strchr(value,'%');
378 if(percent_char) {
379 *percent_char = ',';
380 if(mountpassword == NULL)
381 mountpassword = (char *)calloc(65,1);
382 if(mountpassword) {
383 if(got_password)
384 printf("\nmount.cifs warning - password specified twice\n");
385 got_password = 1;
386 percent_char++;
387 strncpy(mountpassword, percent_char,64);
388 /* remove password from username */
389 while(*percent_char != 0) {
390 *percent_char = ',';
391 percent_char++;
395 /* this is only case in which the user
396 name buf is not malloc - so we have to
397 check for domain name embedded within
398 the user name here since the later
399 call to check_for_domain will not be
400 invoked */
401 domain_name = check_for_domain(&value);
402 } else {
403 printf("username too long\n");
404 return 1;
407 } else if (strncmp(data, "pass", 4) == 0) {
408 if (!value || !*value) {
409 if(got_password) {
410 printf("\npassword specified twice, ignoring second\n");
411 } else
412 got_password = 1;
413 } else if (strnlen(value, 17) < 17) {
414 if(got_password)
415 printf("\nmount.cifs warning - password specified twice\n");
416 got_password = 1;
417 } else {
418 printf("password too long\n");
419 return 1;
421 } else if (strncmp(data, "sec", 3) == 0) {
422 if (value) {
423 if (!strcmp(value, "none"))
424 got_password = 1;
426 } else if (strncmp(data, "ip", 2) == 0) {
427 if (!value || !*value) {
428 printf("target ip address argument missing");
429 } else if (strnlen(value, 35) < 35) {
430 if(verboseflag)
431 printf("ip address %s override specified\n",value);
432 got_ip = 1;
433 } else {
434 printf("ip address too long\n");
435 return 1;
437 } else if ((strncmp(data, "unc", 3) == 0)
438 || (strncmp(data, "target", 6) == 0)
439 || (strncmp(data, "path", 4) == 0)) {
440 if (!value || !*value) {
441 printf("invalid path to network resource\n");
442 return 1; /* needs_arg; */
443 } else if(strnlen(value,5) < 5) {
444 printf("UNC name too short");
447 if (strnlen(value, 300) < 300) {
448 got_unc = 1;
449 if (strncmp(value, "//", 2) == 0) {
450 if(got_unc)
451 printf("unc name specified twice, ignoring second\n");
452 else
453 got_unc = 1;
454 } else if (strncmp(value, "\\\\", 2) != 0) {
455 printf("UNC Path does not begin with // or \\\\ \n");
456 return 1;
457 } else {
458 if(got_unc)
459 printf("unc name specified twice, ignoring second\n");
460 else
461 got_unc = 1;
463 } else {
464 printf("CIFS: UNC name too long\n");
465 return 1;
467 } else if ((strncmp(data, "domain", 3) == 0)
468 || (strncmp(data, "workgroup", 5) == 0)) {
469 if (!value || !*value) {
470 printf("CIFS: invalid domain name\n");
471 return 1; /* needs_arg; */
473 if (strnlen(value, 65) < 65) {
474 got_domain = 1;
475 } else {
476 printf("domain name too long\n");
477 return 1;
479 } else if (strncmp(data, "cred", 4) == 0) {
480 if (value && *value) {
481 rc = open_cred_file(value);
482 if(rc) {
483 printf("error %d opening credential file %s\n",rc, value);
484 return 1;
486 } else {
487 printf("invalid credential file name specified\n");
488 return 1;
490 } else if (strncmp(data, "uid", 3) == 0) {
491 if (value && *value) {
492 got_uid = 1;
493 if (!isdigit(*value)) {
494 struct passwd *pw;
495 static char temp[32];
497 if (!(pw = getpwnam(value))) {
498 printf("bad user name \"%s\"\n", value);
499 exit(1);
501 sprintf(temp, "%u", pw->pw_uid);
502 value = temp;
503 endpwent();
506 } else if (strncmp(data, "gid", 3) == 0) {
507 if (value && *value) {
508 got_gid = 1;
509 if (!isdigit(*value)) {
510 struct group *gr;
511 static char temp[32];
513 if (!(gr = getgrnam(value))) {
514 printf("bad group name \"%s\"\n", value);
515 exit(1);
517 sprintf(temp, "%u", gr->gr_gid);
518 value = temp;
519 endpwent();
522 /* fmask and dmask synonyms for people used to smbfs syntax */
523 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==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, "fmask") == 0) {
534 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
535 data = "file_mode"; /* BB fix this */
537 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
538 if (!value || !*value) {
539 printf ("Option '%s' requires a numerical argument\n", data);
540 return 1;
543 if (value[0] != '0') {
544 printf ("WARNING: '%s' not expressed in octal.\n", data);
547 if (strcmp (data, "dmask") == 0) {
548 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
549 data = "dir_mode";
551 /* the following eight mount options should be
552 stripped out from what is passed into the kernel
553 since these eight options are best passed as the
554 mount flags rather than redundantly to the kernel
555 and could generate spurious warnings depending on the
556 level of the corresponding cifs vfs kernel code */
557 } else if (strncmp(data, "nosuid", 6) == 0) {
558 *filesys_flags |= MS_NOSUID;
559 } else if (strncmp(data, "suid", 4) == 0) {
560 *filesys_flags &= ~MS_NOSUID;
561 } else if (strncmp(data, "nodev", 5) == 0) {
562 *filesys_flags |= MS_NODEV;
563 } else if ((strncmp(data, "nobrl", 5) == 0) ||
564 (strncmp(data, "nolock", 6) == 0)) {
565 *filesys_flags &= ~MS_MANDLOCK;
566 } else if (strncmp(data, "dev", 3) == 0) {
567 *filesys_flags &= ~MS_NODEV;
568 } else if (strncmp(data, "noexec", 6) == 0) {
569 *filesys_flags |= MS_NOEXEC;
570 } else if (strncmp(data, "exec", 4) == 0) {
571 *filesys_flags &= ~MS_NOEXEC;
572 } else if (strncmp(data, "guest", 5) == 0) {
573 got_password=1;
574 } else if (strncmp(data, "ro", 2) == 0) {
575 *filesys_flags |= MS_RDONLY;
576 } else if (strncmp(data, "rw", 2) == 0) {
577 *filesys_flags &= ~MS_RDONLY;
578 } else if (strncmp(data, "remount", 7) == 0) {
579 *filesys_flags |= MS_REMOUNT;
580 } /* else if (strnicmp(data, "port", 4) == 0) {
581 if (value && *value) {
582 vol->port =
583 simple_strtoul(value, &value, 0);
585 } else if (strnicmp(data, "rsize", 5) == 0) {
586 if (value && *value) {
587 vol->rsize =
588 simple_strtoul(value, &value, 0);
590 } else if (strnicmp(data, "wsize", 5) == 0) {
591 if (value && *value) {
592 vol->wsize =
593 simple_strtoul(value, &value, 0);
595 } else if (strnicmp(data, "version", 3) == 0) {
596 } else {
597 printf("CIFS: Unknown mount option %s\n",data);
598 } */ /* nothing to do on those four mount options above.
599 Just pass to kernel and ignore them here */
601 /* Copy (possibly modified) option to out */
602 word_len = strlen(data);
603 if (value)
604 word_len += 1 + strlen(value);
606 out = (char *)realloc(out, out_len + word_len + 2);
607 if (out == NULL) {
608 perror("malloc");
609 exit(1);
612 if (out_len)
613 out[out_len++] = ',';
614 if (value)
615 sprintf(out + out_len, "%s=%s", data, value);
616 else
617 sprintf(out + out_len, "%s", data);
618 out_len = strlen(out);
620 nocopy:
621 data = next_keyword;
623 free(*optionsp);
624 *optionsp = out;
625 return 0;
628 /* replace all (one or more) commas with double commas */
629 static void check_for_comma(char ** ppasswrd)
631 char *new_pass_buf;
632 char *pass;
633 int i,j;
634 int number_of_commas = 0;
635 int len;
637 if(ppasswrd == NULL)
638 return;
639 else
640 (pass = *ppasswrd);
642 len = strlen(pass);
644 for(i=0;i<len;i++) {
645 if(pass[i] == ',')
646 number_of_commas++;
649 if(number_of_commas == 0)
650 return;
651 if(number_of_commas > 64) {
652 /* would otherwise overflow the mount options buffer */
653 printf("\nInvalid password. Password contains too many commas.\n");
654 return;
657 new_pass_buf = (char *)malloc(len+number_of_commas+1);
658 if(new_pass_buf == NULL)
659 return;
661 for(i=0,j=0;i<len;i++,j++) {
662 new_pass_buf[j] = pass[i];
663 if(pass[i] == ',') {
664 j++;
665 new_pass_buf[j] = pass[i];
668 new_pass_buf[len+number_of_commas] = 0;
670 free(*ppasswrd);
671 *ppasswrd = new_pass_buf;
673 return;
676 /* Usernames can not have backslash in them and we use
677 [BB check if usernames can have forward slash in them BB]
678 backslash as domain\user separator character
680 static char * check_for_domain(char **ppuser)
682 char * original_string;
683 char * usernm;
684 char * domainnm;
685 int original_len;
686 int len;
687 int i;
689 if(ppuser == NULL)
690 return NULL;
692 original_string = *ppuser;
694 if (original_string == NULL)
695 return NULL;
697 original_len = strlen(original_string);
699 usernm = strchr(*ppuser,'/');
700 if (usernm == NULL) {
701 usernm = strchr(*ppuser,'\\');
702 if (usernm == NULL)
703 return NULL;
706 if(got_domain) {
707 printf("Domain name specified twice. Username probably malformed\n");
708 return NULL;
711 usernm[0] = 0;
712 domainnm = *ppuser;
713 if (domainnm[0] != 0) {
714 got_domain = 1;
715 } else {
716 printf("null domain\n");
718 len = strlen(domainnm);
719 /* reset domainm to new buffer, and copy
720 domain name into it */
721 domainnm = (char *)malloc(len+1);
722 if(domainnm == NULL)
723 return NULL;
725 strcpy(domainnm,*ppuser);
727 /* move_string(*ppuser, usernm+1) */
728 len = strlen(usernm+1);
730 if(len >= original_len) {
731 /* should not happen */
732 return domainnm;
735 for(i=0;i<original_len;i++) {
736 if(i<len)
737 original_string[i] = usernm[i+1];
738 else /* stuff with commas to remove last parm */
739 original_string[i] = ',';
742 /* BB add check for more than one slash?
743 strchr(*ppuser,'/');
744 strchr(*ppuser,'\\')
747 return domainnm;
750 /* Note that caller frees the returned buffer if necessary */
751 static char * parse_server(char ** punc_name)
753 char * unc_name = *punc_name;
754 int length = strnlen(unc_name,1024);
755 char * share;
756 char * ipaddress_string = NULL;
757 struct hostent * host_entry = NULL;
758 struct in_addr server_ipaddr;
760 if(length > 1023) {
761 printf("mount error: UNC name too long");
762 return NULL;
764 if (strncasecmp("cifs://",unc_name,7) == 0)
765 return parse_cifs_url(unc_name+7);
766 if (strncasecmp("smb://",unc_name,6) == 0) {
767 return parse_cifs_url(unc_name+6);
770 if(length < 3) {
771 /* BB add code to find DFS root here */
772 printf("\nMounting the DFS root for domain not implemented yet\n");
773 return NULL;
774 } else {
775 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
776 /* check for nfs syntax ie server:share */
777 share = strchr(unc_name,':');
778 if(share) {
779 free_share_name = 1;
780 *punc_name = (char *)malloc(length+3);
781 if(*punc_name == NULL) {
782 /* put the original string back if
783 no memory left */
784 *punc_name = unc_name;
785 return NULL;
788 *share = '/';
789 strncpy((*punc_name)+2,unc_name,length);
790 unc_name = *punc_name;
791 unc_name[length+2] = 0;
792 goto continue_unc_parsing;
793 } else {
794 printf("mount error: improperly formatted UNC name.");
795 printf(" %s does not begin with \\\\ or //\n",unc_name);
796 return NULL;
798 } else {
799 continue_unc_parsing:
800 unc_name[0] = '/';
801 unc_name[1] = '/';
802 unc_name += 2;
803 if ((share = strchr(unc_name, '/')) ||
804 (share = strchr(unc_name,'\\'))) {
805 *share = 0; /* temporarily terminate the string */
806 share += 1;
807 if(got_ip == 0) {
808 host_entry = gethostbyname(unc_name);
810 *(share - 1) = '/'; /* put the slash back */
811 if ((prefixpath = strchr(share, '/'))) {
812 *prefixpath = 0; /* permanently terminate the string */
813 if (!strlen(++prefixpath))
814 prefixpath = NULL; /* this needs to be done explicitly */
816 if(got_ip) {
817 if(verboseflag)
818 printf("ip address specified explicitly\n");
819 return NULL;
821 if(host_entry == NULL) {
822 printf("mount error: could not find target server. TCP name %s not found\n", unc_name);
823 return NULL;
824 } else {
825 /* BB should we pass an alternate version of the share name as Unicode */
826 /* BB what about ipv6? BB */
827 /* BB add retries with alternate servers in list */
829 memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
831 ipaddress_string = inet_ntoa(server_ipaddr);
832 if(ipaddress_string == NULL) {
833 printf("mount error: could not get valid ip address for target server\n");
834 return NULL;
836 return ipaddress_string;
838 } else {
839 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
840 printf("Mounting the DFS root for a particular server not implemented yet\n");
841 return NULL;
847 static struct option longopts[] = {
848 { "all", 0, NULL, 'a' },
849 { "help",0, NULL, 'h' },
850 { "move",0, NULL, 'm' },
851 { "bind",0, NULL, 'b' },
852 { "read-only", 0, NULL, 'r' },
853 { "ro", 0, NULL, 'r' },
854 { "verbose", 0, NULL, 'v' },
855 { "version", 0, NULL, 'V' },
856 { "read-write", 0, NULL, 'w' },
857 { "rw", 0, NULL, 'w' },
858 { "options", 1, NULL, 'o' },
859 { "type", 1, NULL, 't' },
860 { "rsize",1, NULL, 'R' },
861 { "wsize",1, NULL, 'W' },
862 { "uid", 1, NULL, '1'},
863 { "gid", 1, NULL, '2'},
864 { "user",1,NULL,'u'},
865 { "username",1,NULL,'u'},
866 { "dom",1,NULL,'d'},
867 { "domain",1,NULL,'d'},
868 { "password",1,NULL,'p'},
869 { "pass",1,NULL,'p'},
870 { "credentials",1,NULL,'c'},
871 { "port",1,NULL,'P'},
872 /* { "uuid",1,NULL,'U'}, */ /* BB unimplemented */
873 { NULL, 0, NULL, 0 }
876 int main(int argc, char ** argv)
878 int c;
879 int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
880 char * orgoptions = NULL;
881 char * share_name = NULL;
882 char * ipaddr = NULL;
883 char * uuid = NULL;
884 char * mountpoint = NULL;
885 char * options = NULL;
886 char * resolved_path = NULL;
887 char * temp;
888 int rc;
889 int rsize = 0;
890 int wsize = 0;
891 int nomtab = 0;
892 int uid = 0;
893 int gid = 0;
894 int optlen = 0;
895 int orgoptlen = 0;
896 int retry = 0; /* set when we have to retry mount with uppercase */
897 struct stat statbuf;
898 struct utsname sysinfo;
899 struct mntent mountent;
900 FILE * pmntfile;
902 /* setlocale(LC_ALL, "");
903 bindtextdomain(PACKAGE, LOCALEDIR);
904 textdomain(PACKAGE); */
906 if(argc && argv) {
907 thisprogram = argv[0];
908 } else {
909 mount_cifs_usage();
910 exit(1);
913 if(thisprogram == NULL)
914 thisprogram = "mount.cifs";
916 uname(&sysinfo);
917 /* BB add workstation name and domain and pass down */
919 /* #ifdef _GNU_SOURCE
920 printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
921 #endif */
922 if(argc > 2) {
923 share_name = argv[1];
924 mountpoint = argv[2];
927 /* add sharename in opts string as unc= parm */
929 while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
930 longopts, NULL)) != -1) {
931 switch (c) {
932 /* No code to do the following options yet */
933 /* case 'l':
934 list_with_volumelabel = 1;
935 break;
936 case 'L':
937 volumelabel = optarg;
938 break; */
939 /* case 'a':
940 ++mount_all;
941 break; */
943 case '?':
944 case 'h': /* help */
945 mount_cifs_usage ();
946 exit(1);
947 case 'n':
948 ++nomtab;
949 break;
950 case 'b':
951 #ifdef MS_BIND
952 flags |= MS_BIND;
953 #else
954 fprintf(stderr,
955 "option 'b' (MS_BIND) not supported\n");
956 #endif
957 break;
958 case 'm':
959 #ifdef MS_MOVE
960 flags |= MS_MOVE;
961 #else
962 fprintf(stderr,
963 "option 'm' (MS_MOVE) not supported\n");
964 #endif
965 break;
966 case 'o':
967 orgoptions = strdup(optarg);
968 break;
969 case 'r': /* mount readonly */
970 flags |= MS_RDONLY;
971 break;
972 case 'U':
973 uuid = optarg;
974 break;
975 case 'v':
976 ++verboseflag;
977 break;
978 case 'V':
979 printf ("mount.cifs version: %s.%s%s\n",
980 MOUNT_CIFS_VERSION_MAJOR,
981 MOUNT_CIFS_VERSION_MINOR,
982 MOUNT_CIFS_VENDOR_SUFFIX);
983 if(mountpassword) {
984 memset(mountpassword,0,64);
986 exit (0);
987 case 'w':
988 flags &= ~MS_RDONLY;
989 break;
990 case 'R':
991 rsize = atoi(optarg) ;
992 break;
993 case 'W':
994 wsize = atoi(optarg);
995 break;
996 case '1':
997 if (isdigit(*optarg)) {
998 char *ep;
1000 uid = strtoul(optarg, &ep, 10);
1001 if (*ep) {
1002 printf("bad uid value \"%s\"\n", optarg);
1003 exit(1);
1005 } else {
1006 struct passwd *pw;
1008 if (!(pw = getpwnam(optarg))) {
1009 printf("bad user name \"%s\"\n", optarg);
1010 exit(1);
1012 uid = pw->pw_uid;
1013 endpwent();
1015 break;
1016 case '2':
1017 if (isdigit(*optarg)) {
1018 char *ep;
1020 gid = strtoul(optarg, &ep, 10);
1021 if (*ep) {
1022 printf("bad gid value \"%s\"\n", optarg);
1023 exit(1);
1025 } else {
1026 struct group *gr;
1028 if (!(gr = getgrnam(optarg))) {
1029 printf("bad user name \"%s\"\n", optarg);
1030 exit(1);
1032 gid = gr->gr_gid;
1033 endpwent();
1035 break;
1036 case 'u':
1037 got_user = 1;
1038 user_name = optarg;
1039 break;
1040 case 'd':
1041 domain_name = optarg; /* BB fix this - currently ignored */
1042 got_domain = 1;
1043 break;
1044 case 'p':
1045 if(mountpassword == NULL)
1046 mountpassword = (char *)calloc(65,1);
1047 if(mountpassword) {
1048 got_password = 1;
1049 strncpy(mountpassword,optarg,64);
1051 break;
1052 case 'S':
1053 get_password_from_file(0 /* stdin */,NULL);
1054 break;
1055 case 't':
1056 break;
1057 default:
1058 printf("unknown mount option %c\n",c);
1059 mount_cifs_usage();
1060 exit(1);
1064 if((argc < 3) || (share_name == NULL) || (mountpoint == NULL)) {
1065 mount_cifs_usage();
1066 exit(1);
1069 if (getenv("PASSWD")) {
1070 if(mountpassword == NULL)
1071 mountpassword = (char *)calloc(65,1);
1072 if(mountpassword) {
1073 strncpy(mountpassword,getenv("PASSWD"),64);
1074 got_password = 1;
1076 } else if (getenv("PASSWD_FD")) {
1077 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
1078 } else if (getenv("PASSWD_FILE")) {
1079 get_password_from_file(0, getenv("PASSWD_FILE"));
1082 if (orgoptions && parse_options(&orgoptions, &flags)) {
1083 rc = -1;
1084 goto mount_exit;
1086 ipaddr = parse_server(&share_name);
1087 if((ipaddr == NULL) && (got_ip == 0)) {
1088 printf("No ip address specified and hostname not found\n");
1089 rc = -1;
1090 goto mount_exit;
1093 /* BB save off path and pop after mount returns? */
1094 resolved_path = (char *)malloc(PATH_MAX+1);
1095 if(resolved_path) {
1096 /* Note that if we can not canonicalize the name, we get
1097 another chance to see if it is valid when we chdir to it */
1098 if (realpath(mountpoint, resolved_path)) {
1099 mountpoint = resolved_path;
1102 if(chdir(mountpoint)) {
1103 printf("mount error: can not change directory into mount target %s\n",mountpoint);
1104 rc = -1;
1105 goto mount_exit;
1108 if(stat (".", &statbuf)) {
1109 printf("mount error: mount point %s does not exist\n",mountpoint);
1110 rc = -1;
1111 goto mount_exit;
1114 if (S_ISDIR(statbuf.st_mode) == 0) {
1115 printf("mount error: mount point %s is not a directory\n",mountpoint);
1116 rc = -1;
1117 goto mount_exit;
1120 if((getuid() != 0) && (geteuid() == 0)) {
1121 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
1122 #ifndef CIFS_ALLOW_USR_SUID
1123 /* Do not allow user mounts to control suid flag
1124 for mount unless explicitly built that way */
1125 flags |= MS_NOSUID | MS_NODEV;
1126 #endif
1127 } else {
1128 printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n");
1129 return -1;
1133 if(got_user == 0) {
1134 user_name = getusername();
1135 got_user = 1;
1138 if(got_password == 0) {
1139 mountpassword = getpass("Password: "); /* BB obsolete */
1140 got_password = 1;
1142 /* FIXME launch daemon (handles dfs name resolution and credential change)
1143 remember to clear parms and overwrite password field before launching */
1144 mount_retry:
1145 if(orgoptions) {
1146 optlen = strlen(orgoptions);
1147 orgoptlen = optlen;
1148 } else
1149 optlen = 0;
1150 if(share_name)
1151 optlen += strlen(share_name) + 4;
1152 else {
1153 printf("No server share name specified\n");
1154 printf("\nMounting the DFS root for server not implemented yet\n");
1155 exit(1);
1157 if(user_name)
1158 optlen += strlen(user_name) + 6;
1159 if(ipaddr)
1160 optlen += strlen(ipaddr) + 4;
1161 if(mountpassword)
1162 optlen += strlen(mountpassword) + 6;
1163 if(options)
1164 free(options);
1165 options = (char *)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 */);
1167 if(options == NULL) {
1168 printf("Could not allocate memory for mount options\n");
1169 return -1;
1173 options[0] = 0;
1174 strncat(options,"unc=",4);
1175 strcat(options,share_name);
1176 /* scan backwards and reverse direction of slash */
1177 temp = strrchr(options, '/');
1178 if(temp > options + 6)
1179 *temp = '\\';
1180 if(ipaddr) {
1181 strncat(options,",ip=",4);
1182 strcat(options,ipaddr);
1185 if(user_name) {
1186 /* check for syntax like user=domain\user */
1187 if(got_domain == 0)
1188 domain_name = check_for_domain(&user_name);
1189 strncat(options,",user=",6);
1190 strcat(options,user_name);
1192 if(retry == 0) {
1193 if(domain_name) {
1194 /* extra length accounted for in option string above */
1195 strncat(options,",domain=",8);
1196 strcat(options,domain_name);
1199 if(mountpassword) {
1200 /* Commas have to be doubled, or else they will
1201 look like the parameter separator */
1202 /* if(sep is not set)*/
1203 if(retry == 0)
1204 check_for_comma(&mountpassword);
1205 strncat(options,",pass=",6);
1206 strcat(options,mountpassword);
1209 strncat(options,",ver=",5);
1210 strcat(options,MOUNT_CIFS_VERSION_MAJOR);
1212 if(orgoptions) {
1213 strcat(options,",");
1214 strcat(options,orgoptions);
1216 if(prefixpath) {
1217 strncat(options,",prefixpath=",12);
1218 strcat(options,prefixpath); /* no need to cat the / */
1220 if(verboseflag)
1221 printf("\nmount.cifs kernel mount options %s \n",options);
1222 if(mount(share_name, mountpoint, "cifs", flags, options)) {
1223 /* remember to kill daemon on error */
1224 char * tmp;
1226 switch (errno) {
1227 case 0:
1228 printf("mount failed but no error number set\n");
1229 break;
1230 case ENODEV:
1231 printf("mount error: cifs filesystem not supported by the system\n");
1232 break;
1233 case ENXIO:
1234 if(retry == 0) {
1235 retry = 1;
1236 tmp = share_name;
1237 while (*tmp && !(((unsigned char)tmp[0]) & 0x80)) {
1238 *tmp = toupper((unsigned char)*tmp);
1239 tmp++;
1241 if(!*tmp) {
1242 printf("retrying with upper case share name\n");
1243 goto mount_retry;
1246 default:
1247 printf("mount error %d = %s\n",errno,strerror(errno));
1249 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
1250 rc = -1;
1251 goto mount_exit;
1252 } else {
1253 pmntfile = setmntent(MOUNTED, "a+");
1254 if(pmntfile) {
1255 mountent.mnt_fsname = share_name;
1256 mountent.mnt_dir = mountpoint;
1257 mountent.mnt_type = CONST_DISCARD(char *,"cifs");
1258 mountent.mnt_opts = (char *)malloc(220);
1259 if(mountent.mnt_opts) {
1260 char * mount_user = getusername();
1261 memset(mountent.mnt_opts,0,200);
1262 if(flags & MS_RDONLY)
1263 strcat(mountent.mnt_opts,"ro");
1264 else
1265 strcat(mountent.mnt_opts,"rw");
1266 if(flags & MS_MANDLOCK)
1267 strcat(mountent.mnt_opts,",mand");
1268 if(flags & MS_NOEXEC)
1269 strcat(mountent.mnt_opts,",noexec");
1270 if(flags & MS_NOSUID)
1271 strcat(mountent.mnt_opts,",nosuid");
1272 if(flags & MS_NODEV)
1273 strcat(mountent.mnt_opts,",nodev");
1274 if(flags & MS_SYNCHRONOUS)
1275 strcat(mountent.mnt_opts,",synch");
1276 if(mount_user) {
1277 if(getuid() != 0) {
1278 strcat(mountent.mnt_opts,",user=");
1279 strcat(mountent.mnt_opts,mount_user);
1281 /* free(mount_user); do not free static mem */
1284 mountent.mnt_freq = 0;
1285 mountent.mnt_passno = 0;
1286 rc = addmntent(pmntfile,&mountent);
1287 endmntent(pmntfile);
1288 if(mountent.mnt_opts)
1289 free(mountent.mnt_opts);
1290 } else {
1291 printf("could not update mount table\n");
1294 rc = 0;
1295 mount_exit:
1296 if(mountpassword) {
1297 int len = strlen(mountpassword);
1298 memset(mountpassword,0,len);
1299 free(mountpassword);
1302 if(options) {
1303 memset(options,0,optlen);
1304 free(options);
1307 if(orgoptions) {
1308 memset(orgoptions,0,orgoptlen);
1309 free(orgoptions);
1311 if(resolved_path) {
1312 free(resolved_path);
1315 if(free_share_name) {
1316 free(share_name);
1318 return rc;