r14428: Call fill_share_mode_entry with NO_OPLOCK instead of 0.
[samba.git] / source3 / locking / locking.c
index 07377831b4adc7bc627646e296b40af4cda3f0d7..5cb1f71555d6ac398dfcce4804476907e78c43be 100644 (file)
@@ -44,20 +44,6 @@ uint16 global_smbpid;
 /* the locking database handle */
 static TDB_CONTEXT *tdb;
 
-struct locking_data {
-        union {
-               struct {
-                       int num_share_mode_entries;
-                       BOOL delete_on_close;
-               } s;
-                struct share_mode_entry dummy; /* Needed for alignment. */
-        } u;
-        /* the following two entries are implicit
-           struct share_mode_entry modes[num_share_mode_entries];
-           char file_name[];
-        */
-};
-
 /****************************************************************************
  Debugging aid :-).
 ****************************************************************************/
@@ -384,11 +370,13 @@ char *share_mode_str(int num, struct share_mode_entry *e)
 {
        static pstring share_str;
 
-       slprintf(share_str, sizeof(share_str)-1, "share_mode_entry[%d]: "
+       slprintf(share_str, sizeof(share_str)-1, "share_mode_entry[%d]: %s "
                 "pid = %s, share_access = 0x%x, private_options = 0x%x, "
                 "access_mask = 0x%x, mid = 0x%x, type= 0x%x, file_id = %lu, "
                 "dev = 0x%x, inode = %.0f",
-                num, procid_str_static(&e->pid),
+                num,
+                e->op_type == UNUSED_SHARE_MODE_ENTRY ? "UNUSED" : "",
+                procid_str_static(&e->pid),
                 e->share_access, e->private_options,
                 e->access_mask, e->op_mid, e->op_type, e->share_file_id,
                 (unsigned int)e->dev, (double)e->inode );
@@ -408,9 +396,11 @@ static void print_share_mode_table(struct locking_data *data)
        int i;
 
        for (i = 0; i < num_share_modes; i++) {
-               struct share_mode_entry *entry_p = &shares[i];
+               struct share_mode_entry entry;
+
+               memcpy(&entry, &shares[i], sizeof(struct share_mode_entry));
                DEBUG(10,("print_share_mode_table: %s\n",
-                         share_mode_str(i, entry_p)));
+                         share_mode_str(i, &entry)));
        }
 }
 
@@ -424,34 +414,36 @@ static BOOL parse_share_modes(TDB_DATA dbuf, struct share_mode_lock *lck)
        int i;
 
        if (dbuf.dsize < sizeof(struct locking_data)) {
-               DEBUG(0, ("parse_share_modes: buffer too short\n"));
-               return False;
+               smb_panic("PANIC: parse_share_modes: buffer too short.\n");
        }
 
        data = (struct locking_data *)dbuf.dptr;
 
        lck->delete_on_close = data->u.s.delete_on_close;
+       lck->initial_delete_on_close = data->u.s.initial_delete_on_close;
        lck->num_share_modes = data->u.s.num_share_mode_entries;
 
        DEBUG(10, ("parse_share_modes: delete_on_close: %d, "
-                  "num_share_modes: %d\n", lck->delete_on_close,
-                  lck->num_share_modes));
+                  "initial_delete_on_close: %d, "
+                  "num_share_modes: %d\n",
+               lck->delete_on_close,
+               lck->initial_delete_on_close,
+               lck->num_share_modes));
 
        if ((lck->num_share_modes < 0) || (lck->num_share_modes > 1000000)) {
                DEBUG(0, ("invalid number of share modes: %d\n",
                          lck->num_share_modes));
-               return False;
+               smb_panic("PANIC: invalid number of share modes");
        }
 
        lck->share_modes = NULL;
-
+       
        if (lck->num_share_modes != 0) {
 
                if (dbuf.dsize < (sizeof(struct locking_data) +
                                  (lck->num_share_modes *
                                   sizeof(struct share_mode_entry)))) {
-                       DEBUG(0, ("parse_share_modes: buffer too short\n"));
-                       return False;
+                       smb_panic("PANIC: parse_share_modes: buffer too short.\n");
                }
                                  
                lck->share_modes = talloc_memdup(lck, dbuf.dptr+sizeof(*data),
@@ -459,20 +451,68 @@ static BOOL parse_share_modes(TDB_DATA dbuf, struct share_mode_lock *lck)
                                                 sizeof(struct share_mode_entry));
 
                if (lck->share_modes == NULL) {
-                       DEBUG(0, ("talloc failed\n"));
-                       return False;
+                       smb_panic("talloc failed\n");
                }
        }
 
