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