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