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