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