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 eno = smbw_errno(&srv->cli);
533 fd = smbw_dir_open(fname);
534 if (fd == -1) errno = eno;
539 file = (struct smbw_file *)malloc(sizeof(*file));
547 file->f = (struct smbw_filedes *)malloc(sizeof(*(file->f)));
553 ZERO_STRUCTP(file->f);
555 file->f->cli_fd = fd;
556 file->f->fname = strdup(path);
557 if (!file->f->fname) {
562 file->fd = open(SMBW_DUMMY, O_WRONLY);
563 if (file->fd == -1) {
568 if (bitmap_query(smbw_file_bmap, file->fd)) {
569 DEBUG(0,("ERROR: fd used in smbw_open\n"));
574 file->f->ref_count=1;
576 bitmap_set(smbw_file_bmap, file->fd);
578 DLIST_ADD(smbw_files, file);
580 DEBUG(4,("opened %s\n", fname));
587 cli_close(&srv->cli, fd);
591 if (file->f->fname) {
592 free(file->f->fname);
603 /*****************************************************
604 a wrapper for pread()
605 *******************************************************/
606 ssize_t smbw_pread(int fd, void *buf, size_t count, off_t ofs)
608 struct smbw_file *file;
613 file = smbw_file(fd);
620 ret = cli_read(&file->srv->cli, file->f->cli_fd, buf, ofs, count);
623 errno = smbw_errno(&file->srv->cli);
632 /*****************************************************
634 *******************************************************/
635 ssize_t smbw_read(int fd, void *buf, size_t count)
637 struct smbw_file *file;
642 file = smbw_file(fd);
649 ret = cli_read(&file->srv->cli, file->f->cli_fd, buf,
650 file->f->offset, count);
653 errno = smbw_errno(&file->srv->cli);
658 file->f->offset += ret;
666 /*****************************************************
667 a wrapper for write()
668 *******************************************************/
669 ssize_t smbw_write(int fd, void *buf, size_t count)
671 struct smbw_file *file;
676 file = smbw_file(fd);
678 DEBUG(3,("bad fd in read\n"));
684 ret = cli_write(&file->srv->cli, file->f->cli_fd, buf, file->f->offset, count);
687 errno = smbw_errno(&file->srv->cli);
692 file->f->offset += ret;
698 /*****************************************************
699 a wrapper for pwrite()
700 *******************************************************/
701 ssize_t smbw_pwrite(int fd, void *buf, size_t count, off_t ofs)
703 struct smbw_file *file;
708 file = smbw_file(fd);
710 DEBUG(3,("bad fd in read\n"));
716 ret = cli_write(&file->srv->cli, file->f->cli_fd, buf, ofs, count);
719 errno = smbw_errno(&file->srv->cli);
728 /*****************************************************
729 a wrapper for close()
730 *******************************************************/
731 int smbw_close(int fd)
733 struct smbw_file *file;
737 file = smbw_file(fd);
739 int ret = smbw_dir_close(fd);
744 if (file->f->ref_count == 1 &&
745 !cli_close(&file->srv->cli, file->f->cli_fd)) {
746 errno = smbw_errno(&file->srv->cli);
752 bitmap_clear(smbw_file_bmap, file->fd);
755 DLIST_REMOVE(smbw_files, file);
757 file->f->ref_count--;
758 if (file->f->ref_count == 0) {
759 free(file->f->fname);
771 /*****************************************************
772 a wrapper for fcntl()
773 *******************************************************/
774 int smbw_fcntl(int fd, int cmd, long arg)
780 /*****************************************************
781 a wrapper for access()
782 *******************************************************/
783 int smbw_access(const char *name, int mode)
786 /* how do we map this properly ?? */
787 return smbw_stat(name, &st);
790 /*****************************************************
791 a wrapper for realink() - needed for correct errno setting
792 *******************************************************/
793 int smbw_readlink(const char *path, char *buf, size_t bufsize)
798 ret = smbw_stat(path, &st);
800 DEBUG(4,("readlink(%s) failed\n", path));
804 /* it exists - say it isn't a link */
805 DEBUG(4,("readlink(%s) not a link\n", path));
812 /*****************************************************
813 a wrapper for unlink()
814 *******************************************************/
815 int smbw_unlink(const char *fname)
817 struct smbw_server *srv;
818 fstring server, share;
830 /* work out what server they are after */
831 smbw_parse_path(fname, server, share, path);
833 /* get a connection to the server */
834 srv = smbw_server(server, share);
836 /* smbw_server sets errno */
840 if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
841 int job = smbw_stat_printjob(srv, path, NULL, NULL);
845 if (cli_printjob_del(&srv->cli, job) != 0) {
848 } else if (!cli_unlink(&srv->cli, path)) {
849 errno = smbw_errno(&srv->cli);
862 /*****************************************************
863 a wrapper for rename()
864 *******************************************************/
865 int smbw_rename(const char *oldname, const char *newname)
867 struct smbw_server *srv;
868 fstring server1, share1;
870 fstring server2, share2;
873 if (!oldname || !newname) {
882 /* work out what server they are after */
883 smbw_parse_path(oldname, server1, share1, path1);
884 smbw_parse_path(newname, server2, share2, path2);
886 if (strcmp(server1, server2) || strcmp(share1, share2)) {
887 /* can't cross filesystems */
892 /* get a connection to the server */
893 srv = smbw_server(server1, share1);
895 /* smbw_server sets errno */
899 if (!cli_rename(&srv->cli, path1, path2)) {
900 errno = smbw_errno(&srv->cli);
913 /*****************************************************
914 a wrapper for utime and utimes
915 *******************************************************/
916 static int smbw_settime(const char *fname, time_t t)
918 struct smbw_server *srv;
919 fstring server, share;
932 /* work out what server they are after */
933 smbw_parse_path(fname, server, share, path);
935 /* get a connection to the server */
936 srv = smbw_server(server, share);
938 /* smbw_server sets errno */
942 if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
943 errno = smbw_errno(&srv->cli);
947 if (!cli_setatr(&srv->cli, path, mode, t)) {
948 errno = smbw_errno(&srv->cli);
960 /*****************************************************
962 *******************************************************/
963 int smbw_utime(const char *fname, void *buf)
965 struct utimbuf *tbuf = (struct utimbuf *)buf;
966 return smbw_settime(fname, tbuf?tbuf->modtime:time(NULL));
969 /*****************************************************
971 *******************************************************/
972 int smbw_utimes(const char *fname, void *buf)
974 struct timeval *tbuf = (struct timeval *)buf;
975 return smbw_settime(fname, tbuf?tbuf->tv_sec:time(NULL));
979 /*****************************************************
980 a wrapper for chown()
981 *******************************************************/
982 int smbw_chown(const char *fname, uid_t owner, gid_t group)
984 struct smbw_server *srv;
985 fstring server, share;
998 /* work out what server they are after */
999 smbw_parse_path(fname, server, share, path);
1001 /* get a connection to the server */
1002 srv = smbw_server(server, share);
1004 /* smbw_server sets errno */
1008 if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
1009 errno = smbw_errno(&srv->cli);
1013 /* assume success */
1023 /*****************************************************
1024 a wrapper for chmod()
1025 *******************************************************/
1026 int smbw_chmod(const char *fname, mode_t newmode)
1028 struct smbw_server *srv;
1029 fstring server, share;
1042 /* work out what server they are after */
1043 smbw_parse_path(fname, server, share, path);
1045 /* get a connection to the server */
1046 srv = smbw_server(server, share);
1048 /* smbw_server sets errno */
1052 if (!cli_getatr(&srv->cli, path, &mode, NULL, NULL)) {
1053 errno = smbw_errno(&srv->cli);
1057 /* assume success for the moment - need to add attribute mapping */
1067 /*****************************************************
1068 a wrapper for lseek()
1069 *******************************************************/
1070 off_t smbw_lseek(int fd, off_t offset, int whence)
1072 struct smbw_file *file;
1077 file = smbw_file(fd);
1079 off_t ret = smbw_dir_lseek(fd, offset, whence);
1086 file->f->offset = offset;
1089 file->f->offset += offset;
1092 if (!cli_qfileinfo(&file->srv->cli, file->f->cli_fd,
1093 NULL, &size, NULL, NULL, NULL) &&
1094 !cli_getattrE(&file->srv->cli, file->f->cli_fd,
1095 NULL, &size, NULL, NULL, NULL)) {
1100 file->f->offset = size + offset;
1105 return file->f->offset;
1109 /*****************************************************
1111 *******************************************************/
1112 int smbw_dup(int fd)
1115 struct smbw_file *file, *file2;
1119 file = smbw_file(fd);
1125 fd2 = dup(file->fd);
1130 if (bitmap_query(smbw_file_bmap, fd2)) {
1131 DEBUG(0,("ERROR: fd already open in dup!\n"));
1136 file2 = (struct smbw_file *)malloc(sizeof(*file2));
1143 ZERO_STRUCTP(file2);
1148 file->f->ref_count++;
1150 bitmap_set(smbw_file_bmap, fd2);
1152 DLIST_ADD(smbw_files, file2);
1163 /*****************************************************
1164 a wrapper for dup2()
1165 *******************************************************/
1166 int smbw_dup2(int fd, int fd2)
1168 struct smbw_file *file, *file2;
1172 file = smbw_file(fd);
1178 if (bitmap_query(smbw_file_bmap, fd2)) {
1179 DEBUG(0,("ERROR: fd already open in dup2!\n"));
1184 if (dup2(file->fd, fd2) != fd2) {
1188 file2 = (struct smbw_file *)malloc(sizeof(*file2));
1195 ZERO_STRUCTP(file2);
1200 file->f->ref_count++;
1202 bitmap_set(smbw_file_bmap, fd2);
1204 DLIST_ADD(smbw_files, file2);