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 lp_load(servicesf,True,False,False);
74 get_myname(global_myname,NULL);
76 if ((p=getenv("SMBW_DEBUG"))) {
80 if ((p=getenv(SMBW_PWD_ENV))) {
82 DEBUG(4,("Initial cwd from smb_cwd is %s\n", smb_cwd));
85 DEBUG(4,("Initial cwd from getwd is %s\n", smb_cwd));
92 /*****************************************************
93 determine if a file descriptor is a smb one
94 *******************************************************/
97 if (smbw_busy) return 0;
98 return smbw_file_bmap && bitmap_query(smbw_file_bmap, fd);
101 /*****************************************************
102 a crude inode number generator
103 *******************************************************/
104 ino_t smbw_inode(const char *name)
106 return (ino_t)str_checksum(name);
109 /*****************************************************
110 remove redundent stuff from a filename
111 *******************************************************/
112 void clean_fname(char *name)
123 DEBUG(5,("cleaning %s\n", name));
125 if ((p=strstr(name,"/./"))) {
133 if ((p=strstr(name,"//"))) {
141 if (strcmp(name,"/../")==0) {
146 if ((p=strstr(name,"/../"))) {
148 for (p2=(p>name?p-1:p);p2>name;p2--) {
149 if (p2[0] == '/') break;
157 if (strcmp(name,"/..")==0) {
163 p = l>=3?(name+l-3):name;
164 if (strcmp(p,"/..")==0) {
166 for (p2=p-1;p2>name;p2--) {
167 if (p2[0] == '/') break;
178 p = l>=2?(name+l-2):name;
179 if (strcmp(p,"/.")==0) {
187 if (strncmp(p=name,"./",2) == 0) {
195 if (l > 1 && p[l-1] == '/') {
203 /*****************************************************
204 parse a smb path into its components.
205 *******************************************************/
206 char *smbw_parse_path(const char *fname, char *server, char *share, char *path)
210 int len = strlen(SMBW_PREFIX)-1;
212 *server = *share = *path = 0;
214 if (fname[0] == '/') {
217 slprintf(s,sizeof(s)-1, "%s/%s", smb_cwd, fname);
221 DEBUG(5,("cleaned %s (fname=%s cwd=%s)\n",
224 if (strncmp(s,SMBW_PREFIX,len) ||
225 (s[len] != '/' && s[len] != 0)) return s;
238 len = MIN(len,sizeof(fstring)-1);
240 strncpy(server, p, len);
246 char *workgroup = getenv("SMBW_WORKGROUP");
247 if (!workgroup) workgroup = lp_workgroup();
248 slprintf(server,sizeof(fstring)-1, "%s#1D", workgroup);
250 fstrcpy(share,"IPC$");
264 len = MIN(len,sizeof(fstring)-1);
266 strncpy(share, p, len);
277 string_sub(path, "/", "\\");
280 DEBUG(5,("parsed path name=%s cwd=%s [%s] [%s] [%s]\n",
282 server, share, path));
287 /*****************************************************
288 determine if a path name (possibly relative) is in the
290 *******************************************************/
291 int smbw_path(const char *path)
293 fstring server, share;
296 int l=strlen(SMBW_PREFIX)-1;
298 if (path[0] == '/' && strncmp(path,SMBW_PREFIX,l)) {
302 if (smbw_busy) return 0;
306 DEBUG(3,("smbw_path(%s)\n", path));
308 cwd = smbw_parse_path(path, server, share, s);
310 if (strncmp(cwd,SMBW_PREFIX,l) == 0 &&
311 (cwd[l] == '/' || cwd[l] == 0)) {
318 /*****************************************************
319 return a unix errno from a SMB error pair
320 *******************************************************/
321 int smbw_errno(struct cli_state *c)
327 ret = cli_error(c, &eclass, &ecode);
330 DEBUG(3,("smbw_error %d %d (0x%x) -> %d\n",
331 (int)eclass, (int)ecode, (int)ecode, ret));
336 /*****************************************************
337 return a connection to a server (existing or new)
338 *******************************************************/
339 struct smbw_server *smbw_server(char *server, char *share)
341 struct smbw_server *srv=NULL;
346 struct nmb_name called, calling;
347 char *p, *server_n = server;
352 username = getenv("SMBW_USER");
353 if (!username) username = getenv("USER");
354 if (!username) username = "guest";
356 workgroup = getenv("SMBW_WORKGROUP");
357 if (!workgroup) workgroup = lp_workgroup();
359 password = getenv("SMBW_PASSWORD");
360 if (!password) password = "";
362 /* try to use an existing connection */
363 for (srv=smbw_srvs;srv;srv=srv->next) {
364 if (strcmp(server,srv->server_name)==0 &&
365 strcmp(share,srv->share_name)==0) return srv;
368 if (server[0] == 0) {
373 make_nmb_name(&calling, global_myname, 0x0, "");
374 make_nmb_name(&called , server, 0x20, "");
376 DEBUG(5,("server_n=[%s] server=[%s]\n", server_n, server));
378 if ((p=strchr(server_n,'#')) && strcmp(p+1,"1D")==0) {
380 fstrcpy(group, server_n);
381 p = strchr(group,'#');
383 if (!find_master(group, &ip)) {
387 fstrcpy(group, inet_ntoa(ip));
391 DEBUG(5,(" -> server_n=[%s] server=[%s]\n", server_n, server));
394 /* have to open a new connection */
395 if (!cli_initialise(&c) || !cli_connect(&c, server_n, NULL)) {
400 if (!cli_session_request(&c, &calling, &called)) {
402 if (strcmp(called.name, "*SMBSERVER")) {
403 make_nmb_name(&called , "*SMBSERVER", 0x20, "");
411 if (!cli_negprot(&c)) {
417 if (!cli_session_setup(&c, username,
418 password, strlen(password),
419 password, strlen(password),
426 if (!cli_send_tconX(&c, share, "?????",
427 password, strlen(password)+1)) {
428 errno = smbw_errno(&c);
433 srv = (struct smbw_server *)malloc(sizeof(*srv));
443 srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
445 srv->server_name = strdup(server);
446 if (!srv->server_name) {
451 srv->share_name = strdup(share);
452 if (!srv->share_name) {
457 /* some programs play with file descriptors fairly intimately. We
458 try to get out of the way by duping to a high fd number */
459 if (fcntl(SMBW_CLI_FD + srv->cli.fd, F_GETFD) && errno == EBADF) {
460 if (dup2(srv->cli.fd,SMBW_CLI_FD+srv->cli.fd) ==
461 srv->cli.fd+SMBW_CLI_FD) {
463 srv->cli.fd += SMBW_CLI_FD;
467 DLIST_ADD(smbw_srvs, srv);
473 if (!srv) return NULL;
475 if (srv->server_name) free(srv->server_name);
476 if (srv->share_name) free(srv->share_name);
482 /*****************************************************
483 map a fd to a smbw_file structure
484 *******************************************************/
485 struct smbw_file *smbw_file(int fd)
487 struct smbw_file *file;
489 for (file=smbw_files;file;file=file->next) {
490 if (file->fd == fd) return file;
495 /*****************************************************
497 *******************************************************/
498 int smbw_open(const char *fname, int flags, mode_t mode)
500 fstring server, share;
502 struct smbw_server *srv=NULL;
504 struct smbw_file *file=NULL;
515 /* work out what server they are after */
516 smbw_parse_path(fname, server, share, path);
518 /* get a connection to the server */
519 srv = smbw_server(server, share);
521 /* smbw_server sets errno */
525 if (path[strlen(path)-1] == '\\') {
528 fd = cli_open(&srv->cli, path, flags, DENY_NONE);
531 /* it might be a directory. Maybe we should use chkpath? */
532 fd = smbw_dir_open(fname);
541 file = (struct smbw_file *)malloc(sizeof(*file));
549 file->f = (struct smbw_filedes *)malloc(sizeof(*(file->f)));
555 ZERO_STRUCTP(file->f);
557 file->f->cli_fd = fd;
558 file->f->fname = strdup(path);
559 if (!file->f->fname) {
564 file->fd = open(SMBW_DUMMY, O_WRONLY);
565 if (file->fd == -1) {
570 if (bitmap_query(smbw_file_bmap, file->fd)) {
571 DEBUG(0,("ERROR: fd used in smbw_open\n"));
576 file->f->ref_count=1;
578 bitmap_set(smbw_file_bmap, file->fd);
580 DLIST_ADD(smbw_files, file);
582 DEBUG(4,("opened %s\n", fname));
589 cli_close(&srv->cli, fd);
593 if (file->f->fname) {
594 free(file->f->fname);
605 /*****************************************************
606 a wrapper for pread()
607 *******************************************************/
608 ssize_t smbw_pread(int fd, void *buf, size_t count, off_t ofs)
610 struct smbw_file *file;
615 file = smbw_file(fd);
622 ret = cli_read(&file->srv->cli, file->f->cli_fd, buf, ofs, count);
625 errno = smbw_errno(&file->srv->cli);
634 /*****************************************************
636 *******************************************************/
637 ssize_t smbw_read(int fd, void *buf, size_t count)
639 struct smbw_file *file;
644 file = smbw_file(fd);
651 ret = cli_read(&file->srv->cli, file->f->cli_fd, buf,
652 file->f->offset, count);
655 errno = smbw_errno(&file->srv->cli);
660 file->f->offset += ret;
668 /*****************************************************
669 a wrapper for write()
670 *******************************************************/
671 ssize_t smbw_write(int fd, void *buf, size_t count)
673 struct smbw_file *file;
678 file = smbw_file(fd);
680 DEBUG(3,("bad fd in read\n"));
686 ret = cli_write(&file->srv->cli, file->f->cli_fd, buf, file->f->offset, count);
689 errno = smbw_errno(&file->srv->cli);
694 file->f->offset += ret;
700 /*****************************************************
701 a wrapper for pwrite()
702 *******************************************************/
703 ssize_t smbw_pwrite(int fd, void *buf, size_t count, off_t ofs)
705 struct smbw_file *file;
710 file = smbw_file(fd);
712 DEBUG(3,("bad fd in read\n"));
718 ret = cli_write(&file->srv->cli, file->f->cli_fd, buf, ofs, count);
721 errno = smbw_errno(&file->srv->cli);
730 /*****************************************************
731 a wrapper for close()
732 *******************************************************/
733 int smbw_close(int fd)
735 struct smbw_file *file;
739 file = smbw_file(fd);
741 int ret = smbw_dir_close(fd);
746 if (file->f->ref_count == 1 &&
747 !cli_close(&file->srv->cli, file->f->cli_fd)) {
748 errno = smbw_errno(&file->srv->cli);
754 bitmap_clear(smbw_file_bmap, file->fd);
757 DLIST_REMOVE(smbw_files, file);
759 file->f->ref_count--;
760 if (file->f->ref_count == 0) {
761 free(file->f->fname);
773 /*****************************************************
774 a wrapper for fcntl()
775 *******************************************************/
776 int smbw_fcntl(int fd, int cmd, long arg)
782 /*****************************************************
783 a wrapper for access()
784 *******************************************************/
785 int smbw_access(const char *name, int mode)
788 /* how do we map this properly ?? */
789 return smbw_stat(name, &st);
792 /*****************************************************
793 a wrapper for realink() - needed for correct errno setting
794 *******************************************************/
795 int smbw_readlink(const char *path, char *buf, size_t bufsize)
800 ret = smbw_stat(path, &st);
802 DEBUG(4,("readlink(%s) failed\n", path));
806 /* it exists - say it isn't a link */
807 DEBUG(4,("readlink(%s) not a link\n", path));
814 /*****************************************************
815 a wrapper for unlink()
816 *******************************************************/
817 int smbw_unlink(const char *fname)
819 struct smbw_server *srv;
820 fstring server, share;
832 /* work out what server they are after */
833 smbw_parse_path(fname, server, share, path);
835 /* get a connection to the server */
836 srv = smbw_server(server, share);
838 /* smbw_server sets errno */
842 if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
843 int job = smbw_stat_printjob(srv, path, NULL, NULL);
847 if (cli_printjob_del(&srv->cli, job) != 0) {
850 } else if (!cli_unlink(&srv->cli, path)) {
851 errno = smbw_errno(&srv->cli);
864 /*****************************************************
865 a wrapper for rename()
866 *******************************************************/
867 int smbw_rename(const char *oldname, const char *newname)
869 struct smbw_server *srv;
870 fstring server1, share1;
872 fstring server2, share2;
875 if (!oldname || !newname) {
884 /* work out what server they are after */
885 smbw_parse_path(oldname, server1, share1, path1);
886 smbw_parse_path(newname, server2, share2, path2);
888 if (strcmp(server1, server2) || strcmp(share1, share2)) {
889 /* can't cross filesystems */
894 /* get a connection to the server */
895 srv = smbw_server(server1, share1);
897 /* smbw_server sets errno */
901 if (!cli_rename(&srv->cli, path1, path2)) {
902 errno = smbw_errno(&srv->cli);
915 /*****************************************************
916 a wrapper for utime and utimes
917 *******************************************************/
918 static int smbw_settime(const char *fname, time_t t)
920 struct smbw_server *srv;
921 fstring server, share;
934 /* work out what server they are after */
935 smbw_parse_path(fname, server, share, path);
937 /* get a connection to the server */
938 srv = smbw_server(server, share);
940 /* smbw_server sets errno */
944 if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
945 errno = smbw_errno(&srv->cli);
949 if (!cli_setatr(&srv->cli, path, mode, t)) {
950 errno = smbw_errno(&srv->cli);
962 /*****************************************************
964 *******************************************************/
965 int smbw_utime(const char *fname, void *buf)
967 struct utimbuf *tbuf = (struct utimbuf *)buf;
968 return smbw_settime(fname, tbuf?tbuf->modtime:time(NULL));
971 /*****************************************************
973 *******************************************************/
974 int smbw_utimes(const char *fname, void *buf)
976 struct timeval *tbuf = (struct timeval *)buf;
977 return smbw_settime(fname, tbuf?tbuf->tv_sec:time(NULL));
981 /*****************************************************
982 a wrapper for chown()
983 *******************************************************/
984 int smbw_chown(const char *fname, uid_t owner, gid_t group)
986 struct smbw_server *srv;
987 fstring server, share;
1000 /* work out what server they are after */
1001 smbw_parse_path(fname, server, share, path);
1003 /* get a connection to the server */
1004 srv = smbw_server(server, share);
1006 /* smbw_server sets errno */
1010 if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
1011 errno = smbw_errno(&srv->cli);
1015 /* assume success */
1025 /*****************************************************
1026 a wrapper for chmod()
1027 *******************************************************/
1028 int smbw_chmod(const char *fname, mode_t newmode)
1030 struct smbw_server *srv;
1031 fstring server, share;
1044 /* work out what server they are after */
1045 smbw_parse_path(fname, server, share, path);
1047 /* get a connection to the server */
1048 srv = smbw_server(server, share);
1050 /* smbw_server sets errno */
1054 if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
1055 errno = smbw_errno(&srv->cli);
1059 /* assume success for the moment - need to add attribute mapping */
1069 /*****************************************************
1070 a wrapper for lseek()
1071 *******************************************************/
1072 off_t smbw_lseek(int fd, off_t offset, int whence)
1074 struct smbw_file *file;
1079 file = smbw_file(fd);
1081 off_t ret = smbw_dir_lseek(fd, offset, whence);
1088 file->f->offset = offset;
1091 file->f->offset += offset;
1094 if (!cli_qfileinfo(&file->srv->cli, file->f->cli_fd,
1095 NULL, &size, NULL, NULL, NULL) &&
1096 !cli_getattrE(&file->srv->cli, file->f->cli_fd,
1097 NULL, &size, NULL, NULL, NULL)) {
1102 file->f->offset = size + offset;
1107 return file->f->offset;
1111 /*****************************************************
1113 *******************************************************/
1114 int smbw_dup(int fd)
1117 struct smbw_file *file, *file2;
1121 file = smbw_file(fd);
1127 fd2 = dup(file->fd);
1132 if (bitmap_query(smbw_file_bmap, fd2)) {
1133 DEBUG(0,("ERROR: fd already open in dup!\n"));
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);
1165 /*****************************************************
1166 a wrapper for dup2()
1167 *******************************************************/
1168 int smbw_dup2(int fd, int fd2)
1170 struct smbw_file *file, *file2;
1174 file = smbw_file(fd);
1180 if (bitmap_query(smbw_file_bmap, fd2)) {
1181 DEBUG(0,("ERROR: fd already open in dup2!\n"));
1186 if (dup2(file->fd, fd2) != fd2) {
1190 file2 = (struct smbw_file *)malloc(sizeof(*file2));
1197 ZERO_STRUCTP(file2);
1202 file->f->ref_count++;
1204 bitmap_set(smbw_file_bmap, fd2);
1206 DLIST_ADD(smbw_files, file2);