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