Remove xstrdup since it was added to lib/util.c. Caused compile failure
[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
32 extern BOOL in_client;
33 extern pstring user_socket_options;
34 extern BOOL append_log;
35 extern fstring remote_machine;
36
37 static pstring credentials;
38 static pstring my_netbios_name;
39 static pstring password;
40 static pstring username;
41 static pstring workgroup;
42 static pstring mpoint;
43 static pstring service;
44 static pstring options;
45
46 static struct in_addr dest_ip;
47 static BOOL have_ip;
48 static int smb_port = 0;
49 static BOOL got_pass;
50 static uid_t mount_uid;
51 static gid_t mount_gid;
52 static int mount_ro;
53 static unsigned mount_fmask;
54 static unsigned mount_dmask;
55
56 static void usage(void);
57
58 static void exit_parent(int sig)
59 {
60         /* parent simply exits when child says go... */
61         exit(0);
62 }
63
64 static void daemonize(void)
65 {
66         int j, status;
67         pid_t child_pid;
68
69         signal( SIGTERM, exit_parent );
70
71         if ((child_pid = sys_fork()) < 0) {
72                 DEBUG(0,("could not fork\n"));
73         }
74
75         if (child_pid > 0) {
76                 while( 1 ) {
77                         j = waitpid( child_pid, &status, 0 );
78                         if( j < 0 ) {
79                                 if( EINTR == errno ) {
80                                         continue;
81                                 }
82                                 status = errno;
83                         }
84                         break;
85                 }
86                 /* If we get here - the child exited with some error status */
87                 exit(status);
88         }
89
90         signal( SIGTERM, SIG_DFL );
91         chdir("/");
92 }
93
94 static void close_our_files(int client_fd)
95 {
96         int i;
97         struct rlimit limits;
98
99         getrlimit(RLIMIT_NOFILE,&limits);
100         for (i = 0; i< limits.rlim_max; i++) {
101                 if (i == client_fd)
102                         continue;
103                 close(i);
104         }
105 }
106
107 static void usr1_handler(int x)
108 {
109         return;
110 }
111
112
113 /***************************************************** 
114 return a connection to a server
115 *******************************************************/
116 static struct cli_state *do_connection(char *service)
117 {
118         struct cli_state *c;
119         struct nmb_name called, calling;
120         char *server_n;
121         struct in_addr ip;
122         extern struct in_addr ipzero;
123         pstring server;
124         char *share;
125
126         if (service[0] != '\\' || service[1] != '\\') {
127                 usage();
128                 exit(1);
129         }
130
131         pstrcpy(server, service+2);
132         share = strchr_m(server,'\\');
133         if (!share) {
134                 usage();
135                 exit(1);
136         }
137         *share = 0;
138         share++;
139
140         server_n = server;
141
142         make_nmb_name(&calling, my_netbios_name, 0x0);
143         make_nmb_name(&called , server, 0x20);
144
145  again:
146         ip = ipzero;
147         if (have_ip) ip = dest_ip;
148
149         /* have to open a new connection */
150         if (!(c=cli_initialise(NULL)) || (cli_set_port(c, smb_port) != smb_port) ||
151             !cli_connect(c, server_n, &ip)) {
152                 DEBUG(0,("%d: Connection to %s failed\n", getpid(), server_n));
153                 if (c) {
154                         cli_shutdown(c);
155                         SAFE_FREE(c);
156                 }
157                 return NULL;
158         }
159
160         if (!cli_session_request(c, &calling, &called)) {
161                 char *p;
162                 DEBUG(0,("%d: session request to %s failed (%s)\n", 
163                          getpid(), called.name, cli_errstr(c)));
164                 cli_shutdown(c);
165                 SAFE_FREE(c);
166                 if ((p=strchr_m(called.name, '.'))) {
167                         *p = 0;
168                         goto again;
169                 }
170                 if (strcmp(called.name, "*SMBSERVER")) {
171                         make_nmb_name(&called , "*SMBSERVER", 0x20);
172                         goto again;
173                 }
174                 return NULL;
175         }
176
177         DEBUG(4,("%d: session request ok\n", getpid()));
178
179         if (!cli_negprot(c)) {
180                 DEBUG(0,("%d: protocol negotiation failed\n", getpid()));
181                 cli_shutdown(c);
182                 SAFE_FREE(c);
183                 return NULL;
184         }
185
186         if (!got_pass) {
187                 char *pass = getpass("Password: ");
188                 if (pass) {
189                         pstrcpy(password, pass);
190                 }
191         }
192
193         if (!cli_session_setup(c, username, 
194                                password, strlen(password),
195                                password, strlen(password),
196                                workgroup)) {
197                 /* if a password was not supplied then try again with a
198                         null username */
199                 if (password[0] || !username[0] ||
200                                 !cli_session_setup(c, "", "", 0, "", 0, workgroup)) {
201                         DEBUG(0,("%d: session setup failed: %s\n",
202                                 getpid(), cli_errstr(c)));
203                         cli_shutdown(c);
204                         SAFE_FREE(c);
205                         return NULL;
206                 }
207                 DEBUG(0,("Anonymous login successful\n"));
208         }
209
210         DEBUG(4,("%d: session setup ok\n", getpid()));
211
212         if (!cli_send_tconX(c, share, "?????",
213                             password, strlen(password)+1)) {
214                 DEBUG(0,("%d: tree connect failed: %s\n",
215                          getpid(), cli_errstr(c)));
216                 cli_shutdown(c);
217                 SAFE_FREE(c);
218                 return NULL;
219         }
220
221         DEBUG(4,("%d: tconx ok\n", getpid()));
222
223         got_pass = True;
224
225         return c;
226 }
227
228
229 /****************************************************************************
230 unmount smbfs  (this is a bailout routine to clean up if a reconnect fails)
231         Code blatently stolen from smbumount.c
232                 -mhw-
233 ****************************************************************************/
234 static void smb_umount(char *mount_point)
235 {
236         int fd;
237         struct mntent *mnt;
238         FILE* mtab;
239         FILE* new_mtab;
240
241         /* Programmers Note:
242                 This routine only gets called to the scene of a disaster
243                 to shoot the survivors...  A connection that was working
244                 has now apparently failed.  We have an active mount point
245                 (presumably) that we need to dump.  If we get errors along
246                 the way - make some noise, but we are already turning out
247                 the lights to exit anyways...
248         */
249         if (umount(mount_point) != 0) {
250                 DEBUG(0,("%d: Could not umount %s: %s\n",
251                          getpid(), mount_point, strerror(errno)));
252                 return;
253         }
254
255         if ((fd = open(MOUNTED"~", O_RDWR|O_CREAT|O_EXCL, 0600)) == -1) {
256                 DEBUG(0,("%d: Can't get "MOUNTED"~ lock file", getpid()));
257                 return;
258         }
259
260         close(fd);
261         
262         if ((mtab = setmntent(MOUNTED, "r")) == NULL) {
263                 DEBUG(0,("%d: Can't open " MOUNTED ": %s\n",
264                          getpid(), strerror(errno)));
265                 return;
266         }
267
268 #define MOUNTED_TMP MOUNTED".tmp"
269
270         if ((new_mtab = setmntent(MOUNTED_TMP, "w")) == NULL) {
271                 DEBUG(0,("%d: Can't open " MOUNTED_TMP ": %s\n",
272                          getpid(), strerror(errno)));
273                 endmntent(mtab);
274                 return;
275         }
276
277         while ((mnt = getmntent(mtab)) != NULL) {
278                 if (strcmp(mnt->mnt_dir, mount_point) != 0) {
279                         addmntent(new_mtab, mnt);
280                 }
281         }
282
283         endmntent(mtab);
284
285         if (fchmod (fileno (new_mtab), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
286                 DEBUG(0,("%d: Error changing mode of %s: %s\n",
287                          getpid(), MOUNTED_TMP, strerror(errno)));
288                 return;
289         }
290
291         endmntent(new_mtab);
292
293         if (rename(MOUNTED_TMP, MOUNTED) < 0) {
294                 DEBUG(0,("%d: Cannot rename %s to %s: %s\n",
295                          getpid(), MOUNTED, MOUNTED_TMP, strerror(errno)));
296                 return;
297         }
298
299         if (unlink(MOUNTED"~") == -1) {
300                 DEBUG(0,("%d: Can't remove "MOUNTED"~", getpid()));
301                 return;
302         }
303 }
304
305
306 /*
307  * Call the smbfs ioctl to install a connection socket,
308  * then wait for a signal to reconnect. Note that we do
309  * not exit after open_sockets() or send_login() errors,
310  * as the smbfs mount would then have no way to recover.
311  */
312 static void send_fs_socket(char *service, char *mount_point, struct cli_state *c)
313 {
314         int fd, closed = 0, res = 1;
315         pid_t parentpid = getppid();
316         struct smb_conn_opt conn_options;
317
318         memset(&conn_options, 0, sizeof(conn_options));
319
320         while (1) {
321                 if ((fd = open(mount_point, O_RDONLY)) < 0) {
322                         DEBUG(0,("mount.smbfs[%d]: can't open %s\n",
323                                  getpid(), mount_point));
324                         break;
325                 }
326
327                 conn_options.fd = c->fd;
328                 conn_options.protocol = c->protocol;
329                 conn_options.case_handling = SMB_CASE_DEFAULT;
330                 conn_options.max_xmit = c->max_xmit;
331                 conn_options.server_uid = c->vuid;
332                 conn_options.tid = c->cnum;
333                 conn_options.secmode = c->sec_mode;
334                 conn_options.rawmode = 0;
335                 conn_options.sesskey = c->sesskey;
336                 conn_options.maxraw = 0;
337                 conn_options.capabilities = c->capabilities;
338                 conn_options.serverzone = c->serverzone/60;
339
340                 res = ioctl(fd, SMB_IOC_NEWCONN, &conn_options);
341                 if (res != 0) {
342                         DEBUG(0,("mount.smbfs[%d]: ioctl failed, res=%d\n",
343                                  getpid(), res));
344                         close(fd);
345                         break;
346                 }
347
348                 if (parentpid) {
349                         /* Ok...  We are going to kill the parent.  Now
350                                 is the time to break the process group... */
351                         setsid();
352                         /* Send a signal to the parent to terminate */
353                         kill(parentpid, SIGTERM);
354                         parentpid = 0;
355                 }
356
357                 close(fd);
358
359                 /* This looks wierd but we are only closing the userspace
360                    side, the connection has already been passed to smbfs and 
361                    it has increased the usage count on the socket.
362
363                    If we don't do this we will "leak" sockets and memory on
364                    each reconnection we have to make. */
365                 cli_shutdown(c);
366                 SAFE_FREE(c);
367
368                 if (!closed) {
369                         /* redirect stdout & stderr since we can't know that
370                            the library functions we use are using DEBUG. */
371                         if ( (fd = open("/dev/null", O_WRONLY)) < 0)
372                                 DEBUG(2,("mount.smbfs: can't open /dev/null\n"));
373                         close_our_files(fd);
374                         if (fd >= 0) {
375                                 dup2(fd, STDOUT_FILENO);
376                                 dup2(fd, STDERR_FILENO);
377                                 close(fd);
378                         }
379
380                         /* here we are no longer interactive */
381                         pstrcpy(remote_machine, "smbmount");    /* sneaky ... */
382                         setup_logging("mount.smbfs", False);
383                         append_log = True;
384                         reopen_logs();
385                         DEBUG(0, ("mount.smbfs: entering daemon mode for service %s, pid=%d\n", service, getpid()));
386
387                         closed = 1;
388                 }
389
390                 /* Wait for a signal from smbfs ... but don't continue
391                    until we actually get a new connection. */
392                 while (!c) {
393                         CatchSignal(SIGUSR1, &usr1_handler);
394                         pause();
395                         DEBUG(2,("mount.smbfs[%d]: got signal, getting new socket\n", getpid()));
396                         c = do_connection(service);
397                 }
398         }
399
400         smb_umount(mount_point);
401         DEBUG(2,("mount.smbfs[%d]: exit\n", getpid()));
402         exit(1);
403 }
404
405
406 /****************************************************************************
407 mount smbfs
408 ****************************************************************************/
409 static void init_mount(void)
410 {
411         char mount_point[MAXPATHLEN+1];
412         pstring tmp;
413         pstring svc2;
414         struct cli_state *c;
415         char *args[20];
416         int i, status;
417
418         if (realpath(mpoint, mount_point) == NULL) {
419                 fprintf(stderr, "Could not resolve mount point %s\n", mpoint);
420                 return;
421         }
422
423
424         c = do_connection(service);
425         if (!c) {
426                 fprintf(stderr,"SMB connection failed\n");
427                 exit(1);
428         }
429
430         /*
431                 Set up to return as a daemon child and wait in the parent
432                 until the child say it's ready...
433         */
434         daemonize();
435
436         pstrcpy(svc2, service);
437         string_replace(svc2, '\\','/');
438         string_replace(svc2, ' ','_');
439
440         memset(args, 0, sizeof(args[0])*20);
441
442         i=0;
443         args[i++] = "smbmnt";
444
445         args[i++] = mount_point;
446         args[i++] = "-s";
447         args[i++] = svc2;
448
449         if (mount_ro) {
450                 args[i++] = "-r";
451         }
452         if (mount_uid) {
453                 slprintf(tmp, sizeof(tmp)-1, "%d", mount_uid);
454                 args[i++] = "-u";
455                 args[i++] = xstrdup(tmp);
456         }
457         if (mount_gid) {
458                 slprintf(tmp, sizeof(tmp)-1, "%d", mount_gid);
459                 args[i++] = "-g";
460                 args[i++] = xstrdup(tmp);
461         }
462         if (mount_fmask) {
463                 slprintf(tmp, sizeof(tmp)-1, "0%o", mount_fmask);
464                 args[i++] = "-f";
465                 args[i++] = xstrdup(tmp);
466         }
467         if (mount_dmask) {
468                 slprintf(tmp, sizeof(tmp)-1, "0%o", mount_dmask);
469                 args[i++] = "-d";
470                 args[i++] = xstrdup(tmp);
471         }
472         if (options) {
473                 args[i++] = "-o";
474                 args[i++] = options;
475         }
476
477         if (sys_fork() == 0) {
478                 if (file_exist(BINDIR "/smbmnt", NULL)) {
479                         execv(BINDIR "/smbmnt", args);
480                         fprintf(stderr,"execv of %s failed. Error was %s.", BINDIR "/smbmnt", strerror(errno));
481                 } else {
482                         execvp("smbmnt", args);
483                         fprintf(stderr,"execvp of smbmnt failed. Error was %s.", strerror(errno) );
484                 }
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 (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         static pstring servicesf = CONFIGFILE;
805         char *p;
806
807         DEBUGLEVEL = 1;
808
809         /* here we are interactive, even if run from autofs */
810         setup_logging("mount.smbfs",True);
811
812         /* CLI_FORCE_ASCII=false makes smbmount negotiate unicode. The default
813            is to not announce any unicode capabilities as current smbfs does
814            not support it. */
815         p = getenv("CLI_FORCE_ASCII");
816         if (p && !strcmp(p, "false"))
817                 unsetenv("CLI_FORCE_ASCII");
818         else
819                 setenv("CLI_FORCE_ASCII", "true", 1);
820
821         TimeInit();
822         
823         in_client = True;   /* Make sure that we tell lp_load we are */
824
825         if (getenv("USER")) {
826                 pstrcpy(username,getenv("USER"));
827
828                 if ((p=strchr_m(username,'%'))) {
829                         *p = 0;
830                         pstrcpy(password,p+1);
831                         got_pass = True;
832                         memset(strchr_m(getenv("USER"),'%')+1,'X',strlen(password));
833                 }
834                 strupper(username);
835         }
836
837         if (getenv("PASSWD")) {
838                 pstrcpy(password,getenv("PASSWD"));
839                 got_pass = True;
840         }
841
842         if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
843                 get_password_file();
844                 got_pass = True;
845         }
846
847         if (*username == 0 && getenv("LOGNAME")) {
848                 pstrcpy(username,getenv("LOGNAME"));
849         }
850
851         if (!lp_load(servicesf,True,False,False)) {
852                 fprintf(stderr, "Can't load %s - run testparm to debug it\n", 
853                         servicesf);
854         }
855
856         parse_mount_smb(argc, argv);
857
858         if (*credentials != 0) {
859                 read_credentials_file(credentials);
860         }
861
862         DEBUG(3,("mount.smbfs started (version %s)\n", VERSION));
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 }