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