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