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