root/source3/lib/util_tdb.c

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

DEFINITIONS

This source file includes following definitions.
  1. gotalarm_sig
  2. tdb_chainlock_with_timeout_internal
  3. tdb_chainlock_with_timeout
  4. tdb_lock_bystring_with_timeout
  5. tdb_read_lock_bystring_with_timeout
  6. tdb_trans_store_bystring
  7. tdb_pack_va
  8. tdb_pack
  9. tdb_pack_append
  10. tdb_unpack
  11. tdb_log
  12. tdb_open_log
  13. tdb_trans_store
  14. tdb_trans_delete
  15. tdb_wrap_log
  16. tdb_wrap_destructor
  17. tdb_wrap_open
  18. map_nt_error_from_tdb

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    tdb utility functions
   4    Copyright (C) Andrew Tridgell   1992-1998
   5    Copyright (C) Rafal Szczesniak  2002
   6    Copyright (C) Michael Adam      2007
   7    
   8    This program is free software; you can redistribute it and/or modify
   9    it under the terms of the GNU General Public License as published by
  10    the Free Software Foundation; either version 3 of the License, or
  11    (at your option) any later version.
  12    
  13    This program is distributed in the hope that it will be useful,
  14    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16    GNU General Public License for more details.
  17    
  18    You should have received a copy of the GNU General Public License
  19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  20 */
  21 
  22 #include "includes.h"
  23 #undef malloc
  24 #undef realloc
  25 #undef calloc
  26 #undef strdup
  27 
  28 /* these are little tdb utility functions that are meant to make
  29    dealing with a tdb database a little less cumbersome in Samba */
  30 
  31 static SIG_ATOMIC_T gotalarm;
  32 
  33 /***************************************************************
  34  Signal function to tell us we timed out.
  35 ****************************************************************/
  36 
  37 static void gotalarm_sig(void)
     /* [<][>][^][v][top][bottom][index][help] */
  38 {
  39         gotalarm = 1;
  40 }
  41 
  42 /****************************************************************************
  43  Lock a chain with timeout (in seconds).
  44 ****************************************************************************/
  45 
  46 static int tdb_chainlock_with_timeout_internal( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout, int rw_type)
     /* [<][>][^][v][top][bottom][index][help] */
  47 {
  48         /* Allow tdb_chainlock to be interrupted by an alarm. */
  49         int ret;
  50         gotalarm = 0;
  51 
  52         if (timeout) {
  53                 CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
  54                 tdb_setalarm_sigptr(tdb, &gotalarm);
  55                 alarm(timeout);
  56         }
  57 
  58         if (rw_type == F_RDLCK)
  59                 ret = tdb_chainlock_read(tdb, key);
  60         else
  61                 ret = tdb_chainlock(tdb, key);
  62 
  63         if (timeout) {
  64                 alarm(0);
  65                 tdb_setalarm_sigptr(tdb, NULL);
  66                 CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
  67                 if (gotalarm && (ret == -1)) {
  68                         DEBUG(0,("tdb_chainlock_with_timeout_internal: alarm (%u) timed out for key %s in tdb %s\n",
  69                                 timeout, key.dptr, tdb_name(tdb)));
  70                         /* TODO: If we time out waiting for a lock, it might
  71                          * be nice to use F_GETLK to get the pid of the
  72                          * process currently holding the lock and print that
  73                          * as part of the debugging message. -- mbp */
  74                         return -1;
  75                 }
  76         }
  77 
  78         return ret;
  79 }
  80 
  81 /****************************************************************************
  82  Write lock a chain. Return -1 if timeout or lock failed.
  83 ****************************************************************************/
  84 
  85 int tdb_chainlock_with_timeout( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout)
     /* [<][>][^][v][top][bottom][index][help] */
  86 {
  87         return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_WRLCK);
  88 }
  89 
  90 int tdb_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval,
     /* [<][>][^][v][top][bottom][index][help] */
  91                                    int timeout)
  92 {
  93         TDB_DATA key = string_term_tdb_data(keyval);
  94         
  95         return tdb_chainlock_with_timeout(tdb, key, timeout);
  96 }
  97 
  98 /****************************************************************************
  99  Read lock a chain by string. Return -1 if timeout or lock failed.
 100 ****************************************************************************/
 101 
 102 int tdb_read_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval, unsigned int timeout)
     /* [<][>][^][v][top][bottom][index][help] */
 103 {
 104         TDB_DATA key = string_term_tdb_data(keyval);
 105         
 106         return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_RDLCK);
 107 }
 108 
 109 
 110 
 111 
 112 int tdb_trans_store_bystring(TDB_CONTEXT *tdb, const char *keystr,
     /* [<][>][^][v][top][bottom][index][help] */
 113                              TDB_DATA data, int flags)
 114 {
 115         TDB_DATA key = string_term_tdb_data(keystr);
 116         
 117         return tdb_trans_store(tdb, key, data, flags);
 118 }
 119 
 120 /****************************************************************************
 121  Useful pair of routines for packing/unpacking data consisting of
 122  integers and strings.
 123 ****************************************************************************/
 124 
 125 static size_t tdb_pack_va(uint8 *buf, int bufsize, const char *fmt, va_list ap)
     /* [<][>][^][v][top][bottom][index][help] */
 126 {
 127         uint8 bt;
 128         uint16 w;
 129         uint32 d;
 130         int i;
 131         void *p;
 132         int len;
 133         char *s;
 134         char c;
 135         uint8 *buf0 = buf;
 136         const char *fmt0 = fmt;
 137         int bufsize0 = bufsize;
 138 
 139         while (*fmt) {
 140                 switch ((c = *fmt++)) {
 141                 case 'b': /* unsigned 8-bit integer */
 142                         len = 1;
 143                         bt = (uint8)va_arg(ap, int);
 144                         if (bufsize && bufsize >= len)
 145                                 SSVAL(buf, 0, bt);
 146                         break;
 147                 case 'w': /* unsigned 16-bit integer */
 148                         len = 2;
 149                         w = (uint16)va_arg(ap, int);
 150                         if (bufsize && bufsize >= len)
 151                                 SSVAL(buf, 0, w);
 152                         break;
 153                 case 'd': /* signed 32-bit integer (standard int in most systems) */
 154                         len = 4;
 155                         d = va_arg(ap, uint32);
 156                         if (bufsize && bufsize >= len)
 157                                 SIVAL(buf, 0, d);
 158                         break;
 159                 case 'p': /* pointer */
 160                         len = 4;
 161                         p = va_arg(ap, void *);
 162                         d = p?1:0;
 163                         if (bufsize && bufsize >= len)
 164                                 SIVAL(buf, 0, d);
 165                         break;
 166                 case 'P': /* null-terminated string */
 167                         s = va_arg(ap,char *);
 168                         w = strlen(s);
 169                         len = w + 1;
 170                         if (bufsize && bufsize >= len)
 171                                 memcpy(buf, s, len);
 172                         break;
 173                 case 'f': /* null-terminated string */
 174                         s = va_arg(ap,char *);
 175                         w = strlen(s);
 176                         len = w + 1;
 177                         if (bufsize && bufsize >= len)
 178                                 memcpy(buf, s, len);
 179                         break;
 180                 case 'B': /* fixed-length string */
 181                         i = va_arg(ap, int);
 182                         s = va_arg(ap, char *);
 183                         len = 4+i;
 184                         if (bufsize && bufsize >= len) {
 185                                 SIVAL(buf, 0, i);
 186                                 memcpy(buf+4, s, i);
 187                         }
 188                         break;
 189                 default:
 190                         DEBUG(0,("Unknown tdb_pack format %c in %s\n", 
 191                                  c, fmt));
 192                         len = 0;
 193                         break;
 194                 }
 195 
 196                 buf += len;
 197                 if (bufsize)
 198                         bufsize -= len;
 199                 if (bufsize < 0)
 200                         bufsize = 0;
 201         }
 202 
 203         DEBUG(18,("tdb_pack_va(%s, %d) -> %d\n", 
 204                  fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
 205         
 206         return PTR_DIFF(buf, buf0);
 207 }
 208 
 209 size_t tdb_pack(uint8 *buf, int bufsize, const char *fmt, ...)
     /* [<][>][^][v][top][bottom][index][help] */
 210 {
 211         va_list ap;
 212         size_t result;
 213 
 214         va_start(ap, fmt);
 215         result = tdb_pack_va(buf, bufsize, fmt, ap);
 216         va_end(ap);
 217         return result;
 218 }
 219 
 220 bool tdb_pack_append(TALLOC_CTX *mem_ctx, uint8 **buf, size_t *len,
     /* [<][>][^][v][top][bottom][index][help] */
 221                      const char *fmt, ...)
 222 {
 223         va_list ap;
 224         size_t len1, len2;
 225 
 226         va_start(ap, fmt);
 227         len1 = tdb_pack_va(NULL, 0, fmt, ap);
 228         va_end(ap);
 229 
 230         if (mem_ctx != NULL) {
 231                 *buf = TALLOC_REALLOC_ARRAY(mem_ctx, *buf, uint8,
 232                                             (*len) + len1);
 233         } else {
 234                 *buf = SMB_REALLOC_ARRAY(*buf, uint8, (*len) + len1);
 235         }
 236 
 237         if (*buf == NULL) {
 238                 return False;
 239         }
 240 
 241         va_start(ap, fmt);
 242         len2 = tdb_pack_va((*buf)+(*len), len1, fmt, ap);
 243         va_end(ap);
 244 
 245         if (len1 != len2) {
 246                 return False;
 247         }
 248 
 249         *len += len2;
 250 
 251         return True;
 252 }
 253 
 254 /****************************************************************************
 255  Useful pair of routines for packing/unpacking data consisting of
 256  integers and strings.
 257 ****************************************************************************/
 258 
 259 int tdb_unpack(const uint8 *buf, int bufsize, const char *fmt, ...)
     /* [<][>][^][v][top][bottom][index][help] */
 260 {
 261         va_list ap;
 262         uint8 *bt;
 263         uint16 *w;
 264         uint32 *d;
 265         int len;
 266         int *i;
 267         void **p;
 268         char *s, **b, **ps;
 269         char c;
 270         const uint8 *buf0 = buf;
 271         const char *fmt0 = fmt;
 272         int bufsize0 = bufsize;
 273 
 274         va_start(ap, fmt);
 275 
 276         while (*fmt) {
 277                 switch ((c=*fmt++)) {
 278                 case 'b': /* unsigned 8-bit integer */
 279                         len = 1;
 280                         bt = va_arg(ap, uint8 *);
 281                         if (bufsize < len)
 282                                 goto no_space;
 283                         *bt = SVAL(buf, 0);
 284                         break;
 285                 case 'w': /* unsigned 16-bit integer */
 286                         len = 2;
 287                         w = va_arg(ap, uint16 *);
 288                         if (bufsize < len)
 289                                 goto no_space;
 290                         *w = SVAL(buf, 0);
 291                         break;
 292                 case 'd': /* signed 32-bit integer (standard int in most systems) */
 293                         len = 4;
 294                         d = va_arg(ap, uint32 *);
 295                         if (bufsize < len)
 296                                 goto no_space;
 297                         *d = IVAL(buf, 0);
 298                         break;
 299                 case 'p': /* pointer */
 300                         len = 4;
 301                         p = va_arg(ap, void **);
 302                         if (bufsize < len)
 303                                 goto no_space;
 304                         /*
 305                          * This isn't a real pointer - only a token (1 or 0)
 306                          * to mark the fact a pointer is present.
 307                          */
 308 
 309                         *p = (void *)(IVAL(buf, 0) ? (void *)1 : NULL);
 310                         break;
 311                 case 'P': /* null-terminated string */
 312                         /* Return malloc'ed string. */
 313                         ps = va_arg(ap,char **);
 314                         len = strlen((const char *)buf) + 1;
 315                         *ps = SMB_STRDUP((const char *)buf);
 316                         break;
 317                 case 'f': /* null-terminated string */
 318                         s = va_arg(ap,char *);
 319                         len = strlen((const char *)buf) + 1;
 320                         if (bufsize < len || len > sizeof(fstring))
 321                                 goto no_space;
 322                         memcpy(s, buf, len);
 323                         break;
 324                 case 'B': /* fixed-length string */
 325                         i = va_arg(ap, int *);
 326                         b = va_arg(ap, char **);
 327                         len = 4;
 328                         if (bufsize < len)
 329                                 goto no_space;
 330                         *i = IVAL(buf, 0);
 331                         if (! *i) {
 332                                 *b = NULL;
 333                                 break;
 334                         }
 335                         len += *i;
 336                         if (bufsize < len)
 337                                 goto no_space;
 338                         *b = (char *)SMB_MALLOC(*i);
 339                         if (! *b)
 340                                 goto no_space;
 341                         memcpy(*b, buf+4, *i);
 342                         break;
 343                 default:
 344                         DEBUG(0,("Unknown tdb_unpack format %c in %s\n",
 345                                  c, fmt));
 346 
 347                         len = 0;
 348                         break;
 349                 }
 350 
 351                 buf += len;
 352                 bufsize -= len;
 353         }
 354 
 355         va_end(ap);
 356 
 357         DEBUG(18,("tdb_unpack(%s, %d) -> %d\n",
 358                  fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
 359 
 360         return PTR_DIFF(buf, buf0);
 361 
 362  no_space:
 363         va_end(ap);
 364         return -1;
 365 }
 366 
 367 
 368 /****************************************************************************
 369  Log tdb messages via DEBUG().
 370 ****************************************************************************/
 371 
 372 static void tdb_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, const char *format, ...)
     /* [<][>][^][v][top][bottom][index][help] */
 373 {
 374         va_list ap;
 375         char *ptr = NULL;
 376         int ret;
 377 
 378         va_start(ap, format);
 379         ret = vasprintf(&ptr, format, ap);
 380         va_end(ap);
 381 
 382         if ((ret == -1) || !*ptr)
 383                 return;
 384 
 385         DEBUG((int)level, ("tdb(%s): %s", tdb_name(tdb) ? tdb_name(tdb) : "unnamed", ptr));
 386         SAFE_FREE(ptr);
 387 }
 388 
 389 /****************************************************************************
 390  Like tdb_open() but also setup a logging function that redirects to
 391  the samba DEBUG() system.
 392 ****************************************************************************/
 393 
 394 TDB_CONTEXT *tdb_open_log(const char *name, int hash_size, int tdb_flags,
     /* [<][>][^][v][top][bottom][index][help] */
 395                           int open_flags, mode_t mode)
 396 {
 397         TDB_CONTEXT *tdb;
 398         struct tdb_logging_context log_ctx;
 399 
 400         if (!lp_use_mmap())
 401                 tdb_flags |= TDB_NOMMAP;
 402 
 403         log_ctx.log_fn = tdb_log;
 404         log_ctx.log_private = NULL;
 405 
 406         if ((hash_size == 0) && (name != NULL)) {
 407                 const char *base = strrchr_m(name, '/');
 408                 if (base != NULL) {
 409                         base += 1;
 410                 }
 411                 else {
 412                         base = name;
 413                 }
 414                 hash_size = lp_parm_int(-1, "tdb_hashsize", base, 0);
 415         }
 416 
 417         tdb = tdb_open_ex(name, hash_size, tdb_flags, 
 418                           open_flags, mode, &log_ctx, NULL);
 419         if (!tdb)
 420                 return NULL;
 421 
 422         return tdb;
 423 }
 424 
 425 /****************************************************************************
 426  tdb_store, wrapped in a transaction. This way we make sure that a process
 427  that dies within writing does not leave a corrupt tdb behind.
 428 ****************************************************************************/
 429 
 430 int tdb_trans_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
     /* [<][>][^][v][top][bottom][index][help] */
 431                     int flag)
 432 {
 433         int res;
 434 
 435         if ((res = tdb_transaction_start(tdb)) != 0) {
 436                 DEBUG(5, ("tdb_transaction_start failed\n"));
 437                 return res;
 438         }
 439 
 440         if ((res = tdb_store(tdb, key, dbuf, flag)) != 0) {
 441                 DEBUG(10, ("tdb_store failed\n"));
 442                 if (tdb_transaction_cancel(tdb) != 0) {
 443                         smb_panic("Cancelling transaction failed");
 444                 }
 445                 return res;
 446         }
 447 
 448         if ((res = tdb_transaction_commit(tdb)) != 0) {
 449                 DEBUG(5, ("tdb_transaction_commit failed\n"));
 450         }
 451 
 452         return res;
 453 }
 454 
 455 /****************************************************************************
 456  tdb_delete, wrapped in a transaction. This way we make sure that a process
 457  that dies within deleting does not leave a corrupt tdb behind.
 458 ****************************************************************************/
 459 
 460 int tdb_trans_delete(struct tdb_context *tdb, TDB_DATA key)
     /* [<][>][^][v][top][bottom][index][help] */
 461 {
 462         int res;
 463 
 464         if ((res = tdb_transaction_start(tdb)) != 0) {
 465                 DEBUG(5, ("tdb_transaction_start failed\n"));
 466                 return res;
 467         }
 468 
 469         if ((res = tdb_delete(tdb, key)) != 0) {
 470                 DEBUG(10, ("tdb_delete failed\n"));
 471                 if (tdb_transaction_cancel(tdb) != 0) {
 472                         smb_panic("Cancelling transaction failed");
 473                 }
 474                 return res;
 475         }
 476 
 477         if ((res = tdb_transaction_commit(tdb)) != 0) {
 478                 DEBUG(5, ("tdb_transaction_commit failed\n"));
 479         }
 480 
 481         return res;
 482 }
 483 
 484 /*
 485  Log tdb messages via DEBUG().
 486 */
 487 static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, 
     /* [<][>][^][v][top][bottom][index][help] */
 488                          const char *format, ...) PRINTF_ATTRIBUTE(3,4);
 489 
 490 static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, 
 491                          const char *format, ...)
 492 {
 493         va_list ap;
 494         char *ptr = NULL;
 495         int debuglevel = 0;
 496         int ret;
 497 
 498         switch (level) {
 499         case TDB_DEBUG_FATAL:
 500                 debuglevel = 0;
 501                 break;
 502         case TDB_DEBUG_ERROR:
 503                 debuglevel = 1;
 504                 break;
 505         case TDB_DEBUG_WARNING:
 506                 debuglevel = 2;
 507                 break;
 508         case TDB_DEBUG_TRACE:
 509                 debuglevel = 5;
 510                 break;
 511         default:
 512                 debuglevel = 0;
 513         }               
 514 
 515         va_start(ap, format);
 516         ret = vasprintf(&ptr, format, ap);
 517         va_end(ap);
 518 
 519         if (ret != -1) {
 520                 const char *name = tdb_name(tdb);
 521                 DEBUG(debuglevel, ("tdb(%s): %s", name ? name : "unnamed", ptr));
 522                 free(ptr);
 523         }
 524 }
 525 
 526 static struct tdb_wrap *tdb_list;
 527 
 528 /* destroy the last connection to a tdb */
 529 static int tdb_wrap_destructor(struct tdb_wrap *w)
     /* [<][>][^][v][top][bottom][index][help] */
 530 {
 531         tdb_close(w->tdb);
 532         DLIST_REMOVE(tdb_list, w);
 533         return 0;
 534 }                                
 535 
 536 /*
 537   wrapped connection to a tdb database
 538   to close just talloc_free() the tdb_wrap pointer
 539  */
 540 struct tdb_wrap *tdb_wrap_open(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 541                                const char *name, int hash_size, int tdb_flags,
 542                                int open_flags, mode_t mode)
 543 {
 544         struct tdb_wrap *w;
 545         struct tdb_logging_context log_ctx;
 546         log_ctx.log_fn = tdb_wrap_log;
 547 
 548         if (!lp_use_mmap())
 549                 tdb_flags |= TDB_NOMMAP;
 550 
 551         for (w=tdb_list;w;w=w->next) {
 552                 if (strcmp(name, w->name) == 0) {
 553                         /*
 554                          * Yes, talloc_reference is exactly what we want
 555                          * here. Otherwise we would have to implement our own
 556                          * reference counting.
 557                          */
 558                         return talloc_reference(mem_ctx, w);
 559                 }
 560         }
 561 
 562         w = talloc(mem_ctx, struct tdb_wrap);
 563         if (w == NULL) {
 564                 return NULL;
 565         }
 566 
 567         if (!(w->name = talloc_strdup(w, name))) {
 568                 talloc_free(w);
 569                 return NULL;
 570         }
 571 
 572         if ((hash_size == 0) && (name != NULL)) {
 573                 const char *base = strrchr_m(name, '/');
 574                 if (base != NULL) {
 575                         base += 1;
 576                 }
 577                 else {
 578                         base = name;
 579                 }
 580                 hash_size = lp_parm_int(-1, "tdb_hashsize", base, 0);
 581         }
 582 
 583         w->tdb = tdb_open_ex(name, hash_size, tdb_flags, 
 584                              open_flags, mode, &log_ctx, NULL);
 585         if (w->tdb == NULL) {
 586                 talloc_free(w);
 587                 return NULL;
 588         }
 589 
 590         talloc_set_destructor(w, tdb_wrap_destructor);
 591 
 592         DLIST_ADD(tdb_list, w);
 593 
 594         return w;
 595 }
 596 
 597 NTSTATUS map_nt_error_from_tdb(enum TDB_ERROR err)
     /* [<][>][^][v][top][bottom][index][help] */
 598 {
 599         struct { enum TDB_ERROR err; NTSTATUS status; } map[] =
 600                 { { TDB_SUCCESS,        NT_STATUS_OK },
 601                   { TDB_ERR_CORRUPT,    NT_STATUS_INTERNAL_DB_CORRUPTION },
 602                   { TDB_ERR_IO,         NT_STATUS_UNEXPECTED_IO_ERROR },
 603                   { TDB_ERR_OOM,        NT_STATUS_NO_MEMORY },
 604                   { TDB_ERR_EXISTS,     NT_STATUS_OBJECT_NAME_COLLISION },
 605 
 606                   /*
 607                    * TDB_ERR_LOCK is very broad, we could for example
 608                    * distinguish between fcntl locks and invalid lock
 609                    * sequences. So NT_STATUS_FILE_LOCK_CONFLICT is a
 610                    * compromise.
 611                    */
 612                   { TDB_ERR_LOCK,       NT_STATUS_FILE_LOCK_CONFLICT },
 613                   /*
 614                    * The next two ones in the enum are not actually used
 615                    */
 616                   { TDB_ERR_NOLOCK,     NT_STATUS_FILE_LOCK_CONFLICT },
 617                   { TDB_ERR_LOCK_TIMEOUT, NT_STATUS_FILE_LOCK_CONFLICT },
 618                   { TDB_ERR_NOEXIST,    NT_STATUS_NOT_FOUND },
 619                   { TDB_ERR_EINVAL,     NT_STATUS_INVALID_PARAMETER },
 620                   { TDB_ERR_RDONLY,     NT_STATUS_ACCESS_DENIED }
 621                 };
 622 
 623         int i;
 624 
 625         for (i=0; i < sizeof(map) / sizeof(map[0]); i++) {
 626                 if (err == map[i].err) {
 627                         return map[i].status;
 628                 }
 629         }
 630 
 631         return NT_STATUS_INTERNAL_ERROR;
 632 }

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