+       /* Get any delete token. */
+       if (data->u.s.delete_token_size) {
+               char *p = dbuf.dptr + sizeof(*data) +
+                               (lck->num_share_modes *
+                               sizeof(struct share_mode_entry));
+
+               if ((data->u.s.delete_token_size < sizeof(uid_t) + sizeof(gid_t)) ||
+                               ((data->u.s.delete_token_size - sizeof(uid_t)) % sizeof(gid_t)) != 0) {
+                       DEBUG(0, ("parse_share_modes: invalid token size %d\n",
+                               data->u.s.delete_token_size));
+                       smb_panic("parse_share_modes: invalid token size\n");
+               }
+
+               lck->delete_token = TALLOC_P(lck, UNIX_USER_TOKEN);
+               if (!lck->delete_token) {
+                       smb_panic("talloc failed\n");
+               }
+
+               /* Copy out the uid and gid. */
+               memcpy(&lck->delete_token->uid, p, sizeof(uid_t));
+               p += sizeof(uid_t);
+               memcpy(&lck->delete_token->gid, p, sizeof(gid_t));
+               p += sizeof(gid_t);
+
+               /* Any supplementary groups ? */
+               lck->delete_token->ngroups = (data->u.s.delete_token_size > (sizeof(uid_t) + sizeof(gid_t))) ?
+                                       ((data->u.s.delete_token_size -
+                                               (sizeof(uid_t) + sizeof(gid_t)))/sizeof(gid_t)) : 0;
+
+               if (lck->delete_token->ngroups) {
+                       /* Make this a talloc child of lck->delete_token. */
+                       lck->delete_token->groups = TALLOC_ARRAY(lck->delete_token, gid_t,
+                                                       lck->delete_token->ngroups);
+                       if (!lck->delete_token) {
+                               smb_panic("talloc failed\n");
+                       }
+
+                       for (i = 0; i < lck->delete_token->ngroups; i++) {
+                               memcpy(&lck->delete_token->groups[i], p, sizeof(gid_t));
+                               p += sizeof(gid_t);
+                       }
+               }
+
+       } else {
+               lck->delete_token = NULL;
+       }
+
        /* Save off the associated service path and filename. */
        lck->servicepath = talloc_strdup(lck, dbuf.dptr + sizeof(*data) +
-                                     (lck->num_share_modes *
-                                     sizeof(struct share_mode_entry)));
+                                       (lck->num_share_modes *
+                                       sizeof(struct share_mode_entry)) +
+                                       data->u.s.delete_token_size );
 
        lck->filename = talloc_strdup(lck, dbuf.dptr + sizeof(*data) +
-                                     (lck->num_share_modes *
-                                     sizeof(struct share_mode_entry)) +
-                                     strlen(lck->servicepath) + 1 );
+                                       (lck->num_share_modes *
+                                       sizeof(struct share_mode_entry)) +
+                                       data->u.s.delete_token_size +
+                                       strlen(lck->servicepath) + 1 );
 
        /*
         * Ensure that each entry has a real process attached.
@@ -501,6 +541,7 @@ static TDB_DATA unparse_share_modes(struct share_mode_lock *lck)
        struct locking_data *data;
        ssize_t offset;
        ssize_t sp_len;
+       uint32 delete_token_size;
 
        result.dptr = NULL;
        result.dsize = 0;
@@ -516,9 +557,12 @@ static TDB_DATA unparse_share_modes(struct share_mode_lock *lck)
        }
 
        sp_len = strlen(lck->servicepath);
+       delete_token_size = (lck->delete_token ?
+                       (sizeof(uid_t) + sizeof(gid_t) + (lck->delete_token->ngroups*sizeof(gid_t))) : 0);
 
        result.dsize = sizeof(*data) +
                lck->num_share_modes * sizeof(struct share_mode_entry) +
+               delete_token_size +
                sp_len + 1 +
                strlen(lck->filename) + 1;
        result.dptr = talloc_size(lck, result.dsize);
@@ -531,19 +575,44 @@ static TDB_DATA unparse_share_modes(struct share_mode_lock *lck)
        ZERO_STRUCTP(data);
        data->u.s.num_share_mode_entries = lck->num_share_modes;
        data->u.s.delete_on_close = lck->delete_on_close;
-       DEBUG(10, ("unparse_share_modes: del: %d, num: %d\n",
-                  data->u.s.delete_on_close,
-                  data->u.s.num_share_mode_entries));
+       data->u.s.initial_delete_on_close = lck->initial_delete_on_close;
+       data->u.s.delete_token_size = delete_token_size;
+       DEBUG(10, ("unparse_share_modes: del: %d, initial del %d, tok = %u, num: %d\n",
+               data->u.s.delete_on_close,
+               data->u.s.initial_delete_on_close,
+               (unsigned int)data->u.s.delete_token_size,
+               data->u.s.num_share_mode_entries));
        memcpy(result.dptr + sizeof(*data), lck->share_modes,
               sizeof(struct share_mode_entry)*lck->num_share_modes);
        offset = sizeof(*data) +
                sizeof(struct share_mode_entry)*lck->num_share_modes;
+
+       /* Store any delete on close token. */
+       if (lck->delete_token) {
+               char *p = result.dptr + offset;
+
+               memcpy(p, &lck->delete_token->uid, sizeof(uid_t));
+               p += sizeof(uid_t);
+
+               memcpy(p, &lck->delete_token->gid, sizeof(gid_t));
+
+               for (i = 0; i < lck->delete_token->ngroups; i++) {
+                       memcpy(p, &lck->delete_token->groups[i], sizeof(gid_t));
+                       p += sizeof(gid_t);
+               }
+               offset = p - result.dptr;
+       }
+
        safe_strcpy(result.dptr + offset, lck->servicepath,
                    result.dsize - offset - 1);
        offset += sp_len + 1;
        safe_strcpy(result.dptr + offset, lck->filename,
                    result.dsize - offset - 1);
