fix a bunch of places where we can double-free a cli structure
[samba.git] / source / client / smbmount.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 2.0.
4    SMBFS mount program
5    Copyright (C) Andrew Tridgell 1999
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #define NO_SYSLOG
23
24 #include "includes.h"
25
26 #include <mntent.h>
27 #include <asm/types.h>
28 #include <linux/smb_fs.h>
29
30 extern BOOL in_client;
31 extern pstring user_socket_options;
32 extern BOOL append_log;
33 extern fstring remote_machine;
34
35 static pstring credentials;
36 static pstring my_netbios_name;
37 static pstring password;
38 static pstring username;
39 static pstring workgroup;
40 static pstring mpoint;
41 static pstring service;
42 static pstring options;
43
44 static struct in_addr dest_ip;
45 static BOOL have_ip;
46 static int smb_port = 0;
47 static BOOL got_pass;
48 static uid_t mount_uid;
49 static gid_t mount_gid;
50 static int mount_ro;
51 static unsigned mount_fmask;
52 static unsigned mount_dmask;
53
54 static void usage(void);
55
56 static void exit_parent(int sig)
57 {
58         /* parent simply exits when child says go... */
59         exit(0);
60 }
61
62 static void daemonize(void)
63 {
64         int j, status;
65         pid_t child_pid;
66
67         signal( SIGTERM, exit_parent );
68
69         if ((child_pid = sys_fork()) < 0) {
70                 DEBUG(0,("could not fork\n"));
71         }
72
73         if (child_pid > 0) {
74                 while( 1 ) {
75                         j = waitpid( child_pid, &status, 0 );
76                         if( j < 0 ) {
77                                 if( EINTR == errno ) {
78                                         continue;
79                                 }
80                                 status = errno;
81                         }
82                         break;
83                 }
84                 /* If we get here - the child exited with some error status */
85                 exit(status);
86         }
87
88         signal( SIGTERM, SIG_DFL );
89         chdir("/");
90 }
91
92 static void close_our_files(int client_fd)
93 {
94         int i;
95         struct rlimit limits;
96
97         getrlimit(RLIMIT_NOFILE,&limits);
98         for (i = 0; i< limits.rlim_max; i++) {
99                 if (i == client_fd)
100                         continue;
101                 close(i);
102         }
103 }
104
105 static void usr1_handler(int x)
106 {
107         return;
108 }
109
110
111 /***************************************************** 
112 return a connection to a server
113 *******************************************************/
114 static struct cli_state *do_connection(char *the_service)
115 {
116         struct cli_state *c;
117         struct nmb_name called, calling;
118         char *server_n;
119         struct in_addr ip;
120         pstring server;
121         char *share;
122
123         if (the_service[0] != '\\' || the_service[1] != '\\') {
124                 usage();
125                 exit(1);
126         }
127
128         pstrcpy(server, the_service+2);
129         share = strchr_m(server,'\\');
130         if (!share) {
131                 usage();
132                 exit(1);
133         }
134         *share = 0;
135         share++;
136
137         server_n = server;
138
139         make_nmb_name(&calling, my_netbios_name, 0x0);
140         make_nmb_name(&called , server, 0x20);
141
142  again:
143         zero_ip(&ip);
144         if (have_ip) ip = dest_ip;
145
146         /* have to open a new connection */
147         if (!(c=cli_initialise(NULL)) || (cli_set_port(c, smb_port) != smb_port) ||
148             !cli_connect(c, server_n, &ip)) {
149                 DEBUG(0,("%d: Connection to %s failed\n", getpid(), server_n));
150                 if (c) {
151                         cli_shutdown(c);
152                 }
153                 return NULL;
154         }
155
156         if (!cli_session_request(c, &calling, &called)) {
157                 char *p;
158                 DEBUG(0,("%d: session request to %s failed (%s)\n", 
159                          getpid(), called.name, cli_errstr(c)));
160                 cli_shutdown(c);
161                 if ((p=strchr_m(called.name, '.'))) {
162                         *p = 0;
163                         goto again;
164                 }
165                 if (strcmp(called.name, "*SMBSERVER")) {
166                         make_nmb_name(&called , "*SMBSERVER", 0x20);
167                         goto again;
168                 }
169                 return NULL;
170         }
171
172         DEBUG(4,("%d: session request ok\n", getpid()));
173
174         if (!cli_negprot(c)) {
175                 DEBUG(0,("%d: protocol negotiation failed\n", getpid()));
176                 cli_shutdown(c);
177                 return NULL;
178         }
179
180         if (!got_pass) {
181                 char *pass = getpass("Password: ");
182                 if (pass) {
183                         pstrcpy(password, pass);
184                 }
185         }
186
187         if (!cli_session_setup(c, username, 
188                                password, strlen(password),
189                                password, strlen(password),
190                                workgroup)) {
191                 /* if a password was not supplied then try again with a
192                         null username */
193                 if (password[0] || !username[0] ||
194                                 !cli_session_setup(c, "", "", 0, "", 0, workgroup)) {
195                         DEBUG(0,("%d: session setup failed: %s\n",
196                                 getpid(), cli_errstr(c)));
197                         cli_shutdown(c);
198                         return NULL;
199                 }
200                 DEBUG(0,("Anonymous login successful\n"));
201         }
202
203         DEBUG(4,("%d: session setup ok\n", getpid()));
204
205         if (!cli_send_tconX(c, share, "?????",
206                             password, strlen(password)+1)) {
207                 DEBUG(0,("%d: tree connect failed: %s\n",
208                          getpid(), cli_errstr(c)));
209                 cli_shutdown(c);
210                 return NULL;
211         }
212
213         DEBUG(4,("%d: tconx ok\n", getpid()));
214
215         got_pass = True;
216
217         return c;
218 }
219
220
221 /****************************************************************************
222 unmount smbfs  (this is a bailout routine to clean up if a reconnect fails)
223         Code blatently stolen from smbumount.c
224                 -mhw-
225 ****************************************************************************/
226 static void smb_umount(char *mount_point)
227 {
228         int fd;
229         struct mntent *mnt;
230         FILE* mtab;
231         FILE* new_mtab;
232
233         /* Programmers Note:
234                 This routine only gets called to the scene of a disaster
235                 to shoot the survivors...  A connection that was working
236                 has now apparently failed.  We have an active mount point
237                 (presumably) that we need to dump.  If we get errors along
238                 the way - make some noise, but we are already turning out
239                 the lights to exit anyways...
240         */
241         if (umount(mount_point) != 0) {
242                 DEBUG(0,("%d: Could not umount %s: %s\n",
243                          getpid(), mount_point, strerror(errno)));
244                 return;
245         }
246
247         if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1) {
248                 DEBUG(0,("%d: Can't get "MOUNTED"~ lock file", getpid()));
249                 return;
250         }
251
252         close(fd);
253         
254         if ((mtab = setmntent(MOUNTED, "r")) == NULL) {
255                 DEBUG(0,("%d: Can't open " MOUNTED ": %s\n",
256                          getpid(), strerror(errno)));
257                 return;
258         }
259
260 #define MOUNTED_TMP MOUNTED".tmp"
261
262         if ((new_mtab = setmntent(MOUNTED_TMP, "w")) == NULL) {
263                 DEBUG(0,("%d: Can't open " MOUNTED_TMP ": %s\n",
264                          getpid(), strerror(errno)));
265                 endmntent(mtab);
266                 return;
267         }
268
269         while ((mnt = getmntent(mtab)) != NULL) {
270                 if (strcmp(mnt->mnt_dir, mount_point) != 0) {
271                         addmntent(new_mtab, mnt);
272                 }
273         }
274
275         endmntent(mtab);
276
277         if (fchmod (fileno (new_mtab), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
278                 DEBUG(0,("%d: Error changing mode of %s: %s\n",
279                          getpid(), MOUNTED_TMP, strerror(errno)));
280                 return;
281         }
282
283         endmntent(new_mtab);
284
285         if (rename(MOUNTED_TMP, MOUNTED) < 0) {
286                 DEBUG(0,("%d: Cannot rename %s to %s: %s\n",
287                          getpid(), MOUNTED, MOUNTED_TMP, strerror(errno)));
288                 return;
289         }
290
291         if (unlink(MOUNTED"~") == -1) {
292                 DEBUG(0,("%d: Can't remove "MOUNTED"~", getpid()));
293                 return;
294         }
295 }
296
297
298 /*
299  * Call the smbfs ioctl to install a connection socket,
300  * then wait for a signal to reconnect. Note that we do
301  * not exit after open_sockets() or send_login() errors,
302  * as the smbfs mount would then have no way to recover.
303  */
304 static void send_fs_socket(char *the_service, char *mount_point, struct cli_state *c)
305 {
306         int fd, closed = 0, res = 1;
307         pid_t parentpid = getppid();
308         struct smb_conn_opt conn_options;
309
310         memset(&conn_options, 0, sizeof(conn_options));
311
312         while (1) {
313                 if ((fd = open(mount_point, O_RDONLY)) < 0) {
314                         DEBUG(0,("mount.smbfs[%d]: can't open %s\n",
315                                  getpid(), mount_point));
316                         break;
317                 }
318
319                 conn_options.fd = c->fd;
320                 conn_options.protocol = c->protocol;
321                 conn_options.case_handling = SMB_CASE_DEFAULT;
322                 conn_options.max_xmit = c->max_xmit;
323                 conn_options.server_uid = c->vuid;
324                 conn_options.tid = c->cnum;
325                 conn_options.secmode = c->sec_mode;
326                 conn_options.rawmode = 0;
327                 conn_options.sesskey = c->sesskey;
328                 conn_options.maxraw = 0;
329                 conn_options.capabilities = c->capabilities;
330                 conn_options.serverzone = c->serverzone/60;
331
332                 res = ioctl(fd, SMB_IOC_NEWCONN, &conn_options);
333                 if (res != 0) {
334                         DEBUG(0,("mount.smbfs[%d]: ioctl failed, res=%d\n",
335                                  getpid(), res));
336                         close(fd);
337                         break;
338                 }
339
340                 if (parentpid) {
341                         /* Ok...  We are going to kill the parent.  Now
342                                 is the time to break the process group... */
343                         setsid();
344                         /* Send a signal to the parent to terminate */
345                         kill(parentpid, SIGTERM);
346                         parentpid = 0;
347                 }
348
349                 close(fd);
350
351                 /* This looks wierd but we are only closing the userspace
352                    side, the connection has already been passed to smbfs and 
353                    it has increased the usage count on the socket.
354
355                    If we don't do this we will "leak" sockets and memory on
356                    each reconnection we have to make. */
357                 cli_shutdown(c);
358
359                 if (!closed) {
360                         /* redirect stdout & stderr since we can't know that
361                            the library functions we use are using DEBUG. */
362                         if ( (fd = open("/dev/null", O_WRONLY)) < 0)
363                                 DEBUG(2,("mount.smbfs: can't open /dev/null\n"));
364                         close_our_files(fd);
365                         if (fd >= 0) {
366                                 dup2(fd, STDOUT_FILENO);
367                                 dup2(fd, STDERR_FILENO);
368                                 close(fd);
369                         }
370
371                         /* here we are no longer interactive */
372                         pstrcpy(remote_machine, "smbmount");    /* sneaky ... */
373                         setup_logging("mount.smbfs", False);
374                         append_log = True;
375                         reopen_logs();
376                         DEBUG(0, ("mount.smbfs: entering daemon mode for service %s, pid=%d\n", the_service, getpid()));
377
378                         closed = 1;
379                 }
380
381                 /* Wait for a signal from smbfs ... but don't continue
382                    until we actually get a new connection. */
383                 while (!c) {
384                         CatchSignal(SIGUSR1, &usr1_handler);
385                         pause();
386                         DEBUG(2,("mount.smbfs[%d]: got signal, getting new socket\n", getpid()));
387                         c = do_connection(the_service);
388                 }
389         }
390
391         smb_umount(mount_point);
392         DEBUG(2,("mount.smbfs[%d]: exit\n", getpid()));
393         exit(1);
394 }
395
396
397 /**
398  * Mount a smbfs
399  **/
400 static void init_mount(void)
401 {
402         char mount_point[MAXPATHLEN+1];
403         pstring tmp;
404         pstring svc2;
405         struct cli_state *c;
406         char *args[20];
407         int i, status;
408
409         if (realpath(mpoint, mount_point) == NULL) {
410                 fprintf(stderr, "Could not resolve mount point %s\n", mpoint);
411                 return;
412         }
413
414
415         c = do_connection(service);
416         if (!c) {
417                 fprintf(stderr,"SMB connection failed\n");
418                 exit(1);
419         }
420
421         /*
422                 Set up to return as a daemon child and wait in the parent
423                 until the child say it's ready...
424         */
425         daemonize();
426
427         pstrcpy(svc2, service);
428         string_replace(svc2, '\\','/');
429         string_replace(svc2, ' ','_');
430
431         memset(args, 0, sizeof(args[0])*20);
432
433         i=0;
434         args[i++] = "smbmnt";
435
436         args[i++] = mount_point;
437         args[i++] = "-s";
438         args[i++] = svc2;
439
440         if (mount_ro) {
441                 args[i++] = "-r";
442         }
443         if (mount_uid) {
444                 slprintf(tmp, sizeof(tmp)-1, "%d", mount_uid);
445                 args[i++] = "-u";
446                 args[i++] = smb_xstrdup(tmp);
447         }
448         if (mount_gid) {
449                 slprintf(tmp, sizeof(tmp)-1, "%d", mount_gid);
450                 args[i++] = "-g";
451                 args[i++] = smb_xstrdup(tmp);
452         }
453         if (mount_fmask) {
454                 slprintf(tmp, sizeof(tmp)-1, "0%o", mount_fmask);
455                 args[i++] = "-f";
456                 args[i++] = smb_xstrdup(tmp);
457         }
458         if (mount_dmask) {
459                 slprintf(tmp, sizeof(tmp)-1, "0%o", mount_dmask);
460                 args[i++] = "-d";
461                 args[i++] = smb_xstrdup(tmp);
462         }
463         if (options) {
464                 args[i++] = "-o";
465                 args[i++] = options;
466         }
467
468         if (sys_fork() == 0) {
469                 char *smbmnt_path;
470
471                 asprintf(&smbmnt_path, "%s/smbmnt", dyn_BINDIR);
472                 
473                 if (file_exist(smbmnt_path, NULL)) {
474                         execv(smbmnt_path, args);
475                         fprintf(stderr,
476                                 "smbfs/init_mount: execv of %s failed. Error was %s.",
477                                 smbmnt_path, strerror(errno));
478                 } else {
479                         execvp("smbmnt", args);
480                         fprintf(stderr,
481                                 "smbfs/init_mount: execv of %s failed. Error was %s.",
482                                 "smbmnt", strerror(errno));
483                 }
484                 free(smbmnt_path);
485                 exit(1);
486         }
487
488         if (waitpid(-1, &status, 0) == -1) {
489                 fprintf(stderr,"waitpid failed: Error was %s", strerror(errno) );
490                 /* FIXME: do some proper error handling */
491                 exit(1);
492         }
493
494         if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
495                 fprintf(stderr,"smbmnt failed: %d\n", WEXITSTATUS(status));
496                 /* FIXME: do some proper error handling */
497                 exit(1);
498         }
499
500         /* Ok...  This is the rubicon for that mount point...  At any point
501            after this, if the connections fail and can not be reconstructed
502            for any reason, we will have to unmount the mount point.  There
503            is no exit from the next call...
504         */
505         send_fs_socket(service, mount_point, c);
506 }
507
508
509 /****************************************************************************
510 get a password from a a file or file descriptor
511 exit on failure (from smbclient, move to libsmb or shared .c file?)
512 ****************************************************************************/
513 static void get_password_file(void)
514 {
515         int fd = -1;
516         char *p;
517         BOOL close_it = False;
518         pstring spec;
519         char pass[128];
520
521         if ((p = getenv("PASSWD_FD")) != NULL) {
522                 pstrcpy(spec, "descriptor ");
523                 pstrcat(spec, p);
524                 sscanf(p, "%d", &fd);
525                 close_it = False;
526         } else if ((p = getenv("PASSWD_FILE")) != NULL) {
527                 fd = sys_open(p, O_RDONLY, 0);
528                 pstrcpy(spec, p);
529                 if (fd < 0) {
530                         fprintf(stderr, "Error opening PASSWD_FILE %s: %s\n",
531                                 spec, strerror(errno));
532                         exit(1);
533                 }
534                 close_it = True;
535         }
536
537         for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */
538             p && p - pass < sizeof(pass);) {
539                 switch (read(fd, p, 1)) {
540                 case 1:
541                         if (*p != '\n' && *p != '\0') {
542                                 *++p = '\0'; /* advance p, and null-terminate pass */
543                                 break;
544                         }
545                 case 0:
546                         if (p - pass) {
547                                 *p = '\0'; /* null-terminate it, just in case... */
548                                 p = NULL; /* then force the loop condition to become false */
549                                 break;
550                         } else {
551                                 fprintf(stderr, "Error reading password from file %s: %s\n",
552                                         spec, "empty password\n");
553                                 exit(1);
554                         }
555
556                 default:
557                         fprintf(stderr, "Error reading password from file %s: %s\n",
558                                 spec, strerror(errno));
559                         exit(1);
560                 }
561         }
562         pstrcpy(password, pass);
563         if (close_it)
564                 close(fd);
565 }
566
567 /****************************************************************************
568 get username and password from a credentials file
569 exit on failure (from smbclient, move to libsmb or shared .c file?)
570 ****************************************************************************/
571 static void read_credentials_file(char *filename)
572 {
573         FILE *auth;
574         fstring buf;
575         uint16 len = 0;
576         char *ptr, *val, *param;
577
578         if ((auth=sys_fopen(filename, "r")) == NULL)
579         {
580                 /* fail if we can't open the credentials file */
581                 DEBUG(0,("ERROR: Unable to open credentials file!\n"));
582                 exit (-1);
583         }
584
585         while (!feof(auth))
586         {
587                 /* get a line from the file */
588                 if (!fgets (buf, sizeof(buf), auth))
589                         continue;
590                 len = strlen(buf);
591
592                 if ((len) && (buf[len-1]=='\n'))
593                 {
594                         buf[len-1] = '\0';
595                         len--;
596                 }
597                 if (len == 0)
598                         continue;
599
600                 /* break up the line into parameter & value.
601                    will need to eat a little whitespace possibly */
602                 param = buf;
603                 if (!(ptr = strchr (buf, '=')))
604                         continue;
605                 val = ptr+1;
606                 *ptr = '\0';
607
608                 /* eat leading white space */
609                 while ((*val!='\0') && ((*val==' ') || (*val=='\t')))
610                         val++;
611
612                 if (strwicmp("password", param) == 0)
613                 {
614                         pstrcpy(password, val);
615                         got_pass = True;
616                 }
617                 else if (strwicmp("username", param) == 0)
618                         pstrcpy(username, val);
619
620                 memset(buf, 0, sizeof(buf));
621         }
622         fclose(auth);
623 }
624
625
626 /****************************************************************************
627 usage on the program
628 ****************************************************************************/
629 static void usage(void)
630 {
631         printf("Usage: mount.smbfs service mountpoint [-o options,...]\n");
632
633         printf("Version %s\n\n",VERSION);
634
635         printf(
636 "Options:
637       username=<arg>                  SMB username
638       password=<arg>                  SMB password
639       credentials=<filename>          file with username/password
640       netbiosname=<arg>               source NetBIOS name
641       uid=<arg>                       mount uid or username
642       gid=<arg>                       mount gid or groupname
643       port=<arg>                      remote SMB port number
644       fmask=<arg>                     file umask
645       dmask=<arg>                     directory umask
646       debug=<arg>                     debug level
647       ip=<arg>                        destination host or IP address
648       workgroup=<arg>                 workgroup on destination
649       sockopt=<arg>                   TCP socket options
650       scope=<arg>                     NetBIOS scope
651       iocharset=<arg>                 Linux charset (iso8859-1, utf8)
652       codepage=<arg>                  server codepage (cp850)
653       ttl=<arg>                       dircache time to live
654       guest                           don't prompt for a password
655       ro                              mount read-only
656       rw                              mount read-write
657
658 This command is designed to be run from within /bin/mount by giving
659 the option '-t smbfs'. For example:
660   mount -t smbfs -o username=tridge,password=foobar //fjall/test /data/test
661 ");
662 }
663
664
665 /****************************************************************************
666   Argument parsing for mount.smbfs interface
667   mount will call us like this:
668     mount.smbfs device mountpoint -o <options>
669   
670   <options> is never empty, containing at least rw or ro
671  ****************************************************************************/
672 static void parse_mount_smb(int argc, char **argv)
673 {
674         int opt;
675         char *opts;
676         char *opteq;
677         extern char *optarg;
678         int val;
679         extern pstring global_scope;
680         char *p;
681
682         if (argc < 2 || argv[1][0] == '-') {
683                 usage();
684                 exit(1);
685         }
686         
687         pstrcpy(service, argv[1]);
688         pstrcpy(mpoint, argv[2]);
689
690         /* Convert any '/' characters in the service name to
691            '\' characters */
692         string_replace(service, '/','\\');
693         argc -= 2;
694         argv += 2;
695
696         opt = getopt(argc, argv, "o:");
697         if(opt != 'o') {
698                 return;
699         }
700
701         options[0] = 0;
702         p = options;
703
704         /*
705          * option parsing from nfsmount.c (util-linux-2.9u)
706          */
707         for (opts = strtok(optarg, ","); opts; opts = strtok(NULL, ",")) {
708                 DEBUG(3, ("opts: %s\n", opts));
709                 if ((opteq = strchr_m(opts, '='))) {
710                         val = atoi(opteq + 1);
711                         *opteq = '\0';
712
713                         if (!strcmp(opts, "username") || 
714                             !strcmp(opts, "logon")) {
715                                 char *lp;
716                                 pstrcpy(username,opteq+1);
717                                 if ((lp=strchr_m(username,'%'))) {
718                                         *lp = 0;
719                                         pstrcpy(password,lp+1);
720                                         got_pass = True;
721                                         memset(strchr_m(opteq+1,'%')+1,'X',strlen(password));
722                                 }
723                                 if ((lp=strchr_m(username,'/'))) {
724                                         *lp = 0;
725                                         pstrcpy(workgroup,lp+1);
726                                 }
727                         } else if(!strcmp(opts, "passwd") ||
728                                   !strcmp(opts, "password")) {
729                                 pstrcpy(password,opteq+1);
730                                 got_pass = True;
731                                 memset(opteq+1,'X',strlen(password));
732                         } else if(!strcmp(opts, "credentials")) {
733                                 pstrcpy(credentials,opteq+1);
734                         } else if(!strcmp(opts, "netbiosname")) {
735                                 pstrcpy(my_netbios_name,opteq+1);
736                         } else if(!strcmp(opts, "uid")) {
737                                 mount_uid = nametouid(opteq+1);
738                         } else if(!strcmp(opts, "gid")) {
739                                 mount_gid = nametogid(opteq+1);
740                         } else if(!strcmp(opts, "port")) {
741                                 smb_port = val;
742                         } else if(!strcmp(opts, "fmask")) {
743                                 mount_fmask = strtol(opteq+1, NULL, 8);
744                         } else if(!strcmp(opts, "dmask")) {
745                                 mount_dmask = strtol(opteq+1, NULL, 8);
746                         } else if(!strcmp(opts, "debug")) {
747                                 DEBUGLEVEL = val;
748                         } else if(!strcmp(opts, "ip")) {
749                                 dest_ip = *interpret_addr2(opteq+1);
750                                 if (is_zero_ip(dest_ip)) {
751                                         fprintf(stderr,"Can't resolve address %s\n", opteq+1);
752                                         exit(1);
753                                 }
754                                 have_ip = True;
755                         } else if(!strcmp(opts, "workgroup")) {
756                                 pstrcpy(workgroup,opteq+1);
757                         } else if(!strcmp(opts, "sockopt")) {
758                                 pstrcpy(user_socket_options,opteq+1);
759                         } else if(!strcmp(opts, "scope")) {
760                                 pstrcpy(global_scope,opteq+1);
761                         } else {
762                                 slprintf(p, sizeof(pstring) - (p - options) - 1, "%s=%s,", opts, opteq+1);
763                                 p += strlen(p);
764                         }
765                 } else {
766                         val = 1;
767                         if(!strcmp(opts, "nocaps")) {
768                                 fprintf(stderr, "Unhandled option: %s\n", opteq+1);
769                                 exit(1);
770                         } else if(!strcmp(opts, "guest")) {
771                                 *password = '\0';
772                                 got_pass = True;
773                         } else if(!strcmp(opts, "rw")) {
774                                 mount_ro = 0;
775                         } else if(!strcmp(opts, "ro")) {
776                                 mount_ro = 1;
777                         } else {
778                                 strncpy(p, opts, sizeof(pstring) - (p - options) - 1);
779                                 p += strlen(opts);
780                                 *p++ = ',';
781                                 *p = 0;
782                         }
783                 }
784         }
785
786         if (!*service) {
787                 usage();
788                 exit(1);
789         }
790
791         if (p != options) {
792                 *(p-1) = 0;     /* remove trailing , */
793                 DEBUG(3,("passthrough options '%s'\n", options));
794         }
795 }
796
797 /****************************************************************************
798   main program
799 ****************************************************************************/
800  int main(int argc,char *argv[])
801 {
802         extern char *optarg;
803         extern int optind;
804         char *p;
805
806         DEBUGLEVEL = 1;
807
808         /* here we are interactive, even if run from autofs */
809         setup_logging("mount.smbfs",True);
810
811         /* CLI_FORCE_ASCII=false makes smbmount negotiate unicode. The default
812            is to not announce any unicode capabilities as current smbfs does
813            not support it. */
814         p = getenv("CLI_FORCE_ASCII");
815         if (p && !strcmp(p, "false"))
816                 unsetenv("CLI_FORCE_ASCII");
817         else
818                 setenv("CLI_FORCE_ASCII", "true", 1);
819
820         in_client = True;   /* Make sure that we tell lp_load we are */
821
822         if (getenv("USER")) {
823                 pstrcpy(username,getenv("USER"));
824
825                 if ((p=strchr_m(username,'%'))) {
826                         *p = 0;
827                         pstrcpy(password,p+1);
828                         got_pass = True;
829                         memset(strchr_m(getenv("USER"),'%')+1,'X',strlen(password));
830                 }
831                 strupper(username);
832         }
833
834         if (getenv("PASSWD")) {
835                 pstrcpy(password,getenv("PASSWD"));
836                 got_pass = True;
837         }
838
839         if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
840                 get_password_file();
841                 got_pass = True;
842         }
843
844         if (*username == 0 && getenv("LOGNAME")) {
845                 pstrcpy(username,getenv("LOGNAME"));
846         }
847
848         if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
849                 fprintf(stderr, "Can't load %s - run testparm to debug it\n", 
850                         dyn_CONFIGFILE);
851         }
852
853         parse_mount_smb(argc, argv);
854
855         if (*credentials != 0) {
856                 read_credentials_file(credentials);
857         }
858
859         DEBUG(3,("mount.smbfs started (version %s)\n", VERSION));
860
861         if (*workgroup == 0) {
862                 pstrcpy(workgroup,lp_workgroup());
863         }
864
865         load_interfaces();
866         if (!*my_netbios_name) {
867                 pstrcpy(my_netbios_name, myhostname());
868         }
869         strupper(my_netbios_name);
870
871         init_mount();
872         return 0;
873 }