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