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