9d2b44919571f0e7dd7bb697e41820bd47c752ef
[ira/wip.git] / source3 / 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 (!strncmp(value, "none", 4) ||
477                                     !strncmp(value, "krb5", 4))
478                                         got_password = 1;
479                         }
480                 } else if (strncmp(data, "ip", 2) == 0) {
481                         if (!value || !*value) {
482                                 printf("target ip address argument missing");
483                         } else if (strnlen(value, 35) < 35) {
484                                 if(verboseflag)
485                                         printf("ip address %s override specified\n",value);
486                                 got_ip = 1;
487                         } else {
488                                 printf("ip address too long\n");
489                                 return 1;
490                         }
491                 } else if ((strncmp(data, "unc", 3) == 0)
492                    || (strncmp(data, "target", 6) == 0)
493                    || (strncmp(data, "path", 4) == 0)) {
494                         if (!value || !*value) {
495                                 printf("invalid path to network resource\n");
496                                 return 1;  /* needs_arg; */
497                         } else if(strnlen(value,5) < 5) {
498                                 printf("UNC name too short");
499                         }
500
501                         if (strnlen(value, 300) < 300) {
502                                 got_unc = 1;
503                                 if (strncmp(value, "//", 2) == 0) {
504                                         if(got_unc)
505                                                 printf("unc name specified twice, ignoring second\n");
506                                         else
507                                                 got_unc = 1;
508                                 } else if (strncmp(value, "\\\\", 2) != 0) {                       
509                                         printf("UNC Path does not begin with // or \\\\ \n");
510                                         return 1;
511                                 } else {
512                                         if(got_unc)
513                                                 printf("unc name specified twice, ignoring second\n");
514                                         else
515                                                 got_unc = 1;
516                                 }
517                         } else {
518                                 printf("CIFS: UNC name too long\n");
519                                 return 1;
520                         }
521                 } else if ((strncmp(data, "dom" /* domain */, 3) == 0)
522                            || (strncmp(data, "workg", 5) == 0)) {
523                         /* note this allows for synonyms of "domain"
524                            such as "DOM" and "dom" and "workgroup"
525                            and "WORKGRP" etc. */
526                         if (!value || !*value) {
527                                 printf("CIFS: invalid domain name\n");
528                                 return 1;       /* needs_arg; */
529                         }
530                         if (strnlen(value, DOMAIN_SIZE+1) < DOMAIN_SIZE+1) {
531                                 got_domain = 1;
532                         } else {
533                                 printf("domain name too long\n");
534                                 return 1;
535                         }
536                 } else if (strncmp(data, "cred", 4) == 0) {
537                         if (value && *value) {
538                                 rc = open_cred_file(value);
539                                 if(rc) {
540                                         printf("error %d (%s) opening credential file %s\n",
541                                                 rc, strerror(rc), value);
542                                         return 1;
543                                 }
544                         } else {
545                                 printf("invalid credential file name specified\n");
546                                 return 1;
547                         }
548                 } else if (strncmp(data, "uid", 3) == 0) {
549                         if (value && *value) {
550                                 got_uid = 1;
551                                 if (!isdigit(*value)) {
552                                         struct passwd *pw;
553
554                                         if (!(pw = getpwnam(value))) {
555                                                 printf("bad user name \"%s\"\n", value);
556                                                 exit(1);
557                                         }
558                                         snprintf(user, sizeof(user), "%u", pw->pw_uid);
559                                 } else {
560                                         strlcpy(user,value,sizeof(user));
561                                 }
562                         }
563                         goto nocopy;
564                 } else if (strncmp(data, "gid", 3) == 0) {
565                         if (value && *value) {
566                                 got_gid = 1;
567                                 if (!isdigit(*value)) {
568                                         struct group *gr;
569
570                                         if (!(gr = getgrnam(value))) {
571                                                 printf("bad group name \"%s\"\n", value);
572                                                 exit(1);
573                                         }
574                                         snprintf(group, sizeof(group), "%u", gr->gr_gid);
575                                 } else {
576                                         strlcpy(group,value,sizeof(group));
577                                 }
578                         }
579                         goto nocopy;
580        /* fmask and dmask synonyms for people used to smbfs syntax */
581                 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
582                         if (!value || !*value) {
583                                 printf ("Option '%s' requires a numerical argument\n", data);
584                                 return 1;
585                         }
586
587                         if (value[0] != '0') {
588                                 printf ("WARNING: '%s' not expressed in octal.\n", data);
589                         }
590
591                         if (strcmp (data, "fmask") == 0) {
592                                 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
593                                 data = "file_mode"; /* BB fix this */
594                         }
595                 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
596                         if (!value || !*value) {
597                                 printf ("Option '%s' requires a numerical argument\n", data);
598                                 return 1;
599                         }
600
601                         if (value[0] != '0') {
602                                 printf ("WARNING: '%s' not expressed in octal.\n", data);
603                         }
604
605                         if (strcmp (data, "dmask") == 0) {
606                                 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
607                                 data = "dir_mode";
608                         }
609                         /* the following eight mount options should be
610                         stripped out from what is passed into the kernel
611                         since these eight options are best passed as the
612                         mount flags rather than redundantly to the kernel 
613                         and could generate spurious warnings depending on the
614                         level of the corresponding cifs vfs kernel code */
615                 } else if (strncmp(data, "nosuid", 6) == 0) {
616                         *filesys_flags |= MS_NOSUID;
617                 } else if (strncmp(data, "suid", 4) == 0) {
618                         *filesys_flags &= ~MS_NOSUID;
619                 } else if (strncmp(data, "nodev", 5) == 0) {
620                         *filesys_flags |= MS_NODEV;
621                 } else if ((strncmp(data, "nobrl", 5) == 0) || 
622                            (strncmp(data, "nolock", 6) == 0)) {
623                         *filesys_flags &= ~MS_MANDLOCK;
624                 } else if (strncmp(data, "dev", 3) == 0) {
625                         *filesys_flags &= ~MS_NODEV;
626                 } else if (strncmp(data, "noexec", 6) == 0) {
627                         *filesys_flags |= MS_NOEXEC;
628                 } else if (strncmp(data, "exec", 4) == 0) {
629                         *filesys_flags &= ~MS_NOEXEC;
630                 } else if (strncmp(data, "guest", 5) == 0) {
631                         got_password=1;
632                 } else if (strncmp(data, "ro", 2) == 0) {
633                         *filesys_flags |= MS_RDONLY;
634                 } else if (strncmp(data, "rw", 2) == 0) {
635                         *filesys_flags &= ~MS_RDONLY;
636                 } else if (strncmp(data, "remount", 7) == 0) {
637                         *filesys_flags |= MS_REMOUNT;
638                 } /* else if (strnicmp(data, "port", 4) == 0) {
639                         if (value && *value) {
640                                 vol->port =
641                                         simple_strtoul(value, &value, 0);
642                         }
643                 } else if (strnicmp(data, "rsize", 5) == 0) {
644                         if (value && *value) {
645                                 vol->rsize =
646                                         simple_strtoul(value, &value, 0);
647                         }
648                 } else if (strnicmp(data, "wsize", 5) == 0) {
649                         if (value && *value) {
650                                 vol->wsize =
651                                         simple_strtoul(value, &value, 0);
652                         }
653                 } else if (strnicmp(data, "version", 3) == 0) {
654                 } else {
655                         printf("CIFS: Unknown mount option %s\n",data);
656                 } */ /* nothing to do on those four mount options above.
657                         Just pass to kernel and ignore them here */
658
659                 /* Copy (possibly modified) option to out */
660                 word_len = strlen(data);
661                 if (value)
662                         word_len += 1 + strlen(value);
663
664                 out = (char *)realloc(out, out_len + word_len + 2);
665                 if (out == NULL) {
666                         perror("malloc");
667                         exit(1);
668                 }
669
670                 if (out_len) {
671                         strlcat(out, ",", out_len + word_len + 2);
672                         out_len++;
673                 }
674
675                 if (value)
676                         snprintf(out + out_len, word_len + 1, "%s=%s", data, value);
677                 else
678                         snprintf(out + out_len, word_len + 1, "%s", data);
679                 out_len = strlen(out);
680
681 nocopy:
682                 data = next_keyword;
683         }
684
685         /* special-case the uid and gid */
686         if (got_uid) {
687                 word_len = strlen(user);
688
689                 out = (char *)realloc(out, out_len + word_len + 6);
690                 if (out == NULL) {
691                         perror("malloc");
692                         exit(1);
693                 }
694
695                 if (out_len) {
696                         strlcat(out, ",", out_len + word_len + 6);
697                         out_len++;
698                 }
699                 snprintf(out + out_len, word_len + 5, "uid=%s", user);
700                 out_len = strlen(out);
701         }
702         if (got_gid) {
703                 word_len = strlen(group);
704
705                 out = (char *)realloc(out, out_len + 1 + word_len + 6);
706                 if (out == NULL) {
707                 perror("malloc");
708                         exit(1);
709                 }
710
711                 if (out_len) {
712                         strlcat(out, ",", out_len + word_len + 6);
713                         out_len++;
714                 }
715                 snprintf(out + out_len, word_len + 5, "gid=%s", group);
716                 out_len = strlen(out);
717         }
718
719         SAFE_FREE(*optionsp);
720         *optionsp = out;
721         return 0;
722 }
723
724 /* replace all (one or more) commas with double commas */
725 static void check_for_comma(char ** ppasswrd)
726 {
727         char *new_pass_buf;
728         char *pass;
729         int i,j;
730         int number_of_commas = 0;
731         int len;
732
733         if(ppasswrd == NULL)
734                 return;
735         else 
736                 (pass = *ppasswrd);
737
738         len = strlen(pass);
739
740         for(i=0;i<len;i++)  {
741                 if(pass[i] == ',')
742                         number_of_commas++;
743         }
744
745         if(number_of_commas == 0)
746                 return;
747         if(number_of_commas > MOUNT_PASSWD_SIZE) {
748                 /* would otherwise overflow the mount options buffer */
749                 printf("\nInvalid password. Password contains too many commas.\n");
750                 return;
751         }
752
753         new_pass_buf = (char *)malloc(len+number_of_commas+1);
754         if(new_pass_buf == NULL)
755                 return;
756
757         for(i=0,j=0;i<len;i++,j++) {
758                 new_pass_buf[j] = pass[i];
759                 if(pass[i] == ',') {
760                         j++;
761                         new_pass_buf[j] = pass[i];
762                 }
763         }
764         new_pass_buf[len+number_of_commas] = 0;
765
766         SAFE_FREE(*ppasswrd);
767         *ppasswrd = new_pass_buf;
768         
769         return;
770 }
771
772 /* Usernames can not have backslash in them and we use
773    [BB check if usernames can have forward slash in them BB] 
774    backslash as domain\user separator character
775 */
776 static char * check_for_domain(char **ppuser)
777 {
778         char * original_string;
779         char * usernm;
780         char * domainnm;
781         int    original_len;
782         int    len;
783         int    i;
784
785         if(ppuser == NULL)
786                 return NULL;
787
788         original_string = *ppuser;
789
790         if (original_string == NULL)
791                 return NULL;
792         
793         original_len = strlen(original_string);
794
795         usernm = strchr(*ppuser,'/');
796         if (usernm == NULL) {
797                 usernm = strchr(*ppuser,'\\');
798                 if (usernm == NULL)
799                         return NULL;
800         }
801
802         if(got_domain) {
803                 printf("Domain name specified twice. Username probably malformed\n");
804                 return NULL;
805         }
806
807         usernm[0] = 0;
808         domainnm = *ppuser;
809         if (domainnm[0] != 0) {
810                 got_domain = 1;
811         } else {
812                 printf("null domain\n");
813         }
814         len = strlen(domainnm);
815         /* reset domainm to new buffer, and copy
816         domain name into it */
817         domainnm = (char *)malloc(len+1);
818         if(domainnm == NULL)
819                 return NULL;
820
821         strlcpy(domainnm,*ppuser,len+1);
822
823 /*      move_string(*ppuser, usernm+1) */
824         len = strlen(usernm+1);
825
826         if(len >= original_len) {
827                 /* should not happen */
828                 return domainnm;
829         }
830
831         for(i=0;i<original_len;i++) {
832                 if(i<len)
833                         original_string[i] = usernm[i+1];
834                 else /* stuff with commas to remove last parm */
835                         original_string[i] = ',';
836         }
837
838         /* BB add check for more than one slash? 
839           strchr(*ppuser,'/');
840           strchr(*ppuser,'\\') 
841         */
842         
843         return domainnm;
844 }
845
846 /* replace all occurances of "from" in a string with "to" */
847 static void replace_char(char *string, char from, char to, int maxlen)
848 {
849         char *lastchar = string + maxlen;
850         while (string) {
851                 string = strchr(string, from);
852                 if (string) {
853                         *string = to;
854                         if (string >= lastchar)
855                                 return;
856                 }
857         }
858 }
859
860 /* Note that caller frees the returned buffer if necessary */
861 static char * parse_server(char ** punc_name)
862 {
863         char * unc_name = *punc_name;
864         int length = strnlen(unc_name, MAX_UNC_LEN);
865         char * share;
866         char * ipaddress_string = NULL;
867         struct hostent * host_entry = NULL;
868         struct in_addr server_ipaddr;
869
870         if(length > (MAX_UNC_LEN - 1)) {
871                 printf("mount error: UNC name too long");
872                 return NULL;
873         }
874         if (strncasecmp("cifs://",unc_name,7) == 0)
875                 return parse_cifs_url(unc_name+7);
876         if (strncasecmp("smb://",unc_name,6) == 0) {
877                 return parse_cifs_url(unc_name+6);
878         }
879
880         if(length < 3) {
881                 /* BB add code to find DFS root here */
882                 printf("\nMounting the DFS root for domain not implemented yet\n");
883                 return NULL;
884         } else {
885                 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
886                         /* check for nfs syntax ie server:share */
887                         share = strchr(unc_name,':');
888                         if(share) {
889                                 *punc_name = (char *)malloc(length+3);
890                                 if(*punc_name == NULL) {
891                                         /* put the original string back  if 
892                                            no memory left */
893                                         *punc_name = unc_name;
894                                         return NULL;
895                                 }
896                                 *share = '/';
897                                 strlcpy((*punc_name)+2,unc_name,length+1);
898                                 SAFE_FREE(unc_name);
899                                 unc_name = *punc_name;
900                                 unc_name[length+2] = 0;
901                                 goto continue_unc_parsing;
902                         } else {
903                                 printf("mount error: improperly formatted UNC name.");
904                                 printf(" %s does not begin with \\\\ or //\n",unc_name);
905                                 return NULL;
906                         }
907                 } else {
908 continue_unc_parsing:
909                         unc_name[0] = '/';
910                         unc_name[1] = '/';
911                         unc_name += 2;
912
913                         /* allow for either delimiter between host and sharename */
914                         if ((share = strpbrk(unc_name, "/\\"))) {
915                                 *share = 0;  /* temporarily terminate the string */
916                                 share += 1;
917                                 if(got_ip == 0) {
918                                         host_entry = gethostbyname(unc_name);
919                                 }
920                                 *(share - 1) = '/'; /* put delimiter back */
921
922                                 /* we don't convert the prefixpath delimiters since '\\' is a valid char in posix paths */
923                                 if ((prefixpath = strpbrk(share, "/\\"))) {
924                                         *prefixpath = 0;  /* permanently terminate the string */
925                                         if (!strlen(++prefixpath))
926                                                 prefixpath = NULL; /* this needs to be done explicitly */
927                                 }
928                                 if(got_ip) {
929                                         if(verboseflag)
930                                                 printf("ip address specified explicitly\n");
931                                         return NULL;
932                                 }
933                                 if(host_entry == NULL) {
934                                         printf("mount error: could not find target server. TCP name %s not found\n", unc_name);
935                                         return NULL;
936                                 } else {
937                                         /* BB should we pass an alternate version of the share name as Unicode */
938                                         /* BB what about ipv6? BB */
939                                         /* BB add retries with alternate servers in list */
940
941                                         memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
942
943                                         ipaddress_string = inet_ntoa(server_ipaddr);                                                                                     
944                                         if(ipaddress_string == NULL) {
945                                                 printf("mount error: could not get valid ip address for target server\n");
946                                                 return NULL;
947                                         }
948                                         return ipaddress_string; 
949                                 }
950                         } else {
951                                 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
952                                 printf("Mounting the DFS root for a particular server not implemented yet\n");
953                                 return NULL;
954                         }
955                 }
956         }
957 }
958
959 static struct option longopts[] = {
960         { "all", 0, NULL, 'a' },
961         { "help",0, NULL, 'h' },
962         { "move",0, NULL, 'm' },
963         { "bind",0, NULL, 'b' },
964         { "read-only", 0, NULL, 'r' },
965         { "ro", 0, NULL, 'r' },
966         { "verbose", 0, NULL, 'v' },
967         { "version", 0, NULL, 'V' },
968         { "read-write", 0, NULL, 'w' },
969         { "rw", 0, NULL, 'w' },
970         { "options", 1, NULL, 'o' },
971         { "type", 1, NULL, 't' },
972         { "rsize",1, NULL, 'R' },
973         { "wsize",1, NULL, 'W' },
974         { "uid", 1, NULL, '1'},
975         { "gid", 1, NULL, '2'},
976         { "user",1,NULL,'u'},
977         { "username",1,NULL,'u'},
978         { "dom",1,NULL,'d'},
979         { "domain",1,NULL,'d'},
980         { "password",1,NULL,'p'},
981         { "pass",1,NULL,'p'},
982         { "credentials",1,NULL,'c'},
983         { "port",1,NULL,'P'},
984         /* { "uuid",1,NULL,'U'}, */ /* BB unimplemented */
985         { NULL, 0, NULL, 0 }
986 };
987
988 /* convert a string to uppercase. return false if the string
989  * wasn't ASCII or was a NULL ptr */
990 static int
991 uppercase_string(char *string)
992 {
993         if (!string)
994                 return 0;
995
996         while (*string) {
997                 /* check for unicode */
998                 if ((unsigned char) string[0] & 0x80)
999                         return 0;
1000                 *string = toupper((unsigned char) *string);
1001                 string++;
1002         }
1003
1004         return 1;
1005 }
1006
1007 int main(int argc, char ** argv)
1008 {
1009         int c;
1010         int flags = MS_MANDLOCK; /* no need to set legacy MS_MGC_VAL */
1011         char * orgoptions = NULL;
1012         char * share_name = NULL;
1013         char * ipaddr = NULL;
1014         char * uuid = NULL;
1015         char * mountpoint = NULL;
1016         char * options = NULL;
1017         char * resolved_path = NULL;
1018         char * temp;
1019         char * dev_name;
1020         int rc;
1021         int rsize = 0;
1022         int wsize = 0;
1023         int nomtab = 0;
1024         int uid = 0;
1025         int gid = 0;
1026         int optlen = 0;
1027         int orgoptlen = 0;
1028         size_t options_size = 0;
1029         int retry = 0; /* set when we have to retry mount with uppercase */
1030         struct stat statbuf;
1031         struct utsname sysinfo;
1032         struct mntent mountent;
1033         FILE * pmntfile;
1034
1035         /* setlocale(LC_ALL, "");
1036         bindtextdomain(PACKAGE, LOCALEDIR);
1037         textdomain(PACKAGE); */
1038
1039         if(argc && argv) {
1040                 thisprogram = argv[0];
1041         } else {
1042                 mount_cifs_usage();
1043                 exit(1);
1044         }
1045
1046         if(thisprogram == NULL)
1047                 thisprogram = "mount.cifs";
1048
1049         uname(&sysinfo);
1050         /* BB add workstation name and domain and pass down */
1051
1052 /* #ifdef _GNU_SOURCE
1053         printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
1054 #endif */
1055         if(argc > 2) {
1056                 dev_name = argv[1];
1057                 share_name = strndup(argv[1], MAX_UNC_LEN);
1058                 if (share_name == NULL) {
1059                         fprintf(stderr, "%s: %s", argv[0], strerror(ENOMEM));
1060                         exit(1);
1061                 }
1062                 mountpoint = argv[2];
1063         } else {
1064                 mount_cifs_usage();
1065                 exit(1);
1066         }
1067
1068         /* add sharename in opts string as unc= parm */
1069
1070         while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsSU:vVwt:",
1071                          longopts, NULL)) != -1) {
1072                 switch (c) {
1073 /* No code to do the following  options yet */
1074 /*      case 'l':
1075                 list_with_volumelabel = 1;
1076                 break;
1077         case 'L':
1078                 volumelabel = optarg;
1079                 break; */
1080 /*      case 'a':              
1081                 ++mount_all;
1082                 break; */
1083
1084                 case '?':
1085                 case 'h':        /* help */
1086                         mount_cifs_usage ();
1087                         exit(1);
1088                 case 'n':
1089                     ++nomtab;
1090                     break;
1091                 case 'b':
1092 #ifdef MS_BIND
1093                         flags |= MS_BIND;
1094 #else
1095                         fprintf(stderr,
1096                                 "option 'b' (MS_BIND) not supported\n");
1097 #endif
1098                         break;
1099                 case 'm':
1100 #ifdef MS_MOVE                
1101                         flags |= MS_MOVE;
1102 #else
1103                         fprintf(stderr,
1104                                 "option 'm' (MS_MOVE) not supported\n");
1105 #endif
1106                         break;
1107                 case 'o':
1108                         orgoptions = strdup(optarg);
1109                     break;
1110                 case 'r':  /* mount readonly */
1111                         flags |= MS_RDONLY;
1112                         break;
1113                 case 'U':
1114                         uuid = optarg;
1115                         break;
1116                 case 'v':
1117                         ++verboseflag;
1118                         break;
1119                 case 'V':          
1120                         printf ("mount.cifs version: %s.%s%s\n",
1121                         MOUNT_CIFS_VERSION_MAJOR,
1122                         MOUNT_CIFS_VERSION_MINOR,
1123                         MOUNT_CIFS_VENDOR_SUFFIX);
1124                         exit (0);
1125                 case 'w':
1126                         flags &= ~MS_RDONLY;
1127                         break;
1128                 case 'R':
1129                         rsize = atoi(optarg) ;
1130                         break;
1131                 case 'W':
1132                         wsize = atoi(optarg);
1133                         break;
1134                 case '1':
1135                         if (isdigit(*optarg)) {
1136                                 char *ep;
1137
1138                                 uid = strtoul(optarg, &ep, 10);
1139                                 if (*ep) {
1140                                         printf("bad uid value \"%s\"\n", optarg);
1141                                         exit(1);
1142                                 }
1143                         } else {
1144                                 struct passwd *pw;
1145
1146                                 if (!(pw = getpwnam(optarg))) {
1147                                         printf("bad user name \"%s\"\n", optarg);
1148                                         exit(1);
1149                                 }
1150                                 uid = pw->pw_uid;
1151                                 endpwent();
1152                         }
1153                         break;
1154                 case '2':
1155                         if (isdigit(*optarg)) {
1156                                 char *ep;
1157
1158                                 gid = strtoul(optarg, &ep, 10);
1159                                 if (*ep) {
1160                                         printf("bad gid value \"%s\"\n", optarg);
1161                                         exit(1);
1162                                 }
1163                         } else {
1164                                 struct group *gr;
1165
1166                                 if (!(gr = getgrnam(optarg))) {
1167                                         printf("bad user name \"%s\"\n", optarg);
1168                                         exit(1);
1169                                 }
1170                                 gid = gr->gr_gid;
1171                                 endpwent();
1172                         }
1173                         break;
1174                 case 'u':
1175                         got_user = 1;
1176                         user_name = optarg;
1177                         break;
1178                 case 'd':
1179                         domain_name = optarg; /* BB fix this - currently ignored */
1180                         got_domain = 1;
1181                         break;
1182                 case 'p':
1183                         if(mountpassword == NULL)
1184                                 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
1185                         if(mountpassword) {
1186                                 got_password = 1;
1187                                 strlcpy(mountpassword,optarg,MOUNT_PASSWD_SIZE+1);
1188                         }
1189                         break;
1190                 case 'S':
1191                         get_password_from_file(0 /* stdin */,NULL);
1192                         break;
1193                 case 't':
1194                         break;
1195                 default:
1196                         printf("unknown mount option %c\n",c);
1197                         mount_cifs_usage();
1198                         exit(1);
1199                 }
1200         }
1201
1202         if((argc < 3) || (dev_name == NULL) || (mountpoint == NULL)) {
1203                 mount_cifs_usage();
1204                 exit(1);
1205         }
1206
1207         if (getenv("PASSWD")) {
1208                 if(mountpassword == NULL)
1209                         mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
1210                 if(mountpassword) {
1211                         strlcpy(mountpassword,getenv("PASSWD"),MOUNT_PASSWD_SIZE+1);
1212                         got_password = 1;
1213                 }
1214         } else if (getenv("PASSWD_FD")) {
1215                 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
1216         } else if (getenv("PASSWD_FILE")) {
1217                 get_password_from_file(0, getenv("PASSWD_FILE"));
1218         }
1219
1220         if (orgoptions && parse_options(&orgoptions, &flags)) {
1221                 rc = -1;
1222                 goto mount_exit;
1223         }
1224         ipaddr = parse_server(&share_name);
1225         if((ipaddr == NULL) && (got_ip == 0)) {
1226                 printf("No ip address specified and hostname not found\n");
1227                 rc = -1;
1228                 goto mount_exit;
1229         }
1230         
1231         /* BB save off path and pop after mount returns? */
1232         resolved_path = (char *)malloc(PATH_MAX+1);
1233         if(resolved_path) {
1234                 /* Note that if we can not canonicalize the name, we get
1235                 another chance to see if it is valid when we chdir to it */
1236                 if (realpath(mountpoint, resolved_path)) {
1237                         mountpoint = resolved_path; 
1238                 }
1239         }
1240         if(chdir(mountpoint)) {
1241                 printf("mount error: can not change directory into mount target %s\n",mountpoint);
1242                 rc = -1;
1243                 goto mount_exit;
1244         }
1245
1246         if(stat (".", &statbuf)) {
1247                 printf("mount error: mount point %s does not exist\n",mountpoint);
1248                 rc = -1;
1249                 goto mount_exit;
1250         }
1251
1252         if (S_ISDIR(statbuf.st_mode) == 0) {
1253                 printf("mount error: mount point %s is not a directory\n",mountpoint);
1254                 rc = -1;
1255                 goto mount_exit;
1256         }
1257
1258         if((getuid() != 0) && (geteuid() == 0)) {
1259                 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
1260 #ifndef CIFS_ALLOW_USR_SUID
1261                         /* Do not allow user mounts to control suid flag
1262                         for mount unless explicitly built that way */
1263                         flags |= MS_NOSUID | MS_NODEV;
1264 #endif                                          
1265                 } else {
1266                         printf("mount error: permission denied or not superuser and mount.cifs not installed SUID\n"); 
1267                         return -1;
1268                 }
1269         }
1270
1271         if(got_user == 0) {
1272                 user_name = getusername();
1273                 got_user = 1;
1274         }
1275        
1276         if(got_password == 0) {
1277                 char *tmp_pass = getpass("Password: "); /* BB obsolete sys call but
1278                                                            no good replacement yet. */
1279                 mountpassword = (char *)calloc(MOUNT_PASSWD_SIZE+1,1);
1280                 if (!tmp_pass || !mountpassword) {
1281                         printf("Password not entered, exiting\n");
1282                         return -1;
1283                 }
1284                 strlcpy(mountpassword, tmp_pass, MOUNT_PASSWD_SIZE+1);
1285                 got_password = 1;
1286         }
1287         /* FIXME launch daemon (handles dfs name resolution and credential change) 
1288            remember to clear parms and overwrite password field before launching */
1289 mount_retry:
1290         if(orgoptions) {
1291                 optlen = strlen(orgoptions);
1292                 orgoptlen = optlen;
1293         } else
1294                 optlen = 0;
1295         if(share_name)
1296                 optlen += strlen(share_name) + 4;
1297         else {
1298                 printf("No server share name specified\n");
1299                 printf("\nMounting the DFS root for server not implemented yet\n");
1300                 exit(1);
1301         }
1302         if(user_name)
1303                 optlen += strlen(user_name) + 6;
1304         if(ipaddr)
1305                 optlen += strlen(ipaddr) + 4;
1306         if(mountpassword)
1307                 optlen += strlen(mountpassword) + 6;
1308         SAFE_FREE(options);
1309         options_size = optlen + 10 + DOMAIN_SIZE;
1310         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 */);
1311
1312         if(options == NULL) {
1313                 printf("Could not allocate memory for mount options\n");
1314                 return -1;
1315         }
1316
1317         options[0] = 0;
1318         strlcpy(options,"unc=",options_size);
1319         strlcat(options,share_name,options_size);
1320         /* scan backwards and reverse direction of slash */
1321         temp = strrchr(options, '/');
1322         if(temp > options + 6)
1323                 *temp = '\\';
1324         if(ipaddr) {
1325                 strlcat(options,",ip=",options_size);
1326                 strlcat(options,ipaddr,options_size);
1327         }
1328
1329         if(user_name) {
1330                 /* check for syntax like user=domain\user */
1331                 if(got_domain == 0)
1332                         domain_name = check_for_domain(&user_name);
1333                 strlcat(options,",user=",options_size);
1334                 strlcat(options,user_name,options_size);
1335         }
1336         if(retry == 0) {
1337                 if(domain_name) {
1338                         /* extra length accounted for in option string above */
1339                         strlcat(options,",domain=",options_size);
1340                         strlcat(options,domain_name,options_size);
1341                 }
1342         }
1343         if(mountpassword) {
1344                 /* Commas have to be doubled, or else they will
1345                 look like the parameter separator */
1346 /*              if(sep is not set)*/
1347                 if(retry == 0)
1348                         check_for_comma(&mountpassword);
1349                 strlcat(options,",pass=",options_size);
1350                 strlcat(options,mountpassword,options_size);
1351         }
1352
1353         strlcat(options,",ver=",options_size);
1354         strlcat(options,MOUNT_CIFS_VERSION_MAJOR,options_size);
1355
1356         if(orgoptions) {
1357                 strlcat(options,",",options_size);
1358                 strlcat(options,orgoptions,options_size);
1359         }
1360         if(prefixpath) {
1361                 strlcat(options,",prefixpath=",options_size);
1362                 strlcat(options,prefixpath,options_size); /* no need to cat the / */
1363         }
1364         if(verboseflag)
1365                 printf("\nmount.cifs kernel mount options %s \n",options);
1366
1367         /* convert all '\\' to '/' in share portion so that /proc/mounts looks pretty */
1368         replace_char(dev_name, '\\', '/', strlen(share_name));
1369
1370         if(mount(dev_name, mountpoint, "cifs", flags, options)) {
1371         /* remember to kill daemon on error */
1372                 switch (errno) {
1373                 case 0:
1374                         printf("mount failed but no error number set\n");
1375                         break;
1376                 case ENODEV:
1377                         printf("mount error: cifs filesystem not supported by the system\n");
1378                         break;
1379                 case ENXIO:
1380                         if(retry == 0) {
1381                                 retry = 1;
1382                                 if (uppercase_string(dev_name) &&
1383                                     uppercase_string(share_name) &&
1384                                     uppercase_string(prefixpath)) {
1385                                         printf("retrying with upper case share name\n");
1386                                         goto mount_retry;
1387                                 }
1388                         }
1389                 default:
1390                         printf("mount error %d = %s\n",errno,strerror(errno));
1391                 }
1392                 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
1393                 rc = -1;
1394                 goto mount_exit;
1395         } else {
1396                 pmntfile = setmntent(MOUNTED, "a+");
1397                 if(pmntfile) {
1398                         mountent.mnt_fsname = dev_name;
1399                         mountent.mnt_dir = mountpoint;
1400                         mountent.mnt_type = CONST_DISCARD(char *,"cifs");
1401                         mountent.mnt_opts = (char *)malloc(220);
1402                         if(mountent.mnt_opts) {
1403                                 char * mount_user = getusername();
1404                                 memset(mountent.mnt_opts,0,200);
1405                                 if(flags & MS_RDONLY)
1406                                         strlcat(mountent.mnt_opts,"ro",220);
1407                                 else
1408                                         strlcat(mountent.mnt_opts,"rw",220);
1409                                 if(flags & MS_MANDLOCK)
1410                                         strlcat(mountent.mnt_opts,",mand",220);
1411                                 if(flags & MS_NOEXEC)
1412                                         strlcat(mountent.mnt_opts,",noexec",220);
1413                                 if(flags & MS_NOSUID)
1414                                         strlcat(mountent.mnt_opts,",nosuid",220);
1415                                 if(flags & MS_NODEV)
1416                                         strlcat(mountent.mnt_opts,",nodev",220);
1417                                 if(flags & MS_SYNCHRONOUS)
1418                                         strlcat(mountent.mnt_opts,",synch",220);
1419                                 if(mount_user) {
1420                                         if(getuid() != 0) {
1421                                                 strlcat(mountent.mnt_opts,",user=",220);
1422                                                 strlcat(mountent.mnt_opts,mount_user,220);
1423                                         }
1424                                         /* free(mount_user); do not free static mem */
1425                                 }
1426                         }
1427                         mountent.mnt_freq = 0;
1428                         mountent.mnt_passno = 0;
1429                         rc = addmntent(pmntfile,&mountent);
1430                         endmntent(pmntfile);
1431                         SAFE_FREE(mountent.mnt_opts);
1432                 } else {
1433                     printf("could not update mount table\n");
1434                 }
1435         }
1436         rc = 0;
1437 mount_exit:
1438         if(mountpassword) {
1439                 int len = strlen(mountpassword);
1440                 memset(mountpassword,0,len);
1441                 SAFE_FREE(mountpassword);
1442         }
1443
1444         SAFE_FREE(options);
1445         SAFE_FREE(orgoptions);
1446         SAFE_FREE(resolved_path);
1447         SAFE_FREE(share_name);
1448         return rc;
1449 }