Support getting gpfs birthtime
[Samba/kamenim.git] / source3 / client / mount.cifs.c
bloba5d99dc3d918dc53c17b48f6463efb998b70a128
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 128
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);
184 /* caller frees username if necessary */
185 static char * getusername(void) {
186 char *username = NULL;
187 struct passwd *password = getpwuid(getuid());
189 if (password) {
190 username = password->pw_name;
192 return username;
195 static int open_cred_file(char * file_name)
197 char * line_buf;
198 char * temp_val;
199 FILE * fs;
200 int i, length;
201 fs = fopen(file_name,"r");
202 if(fs == NULL)
203 return errno;
204 line_buf = (char *)malloc(4096);
205 if(line_buf == NULL) {
206 fclose(fs);
207 return ENOMEM;
210 while(fgets(line_buf,4096,fs)) {
211 /* parse line from credential file */
213 /* eat leading white space */
214 for(i=0;i<4086;i++) {
215 if((line_buf[i] != ' ') && (line_buf[i] != '\t'))
216 break;
217 /* if whitespace - skip past it */
219 if (strncasecmp("username",line_buf+i,8) == 0) {
220 temp_val = strchr(line_buf + i,'=');
221 if(temp_val) {
222 /* go past equals sign */
223 temp_val++;
224 for(length = 0;length<4087;length++) {
225 if ((temp_val[length] == '\n')
226 || (temp_val[length] == '\0')) {
227 temp_val[length] = '\0';
228 break;
231 if(length > 4086) {
232 printf("mount.cifs failed due to malformed username in credentials file");
233 memset(line_buf,0,4096);
234 exit(EX_USAGE);
235 } else {
236 got_user = 1;
237 user_name = (char *)calloc(1 + length,1);
238 /* BB adding free of user_name string before exit,
239 not really necessary but would be cleaner */
240 strlcpy(user_name,temp_val, length+1);
243 } else if (strncasecmp("password",line_buf+i,8) == 0) {
244 temp_val = strchr(line_buf+i,'=');
245 if(temp_val) {
246 /* go past equals sign */
247 temp_val++;
248 for(length = 0;length<MOUNT_PASSWD_SIZE+1;length++) {
249 if ((temp_val[length] == '\n')
250 || (temp_val[length] == '\0')) {
251 temp_val[length] = '\0';
252 break;
255 if(length > MOUNT_PASSWD_SIZE) {
256 printf("mount.cifs failed: password in credentials file too long\n");
257 memset(line_buf,0, 4096);
258 exit(EX_USAGE);
259 } else {
260 if(mountpassword == NULL) {
261 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
262 } else
263 memset(mountpassword,0,MOUNT_PASSWD_SIZE);
264 if(mountpassword) {
265 strlcpy(mountpassword,temp_val,MOUNT_PASSWD_SIZE+1);
266 got_password = 1;
270 } else if (strncasecmp("domain",line_buf+i,6) == 0) {
271 temp_val = strchr(line_buf+i,'=');
272 if(temp_val) {
273 /* go past equals sign */
274 temp_val++;
275 if(verboseflag)
276 printf("\nDomain %s\n",temp_val);
277 for(length = 0;length<DOMAIN_SIZE+1;length++) {
278 if ((temp_val[length] == '\n')
279 || (temp_val[length] == '\0')) {
280 temp_val[length] = '\0';
281 break;
284 if(length > DOMAIN_SIZE) {
285 printf("mount.cifs failed: domain in credentials file too long\n");
286 exit(EX_USAGE);
287 } else {
288 if(domain_name == NULL) {
289 domain_name = (char *)calloc(DOMAIN_SIZE+1,1);
290 } else
291 memset(domain_name,0,DOMAIN_SIZE);
292 if(domain_name) {
293 strlcpy(domain_name,temp_val,DOMAIN_SIZE+1);
294 got_domain = 1;
301 fclose(fs);
302 SAFE_FREE(line_buf);
303 return 0;
306 static int get_password_from_file(int file_descript, char * filename)
308 int rc = 0;
309 int i;
310 char c;
312 if(mountpassword == NULL)
313 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
314 else
315 memset(mountpassword, 0, MOUNT_PASSWD_SIZE);
317 if (mountpassword == NULL) {
318 printf("malloc failed\n");
319 exit(EX_SYSERR);
322 if(filename != NULL) {
323 file_descript = open(filename, O_RDONLY);
324 if(file_descript < 0) {
325 printf("mount.cifs failed. %s attempting to open password file %s\n",
326 strerror(errno),filename);
327 exit(EX_SYSERR);
330 /* else file already open and fd provided */
332 for(i=0;i<MOUNT_PASSWD_SIZE;i++) {
333 rc = read(file_descript,&c,1);
334 if(rc < 0) {
335 printf("mount.cifs failed. Error %s reading password file\n",strerror(errno));
336 if(filename != NULL)
337 close(file_descript);
338 exit(EX_SYSERR);
339 } else if(rc == 0) {
340 if(mountpassword[0] == 0) {
341 if(verboseflag)
342 printf("\nWarning: null password used since cifs password file empty");
344 break;
345 } else /* read valid character */ {
346 if((c == 0) || (c == '\n')) {
347 mountpassword[i] = '\0';
348 break;
349 } else
350 mountpassword[i] = c;
353 if((i == MOUNT_PASSWD_SIZE) && (verboseflag)) {
354 printf("\nWarning: password longer than %d characters specified in cifs password file",
355 MOUNT_PASSWD_SIZE);
357 got_password = 1;
358 if(filename != NULL) {
359 close(file_descript);
362 return rc;
365 static int parse_options(char ** optionsp, int * filesys_flags)
367 const char * data;
368 char * percent_char = NULL;
369 char * value = NULL;
370 char * next_keyword = NULL;
371 char * out = NULL;
372 int out_len = 0;
373 int word_len;
374 int rc = 0;
375 char user[32];
376 char group[32];
378 if (!optionsp || !*optionsp)
379 return 1;
380 data = *optionsp;
382 if(verboseflag)
383 printf("parsing options: %s\n", data);
385 /* BB fixme check for separator override BB */
387 if (getuid()) {
388 got_uid = 1;
389 snprintf(user,sizeof(user),"%u",getuid());
390 got_gid = 1;
391 snprintf(group,sizeof(group),"%u",getgid());
394 /* while ((data = strsep(&options, ",")) != NULL) { */
395 while(data != NULL) {
396 /* check if ends with trailing comma */
397 if(*data == 0)
398 break;
400 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
401 /* data = next keyword */
402 /* value = next value ie stuff after equal sign */
404 next_keyword = strchr(data,','); /* BB handle sep= */
406 /* temporarily null terminate end of keyword=value pair */
407 if(next_keyword)
408 *next_keyword++ = 0;
410 /* temporarily null terminate keyword to make keyword and value distinct */
411 if ((value = strchr(data, '=')) != NULL) {
412 *value = '\0';
413 value++;
416 if (strncmp(data, "users",5) == 0) {
417 if(!value || !*value) {
418 goto nocopy;
420 } else if (strncmp(data, "user_xattr",10) == 0) {
421 /* do nothing - need to skip so not parsed as user name */
422 } else if (strncmp(data, "user", 4) == 0) {
424 if (!value || !*value) {
425 if(data[4] == '\0') {
426 if(verboseflag)
427 printf("\nskipping empty user mount parameter\n");
428 /* remove the parm since it would otherwise be confusing
429 to the kernel code which would think it was a real username */
430 goto nocopy;
431 } else {
432 printf("username specified with no parameter\n");
433 SAFE_FREE(out);
434 return 1; /* needs_arg; */
436 } else {
437 if (strnlen(value, 260) < 260) {
438 got_user=1;
439 percent_char = strchr(value,'%');
440 if(percent_char) {
441 *percent_char = ',';
442 if(mountpassword == NULL)
443 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
444 if(mountpassword) {
445 if(got_password)
446 printf("\nmount.cifs warning - password specified twice\n");
447 got_password = 1;
448 percent_char++;
449 strlcpy(mountpassword, percent_char,MOUNT_PASSWD_SIZE+1);
450 /* remove password from username */
451 while(*percent_char != 0) {
452 *percent_char = ',';
453 percent_char++;
457 /* this is only case in which the user
458 name buf is not malloc - so we have to
459 check for domain name embedded within
460 the user name here since the later
461 call to check_for_domain will not be
462 invoked */
463 domain_name = check_for_domain(&value);
464 } else {
465 printf("username too long\n");
466 SAFE_FREE(out);
467 return 1;
470 } else if (strncmp(data, "pass", 4) == 0) {
471 if (!value || !*value) {
472 if(got_password) {
473 printf("\npassword specified twice, ignoring second\n");
474 } else
475 got_password = 1;
476 } else if (strnlen(value, MOUNT_PASSWD_SIZE) < MOUNT_PASSWD_SIZE) {
477 if(got_password)
478 printf("\nmount.cifs warning - password specified twice\n");
479 got_password = 1;
480 } else {
481 printf("password too long\n");
482 SAFE_FREE(out);
483 return 1;
485 } else if (strncmp(data, "sec", 3) == 0) {
486 if (value) {
487 if (!strncmp(value, "none", 4) ||
488 !strncmp(value, "krb5", 4))
489 got_password = 1;
491 } else if (strncmp(data, "ip", 2) == 0) {
492 if (!value || !*value) {
493 printf("target ip address argument missing");
494 } else if (strnlen(value, MAX_ADDRESS_LEN) <= MAX_ADDRESS_LEN) {
495 if(verboseflag)
496 printf("ip address %s override specified\n",value);
497 got_ip = 1;
498 } else {
499 printf("ip address too long\n");
500 SAFE_FREE(out);
501 return 1;
503 } else if ((strncmp(data, "unc", 3) == 0)
504 || (strncmp(data, "target", 6) == 0)
505 || (strncmp(data, "path", 4) == 0)) {
506 if (!value || !*value) {
507 printf("invalid path to network resource\n");
508 SAFE_FREE(out);
509 return 1; /* needs_arg; */
510 } else if(strnlen(value,5) < 5) {
511 printf("UNC name too short");
514 if (strnlen(value, 300) < 300) {
515 got_unc = 1;
516 if (strncmp(value, "//", 2) == 0) {
517 if(got_unc)
518 printf("unc name specified twice, ignoring second\n");
519 else
520 got_unc = 1;
521 } else if (strncmp(value, "\\\\", 2) != 0) {
522 printf("UNC Path does not begin with // or \\\\ \n");
523 SAFE_FREE(out);
524 return 1;
525 } else {
526 if(got_unc)
527 printf("unc name specified twice, ignoring second\n");
528 else
529 got_unc = 1;
531 } else {
532 printf("CIFS: UNC name too long\n");
533 SAFE_FREE(out);
534 return 1;
536 } else if ((strncmp(data, "dom" /* domain */, 3) == 0)
537 || (strncmp(data, "workg", 5) == 0)) {
538 /* note this allows for synonyms of "domain"
539 such as "DOM" and "dom" and "workgroup"
540 and "WORKGRP" etc. */
541 if (!value || !*value) {
542 printf("CIFS: invalid domain name\n");
543 SAFE_FREE(out);
544 return 1; /* needs_arg; */
546 if (strnlen(value, DOMAIN_SIZE+1) < DOMAIN_SIZE+1) {
547 got_domain = 1;
548 } else {
549 printf("domain name too long\n");
550 SAFE_FREE(out);
551 return 1;
553 } else if (strncmp(data, "cred", 4) == 0) {
554 if (value && *value) {
555 rc = open_cred_file(value);
556 if(rc) {
557 printf("error %d (%s) opening credential file %s\n",
558 rc, strerror(rc), value);
559 SAFE_FREE(out);
560 return 1;
562 } else {
563 printf("invalid credential file name specified\n");
564 SAFE_FREE(out);
565 return 1;
567 } else if (strncmp(data, "uid", 3) == 0) {
568 if (value && *value) {
569 got_uid = 1;
570 if (!isdigit(*value)) {
571 struct passwd *pw;
573 if (!(pw = getpwnam(value))) {
574 printf("bad user name \"%s\"\n", value);
575 exit(EX_USAGE);
577 snprintf(user, sizeof(user), "%u", pw->pw_uid);
578 } else {
579 strlcpy(user,value,sizeof(user));
582 goto nocopy;
583 } else if (strncmp(data, "gid", 3) == 0) {
584 if (value && *value) {
585 got_gid = 1;
586 if (!isdigit(*value)) {
587 struct group *gr;
589 if (!(gr = getgrnam(value))) {
590 printf("bad group name \"%s\"\n", value);
591 exit(EX_USAGE);
593 snprintf(group, sizeof(group), "%u", gr->gr_gid);
594 } else {
595 strlcpy(group,value,sizeof(group));
598 goto nocopy;
599 /* fmask and dmask synonyms for people used to smbfs syntax */
600 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
601 if (!value || !*value) {
602 printf ("Option '%s' requires a numerical argument\n", data);
603 SAFE_FREE(out);
604 return 1;
607 if (value[0] != '0') {
608 printf ("WARNING: '%s' not expressed in octal.\n", data);
611 if (strcmp (data, "fmask") == 0) {
612 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
613 data = "file_mode"; /* BB fix this */
615 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
616 if (!value || !*value) {
617 printf ("Option '%s' requires a numerical argument\n", data);
618 SAFE_FREE(out);
619 return 1;
622 if (value[0] != '0') {
623 printf ("WARNING: '%s' not expressed in octal.\n", data);
626 if (strcmp (data, "dmask") == 0) {
627 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
628 data = "dir_mode";
630 /* the following eight mount options should be
631 stripped out from what is passed into the kernel
632 since these eight options are best passed as the
633 mount flags rather than redundantly to the kernel
634 and could generate spurious warnings depending on the
635 level of the corresponding cifs vfs kernel code */
636 } else if (strncmp(data, "nosuid", 6) == 0) {
637 *filesys_flags |= MS_NOSUID;
638 } else if (strncmp(data, "suid", 4) == 0) {
639 *filesys_flags &= ~MS_NOSUID;
640 } else if (strncmp(data, "nodev", 5) == 0) {
641 *filesys_flags |= MS_NODEV;
642 } else if ((strncmp(data, "nobrl", 5) == 0) ||
643 (strncmp(data, "nolock", 6) == 0)) {
644 *filesys_flags &= ~MS_MANDLOCK;
645 } else if (strncmp(data, "dev", 3) == 0) {
646 *filesys_flags &= ~MS_NODEV;
647 } else if (strncmp(data, "noexec", 6) == 0) {
648 *filesys_flags |= MS_NOEXEC;
649 } else if (strncmp(data, "exec", 4) == 0) {
650 *filesys_flags &= ~MS_NOEXEC;
651 } else if (strncmp(data, "guest", 5) == 0) {
652 user_name = (char *)calloc(1, 1);
653 got_user = 1;
654 got_password = 1;
655 } else if (strncmp(data, "ro", 2) == 0) {
656 *filesys_flags |= MS_RDONLY;
657 } else if (strncmp(data, "rw", 2) == 0) {
658 *filesys_flags &= ~MS_RDONLY;
659 } else if (strncmp(data, "remount", 7) == 0) {
660 *filesys_flags |= MS_REMOUNT;
661 } /* else if (strnicmp(data, "port", 4) == 0) {
662 if (value && *value) {
663 vol->port =
664 simple_strtoul(value, &value, 0);
666 } else if (strnicmp(data, "rsize", 5) == 0) {
667 if (value && *value) {
668 vol->rsize =
669 simple_strtoul(value, &value, 0);
671 } else if (strnicmp(data, "wsize", 5) == 0) {
672 if (value && *value) {
673 vol->wsize =
674 simple_strtoul(value, &value, 0);
676 } else if (strnicmp(data, "version", 3) == 0) {
677 } else {
678 printf("CIFS: Unknown mount option %s\n",data);
679 } */ /* nothing to do on those four mount options above.
680 Just pass to kernel and ignore them here */
682 /* Copy (possibly modified) option to out */
683 word_len = strlen(data);
684 if (value)
685 word_len += 1 + strlen(value);
687 out = (char *)realloc(out, out_len + word_len + 2);
688 if (out == NULL) {
689 perror("malloc");
690 exit(EX_SYSERR);
693 if (out_len) {
694 strlcat(out, ",", out_len + word_len + 2);
695 out_len++;
698 if (value)
699 snprintf(out + out_len, word_len + 1, "%s=%s", data, value);
700 else
701 snprintf(out + out_len, word_len + 1, "%s", data);
702 out_len = strlen(out);
704 nocopy:
705 data = next_keyword;
708 /* special-case the uid and gid */
709 if (got_uid) {
710 word_len = strlen(user);
712 out = (char *)realloc(out, out_len + word_len + 6);
713 if (out == NULL) {
714 perror("malloc");
715 exit(EX_SYSERR);
718 if (out_len) {
719 strlcat(out, ",", out_len + word_len + 6);
720 out_len++;
722 snprintf(out + out_len, word_len + 5, "uid=%s", user);
723 out_len = strlen(out);
725 if (got_gid) {
726 word_len = strlen(group);
728 out = (char *)realloc(out, out_len + 1 + word_len + 6);
729 if (out == NULL) {
730 perror("malloc");
731 exit(EX_SYSERR);
734 if (out_len) {
735 strlcat(out, ",", out_len + word_len + 6);
736 out_len++;
738 snprintf(out + out_len, word_len + 5, "gid=%s", group);
739 out_len = strlen(out);
742 SAFE_FREE(*optionsp);
743 *optionsp = out;
744 return 0;
747 /* replace all (one or more) commas with double commas */
748 static void check_for_comma(char ** ppasswrd)
750 char *new_pass_buf;
751 char *pass;
752 int i,j;
753 int number_of_commas = 0;
754 int len;
756 if(ppasswrd == NULL)
757 return;
758 else
759 (pass = *ppasswrd);
761 len = strlen(pass);
763 for(i=0;i<len;i++) {
764 if(pass[i] == ',')
765 number_of_commas++;
768 if(number_of_commas == 0)
769 return;
770 if(number_of_commas > MOUNT_PASSWD_SIZE) {
771 /* would otherwise overflow the mount options buffer */
772 printf("\nInvalid password. Password contains too many commas.\n");
773 return;
776 new_pass_buf = (char *)malloc(len+number_of_commas+1);
777 if(new_pass_buf == NULL)
778 return;
780 for(i=0,j=0;i<len;i++,j++) {
781 new_pass_buf[j] = pass[i];
782 if(pass[i] == ',') {
783 j++;
784 new_pass_buf[j] = pass[i];
787 new_pass_buf[len+number_of_commas] = 0;
789 SAFE_FREE(*ppasswrd);
790 *ppasswrd = new_pass_buf;
792 return;
795 /* Usernames can not have backslash in them and we use
796 [BB check if usernames can have forward slash in them BB]
797 backslash as domain\user separator character
799 static char * check_for_domain(char **ppuser)
801 char * original_string;
802 char * usernm;
803 char * domainnm;
804 int original_len;
805 int len;
806 int i;
808 if(ppuser == NULL)
809 return NULL;
811 original_string = *ppuser;
813 if (original_string == NULL)
814 return NULL;
816 original_len = strlen(original_string);
818 usernm = strchr(*ppuser,'/');
819 if (usernm == NULL) {
820 usernm = strchr(*ppuser,'\\');
821 if (usernm == NULL)
822 return NULL;
825 if(got_domain) {
826 printf("Domain name specified twice. Username probably malformed\n");
827 return NULL;
830 usernm[0] = 0;
831 domainnm = *ppuser;
832 if (domainnm[0] != 0) {
833 got_domain = 1;
834 } else {
835 printf("null domain\n");
837 len = strlen(domainnm);
838 /* reset domainm to new buffer, and copy
839 domain name into it */
840 domainnm = (char *)malloc(len+1);
841 if(domainnm == NULL)
842 return NULL;
844 strlcpy(domainnm,*ppuser,len+1);
846 /* move_string(*ppuser, usernm+1) */
847 len = strlen(usernm+1);
849 if(len >= original_len) {
850 /* should not happen */
851 return domainnm;
854 for(i=0;i<original_len;i++) {
855 if(i<len)
856 original_string[i] = usernm[i+1];
857 else /* stuff with commas to remove last parm */
858 original_string[i] = ',';
861 /* BB add check for more than one slash?
862 strchr(*ppuser,'/');
863 strchr(*ppuser,'\\')
866 return domainnm;
869 /* replace all occurances of "from" in a string with "to" */
870 static void replace_char(char *string, char from, char to, int maxlen)
872 char *lastchar = string + maxlen;
873 while (string) {
874 string = strchr(string, from);
875 if (string) {
876 *string = to;
877 if (string >= lastchar)
878 return;
883 /* Note that caller frees the returned buffer if necessary */
884 static struct addrinfo *
885 parse_server(char ** punc_name)
887 char * unc_name = *punc_name;
888 int length = strnlen(unc_name, MAX_UNC_LEN);
889 char * share;
890 struct addrinfo *addrlist;
891 int rc;
893 if(length > (MAX_UNC_LEN - 1)) {
894 printf("mount error: UNC name too long");
895 return NULL;
897 if ((strncasecmp("cifs://", unc_name, 7) == 0) ||
898 (strncasecmp("smb://", unc_name, 6) == 0)) {
899 printf("\nMounting cifs URL not implemented yet. Attempt to mount %s\n", unc_name);
900 return NULL;
903 if(length < 3) {
904 /* BB add code to find DFS root here */
905 printf("\nMounting the DFS root for domain not implemented yet\n");
906 return NULL;
907 } else {
908 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
909 /* check for nfs syntax ie server:share */
910 share = strchr(unc_name,':');
911 if(share) {
912 *punc_name = (char *)malloc(length+3);
913 if(*punc_name == NULL) {
914 /* put the original string back if
915 no memory left */
916 *punc_name = unc_name;
917 return NULL;
919 *share = '/';
920 strlcpy((*punc_name)+2,unc_name,length+1);
921 SAFE_FREE(unc_name);
922 unc_name = *punc_name;
923 unc_name[length+2] = 0;
924 goto continue_unc_parsing;
925 } else {
926 printf("mount error: improperly formatted UNC name.");
927 printf(" %s does not begin with \\\\ or //\n",unc_name);
928 return NULL;
930 } else {
931 continue_unc_parsing:
932 unc_name[0] = '/';
933 unc_name[1] = '/';
934 unc_name += 2;
936 /* allow for either delimiter between host and sharename */
937 if ((share = strpbrk(unc_name, "/\\"))) {
938 *share = 0; /* temporarily terminate the string */
939 share += 1;
940 if(got_ip == 0) {
941 rc = getaddrinfo(unc_name, NULL, NULL, &addrlist);
942 if (rc != 0) {
943 printf("mount error: could not resolve address for %s: %s\n",
944 unc_name, gai_strerror(rc));
945 addrlist = NULL;
948 *(share - 1) = '/'; /* put delimiter back */
950 /* we don't convert the prefixpath delimiters since '\\' is a valid char in posix paths */
951 if ((prefixpath = strpbrk(share, "/\\"))) {
952 *prefixpath = 0; /* permanently terminate the string */
953 if (!strlen(++prefixpath))
954 prefixpath = NULL; /* this needs to be done explicitly */
956 if(got_ip) {
957 if(verboseflag)
958 printf("ip address specified explicitly\n");
959 return NULL;
961 /* BB should we pass an alternate version of the share name as Unicode */
963 return addrlist;
964 } else {
965 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
966 printf("Mounting the DFS root for a particular server not implemented yet\n");
967 return NULL;
973 static struct option longopts[] = {
974 { "all", 0, NULL, 'a' },
975 { "help",0, NULL, 'h' },
976 { "move",0, NULL, 'm' },
977 { "bind",0, NULL, 'b' },
978 { "read-only", 0, NULL, 'r' },
979 { "ro", 0, NULL, 'r' },
980 { "verbose", 0, NULL, 'v' },
981 { "version", 0, NULL, 'V' },
982 { "read-write", 0, NULL, 'w' },
983 { "rw", 0, NULL, 'w' },
984 { "options", 1, NULL, 'o' },
985 { "type", 1, NULL, 't' },
986 { "rsize",1, NULL, 'R' },
987 { "wsize",1, NULL, 'W' },
988 { "uid", 1, NULL, '1'},
989 { "gid", 1, NULL, '2'},
990 { "user",1,NULL,'u'},
991 { "username",1,NULL,'u'},
992 { "dom",1,NULL,'d'},
993 { "domain",1,NULL,'d'},
994 { "password",1,NULL,'p'},
995 { "pass",1,NULL,'p'},
996 { "credentials",1,NULL,'c'},
997 { "port",1,NULL,'P'},
998 /* { "uuid",1,NULL,'U'}, */ /* BB unimplemented */
999 { NULL, 0, NULL, 0 }
1002 /* convert a string to uppercase. return false if the string
1003 * wasn't ASCII. Return success on a NULL ptr */
1004 static int
1005 uppercase_string(char *string)
1007 if (!string)
1008 return 1;
1010 while (*string) {
1011 /* check for unicode */
1012 if ((unsigned char) string[0] & 0x80)
1013 return 0;
1014 *string = toupper((unsigned char) *string);
1015 string++;
1018 return 1;
1021 static void print_cifs_mount_version(void)
1023 printf("mount.cifs version: %s.%s%s\n",
1024 MOUNT_CIFS_VERSION_MAJOR,
1025 MOUNT_CIFS_VERSION_MINOR,
1026 MOUNT_CIFS_VENDOR_SUFFIX);
1029 int main(int argc, char ** argv)
1031 int c;
1032 int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
1033 char * orgoptions = NULL;
1034 char * share_name = NULL;
1035 const char * ipaddr = NULL;
1036 char * uuid = NULL;
1037 char * mountpoint = NULL;
1038 char * options = NULL;
1039 char * optionstail;
1040 char * resolved_path = NULL;
1041 char * temp;
1042 char * dev_name;
1043 int rc = 0;
1044 int rsize = 0;
1045 int wsize = 0;
1046 int nomtab = 0;
1047 int uid = 0;
1048 int gid = 0;
1049 int optlen = 0;
1050 int orgoptlen = 0;
1051 size_t options_size = 0;
1052 size_t current_len;
1053 int retry = 0; /* set when we have to retry mount with uppercase */
1054 struct addrinfo *addrhead = NULL, *addr;
1055 struct stat statbuf;
1056 struct utsname sysinfo;
1057 struct mntent mountent;
1058 struct sockaddr_in *addr4;
1059 struct sockaddr_in6 *addr6;
1060 FILE * pmntfile;
1062 /* setlocale(LC_ALL, "");
1063 bindtextdomain(PACKAGE, LOCALEDIR);
1064 textdomain(PACKAGE); */
1066 if(argc && argv) {
1067 thisprogram = argv[0];
1068 } else {
1069 mount_cifs_usage();
1070 exit(EX_USAGE);
1073 if(thisprogram == NULL)
1074 thisprogram = "mount.cifs";
1076 uname(&sysinfo);
1077 /* BB add workstation name and domain and pass down */
1079 /* #ifdef _GNU_SOURCE
1080 printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
1081 #endif */
1082 if(argc > 2) {
1083 dev_name = argv[1];
1084 share_name = strndup(argv[1], MAX_UNC_LEN);
1085 if (share_name == NULL) {
1086 fprintf(stderr, "%s: %s", argv[0], strerror(ENOMEM));
1087 exit(EX_SYSERR);
1089 mountpoint = argv[2];
1090 } else if (argc == 2) {
1091 if ((strcmp(argv[1], "-V") == 0) ||
1092 (strcmp(argv[1], "--version") == 0))
1094 print_cifs_mount_version();
1095 exit(0);
1098 if ((strcmp(argv[1], "-h") == 0) ||
1099 (strcmp(argv[1], "-?") == 0) ||
1100 (strcmp(argv[1], "--help") == 0))
1102 mount_cifs_usage();
1103 exit(0);
1106 mount_cifs_usage();
1107 exit(EX_USAGE);
1108 } else {
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(0);
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 print_cifs_mount_version();
1166 exit (0);
1167 case 'w':
1168 flags &= ~MS_RDONLY;
1169 break;
1170 case 'R':
1171 rsize = atoi(optarg) ;
1172 break;
1173 case 'W':
1174 wsize = atoi(optarg);
1175 break;
1176 case '1':
1177 if (isdigit(*optarg)) {
1178 char *ep;
1180 uid = strtoul(optarg, &ep, 10);
1181 if (*ep) {
1182 printf("bad uid value \"%s\"\n", optarg);
1183 exit(EX_USAGE);
1185 } else {
1186 struct passwd *pw;
1188 if (!(pw = getpwnam(optarg))) {
1189 printf("bad user name \"%s\"\n", optarg);
1190 exit(EX_USAGE);
1192 uid = pw->pw_uid;
1193 endpwent();
1195 break;
1196 case '2':
1197 if (isdigit(*optarg)) {
1198 char *ep;
1200 gid = strtoul(optarg, &ep, 10);
1201 if (*ep) {
1202 printf("bad gid value \"%s\"\n", optarg);
1203 exit(EX_USAGE);
1205 } else {
1206 struct group *gr;
1208 if (!(gr = getgrnam(optarg))) {
1209 printf("bad user name \"%s\"\n", optarg);
1210 exit(EX_USAGE);
1212 gid = gr->gr_gid;
1213 endpwent();
1215 break;
1216 case 'u':
1217 got_user = 1;
1218 user_name = optarg;
1219 break;
1220 case 'd':
1221 domain_name = optarg; /* BB fix this - currently ignored */
1222 got_domain = 1;
1223 break;
1224 case 'p':
1225 if(mountpassword == NULL)
1226 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
1227 if(mountpassword) {
1228 got_password = 1;
1229 strlcpy(mountpassword,optarg,MOUNT_PASSWD_SIZE+1);
1231 break;
1232 case 'S':
1233 get_password_from_file(0 /* stdin */,NULL);
1234 break;
1235 case 't':
1236 break;
1237 case 'f':
1238 ++fakemnt;
1239 break;
1240 default:
1241 printf("unknown mount option %c\n",c);
1242 mount_cifs_usage();
1243 exit(EX_USAGE);
1247 if((argc < 3) || (dev_name == NULL) || (mountpoint == NULL)) {
1248 mount_cifs_usage();
1249 exit(EX_USAGE);
1252 if (getenv("PASSWD")) {
1253 if(mountpassword == NULL)
1254 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
1255 if(mountpassword) {
1256 strlcpy(mountpassword,getenv("PASSWD"),MOUNT_PASSWD_SIZE+1);
1257 got_password = 1;
1259 } else if (getenv("PASSWD_FD")) {
1260 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
1261 } else if (getenv("PASSWD_FILE")) {
1262 get_password_from_file(0, getenv("PASSWD_FILE"));
1265 if (orgoptions && parse_options(&orgoptions, &flags)) {
1266 rc = EX_USAGE;
1267 goto mount_exit;
1269 addrhead = addr = parse_server(&share_name);
1270 if((addrhead == NULL) && (got_ip == 0)) {
1271 printf("No ip address specified and hostname not found\n");
1272 rc = EX_USAGE;
1273 goto mount_exit;
1276 /* BB save off path and pop after mount returns? */
1277 resolved_path = (char *)malloc(PATH_MAX+1);
1278 if(resolved_path) {
1279 /* Note that if we can not canonicalize the name, we get
1280 another chance to see if it is valid when we chdir to it */
1281 if (realpath(mountpoint, resolved_path)) {
1282 mountpoint = resolved_path;
1285 if(chdir(mountpoint)) {
1286 printf("mount error: can not change directory into mount target %s\n",mountpoint);
1287 rc = EX_USAGE;
1288 goto mount_exit;
1291 if(stat (".", &statbuf)) {
1292 printf("mount error: mount point %s does not exist\n",mountpoint);
1293 rc = EX_USAGE;
1294 goto mount_exit;
1297 if (S_ISDIR(statbuf.st_mode) == 0) {
1298 printf("mount error: mount point %s is not a directory\n",mountpoint);
1299 rc = EX_USAGE;
1300 goto mount_exit;
1303 if((getuid() != 0) && (geteuid() == 0)) {
1304 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
1305 #ifndef CIFS_ALLOW_USR_SUID
1306 /* Do not allow user mounts to control suid flag
1307 for mount unless explicitly built that way */
1308 flags |= MS_NOSUID | MS_NODEV;
1309 #endif
1310 } else {
1311 printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n");
1312 exit(EX_USAGE);
1316 if(got_user == 0) {
1317 /* Note that the password will not be retrieved from the
1318 USER env variable (ie user%password form) as there is
1319 already a PASSWD environment varaible */
1320 if (getenv("USER"))
1321 user_name = strdup(getenv("USER"));
1322 if (user_name == NULL)
1323 user_name = getusername();
1324 got_user = 1;
1327 if(got_password == 0) {
1328 char *tmp_pass = getpass("Password: "); /* BB obsolete sys call but
1329 no good replacement yet. */
1330 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
1331 if (!tmp_pass || !mountpassword) {
1332 printf("Password not entered, exiting\n");
1333 exit(EX_USAGE);
1335 strlcpy(mountpassword, tmp_pass, MOUNT_PASSWD_SIZE+1);
1336 got_password = 1;
1338 /* FIXME launch daemon (handles dfs name resolution and credential change)
1339 remember to clear parms and overwrite password field before launching */
1340 if(orgoptions) {
1341 optlen = strlen(orgoptions);
1342 orgoptlen = optlen;
1343 } else
1344 optlen = 0;
1345 if(share_name)
1346 optlen += strlen(share_name) + 4;
1347 else {
1348 printf("No server share name specified\n");
1349 printf("\nMounting the DFS root for server not implemented yet\n");
1350 exit(EX_USAGE);
1352 if(user_name)
1353 optlen += strlen(user_name) + 6;
1354 optlen += MAX_ADDRESS_LEN + 4;
1355 if(mountpassword)
1356 optlen += strlen(mountpassword) + 6;
1357 mount_retry:
1358 SAFE_FREE(options);
1359 options_size = optlen + 10 + DOMAIN_SIZE;
1360 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 */);
1362 if(options == NULL) {
1363 printf("Could not allocate memory for mount options\n");
1364 exit(EX_SYSERR);
1367 strlcpy(options, "unc=", options_size);
1368 strlcat(options,share_name,options_size);
1369 /* scan backwards and reverse direction of slash */
1370 temp = strrchr(options, '/');
1371 if(temp > options + 6)
1372 *temp = '\\';
1373 if(user_name) {
1374 /* check for syntax like user=domain\user */
1375 if(got_domain == 0)
1376 domain_name = check_for_domain(&user_name);
1377 strlcat(options,",user=",options_size);
1378 strlcat(options,user_name,options_size);
1380 if(retry == 0) {
1381 if(domain_name) {
1382 /* extra length accounted for in option string above */
1383 strlcat(options,",domain=",options_size);
1384 strlcat(options,domain_name,options_size);
1387 if(mountpassword) {
1388 /* Commas have to be doubled, or else they will
1389 look like the parameter separator */
1390 /* if(sep is not set)*/
1391 if(retry == 0)
1392 check_for_comma(&mountpassword);
1393 strlcat(options,",pass=",options_size);
1394 strlcat(options,mountpassword,options_size);
1397 strlcat(options,",ver=",options_size);
1398 strlcat(options,MOUNT_CIFS_VERSION_MAJOR,options_size);
1400 if(orgoptions) {
1401 strlcat(options,",",options_size);
1402 strlcat(options,orgoptions,options_size);
1404 if(prefixpath) {
1405 strlcat(options,",prefixpath=",options_size);
1406 strlcat(options,prefixpath,options_size); /* no need to cat the / */
1408 if(verboseflag)
1409 printf("\nmount.cifs kernel mount options %s \n",options);
1411 /* convert all '\\' to '/' in share portion so that /proc/mounts looks pretty */
1412 replace_char(dev_name, '\\', '/', strlen(share_name));
1414 if (!got_ip && addr) {
1415 strlcat(options, ",ip=", options_size);
1416 current_len = strnlen(options, options_size);
1417 optionstail = options + current_len;
1418 switch (addr->ai_addr->sa_family) {
1419 case AF_INET6:
1420 addr6 = (struct sockaddr_in6 *) addr->ai_addr;
1421 ipaddr = inet_ntop(AF_INET6, &addr6->sin6_addr, optionstail,
1422 options_size - current_len);
1423 break;
1424 case AF_INET:
1425 addr4 = (struct sockaddr_in *) addr->ai_addr;
1426 ipaddr = inet_ntop(AF_INET, &addr4->sin_addr, optionstail,
1427 options_size - current_len);
1428 break;
1431 /* if the address looks bogus, try the next one */
1432 if (!ipaddr) {
1433 addr = addr->ai_next;
1434 if (addr)
1435 goto mount_retry;
1436 rc = EX_SYSERR;
1437 goto mount_exit;
1441 if (!fakemnt && mount(dev_name, mountpoint, "cifs", flags, options)) {
1442 switch (errno) {
1443 case ECONNREFUSED:
1444 case EHOSTUNREACH:
1445 if (addr) {
1446 addr = addr->ai_next;
1447 if (addr)
1448 goto mount_retry;
1450 break;
1451 case ENODEV:
1452 printf("mount error: cifs filesystem not supported by the system\n");
1453 break;
1454 case ENXIO:
1455 if(retry == 0) {
1456 retry = 1;
1457 if (uppercase_string(dev_name) &&
1458 uppercase_string(share_name) &&
1459 uppercase_string(prefixpath)) {
1460 printf("retrying with upper case share name\n");
1461 goto mount_retry;
1465 printf("mount error(%d): %s\n", errno, strerror(errno));
1466 printf("Refer to the mount.cifs(8) manual page (e.g. man "
1467 "mount.cifs)\n");
1468 rc = EX_FAIL;
1469 goto mount_exit;
1472 if (nomtab)
1473 goto mount_exit;
1474 atexit(unlock_mtab);
1475 rc = lock_mtab();
1476 if (rc) {
1477 printf("cannot lock mtab");
1478 goto mount_exit;
1480 pmntfile = setmntent(MOUNTED, "a+");
1481 if (!pmntfile) {
1482 printf("could not update mount table\n");
1483 unlock_mtab();
1484 rc = EX_FILEIO;
1485 goto mount_exit;
1487 mountent.mnt_fsname = dev_name;
1488 mountent.mnt_dir = mountpoint;
1489 mountent.mnt_type = CONST_DISCARD(char *,"cifs");
1490 mountent.mnt_opts = (char *)malloc(220);
1491 if(mountent.mnt_opts) {
1492 char * mount_user = getusername();
1493 memset(mountent.mnt_opts,0,200);
1494 if(flags & MS_RDONLY)
1495 strlcat(mountent.mnt_opts,"ro",220);
1496 else
1497 strlcat(mountent.mnt_opts,"rw",220);
1498 if(flags & MS_MANDLOCK)
1499 strlcat(mountent.mnt_opts,",mand",220);
1500 if(flags & MS_NOEXEC)
1501 strlcat(mountent.mnt_opts,",noexec",220);
1502 if(flags & MS_NOSUID)
1503 strlcat(mountent.mnt_opts,",nosuid",220);
1504 if(flags & MS_NODEV)
1505 strlcat(mountent.mnt_opts,",nodev",220);
1506 if(flags & MS_SYNCHRONOUS)
1507 strlcat(mountent.mnt_opts,",sync",220);
1508 if(mount_user) {
1509 if(getuid() != 0) {
1510 strlcat(mountent.mnt_opts,
1511 ",user=", 220);
1512 strlcat(mountent.mnt_opts,
1513 mount_user, 220);
1517 mountent.mnt_freq = 0;
1518 mountent.mnt_passno = 0;
1519 rc = addmntent(pmntfile,&mountent);
1520 endmntent(pmntfile);
1521 unlock_mtab();
1522 SAFE_FREE(mountent.mnt_opts);
1523 if (rc)
1524 rc = EX_FILEIO;
1525 mount_exit:
1526 if(mountpassword) {
1527 int len = strlen(mountpassword);
1528 memset(mountpassword,0,len);
1529 SAFE_FREE(mountpassword);
1532 if (addrhead)
1533 freeaddrinfo(addrhead);
1534 SAFE_FREE(options);
1535 SAFE_FREE(orgoptions);
1536 SAFE_FREE(resolved_path);
1537 SAFE_FREE(share_name);
1538 exit(rc);