summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2004-05-10 23:04:31 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 10:51:31 -0500
commit9aeff8d280875ae573e7b6a92df8e2b39a96b502 (patch)
treef5ced17b90c9dc8e3fc50984e9f36c6151d1db83
parent47e712c95063e2861b1936691071c3b36e27a6f3 (diff)
downloadsamba-9aeff8d280875ae573e7b6a92df8e2b39a96b502.tar.gz
samba-9aeff8d280875ae573e7b6a92df8e2b39a96b502.tar.bz2
samba-9aeff8d280875ae573e7b6a92df8e2b39a96b502.zip
r640: Make cifsvfs symlinks work with paths within and external to the
share. Store external paths prefixed with smbln:. Jeremy. (This used to be commit 14a9997b2eb394174ccb36d2a10a755279740cba)
-rw-r--r--source3/include/trans2.h1
-rw-r--r--source3/smbd/trans2.c48
2 files changed, 42 insertions, 7 deletions
diff --git a/source3/include/trans2.h b/source3/include/trans2.h
index 3106cd092a..98a4fc0976 100644
--- a/source3/include/trans2.h
+++ b/source3/include/trans2.h
@@ -450,6 +450,7 @@ Offset Size Name
#define CIFS_UNIX_FCNTL_LOCKS_CAP 0x1
#define CIFS_UNIX_POSIX_ACLS_CAP 0x2
+#define CIFS_CLIENT_SYMLINK_STRING "smbln:"
/* ... more as we think of them :-). */
#endif
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 25954d4433..825bae86bb 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -2762,6 +2762,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
case SMB_QUERY_FILE_UNIX_LINK:
{
pstring buffer;
+ char *bufp = buffer;
DEBUG(10,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_LINK\n"));
#ifdef S_ISLNK
@@ -2774,7 +2775,11 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
if (len == -1)
return(UNIXERROR(ERRDOS,ERRnoaccess));
buffer[len] = 0;
- len = srvstr_push(outbuf, pdata, buffer, -1, STR_TERMINATE);
+ if (strncmp(buffer, CIFS_CLIENT_SYMLINK_STRING, strlen(CIFS_CLIENT_SYMLINK_STRING)) == 0) {
+ bufp += strlen(CIFS_CLIENT_SYMLINK_STRING);
+ }
+
+ len = srvstr_push(outbuf, pdata, bufp, -1, STR_TERMINATE);
pdata += len;
data_size = PTR_DIFF(pdata,(*ppdata));
@@ -2885,7 +2890,7 @@ static int ensure_link_is_safe(connection_struct *conn, const char *link_dest_in
/* Store the UNIX converted path. */
pstrcpy(link_dest_out, link_dest);
- p = strrchr(link_dest, '/');
+ p = strrchr_m(link_dest, '/');
if (p) {
fstrcpy(last_component, p+1);
*p = '\0';
@@ -2897,6 +2902,9 @@ static int ensure_link_is_safe(connection_struct *conn, const char *link_dest_in
if (SMB_VFS_REALPATH(conn,link_dest,resolved_name) == NULL)
return -1;
+ DEBUG(10,("ensure_link_is_safe: realpath: link_dest (%s) -> real name (%s)\n",
+ link_dest, resolved_name ));
+
pstrcpy(link_dest, resolved_name);
pstrcat(link_dest, "/");
pstrcat(link_dest, last_component);
@@ -2910,6 +2918,9 @@ static int ensure_link_is_safe(connection_struct *conn, const char *link_dest_in
pstrcpy(link_test, link_dest);
}
+ DEBUG(10,("ensure_link_is_safe: connectpath = %s, absolute resolved path = %s\n",
+ conn->connectpath, link_test ));
+
/*
* Check if the link is within the share.
*/
@@ -3483,6 +3494,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
{
pstring oldname;
char *newname = fname;
+ BOOL cifs_client_link = False;
/* Set a symbolic link. */
/* Don't allow this if follow links is false. */
@@ -3490,13 +3502,35 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
if (!lp_symlinks(SNUM(conn)))
return(ERROR_DOS(ERRDOS,ERRnoaccess));
- srvstr_get_path(inbuf, oldname, pdata, sizeof(oldname), -1, STR_TERMINATE, &status);
- if (!NT_STATUS_IS_OK(status)) {
- return ERROR_NT(status);
+ srvstr_pull(inbuf, oldname, pdata, sizeof(oldname), -1, STR_TERMINATE);
+ unix_format(oldname);
+
+ if (*oldname == '/') {
+ /* Absolute paths are automatically a client resolved link. */
+ cifs_client_link = True;
+ } else {
+ pstring rel_name;
+ char *last_dirp = NULL;
+
+ pstrcpy(rel_name, newname);
+ last_dirp = strrchr_m(rel_name, '/');
+ if (last_dirp) {
+ last_dirp[1] = '\0';
+ } else {
+ pstrcpy(rel_name, "./");
+ }
+ pstrcat(rel_name, oldname);
+ if (ensure_link_is_safe(conn, rel_name, rel_name) != 0)
+ cifs_client_link = True;
+
}
- if (ensure_link_is_safe(conn, oldname, oldname) != 0)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ if (cifs_client_link) {
+ pstring tmp_name;
+ pstrcpy(tmp_name, CIFS_CLIENT_SYMLINK_STRING);
+ pstrcat(tmp_name, oldname);
+ pstrcpy(oldname, tmp_name);
+ }
DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n",
fname, oldname ));