1/*
2   Unix SMB/CIFS implementation.
3   SMB wrapper functions
4   Copyright (C) Andrew Tridgell 1998
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#include "realcalls.h"
23
24pstring smbw_cwd;
25
26static struct smbw_file *smbw_files;
27static struct smbw_server *smbw_srvs;
28
29struct bitmap *smbw_file_bmap;
30
31fstring smbw_prefix = SMBW_PREFIX;
32
33int smbw_busy=0;
34
35/* needs to be here because of dumb include files on some systems */
36int creat_bits = O_WRONLY|O_CREAT|O_TRUNC;
37
38
39/*****************************************************
40initialise structures
41*******************************************************/
42void smbw_init(void)
43{
44	extern BOOL in_client;
45	static int initialised;
46	char *p;
47	int eno;
48	pstring line;
49
50	if (initialised) return;
51	initialised = 1;
52
53	eno = errno;
54
55	smbw_busy++;
56
57	DEBUGLEVEL = 0;
58	setup_logging("smbsh",True);
59
60	dbf = x_stderr;
61
62	if ((p=smbw_getshared("LOGFILE"))) {
63		dbf = sys_fopen(p, "a");
64	}
65
66	smbw_file_bmap = bitmap_allocate(SMBW_MAX_OPEN);
67	if (!smbw_file_bmap) {
68		exit(1);
69	}
70
71	in_client = True;
72
73	load_interfaces();
74
75	if ((p=smbw_getshared("SERVICESF"))) {
76		pstrcpy(dyn_CONFIGFILE, p);
77	}
78
79	lp_load(dyn_CONFIGFILE,True,False,False);
80
81	if (!init_names())
82		exit(1);
83
84	if ((p=smbw_getshared("DEBUG"))) {
85		DEBUGLEVEL = atoi(p);
86	}
87
88	if ((p=smbw_getshared("RESOLVE_ORDER"))) {
89		lp_set_name_resolve_order(p);
90	}
91
92	if ((p=smbw_getshared("PREFIX"))) {
93		slprintf(smbw_prefix,sizeof(fstring)-1, "/%s/", p);
94		all_string_sub(smbw_prefix,"//", "/", 0);
95		DEBUG(2,("SMBW_PREFIX is %s\n", smbw_prefix));
96	}
97
98	slprintf(line,sizeof(line)-1,"PWD_%d", (int)getpid());
99
100	p = smbw_getshared(line);
101	if (!p) {
102		sys_getwd(smbw_cwd);
103	}
104	pstrcpy(smbw_cwd, p);
105	DEBUG(4,("Initial cwd is %s\n", smbw_cwd));
106
107	smbw_busy--;
108
109	set_maxfiles(SMBW_MAX_OPEN);
110
111	BlockSignals(True,SIGPIPE);
112
113	errno = eno;
114}
115
116/*****************************************************
117determine if a file descriptor is a smb one
118*******************************************************/
119int smbw_fd(int fd)
120{
121	if (smbw_busy) return 0;
122	return smbw_file_bmap && bitmap_query(smbw_file_bmap, fd);
123}
124
125/*****************************************************
126determine if a file descriptor is an internal smbw fd
127*******************************************************/
128int smbw_local_fd(int fd)
129{
130	struct smbw_server *srv;
131
132	smbw_init();
133
134	if (smbw_busy) return 0;
135	if (smbw_shared_fd(fd)) return 1;
136
137	for (srv=smbw_srvs;srv;srv=srv->next) {
138		if (srv->cli.fd == fd) return 1;
139	}
140
141	return 0;
142}
143
144/*****************************************************
145a crude inode number generator
146*******************************************************/
147ino_t smbw_inode(const char *name)
148{
149	if (!*name) return 2;
150	return (ino_t)str_checksum(name);
151}
152
153/*****************************************************
154remove redundent stuff from a filename
155*******************************************************/
156void clean_fname(char *name)
157{
158	char *p, *p2;
159	int l;
160	int modified = 1;
161
162	if (!name) return;
163
164	while (modified) {
165		modified = 0;
166
167		DEBUG(5,("cleaning %s\n", name));
168
169		if ((p=strstr(name,"/./"))) {
170			modified = 1;
171			while (*p) {
172				p[0] = p[2];
173				p++;
174			}
175		}
176
177		if ((p=strstr(name,"//"))) {
178			modified = 1;
179			while (*p) {
180				p[0] = p[1];
181				p++;
182			}
183		}
184
185		if (strcmp(name,"/../")==0) {
186			modified = 1;
187			name[1] = 0;
188		}
189
190		if ((p=strstr(name,"/../"))) {
191			modified = 1;
192			for (p2=(p>name?p-1:p);p2>name;p2--) {
193				if (p2[0] == '/') break;
194			}
195			while (*p2) {
196				p2[0] = p2[3];
197				p2++;
198			}
199		}
200
201		if (strcmp(name,"/..")==0) {
202			modified = 1;
203			name[1] = 0;
204		}
205
206		l = strlen(name);
207		p = l>=3?(name+l-3):name;
208		if (strcmp(p,"/..")==0) {
209			modified = 1;
210			for (p2=p-1;p2>name;p2--) {
211				if (p2[0] == '/') break;
212			}
213			if (p2==name) {
214				p[0] = '/';
215				p[1] = 0;
216			} else {
217				p2[0] = 0;
218			}
219		}
220
221		l = strlen(name);
222		p = l>=2?(name+l-2):name;
223		if (strcmp(p,"/.")==0) {
224			if (p == name) {
225				p[1] = 0;
226			} else {
227				p[0] = 0;
228			}
229		}
230
231		if (strncmp(p=name,"./",2) == 0) {
232			modified = 1;
233			do {
234				p[0] = p[2];
235			} while (*p++);
236		}
237
238		l = strlen(p=name);
239		if (l > 1 && p[l-1] == '/') {
240			modified = 1;
241			p[l-1] = 0;
242		}
243	}
244}
245
246
247
248/*****************************************************
249find a workgroup (any workgroup!) that has a master
250browser on the local network
251*******************************************************/
252static char *smbw_find_workgroup(void)
253{
254	fstring server;
255	char *p;
256	struct in_addr *ip_list = NULL;
257	int count = 0;
258	int i;
259
260	/* first off see if an existing workgroup name exists */
261	p = smbw_getshared("WORKGROUP");
262	if (!p) p = lp_workgroup();
263
264	slprintf(server, sizeof(server), "%s#1D", p);
265	if (smbw_server(server, "IPC$")) return p;
266
267	/* go looking for workgroups */
268	if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) {
269		DEBUG(1,("No workgroups found!"));
270		return p;
271	}
272
273	for (i=0;i<count;i++) {
274		static fstring name;
275		if (name_status_find("*", 0, 0x1d, ip_list[i], name)) {
276			slprintf(server, sizeof(server), "%s#1D", name);
277			if (smbw_server(server, "IPC$")) {
278				smbw_setshared("WORKGROUP", name);
279				SAFE_FREE(ip_list);
280				return name;
281			}
282		}
283	}
284
285	SAFE_FREE(ip_list);
286
287	return p;
288}
289
290/*****************************************************
291parse a smb path into its components.
292server is one of
293  1) the name of the SMB server
294  2) WORKGROUP#1D for share listing
295  3) WORKGROUP#__ for workgroup listing
296share is the share on the server to query
297path is the SMB path on the server
298return the full path (ie. add cwd if needed)
299*******************************************************/
300char *smbw_parse_path(const char *fname, char *server, char *share, char *path)
301{
302	static pstring s;
303	char *p;
304	int len;
305	fstring workgroup;
306
307	/* add cwd if necessary */
308	if (fname[0] != '/') {
309		slprintf(s, sizeof(s), "%s/%s", smbw_cwd, fname);
310	} else {
311		pstrcpy(s, fname);
312	}
313	clean_fname(s);
314
315	/* see if it has the right prefix */
316	len = strlen(smbw_prefix)-1;
317	if (strncmp(s,smbw_prefix,len) ||
318	    (s[len] != '/' && s[len] != 0)) return s;
319
320	/* ok, its for us. Now parse out the workgroup, share etc. */
321	p = s+len;
322	if (*p == '/') p++;
323	if (!next_token(&p, workgroup, "/", sizeof(fstring))) {
324		/* we're in /smb - give a list of workgroups */
325		slprintf(server,sizeof(fstring), "%s#01", smbw_find_workgroup());
326		fstrcpy(share,"IPC$");
327		pstrcpy(path,"");
328		return s;
329	}
330
331	if (!next_token(&p, server, "/", sizeof(fstring))) {
332		/* we are in /smb/WORKGROUP */
333		slprintf(server,sizeof(fstring), "%s#1D", workgroup);
334		fstrcpy(share,"IPC$");
335		pstrcpy(path,"");
336	}
337
338	if (!next_token(&p, share, "/", sizeof(fstring))) {
339		/* we are in /smb/WORKGROUP/SERVER */
340		fstrcpy(share,"IPC$");
341		pstrcpy(path,"");
342	}
343
344	pstrcpy(path, p);
345
346	all_string_sub(path, "/", "\\", 0);
347
348	return s;
349}
350
351/*****************************************************
352determine if a path name (possibly relative) is in the
353smb name space
354*******************************************************/
355int smbw_path(const char *path)
356{
357	fstring server, share;
358	pstring s;
359	char *cwd;
360	int len;
361
362	if(!path)
363		return 0;
364
365	/* this is needed to prevent recursion with the BSD malloc which
366	   opens /etc/malloc.conf on the first call */
367	if (strncmp(path,"/etc/", 5) == 0) {
368		return 0;
369	}
370
371	smbw_init();
372
373	len = strlen(smbw_prefix)-1;
374
375	if (path[0] == '/' && strncmp(path,smbw_prefix,len)) {
376		return 0;
377	}
378
379	if (smbw_busy) return 0;
380
381	DEBUG(3,("smbw_path(%s)\n", path));
382
383	cwd = smbw_parse_path(path, server, share, s);
384
385	if (strncmp(cwd,smbw_prefix,len) == 0 &&
386	    (cwd[len] == '/' || cwd[len] == 0)) {
387		return 1;
388	}
389
390	return 0;
391}
392
393/*****************************************************
394return a unix errno from a SMB error pair
395*******************************************************/
396int smbw_errno(struct cli_state *c)
397{
398	return cli_errno(c);
399}
400
401/* Return a username and password given a server and share name */
402
403void get_envvar_auth_data(char *server, char *share, char **workgroup,
404			  char **username, char **password)
405{
406	/* Fall back to shared memory/environment variables */
407
408	*username = smbw_getshared("USER");
409	if (!*username) *username = getenv("USER");
410	if (!*username) *username = "guest";
411
412	*workgroup = smbw_getshared("WORKGROUP");
413	if (!*workgroup) *workgroup = lp_workgroup();
414
415	*password = smbw_getshared("PASSWORD");
416	if (!*password) *password = "";
417}
418
419static smbw_get_auth_data_fn get_auth_data_fn = get_envvar_auth_data;
420
421/*****************************************************
422set the get auth data function
423******************************************************/
424void smbw_set_auth_data_fn(smbw_get_auth_data_fn fn)
425{
426	get_auth_data_fn = fn;
427}
428
429/*****************************************************
430return a connection to a server (existing or new)
431*******************************************************/
432struct smbw_server *smbw_server(char *server, char *share)
433{
434	struct smbw_server *srv=NULL;
435	struct cli_state c;
436	char *username;
437	char *password;
438	char *workgroup;
439	struct nmb_name called, calling;
440	char *p, *server_n = server;
441	fstring group;
442	pstring ipenv;
443	struct in_addr ip;
444
445        zero_ip(&ip);
446	ZERO_STRUCT(c);
447
448	get_auth_data_fn(server, share, &workgroup, &username, &password);
449
450	/* try to use an existing connection */
451	for (srv=smbw_srvs;srv;srv=srv->next) {
452		if (strcmp(server,srv->server_name)==0 &&
453		    strcmp(share,srv->share_name)==0 &&
454		    strcmp(workgroup,srv->workgroup)==0 &&
455		    strcmp(username, srv->username) == 0)
456			return srv;
457	}
458
459	if (server[0] == 0) {
460		errno = EPERM;
461		return NULL;
462	}
463
464	make_nmb_name(&calling, global_myname(), 0x0);
465	make_nmb_name(&called , server, 0x20);
466
467	DEBUG(4,("server_n=[%s] server=[%s]\n", server_n, server));
468
469	if ((p=strchr_m(server_n,'#')) &&
470	    (strcmp(p+1,"1D")==0 || strcmp(p+1,"01")==0)) {
471		struct in_addr sip;
472		pstring s;
473
474		fstrcpy(group, server_n);
475		p = strchr_m(group,'#');
476		*p = 0;
477
478		/* cache the workgroup master lookup */
479		slprintf(s,sizeof(s)-1,"MASTER_%s", group);
480		if (!(server_n = smbw_getshared(s))) {
481			if (!find_master_ip(group, &sip)) {
482				errno = ENOENT;
483				return NULL;
484			}
485			fstrcpy(group, inet_ntoa(sip));
486			server_n = group;
487			smbw_setshared(s,server_n);
488		}
489	}
490
491	DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));
492
493 again:
494	slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n);
495
496        zero_ip(&ip);
497	if ((p=smbw_getshared(ipenv))) {
498		ip = *(interpret_addr2(p));
499	}
500
501	/* have to open a new connection */
502	if (!cli_initialise(&c) || !cli_connect(&c, server_n, &ip)) {
503		errno = ENOENT;
504		return NULL;
505	}
506
507	if (!cli_session_request(&c, &calling, &called)) {
508		cli_shutdown(&c);
509		if (strcmp(called.name, "*SMBSERVER")) {
510			make_nmb_name(&called , "*SMBSERVER", 0x20);
511			goto again;
512		}
513		errno = ENOENT;
514		return NULL;
515	}
516
517	DEBUG(4,(" session request ok\n"));
518
519	if (!cli_negprot(&c)) {
520		cli_shutdown(&c);
521		errno = ENOENT;
522		return NULL;
523	}
524
525	if (!cli_session_setup(&c, username,
526			       password, strlen(password),
527			       password, strlen(password),
528			       workgroup) &&
529	    /* try an anonymous login if it failed */
530	    !cli_session_setup(&c, "", "", 1,"", 0, workgroup)) {
531		cli_shutdown(&c);
532		errno = EPERM;
533		return NULL;
534	}
535
536	DEBUG(4,(" session setup ok\n"));
537
538	if (!cli_send_tconX(&c, share, "?????",
539			    password, strlen(password)+1)) {
540		errno = smbw_errno(&c);
541		cli_shutdown(&c);
542		return NULL;
543	}
544
545	smbw_setshared(ipenv,inet_ntoa(ip));
546
547	DEBUG(4,(" tconx ok\n"));
548
549	srv = SMB_MALLOC_P(struct smbw_server);
550	if (!srv) {
551		errno = ENOMEM;
552		goto failed;
553	}
554
555	ZERO_STRUCTP(srv);
556
557	srv->cli = c;
558
559	srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
560
561	srv->server_name = SMB_STRDUP(server);
562	if (!srv->server_name) {
563		errno = ENOMEM;
564		goto failed;
565	}
566
567	srv->share_name = SMB_STRDUP(share);
568	if (!srv->share_name) {
569		errno = ENOMEM;
570		goto failed;
571	}
572
573	srv->workgroup = SMB_STRDUP(workgroup);
574	if (!srv->workgroup) {
575		errno = ENOMEM;
576		goto failed;
577	}
578
579	srv->username = SMB_STRDUP(username);
580	if (!srv->username) {
581		errno = ENOMEM;
582		goto failed;
583	}
584
585	/* some programs play with file descriptors fairly intimately. We
586	   try to get out of the way by duping to a high fd number */
587	if (fcntl(SMBW_CLI_FD + srv->cli.fd, F_GETFD) && errno == EBADF) {
588		if (dup2(srv->cli.fd,SMBW_CLI_FD+srv->cli.fd) ==
589		    srv->cli.fd+SMBW_CLI_FD) {
590			close(srv->cli.fd);
591			srv->cli.fd += SMBW_CLI_FD;
592		}
593	}
594
595	DLIST_ADD(smbw_srvs, srv);
596
597	return srv;
598
599 failed:
600	cli_shutdown(&c);
601	if (!srv) return NULL;
602
603	SAFE_FREE(srv->server_name);
604	SAFE_FREE(srv->share_name);
605	SAFE_FREE(srv);
606	return NULL;
607}
608
609
610/*****************************************************
611map a fd to a smbw_file structure
612*******************************************************/
613struct smbw_file *smbw_file(int fd)
614{
615	struct smbw_file *file;
616
617	for (file=smbw_files;file;file=file->next) {
618		if (file->fd == fd) return file;
619	}
620	return NULL;
621}
622
623/*****************************************************
624a wrapper for open()
625*******************************************************/
626int smbw_open(const char *fname, int flags, mode_t mode)
627{
628	fstring server, share;
629	pstring path;
630	struct smbw_server *srv=NULL;
631	int eno=0, fd = -1;
632	struct smbw_file *file=NULL;
633
634	smbw_init();
635
636	if (!fname) {
637		errno = EINVAL;
638		return -1;
639	}
640
641	smbw_busy++;
642
643	/* work out what server they are after */
644	smbw_parse_path(fname, server, share, path);
645
646	/* get a connection to the server */
647	srv = smbw_server(server, share);
648	if (!srv) {
649		/* smbw_server sets errno */
650		goto failed;
651	}
652
653	if (path[strlen(path)-1] == '\\') {
654		fd = -1;
655	} else {
656		fd = cli_open(&srv->cli, path, flags, DENY_NONE);
657	}
658	if (fd == -1) {
659		/* it might be a directory. Maybe we should use chkpath? */
660		eno = smbw_errno(&srv->cli);
661		fd = smbw_dir_open(fname);
662		if (fd == -1) errno = eno;
663		smbw_busy--;
664		return fd;
665	}
666
667	file = SMB_MALLOC_P(struct smbw_file);
668	if (!file) {
669		errno = ENOMEM;
670		goto failed;
671	}
672
673	ZERO_STRUCTP(file);
674
675	file->f = SMB_MALLOC_P(struct smbw_filedes);
676	if (!file->f) {
677		errno = ENOMEM;
678		goto failed;
679	}
680
681	ZERO_STRUCTP(file->f);
682
683	file->f->cli_fd = fd;
684	file->f->fname = SMB_STRDUP(path);
685	if (!file->f->fname) {
686		errno = ENOMEM;
687		goto failed;
688	}
689	file->srv = srv;
690	file->fd = open(SMBW_DUMMY, O_WRONLY);
691	if (file->fd == -1) {
692		errno = EMFILE;
693		goto failed;
694	}
695
696	if (bitmap_query(smbw_file_bmap, file->fd)) {
697		DEBUG(0,("ERROR: fd used in smbw_open\n"));
698		errno = EIO;
699		goto failed;
700	}
701
702	file->f->ref_count=1;
703
704	bitmap_set(smbw_file_bmap, file->fd);
705
706	DLIST_ADD(smbw_files, file);
707
708	DEBUG(4,("opened %s\n", fname));
709
710	smbw_busy--;
711	return file->fd;
712
713 failed:
714	if (fd != -1) {
715		cli_close(&srv->cli, fd);
716	}
717	if (file) {
718		if (file->f) {
719			SAFE_FREE(file->f->fname);
720			SAFE_FREE(file->f);
721		}
722		SAFE_FREE(file);
723	}
724	smbw_busy--;
725	return -1;
726}
727
728
729/*****************************************************
730a wrapper for pread()
731*******************************************************/
732ssize_t smbw_pread(int fd, void *buf, size_t count, off_t ofs)
733{
734	struct smbw_file *file;
735	int ret;
736
737	smbw_busy++;
738
739	file = smbw_file(fd);
740	if (!file) {
741		errno = EBADF;
742		smbw_busy--;
743		return -1;
744	}
745
746	ret = cli_read(&file->srv->cli, file->f->cli_fd, buf, ofs, count);
747
748	if (ret == -1) {
749		errno = smbw_errno(&file->srv->cli);
750		smbw_busy--;
751		return -1;
752	}
753
754	smbw_busy--;
755	return ret;
756}
757
758/*****************************************************
759a wrapper for read()
760*******************************************************/
761ssize_t smbw_read(int fd, void *buf, size_t count)
762{
763	struct smbw_file *file;
764	int ret;
765
766	DEBUG(4,("smbw_read(%d, %d)\n", fd, (int)count));
767
768	smbw_busy++;
769
770	file = smbw_file(fd);
771	if (!file) {
772		errno = EBADF;
773		smbw_busy--;
774		return -1;
775	}
776
777	ret = cli_read(&file->srv->cli, file->f->cli_fd, buf,
778		       file->f->offset, count);
779
780	if (ret == -1) {
781		errno = smbw_errno(&file->srv->cli);
782		smbw_busy--;
783		return -1;
784	}
785
786	file->f->offset += ret;
787
788	DEBUG(4,(" -> %d\n", ret));
789
790	smbw_busy--;
791	return ret;
792}
793
794
795
796/*****************************************************
797a wrapper for write()
798*******************************************************/
799ssize_t smbw_write(int fd, void *buf, size_t count)
800{
801	struct smbw_file *file;
802	int ret;
803
804	smbw_busy++;
805
806	file = smbw_file(fd);
807	if (!file) {
808		errno = EBADF;
809		smbw_busy--;
810		return -1;
811	}
812
813	ret = cli_write(&file->srv->cli, file->f->cli_fd, 0, buf, file->f->offset, count);
814
815	if (ret == -1) {
816		errno = smbw_errno(&file->srv->cli);
817		smbw_busy--;
818		return -1;
819	}
820
821	file->f->offset += ret;
822
823	smbw_busy--;
824	return ret;
825}
826
827/*****************************************************
828a wrapper for pwrite()
829*******************************************************/
830ssize_t smbw_pwrite(int fd, void *buf, size_t count, off_t ofs)
831{
832	struct smbw_file *file;
833	int ret;
834
835	smbw_busy++;
836
837	file = smbw_file(fd);
838	if (!file) {
839		errno = EBADF;
840		smbw_busy--;
841		return -1;
842	}
843
844	ret = cli_write(&file->srv->cli, file->f->cli_fd, 0, buf, ofs, count);
845
846	if (ret == -1) {
847		errno = smbw_errno(&file->srv->cli);
848		smbw_busy--;
849		return -1;
850	}
851
852	smbw_busy--;
853	return ret;
854}
855
856/*****************************************************
857a wrapper for close()
858*******************************************************/
859int smbw_close(int fd)
860{
861	struct smbw_file *file;
862
863	smbw_busy++;
864
865	file = smbw_file(fd);
866	if (!file) {
867		int ret = smbw_dir_close(fd);
868		smbw_busy--;
869		return ret;
870	}
871
872	if (file->f->ref_count == 1 &&
873	    !cli_close(&file->srv->cli, file->f->cli_fd)) {
874		errno = smbw_errno(&file->srv->cli);
875		smbw_busy--;
876		return -1;
877	}
878
879
880	bitmap_clear(smbw_file_bmap, file->fd);
881	close(file->fd);
882
883	DLIST_REMOVE(smbw_files, file);
884
885	file->f->ref_count--;
886	if (file->f->ref_count == 0) {
887		SAFE_FREE(file->f->fname);
888		SAFE_FREE(file->f);
889	}
890	ZERO_STRUCTP(file);
891	SAFE_FREE(file);
892
893	smbw_busy--;
894
895	return 0;
896}
897
898
899/*****************************************************
900a wrapper for fcntl()
901*******************************************************/
902int smbw_fcntl(int fd, int cmd, long arg)
903{
904	return 0;
905}
906
907
908/*****************************************************
909a wrapper for access()
910*******************************************************/
911int smbw_access(const char *name, int mode)
912{
913	struct stat st;
914
915	DEBUG(4,("smbw_access(%s, 0x%x)\n", name, mode));
916
917	if (smbw_stat(name, &st)) return -1;
918
919	if (((mode & R_OK) && !(st.st_mode & S_IRUSR)) ||
920	    ((mode & W_OK) && !(st.st_mode & S_IWUSR)) ||
921	    ((mode & X_OK) && !(st.st_mode & S_IXUSR))) {
922		errno = EACCES;
923		return -1;
924	}
925
926	return 0;
927}
928
929/*****************************************************
930a wrapper for realink() - needed for correct errno setting
931*******************************************************/
932int smbw_readlink(const char *path, char *buf, size_t bufsize)
933{
934	struct stat st;
935	int ret;
936
937	ret = smbw_stat(path, &st);
938	if (ret != 0) {
939		DEBUG(4,("readlink(%s) failed\n", path));
940		return -1;
941	}
942
943	/* it exists - say it isn't a link */
944	DEBUG(4,("readlink(%s) not a link\n", path));
945
946	errno = EINVAL;
947	return -1;
948}
949
950
951/*****************************************************
952a wrapper for unlink()
953*******************************************************/
954int smbw_unlink(const char *fname)
955{
956	struct smbw_server *srv;
957	fstring server, share;
958	pstring path;
959
960	if (!fname) {
961		errno = EINVAL;
962		return -1;
963	}
964
965	smbw_init();
966
967	smbw_busy++;
968
969	/* work out what server they are after */
970	smbw_parse_path(fname, server, share, path);
971
972	/* get a connection to the server */
973	srv = smbw_server(server, share);
974	if (!srv) {
975		/* smbw_server sets errno */
976		goto failed;
977	}
978
979	if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
980		int job = smbw_stat_printjob(srv, path, NULL, NULL);
981		if (job == -1) {
982			goto failed;
983		}
984		if (cli_printjob_del(&srv->cli, job) != 0) {
985			goto failed;
986		}
987	} else if (!cli_unlink(&srv->cli, path)) {
988		errno = smbw_errno(&srv->cli);
989		goto failed;
990	}
991
992	smbw_busy--;
993	return 0;
994
995 failed:
996	smbw_busy--;
997	return -1;
998}
999
1000
1001/*****************************************************
1002a wrapper for rename()
1003*******************************************************/
1004int smbw_rename(const char *oldname, const char *newname)
1005{
1006	struct smbw_server *srv;
1007	fstring server1, share1;
1008	pstring path1;
1009	fstring server2, share2;
1010	pstring path2;
1011
1012	if (!oldname || !newname) {
1013		errno = EINVAL;
1014		return -1;
1015	}
1016
1017	smbw_init();
1018
1019	DEBUG(4,("smbw_rename(%s,%s)\n", oldname, newname));
1020
1021	smbw_busy++;
1022
1023	/* work out what server they are after */
1024	smbw_parse_path(oldname, server1, share1, path1);
1025	smbw_parse_path(newname, server2, share2, path2);
1026
1027	if (strcmp(server1, server2) || strcmp(share1, share2)) {
1028		/* can't cross filesystems */
1029		errno = EXDEV;
1030		return -1;
1031	}
1032
1033	/* get a connection to the server */
1034	srv = smbw_server(server1, share1);
1035	if (!srv) {
1036		/* smbw_server sets errno */
1037		goto failed;
1038	}
1039
1040	if (!cli_rename(&srv->cli, path1, path2)) {
1041		int eno = smbw_errno(&srv->cli);
1042		if (eno != EEXIST ||
1043		    !cli_unlink(&srv->cli, path2) ||
1044		    !cli_rename(&srv->cli, path1, path2)) {
1045			errno = eno;
1046			goto failed;
1047		}
1048	}
1049
1050	smbw_busy--;
1051	return 0;
1052
1053 failed:
1054	smbw_busy--;
1055	return -1;
1056}
1057
1058
1059/*****************************************************
1060a wrapper for utime and utimes
1061*******************************************************/
1062static int smbw_settime(const char *fname, time_t t)
1063{
1064	struct smbw_server *srv;
1065	fstring server, share;
1066	pstring path;
1067	uint16 mode;
1068
1069	if (!fname) {
1070		errno = EINVAL;
1071		return -1;
1072	}
1073
1074	smbw_init();
1075
1076	smbw_busy++;
1077
1078	/* work out what server they are after */
1079	smbw_parse_path(fname, server, share, path);
1080
1081	/* get a connection to the server */
1082	srv = smbw_server(server, share);
1083	if (!srv) {
1084		/* smbw_server sets errno */
1085		goto failed;
1086	}
1087
1088	if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
1089		errno = smbw_errno(&srv->cli);
1090		goto failed;
1091	}
1092
1093	if (!cli_setatr(&srv->cli, path, mode, t)) {
1094		/* some servers always refuse directory changes */
1095		if (!(mode & aDIR)) {
1096			errno = smbw_errno(&srv->cli);
1097			goto failed;
1098		}
1099	}
1100
1101	smbw_busy--;
1102	return 0;
1103
1104 failed:
1105	smbw_busy--;
1106	return -1;
1107}
1108
1109/*****************************************************
1110a wrapper for utime
1111*******************************************************/
1112int smbw_utime(const char *fname, void *buf)
1113{
1114	struct utimbuf *tbuf = (struct utimbuf *)buf;
1115	return smbw_settime(fname, tbuf?tbuf->modtime:time(NULL));
1116}
1117
1118/*****************************************************
1119a wrapper for utime
1120*******************************************************/
1121int smbw_utimes(const char *fname, void *buf)
1122{
1123	struct timeval *tbuf = (struct timeval *)buf;
1124	return smbw_settime(fname, tbuf?tbuf->tv_sec:time(NULL));
1125}
1126
1127
1128/*****************************************************
1129a wrapper for chown()
1130*******************************************************/
1131int smbw_chown(const char *fname, uid_t owner, gid_t group)
1132{
1133	struct smbw_server *srv;
1134	fstring server, share;
1135	pstring path;
1136	uint16 mode;
1137
1138	if (!fname) {
1139		errno = EINVAL;
1140		return -1;
1141	}
1142
1143	smbw_init();
1144
1145	smbw_busy++;
1146
1147	/* work out what server they are after */
1148	smbw_parse_path(fname, server, share, path);
1149
1150	/* get a connection to the server */
1151	srv = smbw_server(server, share);
1152	if (!srv) {
1153		/* smbw_server sets errno */
1154		goto failed;
1155	}
1156
1157	if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
1158		errno = smbw_errno(&srv->cli);
1159		goto failed;
1160	}
1161
1162	/* assume success */
1163
1164	smbw_busy--;
1165	return 0;
1166
1167 failed:
1168	smbw_busy--;
1169	return -1;
1170}
1171
1172/*****************************************************
1173a wrapper for chmod()
1174*******************************************************/
1175int smbw_chmod(const char *fname, mode_t newmode)
1176{
1177	struct smbw_server *srv;
1178	fstring server, share;
1179	pstring path;
1180	uint32 mode;
1181
1182	if (!fname) {
1183		errno = EINVAL;
1184		return -1;
1185	}
1186
1187	smbw_init();
1188
1189	smbw_busy++;
1190
1191	/* work out what server they are after */
1192	smbw_parse_path(fname, server, share, path);
1193
1194	/* get a connection to the server */
1195	srv = smbw_server(server, share);
1196	if (!srv) {
1197		/* smbw_server sets errno */
1198		goto failed;
1199	}
1200
1201	mode = 0;
1202
1203	if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY;
1204	if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH;
1205	if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM;
1206	if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN;
1207
1208	if (!cli_setatr(&srv->cli, path, mode, 0)) {
1209		errno = smbw_errno(&srv->cli);
1210		goto failed;
1211	}
1212
1213	smbw_busy--;
1214	return 0;
1215
1216 failed:
1217	smbw_busy--;
1218	return -1;
1219}
1220
1221/*****************************************************
1222a wrapper for lseek()
1223*******************************************************/
1224off_t smbw_lseek(int fd, off_t offset, int whence)
1225{
1226	struct smbw_file *file;
1227	size_t size;
1228
1229	smbw_busy++;
1230
1231	file = smbw_file(fd);
1232	if (!file) {
1233		off_t ret = smbw_dir_lseek(fd, offset, whence);
1234		smbw_busy--;
1235		return ret;
1236	}
1237
1238	switch (whence) {
1239	case SEEK_SET:
1240		file->f->offset = offset;
1241		break;
1242	case SEEK_CUR:
1243		file->f->offset += offset;
1244		break;
1245	case SEEK_END:
1246		if (!cli_qfileinfo(&file->srv->cli, file->f->cli_fd,
1247				   NULL, &size, NULL, NULL, NULL,
1248				   NULL, NULL) &&
1249		    !cli_getattrE(&file->srv->cli, file->f->cli_fd,
1250				  NULL, &size, NULL, NULL, NULL)) {
1251			errno = EINVAL;
1252			smbw_busy--;
1253			return -1;
1254		}
1255		file->f->offset = size + offset;
1256		break;
1257	}
1258
1259	smbw_busy--;
1260	return file->f->offset;
1261}
1262
1263
1264/*****************************************************
1265a wrapper for dup()
1266*******************************************************/
1267int smbw_dup(int fd)
1268{
1269	int fd2;
1270	struct smbw_file *file, *file2;
1271
1272	smbw_busy++;
1273
1274	file = smbw_file(fd);
1275	if (!file) {
1276		errno = EBADF;
1277		goto failed;
1278	}
1279
1280	fd2 = dup(file->fd);
1281	if (fd2 == -1) {
1282		goto failed;
1283	}
1284
1285	if (bitmap_query(smbw_file_bmap, fd2)) {
1286		DEBUG(0,("ERROR: fd already open in dup!\n"));
1287		errno = EIO;
1288		goto failed;
1289	}
1290
1291	file2 = SMB_MALLOC_P(struct smbw_file);
1292	if (!file2) {
1293		close(fd2);
1294		errno = ENOMEM;
1295		goto failed;
1296	}
1297
1298	ZERO_STRUCTP(file2);
1299
1300	*file2 = *file;
1301	file2->fd = fd2;
1302
1303	file->f->ref_count++;
1304
1305	bitmap_set(smbw_file_bmap, fd2);
1306
1307	DLIST_ADD(smbw_files, file2);
1308
1309	smbw_busy--;
1310	return fd2;
1311
1312 failed:
1313	smbw_busy--;
1314	return -1;
1315}
1316
1317
1318/*****************************************************
1319a wrapper for dup2()
1320*******************************************************/
1321int smbw_dup2(int fd, int fd2)
1322{
1323	struct smbw_file *file, *file2;
1324
1325	smbw_busy++;
1326
1327	file = smbw_file(fd);
1328	if (!file) {
1329		errno = EBADF;
1330		goto failed;
1331	}
1332
1333	if (bitmap_query(smbw_file_bmap, fd2)) {
1334		DEBUG(0,("ERROR: fd already open in dup2!\n"));
1335		errno = EIO;
1336		goto failed;
1337	}
1338
1339	if (dup2(file->fd, fd2) != fd2) {
1340		goto failed;
1341	}
1342
1343	file2 = SMB_MALLOC_P(struct smbw_file);
1344	if (!file2) {
1345		close(fd2);
1346		errno = ENOMEM;
1347		goto failed;
1348	}
1349
1350	ZERO_STRUCTP(file2);
1351
1352	*file2 = *file;
1353	file2->fd = fd2;
1354
1355	file->f->ref_count++;
1356
1357	bitmap_set(smbw_file_bmap, fd2);
1358
1359	DLIST_ADD(smbw_files, file2);
1360
1361	smbw_busy--;
1362	return fd2;
1363
1364 failed:
1365	smbw_busy--;
1366	return -1;
1367}
1368
1369
1370/*****************************************************
1371close a connection to a server
1372*******************************************************/
1373static void smbw_srv_close(struct smbw_server *srv)
1374{
1375	smbw_busy++;
1376
1377	cli_shutdown(&srv->cli);
1378
1379	SAFE_FREE(srv->server_name);
1380	SAFE_FREE(srv->share_name);
1381
1382	DLIST_REMOVE(smbw_srvs, srv);
1383
1384	ZERO_STRUCTP(srv);
1385
1386	SAFE_FREE(srv);
1387
1388	smbw_busy--;
1389}
1390
1391/*****************************************************
1392when we fork we have to close all connections and files
1393in the child
1394*******************************************************/
1395int smbw_fork(void)
1396{
1397	pid_t child;
1398	int p[2];
1399	char c=0;
1400	pstring line;
1401
1402	struct smbw_file *file, *next_file;
1403	struct smbw_server *srv, *next_srv;
1404
1405	if (pipe(p)) return real_fork();
1406
1407	child = real_fork();
1408
1409	if (child) {
1410		/* block the parent for a moment until the sockets are
1411                   closed */
1412		close(p[1]);
1413		read(p[0], &c, 1);
1414		close(p[0]);
1415		return child;
1416	}
1417
1418	close(p[0]);
1419
1420	/* close all files */
1421	for (file=smbw_files;file;file=next_file) {
1422		next_file = file->next;
1423		close(file->fd);
1424	}
1425
1426	/* close all server connections */
1427	for (srv=smbw_srvs;srv;srv=next_srv) {
1428		next_srv = srv->next;
1429		smbw_srv_close(srv);
1430	}
1431
1432	slprintf(line,sizeof(line)-1,"PWD_%d", (int)getpid());
1433	smbw_setshared(line,smbw_cwd);
1434
1435	/* unblock the parent */
1436	write(p[1], &c, 1);
1437	close(p[1]);
1438
1439	/* and continue in the child */
1440	return 0;
1441}
1442
1443#ifndef NO_ACL_WRAPPER
1444/*****************************************************
1445say no to acls
1446*******************************************************/
1447 int smbw_acl(const char *pathp, int cmd, int nentries, aclent_t *aclbufp)
1448{
1449	if (cmd == GETACL || cmd == GETACLCNT) return 0;
1450	errno = ENOSYS;
1451	return -1;
1452}
1453#endif
1454
1455#ifndef NO_FACL_WRAPPER
1456/*****************************************************
1457say no to acls
1458*******************************************************/
1459 int smbw_facl(int fd, int cmd, int nentries, aclent_t *aclbufp)
1460{
1461	if (cmd == GETACL || cmd == GETACLCNT) return 0;
1462	errno = ENOSYS;
1463	return -1;
1464}
1465#endif
1466
1467#ifdef HAVE_EXPLICIT_LARGEFILE_SUPPORT
1468#ifdef HAVE_STAT64
1469/* this can't be in wrapped.c because of include conflicts */
1470 void stat64_convert(struct stat *st, struct stat64 *st64)
1471{
1472	st64->st_size = st->st_size;
1473	st64->st_mode = st->st_mode;
1474	st64->st_ino = st->st_ino;
1475	st64->st_dev = st->st_dev;
1476	st64->st_rdev = st->st_rdev;
1477	st64->st_nlink = st->st_nlink;
1478	st64->st_uid = st->st_uid;
1479	st64->st_gid = st->st_gid;
1480	st64->st_atime = st->st_atime;
1481	st64->st_mtime = st->st_mtime;
1482	st64->st_ctime = st->st_ctime;
1483#ifdef HAVE_STAT_ST_BLKSIZE
1484	st64->st_blksize = st->st_blksize;
1485#endif
1486#ifdef HAVE_STAT_ST_BLOCKS
1487	st64->st_blocks = st->st_blocks;
1488#endif
1489}
1490#endif
1491
1492#ifdef HAVE_READDIR64
1493 void dirent64_convert(struct dirent *d, struct dirent64 *d64)
1494{
1495	d64->d_ino = d->d_ino;
1496	d64->d_off = d->d_off;
1497	d64->d_reclen = d->d_reclen;
1498	pstrcpy(d64->d_name, d->d_name);
1499}
1500#endif
1501#endif
1502
1503
1504#ifdef HAVE___XSTAT
1505/* Definition of `struct stat' used in the linux kernel..  */
1506struct kernel_stat {
1507	unsigned short int st_dev;
1508	unsigned short int __pad1;
1509	unsigned long int st_ino;
1510	unsigned short int st_mode;
1511	unsigned short int st_nlink;
1512	unsigned short int st_uid;
1513	unsigned short int st_gid;
1514	unsigned short int st_rdev;
1515	unsigned short int __pad2;
1516	unsigned long int st_size;
1517	unsigned long int st_blksize;
1518	unsigned long int st_blocks;
1519	unsigned long int st_atime_;
1520	unsigned long int __unused1;
1521	unsigned long int st_mtime_;
1522	unsigned long int __unused2;
1523	unsigned long int st_ctime_;
1524	unsigned long int __unused3;
1525	unsigned long int __unused4;
1526	unsigned long int __unused5;
1527};
1528
1529/*
1530 * Prototype for gcc in 'fussy' mode.
1531 */
1532 void xstat_convert(int vers, struct stat *st, struct kernel_stat *kbuf);
1533 void xstat_convert(int vers, struct stat *st, struct kernel_stat *kbuf)
1534{
1535#ifdef _STAT_VER_LINUX_OLD
1536	if (vers == _STAT_VER_LINUX_OLD) {
1537		memcpy(st, kbuf, sizeof(*st));
1538		return;
1539	}
1540#endif
1541
1542	ZERO_STRUCTP(st);
1543
1544	st->st_dev = kbuf->st_dev;
1545	st->st_ino = kbuf->st_ino;
1546	st->st_mode = kbuf->st_mode;
1547	st->st_nlink = kbuf->st_nlink;
1548	st->st_uid = kbuf->st_uid;
1549	st->st_gid = kbuf->st_gid;
1550	st->st_rdev = kbuf->st_rdev;
1551	st->st_size = kbuf->st_size;
1552#ifdef HAVE_STAT_ST_BLKSIZE
1553	st->st_blksize = kbuf->st_blksize;
1554#endif
1555#ifdef HAVE_STAT_ST_BLOCKS
1556	st->st_blocks = kbuf->st_blocks;
1557#endif
1558	st->st_atime = kbuf->st_atime_;
1559	st->st_mtime = kbuf->st_mtime_;
1560	st->st_ctime = kbuf->st_ctime_;
1561}
1562#endif
1563