2
Unix SMB/Netbios implementation.
5
Copyright (C) Andrew Tridgell 1998
6
Copyright (C) Derrell Lipman 2003-2005
8
This program is free software; you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation; either version 3 of the License, or
11
(at your option) any later version.
13
This program is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
GNU General Public License for more details.
18
You should have received a copy of the GNU General Public License
19
along with this program. If not, see <http://www.gnu.org/licenses/>.
28
#include "bsd-strlfunc.h"
30
typedef enum StartupType
36
int smbw_fd_map[__FD_SETSIZE];
37
int smbw_ref_count[__FD_SETSIZE];
38
char smbw_cwd[PATH_MAX];
39
char smbw_prefix[] = SMBW_PREFIX;
41
/* needs to be here because of dumb include files on some systems */
42
int creat_bits = O_WRONLY|O_CREAT|O_TRUNC;
44
int smbw_initialized = 0;
46
static int debug_level = 0;
48
static SMBCCTX *smbw_ctx;
50
extern int smbw_debug;
53
/*****************************************************
54
smbw_ref -- manipulate reference counts
55
******************************************************/
56
int smbw_ref(int client_fd, Ref_Count_Type type, ...)
60
/* client id values begin at SMBC_BASE_FC. */
61
client_fd -= SMBC_BASE_FD;
66
case SMBW_RCT_Increment:
67
return ++smbw_ref_count[client_fd];
69
case SMBW_RCT_Decrement:
70
return --smbw_ref_count[client_fd];
73
return smbw_ref_count[client_fd];
76
return (smbw_ref_count[client_fd] = va_arg(ap, int));
86
* Return a username and password given a server and share name
88
* Returns 0 upon success;
89
* non-zero otherwise, and errno is set to indicate the error.
91
static void get_envvar_auth_data(const char *srv,
101
/* Fall back to environment variables */
103
w = getenv("WORKGROUP");
104
if (w == NULL) w = "";
107
if (u == NULL) u = "";
109
p = getenv("PASSWORD");
110
if (p == NULL) p = "";
112
smbw_strlcpy(wg, w, wglen);
113
smbw_strlcpy(un, u, unlen);
114
smbw_strlcpy(pw, p, pwlen);
117
static smbc_get_auth_data_fn get_auth_data_fn = get_envvar_auth_data;
119
/*****************************************************
120
set the get auth data function
121
******************************************************/
122
void smbw_set_auth_data_fn(smbc_get_auth_data_fn fn)
124
get_auth_data_fn = fn;
128
/*****************************************************
129
ensure that all connections are terminated upon exit
130
******************************************************/
131
static void do_shutdown(void)
133
if (smbw_ctx != NULL) {
134
smbc_free_context(smbw_ctx, 1);
139
/*****************************************************
140
initialise structures
141
*******************************************************/
142
static void do_init(StartupType startupType)
147
smbw_initialized = 1; /* this must be first to avoid recursion! */
149
smbw_ctx = NULL; /* don't free context until it's established */
151
/* initially, no file descriptors are mapped */
152
for (i = 0; i < __FD_SETSIZE; i++) {
154
smbw_ref_count[i] = 0;
157
/* See if we've been told to start in a particular directory */
158
if ((p=getenv("SMBW_DIR")) != NULL) {
159
smbw_strlcpy(smbw_cwd, p, PATH_MAX);
161
/* we don't want the old directory to be busy */
162
(* smbw_libc.chdir)("/");
168
if ((p=getenv("DEBUG"))) {
169
debug_level = atoi(p);
172
if ((smbw_ctx = smbc_new_context()) == NULL) {
173
fprintf(stderr, "Could not create a context.\n");
177
smbc_setDebug(smbw_ctx, debug_level);
178
smbc_setFunctionAuthData(smbw_ctx, get_auth_data_fn);
179
smbc_setOptionBrowseMaxLmbCount(smbw_ctx, 0);
180
smbc_setOptionUrlEncodeReaddirEntries(smbw_ctx, 1);
181
smbc_setOptionOneSharePerServer(smbw_ctx, 1);
183
if (smbc_init_context(smbw_ctx) == NULL) {
184
fprintf(stderr, "Could not initialize context.\n");
188
smbc_set_context(smbw_ctx);
190
/* if not real startup, exit handler has already been established */
191
if (startupType == StartupType_Real) {
196
/*****************************************************
197
initialise structures, real start up vs a fork()
198
*******************************************************/
201
do_init(StartupType_Real);
205
/*****************************************************
206
determine if a file descriptor is a smb one
207
*******************************************************/
208
int smbw_fd(int smbw_fd)
212
return (smbw_fd >= 0 &&
213
smbw_fd < __FD_SETSIZE &&
214
smbw_fd_map[smbw_fd] >= SMBC_BASE_FD); /* minimum smbc_ fd */
218
/*****************************************************
219
determine if a path is a smb one
220
*******************************************************/
221
int smbw_path(const char *name)
231
len = strlen(smbw_prefix);
233
ret = ((strncmp(name, smbw_prefix, len) == 0 &&
234
(name[len] == '\0' || name[len] == '/')) ||
235
(*name != '/' && *smbw_cwd != '\0'));
242
/*****************************************************
243
remove redundent stuff from a filename
244
*******************************************************/
245
void smbw_clean_fname(char *name)
253
DEBUG(10, ("Clean [%s]...\n", name));
258
if ((p=strstr(name,"/./"))) {
264
DEBUG(10, ("\tclean 1 (/./) produced [%s]\n", name));
267
if ((p=strstr(name,"//"))) {
273
DEBUG(10, ("\tclean 2 (//) produced [%s]\n", name));
276
if (strcmp(name,"/../")==0) {
279
DEBUG(10,("\tclean 3 (^/../$) produced [%s]\n", name));
282
if ((p=strstr(name,"/../"))) {
284
for (p2 = (p > name ? p-1 : p); p2 > name; p2--) {
285
if (p2[0] == '/') break;
293
DEBUG(10, ("\tclean 4 (/../) produced [%s]\n", name));
296
if (strcmp(name,"/..")==0) {
299
DEBUG(10, ("\tclean 5 (^/..$) produced [%s]\n", name));
303
p = l>=3?(name+l-3):name;
304
if (strcmp(p,"/..")==0) {
306
for (p2=p-1;p2>name;p2--) {
307
if (p2[0] == '/') break;
315
DEBUG(10, ("\tclean 6 (/..) produced [%s]\n", name));
319
p = l>=2?(name+l-2):name;
320
if (strcmp(p,"/.")==0) {
327
DEBUG(10, ("\tclean 7 (/.) produced [%s]\n", name));
330
if (strncmp(p=name,"./",2) == 0) {
335
DEBUG(10, ("\tclean 8 (^./) produced [%s]\n", name));
339
if (l > 1 && p[l-1] == '/') {
342
DEBUG(10, ("\tclean 9 (/) produced [%s]\n", name));
347
void smbw_fix_path(const char *src, char *dest)
350
int len = strlen(smbw_prefix);
353
for (p = src + len; *p == '/'; p++)
355
snprintf(dest, PATH_MAX, "smb://%s", p);
357
snprintf(dest, PATH_MAX, "%s/%s", smbw_cwd, src);
360
smbw_clean_fname(dest + 5);
362
DEBUG(10, ("smbw_fix_path(%s) returning [%s]\n", src, dest));
367
/*****************************************************
369
*******************************************************/
370
int smbw_open(const char *fname, int flags, mode_t mode)
383
smbw_fd = (smbw_libc.open)(SMBW_DUMMY, O_WRONLY, 0200);
389
smbw_fix_path(fname, path);
390
if (flags == creat_bits) {
391
client_fd = smbc_creat(path, mode);
393
client_fd = smbc_open(path, flags, mode);
397
(* smbw_libc.close)(smbw_fd);
401
smbw_fd_map[smbw_fd] = client_fd;
402
smbw_ref(client_fd, SMBW_RCT_Increment);
407
/*****************************************************
408
a wrapper for pread()
410
there should really be an smbc_pread() to avoid the two
411
lseek()s required in this kludge.
412
*******************************************************/
413
ssize_t smbw_pread(int smbw_fd, void *buf, size_t count, SMBW_OFF_T ofs)
424
client_fd = smbw_fd_map[smbw_fd];
426
if ((old_ofs = smbc_lseek(client_fd, 0, SEEK_CUR)) < 0 ||
427
smbc_lseek(client_fd, ofs, SEEK_SET) < 0) {
431
if ((ret = smbc_read(client_fd, buf, count)) < 0) {
433
(void) smbc_lseek(client_fd, old_ofs, SEEK_SET);
441
/*****************************************************
443
*******************************************************/
444
ssize_t smbw_read(int smbw_fd, void *buf, size_t count)
448
client_fd = smbw_fd_map[smbw_fd];
450
return smbc_read(client_fd, buf, count);
455
/*****************************************************
456
a wrapper for write()
457
*******************************************************/
458
ssize_t smbw_write(int smbw_fd, void *buf, size_t count)
462
client_fd = smbw_fd_map[smbw_fd];
464
return smbc_write(client_fd, buf, count);
467
/*****************************************************
468
a wrapper for pwrite()
469
*******************************************************/
470
ssize_t smbw_pwrite(int smbw_fd, void *buf, size_t count, SMBW_OFF_T ofs)
481
client_fd = smbw_fd_map[smbw_fd];
483
if ((old_ofs = smbc_lseek(client_fd, 0, SEEK_CUR)) < 0 ||
484
smbc_lseek(client_fd, ofs, SEEK_SET) < 0) {
488
if ((ret = smbc_write(client_fd, buf, count)) < 0) {
490
(void) smbc_lseek(client_fd, old_ofs, SEEK_SET);
498
/*****************************************************
499
a wrapper for close()
500
*******************************************************/
501
int smbw_close(int smbw_fd)
505
client_fd = smbw_fd_map[smbw_fd];
507
if (smbw_ref(client_fd, SMBW_RCT_Decrement) > 0) {
511
(* smbw_libc.close)(smbw_fd);
512
smbw_fd_map[smbw_fd] = -1;
513
return smbc_close(client_fd);
517
/*****************************************************
518
a wrapper for fcntl()
519
*******************************************************/
520
int smbw_fcntl(int smbw_fd, int cmd, long arg)
526
/*****************************************************
527
a wrapper for access()
528
*******************************************************/
529
int smbw_access(const char *name, int mode)
535
if (smbw_stat(name, &st)) return -1;
537
if (((mode & R_OK) && !(st.s_mode & S_IRUSR)) ||
538
((mode & W_OK) && !(st.s_mode & S_IWUSR)) ||
539
((mode & X_OK) && !(st.s_mode & S_IXUSR))) {
547
/*****************************************************
548
a wrapper for readlink() - needed for correct errno setting
549
*******************************************************/
550
int smbw_readlink(const char *fname, char *buf, size_t bufsize)
557
ret = smbw_stat(fname, &st);
562
/* it exists - say it isn't a link */
568
/*****************************************************
569
a wrapper for unlink()
570
*******************************************************/
571
int smbw_unlink(const char *fname)
577
smbw_fix_path(fname, path);
578
return smbc_unlink(path);
582
/*****************************************************
583
a wrapper for rename()
584
*******************************************************/
585
int smbw_rename(const char *oldname, const char *newname)
587
char path_old[PATH_MAX];
588
char path_new[PATH_MAX];
592
smbw_fix_path(oldname, path_old);
593
smbw_fix_path(newname, path_new);
594
return smbc_rename(path_old, path_new);
598
/*****************************************************
600
*******************************************************/
601
int smbw_utimes(const char *fname, void *buf)
605
smbw_fix_path(fname, path);
606
return smbc_utimes(path, buf);
610
/*****************************************************
612
*******************************************************/
613
int smbw_utime(const char *fname, void *buf)
617
smbw_fix_path(fname, path);
618
return smbc_utime(path, buf);
621
/*****************************************************
622
a wrapper for chown()
623
*******************************************************/
624
int smbw_chown(const char *fname, uid_t owner, gid_t group)
626
/* always indiciate that this is not supported. */
631
/*****************************************************
632
a wrapper for chmod()
633
*******************************************************/
634
int smbw_chmod(const char *fname, mode_t newmode)
638
smbw_fix_path(fname, path);
639
return smbc_chmod(path, newmode);
643
/*****************************************************
644
a wrapper for lseek()
645
*******************************************************/
646
SMBW_OFF_T smbw_lseek(int smbw_fd,
653
client_fd = smbw_fd_map[smbw_fd];
655
ret = smbc_lseek(client_fd, offset, whence);
658
printf("smbw_lseek(%d/%d, 0x%llx) returned 0x%llx\n",
660
(unsigned long long) offset,
661
(unsigned long long) ret);
666
/*****************************************************
668
*******************************************************/
669
int smbw_dup(int smbw_fd)
673
fd2 = (smbw_libc.dup)(smbw_fd);
678
smbw_fd_map[fd2] = smbw_fd_map[smbw_fd];
679
smbw_ref(smbw_fd_map[smbw_fd], SMBW_RCT_Increment);
684
/*****************************************************
686
*******************************************************/
687
int smbw_dup2(int smbw_fd, int fd2)
689
if ((* smbw_libc.dup2)(smbw_fd, fd2) != fd2) {
693
smbw_fd_map[fd2] = smbw_fd_map[smbw_fd];
694
smbw_ref(smbw_fd_map[smbw_fd], SMBW_RCT_Increment);
699
/*****************************************************
700
when we fork we have to close all connections and files
702
*******************************************************/
712
if (pipe(p)) return (* smbw_libc.fork)();
714
child_pid = (* smbw_libc.fork)();
717
/* block the parent for a moment until the sockets are
719
(* smbw_libc.close)(p[1]);
720
(* smbw_libc.read)(p[0], &c, 1);
721
(* smbw_libc.close)(p[0]);
725
(* smbw_libc.close)(p[0]);
727
/* close all server connections and locally-opened files */
728
for (i = 0; i < __FD_SETSIZE; i++) {
729
if (smbw_fd_map[i] > 0 &&
730
smbw_ref(smbw_fd_map[i], SMBW_RCT_Get) > 0) {
732
smbc_close(smbw_fd_map[i]);
733
smbw_ref(smbw_fd_map[i], SMBW_RCT_Set, 0);
734
(* smbw_libc.close)(i);
740
/* unblock the parent */
742
(* smbw_libc.close)(p[1]);
744
/* specify directory to start in, if it's simulated smb */
745
if (*smbw_cwd != '\0') {
746
setenv("SMBW_DIR", smbw_cwd, 1);
748
unsetenv("SMBW_DIR");
751
/* Re-initialize this library for the child */
752
do_init(StartupType_Fake);
754
/* and continue in the child */
758
int smbw_setxattr(const char *fname,
766
if (strcmp(name, "system.posix_acl_access") == 0)
771
smbw_fix_path(fname, path);
772
return smbc_setxattr(path, name, value, size, flags);
775
int smbw_lsetxattr(const char *fname,
783
if (strcmp(name, "system.posix_acl_access") == 0)
788
smbw_fix_path(fname, path);
789
return smbc_lsetxattr(path, name, value, size, flags);
792
int smbw_fsetxattr(int smbw_fd,
800
if (strcmp(name, "system.posix_acl_access") == 0)
805
client_fd = smbw_fd_map[smbw_fd];
806
return smbc_fsetxattr(client_fd, name, value, size, flags);
809
int smbw_getxattr(const char *fname,
816
if (strcmp(name, "system.posix_acl_access") == 0)
821
smbw_fix_path(fname, path);
823
return smbc_getxattr(path, name, value, size);
826
int smbw_lgetxattr(const char *fname,
833
if (strcmp(name, "system.posix_acl_access") == 0)
838
smbw_fix_path(fname, path);
839
return smbc_lgetxattr(path, name, value, size);
842
int smbw_fgetxattr(int smbw_fd,
849
if (strcmp(name, "system.posix_acl_access") == 0)
854
client_fd = smbw_fd_map[smbw_fd];
855
return smbc_fgetxattr(client_fd, name, value, size);
858
int smbw_removexattr(const char *fname,
863
if (strcmp(name, "system.posix_acl_access") == 0)
868
smbw_fix_path(fname, path);
869
return smbc_removexattr(path, name);
872
int smbw_lremovexattr(const char *fname,
877
if (strcmp(name, "system.posix_acl_access") == 0)
882
smbw_fix_path(fname, path);
883
return smbc_lremovexattr(path, name);
886
int smbw_fremovexattr(int smbw_fd,
891
if (strcmp(name, "system.posix_acl_access") == 0)
896
client_fd = smbw_fd_map[smbw_fd];
897
return smbc_fremovexattr(client_fd, name);
900
int smbw_listxattr(const char *fname,
906
smbw_fix_path(fname, path);
907
return smbc_listxattr(path, list, size);
910
int smbw_llistxattr(const char *fname,
916
smbw_fix_path(fname, path);
917
return smbc_llistxattr(path, list, size);
920
int smbw_flistxattr(int smbw_fd,
926
client_fd = smbw_fd_map[smbw_fd];
927
return smbc_flistxattr(client_fd, list, size);