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