mount.cifs: don't leak passwords with verbose option
[Samba.git] / source / client / mount.cifs.c
blobc78aee03a0ea76b5067a98d260264c2a24d29d46
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)
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.
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.
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/>. */
19 #ifndef _GNU_SOURCE
20 #define _GNU_SOURCE
21 #endif
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <unistd.h>
26 #include <pwd.h>
27 #include <grp.h>
28 #include <ctype.h>
29 #include <sys/types.h>
30 #include <sys/mount.h>
31 #include <sys/stat.h>
32 #include <sys/utsname.h>
33 #include <sys/socket.h>
34 #include <arpa/inet.h>
35 #include <getopt.h>
36 #include <errno.h>
37 #include <netdb.h>
38 #include <string.h>
39 #include <mntent.h>
40 #include <fcntl.h>
41 #include <limits.h>
42 #include "mount.h"
44 #define MOUNT_CIFS_VERSION_MAJOR "1"
45 #define MOUNT_CIFS_VERSION_MINOR "12"
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 */
60 #ifdef _SAMBA_BUILD_
61 #include "include/config.h"
62 #endif
64 #ifndef MS_MOVE
65 #define MS_MOVE 8192
66 #endif
68 #ifndef MS_BIND
69 #define MS_BIND 4096
70 #endif
72 #define MAX_UNC_LEN 1024
74 #define CONST_DISCARD(type, ptr) ((type) ((void *) (ptr)))
76 #ifndef SAFE_FREE
77 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
78 #endif
80 #define MOUNT_PASSWD_SIZE 64
81 #define DOMAIN_SIZE 64
83 /* currently maximum length of IPv6 address string */
84 #define MAX_ADDRESS_LEN INET6_ADDRSTRLEN
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;
101 /* glibc doesn't have strlcpy, strlcat. Ensure we do. JRA. We
102 * don't link to libreplace so need them here. */
104 /* like strncpy but does not 0 fill the buffer and always null
105 * terminates. bufsize is the size of the destination buffer */
107 #ifndef HAVE_STRLCPY
108 static size_t strlcpy(char *d, const char *s, size_t bufsize)
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;
118 #endif
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 */
124 #ifndef HAVE_STRLCAT
125 static size_t strlcat(char *d, const char *s, size_t bufsize)
127 size_t len1 = strlen(d);
128 size_t len2 = strlen(s);
129 size_t ret = len1 + len2;
131 if (len1+len2 >= bufsize) {
132 if (bufsize < (len1+1)) {
133 return ret;
135 len2 = bufsize - (len1+1);
137 if (len2 > 0) {
138 memcpy(d+len1, s, len2);
139 d[len1+len2] = 0;
141 return ret;
143 #endif
145 /* BB finish BB
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.
152 BB end finish BB */
154 static char * check_for_domain(char **);
157 static void mount_cifs_usage(void)
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);
181 SAFE_FREE(mountpassword);
182 exit(EX_USAGE);
185 /* caller frees username if necessary */
186 static char * getusername(void) {
187 char *username = NULL;
188 struct passwd *password = getpwuid(getuid());
190 if (password) {
191 username = password->pw_name;
193 return username;
196 static int open_cred_file(char * file_name)
198 char * line_buf;
199 char * temp_val;
200 FILE * fs;
201 int i, length;
203 i = access(file_name, R_OK);
204 if (i)
205 return i;
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;
216 while(fgets(line_buf,4096,fs)) {
217 /* parse line from credential file */
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 */
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;
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);
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;
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;
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;
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;
307 fclose(fs);
308 SAFE_FREE(line_buf);
309 return 0;
312 static int get_password_from_file(int file_descript, char * filename)
314 int rc = 0;
315 int i;
316 char c;
318 if(mountpassword == NULL)
319 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
320 else
321 memset(mountpassword, 0, MOUNT_PASSWD_SIZE);
323 if (mountpassword == NULL) {
324 printf("malloc failed\n");
325 exit(EX_SYSERR);
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);
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);
342 /* else file already open and fd provided */
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");
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;
365 if((i == MOUNT_PASSWD_SIZE) && (verboseflag)) {
366 printf("\nWarning: password longer than %d characters specified in cifs password file",
367 MOUNT_PASSWD_SIZE);
369 got_password = 1;
370 if(filename != NULL) {
371 close(file_descript);
374 return rc;
377 static int parse_options(char ** optionsp, int * filesys_flags)
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];
390 if (!optionsp || !*optionsp)
391 return 1;
392 data = *optionsp;
394 /* BB fixme check for separator override BB */
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());
403 /* while ((data = strsep(&options, ",")) != NULL) { */
404 while(data != NULL) {
405 /* check if ends with trailing comma */
406 if(*data == 0)
407 break;
409 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
410 /* data = next keyword */
411 /* value = next value ie stuff after equal sign */
413 next_keyword = strchr(data,','); /* BB handle sep= */
415 /* temporarily null terminate end of keyword=value pair */
416 if(next_keyword)
417 *next_keyword++ = 0;
419 /* temporarily null terminate keyword to make keyword and value distinct */
420 if ((value = strchr(data, '=')) != NULL) {
421 *value = '\0';
422 value++;
425 if (strncmp(data, "users",5) == 0) {
426 if(!value || !*value) {
427 goto nocopy;
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) {
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; */
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++;
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;
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;
495 got_password = 1;
497 } else {
498 fprintf(stderr, "password too long\n");
499 SAFE_FREE(out);
500 return 1;
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;
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;
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");
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;
549 } else {
550 printf("CIFS: UNC name too long\n");
551 SAFE_FREE(out);
552 return 1;
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; */
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;
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;
580 } else {
581 printf("invalid credential file name specified\n");
582 SAFE_FREE(out);
583 return 1;
585 } else if (strncmp(data, "uid", 3) == 0) {
586 if (value && *value) {
587 got_uid = 1;
588 if (!isdigit(*value)) {
589 struct passwd *pw;
591 if (!(pw = getpwnam(value))) {
592 printf("bad user name \"%s\"\n", value);
593 exit(EX_USAGE);
595 snprintf(user, sizeof(user), "%u", pw->pw_uid);
596 } else {
597 strlcpy(user,value,sizeof(user));
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;
607 if (!(gr = getgrnam(value))) {
608 printf("bad group name \"%s\"\n", value);
609 exit(EX_USAGE);
611 snprintf(group, sizeof(group), "%u", gr->gr_gid);
612 } else {
613 strlcpy(group,value,sizeof(group));
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;
625 if (value[0] != '0') {
626 printf ("WARNING: '%s' not expressed in octal.\n", data);
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 */
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;
640 if (value[0] != '0') {
641 printf ("WARNING: '%s' not expressed in octal.\n", data);
644 if (strcmp (data, "dmask") == 0) {
645 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
646 data = "dir_mode";
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);
684 } else if (strnicmp(data, "rsize", 5) == 0) {
685 if (value && *value) {
686 vol->rsize =
687 simple_strtoul(value, &value, 0);
689 } else if (strnicmp(data, "wsize", 5) == 0) {
690 if (value && *value) {
691 vol->wsize =
692 simple_strtoul(value, &value, 0);
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 */
700 /* Copy (possibly modified) option to out */
701 word_len = strlen(data);
702 if (value)
703 word_len += 1 + strlen(value);
705 out = (char *)realloc(out, out_len + word_len + 2);
706 if (out == NULL) {
707 perror("malloc");
708 exit(EX_SYSERR);
711 if (out_len) {
712 strlcat(out, ",", out_len + word_len + 2);
713 out_len++;
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);
722 nocopy:
723 data = next_keyword;
726 /* special-case the uid and gid */
727 if (got_uid) {
728 word_len = strlen(user);
730 out = (char *)realloc(out, out_len + word_len + 6);
731 if (out == NULL) {
732 perror("malloc");
733 exit(EX_SYSERR);
736 if (out_len) {
737 strlcat(out, ",", out_len + word_len + 6);
738 out_len++;
740 snprintf(out + out_len, word_len + 5, "uid=%s", user);
741 out_len = strlen(out);
743 if (got_gid) {
744 word_len = strlen(group);
746 out = (char *)realloc(out, out_len + 1 + word_len + 6);
747 if (out == NULL) {
748 perror("malloc");
749 exit(EX_SYSERR);
752 if (out_len) {
753 strlcat(out, ",", out_len + word_len + 6);
754 out_len++;
756 snprintf(out + out_len, word_len + 5, "gid=%s", group);
757 out_len = strlen(out);
760 SAFE_FREE(*optionsp);
761 *optionsp = out;
762 return 0;
765 /* replace all (one or more) commas with double commas */
766 static void check_for_comma(char ** ppasswrd)
768 char *new_pass_buf;
769 char *pass;
770 int i,j;
771 int number_of_commas = 0;
772 int len;
774 if(ppasswrd == NULL)
775 return;
776 else
777 (pass = *ppasswrd);
779 len = strlen(pass);
781 for(i=0;i<len;i++) {
782 if(pass[i] == ',')
783 number_of_commas++;
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;
794 new_pass_buf = (char *)malloc(len+number_of_commas+1);
795 if(new_pass_buf == NULL)
796 return;
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];
805 new_pass_buf[len+number_of_commas] = 0;
807 SAFE_FREE(*ppasswrd);
808 *ppasswrd = new_pass_buf;
810 return;
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
817 static char * check_for_domain(char **ppuser)
819 char * original_string;
820 char * usernm;
821 char * domainnm;
822 int original_len;
823 int len;
824 int i;
826 if(ppuser == NULL)
827 return NULL;
829 original_string = *ppuser;
831 if (original_string == NULL)
832 return NULL;
834 original_len = strlen(original_string);
836 usernm = strchr(*ppuser,'/');
837 if (usernm == NULL) {
838 usernm = strchr(*ppuser,'\\');
839 if (usernm == NULL)
840 return NULL;
843 if(got_domain) {
844 printf("Domain name specified twice. Username probably malformed\n");
845 return NULL;
848 usernm[0] = 0;
849 domainnm = *ppuser;
850 if (domainnm[0] != 0) {
851 got_domain = 1;
852 } else {
853 printf("null domain\n");
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;
862 strlcpy(domainnm,*ppuser,len+1);
864 /* move_string(*ppuser, usernm+1) */
865 len = strlen(usernm+1);
867 if(len >= original_len) {
868 /* should not happen */
869 return domainnm;
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] = ',';
879 /* BB add check for more than one slash?
880 strchr(*ppuser,'/');
881 strchr(*ppuser,'\\')
884 return domainnm;
887 /* replace all occurances of "from" in a string with "to" */
888 static void replace_char(char *string, char from, char to, int maxlen)
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;
901 /* Note that caller frees the returned buffer if necessary */
902 static struct addrinfo *
903 parse_server(char ** punc_name)
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;
911 if(length > (MAX_UNC_LEN - 1)) {
912 printf("mount error: UNC name too long");
913 return NULL;
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;
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;
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;
948 } else {
949 continue_unc_parsing:
950 unc_name[0] = '/';
951 unc_name[1] = '/';
952 unc_name += 2;
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;
966 *(share - 1) = '/'; /* put delimiter back */
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 */
974 if(got_ip) {
975 if(verboseflag)
976 printf("ip address specified explicitly\n");
977 return NULL;
979 /* BB should we pass an alternate version of the share name as Unicode */
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;
991 static 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 }
1020 /* convert a string to uppercase. return false if the string
1021 * wasn't ASCII. Return success on a NULL ptr */
1022 static int
1023 uppercase_string(char *string)
1025 if (!string)
1026 return 1;
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++;
1036 return 1;
1039 int main(int argc, char ** argv)
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;
1072 /* setlocale(LC_ALL, "");
1073 bindtextdomain(PACKAGE, LOCALEDIR);
1074 textdomain(PACKAGE); */
1076 if(argc && argv) {
1077 thisprogram = argv[0];
1078 } else {
1079 mount_cifs_usage();
1080 exit(EX_USAGE);
1083 if(thisprogram == NULL)
1084 thisprogram = "mount.cifs";
1086 uname(&sysinfo);
1087 /* BB add workstation name and domain and pass down */
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);
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);
1109 mount_cifs_usage();
1110 exit(EX_USAGE);
1113 /* add sharename in opts string as unc= parm */
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; */
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;
1183 uid = strtoul(optarg, &ep, 10);
1184 if (*ep) {
1185 printf("bad uid value \"%s\"\n", optarg);
1186 exit(EX_USAGE);
1188 } else {
1189 struct passwd *pw;
1191 if (!(pw = getpwnam(optarg))) {
1192 printf("bad user name \"%s\"\n", optarg);
1193 exit(EX_USAGE);
1195 uid = pw->pw_uid;
1196 endpwent();
1198 break;
1199 case '2':
1200 if (isdigit(*optarg)) {
1201 char *ep;
1203 gid = strtoul(optarg, &ep, 10);
1204 if (*ep) {
1205 printf("bad gid value \"%s\"\n", optarg);
1206 exit(EX_USAGE);
1208 } else {
1209 struct group *gr;
1211 if (!(gr = getgrnam(optarg))) {
1212 printf("bad user name \"%s\"\n", optarg);
1213 exit(EX_USAGE);
1215 gid = gr->gr_gid;
1216 endpwent();
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);
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);
1250 if((argc < 3) || (dev_name == NULL) || (mountpoint == NULL)) {
1251 mount_cifs_usage();
1252 exit(EX_USAGE);
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;
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"));
1268 if (orgoptions && parse_options(&orgoptions, &flags)) {
1269 rc = EX_USAGE;
1270 goto mount_exit;
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;
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;
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;
1294 if(stat (".", &statbuf)) {
1295 printf("mount error: mount point %s does not exist\n",mountpoint);
1296 rc = EX_USAGE;
1297 goto mount_exit;
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;
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);
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;
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);
1338 strlcpy(mountpassword, tmp_pass, MOUNT_PASSWD_SIZE+1);
1339 got_password = 1;
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);
1355 if(user_name)
1356 optlen += strlen(user_name) + 6;
1357 optlen += MAX_ADDRESS_LEN + 4;
1358 if(mountpassword)
1359 optlen += strlen(mountpassword) + 6;
1360 mount_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 */);
1365 if(options == NULL) {
1366 printf("Could not allocate memory for mount options\n");
1367 exit(EX_SYSERR);
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);
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);
1391 strlcat(options,",ver=",options_size);
1392 strlcat(options,MOUNT_CIFS_VERSION_MAJOR,options_size);
1394 if(orgoptions) {
1395 strlcat(options,",",options_size);
1396 strlcat(options,orgoptions,options_size);
1398 if(prefixpath) {
1399 strlcat(options,",prefixpath=",options_size);
1400 strlcat(options,prefixpath,options_size); /* no need to cat the / */
1403 /* convert all '\\' to '/' in share portion so that /proc/mounts looks pretty */
1404 replace_char(dev_name, '\\', '/', strlen(share_name));
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;
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;
1433 if(verboseflag)
1434 fprintf(stderr, "\nmount.cifs kernel mount options: %s", options);
1436 if (mountpassword) {
1438 * Commas have to be doubled, or else they will
1439 * look like the parameter separator
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=********");
1449 if (verboseflag)
1450 fprintf(stderr, "\n");
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;
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;
1476 printf("mount error(%d): %s\n", errno, strerror(errno));
1477 printf("Refer to the mount.cifs(8) manual page (e.g. man "
1478 "mount.cifs)\n");
1479 rc = EX_FAIL;
1480 goto mount_exit;
1483 if (nomtab)
1484 goto mount_exit;
1485 atexit(unlock_mtab);
1486 rc = lock_mtab();
1487 if (rc) {
1488 printf("cannot lock mtab");
1489 goto mount_exit;
1491 pmntfile = setmntent(MOUNTED, "a+");
1492 if (!pmntfile) {
1493 printf("could not update mount table\n");
1494 unlock_mtab();
1495 rc = EX_FILEIO;
1496 goto mount_exit;
1498 mountent.mnt_fsname = dev_name;
1499 mountent.mnt_dir = mountpoint;
1500 mountent.mnt_type = CONST_DISCARD(char *,"cifs");
1501 mountent.mnt_opts = (char *)malloc(220);
1502 if(mountent.mnt_opts) {
1503 char * mount_user = getusername();
1504 memset(mountent.mnt_opts,0,200);
1505 if(flags & MS_RDONLY)
1506 strlcat(mountent.mnt_opts,"ro",220);
1507 else
1508 strlcat(mountent.mnt_opts,"rw",220);
1509 if(flags & MS_MANDLOCK)
1510 strlcat(mountent.mnt_opts,",mand",220);
1511 if(flags & MS_NOEXEC)
1512 strlcat(mountent.mnt_opts,",noexec",220);
1513 if(flags & MS_NOSUID)
1514 strlcat(mountent.mnt_opts,",nosuid",220);
1515 if(flags & MS_NODEV)
1516 strlcat(mountent.mnt_opts,",nodev",220);
1517 if(flags & MS_SYNCHRONOUS)
1518 strlcat(mountent.mnt_opts,",sync",220);
1519 if(mount_user) {
1520 if(getuid() != 0) {
1521 strlcat(mountent.mnt_opts,
1522 ",user=", 220);
1523 strlcat(mountent.mnt_opts,
1524 mount_user, 220);
1528 mountent.mnt_freq = 0;
1529 mountent.mnt_passno = 0;
1530 rc = addmntent(pmntfile,&mountent);
1531 endmntent(pmntfile);
1532 unlock_mtab();
1533 SAFE_FREE(mountent.mnt_opts);
1534 if (rc)
1535 rc = EX_FILEIO;
1536 mount_exit:
1537 if(mountpassword) {
1538 int len = strlen(mountpassword);
1539 memset(mountpassword,0,len);
1540 SAFE_FREE(mountpassword);
1543 if (addrhead)
1544 freeaddrinfo(addrhead);
1545 SAFE_FREE(options);
1546 SAFE_FREE(orgoptions);
1547 SAFE_FREE(resolved_path);
1548 SAFE_FREE(share_name);
1549 exit(rc);