reset time and duration are set in minutes, not seconds. Works from usrmgr.
[Samba/gebeck_regimport.git] / source / client / mount.cifs.c
blob8c23cc2212312793d564c973805aeff4a7c0d37a
1 /*
2 Mount helper utility for Linux CIFS VFS (virtual filesystem) client
3 Copyright (C) 2003 Steve French (sfrench@us.ibm.com)
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
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 <sys/types.h>
28 #include <sys/mount.h>
29 #include <sys/stat.h>
30 #include <sys/utsname.h>
31 #include <sys/socket.h>
32 #include <arpa/inet.h>
33 #include <getopt.h>
34 #include <errno.h>
35 #include <netdb.h>
36 #include <string.h>
37 #include <mntent.h>
38 #include <fcntl.h>
40 #define MOUNT_CIFS_VERSION_MAJOR "1"
41 #define MOUNT_CIFS_VERSION_MINOR "0"
43 #ifndef MOUNT_CIFS_VENDOR_SUFFIX
44 #define MOUNT_CIFS_VENDOR_SUFFIX ""
45 #endif
47 char * thisprogram;
48 int verboseflag = 0;
49 static int got_password = 0;
50 static int got_user = 0;
51 static int got_domain = 0;
52 static int got_ip = 0;
53 static int got_unc = 0;
54 static int got_uid = 0;
55 static int got_gid = 0;
56 static char * user_name = NULL;
57 char * mountpassword = NULL;
60 /* BB finish BB
62 cifs_umount
63 open nofollow - avoid symlink exposure?
64 get owner of dir see if matches self or if root
65 call system(umount argv) etc.
67 BB end finish BB */
69 static void mount_cifs_usage(void)
71 printf("\nUsage: %s <remotetarget> <dir> -o <options>\n", thisprogram);
72 printf("\nMount the remote target, specified as a UNC name,");
73 printf(" to a local directory.\n");
74 if(mountpassword) {
75 memset(mountpassword,0,64);
76 free(mountpassword);
78 exit(1);
81 /* caller frees username if necessary */
82 static char * getusername(void) {
83 char *username = NULL;
84 struct passwd *password = getpwuid(getuid());
86 if (password) {
87 username = password->pw_name;
89 return username;
92 char * parse_cifs_url(char * unc_name)
94 printf("\ncifs url %s\n",unc_name);
95 return NULL;
98 static int open_cred_file(char * file_name)
100 char * line_buf;
101 char * temp_val;
102 FILE * fs;
103 int i, length;
104 fs = fopen(file_name,"r");
105 if(fs == NULL)
106 return errno;
107 line_buf = malloc(4096);
108 if(line_buf == NULL)
109 return -ENOMEM;
111 while(fgets(line_buf,4096,fs)) {
112 /* parse line from credential file */
114 /* eat leading white space */
115 for(i=0;i<4096;i++) {
116 if(line_buf[i] == '\0')
117 break;
118 else if((line_buf[i] != ' ') && (line_buf[i] != '\t'))
119 break;
120 line_buf++;
123 if (strncasecmp("username",line_buf,8) == 0) {
124 temp_val = strchr(line_buf + i,'=');
125 if(temp_val) {
126 /* go past equals sign */
127 temp_val++;
128 length = strlen(temp_val);
129 if(length > 4086) {
130 printf("cifs.mount failed due to malformed username in credentials file");
131 memset(line_buf,0,4096);
132 if(mountpassword) {
133 memset(mountpassword,0,64);
135 exit(1);
136 } else {
137 got_user = 1;
138 user_name = calloc(1 + length,1);
139 /* BB adding free of user_name string before exit,
140 not really necessary but would be cleaner */
141 strncpy(user_name,temp_val, length);
144 } else if (strncasecmp("password",line_buf,8) == 0) {
145 temp_val = strchr(line_buf+i,'=');
146 if(temp_val) {
147 /* go past equals sign */
148 temp_val++;
149 length = strlen(temp_val);
150 if(length > 64) {
151 printf("cifs.mount failed: password in credentials file too long\n");
152 memset(line_buf,0, 4096);
153 if(mountpassword) {
154 memset(mountpassword,0,64);
156 exit(1);
157 } else {
158 if(mountpassword == NULL) {
159 mountpassword = calloc(65,1);
161 if(mountpassword) {
162 strncpy(mountpassword,temp_val,64);
163 got_password = 1;
169 fclose(fs);
170 if(line_buf) {
171 memset(line_buf,0,4096);
172 free(line_buf);
174 return 0;
177 static int get_password_from_file(int file_descript, char * filename)
179 int rc = 0;
180 int i;
181 char c;
183 if(mountpassword == NULL)
184 mountpassword = calloc(65,1);
185 else
186 memset(mountpassword, 0, 64);
188 if(filename != NULL) {
189 file_descript = open(filename, O_RDONLY);
190 if(file_descript < 0) {
191 printf("cifs.mount failed. %s attempting to open password file %s\n",
192 strerror(errno),filename);
193 exit(1);
196 /* else file already open and fd provided */
198 for(i=0;i<64;i++) {
199 rc = read(file_descript,&c,1);
200 if(rc < 0) {
201 printf("cifs.mount failed. Error %s reading password file\n",strerror(errno));
202 memset(mountpassword,0,64);
203 if(filename != NULL)
204 close(file_descript);
205 exit(1);
206 } else if(rc == 0) {
207 if(mountpassword[0] == 0) {
208 if(verboseflag)
209 printf("\nWarning: null password used since cifs password file empty");
211 break;
212 } else /* read valid character */ {
213 if((c == 0) || (c == '\n')) {
214 break;
215 } else
216 mountpassword[i] = c;
219 if((i == 64) && (verboseflag)) {
220 printf("\nWarning: password longer than 64 characters specified in cifs password file");
222 got_password = 1;
223 if(filename != NULL) {
224 close(file_descript);
227 return rc;
230 static int parse_options(char * options)
232 char * data;
233 char * percent_char = 0;
234 char * value = 0;
235 char * next_keyword = 0;
236 int rc = 0;
238 if (!options)
239 return 1;
240 else
241 data = options;
243 if(verboseflag)
244 printf("\n parsing options: %s", options);
246 /* while ((data = strsep(&options, ",")) != NULL) { */
247 while(data != NULL) {
248 /* check if ends with trailing comma */
249 if(*data == 0)
250 break;
252 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
253 /* data = next keyword */
254 /* value = next value ie stuff after equal sign */
256 next_keyword = strchr(data,',');
258 /* temporarily null terminate end of keyword=value pair */
259 if(next_keyword)
260 *next_keyword = 0;
262 /* if (!*data)
263 continue; */
265 /* temporarily null terminate keyword to make keyword and value distinct */
266 if ((value = strchr(data, '=')) != NULL) {
267 *value = '\0';
268 value++;
271 if (strncmp(data, "user", 4) == 0) {
272 if (!value || !*value) {
273 printf("invalid or missing username\n");
274 return 1; /* needs_arg; */
276 if (strnlen(value, 260) < 260) {
277 got_user=1;
278 percent_char = strchr(value,'%');
279 if(percent_char) {
280 *percent_char = ',';
281 if(mountpassword == NULL)
282 mountpassword = calloc(65,1);
283 if(mountpassword) {
284 if(got_password)
285 printf("\ncifs.mount warning - password specified twice\n");
286 got_password = 1;
287 percent_char++;
288 strncpy(mountpassword, percent_char,64);
289 /* remove password from username */
290 while(*percent_char != 0) {
291 *percent_char = ',';
292 percent_char++;
296 } else {
297 printf("username too long\n");
298 return 1;
300 } else if (strncmp(data, "pass", 4) == 0) {
301 if (!value || !*value) {
302 if(got_password) {
303 printf("\npassword specified twice, ignoring second\n");
304 } else
305 got_password = 1;
306 } else if (strnlen(value, 17) < 17) {
307 if(got_password)
308 printf("\ncifs.mount warning - password specified twice\n");
309 got_password = 1;
310 } else {
311 printf("password too long\n");
312 return 1;
314 } else if (strncmp(data, "ip", 2) == 0) {
315 if (!value || !*value) {
316 printf("target ip address argument missing");
317 } else if (strnlen(value, 35) < 35) {
318 got_ip = 1;
319 } else {
320 printf("ip address too long\n");
321 return 1;
323 } else if ((strncmp(data, "unc", 3) == 0)
324 || (strncmp(data, "target", 6) == 0)
325 || (strncmp(data, "path", 4) == 0)) {
326 if (!value || !*value) {
327 printf("invalid path to network resource\n");
328 return 1; /* needs_arg; */
329 } else if(strnlen(value,5) < 5) {
330 printf("UNC name too short");
333 if (strnlen(value, 300) < 300) {
334 got_unc = 1;
335 if (strncmp(value, "//", 2) == 0) {
336 if(got_unc)
337 printf("unc name specified twice, ignoring second\n");
338 else
339 got_unc = 1;
340 } else if (strncmp(value, "\\\\", 2) != 0) {
341 printf("UNC Path does not begin with // or \\\\ \n");
342 return 1;
343 } else {
344 if(got_unc)
345 printf("unc name specified twice, ignoring second\n");
346 else
347 got_unc = 1;
349 } else {
350 printf("CIFS: UNC name too long\n");
351 return 1;
353 } else if ((strncmp(data, "domain", 3) == 0)
354 || (strncmp(data, "workgroup", 5) == 0)) {
355 if (!value || !*value) {
356 printf("CIFS: invalid domain name\n");
357 return 1; /* needs_arg; */
359 if (strnlen(value, 65) < 65) {
360 got_domain = 1;
361 } else {
362 printf("domain name too long\n");
363 return 1;
365 } else if (strncmp(data, "cred", 4) == 0) {
366 if (value && *value) {
367 rc = open_cred_file(value);
368 if(rc) {
369 printf("error %d opening credential file %s",rc, value);
370 return 1;
372 } else {
373 printf("invalid credential file name specified\n");
374 return 1;
376 } else if (strncmp(data, "uid", 3) == 0) {
377 if (value && *value) {
378 got_uid = 1;
380 } else if (strncmp(data, "gid", 3) == 0) {
381 if (value && *value) {
382 got_gid = 1;
384 /* fmask and dmask synonyms for people used to smbfs syntax */
385 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
386 if (!value || !*value) {
387 printf ("Option '%s' requires a numerical argument\n", data);
388 return 1;
391 if (value[0] != '0') {
392 printf ("WARNING: '%s' not expressed in octal.\n", data);
395 if (strcmp (data, "fmask") == 0) {
396 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
397 data = "file_mode";
399 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
400 if (!value || !*value) {
401 printf ("Option '%s' requires a numerical argument\n", data);
402 return 1;
405 if (value[0] != '0') {
406 printf ("WARNING: '%s' not expressed in octal.\n", data);
409 if (strcmp (data, "dmask") == 0) {
410 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
411 data = "dir_mode";
413 } /* else if (strnicmp(data, "port", 4) == 0) {
414 if (value && *value) {
415 vol->port =
416 simple_strtoul(value, &value, 0);
418 } else if (strnicmp(data, "rsize", 5) == 0) {
419 if (value && *value) {
420 vol->rsize =
421 simple_strtoul(value, &value, 0);
423 } else if (strnicmp(data, "wsize", 5) == 0) {
424 if (value && *value) {
425 vol->wsize =
426 simple_strtoul(value, &value, 0);
428 } else if (strnicmp(data, "version", 3) == 0) {
430 } else if (strnicmp(data, "rw", 2) == 0) {
432 } else
433 printf("CIFS: Unknown mount option %s\n",data); */
435 /* move to next option */
436 data = next_keyword+1;
438 /* put overwritten equals sign back */
439 if(value) {
440 value--;
441 *value = '=';
444 /* put previous overwritten comma back */
445 if(next_keyword)
446 *next_keyword = ',';
447 else
448 data = 0;
451 return 0;
454 /* Note that caller frees the returned buffer if necessary */
455 char * parse_server(char * unc_name)
457 int length = strnlen(unc_name,1024);
458 char * share;
459 char * ipaddress_string = NULL;
460 struct hostent * host_entry;
461 struct in_addr server_ipaddr;
462 int rc;
464 if(length > 1023) {
465 printf("mount error: UNC name too long");
466 return 0;
468 if (strncasecmp("cifs://",unc_name,7) == 0)
469 return parse_cifs_url(unc_name+7);
470 if (strncasecmp("smb://",unc_name,6) == 0) {
471 return parse_cifs_url(unc_name+6);
474 if(length < 3) {
475 /* BB add code to find DFS root here */
476 printf("\nMounting the DFS root for domain not implemented yet");
477 return 0;
478 } else {
479 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
480 printf("mount error: improperly formatted UNC name.");
481 printf(" %s does not begin with \\\\ or //\n",unc_name);
482 return 0;
483 } else {
484 unc_name[0] = '\\';
485 unc_name[0] = '/';
486 unc_name[1] = '/';
487 unc_name += 2;
488 if ((share = strchr(unc_name, '/')) ||
489 (share = strchr(unc_name,'\\'))) {
490 *share = 0; /* temporarily terminate the string */
491 share += 1;
492 host_entry = gethostbyname(unc_name);
493 *(share - 1) = '/'; /* put the slash back */
494 /* rc = getipnodebyname(unc_name, AF_INET, AT_ADDRCONFIG ,&rc);*/
495 if(host_entry == NULL) {
496 printf("mount error: could not find target server. TCP name %s not found ", unc_name);
497 printf(" rc = %d\n",rc);
498 return 0;
500 else {
501 /* BB should we pass an alternate version of the share name as Unicode */
502 /* BB what about ipv6? BB */
503 /* BB add retries with alternate servers in list */
505 memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
507 ipaddress_string = inet_ntoa(server_ipaddr);
508 if(ipaddress_string == NULL) {
509 printf("mount error: could not get valid ip address for target server\n");
510 return 0;
512 return ipaddress_string;
514 } else {
515 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
516 printf("Mounting the DFS root for a particular server not implemented yet\n");
517 return 0;
523 static struct option longopts[] = {
524 { "all", 0, 0, 'a' },
525 { "help", 0, 0, 'h' },
526 { "read-only", 0, 0, 'r' },
527 { "ro", 0, 0, 'r' },
528 { "verbose", 0, 0, 'v' },
529 { "version", 0, 0, 'V' },
530 { "read-write", 0, 0, 'w' },
531 { "rw", 0, 0, 'w' },
532 { "options", 1, 0, 'o' },
533 { "types", 1, 0, 't' },
534 { "rsize",1, 0, 'R' },
535 { "wsize",1, 0, 'W' },
536 { "uid", 1, 0, '1'},
537 { "gid", 1, 0, '2'},
538 { "uuid",1,0,'U' },
539 { "user",1,0,'u'},
540 { "username",1,0,'u'},
541 { "dom",1,0,'d'},
542 { "domain",1,0,'d'},
543 { "password",1,0,'p'},
544 { "pass",1,0,'p'},
545 { "credentials",1,0,'c'},
546 { "port",1,0,'P'},
547 { NULL, 0, 0, 0 }
550 int main(int argc, char ** argv)
552 int c;
553 int flags = MS_MANDLOCK | MS_MGC_VAL;
554 char * orgoptions = NULL;
555 char * share_name = NULL;
556 char * domain_name = NULL;
557 char * ipaddr = NULL;
558 char * uuid = NULL;
559 char * mountpoint;
560 char * options;
561 char * temp;
562 int rc;
563 int rsize = 0;
564 int wsize = 0;
565 int nomtab = 0;
566 int uid = 0;
567 int gid = 0;
568 int optlen = 0;
569 int orgoptlen = 0;
570 struct stat statbuf;
571 struct utsname sysinfo;
572 struct mntent mountent;
573 FILE * pmntfile;
575 /* setlocale(LC_ALL, "");
576 bindtextdomain(PACKAGE, LOCALEDIR);
577 textdomain(PACKAGE); */
579 if(argc && argv) {
580 thisprogram = argv[0];
582 if(thisprogram == NULL)
583 thisprogram = "mount.cifs";
585 uname(&sysinfo);
586 /* BB add workstation name and domain and pass down */
588 /* #ifdef _GNU_SOURCE
589 printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
590 #endif */
592 share_name = argv[1];
593 mountpoint = argv[2];
595 /* add sharename in opts string as unc= parm */
597 while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsU:vVwt:",
598 longopts, NULL)) != -1) {
599 switch (c) {
600 /* No code to do the following options yet */
601 /* case 'l':
602 list_with_volumelabel = 1;
603 break;
604 case 'L':
605 volumelabel = optarg;
606 break; */
607 /* case 'a':
608 ++mount_all;
609 break; */
611 case '?':
612 case 'h': /* help */
613 mount_cifs_usage ();
614 exit(1);
615 case 'n':
616 ++nomtab;
617 break;
618 case 'o':
619 orgoptions = strdup(optarg);
620 break;
621 case 'r': /* mount readonly */
622 flags |= MS_RDONLY;
623 break;
624 case 'U':
625 uuid = optarg;
626 break;
627 case 'v':
628 ++verboseflag;
629 break;
630 case 'V':
631 printf ("mount.cifs version: %s.%s%s\n",
632 MOUNT_CIFS_VERSION_MAJOR,
633 MOUNT_CIFS_VERSION_MINOR,
634 MOUNT_CIFS_VENDOR_SUFFIX);
635 if(mountpassword) {
636 memset(mountpassword,0,64);
638 exit (0);
639 case 'w':
640 flags &= ~MS_RDONLY;
641 break;
642 case 'R':
643 rsize = atoi(optarg) ;
644 break;
645 case 'W':
646 wsize = atoi(optarg);
647 break;
648 case '1':
649 uid = atoi(optarg);
650 break;
651 case '2':
652 gid = atoi(optarg);
653 break;
654 case 'u':
655 got_user = 1;
656 user_name = optarg;
657 break;
658 case 'd':
659 domain_name = optarg;
660 break;
661 case 'p':
662 if(mountpassword == NULL)
663 mountpassword = calloc(65,1);
664 if(mountpassword) {
665 got_password = 1;
666 strncpy(mountpassword,optarg,64);
668 break;
669 case 't':
670 break;
671 default:
672 printf("unknown mount option %c\n",c);
673 mount_cifs_usage();
674 exit(1);
678 if(argc < 3)
679 mount_cifs_usage();
681 if (getenv("PASSWD")) {
682 if(mountpassword == NULL)
683 mountpassword = calloc(65,1);
684 if(mountpassword) {
685 strncpy(mountpassword,getenv("PASSWD"),64);
686 got_password = 1;
688 } else if (getenv("PASSWD_FD")) {
689 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
690 } else if (getenv("PASSWD_FILE")) {
691 get_password_from_file(0, getenv("PASSWD_FILE"));
694 ipaddr = parse_server(share_name);
696 if (orgoptions && parse_options(orgoptions))
697 return 1;
699 /* BB save off path and pop after mount returns? */
700 /* BB canonicalize the path in argv[1]? */
702 if(chdir(mountpoint)) {
703 printf("mount error: can not change directory into mount target %s\n",mountpoint);
706 if(stat (mountpoint, &statbuf)) {
707 printf("mount error: mount point %s does not exist\n",mountpoint);
708 return -1;
711 if (S_ISDIR(statbuf.st_mode) == 0) {
712 printf("mount error: mount point %s is not a directory\n",mountpoint);
713 return -1;
716 if((getuid() != 0) && (geteuid() == 0)) {
717 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
718 printf("setuid mount allowed\n");
719 } else {
720 printf("mount error: permission denied or not superuser and cifs.mount not installed SUID\n");
721 return -1;
725 if(got_user == 0)
726 user_name = getusername();
728 if(got_password == 0) {
729 mountpassword = getpass("Password: "); /* BB obsolete */
730 got_password = 1;
732 /* FIXME launch daemon (handles dfs name resolution and credential change)
733 remember to clear parms and overwrite password field before launching */
734 if(orgoptions) {
735 optlen = strlen(orgoptions);
736 orgoptlen = optlen;
737 } else
738 optlen = 0;
739 if(share_name)
740 optlen += strlen(share_name) + 4;
741 if(user_name)
742 optlen += strlen(user_name) + 6;
743 if(ipaddr)
744 optlen += strlen(ipaddr) + 4;
745 if(mountpassword)
746 optlen += strlen(mountpassword) + 6;
747 options = malloc(optlen + 10);
749 options[0] = 0;
750 strncat(options,"unc=",4);
751 strcat(options,share_name);
752 /* scan backwards and reverse direction of slash */
753 temp = strrchr(options, '/');
754 if(temp > options + 6)
755 *temp = '\\';
756 if(ipaddr) {
757 strncat(options,",ip=",4);
758 strcat(options,ipaddr);
760 if(user_name) {
761 strncat(options,",user=",6);
762 strcat(options,user_name);
764 if(mountpassword) {
765 strncat(options,",pass=",6);
766 strcat(options,mountpassword);
768 strncat(options,",ver=",5);
769 strcat(options,MOUNT_CIFS_VERSION_MAJOR);
771 if(orgoptions) {
772 strcat(options,",");
773 strcat(options,orgoptions);
775 if(verboseflag)
776 printf("\ncifs.mount kernel mount options %s \n",options);
777 if(mount(share_name, mountpoint, "cifs", flags, options)) {
778 /* remember to kill daemon on error */
779 switch (errno) {
780 case 0:
781 printf("mount failed but no error number set\n");
782 break;
783 case ENODEV:
784 printf("mount error: cifs filesystem not supported by the system\n");
785 break;
786 default:
787 printf("mount error %d = %s\n",errno,strerror(errno));
789 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
790 if(mountpassword) {
791 memset(mountpassword,0,64);
793 return -1;
794 } else {
795 pmntfile = setmntent(MOUNTED, "a+");
796 if(pmntfile) {
797 mountent.mnt_fsname = share_name;
798 mountent.mnt_dir = mountpoint;
799 mountent.mnt_type = "cifs";
800 mountent.mnt_opts = "";
801 mountent.mnt_freq = 0;
802 mountent.mnt_passno = 0;
803 rc = addmntent(pmntfile,&mountent);
804 endmntent(pmntfile);
805 } else {
806 printf("could not update mount table\n");
809 if(mountpassword) {
810 memset(mountpassword,0,64);
811 free(mountpassword);
814 if(options) {
815 memset(options,0,optlen);
816 free(options);
819 if(orgoptions) {
820 memset(orgoptions,0,orgoptlen);
821 free(orgoptions);
823 return 0;