- got client code cleartext passwords working again in cli_session_setup.
[samba.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 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         char lm_24[24], nt_24[24];
407
408         ip = ipzero;
409         ZERO_STRUCT(c);
410
411         username = smbw_getshared("USER");
412         if (!username) username = getenv("USER");
413         if (!username) username = "guest";
414
415         workgroup = smbw_getshared("WORKGROUP");
416         if (!workgroup) workgroup = lp_workgroup();
417
418         password = smbw_getshared("PASSWORD");
419         if (!password) password = "";
420
421         /* try to use an existing connection */
422         for (srv=smbw_srvs;srv;srv=srv->next) {
423                 if (strcmp(server,srv->server_name)==0 &&
424                     strcmp(share,srv->share_name)==0) return srv;
425         }
426
427         if (server[0] == 0) {
428                 errno = EPERM;
429                 return NULL;
430         }
431
432         make_nmb_name(&calling, global_myname, 0x0, "");
433         make_nmb_name(&called , server, 0x20, "");
434
435         DEBUG(4,("server_n=[%s] server=[%s]\n", server_n, server));
436
437         if ((p=strchr(server_n,'#')) && strcmp(p+1,"1D")==0) {
438                 struct in_addr sip;
439                 pstring s;
440
441                 fstrcpy(group, server_n);
442                 p = strchr(group,'#');
443                 *p = 0;
444                 
445                 /* cache the workgroup master lookup */
446                 slprintf(s,sizeof(s)-1,"MASTER_%s", group);
447                 if (!(server_n = smbw_getshared(s))) {
448                         if (!find_master_ip(group, &sip)) {
449                                 errno = ENOENT;
450                                 return NULL;
451                         }
452                         fstrcpy(group, inet_ntoa(sip));
453                         server_n = group;
454                         smbw_setshared(s,server_n);
455                 }
456         }
457
458         DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));
459
460  again:
461         slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n);
462
463         ip = ipzero;
464         if ((p=smbw_getshared(ipenv))) {
465                 ip = *(interpret_addr2(p));
466         }
467
468         /* have to open a new connection */
469         if (!cli_initialise(&c) || !cli_connect(&c, server_n, &ip)) {
470                 errno = ENOENT;
471                 return NULL;
472         }
473
474         if (!cli_session_request(&c, &calling, &called)) {
475                 cli_shutdown(&c);
476                 if (strcmp(called.name, "*SMBSERVER")) {
477                         make_nmb_name(&called , "*SMBSERVER", 0x20, "");
478                         goto again;
479                 }
480                 errno = ENOENT;
481                 return NULL;
482         }
483
484         DEBUG(4,(" session request ok\n"));
485
486         if (!cli_negprot(&c)) {
487                 cli_shutdown(&c);
488                 errno = ENOENT;
489                 return NULL;
490         }
491
492         SMBencrypt  ((uchar *)password,(uchar *)c.cryptkey,(uchar *)lm_24);
493         SMBNTencrypt((uchar *)password,(uchar *)c.cryptkey,(uchar *)nt_24);
494
495         if (!cli_session_setup(&c, username, 
496                                lm_24, 24,
497                                nt_24, 24,
498                                workgroup) &&
499             /* try an anonymous login if it failed */
500             !cli_session_setup(&c, "", "", 1,"", 0, workgroup)) {
501                 cli_shutdown(&c);
502                 errno = EPERM;
503                 return NULL;
504         }
505
506         DEBUG(4,(" session setup ok\n"));
507
508         if (!cli_send_tconX(&c, share, "?????",
509                             password, strlen(password)+1)) {
510                 errno = smbw_errno(&c);
511                 cli_shutdown(&c);
512                 return NULL;
513         }
514
515         smbw_setshared(ipenv,inet_ntoa(ip));
516         
517         DEBUG(4,(" tconx ok\n"));
518
519         srv = (struct smbw_server *)malloc(sizeof(*srv));
520         if (!srv) {
521                 errno = ENOMEM;
522                 goto failed;
523         }
524
525         ZERO_STRUCTP(srv);
526
527         srv->cli = c;
528
529         srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
530
531         srv->server_name = strdup(server);
532         if (!srv->server_name) {
533                 errno = ENOMEM;
534                 goto failed;
535         }
536
537         srv->share_name = strdup(share);
538         if (!srv->share_name) {
539                 errno = ENOMEM;
540                 goto failed;
541         }
542
543         /* some programs play with file descriptors fairly intimately. We
544            try to get out of the way by duping to a high fd number */
545         if (fcntl(SMBW_CLI_FD + srv->cli.fd, F_GETFD) && errno == EBADF) {
546                 if (dup2(srv->cli.fd,SMBW_CLI_FD+srv->cli.fd) == 
547                     srv->cli.fd+SMBW_CLI_FD) {
548                         close(srv->cli.fd);
549                         srv->cli.fd += SMBW_CLI_FD;
550                 }
551         }
552
553         DLIST_ADD(smbw_srvs, srv);
554
555         return srv;
556
557  failed:
558         cli_shutdown(&c);
559         if (!srv) return NULL;
560
561         if (srv->server_name) free(srv->server_name);
562         if (srv->share_name) free(srv->share_name);
563         free(srv);
564         return NULL;
565 }
566
567
568 /***************************************************** 
569 map a fd to a smbw_file structure
570 *******************************************************/
571 struct smbw_file *smbw_file(int fd)
572 {
573         struct smbw_file *file;
574
575         for (file=smbw_files;file;file=file->next) {
576                 if (file->fd == fd) return file;
577         }
578         return NULL;
579 }
580
581 /***************************************************** 
582 a wrapper for open()
583 *******************************************************/
584 int smbw_open(const char *fname, int flags, mode_t mode)
585 {
586         fstring server, share;
587         pstring path;
588         struct smbw_server *srv=NULL;
589         int eno=0, fd = -1;
590         struct smbw_file *file=NULL;
591
592         smbw_init();
593
594         if (!fname) {
595                 errno = EINVAL;
596                 return -1;
597         }
598
599         smbw_busy++;    
600
601         /* work out what server they are after */
602         smbw_parse_path(fname, server, share, path);
603
604         /* get a connection to the server */
605         srv = smbw_server(server, share);
606         if (!srv) {
607                 /* smbw_server sets errno */
608                 goto failed;
609         }
610
611         if (path[strlen(path)-1] == '\\') {
612                 fd = -1;
613         } else {
614                 fd = cli_open(&srv->cli, path, flags, DENY_NONE);
615         }
616         if (fd == -1) {
617                 /* it might be a directory. Maybe we should use chkpath? */
618                 eno = smbw_errno(&srv->cli);
619                 fd = smbw_dir_open(fname);
620                 if (fd == -1) errno = eno;
621                 smbw_busy--;
622                 return fd;
623         }
624
625         file = (struct smbw_file *)malloc(sizeof(*file));
626         if (!file) {
627                 errno = ENOMEM;
628                 goto failed;
629         }
630
631         ZERO_STRUCTP(file);
632
633         file->f = (struct smbw_filedes *)malloc(sizeof(*(file->f)));
634         if (!file->f) {
635                 errno = ENOMEM;
636                 goto failed;
637         }
638
639         ZERO_STRUCTP(file->f);
640
641         file->f->cli_fd = fd;
642         file->f->fname = strdup(path);
643         if (!file->f->fname) {
644                 errno = ENOMEM;
645                 goto failed;
646         }
647         file->srv = srv;
648         file->fd = open(SMBW_DUMMY, O_WRONLY);
649         if (file->fd == -1) {
650                 errno = EMFILE;
651                 goto failed;
652         }
653
654         if (bitmap_query(smbw_file_bmap, file->fd)) {
655                 DEBUG(0,("ERROR: fd used in smbw_open\n"));
656                 errno = EIO;
657                 goto failed;
658         }
659
660         file->f->ref_count=1;
661
662         bitmap_set(smbw_file_bmap, file->fd);
663
664         DLIST_ADD(smbw_files, file);
665
666         DEBUG(4,("opened %s\n", fname));
667
668         smbw_busy--;
669         return file->fd;
670
671  failed:
672         if (fd != -1) {
673                 cli_close(&srv->cli, fd);
674         }
675         if (file) {
676                 if (file->f) {
677                         if (file->f->fname) {
678                                 free(file->f->fname);
679                         }
680                         free(file->f);
681                 }
682                 free(file);
683         }
684         smbw_busy--;
685         return -1;
686 }
687
688
689 /***************************************************** 
690 a wrapper for pread()
691 *******************************************************/
692 ssize_t smbw_pread(int fd, void *buf, size_t count, off_t ofs)
693 {
694         struct smbw_file *file;
695         int ret;
696
697         smbw_busy++;
698
699         file = smbw_file(fd);
700         if (!file) {
701                 errno = EBADF;
702                 smbw_busy--;
703                 return -1;
704         }
705         
706         ret = cli_read(&file->srv->cli, file->f->cli_fd, buf, ofs, count);
707
708         if (ret == -1) {
709                 errno = smbw_errno(&file->srv->cli);
710                 smbw_busy--;
711                 return -1;
712         }
713
714         smbw_busy--;
715         return ret;
716 }
717
718 /***************************************************** 
719 a wrapper for read()
720 *******************************************************/
721 ssize_t smbw_read(int fd, void *buf, size_t count)
722 {
723         struct smbw_file *file;
724         int ret;
725
726         DEBUG(4,("smbw_read(%d, %d)\n", fd, (int)count));
727
728         smbw_busy++;
729
730         file = smbw_file(fd);
731         if (!file) {
732                 errno = EBADF;
733                 smbw_busy--;
734                 return -1;
735         }
736         
737         ret = cli_read(&file->srv->cli, file->f->cli_fd, buf, 
738                        file->f->offset, count);
739
740         if (ret == -1) {
741                 errno = smbw_errno(&file->srv->cli);
742                 smbw_busy--;
743                 return -1;
744         }
745
746         file->f->offset += ret;
747         
748         DEBUG(4,(" -> %d\n", ret));
749
750         smbw_busy--;
751         return ret;
752 }
753
754         
755
756 /***************************************************** 
757 a wrapper for write()
758 *******************************************************/
759 ssize_t smbw_write(int fd, void *buf, size_t count)
760 {
761         struct smbw_file *file;
762         int ret;
763
764         smbw_busy++;
765
766         file = smbw_file(fd);
767         if (!file) {
768                 errno = EBADF;
769                 smbw_busy--;
770                 return -1;
771         }
772         
773         ret = cli_write(&file->srv->cli, file->f->cli_fd, 0, buf, file->f->offset, count);
774
775         if (ret == -1) {
776                 errno = smbw_errno(&file->srv->cli);
777                 smbw_busy--;
778                 return -1;
779         }
780
781         file->f->offset += ret;
782
783         smbw_busy--;
784         return ret;
785 }
786
787 /***************************************************** 
788 a wrapper for pwrite()
789 *******************************************************/
790 ssize_t smbw_pwrite(int fd, void *buf, size_t count, off_t ofs)
791 {
792         struct smbw_file *file;
793         int ret;
794
795         smbw_busy++;
796
797         file = smbw_file(fd);
798         if (!file) {
799                 errno = EBADF;
800                 smbw_busy--;
801                 return -1;
802         }
803         
804         ret = cli_write(&file->srv->cli, file->f->cli_fd, 0, buf, ofs, count);
805
806         if (ret == -1) {
807                 errno = smbw_errno(&file->srv->cli);
808                 smbw_busy--;
809                 return -1;
810         }
811
812         smbw_busy--;
813         return ret;
814 }
815
816 /***************************************************** 
817 a wrapper for close()
818 *******************************************************/
819 int smbw_close(int fd)
820 {
821         struct smbw_file *file;
822
823         smbw_busy++;
824
825         file = smbw_file(fd);
826         if (!file) {
827                 int ret = smbw_dir_close(fd);
828                 smbw_busy--;
829                 return ret;
830         }
831         
832         if (file->f->ref_count == 1 &&
833             !cli_close(&file->srv->cli, file->f->cli_fd)) {
834                 errno = smbw_errno(&file->srv->cli);
835                 smbw_busy--;
836                 return -1;
837         }
838
839
840         bitmap_clear(smbw_file_bmap, file->fd);
841         close(file->fd);
842         
843         DLIST_REMOVE(smbw_files, file);
844
845         file->f->ref_count--;
846         if (file->f->ref_count == 0) {
847                 free(file->f->fname);
848                 free(file->f);
849         }
850         ZERO_STRUCTP(file);
851         free(file);
852         
853         smbw_busy--;
854
855         return 0;
856 }
857
858
859 /***************************************************** 
860 a wrapper for fcntl()
861 *******************************************************/
862 int smbw_fcntl(int fd, int cmd, long arg)
863 {
864         return 0;
865 }
866
867
868 /***************************************************** 
869 a wrapper for access()
870 *******************************************************/
871 int smbw_access(const char *name, int mode)
872 {
873         struct stat st;
874
875         DEBUG(4,("smbw_access(%s, 0x%x)\n", name, mode));
876
877         if (smbw_stat(name, &st)) return -1;
878
879         if (((mode & R_OK) && !(st.st_mode & S_IRUSR)) ||
880             ((mode & W_OK) && !(st.st_mode & S_IWUSR)) ||
881             ((mode & X_OK) && !(st.st_mode & S_IXUSR))) {
882                 errno = EACCES;
883                 return -1;
884         }
885         
886         return 0;
887 }
888
889 /***************************************************** 
890 a wrapper for realink() - needed for correct errno setting
891 *******************************************************/
892 int smbw_readlink(const char *path, char *buf, size_t bufsize)
893 {
894         struct stat st;
895         int ret;
896
897         ret = smbw_stat(path, &st);
898         if (ret != 0) {
899                 DEBUG(4,("readlink(%s) failed\n", path));
900                 return -1;
901         }
902         
903         /* it exists - say it isn't a link */
904         DEBUG(4,("readlink(%s) not a link\n", path));
905
906         errno = EINVAL;
907         return -1;
908 }
909
910
911 /***************************************************** 
912 a wrapper for unlink()
913 *******************************************************/
914 int smbw_unlink(const char *fname)
915 {
916         struct smbw_server *srv;
917         fstring server, share;
918         pstring path;
919
920         if (!fname) {
921                 errno = EINVAL;
922                 return -1;
923         }
924
925         smbw_init();
926
927         smbw_busy++;
928
929         /* work out what server they are after */
930         smbw_parse_path(fname, server, share, path);
931
932         /* get a connection to the server */
933         srv = smbw_server(server, share);
934         if (!srv) {
935                 /* smbw_server sets errno */
936                 goto failed;
937         }
938
939         if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
940                 int job = smbw_stat_printjob(srv, path, NULL, NULL);
941                 if (job == -1) {
942                         goto failed;
943                 }
944                 if (cli_printjob_del(&srv->cli, job) != 0) {
945                         goto failed;
946                 }
947         } else if (!cli_unlink(&srv->cli, path)) {
948                 errno = smbw_errno(&srv->cli);
949                 goto failed;
950         }
951
952         smbw_busy--;
953         return 0;
954
955  failed:
956         smbw_busy--;
957         return -1;
958 }
959
960
961 /***************************************************** 
962 a wrapper for rename()
963 *******************************************************/
964 int smbw_rename(const char *oldname, const char *newname)
965 {
966         struct smbw_server *srv;
967         fstring server1, share1;
968         pstring path1;
969         fstring server2, share2;
970         pstring path2;
971
972         if (!oldname || !newname) {
973                 errno = EINVAL;
974                 return -1;
975         }
976
977         smbw_init();
978
979         DEBUG(4,("smbw_rename(%s,%s)\n", oldname, newname));
980
981         smbw_busy++;
982
983         /* work out what server they are after */
984         smbw_parse_path(oldname, server1, share1, path1);
985         smbw_parse_path(newname, server2, share2, path2);
986
987         if (strcmp(server1, server2) || strcmp(share1, share2)) {
988                 /* can't cross filesystems */
989                 errno = EXDEV;
990                 return -1;
991         }
992
993         /* get a connection to the server */
994         srv = smbw_server(server1, share1);
995         if (!srv) {
996                 /* smbw_server sets errno */
997                 goto failed;
998         }
999
1000         if (!cli_rename(&srv->cli, path1, path2)) {
1001                 int eno = smbw_errno(&srv->cli);
1002                 if (eno != EEXIST ||
1003                     !cli_unlink(&srv->cli, path2) ||
1004                     !cli_rename(&srv->cli, path1, path2)) {
1005                         errno = eno;
1006                         goto failed;
1007                 }
1008         }
1009
1010         smbw_busy--;
1011         return 0;
1012
1013  failed:
1014         smbw_busy--;
1015         return -1;
1016 }
1017
1018
1019 /***************************************************** 
1020 a wrapper for utime and utimes
1021 *******************************************************/
1022 static int smbw_settime(const char *fname, time_t t)
1023 {
1024         struct smbw_server *srv;
1025         fstring server, share;
1026         pstring path;
1027         uint16 mode;
1028
1029         if (!fname) {
1030                 errno = EINVAL;
1031                 return -1;
1032         }
1033
1034         smbw_init();
1035
1036         smbw_busy++;
1037
1038         /* work out what server they are after */
1039         smbw_parse_path(fname, server, share, path);
1040
1041         /* get a connection to the server */
1042         srv = smbw_server(server, share);
1043         if (!srv) {
1044                 /* smbw_server sets errno */
1045                 goto failed;
1046         }
1047
1048         if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
1049                 errno = smbw_errno(&srv->cli);
1050                 goto failed;
1051         }
1052
1053         if (!cli_setatr(&srv->cli, path, mode, t)) {
1054                 /* some servers always refuse directory changes */
1055                 if (!(mode & aDIR)) {
1056                         errno = smbw_errno(&srv->cli);
1057                         goto failed;
1058                 }
1059         }
1060
1061         smbw_busy--;
1062         return 0;
1063
1064  failed:
1065         smbw_busy--;
1066         return -1;
1067 }
1068
1069 /***************************************************** 
1070 a wrapper for utime 
1071 *******************************************************/
1072 int smbw_utime(const char *fname, void *buf)
1073 {
1074         struct utimbuf *tbuf = (struct utimbuf *)buf;
1075         return smbw_settime(fname, tbuf?tbuf->modtime:time(NULL));
1076 }
1077
1078 /***************************************************** 
1079 a wrapper for utime 
1080 *******************************************************/
1081 int smbw_utimes(const char *fname, void *buf)
1082 {
1083         struct timeval *tbuf = (struct timeval *)buf;
1084         return smbw_settime(fname, tbuf?tbuf->tv_sec:time(NULL));
1085 }
1086
1087
1088 /***************************************************** 
1089 a wrapper for chown()
1090 *******************************************************/
1091 int smbw_chown(const char *fname, uid_t owner, gid_t group)
1092 {
1093         struct smbw_server *srv;
1094         fstring server, share;
1095         pstring path;
1096         uint16 mode;
1097
1098         if (!fname) {
1099                 errno = EINVAL;
1100                 return -1;
1101         }
1102
1103         smbw_init();
1104
1105         smbw_busy++;
1106
1107         /* work out what server they are after */
1108         smbw_parse_path(fname, server, share, path);
1109
1110         /* get a connection to the server */
1111         srv = smbw_server(server, share);
1112         if (!srv) {
1113                 /* smbw_server sets errno */
1114                 goto failed;
1115         }
1116
1117         if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
1118                 errno = smbw_errno(&srv->cli);
1119                 goto failed;
1120         }
1121         
1122         /* assume success */
1123
1124         smbw_busy--;
1125         return 0;
1126
1127  failed:
1128         smbw_busy--;
1129         return -1;
1130 }
1131
1132 /***************************************************** 
1133 a wrapper for chmod()
1134 *******************************************************/
1135 int smbw_chmod(const char *fname, mode_t newmode)
1136 {
1137         struct smbw_server *srv;
1138         fstring server, share;
1139         pstring path;
1140         uint32 mode;
1141
1142         if (!fname) {
1143                 errno = EINVAL;
1144                 return -1;
1145         }
1146
1147         smbw_init();
1148
1149         smbw_busy++;
1150
1151         /* work out what server they are after */
1152         smbw_parse_path(fname, server, share, path);
1153
1154         /* get a connection to the server */
1155         srv = smbw_server(server, share);
1156         if (!srv) {
1157                 /* smbw_server sets errno */
1158                 goto failed;
1159         }
1160
1161         mode = 0;
1162
1163         if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY;
1164         if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH;
1165         if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM;
1166         if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN;
1167
1168         if (!cli_setatr(&srv->cli, path, mode, 0)) {
1169                 errno = smbw_errno(&srv->cli);
1170                 goto failed;
1171         }
1172         
1173         smbw_busy--;
1174         return 0;
1175
1176  failed:
1177         smbw_busy--;
1178         return -1;
1179 }
1180
1181 /***************************************************** 
1182 a wrapper for lseek()
1183 *******************************************************/
1184 off_t smbw_lseek(int fd, off_t offset, int whence)
1185 {
1186         struct smbw_file *file;
1187         size_t size;
1188
1189         smbw_busy++;
1190
1191         file = smbw_file(fd);
1192         if (!file) {
1193                 off_t ret = smbw_dir_lseek(fd, offset, whence);
1194                 smbw_busy--;
1195                 return ret;
1196         }
1197
1198         switch (whence) {
1199         case SEEK_SET:
1200                 file->f->offset = offset;
1201                 break;
1202         case SEEK_CUR:
1203                 file->f->offset += offset;
1204                 break;
1205         case SEEK_END:
1206                 if (!cli_qfileinfo(&file->srv->cli, file->f->cli_fd, 
1207                                    NULL, &size, NULL, NULL, NULL, 
1208                                    NULL, NULL) &&
1209                     !cli_getattrE(&file->srv->cli, file->f->cli_fd, 
1210                                   NULL, &size, NULL, NULL, NULL)) {
1211                         errno = EINVAL;
1212                         smbw_busy--;
1213                         return -1;
1214                 }
1215                 file->f->offset = size + offset;
1216                 break;
1217         }
1218
1219         smbw_busy--;
1220         return file->f->offset;
1221 }
1222
1223
1224 /***************************************************** 
1225 a wrapper for dup()
1226 *******************************************************/
1227 int smbw_dup(int fd)
1228 {
1229         int fd2;
1230         struct smbw_file *file, *file2;
1231
1232         smbw_busy++;
1233
1234         file = smbw_file(fd);
1235         if (!file) {
1236                 errno = EBADF;
1237                 goto failed;
1238         }
1239
1240         fd2 = dup(file->fd);
1241         if (fd2 == -1) {
1242                 goto failed;
1243         }
1244
1245         if (bitmap_query(smbw_file_bmap, fd2)) {
1246                 DEBUG(0,("ERROR: fd already open in dup!\n"));
1247                 errno = EIO;
1248                 goto failed;
1249         }
1250
1251         file2 = (struct smbw_file *)malloc(sizeof(*file2));
1252         if (!file2) {
1253                 close(fd2);
1254                 errno = ENOMEM;
1255                 goto failed;
1256         }
1257
1258         ZERO_STRUCTP(file2);
1259
1260         *file2 = *file;
1261         file2->fd = fd2;
1262
1263         file->f->ref_count++;
1264
1265         bitmap_set(smbw_file_bmap, fd2);
1266         
1267         DLIST_ADD(smbw_files, file2);
1268         
1269         smbw_busy--;
1270         return fd2;
1271
1272  failed:
1273         smbw_busy--;
1274         return -1;
1275 }
1276
1277
1278 /***************************************************** 
1279 a wrapper for dup2()
1280 *******************************************************/
1281 int smbw_dup2(int fd, int fd2)
1282 {
1283         struct smbw_file *file, *file2;
1284
1285         smbw_busy++;
1286
1287         file = smbw_file(fd);
1288         if (!file) {
1289                 errno = EBADF;
1290                 goto failed;
1291         }
1292
1293         if (bitmap_query(smbw_file_bmap, fd2)) {
1294                 DEBUG(0,("ERROR: fd already open in dup2!\n"));
1295                 errno = EIO;
1296                 goto failed;
1297         }
1298
1299         if (dup2(file->fd, fd2) != fd2) {
1300                 goto failed;
1301         }
1302
1303         file2 = (struct smbw_file *)malloc(sizeof(*file2));
1304         if (!file2) {
1305                 close(fd2);
1306                 errno = ENOMEM;
1307                 goto failed;
1308         }
1309
1310         ZERO_STRUCTP(file2);
1311
1312         *file2 = *file;
1313         file2->fd = fd2;
1314
1315         file->f->ref_count++;
1316
1317         bitmap_set(smbw_file_bmap, fd2);
1318         
1319         DLIST_ADD(smbw_files, file2);
1320         
1321         smbw_busy--;
1322         return fd2;
1323
1324  failed:
1325         smbw_busy--;
1326         return -1;
1327 }
1328
1329
1330 /***************************************************** 
1331 close a connection to a server
1332 *******************************************************/
1333 static void smbw_srv_close(struct smbw_server *srv)
1334 {
1335         smbw_busy++;
1336
1337         cli_shutdown(&srv->cli);
1338
1339         free(srv->server_name);
1340         free(srv->share_name);
1341
1342         DLIST_REMOVE(smbw_srvs, srv);
1343
1344         ZERO_STRUCTP(srv);
1345
1346         free(srv);
1347         
1348         smbw_busy--;
1349 }
1350
1351 /***************************************************** 
1352 when we fork we have to close all connections and files
1353 in the child
1354 *******************************************************/
1355 int smbw_fork(void)
1356 {
1357         pid_t child;
1358         int p[2];
1359         char c=0;
1360         pstring line;
1361
1362         struct smbw_file *file, *next_file;
1363         struct smbw_server *srv, *next_srv;
1364
1365         if (pipe(p)) return real_fork();
1366
1367         child = real_fork();
1368
1369         if (child) {
1370                 /* block the parent for a moment until the sockets are
1371                    closed */
1372                 close(p[1]);
1373                 read(p[0], &c, 1);
1374                 close(p[0]);
1375                 return child;
1376         }
1377
1378         close(p[0]);
1379
1380         /* close all files */
1381         for (file=smbw_files;file;file=next_file) {
1382                 next_file = file->next;
1383                 close(file->fd);
1384         }
1385
1386         /* close all server connections */
1387         for (srv=smbw_srvs;srv;srv=next_srv) {
1388                 next_srv = srv->next;
1389                 smbw_srv_close(srv);
1390         }
1391
1392         slprintf(line,sizeof(line)-1,"PWD_%d", getpid());
1393         smbw_setshared(line,smbw_cwd);
1394
1395         /* unblock the parent */
1396         write(p[1], &c, 1);
1397         close(p[1]);
1398
1399         /* and continue in the child */
1400         return 0;
1401 }
1402
1403 #ifndef NO_ACL_WRAPPER
1404 /***************************************************** 
1405 say no to acls
1406 *******************************************************/
1407  int smbw_acl(const char *pathp, int cmd, int nentries, aclent_t *aclbufp)
1408 {
1409         if (cmd == GETACL || cmd == GETACLCNT) return 0;
1410         errno = ENOSYS;
1411         return -1;
1412 }
1413 #endif
1414
1415 #ifndef NO_FACL_WRAPPER
1416 /***************************************************** 
1417 say no to acls
1418 *******************************************************/
1419  int smbw_facl(int fd, int cmd, int nentries, aclent_t *aclbufp)
1420 {
1421         if (cmd == GETACL || cmd == GETACLCNT) return 0;
1422         errno = ENOSYS;
1423         return -1;
1424 }
1425 #endif
1426
1427
1428 #ifdef HAVE_STAT64
1429 /* this can't be in wrapped.c because of include conflicts */
1430  void stat64_convert(struct stat *st, struct stat64 *st64)
1431 {
1432         st64->st_size = st->st_size;
1433         st64->st_mode = st->st_mode;
1434         st64->st_ino = st->st_ino;
1435         st64->st_dev = st->st_dev;
1436         st64->st_rdev = st->st_rdev;
1437         st64->st_nlink = st->st_nlink;
1438         st64->st_uid = st->st_uid;
1439         st64->st_gid = st->st_gid;
1440         st64->st_atime = st->st_atime;
1441         st64->st_mtime = st->st_mtime;
1442         st64->st_ctime = st->st_ctime;
1443         st64->st_blksize = st->st_blksize;
1444         st64->st_blocks = st->st_blocks;
1445 }
1446 #endif
1447
1448 #ifdef HAVE_READDIR64
1449  void dirent64_convert(struct dirent *d, struct dirent64 *d64)
1450 {
1451         d64->d_ino = d->d_ino;
1452         d64->d_off = d->d_off;
1453         d64->d_reclen = d->d_reclen;
1454         pstrcpy(d64->d_name, d->d_name);
1455 }
1456 #endif
1457
1458
1459 #ifdef HAVE___XSTAT
1460 /* Definition of `struct stat' used in the linux kernel..  */
1461 struct kernel_stat {
1462         unsigned short int st_dev;
1463         unsigned short int __pad1;
1464         unsigned long int st_ino;
1465         unsigned short int st_mode;
1466         unsigned short int st_nlink;
1467         unsigned short int st_uid;
1468         unsigned short int st_gid;
1469         unsigned short int st_rdev;
1470         unsigned short int __pad2;
1471         unsigned long int st_size;
1472         unsigned long int st_blksize;
1473         unsigned long int st_blocks;
1474         unsigned long int st_atime;
1475         unsigned long int __unused1;
1476         unsigned long int st_mtime;
1477         unsigned long int __unused2;
1478         unsigned long int st_ctime;
1479         unsigned long int __unused3;
1480         unsigned long int __unused4;
1481         unsigned long int __unused5;
1482 };
1483
1484 /*
1485  * Prototype for gcc in 'fussy' mode.
1486  */
1487  void xstat_convert(int vers, struct stat *st, struct kernel_stat *kbuf);
1488  void xstat_convert(int vers, struct stat *st, struct kernel_stat *kbuf)
1489 {
1490 #ifdef _STAT_VER_LINUX_OLD
1491         if (vers == _STAT_VER_LINUX_OLD) {
1492                 memcpy(st, kbuf, sizeof(*st));
1493                 return;
1494         }
1495 #endif
1496
1497         ZERO_STRUCTP(st);
1498
1499         st->st_dev = kbuf->st_dev;
1500         st->st_ino = kbuf->st_ino;
1501         st->st_mode = kbuf->st_mode;
1502         st->st_nlink = kbuf->st_nlink;
1503         st->st_uid = kbuf->st_uid;
1504         st->st_gid = kbuf->st_gid;
1505         st->st_rdev = kbuf->st_rdev;
1506         st->st_size = kbuf->st_size;
1507         st->st_blksize = kbuf->st_blksize;
1508         st->st_blocks = kbuf->st_blocks;
1509         st->st_atime = kbuf->st_atime;
1510         st->st_mtime = kbuf->st_mtime;
1511         st->st_ctime = kbuf->st_ctime;
1512 }
1513 #endif