-       print_share_mode_table(data);
+
+       if (DEBUGLEVEL >= 10) {
+               print_share_mode_table(data);
+       }
+
        return result;
 }
 
@@ -604,13 +673,15 @@ struct share_mode_lock *get_share_mode_lock(TALLOC_CTX *mem_ctx,
        lck->ino = ino;
        lck->num_share_modes = 0;
        lck->share_modes = NULL;
+       lck->delete_token = NULL;
        lck->delete_on_close = False;
+       lck->initial_delete_on_close = False;
        lck->fresh = False;
        lck->modified = False;
 
        if (tdb_chainlock(tdb, key) != 0) {
                DEBUG(3, ("Could not lock share entry\n"));
-               talloc_free(lck);
+               TALLOC_FREE(lck);
                return NULL;
        }
 
@@ -626,21 +697,20 @@ struct share_mode_lock *get_share_mode_lock(TALLOC_CTX *mem_ctx,
        if (lck->fresh) {
 
                if (fname == NULL || servicepath == NULL) {
-                       DEBUG(0, ("New file, but no filename or servicepath supplied\n"));
-                       talloc_free(lck);
+                       TALLOC_FREE(lck);
                        return NULL;
                }
                lck->filename = talloc_strdup(lck, fname);
                lck->servicepath = talloc_strdup(lck, servicepath);
                if (lck->filename == NULL || lck->servicepath == NULL) {
                        DEBUG(0, ("talloc failed\n"));
-                       talloc_free(lck);
+                       TALLOC_FREE(lck);
                        return NULL;
                }
        } else {
                if (!parse_share_modes(data, lck)) {
                        DEBUG(0, ("Could not parse share modes\n"));
-                       talloc_free(lck);
+                       TALLOC_FREE(lck);
                        SAFE_FREE(data.dptr);
                        return NULL;
                }
@@ -662,10 +732,10 @@ BOOL rename_share_filename(struct share_mode_lock *lck,
                        const char *servicepath,
                        const char *newname)
 {
-       struct file_renamed_message *frm = NULL;
        size_t sp_len;
        size_t fn_len;
        size_t msg_len;
+       char *frm = NULL;
        int i;
 
        if (!lck) {
@@ -694,20 +764,21 @@ BOOL rename_share_filename(struct share_mode_lock *lck,
        sp_len = strlen(lck->servicepath);
        fn_len = strlen(lck->filename);
 
-       msg_len = sizeof(*frm) + sp_len + 1 + fn_len + 1;
+       msg_len = MSG_FILE_RENAMED_MIN_SIZE + sp_len + 1 + fn_len + 1;
 
        /* Set up the name changed message. */
        frm = TALLOC(lck, msg_len);
        if (!frm) {
                return False;
        }
-       frm->dev = lck->dev;
-       frm->inode = lck->ino;
+
+       SDEV_T_VAL(frm,0,lck->dev);
+       SINO_T_VAL(frm,8,lck->ino);
 
        DEBUG(10,("rename_share_filename: msg_len = %d\n", msg_len ));
 
-       safe_strcpy(&frm->names[0], lck->servicepath, sp_len);
-       safe_strcpy(&frm->names[sp_len + 1], lck->filename, fn_len);
+       safe_strcpy(&frm[16], lck->servicepath, sp_len);
+       safe_strcpy(&frm[16 + sp_len + 1], lck->filename, fn_len);
 
        /* Send the messages. */
        for (i=0; i<lck->num_share_modes; i++) {
@@ -723,11 +794,13 @@ BOOL rename_share_filename(struct share_mode_lock *lck,
                DEBUG(10,("rename_share_filename: sending rename message to pid %u "
                        "dev %x, inode  %.0f sharepath %s newname %s\n",
                        (unsigned int)procid_to_pid(&se->pid),
-                       (unsigned int)frm->dev, (double)frm->inode,
+                       (unsigned int)lck->dev, (double)lck->ino,
                        lck->servicepath, lck->filename ));
 
+               become_root();
                message_send_pid(se->pid, MSG_SMB_FILE_RENAME,
                                frm, msg_len, True);
+               unbecome_root();
        }
 
        return True;
@@ -741,7 +814,7 @@ BOOL get_delete_on_close_flag(SMB_DEV_T dev, SMB_INO_T inode)
                return False;
        }
        result = lck->delete_on_close;
-       talloc_free(lck);
+       TALLOC_FREE(lck);
        return result;
 }
 
@@ -909,7 +982,7 @@ BOOL del_share_mode(struct share_mode_lock *lck, files_struct *fsp)
 {
        struct share_mode_entry entry, *e;
 
-       fill_share_mode_entry(&entry, fsp, 0, 0);
+       fill_share_mode_entry(&entry, fsp, 0, NO_OPLOCK);
 
        e = find_share_mode_entry(lck, &entry);
        if (e == NULL) {
@@ -945,7 +1018,7 @@ BOOL remove_share_oplock(struct share_mode_lock *lck, files_struct *fsp)
 {
        struct share_mode_entry entry, *e;
 
-       fill_share_mode_entry(&entry, fsp, 0, 0);
+       fill_share_mode_entry(&entry, fsp, 0, NO_OPLOCK);
 
        e = find_share_mode_entry(lck, &entry);
        if (e == NULL) {
@@ -966,7 +1039,7 @@ BOOL downgrade_share_oplock(struct share_mode_lock *lck, files_struct *fsp)
 {
        struct share_mode_entry entry, *e;
 
-       fill_share_mode_entry(&entry, fsp, 0, 0);
+       fill_share_mode_entry(&entry, fsp, 0, NO_OPLOCK);
 
        e = find_share_mode_entry(lck, &entry);
        if (e == NULL) {
@@ -978,28 +1051,6 @@ BOOL downgrade_share_oplock(struct share_mode_lock *lck, files_struct *fsp)
        return True;
 }
 
-
-/*******************************************************************
- We've just told all the smbd's that our level2 or fake level2 has been
- written to.
-********************************************************************/
-BOOL remove_all_share_oplocks(struct share_mode_lock *lck, files_struct *fsp)
-{
-       int i;
-       for (i=0; i<lck->num_share_modes; i++) {
-               struct share_mode_entry *e = &lck->share_modes[i];
-               if (!is_valid_share_mode_entry(e)) {
-                       continue;
-               }
-               if (e->op_type == NO_OPLOCK) {
-                       continue;
-               }
-               e->op_type = NO_OPLOCK;
-               lck->modified = True;
-       }
-       return True;
-}
-
 /****************************************************************************
  Deal with the internal needs of setting the delete on close flag. Note that
  as the tdb locking is recursive, it is safe to call this from within 
@@ -1051,6 +1102,55 @@ NTSTATUS can_set_delete_on_close(files_struct *fsp, BOOL delete_on_close,
        return NT_STATUS_OK;
 }
 
+/*************************************************************************
+ Return a talloced copy of a UNIX_USER_TOKEN. NULL on fail.
+ (Should this be in locking.c.... ?).
+*************************************************************************/
+
+static UNIX_USER_TOKEN *copy_unix_token(TALLOC_CTX *ctx, UNIX_USER_TOKEN *tok)
+{
+       UNIX_USER_TOKEN *cpy;
+
+       if (tok == NULL) {
+               return NULL;
+       }
+
+       cpy = TALLOC_P(ctx, UNIX_USER_TOKEN);
+       if (!cpy) {
+               return NULL;
+       }
+
+       cpy->uid = tok->uid;
+       cpy->gid = tok->gid;
+       cpy->ngroups = tok->ngroups;
+       if (tok->ngroups) {
+               /* Make this a talloc child of cpy. */
+               cpy->groups = TALLOC_ARRAY(cpy, gid_t, tok->ngroups);
+               if (!cpy->groups) {
+                       return NULL;
+               }
+               memcpy(cpy->groups, tok->groups, tok->ngroups * sizeof(gid_t));
+       }
+       return cpy;
+}
+
+/****************************************************************************
+ Replace the delete on close token.
+****************************************************************************/
+
+void set_delete_on_close_token(struct share_mode_lock *lck, UNIX_USER_TOKEN *tok)
+{
+       /* Ensure there's no token. */
+       if (lck->delete_token) {
+               TALLOC_FREE(lck->delete_token); /* Also deletes groups... */
+               lck->delete_token = NULL;
+       }
+
+       /* Copy the new token (can be NULL). */
+       lck->delete_token = copy_unix_token(lck, tok);
+       lck->modified = True;
+}
+
 /****************************************************************************
  Sets the delete on close flag over all share modes on this file.
  Modify the share mode entry for all files open
@@ -1058,9 +1158,12 @@ NTSTATUS can_set_delete_on_close(files_struct *fsp, BOOL delete_on_close,
  changed the delete on close flag. This will be noticed
  in the close code, the last closer will delete the file
  if flag is set.
+ Note that setting this to any value clears the initial_delete_on_close flag.
+ If delete_on_close is True this makes a copy of any UNIX_USER_TOKEN into the
+ lck entry.
 ****************************************************************************/
 
-BOOL set_delete_on_close(files_struct *fsp, BOOL delete_on_close)
+BOOL set_delete_on_close(files_struct *fsp, BOOL delete_on_close, UNIX_USER_TOKEN *tok)
 {
        struct share_mode_lock *lck;
        
@@ -1077,12 +1180,22 @@ BOOL set_delete_on_close(files_struct *fsp, BOOL delete_on_close)
        if (lck == NULL) {
                return False;
        }
+
        if (lck->delete_on_close != delete_on_close) {
+               set_delete_on_close_token(lck, tok);
                lck->delete_on_close = delete_on_close;
+               if (delete_on_close) {
+                       SMB_ASSERT(lck->delete_token != NULL);
+               }
                lck->modified = True;
        }
 
-       talloc_free(lck);
+       if (lck->initial_delete_on_close) {
+               lck->initial_delete_on_close = False;
+               lck->modified = True;
+       }
+
+       TALLOC_FREE(lck);
        return True;
 }
 
@@ -1103,9 +1216,11 @@ static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf,
        data = (struct locking_data *)dbuf.dptr;
        shares = (struct share_mode_entry *)(dbuf.dptr + sizeof(*data));
        sharepath = dbuf.dptr + sizeof(*data) +
-               data->u.s.num_share_mode_entries*sizeof(*shares);
+               data->u.s.num_share_mode_entries*sizeof(*shares) +
+               data->u.s.delete_token_size;
        fname = dbuf.dptr + sizeof(*data) +
                data->u.s.num_share_mode_entries*sizeof(*shares) +
+               data->u.s.delete_token_size +
                strlen(sharepath) + 1;
 
        for (i=0;i<data->u.s.num_share_mode_entries;i++) {