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