source: trunk-3.0/source/client/mount.cifs.c@ 101

Last change on this file since 101 was 39, checked in by Paul Smedley, 18 years ago

Upgrade source to 3.0.25a

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