s3:vfs_tsmsm: fix potential segfault (freeing uninitialized buffer)
[metze/samba/wip.git] / source3 / modules / vfs_tsmsm.c
index aa0f945df1cb6ab6de2a554a9cb956d1f29c66da..6fb1d1d2d46715a471e58b77511be9cd61eeef8f 100644 (file)
@@ -72,6 +72,7 @@ struct tsmsm_struct {
        float online_ratio;
        char *hsmscript;
        const char *attrib_name;
+       const char *attrib_value;
 };
 
 static void tsmsm_free_data(void **pptr) {
@@ -111,7 +112,11 @@ static int tsmsm_connect(struct vfs_handle_struct *handle,
        tsmd->attrib_name = lp_parm_talloc_string(SNUM(handle->conn), tsmname, 
                                                  "dmapi attribute", DM_ATTRIB_OBJECT);
        talloc_steal(tsmd, tsmd->attrib_name);
-
+       
+       tsmd->attrib_value = lp_parm_talloc_string(SNUM(handle->conn), "tsmsm", 
+                                                  "dmapi value", NULL);
+       talloc_steal(tsmd, tsmd->attrib_value);
+       
        /* retrieve 'online ratio'. In case of error default to FILE_IS_ONLINE_RATIO */
        fres = lp_parm_const_string(SNUM(handle->conn), tsmname, 
                                    "online ratio", NULL);
@@ -143,7 +148,8 @@ static bool tsmsm_is_offline(struct vfs_handle_struct *handle,
        dm_attrname_t dmname;
        int ret, lerrno;
        bool offline;
-       char buf[1];
+       char *buf = NULL;
+       size_t buflen;
 
         /* if the file has more than FILE_IS_ONLINE_RATIO of blocks available,
           then assume it is not offline (it may not be 100%, as it could be sparse) */
@@ -181,11 +187,24 @@ static bool tsmsm_is_offline(struct vfs_handle_struct *handle,
        memset(&dmname, 0, sizeof(dmname));
        strlcpy((char *)&dmname.an_chars[0], tsmd->attrib_name, sizeof(dmname.an_chars));
 
-       lerrno = 0;
+       if (tsmd->attrib_value != NULL) {
+               buflen = strlen(tsmd->attrib_value);
+       } else {
+               buflen = 1;
+       }
+       buf = talloc_zero_size(tsmd, buflen);
+       if (buf == NULL) {
+               DEBUG(0,("out of memory in tsmsm_is_offline -- assuming online (%s)\n", path));
+               errno = ENOMEM;
+               offline = false;
+               goto done;
+       }
 
        do {
+               lerrno = 0;
+
                ret = dm_get_dmattr(*dmsession_id, dmhandle, dmhandle_len, 
-                                   DM_NO_TOKEN, &dmname, sizeof(buf), buf, &rlen);
+                                   DM_NO_TOKEN, &dmname, buflen, buf, &rlen);
                if (ret == -1 && errno == EINVAL) {
                        DEBUG(0, ("Stale DMAPI session, re-creating it.\n"));
                        lerrno = EINVAL;
@@ -202,8 +221,14 @@ static bool tsmsm_is_offline(struct vfs_handle_struct *handle,
                }
        } while (ret == -1 && lerrno == EINVAL);
 
-       /* its offline if the specified DMAPI attribute exists */
-       offline = (ret == 0 || (ret == -1 && errno == E2BIG));
+       /* check if we need a specific attribute value */
+       if (tsmd->attrib_value != NULL) {
+               offline = (ret == 0 && rlen == buflen && 
+                           memcmp(buf, tsmd->attrib_value, buflen) == 0);
+       } else {
+               /* its offline if the specified DMAPI attribute exists */
+               offline = (ret == 0 || (ret == -1 && errno == E2BIG));
+       }
 
        DEBUG(10,("dm_get_dmattr %s ret=%d (%s)\n", path, ret, strerror(errno)));
 
@@ -212,6 +237,7 @@ static bool tsmsm_is_offline(struct vfs_handle_struct *handle,
        dm_handle_free(dmhandle, dmhandle_len); 
 
 done:
+       talloc_free(buf);
        unbecome_root();
        return offline;
 }
@@ -253,10 +279,13 @@ static ssize_t tsmsm_aio_return(struct vfs_handle_struct *handle, struct files_s
 static ssize_t tsmsm_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fsp, const DATA_BLOB *hdr,
                              SMB_OFF_T offset, size_t n)
 {
-       bool file_online = tsmsm_aio_force(handle, fsp);
+       bool file_offline = tsmsm_aio_force(handle, fsp);
 
-       if(!file_online) 
-           return ENOSYS;
+       if (file_offline) {
+               DEBUG(10,("tsmsm_sendfile on offline file - rejecting\n"));
+               errno = ENOSYS;
+               return -1;
+       }
            
        return SMB_VFS_NEXT_SENDFILE(handle, tofd, fsp, hdr, offset, n);
 }
@@ -307,7 +336,7 @@ static int tsmsm_set_offline(struct vfs_handle_struct *handle,
 
        if (tsmd->hsmscript == NULL) {
                /* no script enabled */
-               DEBUG(1, ("tsmsm_set_offline: No tsmsm:hsmscript configured\n"));
+               DEBUG(1, ("tsmsm_set_offline: No 'tsmsm:hsm script' configured\n"));
                return 0;
        }