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