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#define NO_SYSLOG
22
23#include "includes.h"
24
25#include <mntent.h>
26#include <asm/types.h>
27#include <linux/smb_fs.h>
28
29extern BOOL in_client;
30extern pstring user_socket_options;
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(NULL)) || (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 (!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				!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			/* redirect stdout & stderr since we can't know that
392			   the library functions we use are using DEBUG. */
393			if ( (fd = open("/dev/null", O_WRONLY)) < 0)
394				DEBUG(2,("mount.smbfs: can't open /dev/null\n"));
395			close_our_files(fd);
396			if (fd >= 0) {
397				dup2(fd, STDOUT_FILENO);
398				dup2(fd, STDERR_FILENO);
399				close(fd);
400			}
401
402			/* here we are no longer interactive */
403			set_remote_machine_name("smbmount", False);	/* sneaky ... */
404			setup_logging("mount.smbfs", False);
405			reopen_logs();
406			DEBUG(0, ("mount.smbfs: entering daemon mode for service %s, pid=%d\n", the_service, sys_getpid()));
407
408			closed = 1;
409		}
410
411		/* Wait for a signal from smbfs ... but don't continue
412                   until we actually get a new connection. */
413		while (!c) {
414			CatchSignal(SIGUSR1, &usr1_handler);
415			pause();
416			DEBUG(2,("mount.smbfs[%d]: got signal, getting new socket\n", sys_getpid()));
417			c = do_connection(the_service);
418		}
419	}
420
421	smb_umount(mount_point);
422	DEBUG(2,("mount.smbfs[%d]: exit\n", sys_getpid()));
423	exit(1);
424}
425
426
427/**
428 * Mount a smbfs
429 **/
430static void init_mount(void)
431{
432	char mount_point[PATH_MAX+1];
433	pstring tmp;
434	pstring svc2;
435	struct cli_state *c;
436	char *args[20];
437	int i, status;
438
439	if (realpath(mpoint, mount_point) == NULL) {
440		fprintf(stderr, "Could not resolve mount point %s\n", mpoint);
441		return;
442	}
443
444
445	c = do_connection(service);
446	if (!c) {
447		fprintf(stderr,"SMB connection failed\n");
448		exit(1);
449	}
450
451	/*
452		Set up to return as a daemon child and wait in the parent
453		until the child say it's ready...
454	*/
455	daemonize();
456
457	pstrcpy(svc2, service);
458	string_replace(svc2, '\\','/');
459	string_replace(svc2, ' ','_');
460
461	memset(args, 0, sizeof(args[0])*20);
462
463	i=0;
464	args[i++] = "smbmnt";
465
466	args[i++] = mount_point;
467	args[i++] = "-s";
468	args[i++] = svc2;
469
470	if (mount_ro) {
471		args[i++] = "-r";
472	}
473	if (mount_uid) {
474		slprintf(tmp, sizeof(tmp)-1, "%d", mount_uid);
475		args[i++] = "-u";
476		args[i++] = smb_xstrdup(tmp);
477	}
478	if (mount_gid) {
479		slprintf(tmp, sizeof(tmp)-1, "%d", mount_gid);
480		args[i++] = "-g";
481		args[i++] = smb_xstrdup(tmp);
482	}
483	if (mount_fmask) {
484		slprintf(tmp, sizeof(tmp)-1, "0%o", mount_fmask);
485		args[i++] = "-f";
486		args[i++] = smb_xstrdup(tmp);
487	}
488	if (mount_dmask) {
489		slprintf(tmp, sizeof(tmp)-1, "0%o", mount_dmask);
490		args[i++] = "-d";
491		args[i++] = smb_xstrdup(tmp);
492	}
493	if (options) {
494		args[i++] = "-o";
495		args[i++] = options;
496	}
497
498	if (sys_fork() == 0) {
499		char *smbmnt_path;
500
501		asprintf(&smbmnt_path, "%s/smbmnt", dyn_BINDIR);
502
503		if (file_exist(smbmnt_path, NULL)) {
504			execv(smbmnt_path, args);
505			fprintf(stderr,
506				"smbfs/init_mount: execv of %s failed. Error was %s.",
507				smbmnt_path, strerror(errno));
508		} else {
509			execvp("smbmnt", args);
510			fprintf(stderr,
511				"smbfs/init_mount: execv of %s failed. Error was %s.",
512				"smbmnt", strerror(errno));
513		}
514		free(smbmnt_path);
515		exit(1);
516	}
517
518	if (waitpid(-1, &status, 0) == -1) {
519		fprintf(stderr,"waitpid failed: Error was %s", strerror(errno) );
520		/* FIXME: do some proper error handling */
521		exit(1);
522	}
523
524	if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
525		fprintf(stderr,"smbmnt failed: %d\n", WEXITSTATUS(status));
526		/* FIXME: do some proper error handling */
527		exit(1);
528	} else if (WIFSIGNALED(status)) {
529		fprintf(stderr, "smbmnt killed by signal %d\n", WTERMSIG(status));
530		exit(1);
531	}
532
533	/* Ok...  This is the rubicon for that mount point...  At any point
534	   after this, if the connections fail and can not be reconstructed
535	   for any reason, we will have to unmount the mount point.  There
536	   is no exit from the next call...
537	*/
538	send_fs_socket(service, mount_point, c);
539}
540
541
542/****************************************************************************
543get a password from a a file or file descriptor
544exit on failure (from smbclient, move to libsmb or shared .c file?)
545****************************************************************************/
546static void get_password_file(void)
547{
548	int fd = -1;
549	char *p;
550	BOOL close_it = False;
551	pstring spec;
552	char pass[128];
553
554	if ((p = getenv("PASSWD_FD")) != NULL) {
555		pstrcpy(spec, "descriptor ");
556		pstrcat(spec, p);
557		sscanf(p, "%d", &fd);
558		close_it = False;
559	} else if ((p = getenv("PASSWD_FILE")) != NULL) {
560		fd = sys_open(p, O_RDONLY, 0);
561		pstrcpy(spec, p);
562		if (fd < 0) {
563			fprintf(stderr, "Error opening PASSWD_FILE %s: %s\n",
564				spec, strerror(errno));
565			exit(1);
566		}
567		close_it = True;
568	}
569
570	for(p = pass, *p = '\0'; /* ensure that pass is null-terminated */
571	    p && p - pass < sizeof(pass);) {
572		switch (read(fd, p, 1)) {
573		case 1:
574			if (*p != '\n' && *p != '\0') {
575				*++p = '\0'; /* advance p, and null-terminate pass */
576				break;
577			}
578		case 0:
579			if (p - pass) {
580				*p = '\0'; /* null-terminate it, just in case... */
581				p = NULL; /* then force the loop condition to become false */
582				break;
583			} else {
584				fprintf(stderr, "Error reading password from file %s: %s\n",
585					spec, "empty password\n");
586				exit(1);
587			}
588
589		default:
590			fprintf(stderr, "Error reading password from file %s: %s\n",
591				spec, strerror(errno));
592			exit(1);
593		}
594	}
595	pstrcpy(password, pass);
596	if (close_it)
597		close(fd);
598}
599
600/****************************************************************************
601get username and password from a credentials file
602exit on failure (from smbclient, move to libsmb or shared .c file?)
603****************************************************************************/
604static void read_credentials_file(char *filename)
605{
606	FILE *auth;
607	fstring buf;
608	uint16 len = 0;
609	char *ptr, *val, *param;
610
611	if ((auth=sys_fopen(filename, "r")) == NULL)
612	{
613		/* fail if we can't open the credentials file */
614		DEBUG(0,("ERROR: Unable to open credentials file!\n"));
615		exit (-1);
616	}
617
618	while (!feof(auth))
619	{
620		/* get a line from the file */
621		if (!fgets (buf, sizeof(buf), auth))
622			continue;
623		len = strlen(buf);
624
625		if ((len) && (buf[len-1]=='\n'))
626		{
627			buf[len-1] = '\0';
628			len--;
629		}
630		if (len == 0)
631			continue;
632
633		/* break up the line into parameter & value.
634		   will need to eat a little whitespace possibly */
635		param = buf;
636		if (!(ptr = strchr (buf, '=')))
637			continue;
638		val = ptr+1;
639		*ptr = '\0';
640
641		/* eat leading white space */
642		while ((*val!='\0') && ((*val==' ') || (*val=='\t')))
643			val++;
644
645		if (strwicmp("password", param) == 0)
646		{
647			pstrcpy(password, val);
648			got_pass = True;
649		}
650		else if (strwicmp("username", param) == 0) {
651			pstrcpy(username, val);
652		}
653
654		memset(buf, 0, sizeof(buf));
655	}
656	fclose(auth);
657}
658
659
660/****************************************************************************
661usage on the program
662****************************************************************************/
663static void usage(void)
664{
665	printf("Usage: mount.smbfs service mountpoint [-o options,...]\n");
666
667	printf("Version %s\n\n",SAMBA_VERSION_STRING);
668
669	printf(
670"Options:\n\
671      username=<arg>                  SMB username\n\
672      password=<arg>                  SMB password\n\
673      credentials=<filename>          file with username/password\n\
674      krb                             use kerberos (active directory)\n\
675      netbiosname=<arg>               source NetBIOS name\n\
676      uid=<arg>                       mount uid or username\n\
677      gid=<arg>                       mount gid or groupname\n\
678      port=<arg>                      remote SMB port number\n\
679      fmask=<arg>                     file umask\n\
680      dmask=<arg>                     directory umask\n\
681      debug=<arg>                     debug level\n\
682      ip=<arg>                        destination host or IP address\n\
683      workgroup=<arg>                 workgroup on destination\n\
684      sockopt=<arg>                   TCP socket options\n\
685      scope=<arg>                     NetBIOS scope\n\
686      iocharset=<arg>                 Linux charset (iso8859-1, utf8)\n\
687      codepage=<arg>                  server codepage (cp850)\n\
688      unicode                         use unicode when communicating with server\n\
689      lfs                             large file system support\n\
690      ttl=<arg>                       dircache time to live\n\
691      guest                           don't prompt for a password\n\
692      ro                              mount read-only\n\
693      rw                              mount read-write\n\
694\n\
695This command is designed to be run from within /bin/mount by giving\n\
696the option '-t smbfs'. For example:\n\
697  mount -t smbfs -o username=tridge,password=foobar //fjall/test /data/test\n\
698");
699}
700
701
702/****************************************************************************
703  Argument parsing for mount.smbfs interface
704  mount will call us like this:
705    mount.smbfs device mountpoint -o <options>
706
707  <options> is never empty, containing at least rw or ro
708 ****************************************************************************/
709static void parse_mount_smb(int argc, char **argv)
710{
711	int opt;
712	char *opts;
713	char *opteq;
714	extern char *optarg;
715	int val;
716	char *p;
717
718	/* FIXME: This function can silently fail if the arguments are
719	 * not in the expected order.
720
721	> The arguments syntax of smbmount 2.2.3a (smbfs of Debian stable)
722	> requires that one gives "-o" before further options like username=...
723	> . Without -o, the username=.. setting is *silently* ignored. I've
724	> spent about an hour trying to find out why I couldn't log in now..
725
726	*/
727
728
729	if (argc < 2 || argv[1][0] == '-') {
730		usage();
731		exit(1);
732	}
733
734	pstrcpy(service, argv[1]);
735	pstrcpy(mpoint, argv[2]);
736
737	/* Convert any '/' characters in the service name to
738	   '\' characters */
739	string_replace(service, '/','\\');
740	argc -= 2;
741	argv += 2;
742
743	opt = getopt(argc, argv, "o:");
744	if(opt != 'o') {
745		return;
746	}
747
748	options[0] = 0;
749	p = options;
750
751	/*
752	 * option parsing from nfsmount.c (util-linux-2.9u)
753	 */
754        for (opts = strtok(optarg, ","); opts; opts = strtok(NULL, ",")) {
755		DEBUG(3, ("opts: %s\n", opts));
756                if ((opteq = strchr_m(opts, '='))) {
757                        val = atoi(opteq + 1);
758                        *opteq = '\0';
759
760                        if (!strcmp(opts, "username") ||
761			    !strcmp(opts, "logon")) {
762				char *lp;
763				got_user = True;
764				pstrcpy(username,opteq+1);
765				if ((lp=strchr_m(username,'%'))) {
766					*lp = 0;
767					pstrcpy(password,lp+1);
768					got_pass = True;
769					memset(strchr_m(opteq+1,'%')+1,'X',strlen(password));
770				}
771				if ((lp=strchr_m(username,'/'))) {
772					*lp = 0;
773					pstrcpy(workgroup,lp+1);
774				}
775			} else if(!strcmp(opts, "passwd") ||
776				  !strcmp(opts, "password")) {
777				pstrcpy(password,opteq+1);
778				got_pass = True;
779				memset(opteq+1,'X',strlen(password));
780			} else if(!strcmp(opts, "credentials")) {
781				pstrcpy(credentials,opteq+1);
782			} else if(!strcmp(opts, "netbiosname")) {
783				pstrcpy(my_netbios_name,opteq+1);
784			} else if(!strcmp(opts, "uid")) {
785				mount_uid = nametouid(opteq+1);
786			} else if(!strcmp(opts, "gid")) {
787				mount_gid = nametogid(opteq+1);
788			} else if(!strcmp(opts, "port")) {
789				smb_port = val;
790			} else if(!strcmp(opts, "fmask")) {
791				mount_fmask = strtol(opteq+1, NULL, 8);
792			} else if(!strcmp(opts, "dmask")) {
793				mount_dmask = strtol(opteq+1, NULL, 8);
794			} else if(!strcmp(opts, "debug")) {
795				DEBUGLEVEL = val;
796			} else if(!strcmp(opts, "ip")) {
797				dest_ip = *interpret_addr2(opteq+1);
798				if (is_zero_ip(dest_ip)) {
799					fprintf(stderr,"Can't resolve address %s\n", opteq+1);
800					exit(1);
801				}
802				have_ip = True;
803			} else if(!strcmp(opts, "workgroup")) {
804				pstrcpy(workgroup,opteq+1);
805			} else if(!strcmp(opts, "sockopt")) {
806				pstrcpy(user_socket_options,opteq+1);
807			} else if(!strcmp(opts, "scope")) {
808				set_global_scope(opteq+1);
809			} else {
810				slprintf(p, sizeof(pstring) - (p - options) - 1, "%s=%s,", opts, opteq+1);
811				p += strlen(p);
812			}
813		} else {
814			val = 1;
815			if(!strcmp(opts, "nocaps")) {
816				fprintf(stderr, "Unhandled option: %s\n", opteq+1);
817				exit(1);
818			} else if(!strcmp(opts, "guest")) {
819				*password = '\0';
820				got_pass = True;
821			} else if(!strcmp(opts, "krb")) {
822#ifdef HAVE_KRB5
823
824				use_kerberos = True;
825				if(!status32_smbfs)
826					fprintf(stderr, "Warning: kerberos support will only work for samba servers\n");
827#else
828				fprintf(stderr,"No kerberos support compiled in\n");
829				exit(1);
830#endif
831			} else if(!strcmp(opts, "rw")) {
832				mount_ro = 0;
833			} else if(!strcmp(opts, "ro")) {
834				mount_ro = 1;
835			} else if(!strcmp(opts, "unicode")) {
836				smbfs_has_unicode = True;
837			} else if(!strcmp(opts, "lfs")) {
838				smbfs_has_lfs = True;
839			} else {
840				strncpy(p, opts, sizeof(pstring) - (p - options) - 1);
841				p += strlen(opts);
842				*p++ = ',';
843				*p = 0;
844			}
845		}
846	}
847
848	if (!*service) {
849		usage();
850		exit(1);
851	}
852
853	if (p != options) {
854		*(p-1) = 0;	/* remove trailing , */
855		DEBUG(3,("passthrough options '%s'\n", options));
856	}
857}
858
859/****************************************************************************
860  main program
861****************************************************************************/
862 int main(int argc,char *argv[])
863{
864	extern char *optarg;
865	extern int optind;
866	char *p;
867
868	DEBUGLEVEL = 1;
869
870	/* here we are interactive, even if run from autofs */
871	setup_logging("mount.smbfs",True);
872
873#if 0 /* JRA - Urban says not needed ? */
874	/* CLI_FORCE_ASCII=false makes smbmount negotiate unicode. The default
875	   is to not announce any unicode capabilities as current smbfs does
876	   not support it. */
877	p = getenv("CLI_FORCE_ASCII");
878	if (p && !strcmp(p, "false"))
879		unsetenv("CLI_FORCE_ASCII");
880	else
881		setenv("CLI_FORCE_ASCII", "true", 1);
882#endif
883
884	in_client = True;   /* Make sure that we tell lp_load we are */
885
886	if (getenv("USER")) {
887		pstrcpy(username,getenv("USER"));
888
889		if ((p=strchr_m(username,'%'))) {
890			*p = 0;
891			pstrcpy(password,p+1);
892			got_pass = True;
893			memset(strchr_m(getenv("USER"),'%')+1,'X',strlen(password));
894		}
895		strupper_m(username);
896	}
897
898	if (getenv("PASSWD")) {
899		pstrcpy(password,getenv("PASSWD"));
900		got_pass = True;
901	}
902
903	if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) {
904		get_password_file();
905		got_pass = True;
906	}
907
908	if (*username == 0 && getenv("LOGNAME")) {
909		pstrcpy(username,getenv("LOGNAME"));
910	}
911
912	if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
913		fprintf(stderr, "Can't load %s - run testparm to debug it\n",
914			dyn_CONFIGFILE);
915	}
916
917	parse_mount_smb(argc, argv);
918
919	if (use_kerberos && !got_user) {
920		got_pass = True;
921	}
922
923	if (*credentials != 0) {
924		read_credentials_file(credentials);
925	}
926
927	DEBUG(3,("mount.smbfs started (version %s)\n", SAMBA_VERSION_STRING));
928
929	if (*workgroup == 0) {
930		pstrcpy(workgroup,lp_workgroup());
931	}
932
933	load_interfaces();
934	if (!*my_netbios_name) {
935		pstrcpy(my_netbios_name, myhostname());
936	}
937	strupper_m(my_netbios_name);
938
939	init_mount();
940	return 0;
941}
942