mount.cifs: fix several problems when mounting subdirectories of shares (try 2)
[kai/samba.git] / source3 / client / mount.cifs.c
1 /* 
2    Mount helper utility for Linux CIFS VFS (virtual filesystem) client
3    Copyright (C) 2003,2005 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 3 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, see <http://www.gnu.org/licenses/>.  */
17
18 #ifndef _GNU_SOURCE
19 #define _GNU_SOURCE
20 #endif
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <pwd.h>
26 #include <grp.h>
27 #include <ctype.h>
28 #include <sys/types.h>
29 #include <sys/mount.h>
30 #include <sys/stat.h>
31 #include <sys/utsname.h>
32 #include <sys/socket.h>
33 #include <arpa/inet.h>
34 #include <getopt.h>
35 #include <errno.h>
36 #include <netdb.h>
37 #include <string.h>
38 #include <mntent.h>
39 #include <fcntl.h>
40 #include <limits.h>
41
42 #define MOUNT_CIFS_VERSION_MAJOR "1"
43 #define MOUNT_CIFS_VERSION_MINOR "11"
44
45 #ifndef MOUNT_CIFS_VENDOR_SUFFIX
46  #ifdef _SAMBA_BUILD_
47   #include "include/version.h"
48   #ifdef SAMBA_VERSION_VENDOR_SUFFIX
49    #define MOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING"-"SAMBA_VERSION_VENDOR_SUFFIX
50   #else
51    #define MOUNT_CIFS_VENDOR_SUFFIX "-"SAMBA_VERSION_OFFICIAL_STRING
52   #endif /* SAMBA_VERSION_OFFICIAL_STRING and SAMBA_VERSION_VENDOR_SUFFIX */
53  #else
54    #define MOUNT_CIFS_VENDOR_SUFFIX ""
55  #endif /* _SAMBA_BUILD_ */
56 #endif /* MOUNT_CIFS_VENDOR_SUFFIX */
57
58 #ifndef MS_MOVE 
59 #define MS_MOVE 8192 
60 #endif 
61
62 #ifndef MS_BIND
63 #define MS_BIND 4096
64 #endif
65
66 #define MAX_UNC_LEN 1024
67
68 #define CONST_DISCARD(type, ptr)      ((type) ((void *) (ptr)))
69
70 const char *thisprogram;
71 int verboseflag = 0;
72 static int got_password = 0;
73 static int got_user = 0;
74 static int got_domain = 0;
75 static int got_ip = 0;
76 static int got_unc = 0;
77 static int got_uid = 0;
78 static int got_gid = 0;
79 static char * user_name = NULL;
80 static char * mountpassword = NULL;
81 char * domain_name = NULL;
82 char * prefixpath = NULL;
83
84 /* glibc doesn't have strlcpy, strlcat. Ensure we do. JRA. We
85  * don't link to libreplace so need them here. */
86
87 /* like strncpy but does not 0 fill the buffer and always null
88  *    terminates. bufsize is the size of the destination buffer */
89 size_t strlcpy(char *d, const char *s, size_t bufsize)
90 {
91         size_t len = strlen(s);
92         size_t ret = len;
93         if (bufsize <= 0) return 0;
94         if (len >= bufsize) len = bufsize-1;
95         memcpy(d, s, len);
96         d[len] = 0;
97         return ret;
98 }
99
100 /* like strncat but does not 0 fill the buffer and always null
101  *    terminates. bufsize is the length of the buffer, which should
102  *       be one more than the maximum resulting string length */
103 size_t strlcat(char *d, const char *s, size_t bufsize)
104 {
105         size_t len1 = strlen(d);
106         size_t len2 = strlen(s);
107         size_t ret = len1 + len2;
108
109         if (len1+len2 >= bufsize) {
110                 len2 = bufsize - (len1+1);
111         }
112         if (len2 > 0) {
113                 memcpy(d+len1, s, len2);
114                 d[len1+len2] = 0;
115         }
116         return ret;
117 }
118
119 /* BB finish BB
120
121         cifs_umount
122         open nofollow - avoid symlink exposure? 
123         get owner of dir see if matches self or if root
124         call system(umount argv) etc.
125                 
126 BB end finish BB */
127
128 static char * check_for_domain(char **);
129
130
131 static void mount_cifs_usage(void)
132 {
133         printf("\nUsage:  %s <remotetarget> <dir> -o <options>\n", thisprogram);
134         printf("\nMount the remote target, specified as a UNC name,");
135         printf(" to a local directory.\n\nOptions:\n");
136         printf("\tuser=<arg>\n\tpass=<arg>\n\tdom=<arg>\n");
137         printf("\nLess commonly used options:");
138         printf("\n\tcredentials=<filename>,guest,perm,noperm,setuids,nosetuids,rw,ro,");
139         printf("\n\tsep=<char>,iocharset=<codepage>,suid,nosuid,exec,noexec,serverino,");
140         printf("\n\tmapchars,nomapchars,nolock,servernetbiosname=<SRV_RFC1001NAME>");
141         printf("\n\tdirectio,nounix,cifsacl,sec=<authentication mechanism>,sign");
142         printf("\n\nOptions not needed for servers supporting CIFS Unix extensions");
143         printf("\n\t(e.g. unneeded for mounts to most Samba versions):");
144         printf("\n\tuid=<uid>,gid=<gid>,dir_mode=<mode>,file_mode=<mode>,sfu");
145         printf("\n\nRarely used options:");
146         printf("\n\tport=<tcpport>,rsize=<size>,wsize=<size>,unc=<unc_name>,ip=<ip_address>,");
147         printf("\n\tdev,nodev,nouser_xattr,netbiosname=<OUR_RFC1001NAME>,hard,soft,intr,");
148         printf("\n\tnointr,ignorecase,noposixpaths,noacl,prefixpath=<path>,nobrl");
149         printf("\n\tin6_addr");
150         printf("\n\nOptions are described in more detail in the manual page");
151         printf("\n\tman 8 mount.cifs\n");
152         printf("\nTo display the version number of the mount helper:");
153         printf("\n\t%s -V\n",thisprogram);
154
155         if(mountpassword) {
156                 memset(mountpassword,0,64);
157                 free(mountpassword);
158         }
159         exit(1);
160 }
161
162 /* caller frees username if necessary */
163 static char * getusername(void) {
164         char *username = NULL;
165         struct passwd *password = getpwuid(getuid());
166
167         if (password) {
168                 username = password->pw_name;
169         }
170         return username;
171 }
172
173 static char * parse_cifs_url(char * unc_name)
174 {
175         printf("\nMounting cifs URL not implemented yet. Attempt to mount %s\n",unc_name);
176         return NULL;
177 }
178
179 static int open_cred_file(char * file_name)
180 {
181         char * line_buf;
182         char * temp_val;
183         FILE * fs;
184         int i, length;
185         fs = fopen(file_name,"r");
186         if(fs == NULL)
187                 return errno;
188         line_buf = (char *)malloc(4096);
189         if(line_buf == NULL) {
190                 fclose(fs);
191                 return -ENOMEM;
192         }
193
194         while(fgets(line_buf,4096,fs)) {
195                 /* parse line from credential file */
196
197                 /* eat leading white space */
198                 for(i=0;i<4086;i++) {
199                         if((line_buf[i] != ' ') && (line_buf[i] != '\t'))
200                                 break;
201                         /* if whitespace - skip past it */
202                 }
203                 if (strncasecmp("username",line_buf+i,8) == 0) {
204                         temp_val = strchr(line_buf + i,'=');
205                         if(temp_val) {
206                                 /* go past equals sign */
207                                 temp_val++;
208                                 for(length = 0;length<4087;length++) {
209                                         if ((temp_val[length] == '\n')
210                                             || (temp_val[length] == '\0')) {
211                                                 break;
212                                         }
213                                 }
214                                 if(length > 4086) {
215                                         printf("mount.cifs failed due to malformed username in credentials file");
216                                         memset(line_buf,0,4096);
217                                         if(mountpassword) {
218                                                 memset(mountpassword,0,64);
219                                         }
220                                         exit(1);
221                                 } else {
222                                         got_user = 1;
223                                         user_name = (char *)calloc(1 + length,1);
224                                         /* BB adding free of user_name string before exit,
225                                                 not really necessary but would be cleaner */
226                                         strncpy(user_name,temp_val, length);
227                                 }
228                         }
229                 } else if (strncasecmp("password",line_buf+i,8) == 0) {
230                         temp_val = strchr(line_buf+i,'=');
231                         if(temp_val) {
232                                 /* go past equals sign */
233                                 temp_val++;
234                                 for(length = 0;length<65;length++) {
235                                         if ((temp_val[length] == '\n')
236                                             || (temp_val[length] == '\0')) {
237                                                 break;
238                                         }
239                                 }
240                                 if(length > 64) {
241                                         printf("mount.cifs failed: password in credentials file too long\n");
242                                         memset(line_buf,0, 4096);
243                                         if(mountpassword) {
244                                                 memset(mountpassword,0,64);
245                                         }
246                                         exit(1);
247                                 } else {
248                                         if(mountpassword == NULL) {
249                                                 mountpassword = (char *)calloc(65,1);
250                                         } else
251                                                 memset(mountpassword,0,64);
252                                         if(mountpassword) {
253                                                 strncpy(mountpassword,temp_val,length);
254                                                 got_password = 1;
255                                         }
256                                 }
257                         }
258                 } else if (strncasecmp("domain",line_buf+i,6) == 0) {
259                         temp_val = strchr(line_buf+i,'=');
260                         if(temp_val) {
261                                 /* go past equals sign */
262                                 temp_val++;
263                                 if(verboseflag)
264                                         printf("\nDomain %s\n",temp_val);
265                                 for(length = 0;length<65;length++) {
266                                         if ((temp_val[length] == '\n')
267                                             || (temp_val[length] == '\0')) {
268                                                 break;
269                                         }
270                                 }
271                                 if(length > 64) {
272                                         printf("mount.cifs failed: domain in credentials file too long\n");
273                                         if(mountpassword) {
274                                                 memset(mountpassword,0,64);
275                                         }
276                                         exit(1);
277                                 } else {
278                                         if(domain_name == NULL) {
279                                                 domain_name = (char *)calloc(65,1);
280                                         } else
281                                                 memset(domain_name,0,64);
282                                         if(domain_name) {
283                                                 strncpy(domain_name,temp_val,length);
284                                                 got_domain = 1;
285                                         }
286                                 }
287                         }
288                 }
289
290         }
291         fclose(fs);
292         if(line_buf) {
293                 memset(line_buf,0,4096);
294                 free(line_buf);
295         }
296         return 0;
297 }
298
299 static int get_password_from_file(int file_descript, char * filename)
300 {
301         int rc = 0;
302         int i;
303         char c;
304
305         if(mountpassword == NULL)
306                 mountpassword = (char *)calloc(65,1);
307         else 
308                 memset(mountpassword, 0, 64);
309
310         if (mountpassword == NULL) {
311                 printf("malloc failed\n");
312                 exit(1);
313         }
314
315         if(filename != NULL) {
316                 file_descript = open(filename, O_RDONLY);
317                 if(file_descript < 0) {
318                         printf("mount.cifs failed. %s attempting to open password file %s\n",
319                                    strerror(errno),filename);
320                         exit(1);
321                 }
322         }
323         /* else file already open and fd provided */
324
325         for(i=0;i<64;i++) {
326                 rc = read(file_descript,&c,1);
327                 if(rc < 0) {
328                         printf("mount.cifs failed. Error %s reading password file\n",strerror(errno));
329                         memset(mountpassword,0,64);
330                         if(filename != NULL)
331                                 close(file_descript);
332                         exit(1);
333                 } else if(rc == 0) {
334                         if(mountpassword[0] == 0) {
335                                 if(verboseflag)
336                                         printf("\nWarning: null password used since cifs password file empty");
337                         }
338                         break;
339                 } else /* read valid character */ {
340                         if((c == 0) || (c == '\n')) {
341                                 break;
342                         } else 
343                                 mountpassword[i] = c;
344                 }
345         }
346         if((i == 64) && (verboseflag)) {
347                 printf("\nWarning: password longer than 64 characters specified in cifs password file");
348         }
349         got_password = 1;
350         if(filename != NULL) {
351                 close(file_descript);
352         }
353
354         return rc;
355 }
356
357 static int parse_options(char ** optionsp, int * filesys_flags)
358 {
359         const char * data;
360         char * percent_char = NULL;
361         char * value = NULL;
362         char * next_keyword = NULL;
363         char * out = NULL;
364         int out_len = 0;
365         int word_len;
366         int rc = 0;
367         char user[32];
368         char group[32];
369
370         if (!optionsp || !*optionsp)
371                 return 1;
372         data = *optionsp;
373
374         if(verboseflag)
375                 printf("parsing options: %s\n", data);
376
377         /* BB fixme check for separator override BB */
378
379         if (getuid()) {
380                 got_uid = 1;
381                 snprintf(user,sizeof(user),"%u",getuid());
382                 got_gid = 1;
383                 snprintf(group,sizeof(group),"%u",getgid());
384         }
385
386 /* while ((data = strsep(&options, ",")) != NULL) { */
387         while(data != NULL) {
388                 /*  check if ends with trailing comma */
389                 if(*data == 0)
390                         break;
391
392                 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
393                 /* data  = next keyword */
394                 /* value = next value ie stuff after equal sign */
395
396                 next_keyword = strchr(data,','); /* BB handle sep= */
397         
398                 /* temporarily null terminate end of keyword=value pair */
399                 if(next_keyword)
400                         *next_keyword++ = 0;
401
402                 /* temporarily null terminate keyword to make keyword and value distinct */
403                 if ((value = strchr(data, '=')) != NULL) {
404                         *value = '\0';
405                         value++;
406                 }
407
408                 if (strncmp(data, "users",5) == 0) {
409                         if(!value || !*value) {
410                                 goto nocopy;
411                         }
412                 } else if (strncmp(data, "user_xattr",10) == 0) {
413                    /* do nothing - need to skip so not parsed as user name */
414                 } else if (strncmp(data, "user", 4) == 0) {
415
416                         if (!value || !*value) {
417                                 if(data[4] == '\0') {
418                                         if(verboseflag)
419                                                 printf("\nskipping empty user mount parameter\n");
420                                         /* remove the parm since it would otherwise be confusing
421                                         to the kernel code which would think it was a real username */
422                                         goto nocopy;
423                                 } else {
424                                         printf("username specified with no parameter\n");
425                                         return 1;       /* needs_arg; */
426                                 }
427                         } else {
428                                 if (strnlen(value, 260) < 260) {
429                                         got_user=1;
430                                         percent_char = strchr(value,'%');
431                                         if(percent_char) {
432                                                 *percent_char = ',';
433                                                 if(mountpassword == NULL)
434                                                         mountpassword = (char *)calloc(65,1);
435                                                 if(mountpassword) {
436                                                         if(got_password)
437                                                                 printf("\nmount.cifs warning - password specified twice\n");
438                                                         got_password = 1;
439                                                         percent_char++;
440                                                         strncpy(mountpassword, percent_char,64);
441                                                 /*  remove password from username */
442                                                         while(*percent_char != 0) {
443                                                                 *percent_char = ',';
444                                                                 percent_char++;
445                                                         }
446                                                 }
447                                         }
448                                         /* this is only case in which the user
449                                         name buf is not malloc - so we have to
450                                         check for domain name embedded within
451                                         the user name here since the later
452                                         call to check_for_domain will not be
453                                         invoked */
454                                         domain_name = check_for_domain(&value);
455                                 } else {
456                                         printf("username too long\n");
457                                         return 1;
458                                 }
459                         }
460                 } else if (strncmp(data, "pass", 4) == 0) {
461                         if (!value || !*value) {
462                                 if(got_password) {
463                                         printf("\npassword specified twice, ignoring second\n");
464                                 } else
465                                         got_password = 1;
466                         } else if (strnlen(value, 17) < 17) {
467                                 if(got_password)
468                                         printf("\nmount.cifs warning - password specified twice\n");
469                                 got_password = 1;
470                         } else {
471                                 printf("password too long\n");
472                                 return 1;
473                         }
474                 } else if (strncmp(data, "sec", 3) == 0) {
475                         if (value) {
476                                 if (!strcmp(value, "none"))
477                                         got_password = 1;
478                         }
479                 } else if (strncmp(data, "ip", 2) == 0) {
480                         if (!value || !*value) {
481                                 printf("target ip address argument missing");
482                         } else if (strnlen(value, 35) < 35) {
483                                 if(verboseflag)
484                                         printf("ip address %s override specified\n",value);
485                                 got_ip = 1;
486                         } else {
487                                 printf("ip address too long\n");
488                                 return 1;
489                         }
490                 } else if ((strncmp(data, "unc", 3) == 0)
491                    || (strncmp(data, "target", 6) == 0)
492                    || (strncmp(data, "path", 4) == 0)) {
493                         if (!value || !*value) {
494                                 printf("invalid path to network resource\n");
495                                 return 1;  /* needs_arg; */
496                         } else if(strnlen(value,5) < 5) {
497                                 printf("UNC name too short");
498                         }
499
500                         if (strnlen(value, 300) < 300) {
501                                 got_unc = 1;
502                                 if (strncmp(value, "//", 2) == 0) {
503                                         if(got_unc)
504                                                 printf("unc name specified twice, ignoring second\n");
505                                         else
506                                                 got_unc = 1;
507                                 } else if (strncmp(value, "\\\\", 2) != 0) {                       
508                                         printf("UNC Path does not begin with // or \\\\ \n");
509                                         return 1;
510                                 } else {
511                                         if(got_unc)
512                                                 printf("unc name specified twice, ignoring second\n");
513                                         else
514                                                 got_unc = 1;
515                                 }
516                         } else {
517                                 printf("CIFS: UNC name too long\n");
518                                 return 1;
519                         }
520                 } else if ((strncmp(data, "domain", 3) == 0)
521                            || (strncmp(data, "workgroup", 5) == 0)) {
522                         if (!value || !*value) {
523                                 printf("CIFS: invalid domain name\n");
524                                 return 1;       /* needs_arg; */
525                         }
526                         if (strnlen(value, 65) < 65) {
527                                 got_domain = 1;
528                         } else {
529                                 printf("domain name too long\n");
530                                 return 1;
531                         }
532                 } else if (strncmp(data, "cred", 4) == 0) {
533                         if (value && *value) {
534                                 rc = open_cred_file(value);
535                                 if(rc) {
536                                         printf("error %d opening credential file %s\n",rc, value);
537                                         return 1;
538                                 }
539                         } else {
540                                 printf("invalid credential file name specified\n");
541                                 return 1;
542                         }
543                 } else if (strncmp(data, "uid", 3) == 0) {
544                         if (value && *value) {
545                                 got_uid = 1;
546                                 if (!isdigit(*value)) {
547                                         struct passwd *pw;
548
549                                         if (!(pw = getpwnam(value))) {
550                                                 printf("bad user name \"%s\"\n", value);
551                                                 exit(1);
552                                         }
553                                         snprintf(user, sizeof(user), "%u", pw->pw_uid);
554                                 } else {
555                                         strlcpy(user,value,sizeof(user));
556                                 }
557                         }
558                         goto nocopy;
559                 } else if (strncmp(data, "gid", 3) == 0) {
560                         if (value && *value) {
561                                 got_gid = 1;
562                                 if (!isdigit(*value)) {
563                                         struct group *gr;
564
565                                         if (!(gr = getgrnam(value))) {
566                                                 printf("bad group name \"%s\"\n", value);
567                                                 exit(1);
568                                         }
569                                         snprintf(group, sizeof(group), "%u", gr->gr_gid);
570                                 } else {
571                                         strlcpy(group,value,sizeof(group));
572                                 }
573                         }
574                         goto nocopy;
575        /* fmask and dmask synonyms for people used to smbfs syntax */
576                 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
577                         if (!value || !*value) {
578                                 printf ("Option '%s' requires a numerical argument\n", data);
579                                 return 1;
580                         }
581
582                         if (value[0] != '0') {
583                                 printf ("WARNING: '%s' not expressed in octal.\n", data);
584                         }
585
586                         if (strcmp (data, "fmask") == 0) {
587                                 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
588                                 data = "file_mode"; /* BB fix this */
589                         }
590                 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
591                         if (!value || !*value) {
592                                 printf ("Option '%s' requires a numerical argument\n", data);
593                                 return 1;
594                         }
595
596                         if (value[0] != '0') {
597                                 printf ("WARNING: '%s' not expressed in octal.\n", data);
598                         }
599
600                         if (strcmp (data, "dmask") == 0) {
601                                 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
602                                 data = "dir_mode";
603                         }
604                         /* the following eight mount options should be
605                         stripped out from what is passed into the kernel
606                         since these eight options are best passed as the
607                         mount flags rather than redundantly to the kernel 
608                         and could generate spurious warnings depending on the
609                         level of the corresponding cifs vfs kernel code */
610                 } else if (strncmp(data, "nosuid", 6) == 0) {
611                         *filesys_flags |= MS_NOSUID;
612                 } else if (strncmp(data, "suid", 4) == 0) {
613                         *filesys_flags &= ~MS_NOSUID;
614                 } else if (strncmp(data, "nodev", 5) == 0) {
615                         *filesys_flags |= MS_NODEV;
616                 } else if ((strncmp(data, "nobrl", 5) == 0) || 
617                            (strncmp(data, "nolock", 6) == 0)) {
618                         *filesys_flags &= ~MS_MANDLOCK;
619                 } else if (strncmp(data, "dev", 3) == 0) {
620                         *filesys_flags &= ~MS_NODEV;
621                 } else if (strncmp(data, "noexec", 6) == 0) {
622                         *filesys_flags |= MS_NOEXEC;
623                 } else if (strncmp(data, "exec", 4) == 0) {
624                         *filesys_flags &= ~MS_NOEXEC;
625                 } else if (strncmp(data, "guest", 5) == 0) {
626                         got_password=1;
627                 } else if (strncmp(data, "ro", 2) == 0) {
628                         *filesys_flags |= MS_RDONLY;
629                 } else if (strncmp(data, "rw", 2) == 0) {
630                         *filesys_flags &= ~MS_RDONLY;
631                 } else if (strncmp(data, "remount", 7) == 0) {
632                         *filesys_flags |= MS_REMOUNT;
633                 } /* else if (strnicmp(data, "port", 4) == 0) {
634                         if (value && *value) {
635                                 vol->port =
636                                         simple_strtoul(value, &value, 0);
637                         }
638                 } else if (strnicmp(data, "rsize", 5) == 0) {
639                         if (value && *value) {
640                                 vol->rsize =
641                                         simple_strtoul(value, &value, 0);
642                         }
643                 } else if (strnicmp(data, "wsize", 5) == 0) {
644                         if (value && *value) {
645                                 vol->wsize =
646                                         simple_strtoul(value, &value, 0);
647                         }
648                 } else if (strnicmp(data, "version", 3) == 0) {
649                 } else {
650                         printf("CIFS: Unknown mount option %s\n",data);
651                 } */ /* nothing to do on those four mount options above.
652                         Just pass to kernel and ignore them here */
653
654                 /* Copy (possibly modified) option to out */
655                 word_len = strlen(data);
656                 if (value)
657                         word_len += 1 + strlen(value);
658
659                 out = (char *)realloc(out, out_len + word_len + 2);
660                 if (out == NULL) {
661                         perror("malloc");
662                         exit(1);
663                 }
664
665                 if (out_len) {
666                         strlcat(out, ",", out_len + word_len + 2);
667                         out_len++;
668                 }
669
670                 if (value)
671                         snprintf(out + out_len, word_len + 1, "%s=%s", data, value);
672                 else
673                         snprintf(out + out_len, word_len + 1, "%s", data);
674                 out_len = strlen(out);
675
676 nocopy:
677                 data = next_keyword;
678         }
679
680         /* special-case the uid and gid */
681         if (got_uid) {
682                 word_len = strlen(user);
683
684                 out = (char *)realloc(out, out_len + word_len + 6);
685                 if (out == NULL) {
686                         perror("malloc");
687                         exit(1);
688                 }
689
690                 if (out_len) {
691                         strlcat(out, ",", out_len + word_len + 6);
692                         out_len++;
693                 }
694                 snprintf(out + out_len, word_len + 5, "uid=%s", user);
695                 out_len = strlen(out);
696         }
697         if (got_gid) {
698                 word_len = strlen(group);
699
700                 out = (char *)realloc(out, out_len + 1 + word_len + 6);
701                 if (out == NULL) {
702                 perror("malloc");
703                         exit(1);
704                 }
705
706                 if (out_len) {
707                         strlcat(out, ",", out_len + word_len + 6);
708                         out_len++;
709                 }
710                 snprintf(out + out_len, word_len + 5, "gid=%s", group);
711                 out_len = strlen(out);
712         }
713
714         free(*optionsp);
715         *optionsp = out;
716         return 0;
717 }
718
719 /* replace all (one or more) commas with double commas */
720 static void check_for_comma(char ** ppasswrd)
721 {
722         char *new_pass_buf;
723         char *pass;
724         int i,j;
725         int number_of_commas = 0;
726         int len;
727
728         if(ppasswrd == NULL)
729                 return;
730         else 
731                 (pass = *ppasswrd);
732
733         len = strlen(pass);
734
735         for(i=0;i<len;i++)  {
736                 if(pass[i] == ',')
737                         number_of_commas++;
738         }
739
740         if(number_of_commas == 0)
741                 return;
742         if(number_of_commas > 64) {
743                 /* would otherwise overflow the mount options buffer */
744                 printf("\nInvalid password. Password contains too many commas.\n");
745                 return;
746         }
747
748         new_pass_buf = (char *)malloc(len+number_of_commas+1);
749         if(new_pass_buf == NULL)
750                 return;
751
752         for(i=0,j=0;i<len;i++,j++) {
753                 new_pass_buf[j] = pass[i];
754                 if(pass[i] == ',') {
755                         j++;
756                         new_pass_buf[j] = pass[i];
757                 }
758         }
759         new_pass_buf[len+number_of_commas] = 0;
760
761         free(*ppasswrd);
762         *ppasswrd = new_pass_buf;
763         
764         return;
765 }
766
767 /* Usernames can not have backslash in them and we use
768    [BB check if usernames can have forward slash in them BB] 
769    backslash as domain\user separator character
770 */
771 static char * check_for_domain(char **ppuser)
772 {
773         char * original_string;
774         char * usernm;
775         char * domainnm;
776         int    original_len;
777         int    len;
778         int    i;
779
780         if(ppuser == NULL)
781                 return NULL;
782
783         original_string = *ppuser;
784
785         if (original_string == NULL)
786                 return NULL;
787         
788         original_len = strlen(original_string);
789
790         usernm = strchr(*ppuser,'/');
791         if (usernm == NULL) {
792                 usernm = strchr(*ppuser,'\\');
793                 if (usernm == NULL)
794                         return NULL;
795         }
796
797         if(got_domain) {
798                 printf("Domain name specified twice. Username probably malformed\n");
799                 return NULL;
800         }
801
802         usernm[0] = 0;
803         domainnm = *ppuser;
804         if (domainnm[0] != 0) {
805                 got_domain = 1;
806         } else {
807                 printf("null domain\n");
808         }
809         len = strlen(domainnm);
810         /* reset domainm to new buffer, and copy
811         domain name into it */
812         domainnm = (char *)malloc(len+1);
813         if(domainnm == NULL)
814                 return NULL;
815
816         strlcpy(domainnm,*ppuser,len+1);
817
818 /*      move_string(*ppuser, usernm+1) */
819         len = strlen(usernm+1);
820
821         if(len >= original_len) {
822                 /* should not happen */
823                 return domainnm;
824         }
825
826         for(i=0;i<original_len;i++) {
827                 if(i<len)
828                         original_string[i] = usernm[i+1];
829                 else /* stuff with commas to remove last parm */
830                         original_string[i] = ',';
831         }
832
833         /* BB add check for more than one slash? 
834           strchr(*ppuser,'/');
835           strchr(*ppuser,'\\') 
836         */
837         
838         return domainnm;
839 }
840
841 /* replace all occurances of "from" in a string with "to" */
842 static void replace_char(char *string, char from, char to, int maxlen)
843 {
844         char *lastchar = string + maxlen;
845         while (string) {
846                 string = strchr(string, from);
847                 if (string) {
848                         *string = to;
849                         if (string >= lastchar)
850                                 return;
851                 }
852         }
853 }
854
855 /* Note that caller frees the returned buffer if necessary */
856 static char * parse_server(char ** punc_name)
857 {
858         char * unc_name = *punc_name;
859         int length = strnlen(unc_name, MAX_UNC_LEN);
860         char * share;
861         char * ipaddress_string = NULL;
862         struct hostent * host_entry = NULL;
863         struct in_addr server_ipaddr;
864
865         if(length > (MAX_UNC_LEN - 1)) {
866                 printf("mount error: UNC name too long");
867                 return NULL;
868         }
869         if (strncasecmp("cifs://",unc_name,7) == 0)
870                 return parse_cifs_url(unc_name+7);
871         if (strncasecmp("smb://",unc_name,6) == 0) {
872                 return parse_cifs_url(unc_name+6);
873         }
874
875         if(length < 3) {
876                 /* BB add code to find DFS root here */
877                 printf("\nMounting the DFS root for domain not implemented yet\n");
878                 return NULL;
879         } else {
880                 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
881                         /* check for nfs syntax ie server:share */
882                         share = strchr(unc_name,':');
883                         if(share) {
884                                 *punc_name = (char *)malloc(length+3);
885                                 if(*punc_name == NULL) {
886                                         /* put the original string back  if 
887                                            no memory left */
888                                         *punc_name = unc_name;
889                                         return NULL;
890                                 }
891                                 *share = '/';
892                                 strncpy((*punc_name)+2,unc_name,length);
893                                 free(unc_name);
894                                 unc_name = *punc_name;
895                                 unc_name[length+2] = 0;
896                                 goto continue_unc_parsing;
897                         } else {
898                                 printf("mount error: improperly formatted UNC name.");
899                                 printf(" %s does not begin with \\\\ or //\n",unc_name);
900                                 return NULL;
901                         }
902                 } else {
903 continue_unc_parsing:
904                         unc_name[0] = '/';
905                         unc_name[1] = '/';
906                         unc_name += 2;
907
908                         /* allow for either delimiter between host and sharename */
909                         if ((share = strpbrk(unc_name, "/\\"))) {
910                                 *share = 0;  /* temporarily terminate the string */
911                                 share += 1;
912                                 if(got_ip == 0) {
913                                         host_entry = gethostbyname(unc_name);
914                                 }
915                                 *(share - 1) = '/'; /* put delimiter back */
916
917                                 /* we don't convert the prefixpath delimiters since '\\' is a valid char in posix paths */
918                                 if ((prefixpath = strpbrk(share, "/\\"))) {
919                                         *prefixpath = 0;  /* permanently terminate the string */
920                                         if (!strlen(++prefixpath))
921                                                 prefixpath = NULL; /* this needs to be done explicitly */
922                                 }
923                                 if(got_ip) {
924                                         if(verboseflag)
925                                                 printf("ip address specified explicitly\n");
926                                         return NULL;
927                                 }
928                                 if(host_entry == NULL) {
929                                         printf("mount error: could not find target server. TCP name %s not found\n", unc_name);
930                                         return NULL;
931                                 } else {
932                                         /* BB should we pass an alternate version of the share name as Unicode */
933                                         /* BB what about ipv6? BB */
934                                         /* BB add retries with alternate servers in list */
935
936                                         memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
937
938                                         ipaddress_string = inet_ntoa(server_ipaddr);                                                                                     
939                                         if(ipaddress_string == NULL) {
940                                                 printf("mount error: could not get valid ip address for target server\n");
941                                                 return NULL;
942                                         }
943                                         return ipaddress_string; 
944                                 }
945                         } else {
946                                 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
947                                 printf("Mounting the DFS root for a particular server not implemented yet\n");
948                                 return NULL;
949                         }
950                 }
951         }
952 }
953
954 static struct option longopts[] = {
955         { "all", 0, NULL, 'a' },
956         { "help",0, NULL, 'h' },
957         { "move",0, NULL, 'm' },
958         { "bind",0, NULL, 'b' },
959         { "read-only", 0, NULL, 'r' },
960         { "ro", 0, NULL, 'r' },
961         { "verbose", 0, NULL, 'v' },
962         { "version", 0, NULL, 'V' },
963         { "read-write", 0, NULL, 'w' },
964         { "rw", 0, NULL, 'w' },
965         { "options", 1, NULL, 'o' },
966         { "type", 1, NULL, 't' },
967         { "rsize",1, NULL, 'R' },
968         { "wsize",1, NULL, 'W' },
969         { "uid", 1, NULL, '1'},
970         { "gid", 1, NULL, '2'},
971         { "user",1,NULL,'u'},
972         { "username",1,NULL,'u'},
973         { "dom",1,NULL,'d'},
974         { "domain",1,NULL,'d'},
975         { "password",1,NULL,'p'},
976         { "pass",1,NULL,'p'},
977         { "credentials",1,NULL,'c'},
978         { "port",1,NULL,'P'},
979         /* { "uuid",1,NULL,'U'}, */ /* BB unimplemented */
980         { NULL, 0, NULL, 0 }
981 };
982
983 /* convert a string to uppercase. return false if the string
984  * wasn't ASCII or was a NULL ptr */
985 static int
986 uppercase_string(char *string)
987 {
988         if (!string)
989                 return 0;
990
991         while (*string) {
992                 /* check for unicode */
993                 if ((unsigned char) string[0] & 0x80)
994                         return 0;
995                 *string = toupper((unsigned char) *string);
996                 string++;
997         }
998
999         return 1;
1000 }
1001
1002 int main(int argc, char ** argv)
1003 {
1004         int c;
1005         int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
1006         char * orgoptions = NULL;
1007         char * share_name = NULL;
1008         char * ipaddr = NULL;
1009         char * uuid = NULL;
1010         char * mountpoint = NULL;
1011         char * options = NULL;
1012         char * resolved_path = NULL;
1013         char * temp;
1014         char * dev_name;
1015         int rc;
1016         int rsize = 0;
1017         int wsize = 0;
1018         int nomtab = 0;
1019         int uid = 0;
1020         int gid = 0;
1021         int optlen = 0;
1022         int orgoptlen = 0;
1023         size_t options_size = 0;
1024         int retry = 0; /* set when we have to retry mount with uppercase */
1025         struct stat statbuf;
1026         struct utsname sysinfo;
1027         struct mntent mountent;
1028         FILE * pmntfile;
1029
1030         /* setlocale(LC_ALL, "");
1031         bindtextdomain(PACKAGE, LOCALEDIR);
1032         textdomain(PACKAGE); */
1033
1034         if(argc && argv) {
1035                 thisprogram = argv[0];
1036         } else {
1037                 mount_cifs_usage();
1038                 exit(1);
1039         }
1040
1041         if(thisprogram == NULL)
1042                 thisprogram = "mount.cifs";
1043
1044         uname(&sysinfo);
1045         /* BB add workstation name and domain and pass down */
1046
1047 /* #ifdef _GNU_SOURCE
1048         printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
1049 #endif */
1050         if(argc > 2) {
1051                 dev_name = argv[1];
1052                 share_name = strndup(argv[1], MAX_UNC_LEN);
1053                 if (share_name == NULL) {
1054                         fprintf(stderr, "%s: %s", argv[0], strerror(ENOMEM));
1055                         exit(1);
1056                 }
1057                 mountpoint = argv[2];
1058         } else {
1059                 mount_cifs_usage();
1060                 exit(1);
1061         }
1062
1063         /* add sharename in opts string as unc= parm */
1064
1065         while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
1066                          longopts, NULL)) != -1) {
1067                 switch (c) {
1068 /* No code to do the following  options yet */
1069 /*      case 'l':
1070                 list_with_volumelabel = 1;
1071                 break;
1072         case 'L':
1073                 volumelabel = optarg;
1074                 break; */
1075 /*      case 'a':              
1076                 ++mount_all;
1077                 break; */
1078
1079                 case '?':
1080                 case 'h':        /* help */
1081                         mount_cifs_usage ();
1082                         exit(1);
1083                 case 'n':
1084                     ++nomtab;
1085                     break;
1086                 case 'b':
1087 #ifdef MS_BIND
1088                         flags |= MS_BIND;
1089 #else
1090                         fprintf(stderr,
1091                                 "option 'b' (MS_BIND) not supported\n");
1092 #endif
1093                         break;
1094                 case 'm':
1095 #ifdef MS_MOVE                
1096                         flags |= MS_MOVE;
1097 #else
1098                         fprintf(stderr,
1099                                 "option 'm' (MS_MOVE) not supported\n");
1100 #endif
1101                         break;
1102                 case 'o':
1103                         orgoptions = strdup(optarg);
1104                     break;
1105                 case 'r':  /* mount readonly */
1106                         flags |= MS_RDONLY;
1107                         break;
1108                 case 'U':
1109                         uuid = optarg;
1110                         break;
1111                 case 'v':
1112                         ++verboseflag;
1113                         break;
1114                 case 'V':          
1115                         printf ("mount.cifs version: %s.%s%s\n",
1116                         MOUNT_CIFS_VERSION_MAJOR,
1117                         MOUNT_CIFS_VERSION_MINOR,
1118                         MOUNT_CIFS_VENDOR_SUFFIX);
1119                         if(mountpassword) {
1120                                 memset(mountpassword,0,64);
1121                         }
1122                         exit (0);
1123                 case 'w':
1124                         flags &= ~MS_RDONLY;
1125                         break;
1126                 case 'R':
1127                         rsize = atoi(optarg) ;
1128                         break;
1129                 case 'W':
1130                         wsize = atoi(optarg);
1131                         break;
1132                 case '1':
1133                         if (isdigit(*optarg)) {
1134                                 char *ep;
1135
1136                                 uid = strtoul(optarg, &ep, 10);
1137                                 if (*ep) {
1138                                         printf("bad uid value \"%s\"\n", optarg);
1139                                         exit(1);
1140                                 }
1141                         } else {
1142                                 struct passwd *pw;
1143
1144                                 if (!(pw = getpwnam(optarg))) {
1145                                         printf("bad user name \"%s\"\n", optarg);
1146                                         exit(1);
1147                                 }
1148                                 uid = pw->pw_uid;
1149                                 endpwent();
1150                         }
1151                         break;
1152                 case '2':
1153                         if (isdigit(*optarg)) {
1154                                 char *ep;
1155
1156                                 gid = strtoul(optarg, &ep, 10);
1157                                 if (*ep) {
1158                                         printf("bad gid value \"%s\"\n", optarg);
1159                                         exit(1);
1160                                 }
1161                         } else {
1162                                 struct group *gr;
1163
1164                                 if (!(gr = getgrnam(optarg))) {
1165                                         printf("bad user name \"%s\"\n", optarg);
1166                                         exit(1);
1167                                 }
1168                                 gid = gr->gr_gid;
1169                                 endpwent();
1170                         }
1171                         break;
1172                 case 'u':
1173                         got_user = 1;
1174                         user_name = optarg;
1175                         break;
1176                 case 'd':
1177                         domain_name = optarg; /* BB fix this - currently ignored */
1178                         got_domain = 1;
1179                         break;
1180                 case 'p':
1181                         if(mountpassword == NULL)
1182                                 mountpassword = (char *)calloc(65,1);
1183                         if(mountpassword) {
1184                                 got_password = 1;
1185                                 strncpy(mountpassword,optarg,64);
1186                         }
1187                         break;
1188                 case 'S':
1189                         get_password_from_file(0 /* stdin */,NULL);
1190                         break;
1191                 case 't':
1192                         break;
1193                 default:
1194                         printf("unknown mount option %c\n",c);
1195                         mount_cifs_usage();
1196                         exit(1);
1197                 }
1198         }
1199
1200         if((argc < 3) || (dev_name == NULL) || (mountpoint == NULL)) {
1201                 mount_cifs_usage();
1202                 exit(1);
1203         }
1204
1205         if (getenv("PASSWD")) {
1206                 if(mountpassword == NULL)
1207                         mountpassword = (char *)calloc(65,1);
1208                 if(mountpassword) {
1209                         strncpy(mountpassword,getenv("PASSWD"),64);
1210                         got_password = 1;
1211                 }
1212         } else if (getenv("PASSWD_FD")) {
1213                 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
1214         } else if (getenv("PASSWD_FILE")) {
1215                 get_password_from_file(0, getenv("PASSWD_FILE"));
1216         }
1217
1218         if (orgoptions && parse_options(&orgoptions, &flags)) {
1219                 rc = -1;
1220                 goto mount_exit;
1221         }
1222         ipaddr = parse_server(&share_name);
1223         if((ipaddr == NULL) && (got_ip == 0)) {
1224                 printf("No ip address specified and hostname not found\n");
1225                 rc = -1;
1226                 goto mount_exit;
1227         }
1228         
1229         /* BB save off path and pop after mount returns? */
1230         resolved_path = (char *)malloc(PATH_MAX+1);
1231         if(resolved_path) {
1232                 /* Note that if we can not canonicalize the name, we get
1233                 another chance to see if it is valid when we chdir to it */
1234                 if (realpath(mountpoint, resolved_path)) {
1235                         mountpoint = resolved_path; 
1236                 }
1237         }
1238         if(chdir(mountpoint)) {
1239                 printf("mount error: can not change directory into mount target %s\n",mountpoint);
1240                 rc = -1;
1241                 goto mount_exit;
1242         }
1243
1244         if(stat (".", &statbuf)) {
1245                 printf("mount error: mount point %s does not exist\n",mountpoint);
1246                 rc = -1;
1247                 goto mount_exit;
1248         }
1249
1250         if (S_ISDIR(statbuf.st_mode) == 0) {
1251                 printf("mount error: mount point %s is not a directory\n",mountpoint);
1252                 rc = -1;
1253                 goto mount_exit;
1254         }
1255
1256         if((getuid() != 0) && (geteuid() == 0)) {
1257                 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
1258 #ifndef CIFS_ALLOW_USR_SUID
1259                         /* Do not allow user mounts to control suid flag
1260                         for mount unless explicitly built that way */
1261                         flags |= MS_NOSUID | MS_NODEV;
1262 #endif                                          
1263                 } else {
1264                         printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n"); 
1265                         return -1;
1266                 }
1267         }
1268
1269         if(got_user == 0) {
1270                 user_name = getusername();
1271                 got_user = 1;
1272         }
1273        
1274         if(got_password == 0) {
1275                 mountpassword = getpass("Password: "); /* BB obsolete */
1276                 got_password = 1;
1277         }
1278         /* FIXME launch daemon (handles dfs name resolution and credential change) 
1279            remember to clear parms and overwrite password field before launching */
1280 mount_retry:
1281         if(orgoptions) {
1282                 optlen = strlen(orgoptions);
1283                 orgoptlen = optlen;
1284         } else
1285                 optlen = 0;
1286         if(share_name)
1287                 optlen += strlen(share_name) + 4;
1288         else {
1289                 printf("No server share name specified\n");
1290                 printf("\nMounting the DFS root for server not implemented yet\n");
1291                 exit(1);
1292         }
1293         if(user_name)
1294                 optlen += strlen(user_name) + 6;
1295         if(ipaddr)
1296                 optlen += strlen(ipaddr) + 4;
1297         if(mountpassword)
1298                 optlen += strlen(mountpassword) + 6;
1299         if(options)
1300                 free(options);
1301         options_size = optlen + 10 + 64;
1302         options = (char *)malloc(options_size /* space for commas in password */ + 8 /* space for domain=  , domain name itself was counted as part of the length username string above */);
1303
1304         if(options == NULL) {
1305                 printf("Could not allocate memory for mount options\n");
1306                 return -1;
1307         }
1308
1309         options[0] = 0;
1310         strlcpy(options,"unc=",options_size);
1311         strlcat(options,share_name,options_size);
1312         /* scan backwards and reverse direction of slash */
1313         temp = strrchr(options, '/');
1314         if(temp > options + 6)
1315                 *temp = '\\';
1316         if(ipaddr) {
1317                 strlcat(options,",ip=",options_size);
1318                 strlcat(options,ipaddr,options_size);
1319         }
1320
1321         if(user_name) {
1322                 /* check for syntax like user=domain\user */
1323                 if(got_domain == 0)
1324                         domain_name = check_for_domain(&user_name);
1325                 strlcat(options,",user=",options_size);
1326                 strlcat(options,user_name,options_size);
1327         }
1328         if(retry == 0) {
1329                 if(domain_name) {
1330                         /* extra length accounted for in option string above */
1331                         strlcat(options,",domain=",options_size);
1332                         strlcat(options,domain_name,options_size);
1333                 }
1334         }
1335         if(mountpassword) {
1336                 /* Commas have to be doubled, or else they will
1337                 look like the parameter separator */
1338 /*              if(sep is not set)*/
1339                 if(retry == 0)
1340                         check_for_comma(&mountpassword);
1341                 strlcat(options,",pass=",options_size);
1342                 strlcat(options,mountpassword,options_size);
1343         }
1344
1345         strlcat(options,",ver=",options_size);
1346         strlcat(options,MOUNT_CIFS_VERSION_MAJOR,options_size);
1347
1348         if(orgoptions) {
1349                 strlcat(options,",",options_size);
1350                 strlcat(options,orgoptions,options_size);
1351         }
1352         if(prefixpath) {
1353                 strlcat(options,",prefixpath=",options_size);
1354                 strlcat(options,prefixpath,options_size); /* no need to cat the / */
1355         }
1356         if(verboseflag)
1357                 printf("\nmount.cifs kernel mount options %s \n",options);
1358
1359         /* convert all '\\' to '/' in share portion so that /proc/mounts looks pretty */
1360         replace_char(dev_name, '\\', '/', strlen(share_name));
1361
1362         if(mount(dev_name, mountpoint, "cifs", flags, options)) {
1363         /* remember to kill daemon on error */
1364                 switch (errno) {
1365                 case 0:
1366                         printf("mount failed but no error number set\n");
1367                         break;
1368                 case ENODEV:
1369                         printf("mount error: cifs filesystem not supported by the system\n");
1370                         break;
1371                 case ENXIO:
1372                         if(retry == 0) {
1373                                 retry = 1;
1374                                 if (uppercase_string(dev_name) &&
1375                                     uppercase_string(share_name) &&
1376                                     uppercase_string(prefixpath)) {
1377                                         printf("retrying with upper case share name\n");
1378                                         goto mount_retry;
1379                                 }
1380                         }
1381                 default:
1382                         printf("mount error %d = %s\n",errno,strerror(errno));
1383                 }
1384                 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
1385                 rc = -1;
1386                 goto mount_exit;
1387         } else {
1388                 pmntfile = setmntent(MOUNTED, "a+");
1389                 if(pmntfile) {
1390                         mountent.mnt_fsname = dev_name;
1391                         mountent.mnt_dir = mountpoint;
1392                         mountent.mnt_type = CONST_DISCARD(char *,"cifs");
1393                         mountent.mnt_opts = (char *)malloc(220);
1394                         if(mountent.mnt_opts) {
1395                                 char * mount_user = getusername();
1396                                 memset(mountent.mnt_opts,0,200);
1397                                 if(flags & MS_RDONLY)
1398                                         strlcat(mountent.mnt_opts,"ro",220);
1399                                 else
1400                                         strlcat(mountent.mnt_opts,"rw",220);
1401                                 if(flags & MS_MANDLOCK)
1402                                         strlcat(mountent.mnt_opts,",mand",220);
1403                                 if(flags & MS_NOEXEC)
1404                                         strlcat(mountent.mnt_opts,",noexec",220);
1405                                 if(flags & MS_NOSUID)
1406                                         strlcat(mountent.mnt_opts,",nosuid",220);
1407                                 if(flags & MS_NODEV)
1408                                         strlcat(mountent.mnt_opts,",nodev",220);
1409                                 if(flags & MS_SYNCHRONOUS)
1410                                         strlcat(mountent.mnt_opts,",synch",220);
1411                                 if(mount_user) {
1412                                         if(getuid() != 0) {
1413                                                 strlcat(mountent.mnt_opts,",user=",220);
1414                                                 strlcat(mountent.mnt_opts,mount_user,220);
1415                                         }
1416                                         /* free(mount_user); do not free static mem */
1417                                 }
1418                         }
1419                         mountent.mnt_freq = 0;
1420                         mountent.mnt_passno = 0;
1421                         rc = addmntent(pmntfile,&mountent);
1422                         endmntent(pmntfile);
1423                         if(mountent.mnt_opts)
1424                                 free(mountent.mnt_opts);
1425                 } else {
1426                     printf("could not update mount table\n");
1427                 }
1428         }
1429         rc = 0;
1430 mount_exit:
1431         if(mountpassword) {
1432                 int len = strlen(mountpassword);
1433                 memset(mountpassword,0,len);
1434                 free(mountpassword);
1435         }
1436
1437         if(options) {
1438                 memset(options,0,optlen);
1439                 free(options);
1440         }
1441
1442         if(orgoptions) {
1443                 memset(orgoptions,0,orgoptlen);
1444                 free(orgoptions);
1445         }
1446         if(resolved_path) {
1447                 free(resolved_path);
1448         }
1449
1450         free(share_name);
1451         return rc;
1452 }