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