root/source3/libsmb/smb_share_modes.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sharemodes_procid_equal
  2. sharemodes_procid_to_pid
  3. smb_share_mode_db_open
  4. smb_share_mode_db_close
  5. get_locking_key
  6. smb_lock_share_mode_entry
  7. smb_unlock_share_mode_entry
  8. share_mode_entry_equal
  9. create_share_mode_entry
  10. smb_get_share_mode_entries
  11. smb_create_share_mode_entry_ex
  12. smb_create_share_mode_entry
  13. smb_delete_share_mode_entry
  14. smb_change_share_mode_entry

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

/* [<][>][^][v][top][bottom][index][help] */