source: branches/samba-3.2.x/source/client/mount.cifs.c@ 340

Last change on this file since 340 was 340, checked in by Herwig Bauernfeind, 16 years ago

Update 3.2 to 3.2.15 (security update)

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