source: branches/samba-3.3.x/source/client/mount.cifs.c@ 221

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

Update Samba 3.3 to 3.3.1

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