2 Unix SMB/Netbios implementation.
5 Copyright (C) Andrew Tridgell 1998
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.
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.
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.
27 static struct smbw_file *smbw_files;
28 static struct smbw_server *smbw_srvs;
30 struct bitmap *smbw_file_bmap;
31 extern pstring global_myname;
32 extern int DEBUGLEVEL;
36 /*****************************************************
38 *******************************************************/
41 extern BOOL in_client;
42 static int initialised;
43 static pstring servicesf = CONFIGFILE;
47 if (initialised) return;
53 setup_logging("smbw",True);
57 if ((p=getenv("SMBW_LOGFILE"))) {
61 smbw_file_bmap = bitmap_allocate(SMBW_MAX_OPEN);
62 if (!smbw_file_bmap) {
72 if (!lp_load(servicesf,True,False,False)) {
76 get_myname(global_myname,NULL);
78 if ((p=getenv("SMBW_DEBUG"))) {
82 if ((p=getenv(SMBW_PWD_ENV))) {
84 DEBUG(4,("Initial cwd from smb_cwd is %s\n", smb_cwd));
87 DEBUG(4,("Initial cwd from getwd is %s\n", smb_cwd));
94 /*****************************************************
95 determine if a file descriptor is a smb one
96 *******************************************************/
99 if (smbw_busy) return 0;
100 return smbw_file_bmap && bitmap_query(smbw_file_bmap, fd);
103 /*****************************************************
104 a crude inode number generator
105 *******************************************************/
106 ino_t smbw_inode(const char *name)
108 return (ino_t)str_checksum(name);
111 /*****************************************************
112 remove redundent stuff from a filename
113 *******************************************************/
114 void clean_fname(char *name)
125 DEBUG(5,("cleaning %s\n", name));
127 if ((p=strstr(name,"/./"))) {
135 if ((p=strstr(name,"//"))) {
143 if (strcmp(name,"/../")==0) {
148 if ((p=strstr(name,"/../"))) {
150 for (p2=(p>name?p-1:p);p2>name;p2--) {
151 if (p2[0] == '/') break;
159 if (strcmp(name,"/..")==0) {
165 p = l>=3?(name+l-3):name;
166 if (strcmp(p,"/..")==0) {
168 for (p2=p-1;p2>name;p2--) {
169 if (p2[0] == '/') break;
180 p = l>=2?(name+l-2):name;
181 if (strcmp(p,"/.")==0) {
189 if (strncmp(p=name,"./",2) == 0) {
197 if (l > 1 && p[l-1] == '/') {
205 /*****************************************************
206 parse a smb path into its components.
207 *******************************************************/
208 char *smbw_parse_path(const char *fname, char *server, char *share, char *path)
212 int len = strlen(SMBW_PREFIX)-1;
214 *server = *share = *path = 0;
216 if (fname[0] == '/') {
219 slprintf(s,sizeof(s)-1, "%s/%s", smb_cwd, fname);
223 DEBUG(5,("cleaned %s (fname=%s cwd=%s)\n",
226 if (strncmp(s,SMBW_PREFIX,len) ||
227 (s[len] != '/' && s[len] != 0)) return s;
240 len = MIN(len,sizeof(fstring)-1);
242 strncpy(server, p, len);
248 char *workgroup = getenv("SMBW_WORKGROUP");
249 if (!workgroup) workgroup = lp_workgroup();
250 slprintf(server,sizeof(fstring)-1, "%s#1D", workgroup);
252 fstrcpy(share,"IPC$");
266 len = MIN(len,sizeof(fstring)-1);
268 strncpy(share, p, len);
279 string_sub(path, "/", "\\");
282 DEBUG(5,("parsed path name=%s cwd=%s [%s] [%s] [%s]\n",
284 server, share, path));
289 /*****************************************************
290 determine if a path name (possibly relative) is in the
292 *******************************************************/
293 int smbw_path(const char *path)
295 fstring server, share;
298 int l=strlen(SMBW_PREFIX)-1;
300 if (path[0] == '/' && strncmp(path,SMBW_PREFIX,l)) {
304 if (smbw_busy) return 0;
308 DEBUG(3,("smbw_path(%s)\n", path));
310 cwd = smbw_parse_path(path, server, share, s);
312 if (strncmp(cwd,SMBW_PREFIX,l) == 0 &&
313 (cwd[l] == '/' || cwd[l] == 0)) {
320 /*****************************************************
321 return a unix errno from a SMB error pair
322 *******************************************************/
323 int smbw_errno(struct cli_state *c)
329 ret = cli_error(c, &eclass, &ecode);
332 DEBUG(3,("smbw_error %d %d (0x%x) -> %d\n",
333 (int)eclass, (int)ecode, (int)ecode, ret));
338 /*****************************************************
339 return a connection to a server (existing or new)
340 *******************************************************/
341 struct smbw_server *smbw_server(char *server, char *share)
343 struct smbw_server *srv=NULL;
348 struct nmb_name called, calling;
349 char *p, *server_n = server;
354 username = getenv("SMBW_USER");
355 if (!username) username = getenv("USER");
356 if (!username) username = "guest";
358 workgroup = getenv("SMBW_WORKGROUP");
359 if (!workgroup) workgroup = lp_workgroup();
361 password = getenv("SMBW_PASSWORD");
362 if (!password) password = "";
364 /* try to use an existing connection */
365 for (srv=smbw_srvs;srv;srv=srv->next) {
366 if (strcmp(server,srv->server_name)==0 &&
367 strcmp(share,srv->share_name)==0) return srv;
370 if (server[0] == 0) {
375 make_nmb_name(&calling, global_myname, 0x0, "");
376 make_nmb_name(&called , server, 0x20, "");
378 DEBUG(5,("server_n=[%s] server=[%s]\n", server_n, server));
380 if ((p=strchr(server_n,'#')) && strcmp(p+1,"1D")==0) {
382 fstrcpy(group, server_n);
383 p = strchr(group,'#');
385 if (!find_master(group, &ip)) {
389 fstrcpy(group, inet_ntoa(ip));
393 DEBUG(5,(" -> server_n=[%s] server=[%s]\n", server_n, server));
396 /* have to open a new connection */
397 if (!cli_initialise(&c) || !cli_connect(&c, server_n, NULL)) {
402 if (!cli_session_request(&c, &calling, &called)) {
404 if (strcmp(called.name, "*SMBSERVER")) {
405 make_nmb_name(&called , "*SMBSERVER", 0x20, "");
413 if (!cli_negprot(&c)) {
419 if (!cli_session_setup(&c, username,
420 password, strlen(password),
421 password, strlen(password),
428 if (!cli_send_tconX(&c, share, "?????",
429 password, strlen(password)+1)) {
430 errno = smbw_errno(&c);
435 srv = (struct smbw_server *)malloc(sizeof(*srv));
445 srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
447 srv->server_name = strdup(server);
448 if (!srv->server_name) {
453 srv->share_name = strdup(share);
454 if (!srv->share_name) {
459 /* some programs play with file descriptors fairly intimately. We
460 try to get out of the way by duping to a high fd number */
461 if (fcntl(SMBW_CLI_FD + srv->cli.fd, F_GETFD) && errno == EBADF) {
462 if (dup2(srv->cli.fd,SMBW_CLI_FD+srv->cli.fd) ==
463 srv->cli.fd+SMBW_CLI_FD) {
465 srv->cli.fd += SMBW_CLI_FD;
469 DLIST_ADD(smbw_srvs, srv);
475 if (!srv) return NULL;
477 if (srv->server_name) free(srv->server_name);
478 if (srv->share_name) free(srv->share_name);
484 /*****************************************************
485 map a fd to a smbw_file structure
486 *******************************************************/
487 struct smbw_file *smbw_file(int fd)
489 struct smbw_file *file;
491 for (file=smbw_files;file;file=file->next) {
492 if (file->fd == fd) return file;
497 /*****************************************************
499 *******************************************************/
500 int smbw_open(const char *fname, int flags, mode_t mode)
502 fstring server, share;
504 struct smbw_server *srv=NULL;
506 struct smbw_file *file=NULL;
508 DEBUG(4,("%s\n", __FUNCTION__));
519 /* work out what server they are after */
520 smbw_parse_path(fname, server, share, path);
522 /* get a connection to the server */
523 srv = smbw_server(server, share);
525 /* smbw_server sets errno */
529 if (path[strlen(path)-1] == '\\') {
532 fd = cli_open(&srv->cli, path, flags, DENY_NONE);
535 /* it might be a directory. Maybe we should use chkpath? */
536 fd = smbw_dir_open(fname);
545 file = (struct smbw_file *)malloc(sizeof(*file));
553 file->f = (struct smbw_filedes *)malloc(sizeof(*(file->f)));
559 ZERO_STRUCTP(file->f);
561 file->f->cli_fd = fd;
562 file->f->fname = strdup(path);
563 if (!file->f->fname) {
568 file->fd = open(SMBW_DUMMY, O_WRONLY);
569 if (file->fd == -1) {
574 if (bitmap_query(smbw_file_bmap, file->fd)) {
575 DEBUG(0,("ERROR: fd used in smbw_open\n"));
580 file->f->ref_count=1;
582 bitmap_set(smbw_file_bmap, file->fd);
584 DLIST_ADD(smbw_files, file);
586 DEBUG(4,("opened %s\n", fname));
593 cli_close(&srv->cli, fd);
597 if (file->f->fname) {
598 free(file->f->fname);
609 /*****************************************************
611 *******************************************************/
612 ssize_t smbw_read(int fd, void *buf, size_t count)
614 struct smbw_file *file;
618 __FUNCTION__, (int)count));
622 file = smbw_file(fd);
629 ret = cli_read(&file->srv->cli, file->f->cli_fd, buf, file->f->offset, count);
632 errno = smbw_errno(&file->srv->cli);
637 file->f->offset += ret;
643 /*****************************************************
644 a wrapper for write()
645 *******************************************************/
646 ssize_t smbw_write(int fd, void *buf, size_t count)
648 struct smbw_file *file;
651 DEBUG(4,("%s\n", __FUNCTION__));
655 file = smbw_file(fd);
657 DEBUG(3,("bad fd in read\n"));
663 ret = cli_write(&file->srv->cli, file->f->cli_fd, buf, file->f->offset, count);
666 errno = smbw_errno(&file->srv->cli);
671 file->f->offset += ret;
677 /*****************************************************
678 a wrapper for close()
679 *******************************************************/
680 int smbw_close(int fd)
682 struct smbw_file *file;
684 DEBUG(4,("%s\n", __FUNCTION__));
688 file = smbw_file(fd);
690 int ret = smbw_dir_close(fd);
695 if (file->f->ref_count == 1 &&
696 !cli_close(&file->srv->cli, file->f->cli_fd)) {
697 errno = smbw_errno(&file->srv->cli);
703 bitmap_clear(smbw_file_bmap, file->fd);
706 DLIST_REMOVE(smbw_files, file);
708 file->f->ref_count--;
709 if (file->f->ref_count == 0) {
710 free(file->f->fname);
722 /*****************************************************
723 a wrapper for fcntl()
724 *******************************************************/
725 int smbw_fcntl(int fd, int cmd, long arg)
727 DEBUG(4,("%s\n", __FUNCTION__));
732 /*****************************************************
733 a wrapper for access()
734 *******************************************************/
735 int smbw_access(const char *name, int mode)
738 /* how do we map this properly ?? */
739 return smbw_stat(name, &st);
742 /*****************************************************
743 a wrapper for realink() - needed for correct errno setting
744 *******************************************************/
745 int smbw_readlink(const char *path, char *buf, size_t bufsize)
750 ret = smbw_stat(path, &st);
752 DEBUG(4,("readlink(%s) failed\n", path));
756 /* it exists - say it isn't a link */
757 DEBUG(4,("readlink(%s) not a link\n", path));
764 /*****************************************************
765 a wrapper for unlink()
766 *******************************************************/
767 int smbw_unlink(const char *fname)
769 struct smbw_server *srv;
770 fstring server, share;
773 DEBUG(4,("%s (%s)\n", __FUNCTION__, fname));
784 /* work out what server they are after */
785 smbw_parse_path(fname, server, share, path);
787 /* get a connection to the server */
788 srv = smbw_server(server, share);
790 /* smbw_server sets errno */
794 if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
795 int job = smbw_stat_printjob(srv, path, NULL, NULL);
799 if (cli_printjob_del(&srv->cli, job) != 0) {
802 } else if (!cli_unlink(&srv->cli, path)) {
803 errno = smbw_errno(&srv->cli);
816 /*****************************************************
817 a wrapper for rename()
818 *******************************************************/
819 int smbw_rename(const char *oldname, const char *newname)
821 struct smbw_server *srv;
822 fstring server1, share1;
824 fstring server2, share2;
827 DEBUG(4,("%s (%s, %s)\n", __FUNCTION__, oldname, newname));
829 if (!oldname || !newname) {
838 /* work out what server they are after */
839 smbw_parse_path(oldname, server1, share1, path1);
840 smbw_parse_path(newname, server2, share2, path2);
842 if (strcmp(server1, server2) || strcmp(share1, share2)) {
843 /* can't cross filesystems */
848 /* get a connection to the server */
849 srv = smbw_server(server1, share1);
851 /* smbw_server sets errno */
855 if (!cli_rename(&srv->cli, path1, path2)) {
856 errno = smbw_errno(&srv->cli);
869 /*****************************************************
870 a wrapper for utime()
871 *******************************************************/
872 int smbw_utime(const char *fname, void *buf)
874 struct utimbuf *tbuf = (struct utimbuf *)buf;
875 struct smbw_server *srv;
876 fstring server, share;
880 DEBUG(4,("%s (%s)\n", __FUNCTION__, fname));
891 /* work out what server they are after */
892 smbw_parse_path(fname, server, share, path);
894 /* get a connection to the server */
895 srv = smbw_server(server, share);
897 /* smbw_server sets errno */
901 if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
902 errno = smbw_errno(&srv->cli);
906 if (!cli_setatr(&srv->cli, path, mode, tbuf->modtime)) {
907 errno = smbw_errno(&srv->cli);
919 /*****************************************************
920 a wrapper for chown()
921 *******************************************************/
922 int smbw_chown(const char *fname, uid_t owner, gid_t group)
924 struct smbw_server *srv;
925 fstring server, share;
929 DEBUG(4,("%s (%s)\n", __FUNCTION__, fname));
940 /* work out what server they are after */
941 smbw_parse_path(fname, server, share, path);
943 /* get a connection to the server */
944 srv = smbw_server(server, share);
946 /* smbw_server sets errno */
950 if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
951 errno = smbw_errno(&srv->cli);
965 /*****************************************************
966 a wrapper for chmod()
967 *******************************************************/
968 int smbw_chmod(const char *fname, mode_t newmode)
970 struct smbw_server *srv;
971 fstring server, share;
975 DEBUG(4,("%s (%s)\n", __FUNCTION__, fname));
986 /* work out what server they are after */
987 smbw_parse_path(fname, server, share, path);
989 /* get a connection to the server */
990 srv = smbw_server(server, share);
992 /* smbw_server sets errno */
996 if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
997 errno = smbw_errno(&srv->cli);
1001 /* assume success for the moment - need to add attribute mapping */
1011 /*****************************************************
1012 a wrapper for lseek()
1013 *******************************************************/
1014 off_t smbw_lseek(int fd, off_t offset, int whence)
1016 struct smbw_file *file;
1019 DEBUG(4,("%s\n", __FUNCTION__));
1023 file = smbw_file(fd);
1025 off_t ret = smbw_dir_lseek(fd, offset, whence);
1032 file->f->offset = offset;
1035 file->f->offset += offset;
1038 if (!cli_qfileinfo(&file->srv->cli, file->f->cli_fd,
1039 NULL, &size, NULL, NULL, NULL) &&
1040 !cli_getattrE(&file->srv->cli, file->f->cli_fd,
1041 NULL, &size, NULL, NULL, NULL)) {
1046 file->f->offset = size + offset;
1051 return file->f->offset;
1055 /*****************************************************
1057 *******************************************************/
1058 int smbw_dup(int fd)
1061 struct smbw_file *file, *file2;
1063 DEBUG(4,("%s\n", __FUNCTION__));
1067 file = smbw_file(fd);
1073 fd2 = dup(file->fd);
1078 if (bitmap_query(smbw_file_bmap, fd2)) {
1079 DEBUG(0,("ERROR: fd already open in dup!\n"));
1084 file2 = (struct smbw_file *)malloc(sizeof(*file2));
1091 ZERO_STRUCTP(file2);
1096 file->f->ref_count++;
1098 bitmap_set(smbw_file_bmap, fd2);
1100 DLIST_ADD(smbw_files, file2);
1111 /*****************************************************
1112 a wrapper for dup2()
1113 *******************************************************/
1114 int smbw_dup2(int fd, int fd2)
1116 struct smbw_file *file, *file2;
1118 DEBUG(4,("%s\n", __FUNCTION__));
1122 file = smbw_file(fd);
1128 if (bitmap_query(smbw_file_bmap, fd2)) {
1129 DEBUG(0,("ERROR: fd already open in dup2!\n"));
1134 if (dup2(file->fd, fd2) != fd2) {
1138 file2 = (struct smbw_file *)malloc(sizeof(*file2));
1145 ZERO_STRUCTP(file2);
1150 file->f->ref_count++;
1152 bitmap_set(smbw_file_bmap, fd2);
1154 DLIST_ADD(smbw_files, file2);