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