r77: Fix path canonicalization of the mount target path and help text display in...
[abartlet/samba.git/.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 "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("cifs.mount 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("cifs.mount 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("cifs.mount 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("cifs.mount 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("\ncifs.mount 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("\ncifs.mount 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, "ro", 2) == 0) {
447                         *filesys_flags |= MS_RDONLY;
448                 } else if (strncmp(data, "rw", 2) == 0) {
449                         *filesys_flags &= ~MS_RDONLY;
450                 } /* else if (strnicmp(data, "port", 4) == 0) {
451                         if (value && *value) {
452                                 vol->port =
453                                         simple_strtoul(value, &value, 0);
454                         }
455                 } else if (strnicmp(data, "rsize", 5) == 0) {
456                         if (value && *value) {
457                                 vol->rsize =
458                                         simple_strtoul(value, &value, 0);
459                         }
460                 } else if (strnicmp(data, "wsize", 5) == 0) {
461                         if (value && *value) {
462                                 vol->wsize =
463                                         simple_strtoul(value, &value, 0);
464                         }
465                 } else if (strnicmp(data, "version", 3) == 0) {
466                 } else {
467                         printf("CIFS: Unknown mount option %s\n",data);
468                 } */ /* nothing to do on those four mount options above.
469                         Just pass to kernel and ignore them here */
470
471                         /* move to next option */
472                 data = next_keyword+1;
473
474                 /* put overwritten equals sign back */
475                 if(value) {
476                         value--;
477                         *value = '=';
478                 }
479         
480                 /* put previous overwritten comma back */
481                 if(next_keyword)
482                         *next_keyword = ',';
483                 else
484                         data = 0;
485
486         }
487         return 0;
488 }
489
490 /* Note that caller frees the returned buffer if necessary */
491 char * parse_server(char * unc_name)
492 {
493         int length = strnlen(unc_name,1024);
494         char * share;
495         char * ipaddress_string = NULL;
496         struct hostent * host_entry;
497         struct in_addr server_ipaddr;
498         int rc;
499
500         if(length > 1023) {
501                 printf("mount error: UNC name too long");
502                 return 0;
503         }
504         if (strncasecmp("cifs://",unc_name,7) == 0)
505                 return parse_cifs_url(unc_name+7);
506         if (strncasecmp("smb://",unc_name,6) == 0) {
507                 return parse_cifs_url(unc_name+6);
508         }
509
510         if(length < 3) {
511                 /* BB add code to find DFS root here */
512                 printf("\nMounting the DFS root for domain not implemented yet");
513                 return 0;
514         } else {
515                 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
516                         printf("mount error: improperly formatted UNC name.");
517                         printf(" %s does not begin with \\\\ or //\n",unc_name);
518                         return 0;
519                 } else {
520                         unc_name[0] = '\\';
521                         unc_name[0] = '/';
522                         unc_name[1] = '/';
523                         unc_name += 2;
524                         if ((share = strchr(unc_name, '/')) || 
525                                 (share = strchr(unc_name,'\\'))) {
526                                 *share = 0;  /* temporarily terminate the string */
527                                 share += 1;
528                                 host_entry = gethostbyname(unc_name);
529                                 *(share - 1) = '/'; /* put the slash back */
530 /*                              rc = getipnodebyname(unc_name, AF_INET, AT_ADDRCONFIG ,&rc);*/
531                                 if(host_entry == NULL) {
532                                         printf("mount error: could not find target server. TCP name %s not found ", unc_name);
533                                         printf(" rc = %d\n",rc);
534                                         return 0;
535                                 }
536                                 else {
537                                         /* BB should we pass an alternate version of the share name as Unicode */
538                                         /* BB what about ipv6? BB */
539                                         /* BB add retries with alternate servers in list */
540
541                                         memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
542
543                                         ipaddress_string = inet_ntoa(server_ipaddr);                                                                                     
544                                         if(ipaddress_string == NULL) {
545                                                 printf("mount error: could not get valid ip address for target server\n");
546                                                 return 0;
547                                         }
548                                         return ipaddress_string; 
549                                 }
550                         } else {
551                                 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
552                                 printf("Mounting the DFS root for a particular server not implemented yet\n");
553                                 return 0;
554                         }
555                 }
556         }
557 }
558
559 static struct option longopts[] = {
560         { "all", 0, 0, 'a' },
561         { "help",0, 0, 'h' },
562         { "move",0, 0, 'm' },
563         { "bind",0, 0, 'b' },
564         { "read-only", 0, 0, 'r' },
565         { "ro", 0, 0, 'r' },
566         { "verbose", 0, 0, 'v' },
567         { "version", 0, 0, 'V' },
568         { "read-write", 0, 0, 'w' },
569         { "rw", 0, 0, 'w' },
570         { "options", 1, 0, 'o' },
571         { "type", 1, 0, 't' },
572         { "rsize",1, 0, 'R' },
573         { "wsize",1, 0, 'W' },
574         { "uid", 1, 0, '1'},
575         { "gid", 1, 0, '2'},
576         { "user",1,0,'u'},
577         { "username",1,0,'u'},
578         { "dom",1,0,'d'},
579         { "domain",1,0,'d'},
580         { "password",1,0,'p'},
581         { "pass",1,0,'p'},
582         { "credentials",1,0,'c'},
583         { "port",1,0,'P'},
584         /* { "uuid",1,0,'U'}, */ /* BB unimplemented */
585         { NULL, 0, 0, 0 }
586 };
587
588 int main(int argc, char ** argv)
589 {
590         int c;
591         int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
592         char * orgoptions = NULL;
593         char * share_name = NULL;
594         char * domain_name = NULL;
595         char * ipaddr = NULL;
596         char * uuid = NULL;
597         char * mountpoint;
598         char * options;
599         char * resolved_path;
600         char * temp;
601         int rc;
602         int rsize = 0;
603         int wsize = 0;
604         int nomtab = 0;
605         int uid = 0;
606         int gid = 0;
607         int optlen = 0;
608         int orgoptlen = 0;
609         struct stat statbuf;
610         struct utsname sysinfo;
611         struct mntent mountent;
612         FILE * pmntfile;
613
614         /* setlocale(LC_ALL, "");
615         bindtextdomain(PACKAGE, LOCALEDIR);
616         textdomain(PACKAGE); */
617
618         if(argc && argv) {
619                 thisprogram = argv[0];
620         }
621         if(thisprogram == NULL)
622                 thisprogram = "mount.cifs";
623
624         uname(&sysinfo);
625         /* BB add workstation name and domain and pass down */
626
627 /* #ifdef _GNU_SOURCE
628         printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
629 #endif */
630
631         share_name = argv[1];
632         mountpoint = argv[2];
633
634         /* add sharename in opts string as unc= parm */
635
636         while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsU:vVwt:",
637                          longopts, NULL)) != -1) {
638                 switch (c) {
639 /* No code to do the following  options yet */
640 /*      case 'l':
641                 list_with_volumelabel = 1;
642                 break;
643         case 'L':
644                 volumelabel = optarg;
645                 break; */
646 /*      case 'a':              
647                 ++mount_all;
648                 break; */
649
650                 case '?':
651                 case 'h':        /* help */
652                         mount_cifs_usage ();
653                         exit(1);
654                 case 'n':
655                     ++nomtab;
656                     break;
657                 case 'b':
658                         flags |= MS_BIND;
659                         break;
660                 case 'm':
661                         flags |= MS_MOVE;
662                         break;
663                 case 'o':
664                         orgoptions = strdup(optarg);
665                     break;
666                 case 'r':  /* mount readonly */
667                         flags |= MS_RDONLY;
668                         break;
669                 case 'U':
670                         uuid = optarg;
671                         break;
672                 case 'v':
673                         ++verboseflag;
674                         break;
675                 case 'V':          
676                         printf ("mount.cifs version: %s.%s%s\n",
677                         MOUNT_CIFS_VERSION_MAJOR,
678                         MOUNT_CIFS_VERSION_MINOR,
679                         MOUNT_CIFS_VENDOR_SUFFIX);
680                         if(mountpassword) {
681                                 memset(mountpassword,0,64);
682                         }
683                         exit (0);
684                 case 'w':
685                         flags &= ~MS_RDONLY;
686                         break;
687                 case 'R':
688                         rsize = atoi(optarg) ;
689                         break;
690                 case 'W':
691                         wsize = atoi(optarg);
692                         break;
693                 case '1':
694                         uid = atoi(optarg);
695                         break;
696                 case '2':
697                         gid = atoi(optarg);
698                         break;
699                 case 'u':
700                         got_user = 1;
701                         user_name = optarg;
702                         break;
703                 case 'd':
704                         domain_name = optarg;
705                         break;
706                 case 'p':
707                         if(mountpassword == NULL)
708                                 mountpassword = calloc(65,1);
709                         if(mountpassword) {
710                                 got_password = 1;
711                                 strncpy(mountpassword,optarg,64);
712                         }
713                         break;
714                 case 't':
715                         break;
716                 default:
717                         printf("unknown mount option %c\n",c);
718                         mount_cifs_usage();
719                         exit(1);
720                 }
721         }
722
723         if(argc < 3)
724                 mount_cifs_usage();
725
726         if (getenv("PASSWD")) {
727                 if(mountpassword == NULL)
728                         mountpassword = calloc(65,1);
729                 if(mountpassword) {
730                         strncpy(mountpassword,getenv("PASSWD"),64);
731                         got_password = 1;
732                 }
733         } else if (getenv("PASSWD_FD")) {
734                 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
735         } else if (getenv("PASSWD_FILE")) {
736                 get_password_from_file(0, getenv("PASSWD_FILE"));
737         }
738
739         ipaddr = parse_server(share_name);
740
741         if(ipaddr == NULL)
742                 return -1;
743         
744         if (orgoptions && parse_options(orgoptions, &flags))
745                 return -1;
746
747         /* BB save off path and pop after mount returns? */
748         resolved_path = malloc(PATH_MAX+1);
749         if(resolved_path) {
750                 /* Note that if we can not canonicalize the name, we get
751                 another chance to see if it is valid when we chdir to it */
752                 if (realpath(mountpoint, resolved_path)) {
753                         mountpoint = resolved_path; 
754                 }
755         }
756         if(chdir(mountpoint)) {
757                 printf("mount error: can not change directory into mount target %s\n",mountpoint);
758                 return -1;
759         }
760
761         if(stat (".", &statbuf)) {
762                 printf("mount error: mount point %s does not exist\n",mountpoint);
763                 return -1;
764         }
765
766         if (S_ISDIR(statbuf.st_mode) == 0) {
767                 printf("mount error: mount point %s is not a directory\n",mountpoint);
768                 return -1;
769         }
770
771         if((getuid() != 0) && (geteuid() == 0)) {
772                 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
773 #ifndef CIFS_ALLOW_USR_SUID
774                         /* Do not allow user mounts to control suid flag
775                         for mount unless explicitly built that way */
776                         flags |= MS_NOSUID | MS_NODEV;
777 #endif                                          
778                 } else {
779                         printf("mount error: permission denied or not superuser and cifs.mount not installed SUID\n"); 
780                         return -1;
781                 }
782         }
783
784         if(got_user == 0)
785                 user_name = getusername();
786        
787         if(got_password == 0) {
788                 mountpassword = getpass("Password: "); /* BB obsolete */
789                 got_password = 1;
790         }
791         /* FIXME launch daemon (handles dfs name resolution and credential change) 
792            remember to clear parms and overwrite password field before launching */
793         if(orgoptions) {
794                 optlen = strlen(orgoptions);
795                 orgoptlen = optlen;
796         } else
797                 optlen = 0;
798         if(share_name)
799                 optlen += strlen(share_name) + 4;
800         if(user_name)
801                 optlen += strlen(user_name) + 6;
802         if(ipaddr)
803                 optlen += strlen(ipaddr) + 4;
804         if(mountpassword)
805                 optlen += strlen(mountpassword) + 6;
806         options = malloc(optlen + 10);
807
808         if(options == NULL) {
809                 printf("Could not allocate memory for mount options\n");
810                 return -1;
811         }
812                 
813
814         options[0] = 0;
815         strncat(options,"unc=",4);
816         strcat(options,share_name);
817         /* scan backwards and reverse direction of slash */
818         temp = strrchr(options, '/');
819         if(temp > options + 6)
820                 *temp = '\\';
821         if(ipaddr) {
822                 strncat(options,",ip=",4);
823                 strcat(options,ipaddr);
824         } 
825         if(user_name) {
826                 strncat(options,",user=",6);
827                 strcat(options,user_name);
828         } 
829         if(mountpassword) {
830                 strncat(options,",pass=",6);
831                 strcat(options,mountpassword);
832         }
833         strncat(options,",ver=",5);
834         strcat(options,MOUNT_CIFS_VERSION_MAJOR);
835
836         if(orgoptions) {
837                 strcat(options,",");
838                 strcat(options,orgoptions);
839         }
840         if(verboseflag)
841                 printf("\ncifs.mount kernel mount options %s \n",options);
842         if(mount(share_name, mountpoint, "cifs", flags, options)) {
843         /* remember to kill daemon on error */
844                 switch (errno) {
845                 case 0:
846                         printf("mount failed but no error number set\n");
847                         break;
848                 case ENODEV:
849                         printf("mount error: cifs filesystem not supported by the system\n");
850                         break;
851                 default:
852                         printf("mount error %d = %s\n",errno,strerror(errno));
853                 }
854                 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
855                 if(mountpassword) {
856                         memset(mountpassword,0,64);
857                 }
858                 return -1;
859         } else {
860                 pmntfile = setmntent(MOUNTED, "a+");
861                 if(pmntfile) {
862                         mountent.mnt_fsname = share_name;
863                         mountent.mnt_dir = mountpoint; 
864                         mountent.mnt_type = "cifs"; 
865                         mountent.mnt_opts = malloc(200);
866                         if(mountent.mnt_opts) {
867                                 memset(mountent.mnt_opts,0,200);
868                                 if(flags & MS_RDONLY)
869                                         strcat(mountent.mnt_opts,"ro");
870                                 else
871                                         strcat(mountent.mnt_opts,"rw");
872                                 if(flags & MS_MANDLOCK)
873                                         strcat(mountent.mnt_opts,",mand");
874                                 else
875                                         strcat(mountent.mnt_opts,",nomand");
876                                 if(flags & MS_NOEXEC)
877                                         strcat(mountent.mnt_opts,",noexec");
878                                 if(flags & MS_NOSUID)
879                                         strcat(mountent.mnt_opts,",nosuid");
880                                 if(flags & MS_NODEV)
881                                         strcat(mountent.mnt_opts,",nodev");
882                                 if(flags & MS_SYNCHRONOUS)
883                                         strcat(mountent.mnt_opts,",synch");
884                         }
885                         mountent.mnt_freq = 0;
886                         mountent.mnt_passno = 0;
887                         rc = addmntent(pmntfile,&mountent);
888                         endmntent(pmntfile);
889                         if(mountent.mnt_opts)
890                                 free(mountent.mnt_opts);
891                 } else {
892                     printf("could not update mount table\n");
893                 }
894         }
895         if(mountpassword) {
896                 memset(mountpassword,0,64);
897                 free(mountpassword);
898         }
899
900         if(options) {
901                 memset(options,0,optlen);
902                 free(options);
903         }
904
905         if(orgoptions) {
906                 memset(orgoptions,0,orgoptlen);
907                 free(orgoptions);
908         }
909         if(resolved_path) {
910                 free(resolved_path);
911         }
912
913         return 0;
914 }
915