Removed TimeInit() call from every client program (except for one place
[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 a 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++] = smb_xstrdup(tmp);
456         }
457         if (mount_gid) {
458                 slprintf(tmp, sizeof(tmp)-1, "%d", mount_gid);
459                 args[i++] = "-g";
460                 args[i++] = smb_xstrdup(tmp);
461         }
462         if (mount_fmask) {
463                 slprintf(tmp, sizeof(tmp)-1, "0%o", mount_fmask);
464                 args[i++] = "-f";
465                 args[i++] = smb_xstrdup(tmp);
466         }
467         if (mount_dmask) {
468                 slprintf(tmp, sizeof(tmp)-1, "0%o", mount_dmask);
469                 args[i++] = "-d";
470                 args[i++] = smb_xstrdup(tmp);
471         }
472         if (options) {
473                 args[i++] = "-o";
474                 args[i++] = options;
475         }
476
477         if (sys_fork() == 0) {
478                 char *smbmnt_path;
479
480                 smbmnt_path = asprintf("%s/smbmnt", dyn_BINDIR);
481                 
482                 if (file_exist(smbmnt_path, NULL)) {
483                         execv(smbmnt_path, args);
484                         fprintf(stderr,
485                                 "smbfs/init_mount: execv of %s failed. Error was %s.",
486                                 smbmnt_path, strerror(errno));
487                 } else {
488                         execvp("smbmnt", args);
489                         fprintf(stderr,
490                                 "smbfs/init_mount: execv of %s failed. Error was %s.",
491                                 "smbmnt", strerror(errno));
492                 }
493                 free(smbmnt_path);
494                 exit(1);
495         }
496
497         if (waitpid(-1, &status, 0) == -1) {
498                 fprintf(stderr,"waitpid failed: Error was %s", strerror(errno) );
499                 /* FIXME: do some proper error handling */
500                 exit(1);
501         }
502
503         if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
504                 fprintf(stderr,"smbmnt failed: %d\n", WEXITSTATUS(status));
505                 /* FIXME: do some proper error handling */
506                 exit(1);
507         }
508
509         /* Ok...  This is the rubicon for that mount point...  At any point
510            after this, if the connections fail and can not be reconstructed
511            for any reason, we will have to unmount the mount point.  There
512            is no exit from the next call...
513         */
514         send_fs_socket(service, mount_point, c);
515 }
516
517
518 /****************************************************************************
519 get a password from a a file or file descriptor
520 exit on failure (from smbclient, move to libsmb or shared .c file?)
521 ****************************************************************************/
522 static void get_password_file(void)
523 {
524         int fd = -1;
525         char *p;
526         BOOL close_it = False;
527         pstring spec;
528         char pass[128];
529
530         if ((p = getenv("PASSWD_FD")) != NULL) {
531                 pstrcpy(spec, "descriptor ");
532                 pstrcat(spec, p);
533                 sscanf(p, "%d", &fd);
534                 close_it = False;
535         } else if ((p = getenv("PASSWD_FILE")) != NULL) {
536                 fd = sys_open(p, O_RDONLY, 0);
537                 pstrcpy(spec, p);
538                 if (fd < 0) {
539                         fprintf(stderr, "Error opening PASSWD_FILE %s: %s\n",
540                                 spec, strerror(errno));
541                         exit(1);
542                 }
543                 close_it = True;
544         }
545
546         for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */
547             p && p - pass < sizeof(pass);) {
548                 switch (read(fd, p, 1)) {
549                 case 1:
550                         if (*p != '\n' && *p != '\0') {
551                                 *++p = '\0'; /* advance p, and null-terminate pass */
552                                 break;
553                         }
554                 case 0:
555                         if (p - pass) {
556                                 *p = '\0'; /* null-terminate it, just in case... */
557                                 p = NULL; /* then force the loop condition to become false */
558                                 break;
559                         } else {
560                                 fprintf(stderr, "Error reading password from file %s: %s\n",
561                                         spec, "empty password\n");
562                                 exit(1);
563                         }
564
565                 default:
566                         fprintf(stderr, "Error reading password from file %s: %s\n",
567                                 spec, strerror(errno));
568                         exit(1);
569                 }
570         }
571         pstrcpy(password, pass);
572         if (close_it)
573                 close(fd);
574 }
575
576 /****************************************************************************
577 get username and password from a credentials file
578 exit on failure (from smbclient, move to libsmb or shared .c file?)
579 ****************************************************************************/
580 static void read_credentials_file(char *filename)
581 {
582         FILE *auth;
583         fstring buf;
584         uint16 len = 0;
585         char *ptr, *val, *param;
586
587         if ((auth=sys_fopen(filename, "r")) == NULL)
588         {
589                 /* fail if we can't open the credentials file */
590                 DEBUG(0,("ERROR: Unable to open credentials file!\n"));
591                 exit (-1);
592         }
593
594         while (!feof(auth))
595         {
596                 /* get a line from the file */
597                 if (!fgets (buf, sizeof(buf), auth))
598                         continue;
599                 len = strlen(buf);
600
601                 if ((len) && (buf[len-1]=='\n'))
602                 {
603                         buf[len-1] = '\0';
604                         len--;
605                 }
606                 if (len == 0)
607                         continue;
608
609                 /* break up the line into parameter & value.
610                    will need to eat a little whitespace possibly */
611                 param = buf;
612                 if (!(ptr = strchr (buf, '=')))
613                         continue;
614                 val = ptr+1;
615                 *ptr = '\0';
616
617                 /* eat leading white space */
618                 while ((*val!='\0') && ((*val==' ') || (*val=='\t')))
619                         val++;
620
621                 if (strwicmp("password", param) == 0)
622                 {
623                         pstrcpy(password, val);
624                         got_pass = True;
625                 }
626                 else if (strwicmp("username", param) == 0)
627                         pstrcpy(username, val);
628
629                 memset(buf, 0, sizeof(buf));
630         }
631         fclose(auth);
632 }
633
634
635 /****************************************************************************
636 usage on the program
637 ****************************************************************************/
638 static void usage(void)
639 {
640         printf("Usage: mount.smbfs service mountpoint [-o options,...]\n");
641
642         printf("Version %s\n\n",VERSION);
643
644         printf(
645 "Options:
646       username=<arg>                  SMB username
647       password=<arg>                  SMB password
648       credentials=<filename>          file with username/password
649       netbiosname=<arg>               source NetBIOS name
650       uid=<arg>                       mount uid or username
651       gid=<arg>                       mount gid or groupname
652       port=<arg>                      remote SMB port number
653       fmask=<arg>                     file umask
654       dmask=<arg>                     directory umask
655       debug=<arg>                     debug level
656       ip=<arg>                        destination host or IP address
657       workgroup=<arg>                 workgroup on destination
658       sockopt=<arg>                   TCP socket options
659       scope=<arg>                     NetBIOS scope
660       iocharset=<arg>                 Linux charset (iso8859-1, utf8)
661       codepage=<arg>                  server codepage (cp850)
662       ttl=<arg>                       dircache time to live
663       guest                           don't prompt for a password
664       ro                              mount read-only
665       rw                              mount read-write
666
667 This command is designed to be run from within /bin/mount by giving
668 the option '-t smbfs'. For example:
669   mount -t smbfs -o username=tridge,password=foobar //fjall/test /data/test
670 ");
671 }
672
673
674 /****************************************************************************
675   Argument parsing for mount.smbfs interface
676   mount will call us like this:
677     mount.smbfs device mountpoint -o <options>
678   
679   <options> is never empty, containing at least rw or ro
680  ****************************************************************************/
681 static void parse_mount_smb(int argc, char **argv)
682 {
683         int opt;
684         char *opts;
685         char *opteq;
686         extern char *optarg;
687         int val;
688         extern pstring global_scope;
689         char *p;
690
691         if (argc < 2 || argv[1][0] == '-') {
692                 usage();
693                 exit(1);
694         }
695         
696         pstrcpy(service, argv[1]);
697         pstrcpy(mpoint, argv[2]);
698
699         /* Convert any '/' characters in the service name to
700            '\' characters */
701         string_replace(service, '/','\\');
702         argc -= 2;
703         argv += 2;
704
705         opt = getopt(argc, argv, "o:");
706         if(opt != 'o') {
707                 return;
708         }
709
710         options[0] = 0;
711         p = options;
712
713         /*
714          * option parsing from nfsmount.c (util-linux-2.9u)
715          */
716         for (opts = strtok(optarg, ","); opts; opts = strtok(NULL, ",")) {
717                 DEBUG(3, ("opts: %s\n", opts));
718                 if ((opteq = strchr_m(opts, '='))) {
719                         val = atoi(opteq + 1);
720                         *opteq = '\0';
721
722                         if (!strcmp(opts, "username") || 
723                             !strcmp(opts, "logon")) {
724                                 char *lp;
725                                 pstrcpy(username,opteq+1);
726                                 if ((lp=strchr_m(username,'%'))) {
727                                         *lp = 0;
728                                         pstrcpy(password,lp+1);
729                                         got_pass = True;
730                                         memset(strchr_m(opteq+1,'%')+1,'X',strlen(password));
731                                 }
732                                 if ((lp=strchr_m(username,'/'))) {
733                                         *lp = 0;
734                                         pstrcpy(workgroup,lp+1);
735                                 }
736                         } else if(!strcmp(opts, "passwd") ||
737                                   !strcmp(opts, "password")) {
738                                 pstrcpy(password,opteq+1);
739                                 got_pass = True;
740                                 memset(opteq+1,'X',strlen(password));
741                         } else if(!strcmp(opts, "credentials")) {
742                                 pstrcpy(credentials,opteq+1);
743                         } else if(!strcmp(opts, "netbiosname")) {
744                                 pstrcpy(my_netbios_name,opteq+1);
745                         } else if(!strcmp(opts, "uid")) {
746                                 mount_uid = nametouid(opteq+1);
747                         } else if(!strcmp(opts, "gid")) {
748                                 mount_gid = nametogid(opteq+1);
749                         } else if(!strcmp(opts, "port")) {
750                                 smb_port = val;
751                         } else if(!strcmp(opts, "fmask")) {
752                                 mount_fmask = strtol(opteq+1, NULL, 8);
753                         } else if(!strcmp(opts, "dmask")) {
754                                 mount_dmask = strtol(opteq+1, NULL, 8);
755                         } else if(!strcmp(opts, "debug")) {
756                                 DEBUGLEVEL = val;
757                         } else if(!strcmp(opts, "ip")) {
758                                 dest_ip = *interpret_addr2(opteq+1);
759                                 if (zero_ip(dest_ip)) {
760                                         fprintf(stderr,"Can't resolve address %s\n", opteq+1);
761                                         exit(1);
762                                 }
763                                 have_ip = True;
764                         } else if(!strcmp(opts, "workgroup")) {
765                                 pstrcpy(workgroup,opteq+1);
766                         } else if(!strcmp(opts, "sockopt")) {
767                                 pstrcpy(user_socket_options,opteq+1);
768                         } else if(!strcmp(opts, "scope")) {
769                                 pstrcpy(global_scope,opteq+1);
770                         } else {
771                                 slprintf(p, sizeof(pstring) - (p - options) - 1, "%s=%s,", opts, opteq+1);
772                                 p += strlen(p);
773                         }
774                 } else {
775                         val = 1;
776                         if(!strcmp(opts, "nocaps")) {
777                                 fprintf(stderr, "Unhandled option: %s\n", opteq+1);
778                                 exit(1);
779                         } else if(!strcmp(opts, "guest")) {
780                                 *password = '\0';
781                                 got_pass = True;
782                         } else if(!strcmp(opts, "rw")) {
783                                 mount_ro = 0;
784                         } else if(!strcmp(opts, "ro")) {
785                                 mount_ro = 1;
786                         } else {
787                                 strncpy(p, opts, sizeof(pstring) - (p - options) - 1);
788                                 p += strlen(opts);
789                                 *p++ = ',';
790                                 *p = 0;
791                         }
792                 }
793         }
794
795         if (!*service) {
796                 usage();
797                 exit(1);
798         }
799
800         if (p != options) {
801                 *(p-1) = 0;     /* remove trailing , */
802                 DEBUG(3,("passthrough options '%s'\n", options));
803         }
804 }
805
806 /****************************************************************************
807   main program
808 ****************************************************************************/
809  int main(int argc,char *argv[])
810 {
811         extern char *optarg;
812         extern int optind;
813         static pstring servicesf = dyn_CONFIGFILE;
814         char *p;
815
816         DEBUGLEVEL = 1;
817
818         /* here we are interactive, even if run from autofs */
819         setup_logging("mount.smbfs",True);
820
821         /* CLI_FORCE_ASCII=false makes smbmount negotiate unicode. The default
822            is to not announce any unicode capabilities as current smbfs does
823            not support it. */
824         p = getenv("CLI_FORCE_ASCII");
825         if (p && !strcmp(p, "false"))
826                 unsetenv("CLI_FORCE_ASCII");
827         else
828                 setenv("CLI_FORCE_ASCII", "true", 1);
829
830         in_client = True;   /* Make sure that we tell lp_load we are */
831
832         if (getenv("USER")) {
833                 pstrcpy(username,getenv("USER"));
834
835                 if ((p=strchr_m(username,'%'))) {
836                         *p = 0;
837                         pstrcpy(password,p+1);
838                         got_pass = True;
839                         memset(strchr_m(getenv("USER"),'%')+1,'X',strlen(password));
840                 }
841                 strupper(username);
842         }
843
844         if (getenv("PASSWD")) {
845                 pstrcpy(password,getenv("PASSWD"));
846                 got_pass = True;
847         }
848
849         if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
850                 get_password_file();
851                 got_pass = True;
852         }
853
854         if (*username == 0 && getenv("LOGNAME")) {
855                 pstrcpy(username,getenv("LOGNAME"));
856         }
857
858         if (!lp_load(servicesf,True,False,False)) {
859                 fprintf(stderr, "Can't load %s - run testparm to debug it\n", 
860                         servicesf);
861         }
862
863         parse_mount_smb(argc, argv);
864
865         if (*credentials != 0) {
866                 read_credentials_file(credentials);
867         }
868
869         DEBUG(3,("mount.smbfs started (version %s)\n", VERSION));
870
871         if (*workgroup == 0) {
872                 pstrcpy(workgroup,lp_workgroup());
873         }
874
875         load_interfaces();
876         if (!*my_netbios_name) {
877                 pstrcpy(my_netbios_name, myhostname());
878         }
879         strupper(my_netbios_name);
880
881         init_mount();
882         return 0;
883 }