s3: leases: libsmbsharemodes no longer works with SMB2 leases inside our locking...
[samba.git] / source3 / libsmb / smb_share_modes.c
1 /*
2    Samba share mode database library external interface library.
3    Used by non-Samba products needing access to the Samba share mode db.
4
5    NOTICE FOR SAMBA 4.2.0
6
7    THIS CODE IS NON-FUNCTIONAL IN SAMBA 4.2.0 AND ABOVE DUE TO THE CHANGES IN
8    SHARE MODE DATABASE SCHEMA FOR SMB2 LEASES.
9
10    CONTACT THE AUTHOR jra@samba.org IF YOU WISH TO RE-ENABLE
11    THIS CODE.
12
13    Copyright (C) Jeremy Allison 2005 - 2006
14
15    sharemodes_procid functions (C) Copyright (C) Volker Lendecke 2005
16
17      ** NOTE! The following LGPL license applies to this module only.
18      ** This does NOT imply that all of Samba is released
19      ** under the LGPL
20
21    This library is free software; you can redistribute it and/or
22    modify it under the terms of the GNU Lesser General Public
23    License as published by the Free Software Foundation; either
24    version 3 of the License, or (at your option) any later version.
25
26    This library is distributed in the hope that it will be useful,
27    but WITHOUT ANY WARRANTY; without even the implied warranty of
28    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
29    Lesser General Public License for more details.
30
31    You should have received a copy of the GNU Lesser General Public
32    License along with this library; if not, see <http://www.gnu.org/licenses/>.
33 */
34
35 #include "includes.h"
36 #include "system/filesys.h"
37 #include "smb_share_modes.h"
38 #include "tdb_compat.h"
39 #include "librpc/gen_ndr/open_files.h"
40 #include <ccan/hash/hash.h>
41
42 /* Database context handle. */
43 struct smbdb_ctx {
44         TDB_CONTEXT *smb_tdb;
45 };
46
47 /* Remove the paranoid malloc checker. */
48 #ifdef malloc
49 #undef malloc
50 #endif
51
52 /*
53  * Internal structure of locking.tdb share mode db.
54  * Used by locking.c and libsmbsharemodes.c
55  */
56
57 struct locking_data {
58         union {
59                 struct {
60                         int num_share_mode_entries;
61                         struct timespec old_write_time;
62                         struct timespec changed_write_time;
63                         uint32 num_delete_token_entries;
64                 } s;
65                 struct share_mode_entry dummy; /* Needed for alignment. */
66         } u;
67         /* The following four entries are implicit
68
69            (1) struct share_mode_entry modes[num_share_mode_entries];
70
71            (2) A num_delete_token_entries of structs {
72                 uint32_t len_delete_token;
73                 char unix_token[len_delete_token] (divisible by 4).
74            };
75
76            (3) char share_name[];
77            (4) char file_name[];
78         */
79 };
80
81 int smb_create_share_mode_entry_ex(struct smbdb_ctx *db_ctx, uint64_t dev,
82                                 uint64_t ino, uint64_t extid,
83                                 const struct smb_share_mode_entry *new_entry,
84                                 const char *sharepath, const char *filename);
85
86 static bool sharemodes_procid_equal(const struct server_id *p1, const struct server_id *p2)
87 {
88         return (p1->pid == p2->pid);
89 }
90
91 static pid_t sharemodes_procid_to_pid(const struct server_id *proc)
92 {
93         return proc->pid;
94 }
95
96 /*
97  * open/close sharemode database.
98  */
99
100 struct smbdb_ctx *smb_share_mode_db_open(const char *db_path)
101 {
102         struct smbdb_ctx *smb_db = (struct smbdb_ctx *)malloc(sizeof(struct smbdb_ctx));
103
104         if (!smb_db) {
105                 return NULL;
106         }
107
108         memset(smb_db, '\0', sizeof(struct smbdb_ctx));
109
110         /* FIXME: We should *never* open a tdb without logging! */
111         smb_db->smb_tdb = tdb_open_compat(db_path,
112                                           0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
113                                           O_RDWR|O_CREAT,
114                                           0644,
115                                           NULL, NULL);
116
117         if (!smb_db->smb_tdb) {
118                 free(smb_db);
119                 return NULL;
120         }
121
122         /* Should check that this is the correct version.... */
123         return smb_db;
124 }
125
126 /* key and data records in the tdb locking database */
127 struct locking_key {
128         SMB_DEV_T dev;
129         SMB_INO_T inode;
130         uint64_t extid;
131 };
132
133 int smb_share_mode_db_close(struct smbdb_ctx *db_ctx)
134 {
135         int ret = tdb_close(db_ctx->smb_tdb);
136         free(db_ctx);
137         return ret;
138 }
139
140 static TDB_DATA get_locking_key(struct locking_key *lk, uint64_t dev,
141                                 uint64_t ino, uint64_t extid)
142 {
143         TDB_DATA ld;
144
145         memset(lk, '\0', sizeof(*lk));
146         lk->dev = (SMB_DEV_T)dev;
147         lk->inode = (SMB_INO_T)ino;
148         lk->extid = extid;
149         ld.dptr = (uint8 *)lk;
150         ld.dsize = sizeof(*lk);
151         return ld;
152 }
153
154 /*
155  * lock/unlock entry in sharemode database.
156  */
157
158 int smb_lock_share_mode_entry(struct smbdb_ctx *db_ctx,
159                                 uint64_t dev,
160                                 uint64_t ino,
161                                 uint64_t extid)
162 {
163         struct locking_key lk;
164         return tdb_chainlock(db_ctx->smb_tdb, get_locking_key(&lk, dev, ino,
165                                                               extid)) == 0 ? 0 : -1;
166 }
167
168 int smb_unlock_share_mode_entry(struct smbdb_ctx *db_ctx,
169                                 uint64_t dev,
170                                 uint64_t ino,
171                                 uint64_t extid)
172 {
173         struct locking_key lk;
174         tdb_chainunlock(db_ctx->smb_tdb,
175                         get_locking_key(&lk, dev, ino, extid));
176         return 0;
177 }
178
179 /*
180  * Check if an external smb_share_mode_entry and an internal share_mode entry match.
181  */
182
183 static int share_mode_entry_equal(const struct smb_share_mode_entry *e_entry,
184                                 const struct share_mode_entry *entry)
185 {
186         return (sharemodes_procid_equal(&e_entry->pid, &entry->pid) &&
187                 e_entry->file_id == (uint32_t)entry->share_file_id &&
188                 e_entry->open_time.tv_sec == entry->time.tv_sec &&
189                 e_entry->open_time.tv_usec == entry->time.tv_usec &&
190                 e_entry->share_access == (uint32_t)entry->share_access &&
191                 e_entry->access_mask == (uint32_t)entry->access_mask &&
192                 e_entry->dev == entry->id.devid && 
193                 e_entry->ino == entry->id.inode &&
194                 e_entry->extid == entry->id.extid);
195 }
196
197 /*
198  * Create an internal Samba share_mode entry from an external smb_share_mode_entry.
199  */
200
201 static void create_share_mode_entry(struct share_mode_entry *out,
202                                 const struct smb_share_mode_entry *in,
203                                 uint32_t name_hash)
204 {
205         memset(out, '\0', sizeof(struct share_mode_entry));
206
207         out->pid = in->pid;
208         out->share_file_id = (unsigned long)in->file_id;
209         out->time.tv_sec = in->open_time.tv_sec;
210         out->time.tv_usec = in->open_time.tv_usec;
211         out->share_access = in->share_access;
212         out->access_mask = in->access_mask;
213         out->id.devid = in->dev;
214         out->id.inode = in->ino;
215         out->id.extid = in->extid;
216         out->uid = (uint32)geteuid();
217         out->flags = 0;
218         out->name_hash = name_hash;
219 }
220
221 /*
222  * Return the current share mode list for an open file.
223  * This uses similar (but simplified) logic to locking/locking.c
224  */
225
226 int smb_get_share_mode_entries(struct smbdb_ctx *db_ctx,
227                                 uint64_t dev,
228                                 uint64_t ino,
229                                 uint64_t extid,
230                                 struct smb_share_mode_entry **pp_list,
231                                 unsigned char *p_delete_on_close)
232 {
233         struct locking_key lk;
234         TDB_DATA db_data;
235         struct smb_share_mode_entry *list = NULL;
236         int num_share_modes = 0;
237         struct locking_data *ld = NULL; /* internal samba db state. */
238         struct share_mode_entry *shares = NULL;
239         size_t i;
240         int list_num;
241
242         *pp_list = NULL;
243         *p_delete_on_close = 0;
244
245         db_data = tdb_fetch_compat(db_ctx->smb_tdb,
246                                    get_locking_key(&lk, dev, ino, extid));
247         if (!db_data.dptr) {
248                 return 0;
249         }
250
251         ld = (struct locking_data *)db_data.dptr;
252         num_share_modes = ld->u.s.num_share_mode_entries;
253
254         if (!num_share_modes) {
255                 free(db_data.dptr);
256                 return 0;
257         }
258
259         list = (struct smb_share_mode_entry *)malloc(sizeof(struct smb_share_mode_entry)*num_share_modes);
260         if (!list) {
261                 free(db_data.dptr);
262                 return -1;
263         }
264
265         memset(list, '\0', num_share_modes * sizeof(struct smb_share_mode_entry));
266
267         shares = (struct share_mode_entry *)(db_data.dptr + sizeof(struct locking_data));
268
269         list_num = 0;
270         for (i = 0; i < num_share_modes; i++) {
271                 struct share_mode_entry *share = &shares[i];
272                 struct smb_share_mode_entry *sme = &list[list_num];
273                 struct server_id pid = share->pid;
274
275                 /* Check this process really exists. */
276                 if (kill(sharemodes_procid_to_pid(&pid), 0) == -1 && (errno == ESRCH)) {
277                         continue; /* No longer exists. */
278                 }
279
280                 /* Copy into the external list. */
281                 sme->dev = share->id.devid;
282                 sme->ino = share->id.inode;
283                 sme->extid = share->id.extid;
284                 sme->share_access = (uint32_t)share->share_access;
285                 sme->access_mask = (uint32_t)share->access_mask;
286                 sme->open_time.tv_sec = share->time.tv_sec;
287                 sme->open_time.tv_usec = share->time.tv_usec;
288                 sme->file_id = (uint32_t)share->share_file_id;
289                 sme->pid = share->pid;
290                 list_num++;
291         }
292
293         if (list_num == 0) {
294                 free(db_data.dptr);
295                 free(list);
296                 return 0;
297         }
298
299         *p_delete_on_close = ld->u.s.num_delete_token_entries != 0;
300         *pp_list = list;
301         free(db_data.dptr);
302         return list_num;
303 }
304
305 static uint32_t smb_name_hash(const char *sharepath, const char *filename, int *err)
306 {
307         char *fullpath = NULL;
308         size_t sharepath_size = strlen(sharepath);
309         size_t filename_size = strlen(filename);
310         uint32_t name_hash;
311
312         *err = 0;
313         fullpath = (char *)malloc(sharepath_size + filename_size + 2);
314         if (fullpath == NULL) {
315                 *err = 1;
316                 return 0;
317         }
318         memcpy(fullpath, sharepath, sharepath_size);
319         fullpath[sharepath_size] = '/';
320         memcpy(&fullpath[sharepath_size + 1], filename, filename_size + 1);
321
322         name_hash = hash(fullpath, strlen(fullpath) + 1, 0);
323         free(fullpath);
324         return name_hash;
325 }
326
327 /* 
328  * Create an entry in the Samba share mode db.
329  */
330
331 int smb_create_share_mode_entry_ex(struct smbdb_ctx *db_ctx,
332                                 uint64_t dev,
333                                 uint64_t ino,
334                                 uint64_t extid,
335                                 const struct smb_share_mode_entry *new_entry,
336                                 const char *sharepath, /* Must be absolute utf8 path. */
337                                 const char *filename) /* Must be relative utf8 path. */
338 {
339         TDB_DATA db_data;
340         struct locking_key lk;
341         TDB_DATA locking_key =  get_locking_key(&lk, dev, ino, extid);
342         int orig_num_share_modes = 0;
343         struct locking_data *ld = NULL; /* internal samba db state. */
344         struct share_mode_entry *shares = NULL;
345         uint8 *new_data_p = NULL;
346         size_t new_data_size = 0;
347         int err = 0;
348         uint32_t name_hash = smb_name_hash(sharepath, filename, &err);
349
350         if (err) {
351                 return -1;
352         }
353
354         db_data = tdb_fetch_compat(db_ctx->smb_tdb, locking_key);
355         if (!db_data.dptr) {
356                 /* We must create the entry. */
357                 db_data.dptr = (uint8 *)malloc(
358                         sizeof(struct locking_data) +
359                         sizeof(struct share_mode_entry) +
360                         strlen(sharepath) + 1 +
361                         strlen(filename) + 1);
362                 if (!db_data.dptr) {
363                         return -1;
364                 }
365                 ld = (struct locking_data *)db_data.dptr;
366                 memset(ld, '\0', sizeof(struct locking_data));
367                 ld->u.s.num_share_mode_entries = 1;
368                 ld->u.s.num_delete_token_entries = 0;
369                 shares = (struct share_mode_entry *)(db_data.dptr + sizeof(struct locking_data));
370                 create_share_mode_entry(shares, new_entry, name_hash);
371
372                 memcpy(db_data.dptr + sizeof(struct locking_data) + sizeof(struct share_mode_entry),
373                         sharepath,
374                         strlen(sharepath) + 1);
375                 memcpy(db_data.dptr + sizeof(struct locking_data) + sizeof(struct share_mode_entry) +
376                         strlen(sharepath) + 1,
377                         filename,
378                         strlen(filename) + 1);
379
380                 db_data.dsize = sizeof(struct locking_data) + sizeof(struct share_mode_entry) +
381                                         strlen(sharepath) + 1 +
382                                         strlen(filename) + 1;
383                 if (tdb_store(db_ctx->smb_tdb, locking_key, db_data, TDB_INSERT) != 0) {
384                         free(db_data.dptr);
385                         return -1;
386                 }
387                 free(db_data.dptr);
388                 return 0;
389         }
390
391         /* Entry exists, we must add a new entry. */
392         new_data_p = (uint8 *)malloc(
393                 db_data.dsize + sizeof(struct share_mode_entry));
394         if (!new_data_p) {
395                 free(db_data.dptr);
396                 return -1;
397         }
398
399         ld = (struct locking_data *)db_data.dptr;
400         orig_num_share_modes = ld->u.s.num_share_mode_entries;
401
402         /* Copy the original data. */
403         memcpy(new_data_p, db_data.dptr, sizeof(struct locking_data) + (orig_num_share_modes * sizeof(struct share_mode_entry)));
404
405         /* Add in the new share mode */
406         shares = (struct share_mode_entry *)(new_data_p + sizeof(struct locking_data) +
407                         (orig_num_share_modes * sizeof(struct share_mode_entry)));
408
409         create_share_mode_entry(shares, new_entry, name_hash);
410
411         ld = (struct locking_data *)new_data_p;
412         ld->u.s.num_share_mode_entries++;
413
414         /* Append the original delete_tokens and filenames. */
415         memcpy(new_data_p + sizeof(struct locking_data) + (ld->u.s.num_share_mode_entries * sizeof(struct share_mode_entry)),
416                 db_data.dptr + sizeof(struct locking_data) + (orig_num_share_modes * sizeof(struct share_mode_entry)),
417                 db_data.dsize - sizeof(struct locking_data) - (orig_num_share_modes * sizeof(struct share_mode_entry)));
418
419         new_data_size = db_data.dsize + sizeof(struct share_mode_entry);
420
421         free(db_data.dptr);
422
423         db_data.dptr = new_data_p;
424         db_data.dsize = new_data_size;
425
426         if (tdb_store(db_ctx->smb_tdb, locking_key, db_data, TDB_REPLACE) != 0) {
427                 free(db_data.dptr);
428                 return -1;
429         }
430         free(db_data.dptr);
431         return 0;
432 }
433
434 /* 
435  * Create an entry in the Samba share mode db. Original interface - doesn't
436  * Distinguish between share path and filename. Fudge this by using a
437  * sharepath of / and a relative filename of (filename+1).
438  */
439
440 int smb_create_share_mode_entry(struct smbdb_ctx *db_ctx,
441                                 uint64_t dev,
442                                 uint64_t ino,
443                                 uint64_t extid,
444                                 const struct smb_share_mode_entry *new_entry,
445                                 const char *filename) /* Must be absolute utf8 path. */
446 {
447         if (*filename != '/') {
448                 abort();
449         }
450         return smb_create_share_mode_entry_ex(db_ctx, dev, ino, extid, new_entry,
451                                                 "/", &filename[1]);
452 }
453
454 int smb_delete_share_mode_entry(struct smbdb_ctx *db_ctx,
455                                 uint64_t dev,
456                                 uint64_t ino,
457                                 uint64_t extid,
458                                 const struct smb_share_mode_entry *del_entry)
459 {
460         TDB_DATA db_data;
461         struct locking_key lk;
462         TDB_DATA locking_key =  get_locking_key(&lk, dev, ino, extid);
463         int orig_num_share_modes = 0;
464         struct locking_data *ld = NULL; /* internal samba db state. */
465         struct share_mode_entry *shares = NULL;
466         uint8 *new_data_p = NULL;
467         size_t remaining_size = 0;
468         size_t i, num_share_modes;
469         const uint8 *remaining_ptr = NULL;
470
471         db_data = tdb_fetch_compat(db_ctx->smb_tdb, locking_key);
472         if (!db_data.dptr) {
473                 return -1; /* Error - missing entry ! */
474         }
475
476         ld = (struct locking_data *)db_data.dptr;
477         orig_num_share_modes = ld->u.s.num_share_mode_entries;
478         shares = (struct share_mode_entry *)(db_data.dptr + sizeof(struct locking_data));
479
480         if (orig_num_share_modes == 1) {
481                 /* Only one entry - better be ours... */
482                 if (!share_mode_entry_equal(del_entry, shares)) {
483                         /* Error ! We can't delete someone else's entry ! */
484                         free(db_data.dptr);
485                         return -1;
486                 }
487                 /* It's ours - just remove the entire record. */
488                 free(db_data.dptr);
489                 return tdb_delete(db_ctx->smb_tdb, locking_key) ? -1 : 0;
490         }
491
492         /* More than one - allocate a new record minus the one we'll delete. */
493         new_data_p = (uint8 *)malloc(
494                 db_data.dsize - sizeof(struct share_mode_entry));
495         if (!new_data_p) {
496                 free(db_data.dptr);
497                 return -1;
498         }
499
500         /* Copy the header. */
501         memcpy(new_data_p, db_data.dptr, sizeof(struct locking_data));
502
503         num_share_modes = 0;
504         for (i = 0; i < orig_num_share_modes; i++) {
505                 struct share_mode_entry *share = &shares[i];
506                 struct server_id pid = share->pid;
507
508                 /* Check this process really exists. */
509                 if (kill(sharemodes_procid_to_pid(&pid), 0) == -1 && (errno == ESRCH)) {
510                         continue; /* No longer exists. */
511                 }
512
513                 if (share_mode_entry_equal(del_entry, share)) {
514                         continue; /* This is our delete taget. */
515                 }
516
517                 memcpy(new_data_p + sizeof(struct locking_data) +
518                                 (num_share_modes * sizeof(struct share_mode_entry)),
519                         share, sizeof(struct share_mode_entry) );
520
521                 num_share_modes++;
522         }
523
524         if (num_share_modes == 0) {
525                 /* None left after pruning. Delete record. */
526                 free(db_data.dptr);
527                 free(new_data_p);
528                 return tdb_delete(db_ctx->smb_tdb, locking_key) ? -1 : 0;
529         }
530
531         /* Copy any delete tokens plus the terminating filenames. */
532         remaining_ptr = db_data.dptr + sizeof(struct locking_data) + (orig_num_share_modes * sizeof(struct share_mode_entry));
533         remaining_size = db_data.dsize - (remaining_ptr - db_data.dptr);
534
535         memcpy(new_data_p + sizeof(struct locking_data) + (num_share_modes * sizeof(struct share_mode_entry)),
536                 remaining_ptr,
537                 remaining_size);
538
539         free(db_data.dptr);
540
541         db_data.dptr = new_data_p;
542
543         /* Re-save smaller record. */
544         ld = (struct locking_data *)db_data.dptr;
545         ld->u.s.num_share_mode_entries = num_share_modes;
546
547         db_data.dsize = sizeof(struct locking_data) + (num_share_modes * sizeof(struct share_mode_entry)) + remaining_size;
548
549         if (tdb_store(db_ctx->smb_tdb, locking_key, db_data, TDB_REPLACE) != 0) {
550                 free(db_data.dptr);
551                 return -1;
552         }
553         free(db_data.dptr);
554         return 0;
555 }
556
557 int smb_change_share_mode_entry(struct smbdb_ctx *db_ctx,
558                                 uint64_t dev,
559                                 uint64_t ino,
560                                 uint64_t extid,
561                                 const struct smb_share_mode_entry *set_entry,
562                                 const struct smb_share_mode_entry *new_entry)
563 {
564         TDB_DATA db_data;
565         struct locking_key lk;
566         TDB_DATA locking_key =  get_locking_key(&lk, dev, ino, extid);
567         int num_share_modes = 0;
568         struct locking_data *ld = NULL; /* internal samba db state. */
569         struct share_mode_entry *shares = NULL;
570         size_t i;
571         int found_entry = 0;
572
573         db_data = tdb_fetch_compat(db_ctx->smb_tdb, locking_key);
574         if (!db_data.dptr) {
575                 return -1; /* Error - missing entry ! */
576         }
577
578         ld = (struct locking_data *)db_data.dptr;
579         num_share_modes = ld->u.s.num_share_mode_entries;
580         shares = (struct share_mode_entry *)(db_data.dptr + sizeof(struct locking_data));
581
582         for (i = 0; i < num_share_modes; i++) {
583                 struct share_mode_entry *share = &shares[i];
584                 struct server_id pid = share->pid;
585
586                 /* Check this process really exists. */
587                 if (kill(sharemodes_procid_to_pid(&pid), 0) == -1 && (errno == ESRCH)) {
588                         continue; /* No longer exists. */
589                 }
590
591                 if (share_mode_entry_equal(set_entry, share)) {
592                         create_share_mode_entry(share, new_entry, share->name_hash);
593                         found_entry = 1;
594                         break;
595                 }
596         }
597
598         if (!found_entry) {
599                 free(db_data.dptr);
600                 return -1;
601         }
602
603         /* Save modified data. */
604         if (tdb_store(db_ctx->smb_tdb, locking_key, db_data, TDB_REPLACE) != 0) {
605                 free(db_data.dptr);
606                 return -1;
607         }
608         free(db_data.dptr);
609         return 0;
610 }