r5236: Ignore users mount parm (since unneeded by cifs kernel code). Suggested by...
[tprouty/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 "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, "users",5) == 0) {
294                         if(!value || !*value) {
295                                 strncpy(data,",,,,,",5);
296                         }
297                 } else if (strncmp(data, "user", 4) == 0) {
298                         if (!value || !*value) {
299                                 if(data[4] == '\0') {
300                                         if(verboseflag)
301                                                 printf("\nskipping empty user mount parameter\n");
302                                         /* remove the parm since it would otherwise be confusing
303                                         to the kernel code which would think it was a real username */
304                                                 data[0] = ',';
305                                                 data[1] = ',';
306                                                 data[2] = ',';
307                                                 data[3] = ',';
308                                         /* BB remove it from mount line so as not to confuse kernel code */
309                                 } else {
310                                         printf("username specified with no parameter\n");
311                                         return 1;       /* needs_arg; */
312                                 }
313                         } else {
314                                 if (strnlen(value, 260) < 260) {
315                                         got_user=1;
316                                         percent_char = strchr(value,'%');
317                                         if(percent_char) {
318                                                 *percent_char = ',';
319                                                 if(mountpassword == NULL)
320                                                         mountpassword = calloc(65,1);
321                                                 if(mountpassword) {
322                                                         if(got_password)
323                                                                 printf("\nmount.cifs warning - password specified twice\n");
324                                                         got_password = 1;
325                                                         percent_char++;
326                                                         strncpy(mountpassword, percent_char,64);
327                                                 /*  remove password from username */
328                                                         while(*percent_char != 0) {
329                                                                 *percent_char = ',';
330                                                                 percent_char++;
331                                                         }
332                                                 }
333                                         }
334                                 } else {
335                                         printf("username too long\n");
336                                         return 1;
337                                 }
338                         }
339                 } else if (strncmp(data, "pass", 4) == 0) {
340                         if (!value || !*value) {
341                                 if(got_password) {
342                                         printf("\npassword specified twice, ignoring second\n");
343                                 } else
344                                         got_password = 1;
345                         } else if (strnlen(value, 17) < 17) {
346                                 if(got_password)
347                                         printf("\nmount.cifs warning - password specified twice\n");
348                                 got_password = 1;
349                         } else {
350                                 printf("password too long\n");
351                                 return 1;
352                         }
353                 } else if (strncmp(data, "ip", 2) == 0) {
354                         if (!value || !*value) {
355                                 printf("target ip address argument missing");
356                         } else if (strnlen(value, 35) < 35) {
357                                 if(verboseflag)
358                                         printf("ip address %s override specified\n",value);
359                                 got_ip = 1;
360                         } else {
361                                 printf("ip address too long\n");
362                                 return 1;
363                         }
364                 } else if ((strncmp(data, "unc", 3) == 0)
365                    || (strncmp(data, "target", 6) == 0)
366                    || (strncmp(data, "path", 4) == 0)) {
367                         if (!value || !*value) {
368                                 printf("invalid path to network resource\n");
369                                 return 1;  /* needs_arg; */
370                         } else if(strnlen(value,5) < 5) {
371                                 printf("UNC name too short");
372                         }
373
374                         if (strnlen(value, 300) < 300) {
375                                 got_unc = 1;
376                                 if (strncmp(value, "//", 2) == 0) {
377                                         if(got_unc)
378                                                 printf("unc name specified twice, ignoring second\n");
379                                         else
380                                                 got_unc = 1;
381                                 } else if (strncmp(value, "\\\\", 2) != 0) {                       
382                                         printf("UNC Path does not begin with // or \\\\ \n");
383                                         return 1;
384                                 } else {
385                                         if(got_unc)
386                                                 printf("unc name specified twice, ignoring second\n");
387                                         else
388                                                 got_unc = 1;
389                                 }
390                         } else {
391                                 printf("CIFS: UNC name too long\n");
392                                 return 1;
393                         }
394                 } else if ((strncmp(data, "domain", 3) == 0)
395                            || (strncmp(data, "workgroup", 5) == 0)) {
396                         if (!value || !*value) {
397                                 printf("CIFS: invalid domain name\n");
398                                 return 1;       /* needs_arg; */
399                         }
400                         if (strnlen(value, 65) < 65) {
401                                 got_domain = 1;
402                         } else {
403                                 printf("domain name too long\n");
404                                 return 1;
405                         }
406                 } else if (strncmp(data, "cred", 4) == 0) {
407                         if (value && *value) {
408                                 rc = open_cred_file(value);
409                                 if(rc) {
410                                         printf("error %d opening credential file %s\n",rc, value);
411                                         return 1;
412                                 }
413                         } else {
414                                 printf("invalid credential file name specified\n");
415                                 return 1;
416                         }
417                 } else if (strncmp(data, "uid", 3) == 0) {
418                         if (value && *value) {
419                                 got_uid = 1;
420                         }
421                 } else if (strncmp(data, "gid", 3) == 0) {
422                         if (value && *value) {
423                                 got_gid = 1;
424                         }
425        /* fmask and dmask synonyms for people used to smbfs syntax */
426                 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
427                         if (!value || !*value) {
428                                 printf ("Option '%s' requires a numerical argument\n", data);
429                                 return 1;
430                         }
431
432                         if (value[0] != '0') {
433                                 printf ("WARNING: '%s' not expressed in octal.\n", data);
434                         }
435
436                         if (strcmp (data, "fmask") == 0) {
437                                 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
438                                 data = "file_mode"; /* BB fix this */
439                         }
440                 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
441                         if (!value || !*value) {
442                                 printf ("Option '%s' requires a numerical argument\n", data);
443                                 return 1;
444                         }
445
446                         if (value[0] != '0') {
447                                 printf ("WARNING: '%s' not expressed in octal.\n", data);
448                         }
449
450                         if (strcmp (data, "dmask") == 0) {
451                                 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
452                                 data = "dir_mode";
453                         }
454                         /* the following eight mount options should be
455                         stripped out from what is passed into the kernel
456                         since these eight options are best passed as the
457                         mount flags rather than redundantly to the kernel 
458                         and could generate spurious warnings depending on the
459                         level of the corresponding cifs vfs kernel code */
460                 } else if (strncmp(data, "nosuid", 6) == 0) {
461                         *filesys_flags |= MS_NOSUID;
462                 } else if (strncmp(data, "suid", 4) == 0) {
463                         *filesys_flags &= ~MS_NOSUID;
464                 } else if (strncmp(data, "nodev", 5) == 0) {
465                         *filesys_flags |= MS_NODEV;
466                 } else if (strncmp(data, "dev", 3) == 0) {
467                         *filesys_flags &= ~MS_NODEV;
468                 } else if (strncmp(data, "noexec", 6) == 0) {
469                         *filesys_flags |= MS_NOEXEC;
470                 } else if (strncmp(data, "exec", 4) == 0) {
471                         *filesys_flags &= ~MS_NOEXEC;
472                 } else if (strncmp(data, "guest", 5) == 0) {
473                         got_password=1;
474                         /* remove the parm since it would otherwise be logged by kern */
475                         data[0] = ',';
476                         data[1] = ',';
477                         data[2] = ',';
478                         data[3] = ',';
479                         data[4] = ',';
480                 } else if (strncmp(data, "ro", 2) == 0) {
481                         *filesys_flags |= MS_RDONLY;
482                 } else if (strncmp(data, "rw", 2) == 0) {
483                         *filesys_flags &= ~MS_RDONLY;
484                 } /* else if (strnicmp(data, "port", 4) == 0) {
485                         if (value && *value) {
486                                 vol->port =
487                                         simple_strtoul(value, &value, 0);
488                         }
489                 } else if (strnicmp(data, "rsize", 5) == 0) {
490                         if (value && *value) {
491                                 vol->rsize =
492                                         simple_strtoul(value, &value, 0);
493                         }
494                 } else if (strnicmp(data, "wsize", 5) == 0) {
495                         if (value && *value) {
496                                 vol->wsize =
497                                         simple_strtoul(value, &value, 0);
498                         }
499                 } else if (strnicmp(data, "version", 3) == 0) {
500                 } else {
501                         printf("CIFS: Unknown mount option %s\n",data);
502                 } */ /* nothing to do on those four mount options above.
503                         Just pass to kernel and ignore them here */
504
505                         /* move to next option */
506                 data = next_keyword+1;
507
508                 /* put overwritten equals sign back */
509                 if(value) {
510                         value--;
511                         *value = '=';
512                 }
513         
514                 /* put previous overwritten comma back */
515                 if(next_keyword)
516                         *next_keyword = ',';
517                 else
518                         data = NULL;
519         }
520         return 0;
521 }
522
523 /* Note that caller frees the returned buffer if necessary */
524 char * parse_server(char ** punc_name)
525 {
526         char * unc_name = *punc_name;
527         int length = strnlen(unc_name,1024);
528         char * share;
529         char * ipaddress_string = NULL;
530         struct hostent * host_entry;
531         struct in_addr server_ipaddr;
532         int rc;
533
534         if(length > 1023) {
535                 printf("mount error: UNC name too long");
536                 return NULL;
537         }
538         if (strncasecmp("cifs://",unc_name,7) == 0)
539                 return parse_cifs_url(unc_name+7);
540         if (strncasecmp("smb://",unc_name,6) == 0) {
541                 return parse_cifs_url(unc_name+6);
542         }
543
544         if(length < 3) {
545                 /* BB add code to find DFS root here */
546                 printf("\nMounting the DFS root for domain not implemented yet");
547                 return NULL;
548         } else {
549                 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
550                         /* check for nfs syntax ie server:share */
551                         share = strchr(unc_name,':');
552                         if(share) {
553                                 free_share_name = 1;
554                                 *punc_name = malloc(length+3);
555                                 *share = '/';
556                                 strncpy((*punc_name)+2,unc_name,length);
557                                 unc_name = *punc_name;
558                                 unc_name[length+2] = 0;
559                                 goto continue_unc_parsing;
560                         } else {
561                                 printf("mount error: improperly formatted UNC name.");
562                                 printf(" %s does not begin with \\\\ or //\n",unc_name);
563                                 return NULL;
564                         }
565                 } else {
566 continue_unc_parsing:
567                         unc_name[0] = '/';
568                         unc_name[1] = '/';
569                         unc_name += 2;
570                         if ((share = strchr(unc_name, '/')) || 
571                                 (share = strchr(unc_name,'\\'))) {
572                                 *share = 0;  /* temporarily terminate the string */
573                                 share += 1;
574                                 if(got_ip == 0) {
575                                         host_entry = gethostbyname(unc_name);
576                                 }
577                                 *(share - 1) = '/'; /* put the slash back */
578                                 if(got_ip) {
579                                         if(verboseflag)
580                                                 printf("ip address specified explicitly\n");
581                                         return NULL;
582                                 }
583                                 if(host_entry == NULL) {
584                                         printf("mount error: could not find target server. TCP name %s not found ", unc_name);
585                                         printf(" rc = %d\n",rc);
586                                         return NULL;
587                                 } else {
588                                         /* BB should we pass an alternate version of the share name as Unicode */
589                                         /* BB what about ipv6? BB */
590                                         /* BB add retries with alternate servers in list */
591
592                                         memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
593
594                                         ipaddress_string = inet_ntoa(server_ipaddr);                                                                                     
595                                         if(ipaddress_string == NULL) {
596                                                 printf("mount error: could not get valid ip address for target server\n");
597                                                 return NULL;
598                                         }
599                                         return ipaddress_string; 
600                                 }
601                         } else {
602                                 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
603                                 printf("Mounting the DFS root for a particular server not implemented yet\n");
604                                 return NULL;
605                         }
606                 }
607         }
608 }
609
610 static struct option longopts[] = {
611         { "all", 0, NULL, 'a' },
612         { "help",0, NULL, 'h' },
613         { "move",0, NULL, 'm' },
614         { "bind",0, NULL, 'b' },
615         { "read-only", 0, NULL, 'r' },
616         { "ro", 0, NULL, 'r' },
617         { "verbose", 0, NULL, 'v' },
618         { "version", 0, NULL, 'V' },
619         { "read-write", 0, NULL, 'w' },
620         { "rw", 0, NULL, 'w' },
621         { "options", 1, NULL, 'o' },
622         { "type", 1, NULL, 't' },
623         { "rsize",1, NULL, 'R' },
624         { "wsize",1, NULL, 'W' },
625         { "uid", 1, NULL, '1'},
626         { "gid", 1, NULL, '2'},
627         { "user",1,NULL,'u'},
628         { "username",1,NULL,'u'},
629         { "dom",1,NULL,'d'},
630         { "domain",1,NULL,'d'},
631         { "password",1,NULL,'p'},
632         { "pass",1,NULL,'p'},
633         { "credentials",1,NULL,'c'},
634         { "port",1,NULL,'P'},
635         /* { "uuid",1,NULL,'U'}, */ /* BB unimplemented */
636         { NULL, 0, NULL, 0 }
637 };
638
639 int main(int argc, char ** argv)
640 {
641         int c;
642         int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
643         char * orgoptions = NULL;
644         char * share_name = NULL;
645         char * domain_name = NULL;
646         char * ipaddr = NULL;
647         char * uuid = NULL;
648         char * mountpoint;
649         char * options;
650         char * resolved_path;
651         char * temp;
652         int rc;
653         int rsize = 0;
654         int wsize = 0;
655         int nomtab = 0;
656         int uid = 0;
657         int gid = 0;
658         int optlen = 0;
659         int orgoptlen = 0;
660         struct stat statbuf;
661         struct utsname sysinfo;
662         struct mntent mountent;
663         FILE * pmntfile;
664
665         /* setlocale(LC_ALL, "");
666         bindtextdomain(PACKAGE, LOCALEDIR);
667         textdomain(PACKAGE); */
668
669         if(argc && argv) {
670                 thisprogram = argv[0];
671         }
672         if(thisprogram == NULL)
673                 thisprogram = "mount.cifs";
674
675         uname(&sysinfo);
676         /* BB add workstation name and domain and pass down */
677
678 /* #ifdef _GNU_SOURCE
679         printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
680 #endif */
681
682         share_name = argv[1];
683         mountpoint = argv[2];
684
685         /* add sharename in opts string as unc= parm */
686
687         while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
688                          longopts, NULL)) != -1) {
689                 switch (c) {
690 /* No code to do the following  options yet */
691 /*      case 'l':
692                 list_with_volumelabel = 1;
693                 break;
694         case 'L':
695                 volumelabel = optarg;
696                 break; */
697 /*      case 'a':              
698                 ++mount_all;
699                 break; */
700
701                 case '?':
702                 case 'h':        /* help */
703                         mount_cifs_usage ();
704                         exit(1);
705                 case 'n':
706                     ++nomtab;
707                     break;
708                 case 'b':
709                         flags |= MS_BIND;
710                         break;
711                 case 'm':
712                         flags |= MS_MOVE;
713                         break;
714                 case 'o':
715                         orgoptions = strdup(optarg);
716                     break;
717                 case 'r':  /* mount readonly */
718                         flags |= MS_RDONLY;
719                         break;
720                 case 'U':
721                         uuid = optarg;
722                         break;
723                 case 'v':
724                         ++verboseflag;
725                         break;
726                 case 'V':          
727                         printf ("mount.cifs version: %s.%s%s\n",
728                         MOUNT_CIFS_VERSION_MAJOR,
729                         MOUNT_CIFS_VERSION_MINOR,
730                         MOUNT_CIFS_VENDOR_SUFFIX);
731                         if(mountpassword) {
732                                 memset(mountpassword,0,64);
733                         }
734                         exit (0);
735                 case 'w':
736                         flags &= ~MS_RDONLY;
737                         break;
738                 case 'R':
739                         rsize = atoi(optarg) ;
740                         break;
741                 case 'W':
742                         wsize = atoi(optarg);
743                         break;
744                 case '1':
745                         uid = atoi(optarg);
746                         break;
747                 case '2':
748                         gid = atoi(optarg);
749                         break;
750                 case 'u':
751                         got_user = 1;
752                         user_name = optarg;
753                         break;
754                 case 'd':
755                         domain_name = optarg;
756                         break;
757                 case 'p':
758                         if(mountpassword == NULL)
759                                 mountpassword = calloc(65,1);
760                         if(mountpassword) {
761                                 got_password = 1;
762                                 strncpy(mountpassword,optarg,64);
763                         }
764                         break;
765                 case 'S':
766                         get_password_from_file(0 /* stdin */,NULL);
767                         break;
768                 case 't':
769                         break;
770                 default:
771                         printf("unknown mount option %c\n",c);
772                         mount_cifs_usage();
773                         exit(1);
774                 }
775         }
776
777         if(argc < 3)
778                 mount_cifs_usage();
779
780         if (getenv("PASSWD")) {
781                 if(mountpassword == NULL)
782                         mountpassword = calloc(65,1);
783                 if(mountpassword) {
784                         strncpy(mountpassword,getenv("PASSWD"),64);
785                         got_password = 1;
786                 }
787         } else if (getenv("PASSWD_FD")) {
788                 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
789         } else if (getenv("PASSWD_FILE")) {
790                 get_password_from_file(0, getenv("PASSWD_FILE"));
791         }
792
793         if (orgoptions && parse_options(orgoptions, &flags))
794                 return -1;
795         
796         ipaddr = parse_server(&share_name);
797         if((ipaddr == NULL) && (got_ip == 0)) {
798                 printf("No ip address specified and hostname not found\n");
799                 return -1;
800         }
801         
802
803         /* BB save off path and pop after mount returns? */
804         resolved_path = malloc(PATH_MAX+1);
805         if(resolved_path) {
806                 /* Note that if we can not canonicalize the name, we get
807                 another chance to see if it is valid when we chdir to it */
808                 if (realpath(mountpoint, resolved_path)) {
809                         mountpoint = resolved_path; 
810                 }
811         }
812         if(chdir(mountpoint)) {
813                 printf("mount error: can not change directory into mount target %s\n",mountpoint);
814                 return -1;
815         }
816
817         if(stat (".", &statbuf)) {
818                 printf("mount error: mount point %s does not exist\n",mountpoint);
819                 return -1;
820         }
821
822         if (S_ISDIR(statbuf.st_mode) == 0) {
823                 printf("mount error: mount point %s is not a directory\n",mountpoint);
824                 return -1;
825         }
826
827         if((getuid() != 0) && (geteuid() == 0)) {
828                 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
829 #ifndef CIFS_ALLOW_USR_SUID
830                         /* Do not allow user mounts to control suid flag
831                         for mount unless explicitly built that way */
832                         flags |= MS_NOSUID | MS_NODEV;
833 #endif                                          
834                 } else {
835                         printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n"); 
836                         return -1;
837                 }
838         }
839
840         if(got_user == 0)
841                 user_name = getusername();
842        
843         if(got_password == 0) {
844                 mountpassword = getpass("Password: "); /* BB obsolete */
845                 got_password = 1;
846         }
847         /* FIXME launch daemon (handles dfs name resolution and credential change) 
848            remember to clear parms and overwrite password field before launching */
849         if(orgoptions) {
850                 optlen = strlen(orgoptions);
851                 orgoptlen = optlen;
852         } else
853                 optlen = 0;
854         if(share_name)
855                 optlen += strlen(share_name) + 4;
856         if(user_name)
857                 optlen += strlen(user_name) + 6;
858         if(ipaddr)
859                 optlen += strlen(ipaddr) + 4;
860         if(mountpassword)
861                 optlen += strlen(mountpassword) + 6;
862         options = malloc(optlen + 10);
863
864         if(options == NULL) {
865                 printf("Could not allocate memory for mount options\n");
866                 return -1;
867         }
868                 
869
870         options[0] = 0;
871         strncat(options,"unc=",4);
872         strcat(options,share_name);
873         /* scan backwards and reverse direction of slash */
874         temp = strrchr(options, '/');
875         if(temp > options + 6)
876                 *temp = '\\';
877         if(ipaddr) {
878                 strncat(options,",ip=",4);
879                 strcat(options,ipaddr);
880         } 
881         if(user_name) {
882                 strncat(options,",user=",6);
883                 strcat(options,user_name);
884         } 
885         if(mountpassword) {
886                 strncat(options,",pass=",6);
887                 strcat(options,mountpassword);
888         }
889         strncat(options,",ver=",5);
890         strcat(options,MOUNT_CIFS_VERSION_MAJOR);
891
892         if(orgoptions) {
893                 strcat(options,",");
894                 strcat(options,orgoptions);
895         }
896         if(verboseflag)
897                 printf("\nmount.cifs kernel mount options %s \n",options);
898         if(mount(share_name, mountpoint, "cifs", flags, options)) {
899         /* remember to kill daemon on error */
900                 switch (errno) {
901                 case 0:
902                         printf("mount failed but no error number set\n");
903                         break;
904                 case ENODEV:
905                         printf("mount error: cifs filesystem not supported by the system\n");
906                         break;
907                 default:
908                         printf("mount error %d = %s\n",errno,strerror(errno));
909                 }
910                 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
911                 if(mountpassword) {
912                         memset(mountpassword,0,64);
913                 }
914                 return -1;
915         } else {
916                 pmntfile = setmntent(MOUNTED, "a+");
917                 if(pmntfile) {
918                         mountent.mnt_fsname = share_name;
919                         mountent.mnt_dir = mountpoint; 
920                         mountent.mnt_type = "cifs"; 
921                         mountent.mnt_opts = malloc(220);
922                         if(mountent.mnt_opts) {
923                                 char * mount_user = getusername();
924                                 memset(mountent.mnt_opts,0,200);
925                                 if(flags & MS_RDONLY)
926                                         strcat(mountent.mnt_opts,"ro");
927                                 else
928                                         strcat(mountent.mnt_opts,"rw");
929                                 if(flags & MS_MANDLOCK)
930                                         strcat(mountent.mnt_opts,",mand");
931                                 else
932                                         strcat(mountent.mnt_opts,",nomand");
933                                 if(flags & MS_NOEXEC)
934                                         strcat(mountent.mnt_opts,",noexec");
935                                 if(flags & MS_NOSUID)
936                                         strcat(mountent.mnt_opts,",nosuid");
937                                 if(flags & MS_NODEV)
938                                         strcat(mountent.mnt_opts,",nodev");
939                                 if(flags & MS_SYNCHRONOUS)
940                                         strcat(mountent.mnt_opts,",synch");
941                                 if(mount_user) {
942                                         if(getuid() != 0) {
943                                                 strcat(mountent.mnt_opts,",user=");
944                                                 strcat(mountent.mnt_opts,mount_user);
945                                         }
946                                         free(mount_user);
947                                 }
948                         }
949                         mountent.mnt_freq = 0;
950                         mountent.mnt_passno = 0;
951                         rc = addmntent(pmntfile,&mountent);
952                         endmntent(pmntfile);
953                         if(mountent.mnt_opts)
954                                 free(mountent.mnt_opts);
955                 } else {
956                     printf("could not update mount table\n");
957                 }
958         }
959         if(mountpassword) {
960                 memset(mountpassword,0,64);
961                 free(mountpassword);
962         }
963
964         if(options) {
965                 memset(options,0,optlen);
966                 free(options);
967         }
968
969         if(orgoptions) {
970                 memset(orgoptions,0,orgoptlen);
971                 free(orgoptions);
972         }
973         if(resolved_path) {
974                 free(resolved_path);
975         }
976
977         if(free_share_name) {
978                 free(share_name);
979                 }
980         return 0;
981 }
982