cifs mount helper merge
[sfrench/samba-autobuild/.git] / source3 / client / mount.cifs.c
1 /* 
2    Mount helper utility for Linux CIFS VFS (virtual filesystem) client
3    Copyright (C) 2003 Steve French  (sfrench@us.ibm.com)
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9    
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14    
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
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 <sys/types.h>
28 #include <sys/mount.h>
29 #include <sys/stat.h>
30 #include <sys/utsname.h>
31 #include <sys/socket.h>
32 #include <arpa/inet.h>
33 #include <getopt.h>
34 #include <errno.h>
35 #include <netdb.h>
36 #include <string.h>
37 #include <mntent.h>
38 #include <fcntl.h>
39
40 #define MOUNT_CIFS_VERSION_MAJOR "1"
41 #define MOUNT_CIFS_VERSION_MINOR "0"
42
43 #ifndef MOUNT_CIFS_VENDOR_SUFFIX
44 #define MOUNT_CIFS_VENDOR_SUFFIX ""
45 #endif
46
47 char * thisprogram;
48 int verboseflag = 0;
49 static int got_password = 0;
50 static int got_user = 0;
51 static int got_domain = 0;
52 static int got_ip = 0;
53 static int got_unc = 0;
54 static int got_uid = 0;
55 static int got_gid = 0;
56 static char * user_name = NULL;
57 char * mountpassword = NULL;
58
59
60 /* BB finish BB
61
62         cifs_umount
63         open nofollow - avoid symlink exposure? 
64         get owner of dir see if matches self or if root
65         call system(umount argv) etc.
66                 
67 BB end finish BB */
68
69 static void mount_cifs_usage(void)
70 {
71         printf("\nUsage:  %s <remotetarget> <dir> -o <options>\n", thisprogram);
72         printf("\nMount the remote target, specified as a UNC name,");
73         printf(" to a local directory.\n");
74         if(mountpassword) {
75                 memset(mountpassword,0,64);
76                 free(mountpassword);
77         }
78         exit(1);
79 }
80
81 /* caller frees username if necessary */
82 static char * getusername(void) {
83         char *username = NULL;
84         struct passwd *password = getpwuid(getuid());
85
86         if (password) {
87                 username = password->pw_name;
88         }
89         return username;
90 }
91
92 char * parse_cifs_url(char * unc_name)
93 {
94         printf("\ncifs url %s\n",unc_name);
95         return NULL;
96 }
97
98 static int open_cred_file(char * file_name)
99 {
100         char * line_buf;
101         char * temp_val;
102         FILE * fs;
103         int i, length;
104         fs = fopen(file_name,"r");
105         if(fs == NULL)
106                 return errno;
107         line_buf = malloc(4096);
108         if(line_buf == NULL)
109                 return -ENOMEM;
110
111         while(fgets(line_buf,4096,fs)) {
112                 /* parse line from credential file */
113
114                 /* eat leading white space */
115                 for(i=0;i<4096;i++) {
116                         if(line_buf[i] == '\0')
117                                 break;
118                         else if((line_buf[i] != ' ') && (line_buf[i] != '\t'))
119                                 break;
120                         line_buf++;
121                 }
122
123                 if (strncasecmp("username",line_buf,8) == 0) {
124                         temp_val = strchr(line_buf + i,'=');
125                         if(temp_val) {
126                                 /* go past equals sign */
127                                 temp_val++;
128                                 length = strlen(temp_val);
129                                 if(length > 4086) {
130                                         printf("cifs.mount failed due to malformed username in credentials file");
131                                         memset(line_buf,0,4096);
132                                         if(mountpassword) {
133                                                 memset(mountpassword,0,64);
134                                         }
135                                         exit(1);
136                                 } else {
137                                         got_user = 1;
138                                         user_name = calloc(1 + length,1);
139                                         /* BB adding free of user_name string before exit,
140                                                 not really necessary but would be cleaner */
141                                         strncpy(user_name,temp_val, length);
142                                 }
143                         }
144                 } else if (strncasecmp("password",line_buf,8) == 0) {
145                         temp_val = strchr(line_buf+i,'=');
146                         if(temp_val) {
147                                 /* go past equals sign */
148                                 temp_val++;
149                                 length = strlen(temp_val);
150                                 if(length > 64) {
151                                         printf("cifs.mount failed: password in credentials file too long\n");
152                                         memset(line_buf,0, 4096);
153                                         if(mountpassword) {
154                                                 memset(mountpassword,0,64);
155                                         }
156                                         exit(1);
157                                 } else {
158                                         if(mountpassword == NULL) {
159                                                 mountpassword = calloc(65,1);
160                                         }
161                                         if(mountpassword) {
162                                                 strncpy(mountpassword,temp_val,64);
163                                                 got_password = 1;
164                                         }
165                                 }
166                         }
167                 }
168         }
169         fclose(fs);
170         if(line_buf) {
171                 memset(line_buf,0,4096);
172                 free(line_buf);
173         }
174         return 0;
175 }
176
177 static int get_password_from_file(int file_descript, char * filename)
178 {
179         int rc = 0;
180         int i;
181         char c;
182
183         if(mountpassword == NULL)
184                 mountpassword = calloc(65,1);
185         else 
186                 memset(mountpassword, 0, 64);
187
188         if(filename != NULL) {
189                 file_descript = open(filename, O_RDONLY);
190                 if(file_descript < 0) {
191                         printf("cifs.mount failed. %s attempting to open password file %s\n",
192                                    strerror(errno),filename);
193                         exit(1);
194                 }
195         }
196         /* else file already open and fd provided */
197
198         for(i=0;i<64;i++) {
199                 rc = read(file_descript,&c,1);
200                 if(rc < 0) {
201                         printf("cifs.mount failed. Error %s reading password file\n",strerror(errno));
202                         memset(mountpassword,0,64);
203                         if(filename != NULL)
204                                 close(file_descript);
205                         exit(1);
206                 } else if(rc == 0) {
207                         if(mountpassword[0] == 0) {
208                                 if(verboseflag)
209                                         printf("\nWarning: null password used since cifs password file empty");
210                         }
211                         break;
212                 } else /* read valid character */ {
213                         if((c == 0) || (c == '\n')) {
214                                 break;
215                         } else 
216                                 mountpassword[i] = c;
217                 }
218         }
219         if((i == 64) && (verboseflag)) {
220                 printf("\nWarning: password longer than 64 characters specified in cifs password file");
221         }
222         got_password = 1;
223         if(filename != NULL) {
224                 close(file_descript);
225         }
226
227         return rc;
228 }
229
230 static int parse_options(char * options)
231 {
232         char * data;
233         char * percent_char = 0;
234         char * value = 0;
235         char * next_keyword = 0;
236         int rc = 0;
237
238         if (!options)
239                 return 1;
240         else
241                 data = options;
242
243         if(verboseflag)
244                 printf("\n parsing options: %s", options);
245
246 /* while ((data = strsep(&options, ",")) != NULL) { */
247         while(data != NULL) {
248                 /*  check if ends with trailing comma */
249                 if(*data == 0)
250                         break;
251
252                 /* format is keyword=value,keyword2=value2,keyword3=value3 etc.) */
253                 /* data  = next keyword */
254                 /* value = next value ie stuff after equal sign */
255
256                 next_keyword = strchr(data,',');
257         
258                 /* temporarily null terminate end of keyword=value pair */
259                 if(next_keyword)
260                         *next_keyword = 0;
261
262                 /* if (!*data)
263                         continue; */
264                 
265                 /* temporarily null terminate keyword to make keyword and value distinct */
266                 if ((value = strchr(data, '=')) != NULL) {
267                         *value = '\0';
268                         value++;
269                 }
270
271                 if (strncmp(data, "user", 4) == 0) {
272                         if (!value || !*value) {
273                                 printf("invalid or missing username\n");
274                                 return 1;       /* needs_arg; */
275                         }
276                         if (strnlen(value, 260) < 260) {
277                                 got_user=1;
278                                 percent_char = strchr(value,'%');
279                                 if(percent_char) {
280                                         *percent_char = ',';
281                                         if(mountpassword == NULL)
282                                                 mountpassword = calloc(65,1);
283                                         if(mountpassword) {
284                                                 if(got_password)
285                                                         printf("\ncifs.mount warning - password specified twice\n");
286                                                 got_password = 1;
287                                                 percent_char++;
288                                                 strncpy(mountpassword, percent_char,64);
289                                         /*  remove password from username */
290                                                 while(*percent_char != 0) {
291                                                         *percent_char = ',';
292                                                         percent_char++;
293                                                 }
294                                         }
295                                 }
296                         } else {
297                                 printf("username too long\n");
298                                 return 1;
299                         }
300                 } else if (strncmp(data, "pass", 4) == 0) {
301                         if (!value || !*value) {
302                                 if(got_password) {
303                                         printf("\npassword specified twice, ignoring second\n");
304                                 } else
305                                         got_password = 1;
306                         } else if (strnlen(value, 17) < 17) {
307                                 if(got_password)
308                                         printf("\ncifs.mount warning - password specified twice\n");
309                                 got_password = 1;
310                         } else {
311                                 printf("password too long\n");
312                                 return 1;
313                         }
314                 } else if (strncmp(data, "ip", 2) == 0) {
315                         if (!value || !*value) {
316                                 printf("target ip address argument missing");
317                         } else if (strnlen(value, 35) < 35) {
318                                 got_ip = 1;
319                         } else {
320                                 printf("ip address too long\n");
321                                 return 1;
322                         }
323                 } else if ((strncmp(data, "unc", 3) == 0)
324                    || (strncmp(data, "target", 6) == 0)
325                    || (strncmp(data, "path", 4) == 0)) {
326                         if (!value || !*value) {
327                                 printf("invalid path to network resource\n");
328                                 return 1;  /* needs_arg; */
329                         } else if(strnlen(value,5) < 5) {
330                                 printf("UNC name too short");
331                         }
332
333                         if (strnlen(value, 300) < 300) {
334                                 got_unc = 1;
335                                 if (strncmp(value, "//", 2) == 0) {
336                                         if(got_unc)
337                                                 printf("unc name specified twice, ignoring second\n");
338                                         else
339                                                 got_unc = 1;
340                                 } else if (strncmp(value, "\\\\", 2) != 0) {                       
341                                         printf("UNC Path does not begin with // or \\\\ \n");
342                                         return 1;
343                                 } else {
344                                         if(got_unc)
345                                                 printf("unc name specified twice, ignoring second\n");
346                                         else
347                                                 got_unc = 1;
348                                 }
349                         } else {
350                                 printf("CIFS: UNC name too long\n");
351                                 return 1;
352                         }
353                 } else if ((strncmp(data, "domain", 3) == 0)
354                            || (strncmp(data, "workgroup", 5) == 0)) {
355                         if (!value || !*value) {
356                                 printf("CIFS: invalid domain name\n");
357                                 return 1;       /* needs_arg; */
358                         }
359                         if (strnlen(value, 65) < 65) {
360                                 got_domain = 1;
361                         } else {
362                                 printf("domain name too long\n");
363                                 return 1;
364                         }
365                 } else if (strncmp(data, "cred", 4) == 0) {
366                         if (value && *value) {
367                                 rc = open_cred_file(value);
368                                 if(rc) {
369                                         printf("error %d opening credential file %s",rc, value);
370                                         return 1;
371                                 }
372                         } else {
373                                 printf("invalid credential file name specified\n");
374                                 return 1;
375                         }
376                 } else if (strncmp(data, "uid", 3) == 0) {
377                         if (value && *value) {
378                                 got_uid = 1;
379                         }
380                 } else if (strncmp(data, "gid", 3) == 0) {
381                         if (value && *value) {
382                                 got_gid = 1;
383                         }
384        /* fmask and dmask synonyms for people used to smbfs syntax */
385                 } else if (strcmp(data, "file_mode") == 0 || strcmp(data, "fmask")==0) {
386                         if (!value || !*value) {
387                                 printf ("Option '%s' requires a numerical argument\n", data);
388                                 return 1;
389                         }
390
391                         if (value[0] != '0') {
392                                 printf ("WARNING: '%s' not expressed in octal.\n", data);
393                         }
394
395                         if (strcmp (data, "fmask") == 0) {
396                                 printf ("WARNING: CIFS mount option 'fmask' is deprecated. Use 'file_mode' instead.\n");
397                                 data = "file_mode";
398                         }
399                 } else if (strcmp(data, "dir_mode") == 0 || strcmp(data, "dmask")==0) {
400                         if (!value || !*value) {
401                                 printf ("Option '%s' requires a numerical argument\n", data);
402                                 return 1;
403                         }
404
405                         if (value[0] != '0') {
406                                 printf ("WARNING: '%s' not expressed in octal.\n", data);
407                         }
408
409                         if (strcmp (data, "dmask") == 0) {
410                                 printf ("WARNING: CIFS mount option 'dmask' is deprecated. Use 'dir_mode' instead.\n");
411                                 data = "dir_mode";
412                         }
413                 } /* else if (strnicmp(data, "port", 4) == 0) {
414                 if (value && *value) {
415                         vol->port =
416                                 simple_strtoul(value, &value, 0);
417                 }
418         } else if (strnicmp(data, "rsize", 5) == 0) {
419                 if (value && *value) {
420                         vol->rsize =
421                                 simple_strtoul(value, &value, 0);
422                 }
423         } else if (strnicmp(data, "wsize", 5) == 0) {
424                 if (value && *value) {
425                         vol->wsize =
426                                 simple_strtoul(value, &value, 0);
427                 }
428         } else if (strnicmp(data, "version", 3) == 0) {
429                 
430         } else if (strnicmp(data, "rw", 2) == 0) {
431                 
432         } else
433                 printf("CIFS: Unknown mount option %s\n",data); */
434
435                 /* move to next option */
436                 data = next_keyword+1;
437
438                 /* put overwritten equals sign back */
439                 if(value) {
440                         value--;
441                         *value = '=';
442                 }
443                 
444                 /* put previous overwritten comma back */
445                 if(next_keyword)
446                         *next_keyword = ',';
447                 else
448                         data = 0;
449
450         }
451         return 0;
452 }
453
454 /* Note that caller frees the returned buffer if necessary */
455 char * parse_server(char * unc_name)
456 {
457         int length = strnlen(unc_name,1024);
458         char * share;
459         char * ipaddress_string = NULL;
460         struct hostent * host_entry;
461         struct in_addr server_ipaddr;
462         int rc;
463
464         if(length > 1023) {
465                 printf("mount error: UNC name too long");
466                 return 0;
467         }
468         if (strncasecmp("cifs://",unc_name,7) == 0)
469                 return parse_cifs_url(unc_name+7);
470         if (strncasecmp("smb://",unc_name,6) == 0) {
471                 return parse_cifs_url(unc_name+6);
472         }
473
474         if(length < 3) {
475                 /* BB add code to find DFS root here */
476                 printf("\nMounting the DFS root for domain not implemented yet");
477                 return 0;
478         } else {
479                 if(strncmp(unc_name,"//",2) && strncmp(unc_name,"\\\\",2)) {
480                         printf("mount error: improperly formatted UNC name.");
481                         printf(" %s does not begin with \\\\ or //\n",unc_name);
482                         return 0;
483                 } else {
484                         unc_name[0] = '\\';
485                         unc_name[0] = '/';
486                         unc_name[1] = '/';
487                         unc_name += 2;
488                         if ((share = strchr(unc_name, '/')) || 
489                                 (share = strchr(unc_name,'\\'))) {
490                                 *share = 0;  /* temporarily terminate the string */
491                                 share += 1;
492                                 host_entry = gethostbyname(unc_name);
493                                 *(share - 1) = '/'; /* put the slash back */
494 /*                              rc = getipnodebyname(unc_name, AF_INET, AT_ADDRCONFIG ,&rc);*/
495                                 if(host_entry == NULL) {
496                                         printf("mount error: could not find target server. TCP name %s not found ", unc_name);
497                                         printf(" rc = %d\n",rc);
498                                         return 0;
499                                 }
500                                 else {
501                                         /* BB should we pass an alternate version of the share name as Unicode */
502                                         /* BB what about ipv6? BB */
503                                         /* BB add retries with alternate servers in list */
504
505                                         memcpy(&server_ipaddr.s_addr, host_entry->h_addr, 4);
506
507                                         ipaddress_string = inet_ntoa(server_ipaddr);                                                                                     
508                                         if(ipaddress_string == NULL) {
509                                                 printf("mount error: could not get valid ip address for target server\n");
510                                                 return 0;
511                                         }
512                                         return ipaddress_string; 
513                                 }
514                         } else {
515                                 /* BB add code to find DFS root (send null path on get DFS Referral to specified server here */
516                                 printf("Mounting the DFS root for a particular server not implemented yet\n");
517                                 return 0;
518                         }
519                 }
520         }
521 }
522
523 static struct option longopts[] = {
524         { "all", 0, 0, 'a' },
525         { "help", 0, 0, 'h' },
526         { "read-only", 0, 0, 'r' },
527         { "ro", 0, 0, 'r' },
528         { "verbose", 0, 0, 'v' },
529         { "version", 0, 0, 'V' },
530         { "read-write", 0, 0, 'w' },
531         { "rw", 0, 0, 'w' },
532         { "options", 1, 0, 'o' },
533         { "types", 1, 0, 't' },
534         { "rsize",1, 0, 'R' },
535         { "wsize",1, 0, 'W' },
536         { "uid", 1, 0, '1'},
537         { "gid", 1, 0, '2'},
538         { "uuid",1,0,'U' },
539         { "user",1,0,'u'},
540         { "username",1,0,'u'},
541         { "dom",1,0,'d'},
542         { "domain",1,0,'d'},
543         { "password",1,0,'p'},
544         { "pass",1,0,'p'},
545         { "credentials",1,0,'c'},
546         { "port",1,0,'P'},
547         { NULL, 0, 0, 0 }
548 };
549
550 int main(int argc, char ** argv)
551 {
552         int c;
553         int flags = MS_MANDLOCK | MS_MGC_VAL;
554         char * orgoptions = NULL;
555         char * share_name = NULL;
556         char * domain_name = NULL;
557         char * ipaddr = NULL;
558         char * uuid = NULL;
559         char * mountpoint;
560         char * options;
561         char * temp;
562         int rc;
563         int rsize = 0;
564         int wsize = 0;
565         int nomtab = 0;
566         int uid = 0;
567         int gid = 0;
568         int optlen = 0;
569         int orgoptlen = 0;
570         struct stat statbuf;
571         struct utsname sysinfo;
572         struct mntent mountent;
573         FILE * pmntfile;
574
575         /* setlocale(LC_ALL, "");
576         bindtextdomain(PACKAGE, LOCALEDIR);
577         textdomain(PACKAGE); */
578
579         if(argc && argv) {
580                 thisprogram = argv[0];
581         }
582         if(thisprogram == NULL)
583                 thisprogram = "mount.cifs";
584
585         uname(&sysinfo);
586         /* BB add workstation name and domain and pass down */
587
588 /* #ifdef _GNU_SOURCE
589         printf(" node: %s machine: %s sysname %s domain %s\n", sysinfo.nodename,sysinfo.machine,sysinfo.sysname,sysinfo.domainname);
590 #endif */
591
592         share_name = argv[1];
593         mountpoint = argv[2];
594
595         /* add sharename in opts string as unc= parm */
596
597         while ((c = getopt_long (argc, argv, "afFhilL:no:O:rsU:vVwt:",
598                          longopts, NULL)) != -1) {
599                 switch (c) {
600 /* No code to do the following  options yet */
601 /*      case 'l':
602                 list_with_volumelabel = 1;
603                 break;
604         case 'L':
605                 volumelabel = optarg;
606                 break; */
607 /*      case 'a':              
608                 ++mount_all;
609                 break; */
610
611                 case '?':
612                 case 'h':        /* help */
613                         mount_cifs_usage ();
614                         exit(1);
615                 case 'n':
616                     ++nomtab;
617                     break;
618                 case 'o':
619                         orgoptions = strdup(optarg);
620                     break;
621                 case 'r':  /* mount readonly */
622                         flags |= MS_RDONLY;
623                         break;
624                 case 'U':
625                         uuid = optarg;
626                         break;
627                 case 'v':
628                         ++verboseflag;
629                         break;
630                 case 'V':          
631                         printf ("mount.cifs version: %s.%s%s\n",
632                         MOUNT_CIFS_VERSION_MAJOR,
633                         MOUNT_CIFS_VERSION_MINOR,
634                         MOUNT_CIFS_VENDOR_SUFFIX);
635                         if(mountpassword) {
636                                 memset(mountpassword,0,64);
637                         }
638                         exit (0);
639                 case 'w':
640                         flags &= ~MS_RDONLY;
641                         break;
642                 case 'R':
643                         rsize = atoi(optarg) ;
644                         break;
645                 case 'W':
646                         wsize = atoi(optarg);
647                         break;
648                 case '1':
649                         uid = atoi(optarg);
650                         break;
651                 case '2':
652                         gid = atoi(optarg);
653                         break;
654                 case 'u':
655                         got_user = 1;
656                         user_name = optarg;
657                         break;
658                 case 'd':
659                         domain_name = optarg;
660                         break;
661                 case 'p':
662                         if(mountpassword == NULL)
663                                 mountpassword = calloc(65,1);
664                         if(mountpassword) {
665                                 got_password = 1;
666                                 strncpy(mountpassword,optarg,64);
667                         }
668                         break;
669                 case 't':
670                         break;
671                 default:
672                         printf("unknown mount option %c\n",c);
673                         mount_cifs_usage();
674                         exit(1);
675                 }
676         }
677
678         if(argc < 3)
679                 mount_cifs_usage();
680
681         if (getenv("PASSWD")) {
682                 if(mountpassword == NULL)
683                         mountpassword = calloc(65,1);
684                 if(mountpassword) {
685                         strncpy(mountpassword,getenv("PASSWD"),64);
686                         got_password = 1;
687                 }
688         } else if (getenv("PASSWD_FD")) {
689                 get_password_from_file(atoi(getenv("PASSWD_FD")),NULL);
690         } else if (getenv("PASSWD_FILE")) {
691                 get_password_from_file(0, getenv("PASSWD_FILE"));
692         }
693
694         ipaddr = parse_server(share_name);
695         
696         if (orgoptions && parse_options(orgoptions))
697                 return 1;
698
699         /* BB save off path and pop after mount returns? */
700         /* BB canonicalize the path in argv[1]? */
701
702         if(chdir(mountpoint)) {
703                 printf("mount error: can not change directory into mount target %s\n",mountpoint);
704         }
705
706         if(stat (mountpoint, &statbuf)) {
707                 printf("mount error: mount point %s does not exist\n",mountpoint);
708                 return -1;
709         }
710
711         if (S_ISDIR(statbuf.st_mode) == 0) {
712                 printf("mount error: mount point %s is not a directory\n",mountpoint);
713                 return -1;
714         }
715
716         if((getuid() != 0) && (geteuid() == 0)) {
717                 if((statbuf.st_uid == getuid()) && (S_IRWXU == (statbuf.st_mode & S_IRWXU))) {
718                         printf("setuid mount allowed\n");
719                 } else {
720                         printf("mount error: permission denied or not superuser and cifs.mount not installed SUID\n"); 
721                         return -1;
722                 }
723         }
724
725         if(got_user == 0)
726                 user_name = getusername();
727        
728         if(got_password == 0) {
729                 mountpassword = getpass("Password: "); /* BB obsolete */
730                 got_password = 1;
731         }
732         /* FIXME launch daemon (handles dfs name resolution and credential change) 
733            remember to clear parms and overwrite password field before launching */
734         if(orgoptions) {
735                 optlen = strlen(orgoptions);
736                 orgoptlen = optlen;
737         } else
738                 optlen = 0;
739         if(share_name)
740                 optlen += strlen(share_name) + 4;
741         if(user_name)
742                 optlen += strlen(user_name) + 6;
743         if(ipaddr)
744                 optlen += strlen(ipaddr) + 4;
745         if(mountpassword)
746                 optlen += strlen(mountpassword) + 6;
747         options = malloc(optlen + 10);
748
749         options[0] = 0;
750         strncat(options,"unc=",4);
751         strcat(options,share_name);
752         /* scan backwards and reverse direction of slash */
753         temp = strrchr(options, '/');
754         if(temp > options + 6)
755                 *temp = '\\';
756         if(ipaddr) {
757                 strncat(options,",ip=",4);
758                 strcat(options,ipaddr);
759         } 
760         if(user_name) {
761                 strncat(options,",user=",6);
762                 strcat(options,user_name);
763         } 
764         if(mountpassword) {
765                 strncat(options,",pass=",6);
766                 strcat(options,mountpassword);
767         }
768         strncat(options,",ver=",5);
769         strcat(options,MOUNT_CIFS_VERSION_MAJOR);
770
771         if(orgoptions) {
772                 strcat(options,",");
773                 strcat(options,orgoptions);
774         }
775         if(verboseflag)
776                 printf("\ncifs.mount kernel mount options %s \n",options);
777         if(mount(share_name, mountpoint, "cifs", flags, options)) {
778         /* remember to kill daemon on error */
779                 switch (errno) {
780                 case 0:
781                         printf("mount failed but no error number set\n");
782                         break;
783                 case ENODEV:
784                         printf("mount error: cifs filesystem not supported by the system\n");
785                         break;
786                 default:
787                         printf("mount error %d = %s\n",errno,strerror(errno));
788                 }
789                 printf("Refer to the mount.cifs(8) manual page (e.g.man mount.cifs)\n");
790                 if(mountpassword) {
791                         memset(mountpassword,0,64);
792                 }
793                 return -1;
794         } else {
795                 pmntfile = setmntent(MOUNTED, "a+");
796                 if(pmntfile) {
797                         mountent.mnt_fsname = share_name;
798                         mountent.mnt_dir = mountpoint; 
799                         mountent.mnt_type = "cifs"; 
800                         mountent.mnt_opts = "";
801                         mountent.mnt_freq = 0;
802                         mountent.mnt_passno = 0;
803                         rc = addmntent(pmntfile,&mountent);
804                         endmntent(pmntfile);
805                 } else {
806                     printf("could not update mount table\n");
807                 }
808         }
809         if(mountpassword) {
810                 memset(mountpassword,0,64);
811                 free(mountpassword);
812         }
813
814         if(options) {
815                 memset(options,0,optlen);
816                 free(options);
817         }
818
819         if(orgoptions) {
820                 memset(orgoptions,0,orgoptlen);
821                 free(orgoptions);
822         }
823         return 0;
824 }
825