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