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