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