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