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