s3:mount.cifs: make "mount.cifs -V" print the version, not usage.
[Samba/ekacnet.git] / source / client / mount.cifs.c
blob0add7a8d39e06b2b81c6049d31b2b5acc278b09e
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 static void print_cifs_mount_version(void)
1041 printf("mount.cifs version: %s.%s%s\n",
1042 MOUNT_CIFS_VERSION_MAJOR,
1043 MOUNT_CIFS_VERSION_MINOR,
1044 MOUNT_CIFS_VENDOR_SUFFIX);
1047 int main(int argc, char ** argv)
1049 int c;
1050 int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
1051 char * orgoptions = NULL;
1052 char * share_name = NULL;
1053 const char * ipaddr = NULL;
1054 char * uuid = NULL;
1055 char * mountpoint = NULL;
1056 char * options = NULL;
1057 char * optionstail;
1058 char * resolved_path = NULL;
1059 char * temp;
1060 char * dev_name;
1061 int rc = 0;
1062 int rsize = 0;
1063 int wsize = 0;
1064 int nomtab = 0;
1065 int uid = 0;
1066 int gid = 0;
1067 int optlen = 0;
1068 int orgoptlen = 0;
1069 size_t options_size = 0;
1070 size_t current_len;
1071 int retry = 0; /* set when we have to retry mount with uppercase */
1072 struct addrinfo *addrhead = NULL, *addr;
1073 struct stat statbuf;
1074 struct utsname sysinfo;
1075 struct mntent mountent;
1076 struct sockaddr_in *addr4;
1077 struct sockaddr_in6 *addr6;
1078 FILE * pmntfile;
1080 /* setlocale(LC_ALL, "");
1081 bindtextdomain(PACKAGE, LOCALEDIR);
1082 textdomain(PACKAGE); */
1084 if(argc && argv) {
1085 thisprogram = argv[0];
1086 } else {
1087 mount_cifs_usage();
1088 exit(EX_USAGE);
1091 if(thisprogram == NULL)
1092 thisprogram = "mount.cifs";
1094 uname(&sysinfo);
1095 /* BB add workstation name and domain and pass down */
1097 /* #ifdef _GNU_SOURCE
1098 printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
1099 #endif */
1100 if(argc > 2) {
1101 dev_name = argv[1];
1102 share_name = strndup(argv[1], MAX_UNC_LEN);
1103 if (share_name == NULL) {
1104 fprintf(stderr, "%s: %s", argv[0], strerror(ENOMEM));
1105 exit(EX_SYSERR);
1107 mountpoint = argv[2];
1108 } else if (argc == 2) {
1109 if ((strcmp(argv[1], "-V") == 0) ||
1110 (strcmp(argv[1], "--version") == 0))
1112 print_cifs_mount_version();
1113 exit(0);
1116 if ((strcmp(argv[1], "-h") == 0) ||
1117 (strcmp(argv[1], "-?") == 0) ||
1118 (strcmp(argv[1], "--help") == 0))
1120 mount_cifs_usage();
1121 exit(0);
1124 mount_cifs_usage();
1125 exit(EX_USAGE);
1126 } else {
1127 mount_cifs_usage();
1128 exit(EX_USAGE);
1131 /* add sharename in opts string as unc= parm */
1133 while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
1134 longopts, NULL)) != -1) {
1135 switch (c) {
1136 /* No code to do the following options yet */
1137 /* case 'l':
1138 list_with_volumelabel = 1;
1139 break;
1140 case 'L':
1141 volumelabel = optarg;
1142 break; */
1143 /* case 'a':
1144 ++mount_all;
1145 break; */
1147 case '?':
1148 case 'h': /* help */
1149 mount_cifs_usage ();
1150 exit(EX_USAGE);
1151 case 'n':
1152 ++nomtab;
1153 break;
1154 case 'b':
1155 #ifdef MS_BIND
1156 flags |= MS_BIND;
1157 #else
1158 fprintf(stderr,
1159 "option 'b' (MS_BIND) not supported\n");
1160 #endif
1161 break;
1162 case 'm':
1163 #ifdef MS_MOVE
1164 flags |= MS_MOVE;
1165 #else
1166 fprintf(stderr,
1167 "option 'm' (MS_MOVE) not supported\n");
1168 #endif
1169 break;
1170 case 'o':
1171 orgoptions = strdup(optarg);
1172 break;
1173 case 'r': /* mount readonly */
1174 flags |= MS_RDONLY;
1175 break;
1176 case 'U':
1177 uuid = optarg;
1178 break;
1179 case 'v':
1180 ++verboseflag;
1181 break;
1182 case 'V':
1183 print_cifs_mount_version();
1184 exit (0);
1185 case 'w':
1186 flags &= ~MS_RDONLY;
1187 break;
1188 case 'R':
1189 rsize = atoi(optarg) ;
1190 break;
1191 case 'W':
1192 wsize = atoi(optarg);
1193 break;
1194 case '1':
1195 if (isdigit(*optarg)) {
1196 char *ep;
1198 uid = strtoul(optarg, &ep, 10);
1199 if (*ep) {
1200 printf("bad uid value \"%s\"\n", optarg);
1201 exit(EX_USAGE);
1203 } else {
1204 struct passwd *pw;
1206 if (!(pw = getpwnam(optarg))) {
1207 printf("bad user name \"%s\"\n", optarg);
1208 exit(EX_USAGE);
1210 uid = pw->pw_uid;
1211 endpwent();
1213 break;
1214 case '2':
1215 if (isdigit(*optarg)) {
1216 char *ep;
1218 gid = strtoul(optarg, &ep, 10);
1219 if (*ep) {
1220 printf("bad gid value \"%s\"\n", optarg);
1221 exit(EX_USAGE);
1223 } else {
1224 struct group *gr;
1226 if (!(gr = getgrnam(optarg))) {
1227 printf("bad user name \"%s\"\n", optarg);
1228 exit(EX_USAGE);
1230 gid = gr->gr_gid;
1231 endpwent();
1233 break;
1234 case 'u':
1235 got_user = 1;
1236 user_name = optarg;
1237 break;
1238 case 'd':
1239 domain_name = optarg; /* BB fix this - currently ignored */
1240 got_domain = 1;
1241 break;
1242 case 'p':
1243 if(mountpassword == NULL)
1244 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
1245 if(mountpassword) {
1246 got_password = 1;
1247 strlcpy(mountpassword,optarg,MOUNT_PASSWD_SIZE+1);
1249 break;
1250 case 'S':
1251 get_password_from_file(0 /* stdin */,NULL);
1252 break;
1253 case 't':
1254 break;
1255 case 'f':
1256 ++fakemnt;
1257 break;
1258 default:
1259 printf("unknown mount option %c\n",c);
1260 mount_cifs_usage();
1261 exit(EX_USAGE);
1265 if((argc < 3) || (dev_name == NULL) || (mountpoint == NULL)) {
1266 mount_cifs_usage();
1267 exit(EX_USAGE);
1270 if (getenv("PASSWD")) {
1271 if(mountpassword == NULL)
1272 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
1273 if(mountpassword) {
1274 strlcpy(mountpassword,getenv("PASSWD"),MOUNT_PASSWD_SIZE+1);
1275 got_password = 1;
1277 } else if (getenv("PASSWD_FD")) {
1278 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
1279 } else if (getenv("PASSWD_FILE")) {
1280 get_password_from_file(0, getenv("PASSWD_FILE"));
1283 if (orgoptions && parse_options(&orgoptions, &flags)) {
1284 rc = EX_USAGE;
1285 goto mount_exit;
1287 addrhead = addr = parse_server(&share_name);
1288 if((addrhead == NULL) && (got_ip == 0)) {
1289 printf("No ip address specified and hostname not found\n");
1290 rc = EX_USAGE;
1291 goto mount_exit;
1294 /* BB save off path and pop after mount returns? */
1295 resolved_path = (char *)malloc(PATH_MAX+1);
1296 if(resolved_path) {
1297 /* Note that if we can not canonicalize the name, we get
1298 another chance to see if it is valid when we chdir to it */
1299 if (realpath(mountpoint, resolved_path)) {
1300 mountpoint = resolved_path;
1303 if(chdir(mountpoint)) {
1304 printf("mount error: can not change directory into mount target %s\n",mountpoint);
1305 rc = EX_USAGE;
1306 goto mount_exit;
1309 if(stat (".", &statbuf)) {
1310 printf("mount error: mount point %s does not exist\n",mountpoint);
1311 rc = EX_USAGE;
1312 goto mount_exit;
1315 if (S_ISDIR(statbuf.st_mode) == 0) {
1316 printf("mount error: mount point %s is not a directory\n",mountpoint);
1317 rc = EX_USAGE;
1318 goto mount_exit;
1321 if((getuid() != 0) && (geteuid() == 0)) {
1322 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
1323 #ifndef CIFS_ALLOW_USR_SUID
1324 /* Do not allow user mounts to control suid flag
1325 for mount unless explicitly built that way */
1326 flags |= MS_NOSUID | MS_NODEV;
1327 #endif
1328 } else {
1329 printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n");
1330 exit(EX_USAGE);
1334 if(got_user == 0) {
1335 /* Note that the password will not be retrieved from the
1336 USER env variable (ie user%password form) as there is
1337 already a PASSWD environment varaible */
1338 if (getenv("USER"))
1339 user_name = strdup(getenv("USER"));
1340 if (user_name == NULL)
1341 user_name = getusername();
1342 got_user = 1;
1345 if(got_password == 0) {
1346 char *tmp_pass = getpass("Password: "); /* BB obsolete sys call but
1347 no good replacement yet. */
1348 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
1349 if (!tmp_pass || !mountpassword) {
1350 printf("Password not entered, exiting\n");
1351 exit(EX_USAGE);
1353 strlcpy(mountpassword, tmp_pass, MOUNT_PASSWD_SIZE+1);
1354 got_password = 1;
1356 /* FIXME launch daemon (handles dfs name resolution and credential change)
1357 remember to clear parms and overwrite password field before launching */
1358 if(orgoptions) {
1359 optlen = strlen(orgoptions);
1360 orgoptlen = optlen;
1361 } else
1362 optlen = 0;
1363 if(share_name)
1364 optlen += strlen(share_name) + 4;
1365 else {
1366 printf("No server share name specified\n");
1367 printf("\nMounting the DFS root for server not implemented yet\n");
1368 exit(EX_USAGE);
1370 if(user_name)
1371 optlen += strlen(user_name) + 6;
1372 optlen += MAX_ADDRESS_LEN + 4;
1373 if(mountpassword)
1374 optlen += strlen(mountpassword) + 6;
1375 mount_retry:
1376 SAFE_FREE(options);
1377 options_size = optlen + 10 + DOMAIN_SIZE;
1378 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 */);
1380 if(options == NULL) {
1381 printf("Could not allocate memory for mount options\n");
1382 exit(EX_SYSERR);
1385 strlcpy(options, "unc=", options_size);
1386 strlcat(options,share_name,options_size);
1387 /* scan backwards and reverse direction of slash */
1388 temp = strrchr(options, '/');
1389 if(temp > options + 6)
1390 *temp = '\\';
1391 if(user_name) {
1392 /* check for syntax like user=domain\user */
1393 if(got_domain == 0)
1394 domain_name = check_for_domain(&user_name);
1395 strlcat(options,",user=",options_size);
1396 strlcat(options,user_name,options_size);
1398 if(retry == 0) {
1399 if(domain_name) {
1400 /* extra length accounted for in option string above */
1401 strlcat(options,",domain=",options_size);
1402 strlcat(options,domain_name,options_size);
1406 strlcat(options,",ver=",options_size);
1407 strlcat(options,MOUNT_CIFS_VERSION_MAJOR,options_size);
1409 if(orgoptions) {
1410 strlcat(options,",",options_size);
1411 strlcat(options,orgoptions,options_size);
1413 if(prefixpath) {
1414 strlcat(options,",prefixpath=",options_size);
1415 strlcat(options,prefixpath,options_size); /* no need to cat the / */
1418 /* convert all '\\' to '/' in share portion so that /proc/mounts looks pretty */
1419 replace_char(dev_name, '\\', '/', strlen(share_name));
1421 if (!got_ip && addr) {
1422 strlcat(options, ",ip=", options_size);
1423 current_len = strnlen(options, options_size);
1424 optionstail = options + current_len;
1425 switch (addr->ai_addr->sa_family) {
1426 case AF_INET6:
1427 addr6 = (struct sockaddr_in6 *) addr->ai_addr;
1428 ipaddr = inet_ntop(AF_INET6, &addr6->sin6_addr, optionstail,
1429 options_size - current_len);
1430 break;
1431 case AF_INET:
1432 addr4 = (struct sockaddr_in *) addr->ai_addr;
1433 ipaddr = inet_ntop(AF_INET, &addr4->sin_addr, optionstail,
1434 options_size - current_len);
1435 break;
1438 /* if the address looks bogus, try the next one */
1439 if (!ipaddr) {
1440 addr = addr->ai_next;
1441 if (addr)
1442 goto mount_retry;
1443 rc = EX_SYSERR;
1444 goto mount_exit;
1448 if(verboseflag)
1449 fprintf(stderr, "\nmount.cifs kernel mount options: %s", options);
1451 if (mountpassword) {
1453 * Commas have to be doubled, or else they will
1454 * look like the parameter separator
1456 if(retry == 0)
1457 check_for_comma(&mountpassword);
1458 strlcat(options,",pass=",options_size);
1459 strlcat(options,mountpassword,options_size);
1460 if (verboseflag)
1461 fprintf(stderr, ",pass=********");
1464 if (verboseflag)
1465 fprintf(stderr, "\n");
1467 if (!fakemnt && mount(dev_name, mountpoint, "cifs", flags, options)) {
1468 switch (errno) {
1469 case ECONNREFUSED:
1470 case EHOSTUNREACH:
1471 if (addr) {
1472 addr = addr->ai_next;
1473 if (addr)
1474 goto mount_retry;
1476 break;
1477 case ENODEV:
1478 printf("mount error: cifs filesystem not supported by the system\n");
1479 break;
1480 case ENXIO:
1481 if(retry == 0) {
1482 retry = 1;
1483 if (uppercase_string(dev_name) &&
1484 uppercase_string(share_name) &&
1485 uppercase_string(prefixpath)) {
1486 printf("retrying with upper case share name\n");
1487 goto mount_retry;
1491 printf("mount error(%d): %s\n", errno, strerror(errno));
1492 printf("Refer to the mount.cifs(8) manual page (e.g. man "
1493 "mount.cifs)\n");
1494 rc = EX_FAIL;
1495 goto mount_exit;
1498 if (nomtab)
1499 goto mount_exit;
1500 atexit(unlock_mtab);
1501 rc = lock_mtab();
1502 if (rc) {
1503 printf("cannot lock mtab");
1504 goto mount_exit;
1506 pmntfile = setmntent(MOUNTED, "a+");
1507 if (!pmntfile) {
1508 printf("could not update mount table\n");
1509 unlock_mtab();
1510 rc = EX_FILEIO;
1511 goto mount_exit;
1513 mountent.mnt_fsname = dev_name;
1514 mountent.mnt_dir = mountpoint;
1515 mountent.mnt_type = CONST_DISCARD(char *,"cifs");
1516 mountent.mnt_opts = (char *)malloc(220);
1517 if(mountent.mnt_opts) {
1518 char * mount_user = getusername();
1519 memset(mountent.mnt_opts,0,200);
1520 if(flags & MS_RDONLY)
1521 strlcat(mountent.mnt_opts,"ro",220);
1522 else
1523 strlcat(mountent.mnt_opts,"rw",220);
1524 if(flags & MS_MANDLOCK)
1525 strlcat(mountent.mnt_opts,",mand",220);
1526 if(flags & MS_NOEXEC)
1527 strlcat(mountent.mnt_opts,",noexec",220);
1528 if(flags & MS_NOSUID)
1529 strlcat(mountent.mnt_opts,",nosuid",220);
1530 if(flags & MS_NODEV)
1531 strlcat(mountent.mnt_opts,",nodev",220);
1532 if(flags & MS_SYNCHRONOUS)
1533 strlcat(mountent.mnt_opts,",sync",220);
1534 if(mount_user) {
1535 if(getuid() != 0) {
1536 strlcat(mountent.mnt_opts,
1537 ",user=", 220);
1538 strlcat(mountent.mnt_opts,
1539 mount_user, 220);
1543 mountent.mnt_freq = 0;
1544 mountent.mnt_passno = 0;
1545 rc = addmntent(pmntfile,&mountent);
1546 endmntent(pmntfile);
1547 unlock_mtab();
1548 SAFE_FREE(mountent.mnt_opts);
1549 if (rc)
1550 rc = EX_FILEIO;
1551 mount_exit:
1552 if(mountpassword) {
1553 int len = strlen(mountpassword);
1554 memset(mountpassword,0,len);
1555 SAFE_FREE(mountpassword);
1558 if (addrhead)
1559 freeaddrinfo(addrhead);
1560 SAFE_FREE(options);
1561 SAFE_FREE(orgoptions);
1562 SAFE_FREE(resolved_path);
1563 SAFE_FREE(share_name);
1564 exit(rc);