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