Disable dev (MS_NODEV) on user mounts from cifs vfs
[ira/wip.git] / source3 / client / mount.cifs.c
1 /* 
2    Mount helper utility for Linux CIFS VFS (virtual filesystem) client
3    Copyright (C) 2003 Steve French  (sfrench@us.ibm.com)
4
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.
9    
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.
14    
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.  */
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 <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>
39
40 #define MOUNT_CIFS_VERSION_MAJOR "1"
41 #define MOUNT_CIFS_VERSION_MINOR "1"
42
43 #ifndef MOUNT_CIFS_VENDOR_SUFFIX
44 #define MOUNT_CIFS_VENDOR_SUFFIX ""
45 #endif
46
47 #ifndef MS_MOVE 
48 #define MS_MOVE 8192 
49 #endif 
50
51 char * thisprogram;
52 int verboseflag = 0;
53 static int got_password = 0;
54 static int got_user = 0;
55 static int got_domain = 0;
56 static int got_ip = 0;
57 static int got_unc = 0;
58 static int got_uid = 0;
59 static int got_gid = 0;
60 static char * user_name = NULL;
61 char * mountpassword = NULL;
62
63
64 /* BB finish BB
65
66         cifs_umount
67         open nofollow - avoid symlink exposure? 
68         get owner of dir see if matches self or if root
69         call system(umount argv) etc.
70                 
71 BB end finish BB */
72
73 static void mount_cifs_usage(void)
74 {
75         printf("\nUsage:  %s <remotetarget> <dir> -o <options>\n", thisprogram);
76         printf("\nMount the remote target, specified as a UNC name,");
77         printf(" to a local directory.\n");
78         if(mountpassword) {
79                 memset(mountpassword,0,64);
80                 free(mountpassword);
81         }
82         exit(1);
83 }
84
85 /* caller frees username if necessary */
86 static char * getusername(void) {
87         char *username = NULL;
88         struct passwd *password = getpwuid(getuid());
89
90         if (password) {
91                 username = password->pw_name;
92         }
93         return username;
94 }
95
96 char * parse_cifs_url(char * unc_name)
97 {
98         printf("\ncifs url %s\n",unc_name);
99         return NULL;
100 }
101
102 static int open_cred_file(char * file_name)
103 {
104         char * line_buf;
105         char * temp_val;
106         FILE * fs;
107         int i, length;
108         fs = fopen(file_name,"r");
109         if(fs == NULL)
110                 return errno;
111         line_buf = malloc(4096);
112         if(line_buf == NULL)
113                 return -ENOMEM;
114
115         while(fgets(line_buf,4096,fs)) {
116                 /* parse line from credential file */
117
118                 /* eat leading white space */
119                 for(i=0;i<4096;i++) {
120                         if(line_buf[i] == '\0')
121                                 break;
122                         else if((line_buf[i] != ' ') && (line_buf[i] != '\t'))
123                                 break;
124                         line_buf++;
125                 }
126
127                 if (strncasecmp("username",line_buf,8) == 0) {
128                         temp_val = strchr(line_buf + i,'=');
129                         if(temp_val) {
130                                 /* go past equals sign */
131                                 temp_val++;
132                                 length = strlen(temp_val);
133                                 if(length > 4086) {
134                                         printf("cifs.mount failed due to malformed username in credentials file");
135                                         memset(line_buf,0,4096);
136                                         if(mountpassword) {
137                                                 memset(mountpassword,0,64);
138                                         }
139                                         exit(1);
140                                 } else {
141                                         got_user = 1;
142                                         user_name = calloc(1 + length,1);
143                                         /* BB adding free of user_name string before exit,
144                                                 not really necessary but would be cleaner */
145                                         strncpy(user_name,temp_val, length);
146                                 }
147                         }
148                 } else if (strncasecmp("password",line_buf,8) == 0) {
149                         temp_val = strchr(line_buf+i,'=');
150                         if(temp_val) {
151                                 /* go past equals sign */
152                                 temp_val++;
153                                 length = strlen(temp_val);
154                                 if(length > 64) {
155                                         printf("cifs.mount failed: password in credentials file too long\n");
156                                         memset(line_buf,0, 4096);
157                                         if(mountpassword) {
158                                                 memset(mountpassword,0,64);
159                                         }
160                                         exit(1);
161                                 } else {
162                                         if(mountpassword == NULL) {
163                                                 mountpassword = calloc(65,1);
164                                         }
165                                         if(mountpassword) {
166                                                 strncpy(mountpassword,temp_val,64);
167                                                 got_password = 1;
168                                         }
169                                 }
170                         }
171                 }
172         }
173         fclose(fs);
174         if(line_buf) {
175                 memset(line_buf,0,4096);
176                 free(line_buf);
177         }
178         return 0;
179 }
180
181 static int get_password_from_file(int file_descript, char * filename)
182 {
183         int rc = 0;
184         int i;
185         char c;
186
187         if(mountpassword == NULL)
188                 mountpassword = calloc(65,1);
189         else 
190                 memset(mountpassword, 0, 64);
191
192         if(filename != NULL) {
193                 file_descript = open(filename, O_RDONLY);
194                 if(file_descript < 0) {
195                         printf("cifs.mount failed. %s attempting to open password file %s\n",
196                                    strerror(errno),filename);
197                         exit(1);
198                 }
199         }
200         /* else file already open and fd provided */
201
202         for(i=0;i<64;i++) {
203                 rc = read(file_descript,&c,1);
204                 if(rc < 0) {
205                         printf("cifs.mount failed. Error %s reading password file\n",strerror(errno));
206                         memset(mountpassword,0,64);
207                         if(filename != NULL)
208                                 close(file_descript);
209                         exit(1);
210                 } else if(rc == 0) {
211                         if(mountpassword[0] == 0) {
212                                 if(verboseflag)
213                                         printf("\nWarning: null password used since cifs password file empty");
214                         }
215                         break;
216                 } else /* read valid character */ {
217                         if((c == 0) || (c == '\n')) {
218                                 break;
219                         } else 
220                                 mountpassword[i] = c;
221                 }
222         }
223         if((i == 64) && (verboseflag)) {
224                 printf("\nWarning: password longer than 64 characters specified in cifs password file");
225         }
226         got_password = 1;
227         if(filename != NULL) {
228                 close(file_descript);
229         }
230
231         return rc;
232 }
233
234 static int parse_options(char * options, int * filesys_flags)
235 {
236         char * data;
237         char * percent_char = 0;
238         char * value = 0;
239         char * next_keyword = 0;
240         int rc = 0;
241
242         if (!options)
243                 return 1;
244         else
245                 data = options;
246
247         if(verboseflag)
248                 printf("\n parsing options: %s", options);
249
250 /* while ((data = strsep(&options, ",")) != NULL) { */
251         while(data != NULL) {
252                 /*  check if ends with trailing comma */
253                 if(*data == 0)
254                         break;
255
256                 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
257                 /* data  = next keyword */
258                 /* value = next value ie stuff after equal sign */
259
260                 next_keyword = strchr(data,',');
261         
262                 /* temporarily null terminate end of keyword=value pair */
263                 if(next_keyword)
264                         *next_keyword = 0;
265
266                 /* if (!*data)
267                         continue; */
268                 
269                 /* temporarily null terminate keyword to make keyword and value distinct */
270                 if ((value = strchr(data, '=')) != NULL) {
271                         *value = '\0';
272                         value++;
273                 }
274
275                 if (strncmp(data, "user", 4) == 0) {
276                         if (!value || !*value) {
277                                 printf("invalid or missing username\n");
278                                 return 1;       /* needs_arg; */
279                         }
280                         if (strnlen(value, 260) < 260) {
281                                 got_user=1;
282                                 percent_char = strchr(value,'%');
283                                 if(percent_char) {
284                                         *percent_char = ',';
285                                         if(mountpassword == NULL)
286                                                 mountpassword = calloc(65,1);
287                                         if(mountpassword) {
288                                                 if(got_password)
289                                                         printf("\ncifs.mount warning - password specified twice\n");
290                                                 got_password = 1;
291                                                 percent_char++;
292                                                 strncpy(mountpassword, percent_char,64);
293                                         /*  remove password from username */
294                                                 while(*percent_char != 0) {
295                                                         *percent_char = ',';
296                                                         percent_char++;
297                                                 }
298                                         }
299                                 }
300                         } else {
301                                 printf("username too long\n");
302                                 return 1;
303                         }
304                 } else if (strncmp(data, "pass", 4) == 0) {
305                         if (!value || !*value) {
306                                 if(got_password) {
307                                         printf("\npassword specified twice, ignoring second\n");
308                                 } else
309                                         got_password = 1;
310                         } else if (strnlen(value, 17) < 17) {
311                                 if(got_password)
312                                         printf("\ncifs.mount warning - password specified twice\n");
313                                 got_password = 1;
314                         } else {
315                                 printf("password too long\n");
316                                 return 1;
317                         }
318                 } else if (strncmp(data, "ip", 2) == 0) {
319                         if (!value || !*value) {
320                                 printf("target ip address argument missing");
321                         } else if (strnlen(value, 35) < 35) {
322                                 got_ip = 1;
323                         } else {
324                                 printf("ip address too long\n");
325                                 return 1;
326                         }
327                 } else if ((strncmp(data, "unc", 3) == 0)
328                    || (strncmp(data, "target", 6) == 0)
329                    || (strncmp(data, "path", 4) == 0)) {
330                         if (!value || !*value) {
331                                 printf("invalid path to network resource\n");
332                                 return 1;  /* needs_arg; */
333                         } else if(strnlen(value,5) < 5) {
334                                 printf("UNC name too short");
335                         }
336
337                         if (strnlen(value, 300) < 300) {
338                                 got_unc = 1;
339                                 if (strncmp(value, "//", 2) == 0) {
340                                         if(got_unc)
341                                                 printf("unc name specified twice, ignoring second\n");
342                                         else
343                                                 got_unc = 1;
344                                 } else if (strncmp(value, "\\\\", 2) != 0) {                       
345                                         printf("UNC Path does not begin with // or \\\\ \n");
346                                         return 1;
347                                 } else {
348                                         if(got_unc)
349                                                 printf("unc name specified twice, ignoring second\n");
350                                         else
351                                                 got_unc = 1;
352                                 }
353                         } else {
354                                 printf("CIFS: UNC name too long\n");
355                                 return 1;
356                         }
357                 } else if ((strncmp(data, "domain", 3) == 0)
358                            || (strncmp(data, "workgroup", 5) == 0)) {
359                         if (!value || !*value) {
360                                 printf("CIFS: invalid domain name\n");
361                                 return 1;       /* needs_arg; */
362                         }
363                         if (strnlen(value, 65) < 65) {
364                                 got_domain = 1;
365                         } else {
366                                 printf("domain name too long\n");
367                                 return 1;
368                         }
369                 } else if (strncmp(data, "cred", 4) == 0) {
370                         if (value && *value) {
371                                 rc = open_cred_file(value);
372                                 if(rc) {
373                                         printf("error %d opening credential file %s",rc, value);
374                                         return 1;
375                                 }
376                         } else {
377                                 printf("invalid credential file name specified\n");
378                                 return 1;
379                         }
380                 } else if (strncmp(data, "uid", 3) == 0) {
381                         if (value && *value) {
382                                 got_uid = 1;
383                         }
384                 } else if (strncmp(data, "gid", 3) == 0) {
385                         if (value && *value) {
386                                 got_gid = 1;
387                         }
388        /* fmask and dmask synonyms for people used to smbfs syntax */
389                 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
390                         if (!value || !*value) {
391                                 printf ("Option '%s' requires a numerical argument\n", data);
392                                 return 1;
393                         }
394
395                         if (value[0] != '0') {
396                                 printf ("WARNING: '%s' not expressed in octal.\n", data);
397                         }
398
399                         if (strcmp (data, "fmask") == 0) {
400                                 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
401                                 data = "file_mode"; /* BB fix this */
402                         }
403                 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
404                         if (!value || !*value) {
405                                 printf ("Option '%s' requires a numerical argument\n", data);
406                                 return 1;
407                         }
408
409                         if (value[0] != '0') {
410                                 printf ("WARNING: '%s' not expressed in octal.\n", data);
411                         }
412
413                         if (strcmp (data, "dmask") == 0) {
414                                 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
415                                 data = "dir_mode";
416                         }
417                         /* the following eight mount options should be
418                         stripped out from what is passed into the kernel
419                         since these eight options are best passed as the
420                         mount flags rather than redundantly to the kernel 
421                         and could generate spurious warnings depending on the
422                         level of the corresponding cifs vfs kernel code */
423                 } else if (strncmp(data, "nosuid", 6) == 0) {
424                         *filesys_flags |= MS_NOSUID;
425                 } else if (strncmp(data, "suid", 4) == 0) {
426                         *filesys_flags &= ~MS_NOSUID;
427                 } else if (strncmp(data, "nodev", 5) == 0) {
428                         *filesys_flags |= MS_NODEV;
429                 } else if (strncmp(data, "dev", 3) == 0) {
430                         *filesys_flags &= ~MS_NODEV;
431                 } else if (strncmp(data, "noexec", 6) == 0) {
432                         *filesys_flags |= MS_NOEXEC;
433                 } else if (strncmp(data, "exec", 4) == 0) {
434                         *filesys_flags &= ~MS_NOEXEC;
435                 } else if (strncmp(data, "ro", 3) == 0) {
436                         *filesys_flags |= MS_RDONLY;
437                 } else if (strncmp(data, "rw", 2) == 0) {
438                         *filesys_flags &= ~MS_RDONLY;
439                 } /* else if (strnicmp(data, "port", 4) == 0) {
440                 if (value && *value) {
441                         vol->port =
442                                 simple_strtoul(value, &value, 0);
443                 }
444         } else if (strnicmp(data, "rsize", 5) == 0) {
445                 if (value && *value) {
446                         vol->rsize =
447                                 simple_strtoul(value, &value, 0);
448                 }
449         } else if (strnicmp(data, "wsize", 5) == 0) {
450                 if (value && *value) {
451                         vol->wsize =
452                                 simple_strtoul(value, &value, 0);
453                 }
454         } else if (strnicmp(data, "version", 3) == 0) {
455                 
456         } else if (strnicmp(data, "rw", 2) == 0) {
457                 
458         } else
459                 printf("CIFS: Unknown mount option %s\n",data); */
460
461                 /* move to next option */
462                 data = next_keyword+1;
463
464                 /* put overwritten equals sign back */
465                 if(value) {
466                         value--;
467                         *value = '=';
468                 }
469                 
470                 /* put previous overwritten comma back */
471                 if(next_keyword)
472                         *next_keyword = ',';
473                 else
474                         data = 0;
475
476         }
477         return 0;
478 }
479
480 /* Note that caller frees the returned buffer if necessary */
481 char * parse_server(char * unc_name)
482 {
483         int length = strnlen(unc_name,1024);
484         char * share;
485         char * ipaddress_string = NULL;
486         struct hostent * host_entry;
487         struct in_addr server_ipaddr;
488         int rc;
489
490         if(length > 1023) {
491                 printf("mount error: UNC name too long");
492                 return 0;
493         }
494         if (strncasecmp("cifs://",unc_name,7) == 0)
495                 return parse_cifs_url(unc_name+7);
496         if (strncasecmp("smb://",unc_name,6) == 0) {
497                 return parse_cifs_url(unc_name+6);
498         }
499
500         if(length < 3) {
501                 /* BB add code to find DFS root here */
502                 printf("\nMounting the DFS root for domain not implemented yet");
503                 return 0;
504         } else {
505                 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
506                         printf("mount error: improperly formatted UNC name.");
507                         printf(" %s does not begin with \\\\ or //\n",unc_name);
508                         return 0;
509                 } else {
510                         unc_name[0] = '\\';
511                         unc_name[0] = '/';
512                         unc_name[1] = '/';
513                         unc_name += 2;
514                         if ((share = strchr(unc_name, '/')) || 
515                                 (share = strchr(unc_name,'\\'))) {
516                                 *share = 0;  /* temporarily terminate the string */
517                                 share += 1;
518                                 host_entry = gethostbyname(unc_name);
519                                 *(share - 1) = '/'; /* put the slash back */
520 /*                              rc = getipnodebyname(unc_name, AF_INET, AT_ADDRCONFIG ,&rc);*/
521                                 if(host_entry == NULL) {
522                                         printf("mount error: could not find target server. TCP name %s not found ", unc_name);
523                                         printf(" rc = %d\n",rc);
524                                         return 0;
525                                 }
526                                 else {
527                                         /* BB should we pass an alternate version of the share name as Unicode */
528                                         /* BB what about ipv6? BB */
529                                         /* BB add retries with alternate servers in list */
530
531                                         memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
532
533                                         ipaddress_string = inet_ntoa(server_ipaddr);                                                                                     
534                                         if(ipaddress_string == NULL) {
535                                                 printf("mount error: could not get valid ip address for target server\n");
536                                                 return 0;
537                                         }
538                                         return ipaddress_string; 
539                                 }
540                         } else {
541                                 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
542                                 printf("Mounting the DFS root for a particular server not implemented yet\n");
543                                 return 0;
544                         }
545                 }
546         }
547 }
548
549 static struct option longopts[] = {
550         { "all", 0, 0, 'a' },
551         { "help",0, 0, 'h' },
552         { "move",0, 0, 'm' },
553         { "bind",0, 0, 'b' },
554         { "read-only", 0, 0, 'r' },
555         { "ro", 0, 0, 'r' },
556         { "verbose", 0, 0, 'v' },
557         { "version", 0, 0, 'V' },
558         { "read-write", 0, 0, 'w' },
559         { "rw", 0, 0, 'w' },
560         { "options", 1, 0, 'o' },
561         { "type", 1, 0, 't' },
562         { "rsize",1, 0, 'R' },
563         { "wsize",1, 0, 'W' },
564         { "uid", 1, 0, '1'},
565         { "gid", 1, 0, '2'},
566         { "user",1,0,'u'},
567         { "username",1,0,'u'},
568         { "dom",1,0,'d'},
569         { "domain",1,0,'d'},
570         { "password",1,0,'p'},
571         { "pass",1,0,'p'},
572         { "credentials",1,0,'c'},
573         { "port",1,0,'P'},
574         /* { "uuid",1,0,'U'}, */ /* BB unimplemented */
575         { NULL, 0, 0, 0 }
576 };
577
578 int main(int argc, char ** argv)
579 {
580         int c;
581         int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
582         char * orgoptions = NULL;
583         char * share_name = NULL;
584         char * domain_name = NULL;
585         char * ipaddr = NULL;
586         char * uuid = NULL;
587         char * mountpoint;
588         char * options;
589         char * temp;
590         int rc;
591         int rsize = 0;
592         int wsize = 0;
593         int nomtab = 0;
594         int uid = 0;
595         int gid = 0;
596         int optlen = 0;
597         int orgoptlen = 0;
598         struct stat statbuf;
599         struct utsname sysinfo;
600         struct mntent mountent;
601         FILE * pmntfile;
602
603         /* setlocale(LC_ALL, "");
604         bindtextdomain(PACKAGE, LOCALEDIR);
605         textdomain(PACKAGE); */
606
607         if(argc && argv) {
608                 thisprogram = argv[0];
609         }
610         if(thisprogram == NULL)
611                 thisprogram = "mount.cifs";
612
613         uname(&sysinfo);
614         /* BB add workstation name and domain and pass down */
615
616 /* #ifdef _GNU_SOURCE
617         printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
618 #endif */
619
620         share_name = argv[1];
621         mountpoint = argv[2];
622
623         /* add sharename in opts string as unc= parm */
624
625         while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsU:vVwt:",
626                          longopts, NULL)) != -1) {
627                 switch (c) {
628 /* No code to do the following  options yet */
629 /*      case 'l':
630                 list_with_volumelabel = 1;
631                 break;
632         case 'L':
633                 volumelabel = optarg;
634                 break; */
635 /*      case 'a':              
636                 ++mount_all;
637                 break; */
638
639                 case '?':
640                 case 'h':        /* help */
641                         mount_cifs_usage ();
642                         exit(1);
643                 case 'n':
644                     ++nomtab;
645                     break;
646                 case 'b':
647                         flags |= MS_BIND;
648                         break;
649                 case 'm':
650                         flags |= MS_MOVE;
651                         break;
652                 case 'o':
653                         orgoptions = strdup(optarg);
654                     break;
655                 case 'r':  /* mount readonly */
656                         flags |= MS_RDONLY;
657                         break;
658                 case 'U':
659                         uuid = optarg;
660                         break;
661                 case 'v':
662                         ++verboseflag;
663                         break;
664                 case 'V':          
665                         printf ("mount.cifs version: %s.%s%s\n",
666                         MOUNT_CIFS_VERSION_MAJOR,
667                         MOUNT_CIFS_VERSION_MINOR,
668                         MOUNT_CIFS_VENDOR_SUFFIX);
669                         if(mountpassword) {
670                                 memset(mountpassword,0,64);
671                         }
672                         exit (0);
673                 case 'w':
674                         flags &= ~MS_RDONLY;
675                         break;
676                 case 'R':
677                         rsize = atoi(optarg) ;
678                         break;
679                 case 'W':
680                         wsize = atoi(optarg);
681                         break;
682                 case '1':
683                         uid = atoi(optarg);
684                         break;
685                 case '2':
686                         gid = atoi(optarg);
687                         break;
688                 case 'u':
689                         got_user = 1;
690                         user_name = optarg;
691                         break;
692                 case 'd':
693                         domain_name = optarg;
694                         break;
695                 case 'p':
696                         if(mountpassword == NULL)
697                                 mountpassword = calloc(65,1);
698                         if(mountpassword) {
699                                 got_password = 1;
700                                 strncpy(mountpassword,optarg,64);
701                         }
702                         break;
703                 case 't':
704                         break;
705                 default:
706                         printf("unknown mount option %c\n",c);
707                         mount_cifs_usage();
708                         exit(1);
709                 }
710         }
711
712         if(argc < 3)
713                 mount_cifs_usage();
714
715         if (getenv("PASSWD")) {
716                 if(mountpassword == NULL)
717                         mountpassword = calloc(65,1);
718                 if(mountpassword) {
719                         strncpy(mountpassword,getenv("PASSWD"),64);
720                         got_password = 1;
721                 }
722         } else if (getenv("PASSWD_FD")) {
723                 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
724         } else if (getenv("PASSWD_FILE")) {
725                 get_password_from_file(0, getenv("PASSWD_FILE"));
726         }
727
728         ipaddr = parse_server(share_name);
729         
730         if (orgoptions && parse_options(orgoptions, &flags))
731                 return 1;
732
733         /* BB save off path and pop after mount returns? */
734         /* BB canonicalize the path in argv[1]? */
735
736         if(chdir(mountpoint)) {
737                 printf("mount error: can not change directory into mount target %s\n",mountpoint);
738         }
739
740         if(stat (mountpoint, &statbuf)) {
741                 printf("mount error: mount point %s does not exist\n",mountpoint);
742                 return -1;
743         }
744
745         if (S_ISDIR(statbuf.st_mode) == 0) {
746                 printf("mount error: mount point %s is not a directory\n",mountpoint);
747                 return -1;
748         }
749
750         if((getuid() != 0) && (geteuid() == 0)) {
751                 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
752 #ifndef CIFS_ALLOW_USR_SUID
753                         /* Do not allow user mounts to control suid flag
754                         for mount unless explicitly built that way */
755                         flags |= MS_NOSUID | MS_NODEV;
756 #endif                                          
757                 } else {
758                         printf("mount error: permission denied or not superuser and cifs.mount not installed SUID\n"); 
759                         return -1;
760                 }
761         }
762
763         if(got_user == 0)
764                 user_name = getusername();
765        
766         if(got_password == 0) {
767                 mountpassword = getpass("Password: "); /* BB obsolete */
768                 got_password = 1;
769         }
770         /* FIXME launch daemon (handles dfs name resolution and credential change) 
771            remember to clear parms and overwrite password field before launching */
772         if(orgoptions) {
773                 optlen = strlen(orgoptions);
774                 orgoptlen = optlen;
775         } else
776                 optlen = 0;
777         if(share_name)
778                 optlen += strlen(share_name) + 4;
779         if(user_name)
780                 optlen += strlen(user_name) + 6;
781         if(ipaddr)
782                 optlen += strlen(ipaddr) + 4;
783         if(mountpassword)
784                 optlen += strlen(mountpassword) + 6;
785         options = malloc(optlen + 10);
786
787         options[0] = 0;
788         strncat(options,"unc=",4);
789         strcat(options,share_name);
790         /* scan backwards and reverse direction of slash */
791         temp = strrchr(options, '/');
792         if(temp > options + 6)
793                 *temp = '\\';
794         if(ipaddr) {
795                 strncat(options,",ip=",4);
796                 strcat(options,ipaddr);
797         } 
798         if(user_name) {
799                 strncat(options,",user=",6);
800                 strcat(options,user_name);
801         } 
802         if(mountpassword) {
803                 strncat(options,",pass=",6);
804                 strcat(options,mountpassword);
805         }
806         strncat(options,",ver=",5);
807         strcat(options,MOUNT_CIFS_VERSION_MAJOR);
808
809         if(orgoptions) {
810                 strcat(options,",");
811                 strcat(options,orgoptions);
812         }
813         if(verboseflag)
814                 printf("\ncifs.mount kernel mount options %s \n",options);
815         if(mount(share_name, mountpoint, "cifs", flags, options)) {
816         /* remember to kill daemon on error */
817                 switch (errno) {
818                 case 0:
819                         printf("mount failed but no error number set\n");
820                         break;
821                 case ENODEV:
822                         printf("mount error: cifs filesystem not supported by the system\n");
823                         break;
824                 default:
825                         printf("mount error %d = %s\n",errno,strerror(errno));
826                 }
827                 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
828                 if(mountpassword) {
829                         memset(mountpassword,0,64);
830                 }
831                 return -1;
832         } else {
833                 pmntfile = setmntent(MOUNTED, "a+");
834                 if(pmntfile) {
835                         mountent.mnt_fsname = share_name;
836                         mountent.mnt_dir = mountpoint; 
837                         mountent.mnt_type = "cifs"; 
838                         mountent.mnt_opts = "";
839                         mountent.mnt_freq = 0;
840                         mountent.mnt_passno = 0;
841                         rc = addmntent(pmntfile,&mountent);
842                         endmntent(pmntfile);
843                 } else {
844                     printf("could not update mount table\n");
845                 }
846         }
847         if(mountpassword) {
848                 memset(mountpassword,0,64);
849                 free(mountpassword);
850         }
851
852         if(options) {
853                 memset(options,0,optlen);
854                 free(options);
855         }
856
857         if(orgoptions) {
858                 memset(orgoptions,0,orgoptlen);
859                 free(orgoptions);
860         }
861         return 0;
862 }
863