source: branches/samba-3.2.x/source/client/mount.cifs.c@ 231

Last change on this file since 231 was 228, checked in by Herwig Bauernfeind, 16 years ago

Update 3.2 branch to 3.2.6

File size: 39.8 KB
Line 
1/*
2 Mount helper utility for Linux CIFS VFS (virtual filesystem) client
3 Copyright (C) 2003,2008 Steve French (sfrench@us.ibm.com)
4 Copyright (C) 2008 Jeremy Allison (jra@samba.org)
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18
19#ifndef _GNU_SOURCE
20#define _GNU_SOURCE
21#endif
22
23#include <stdlib.h>
24#include <stdio.h>
25#include <unistd.h>
26#include <pwd.h>
27#include <grp.h>
28#include <ctype.h>
29#include <sys/types.h>
30#include <sys/mount.h>
31#include <sys/stat.h>
32#include <sys/utsname.h>
33#include <sys/socket.h>
34#include <arpa/inet.h>
35#include <getopt.h>
36#include <errno.h>
37#include <netdb.h>
38#include <string.h>
39#include <mntent.h>
40#include <fcntl.h>
41#include <limits.h>
42#include "mount.h"
43
44#define MOUNT_CIFS_VERSION_MAJOR "1"
45#define MOUNT_CIFS_VERSION_MINOR "12"
46
47#ifndef MOUNT_CIFS_VENDOR_SUFFIX
48 #ifdef _SAMBA_BUILD_
49 #include "include/version.h"
50 #ifdef SAMBA_VERSION_VENDOR_SUFFIX
51 #define MOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING"-"SAMBA_VERSION_VENDOR_SUFFIX
52 #else
53 #define MOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING
54 #endif /* SAMBA_VERSION_OFFICIAL_STRING and SAMBA_VERSION_VENDOR_SUFFIX */
55 #else
56 #define MOUNT_CIFS_VENDOR_SUFFIX ""
57 #endif /* _SAMBA_BUILD_ */
58#endif /* MOUNT_CIFS_VENDOR_SUFFIX */
59
60#ifdef _SAMBA_BUILD_
61#include "include/config.h"
62#endif
63
64#ifndef MS_MOVE
65#define MS_MOVE 8192
66#endif
67
68#ifndef MS_BIND
69#define MS_BIND 4096
70#endif
71
72#define MAX_UNC_LEN 1024
73
74#define CONST_DISCARD(type, ptr) ((type) ((void *) (ptr)))
75
76#ifndef SAFE_FREE
77#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); x=NULL;} } while(0)
78#endif
79
80#define MOUNT_PASSWD_SIZE 64
81#define DOMAIN_SIZE 64
82
83const char *thisprogram;
84int verboseflag = 0;
85static int got_password = 0;
86static int got_user = 0;
87static int got_domain = 0;
88static int got_ip = 0;
89static int got_unc = 0;
90static int got_uid = 0;
91static int got_gid = 0;
92static char * user_name = NULL;
93static char * mountpassword = NULL;
94char * domain_name = NULL;
95char * prefixpath = NULL;
96
97/* glibc doesn't have strlcpy, strlcat. Ensure we do. JRA. We
98 * don't link to libreplace so need them here. */
99
100/* like strncpy but does not 0 fill the buffer and always null
101 * terminates. bufsize is the size of the destination buffer */
102
103#ifndef HAVE_STRLCPY
104static size_t strlcpy(char *d, const char *s, size_t bufsize)
105{
106 size_t len = strlen(s);
107 size_t ret = len;
108 if (bufsize <= 0) return 0;
109 if (len >= bufsize) len = bufsize-1;
110 memcpy(d, s, len);
111 d[len] = 0;
112 return ret;
113}
114#endif
115
116/* like strncat but does not 0 fill the buffer and always null
117 * terminates. bufsize is the length of the buffer, which should
118 * be one more than the maximum resulting string length */
119
120#ifndef HAVE_STRLCAT
121static size_t strlcat(char *d, const char *s, size_t bufsize)
122{
123 size_t len1 = strlen(d);
124 size_t len2 = strlen(s);
125 size_t ret = len1 + len2;
126
127 if (len1+len2 >= bufsize) {
128 if (bufsize < (len1+1)) {
129 return ret;
130 }
131 len2 = bufsize - (len1+1);
132 }
133 if (len2 > 0) {
134 memcpy(d+len1, s, len2);
135 d[len1+len2] = 0;
136 }
137 return ret;
138}
139#endif
140
141/* BB finish BB
142
143 cifs_umount
144 open nofollow - avoid symlink exposure?
145 get owner of dir see if matches self or if root
146 call system(umount argv) etc.
147
148BB end finish BB */
149
150static char * check_for_domain(char **);
151
152
153static void mount_cifs_usage(void)
154{
155 printf("\nUsage: %s <remotetarget> <dir> -o <options>\n", thisprogram);
156 printf("\nMount the remote target, specified as a UNC name,");
157 printf(" to a local directory.\n\nOptions:\n");
158 printf("\tuser=<arg>\n\tpass=<arg>\n\tdom=<arg>\n");
159 printf("\nLess commonly used options:");
160 printf("\n\tcredentials=<filename>,guest,perm,noperm,setuids,nosetuids,rw,ro,");
161 printf("\n\tsep=<char>,iocharset=<codepage>,suid,nosuid,exec,noexec,serverino,");
162 printf("\n\tmapchars,nomapchars,nolock,servernetbiosname=<SRV_RFC1001NAME>");
163 printf("\n\tdirectio,nounix,cifsacl,sec=<authentication mechanism>,sign");
164 printf("\n\nOptions not needed for servers supporting CIFS Unix extensions");
165 printf("\n\t(e.g. unneeded for mounts to most Samba versions):");
166 printf("\n\tuid=<uid>,gid=<gid>,dir_mode=<mode>,file_mode=<mode>,sfu");
167 printf("\n\nRarely used options:");
168 printf("\n\tport=<tcpport>,rsize=<size>,wsize=<size>,unc=<unc_name>,ip=<ip_address>,");
169 printf("\n\tdev,nodev,nouser_xattr,netbiosname=<OUR_RFC1001NAME>,hard,soft,intr,");
170 printf("\n\tnointr,ignorecase,noposixpaths,noacl,prefixpath=<path>,nobrl");
171 printf("\n\tin6_addr");
172 printf("\n\nOptions are described in more detail in the manual page");
173 printf("\n\tman 8 mount.cifs\n");
174 printf("\nTo display the version number of the mount helper:");
175 printf("\n\t%s -V\n",thisprogram);
176
177 SAFE_FREE(mountpassword);
178 exit(EX_USAGE);
179}
180
181/* caller frees username if necessary */
182static char * getusername(void) {
183 char *username = NULL;
184 struct passwd *password = getpwuid(getuid());
185
186 if (password) {
187 username = password->pw_name;
188 }
189 return username;
190}
191
192static char * parse_cifs_url(char * unc_name)
193{
194 printf("\nMounting cifs URL not implemented yet. Attempt to mount %s\n",unc_name);
195 return NULL;
196}
197
198static int open_cred_file(char * file_name)
199{
200 char * line_buf;
201 char * temp_val;
202 FILE * fs;
203 int i, length;
204 fs = fopen(file_name,"r");
205 if(fs == NULL)
206 return errno;
207 line_buf = (char *)malloc(4096);
208 if(line_buf == NULL) {
209 fclose(fs);
210 return ENOMEM;
211 }
212
213 while(fgets(line_buf,4096,fs)) {
214 /* parse line from credential file */
215
216 /* eat leading white space */
217 for(i=0;i<4086;i++) {
218 if((line_buf[i] != ' ') && (line_buf[i] != '\t'))
219 break;
220 /* if whitespace - skip past it */
221 }
222 if (strncasecmp("username",line_buf+i,8) == 0) {
223 temp_val = strchr(line_buf + i,'=');
224 if(temp_val) {
225 /* go past equals sign */
226 temp_val++;
227 for(length = 0;length<4087;length++) {
228 if ((temp_val[length] == '\n')
229 || (temp_val[length] == '\0')) {
230 temp_val[length] = '\0';
231 break;
232 }
233 }
234 if(length > 4086) {
235 printf("mount.cifs failed due to malformed username in credentials file");
236 memset(line_buf,0,4096);
237 exit(EX_USAGE);
238 } else {
239 got_user = 1;
240 user_name = (char *)calloc(1 + length,1);
241 /* BB adding free of user_name string before exit,
242 not really necessary but would be cleaner */
243 strlcpy(user_name,temp_val, length+1);
244 }
245 }
246 } else if (strncasecmp("password",line_buf+i,8) == 0) {
247 temp_val = strchr(line_buf+i,'=');
248 if(temp_val) {
249 /* go past equals sign */
250 temp_val++;
251 for(length = 0;length<MOUNT_PASSWD_SIZE+1;length++) {
252 if ((temp_val[length] == '\n')
253 || (temp_val[length] == '\0')) {
254 temp_val[length] = '\0';
255 break;
256 }
257 }
258 if(length > MOUNT_PASSWD_SIZE) {
259 printf("mount.cifs failed: password in credentials file too long\n");
260 memset(line_buf,0, 4096);
261 exit(EX_USAGE);
262 } else {
263 if(mountpassword == NULL) {
264 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
265 } else
266 memset(mountpassword,0,MOUNT_PASSWD_SIZE);
267 if(mountpassword) {
268 strlcpy(mountpassword,temp_val,MOUNT_PASSWD_SIZE+1);
269 got_password = 1;
270 }
271 }
272 }
273 } else if (strncasecmp("domain",line_buf+i,6) == 0) {
274 temp_val = strchr(line_buf+i,'=');
275 if(temp_val) {
276 /* go past equals sign */
277 temp_val++;
278 if(verboseflag)
279 printf("\nDomain %s\n",temp_val);
280 for(length = 0;length<DOMAIN_SIZE+1;length++) {
281 if ((temp_val[length] == '\n')
282 || (temp_val[length] == '\0')) {
283 temp_val[length] = '\0';
284 break;
285 }
286 }
287 if(length > DOMAIN_SIZE) {
288 printf("mount.cifs failed: domain in credentials file too long\n");
289 exit(EX_USAGE);
290 } else {
291 if(domain_name == NULL) {
292 domain_name = (char *)calloc(DOMAIN_SIZE+1,1);
293 } else
294 memset(domain_name,0,DOMAIN_SIZE);
295 if(domain_name) {
296 strlcpy(domain_name,temp_val,DOMAIN_SIZE+1);
297 got_domain = 1;
298 }
299 }
300 }
301 }
302
303 }
304 fclose(fs);
305 SAFE_FREE(line_buf);
306 return 0;
307}
308
309static int get_password_from_file(int file_descript, char * filename)
310{
311 int rc = 0;
312 int i;
313 char c;
314
315 if(mountpassword == NULL)
316 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
317 else
318 memset(mountpassword, 0, MOUNT_PASSWD_SIZE);
319
320 if (mountpassword == NULL) {
321 printf("malloc failed\n");
322 exit(EX_SYSERR);
323 }
324
325 if(filename != NULL) {
326 file_descript = open(filename, O_RDONLY);
327 if(file_descript < 0) {
328 printf("mount.cifs failed. %s attempting to open password file %s\n",
329 strerror(errno),filename);
330 exit(EX_SYSERR);
331 }
332 }
333 /* else file already open and fd provided */
334
335 for(i=0;i<MOUNT_PASSWD_SIZE;i++) {
336 rc = read(file_descript,&c,1);
337 if(rc < 0) {
338 printf("mount.cifs failed. Error %s reading password file\n",strerror(errno));
339 if(filename != NULL)
340 close(file_descript);
341 exit(EX_SYSERR);
342 } else if(rc == 0) {
343 if(mountpassword[0] == 0) {
344 if(verboseflag)
345 printf("\nWarning: null password used since cifs password file empty");
346 }
347 break;
348 } else /* read valid character */ {
349 if((c == 0) || (c == '\n')) {
350 mountpassword[i] = '\0';
351 break;
352 } else
353 mountpassword[i] = c;
354 }
355 }
356 if((i == MOUNT_PASSWD_SIZE) && (verboseflag)) {
357 printf("\nWarning: password longer than %d characters specified in cifs password file",
358 MOUNT_PASSWD_SIZE);
359 }
360 got_password = 1;
361 if(filename != NULL) {
362 close(file_descript);
363 }
364
365 return rc;
366}
367
368static int parse_options(char ** optionsp, int * filesys_flags)
369{
370 const char * data;
371 char * percent_char = NULL;
372 char * value = NULL;
373 char * next_keyword = NULL;
374 char * out = NULL;
375 int out_len = 0;
376 int word_len;
377 int rc = 0;
378 char user[32];
379 char group[32];
380
381 if (!optionsp || !*optionsp)
382 return 1;
383 data = *optionsp;
384
385 if(verboseflag)
386 printf("parsing options: %s\n", data);
387
388 /* BB fixme check for separator override BB */
389
390 if (getuid()) {
391 got_uid = 1;
392 snprintf(user,sizeof(user),"%u",getuid());
393 got_gid = 1;
394 snprintf(group,sizeof(group),"%u",getgid());
395 }
396
397/* while ((data = strsep(&options, ",")) != NULL) { */
398 while(data != NULL) {
399 /* check if ends with trailing comma */
400 if(*data == 0)
401 break;
402
403 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
404 /* data = next keyword */
405 /* value = next value ie stuff after equal sign */
406
407 next_keyword = strchr(data,','); /* BB handle sep= */
408
409 /* temporarily null terminate end of keyword=value pair */
410 if(next_keyword)
411 *next_keyword++ = 0;
412
413 /* temporarily null terminate keyword to make keyword and value distinct */
414 if ((value = strchr(data, '=')) != NULL) {
415 *value = '\0';
416 value++;
417 }
418
419 if (strncmp(data, "users",5) == 0) {
420 if(!value || !*value) {
421 goto nocopy;
422 }
423 } else if (strncmp(data, "user_xattr",10) == 0) {
424 /* do nothing - need to skip so not parsed as user name */
425 } else if (strncmp(data, "user", 4) == 0) {
426
427 if (!value || !*value) {
428 if(data[4] == '\0') {
429 if(verboseflag)
430 printf("\nskipping empty user mount parameter\n");
431 /* remove the parm since it would otherwise be confusing
432 to the kernel code which would think it was a real username */
433 goto nocopy;
434 } else {
435 printf("username specified with no parameter\n");
436 SAFE_FREE(out);
437 return 1; /* needs_arg; */
438 }
439 } else {
440 if (strnlen(value, 260) < 260) {
441 got_user=1;
442 percent_char = strchr(value,'%');
443 if(percent_char) {
444 *percent_char = ',';
445 if(mountpassword == NULL)
446 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
447 if(mountpassword) {
448 if(got_password)
449 printf("\nmount.cifs warning - password specified twice\n");
450 got_password = 1;
451 percent_char++;
452 strlcpy(mountpassword, percent_char,MOUNT_PASSWD_SIZE+1);
453 /* remove password from username */
454 while(*percent_char != 0) {
455 *percent_char = ',';
456 percent_char++;
457 }
458 }
459 }
460 /* this is only case in which the user
461 name buf is not malloc - so we have to
462 check for domain name embedded within
463 the user name here since the later
464 call to check_for_domain will not be
465 invoked */
466 domain_name = check_for_domain(&value);
467 } else {
468 printf("username too long\n");
469 SAFE_FREE(out);
470 return 1;
471 }
472 }
473 } else if (strncmp(data, "pass", 4) == 0) {
474 if (!value || !*value) {
475 if(got_password) {
476 printf("\npassword specified twice, ignoring second\n");
477 } else
478 got_password = 1;
479 } else if (strnlen(value, 17) < 17) {
480 if(got_password)
481 printf("\nmount.cifs warning - password specified twice\n");
482 got_password = 1;
483 } else {
484 printf("password too long\n");
485 SAFE_FREE(out);
486 return 1;
487 }
488 } else if (strncmp(data, "sec", 3) == 0) {
489 if (value) {
490 if (!strcmp(value, "none"))
491 got_password = 1;
492 }
493 } else if (strncmp(data, "ip", 2) == 0) {
494 if (!value || !*value) {
495 printf("target ip address argument missing");
496 } else if (strnlen(value, 35) < 35) {
497 if(verboseflag)
498 printf("ip address %s override specified\n",value);
499 got_ip = 1;
500 } else {
501 printf("ip address too long\n");
502 SAFE_FREE(out);
503 return 1;
504 }
505 } else if ((strncmp(data, "unc", 3) == 0)
506 || (strncmp(data, "target", 6) == 0)
507 || (strncmp(data, "path", 4) == 0)) {
508 if (!value || !*value) {
509 printf("invalid path to network resource\n");
510 SAFE_FREE(out);
511 return 1; /* needs_arg; */
512 } else if(strnlen(value,5) < 5) {
513 printf("UNC name too short");
514 }
515
516 if (strnlen(value, 300) < 300) {
517 got_unc = 1;
518 if (strncmp(value, "//", 2) == 0) {
519 if(got_unc)
520 printf("unc name specified twice, ignoring second\n");
521 else
522 got_unc = 1;
523 } else if (strncmp(value, "\\\\", 2) != 0) {
524 printf("UNC Path does not begin with // or \\\\ \n");
525 SAFE_FREE(out);
526 return 1;
527 } else {
528 if(got_unc)
529 printf("unc name specified twice, ignoring second\n");
530 else
531 got_unc = 1;
532 }
533 } else {
534 printf("CIFS: UNC name too long\n");
535 SAFE_FREE(out);
536 return 1;
537 }
538 } else if ((strncmp(data, "domain", 3) == 0)
539 || (strncmp(data, "workgroup", 5) == 0)) {
540 if (!value || !*value) {
541 printf("CIFS: invalid domain name\n");
542 SAFE_FREE(out);
543 return 1; /* needs_arg; */
544 }
545 if (strnlen(value, DOMAIN_SIZE+1) < DOMAIN_SIZE+1) {
546 got_domain = 1;
547 } else {
548 printf("domain name too long\n");
549 SAFE_FREE(out);
550 return 1;
551 }
552 } else if (strncmp(data, "cred", 4) == 0) {
553 if (value && *value) {
554 rc = open_cred_file(value);
555 if(rc) {
556 printf("error %d (%s) opening credential file %s\n",
557 rc, strerror(rc), value);
558 SAFE_FREE(out);
559 return 1;
560 }
561 } else {
562 printf("invalid credential file name specified\n");
563 SAFE_FREE(out);
564 return 1;
565 }
566 } else if (strncmp(data, "uid", 3) == 0) {
567 if (value && *value) {
568 got_uid = 1;
569 if (!isdigit(*value)) {
570 struct passwd *pw;
571
572 if (!(pw = getpwnam(value))) {
573 printf("bad user name \"%s\"\n", value);
574 exit(EX_USAGE);
575 }
576 snprintf(user, sizeof(user), "%u", pw->pw_uid);
577 } else {
578 strlcpy(user,value,sizeof(user));
579 }
580 }
581 goto nocopy;
582 } else if (strncmp(data, "gid", 3) == 0) {
583 if (value && *value) {
584 got_gid = 1;
585 if (!isdigit(*value)) {
586 struct group *gr;
587
588 if (!(gr = getgrnam(value))) {
589 printf("bad group name \"%s\"\n", value);
590 exit(EX_USAGE);
591 }
592 snprintf(group, sizeof(group), "%u", gr->gr_gid);
593 } else {
594 strlcpy(group,value,sizeof(group));
595 }
596 }
597 goto nocopy;
598 /* fmask and dmask synonyms for people used to smbfs syntax */
599 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
600 if (!value || !*value) {
601 printf ("Option '%s' requires a numerical argument\n", data);
602 SAFE_FREE(out);
603 return 1;
604 }
605
606 if (value[0] != '0') {
607 printf ("WARNING: '%s' not expressed in octal.\n", data);
608 }
609
610 if (strcmp (data, "fmask") == 0) {
611 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
612 data = "file_mode"; /* BB fix this */
613 }
614 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
615 if (!value || !*value) {
616 printf ("Option '%s' requires a numerical argument\n", data);
617 SAFE_FREE(out);
618 return 1;
619 }
620
621 if (value[0] != '0') {
622 printf ("WARNING: '%s' not expressed in octal.\n", data);
623 }
624
625 if (strcmp (data, "dmask") == 0) {
626 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
627 data = "dir_mode";
628 }
629 /* the following eight mount options should be
630 stripped out from what is passed into the kernel
631 since these eight options are best passed as the
632 mount flags rather than redundantly to the kernel
633 and could generate spurious warnings depending on the
634 level of the corresponding cifs vfs kernel code */
635 } else if (strncmp(data, "nosuid", 6) == 0) {
636 *filesys_flags |= MS_NOSUID;
637 } else if (strncmp(data, "suid", 4) == 0) {
638 *filesys_flags &= ~MS_NOSUID;
639 } else if (strncmp(data, "nodev", 5) == 0) {
640 *filesys_flags |= MS_NODEV;
641 } else if ((strncmp(data, "nobrl", 5) == 0) ||
642 (strncmp(data, "nolock", 6) == 0)) {
643 *filesys_flags &= ~MS_MANDLOCK;
644 } else if (strncmp(data, "dev", 3) == 0) {
645 *filesys_flags &= ~MS_NODEV;
646 } else if (strncmp(data, "noexec", 6) == 0) {
647 *filesys_flags |= MS_NOEXEC;
648 } else if (strncmp(data, "exec", 4) == 0) {
649 *filesys_flags &= ~MS_NOEXEC;
650 } else if (strncmp(data, "guest", 5) == 0) {
651 got_password=1;
652 } else if (strncmp(data, "ro", 2) == 0) {
653 *filesys_flags |= MS_RDONLY;
654 } else if (strncmp(data, "rw", 2) == 0) {
655 *filesys_flags &= ~MS_RDONLY;
656 } else if (strncmp(data, "remount", 7) == 0) {
657 *filesys_flags |= MS_REMOUNT;
658 } /* else if (strnicmp(data, "port", 4) == 0) {
659 if (value && *value) {
660 vol->port =
661 simple_strtoul(value, &value, 0);
662 }
663 } else if (strnicmp(data, "rsize", 5) == 0) {
664 if (value && *value) {
665 vol->rsize =
666 simple_strtoul(value, &value, 0);
667 }
668 } else if (strnicmp(data, "wsize", 5) == 0) {
669 if (value && *value) {
670 vol->wsize =
671 simple_strtoul(value, &value, 0);
672 }
673 } else if (strnicmp(data, "version", 3) == 0) {
674 } else {
675 printf("CIFS: Unknown mount option %s\n",data);
676 } */ /* nothing to do on those four mount options above.
677 Just pass to kernel and ignore them here */
678
679 /* Copy (possibly modified) option to out */
680 word_len = strlen(data);
681 if (value)
682 word_len += 1 + strlen(value);
683
684 out = (char *)realloc(out, out_len + word_len + 2);
685 if (out == NULL) {
686 perror("malloc");
687 exit(EX_SYSERR);
688 }
689
690 if (out_len) {
691 strlcat(out, ",", out_len + word_len + 2);
692 out_len++;
693 }
694
695 if (value)
696 snprintf(out + out_len, word_len + 1, "%s=%s", data, value);
697 else
698 snprintf(out + out_len, word_len + 1, "%s", data);
699 out_len = strlen(out);
700
701nocopy:
702 data = next_keyword;
703 }
704
705 /* special-case the uid and gid */
706 if (got_uid) {
707 word_len = strlen(user);
708
709 out = (char *)realloc(out, out_len + word_len + 6);
710 if (out == NULL) {
711 perror("malloc");
712 exit(EX_SYSERR);
713 }
714
715 if (out_len) {
716 strlcat(out, ",", out_len + word_len + 6);
717 out_len++;
718 }
719 snprintf(out + out_len, word_len + 5, "uid=%s", user);
720 out_len = strlen(out);
721 }
722 if (got_gid) {
723 word_len = strlen(group);
724
725 out = (char *)realloc(out, out_len + 1 + word_len + 6);
726 if (out == NULL) {
727 perror("malloc");
728 exit(EX_SYSERR);
729 }
730
731 if (out_len) {
732 strlcat(out, ",", out_len + word_len + 6);
733 out_len++;
734 }
735 snprintf(out + out_len, word_len + 5, "gid=%s", group);
736 out_len = strlen(out);
737 }
738
739 SAFE_FREE(*optionsp);
740 *optionsp = out;
741 return 0;
742}
743
744/* replace all (one or more) commas with double commas */
745static void check_for_comma(char ** ppasswrd)
746{
747 char *new_pass_buf;
748 char *pass;
749 int i,j;
750 int number_of_commas = 0;
751 int len;
752
753 if(ppasswrd == NULL)
754 return;
755 else
756 (pass = *ppasswrd);
757
758 len = strlen(pass);
759
760 for(i=0;i<len;i++) {
761 if(pass[i] == ',')
762 number_of_commas++;
763 }
764
765 if(number_of_commas == 0)
766 return;
767 if(number_of_commas > MOUNT_PASSWD_SIZE) {
768 /* would otherwise overflow the mount options buffer */
769 printf("\nInvalid password. Password contains too many commas.\n");
770 return;
771 }
772
773 new_pass_buf = (char *)malloc(len+number_of_commas+1);
774 if(new_pass_buf == NULL)
775 return;
776
777 for(i=0,j=0;i<len;i++,j++) {
778 new_pass_buf[j] = pass[i];
779 if(pass[i] == ',') {
780 j++;
781 new_pass_buf[j] = pass[i];
782 }
783 }
784 new_pass_buf[len+number_of_commas] = 0;
785
786 SAFE_FREE(*ppasswrd);
787 *ppasswrd = new_pass_buf;
788
789 return;
790}
791
792/* Usernames can not have backslash in them and we use
793 [BB check if usernames can have forward slash in them BB]
794 backslash as domain\user separator character
795*/
796static char * check_for_domain(char **ppuser)
797{
798 char * original_string;
799 char * usernm;
800 char * domainnm;
801 int original_len;
802 int len;
803 int i;
804
805 if(ppuser == NULL)
806 return NULL;
807
808 original_string = *ppuser;
809
810 if (original_string == NULL)
811 return NULL;
812
813 original_len = strlen(original_string);
814
815 usernm = strchr(*ppuser,'/');
816 if (usernm == NULL) {
817 usernm = strchr(*ppuser,'\\');
818 if (usernm == NULL)
819 return NULL;
820 }
821
822 if(got_domain) {
823 printf("Domain name specified twice. Username probably malformed\n");
824 return NULL;
825 }
826
827 usernm[0] = 0;
828 domainnm = *ppuser;
829 if (domainnm[0] != 0) {
830 got_domain = 1;
831 } else {
832 printf("null domain\n");
833 }
834 len = strlen(domainnm);
835 /* reset domainm to new buffer, and copy
836 domain name into it */
837 domainnm = (char *)malloc(len+1);
838 if(domainnm == NULL)
839 return NULL;
840
841 strlcpy(domainnm,*ppuser,len+1);
842
843/* move_string(*ppuser, usernm+1) */
844 len = strlen(usernm+1);
845
846 if(len >= original_len) {
847 /* should not happen */
848 return domainnm;
849 }
850
851 for(i=0;i<original_len;i++) {
852 if(i<len)
853 original_string[i] = usernm[i+1];
854 else /* stuff with commas to remove last parm */
855 original_string[i] = ',';
856 }
857
858 /* BB add check for more than one slash?
859 strchr(*ppuser,'/');
860 strchr(*ppuser,'\\')
861 */
862
863 return domainnm;
864}
865
866/* replace all occurances of "from" in a string with "to" */
867static void replace_char(char *string, char from, char to, int maxlen)
868{
869 char *lastchar = string + maxlen;
870 while (string) {
871 string = strchr(string, from);
872 if (string) {
873 *string = to;
874 if (string >= lastchar)
875 return;
876 }
877 }
878}
879
880/* Note that caller frees the returned buffer if necessary */
881static char * parse_server(char ** punc_name)
882{
883 char * unc_name = *punc_name;
884 int length = strnlen(unc_name, MAX_UNC_LEN);
885 char * share;
886 char * ipaddress_string = NULL;
887 struct hostent * host_entry = NULL;
888 struct in_addr server_ipaddr;
889
890 if(length > (MAX_UNC_LEN - 1)) {
891 printf("mount error: UNC name too long");
892 return NULL;
893 }
894 if (strncasecmp("cifs://",unc_name,7) == 0)
895 return parse_cifs_url(unc_name+7);
896 if (strncasecmp("smb://",unc_name,6) == 0) {
897 return parse_cifs_url(unc_name+6);
898 }
899
900 if(length < 3) {
901 /* BB add code to find DFS root here */
902 printf("\nMounting the DFS root for domain not implemented yet\n");
903 return NULL;
904 } else {
905 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
906 /* check for nfs syntax ie server:share */
907 share = strchr(unc_name,':');
908 if(share) {
909 *punc_name = (char *)malloc(length+3);
910 if(*punc_name == NULL) {
911 /* put the original string back if
912 no memory left */
913 *punc_name = unc_name;
914 return NULL;
915 }
916 *share = '/';
917 strlcpy((*punc_name)+2,unc_name,length+1);
918 SAFE_FREE(unc_name);
919 unc_name = *punc_name;
920 unc_name[length+2] = 0;
921 goto continue_unc_parsing;
922 } else {
923 printf("mount error: improperly formatted UNC name.");
924 printf(" %s does not begin with \\\\ or //\n",unc_name);
925 return NULL;
926 }
927 } else {
928continue_unc_parsing:
929 unc_name[0] = '/';
930 unc_name[1] = '/';
931 unc_name += 2;
932
933 /* allow for either delimiter between host and sharename */
934 if ((share = strpbrk(unc_name, "/\\"))) {
935 *share = 0; /* temporarily terminate the string */
936 share += 1;
937 if(got_ip == 0) {
938 host_entry = gethostbyname(unc_name);
939 }
940 *(share - 1) = '/'; /* put delimiter back */
941
942 /* we don't convert the prefixpath delimiters since '\\' is a valid char in posix paths */
943 if ((prefixpath = strpbrk(share, "/\\"))) {
944 *prefixpath = 0; /* permanently terminate the string */
945 if (!strlen(++prefixpath))
946 prefixpath = NULL; /* this needs to be done explicitly */
947 }
948 if(got_ip) {
949 if(verboseflag)
950 printf("ip address specified explicitly\n");
951 return NULL;
952 }
953 if(host_entry == NULL) {
954 printf("mount error: could not find target server. TCP name %s not found\n", unc_name);
955 return NULL;
956 } else {
957 /* BB should we pass an alternate version of the share name as Unicode */
958 /* BB what about ipv6? BB */
959 /* BB add retries with alternate servers in list */
960
961 memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
962
963 ipaddress_string = inet_ntoa(server_ipaddr);
964 if(ipaddress_string == NULL) {
965 printf("mount error: could not get valid ip address for target server\n");
966 return NULL;
967 }
968 return ipaddress_string;
969 }
970 } else {
971 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
972 printf("Mounting the DFS root for a particular server not implemented yet\n");
973 return NULL;
974 }
975 }
976 }
977}
978
979static struct option longopts[] = {
980 { "all", 0, NULL, 'a' },
981 { "help",0, NULL, 'h' },
982 { "move",0, NULL, 'm' },
983 { "bind",0, NULL, 'b' },
984 { "read-only", 0, NULL, 'r' },
985 { "ro", 0, NULL, 'r' },
986 { "verbose", 0, NULL, 'v' },
987 { "version", 0, NULL, 'V' },
988 { "read-write", 0, NULL, 'w' },
989 { "rw", 0, NULL, 'w' },
990 { "options", 1, NULL, 'o' },
991 { "type", 1, NULL, 't' },
992 { "rsize",1, NULL, 'R' },
993 { "wsize",1, NULL, 'W' },
994 { "uid", 1, NULL, '1'},
995 { "gid", 1, NULL, '2'},
996 { "user",1,NULL,'u'},
997 { "username",1,NULL,'u'},
998 { "dom",1,NULL,'d'},
999 { "domain",1,NULL,'d'},
1000 { "password",1,NULL,'p'},
1001 { "pass",1,NULL,'p'},
1002 { "credentials",1,NULL,'c'},
1003 { "port",1,NULL,'P'},
1004 /* { "uuid",1,NULL,'U'}, */ /* BB unimplemented */
1005 { NULL, 0, NULL, 0 }
1006};
1007
1008/* convert a string to uppercase. return false if the string
1009 * wasn't ASCII. Return success on a NULL ptr */
1010static int
1011uppercase_string(char *string)
1012{
1013 if (!string)
1014 return 1;
1015
1016 while (*string) {
1017 /* check for unicode */
1018 if ((unsigned char) string[0] & 0x80)
1019 return 0;
1020 *string = toupper((unsigned char) *string);
1021 string++;
1022 }
1023
1024 return 1;
1025}
1026
1027int main(int argc, char ** argv)
1028{
1029 int c;
1030 int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
1031 char * orgoptions = NULL;
1032 char * share_name = NULL;
1033 char * ipaddr = NULL;
1034 char * uuid = NULL;
1035 char * mountpoint = NULL;
1036 char * options = NULL;
1037 char * resolved_path = NULL;
1038 char * temp;
1039 char * dev_name;
1040 int rc;
1041 int rsize = 0;
1042 int wsize = 0;
1043 int nomtab = 0;
1044 int uid = 0;
1045 int gid = 0;
1046 int optlen = 0;
1047 int orgoptlen = 0;
1048 size_t options_size = 0;
1049 int retry = 0; /* set when we have to retry mount with uppercase */
1050 struct stat statbuf;
1051 struct utsname sysinfo;
1052 struct mntent mountent;
1053 FILE * pmntfile;
1054
1055 /* setlocale(LC_ALL, "");
1056 bindtextdomain(PACKAGE, LOCALEDIR);
1057 textdomain(PACKAGE); */
1058
1059 if(argc && argv) {
1060 thisprogram = argv[0];
1061 } else {
1062 mount_cifs_usage();
1063 exit(EX_USAGE);
1064 }
1065
1066 if(thisprogram == NULL)
1067 thisprogram = "mount.cifs";
1068
1069 uname(&sysinfo);
1070 /* BB add workstation name and domain and pass down */
1071
1072/* #ifdef _GNU_SOURCE
1073 printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
1074#endif */
1075 if(argc > 2) {
1076 dev_name = argv[1];
1077 share_name = strndup(argv[1], MAX_UNC_LEN);
1078 if (share_name == NULL) {
1079 fprintf(stderr, "%s: %s", argv[0], strerror(ENOMEM));
1080 exit(EX_SYSERR);
1081 }
1082 mountpoint = argv[2];
1083 } else {
1084 mount_cifs_usage();
1085 exit(EX_USAGE);
1086 }
1087
1088 /* add sharename in opts string as unc= parm */
1089
1090 while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
1091 longopts, NULL)) != -1) {
1092 switch (c) {
1093/* No code to do the following options yet */
1094/* case 'l':
1095 list_with_volumelabel = 1;
1096 break;
1097 case 'L':
1098 volumelabel = optarg;
1099 break; */
1100/* case 'a':
1101 ++mount_all;
1102 break; */
1103
1104 case '?':
1105 case 'h': /* help */
1106 mount_cifs_usage ();
1107 exit(EX_USAGE);
1108 case 'n':
1109 ++nomtab;
1110 break;
1111 case 'b':
1112#ifdef MS_BIND
1113 flags |= MS_BIND;
1114#else
1115 fprintf(stderr,
1116 "option 'b' (MS_BIND) not supported\n");
1117#endif
1118 break;
1119 case 'm':
1120#ifdef MS_MOVE
1121 flags |= MS_MOVE;
1122#else
1123 fprintf(stderr,
1124 "option 'm' (MS_MOVE) not supported\n");
1125#endif
1126 break;
1127 case 'o':
1128 orgoptions = strdup(optarg);
1129 break;
1130 case 'r': /* mount readonly */
1131 flags |= MS_RDONLY;
1132 break;
1133 case 'U':
1134 uuid = optarg;
1135 break;
1136 case 'v':
1137 ++verboseflag;
1138 break;
1139 case 'V':
1140 printf ("mount.cifs version: %s.%s%s\n",
1141 MOUNT_CIFS_VERSION_MAJOR,
1142 MOUNT_CIFS_VERSION_MINOR,
1143 MOUNT_CIFS_VENDOR_SUFFIX);
1144 exit (0);
1145 case 'w':
1146 flags &= ~MS_RDONLY;
1147 break;
1148 case 'R':
1149 rsize = atoi(optarg) ;
1150 break;
1151 case 'W':
1152 wsize = atoi(optarg);
1153 break;
1154 case '1':
1155 if (isdigit(*optarg)) {
1156 char *ep;
1157
1158 uid = strtoul(optarg, &ep, 10);
1159 if (*ep) {
1160 printf("bad uid value \"%s\"\n", optarg);
1161 exit(EX_USAGE);
1162 }
1163 } else {
1164 struct passwd *pw;
1165
1166 if (!(pw = getpwnam(optarg))) {
1167 printf("bad user name \"%s\"\n", optarg);
1168 exit(EX_USAGE);
1169 }
1170 uid = pw->pw_uid;
1171 endpwent();
1172 }
1173 break;
1174 case '2':
1175 if (isdigit(*optarg)) {
1176 char *ep;
1177
1178 gid = strtoul(optarg, &ep, 10);
1179 if (*ep) {
1180 printf("bad gid value \"%s\"\n", optarg);
1181 exit(EX_USAGE);
1182 }
1183 } else {
1184 struct group *gr;
1185
1186 if (!(gr = getgrnam(optarg))) {
1187 printf("bad user name \"%s\"\n", optarg);
1188 exit(EX_USAGE);
1189 }
1190 gid = gr->gr_gid;
1191 endpwent();
1192 }
1193 break;
1194 case 'u':
1195 got_user = 1;
1196 user_name = optarg;
1197 break;
1198 case 'd':
1199 domain_name = optarg; /* BB fix this - currently ignored */
1200 got_domain = 1;
1201 break;
1202 case 'p':
1203 if(mountpassword == NULL)
1204 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
1205 if(mountpassword) {
1206 got_password = 1;
1207 strlcpy(mountpassword,optarg,MOUNT_PASSWD_SIZE+1);
1208 }
1209 break;
1210 case 'S':
1211 get_password_from_file(0 /* stdin */,NULL);
1212 break;
1213 case 't':
1214 break;
1215 default:
1216 printf("unknown mount option %c\n",c);
1217 mount_cifs_usage();
1218 exit(EX_USAGE);
1219 }
1220 }
1221
1222 if((argc < 3) || (dev_name == NULL) || (mountpoint == NULL)) {
1223 mount_cifs_usage();
1224 exit(EX_USAGE);
1225 }
1226
1227 if (getenv("PASSWD")) {
1228 if(mountpassword == NULL)
1229 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
1230 if(mountpassword) {
1231 strlcpy(mountpassword,getenv("PASSWD"),MOUNT_PASSWD_SIZE+1);
1232 got_password = 1;
1233 }
1234 } else if (getenv("PASSWD_FD")) {
1235 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
1236 } else if (getenv("PASSWD_FILE")) {
1237 get_password_from_file(0, getenv("PASSWD_FILE"));
1238 }
1239
1240 if (orgoptions && parse_options(&orgoptions, &flags)) {
1241 rc = EX_USAGE;
1242 goto mount_exit;
1243 }
1244 ipaddr = parse_server(&share_name);
1245 if((ipaddr == NULL) && (got_ip == 0)) {
1246 printf("No ip address specified and hostname not found\n");
1247 rc = EX_USAGE;
1248 goto mount_exit;
1249 }
1250
1251 /* BB save off path and pop after mount returns? */
1252 resolved_path = (char *)malloc(PATH_MAX+1);
1253 if(resolved_path) {
1254 /* Note that if we can not canonicalize the name, we get
1255 another chance to see if it is valid when we chdir to it */
1256 if (realpath(mountpoint, resolved_path)) {
1257 mountpoint = resolved_path;
1258 }
1259 }
1260 if(chdir(mountpoint)) {
1261 printf("mount error: can not change directory into mount target %s\n",mountpoint);
1262 rc = EX_USAGE;
1263 goto mount_exit;
1264 }
1265
1266 if(stat (".", &statbuf)) {
1267 printf("mount error: mount point %s does not exist\n",mountpoint);
1268 rc = EX_USAGE;
1269 goto mount_exit;
1270 }
1271
1272 if (S_ISDIR(statbuf.st_mode) == 0) {
1273 printf("mount error: mount point %s is not a directory\n",mountpoint);
1274 rc = EX_USAGE;
1275 goto mount_exit;
1276 }
1277
1278 if((getuid() != 0) && (geteuid() == 0)) {
1279 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
1280#ifndef CIFS_ALLOW_USR_SUID
1281 /* Do not allow user mounts to control suid flag
1282 for mount unless explicitly built that way */
1283 flags |= MS_NOSUID | MS_NODEV;
1284#endif
1285 } else {
1286 printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n");
1287 exit(EX_USAGE);
1288 }
1289 }
1290
1291 if(got_user == 0) {
1292 user_name = getusername();
1293 got_user = 1;
1294 }
1295
1296 if(got_password == 0) {
1297 char *tmp_pass = getpass("Password: "); /* BB obsolete sys call but
1298 no good replacement yet. */
1299 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
1300 if (!tmp_pass || !mountpassword) {
1301 printf("Password not entered, exiting\n");
1302 exit(EX_USAGE);
1303 }
1304 strlcpy(mountpassword, tmp_pass, MOUNT_PASSWD_SIZE+1);
1305 got_password = 1;
1306 }
1307 /* FIXME launch daemon (handles dfs name resolution and credential change)
1308 remember to clear parms and overwrite password field before launching */
1309mount_retry:
1310 if(orgoptions) {
1311 optlen = strlen(orgoptions);
1312 orgoptlen = optlen;
1313 } else
1314 optlen = 0;
1315 if(share_name)
1316 optlen += strlen(share_name) + 4;
1317 else {
1318 printf("No server share name specified\n");
1319 printf("\nMounting the DFS root for server not implemented yet\n");
1320 exit(EX_USAGE);
1321 }
1322 if(user_name)
1323 optlen += strlen(user_name) + 6;
1324 if(ipaddr)
1325 optlen += strlen(ipaddr) + 4;
1326 if(mountpassword)
1327 optlen += strlen(mountpassword) + 6;
1328 SAFE_FREE(options);
1329 options_size = optlen + 10 + DOMAIN_SIZE;
1330 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 */);
1331
1332 if(options == NULL) {
1333 printf("Could not allocate memory for mount options\n");
1334 exit(EX_SYSERR);
1335 }
1336
1337 options[0] = 0;
1338 strlcpy(options,"unc=",options_size);
1339 strlcat(options,share_name,options_size);
1340 /* scan backwards and reverse direction of slash */
1341 temp = strrchr(options, '/');
1342 if(temp > options + 6)
1343 *temp = '\\';
1344 if(ipaddr) {
1345 strlcat(options,",ip=",options_size);
1346 strlcat(options,ipaddr,options_size);
1347 }
1348
1349 if(user_name) {
1350 /* check for syntax like user=domain\user */
1351 if(got_domain == 0)
1352 domain_name = check_for_domain(&user_name);
1353 strlcat(options,",user=",options_size);
1354 strlcat(options,user_name,options_size);
1355 }
1356 if(retry == 0) {
1357 if(domain_name) {
1358 /* extra length accounted for in option string above */
1359 strlcat(options,",domain=",options_size);
1360 strlcat(options,domain_name,options_size);
1361 }
1362 }
1363 if(mountpassword) {
1364 /* Commas have to be doubled, or else they will
1365 look like the parameter separator */
1366/* if(sep is not set)*/
1367 if(retry == 0)
1368 check_for_comma(&mountpassword);
1369 strlcat(options,",pass=",options_size);
1370 strlcat(options,mountpassword,options_size);
1371 }
1372
1373 strlcat(options,",ver=",options_size);
1374 strlcat(options,MOUNT_CIFS_VERSION_MAJOR,options_size);
1375
1376 if(orgoptions) {
1377 strlcat(options,",",options_size);
1378 strlcat(options,orgoptions,options_size);
1379 }
1380 if(prefixpath) {
1381 strlcat(options,",prefixpath=",options_size);
1382 strlcat(options,prefixpath,options_size); /* no need to cat the / */
1383 }
1384 if(verboseflag)
1385 printf("\nmount.cifs kernel mount options %s \n",options);
1386
1387 /* convert all '\\' to '/' in share portion so that /proc/mounts looks pretty */
1388 replace_char(dev_name, '\\', '/', strlen(share_name));
1389
1390 if(mount(dev_name, mountpoint, "cifs", flags, options)) {
1391 /* remember to kill daemon on error */
1392 switch (errno) {
1393 case 0:
1394 printf("mount failed but no error number set\n");
1395 break;
1396 case ENODEV:
1397 printf("mount error: cifs filesystem not supported by the system\n");
1398 break;
1399 case ENXIO:
1400 if(retry == 0) {
1401 retry = 1;
1402 if (uppercase_string(dev_name) &&
1403 uppercase_string(share_name) &&
1404 uppercase_string(prefixpath)) {
1405 printf("retrying with upper case share name\n");
1406 goto mount_retry;
1407 }
1408 }
1409 default:
1410 printf("mount error %d = %s\n",errno,strerror(errno));
1411 }
1412 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
1413 rc = EX_FAIL;
1414 } else {
1415 atexit(unlock_mtab);
1416 rc = lock_mtab();
1417 if (rc) {
1418 printf("cannot lock mtab");
1419 goto mount_exit;
1420 }
1421 pmntfile = setmntent(MOUNTED, "a+");
1422 if (!pmntfile) {
1423 printf("could not update mount table\n");
1424 unlock_mtab();
1425 rc = EX_FILEIO;
1426 goto mount_exit;
1427 }
1428 mountent.mnt_fsname = dev_name;
1429 mountent.mnt_dir = mountpoint;
1430 mountent.mnt_type = CONST_DISCARD(char *,"cifs");
1431 mountent.mnt_opts = (char *)malloc(220);
1432 if(mountent.mnt_opts) {
1433 char * mount_user = getusername();
1434 memset(mountent.mnt_opts,0,200);
1435 if(flags & MS_RDONLY)
1436 strlcat(mountent.mnt_opts,"ro",220);
1437 else
1438 strlcat(mountent.mnt_opts,"rw",220);
1439 if(flags & MS_MANDLOCK)
1440 strlcat(mountent.mnt_opts,",mand",220);
1441 if(flags & MS_NOEXEC)
1442 strlcat(mountent.mnt_opts,",noexec",220);
1443 if(flags & MS_NOSUID)
1444 strlcat(mountent.mnt_opts,",nosuid",220);
1445 if(flags & MS_NODEV)
1446 strlcat(mountent.mnt_opts,",nodev",220);
1447 if(flags & MS_SYNCHRONOUS)
1448 strlcat(mountent.mnt_opts,",sync",220);
1449 if(mount_user) {
1450 if(getuid() != 0) {
1451 strlcat(mountent.mnt_opts,
1452 ",user=", 220);
1453 strlcat(mountent.mnt_opts,
1454 mount_user, 220);
1455 }
1456 }
1457 }
1458 mountent.mnt_freq = 0;
1459 mountent.mnt_passno = 0;
1460 rc = addmntent(pmntfile,&mountent);
1461 endmntent(pmntfile);
1462 unlock_mtab();
1463 SAFE_FREE(mountent.mnt_opts);
1464 if (rc)
1465 rc = EX_FILEIO;
1466 }
1467mount_exit:
1468 if(mountpassword) {
1469 int len = strlen(mountpassword);
1470 memset(mountpassword,0,len);
1471 SAFE_FREE(mountpassword);
1472 }
1473
1474 SAFE_FREE(options);
1475 SAFE_FREE(orgoptions);
1476 SAFE_FREE(resolved_path);
1477 SAFE_FREE(share_name);
1478 exit(rc);
1479}
Note: See TracBrowser for help on using the repository browser.