LCOV - code coverage report
Current view: top level - source3/lib - util_tdb.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 169 233 72.5 %
Date: 2021-09-23 10:06:22 Functions: 11 12 91.7 %

          Line data    Source code
       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             : #include "system/filesys.h"
      24             : #include "util_tdb.h"
      25             : #include "cbuf.h"
      26             : 
      27             : #undef malloc
      28             : #undef realloc
      29             : #undef calloc
      30             : #undef strdup
      31             : 
      32             : /****************************************************************************
      33             :  Useful pair of routines for packing/unpacking data consisting of
      34             :  integers and strings.
      35             : ****************************************************************************/
      36             : 
      37      551387 : static size_t tdb_pack_va(uint8_t *buf, int bufsize, const char *fmt, va_list ap)
      38             : {
      39             :         uint8_t bt;
      40             :         uint16_t w;
      41             :         uint32_t d;
      42             :         int i;
      43             :         void *p;
      44      551387 :         int len = 0;
      45             :         char *s;
      46             :         char c;
      47      551387 :         const char *fmt0 = fmt;
      48      551387 :         int bufsize0 = bufsize;
      49      551387 :         size_t to_write = 0;
      50     3895296 :         while (*fmt) {
      51     2871707 :                 switch ((c = *fmt++)) {
      52           0 :                 case 'b': /* unsigned 8-bit integer */
      53           0 :                         len = 1;
      54           0 :                         bt = (uint8_t)va_arg(ap, int);
      55           0 :                         if (bufsize && bufsize >= len)
      56           0 :                                 SSVAL(buf, 0, bt);
      57           0 :                         break;
      58      147258 :                 case 'w': /* unsigned 16-bit integer */
      59      147258 :                         len = 2;
      60      147258 :                         w = (uint16_t)va_arg(ap, int);
      61      147258 :                         if (bufsize && bufsize >= len)
      62       73629 :                                 SSVAL(buf, 0, w);
      63      147222 :                         break;
      64     1179215 :                 case 'd': /* signed 32-bit integer (standard int in most systems) */
      65     1179215 :                         len = 4;
      66     1179215 :                         d = va_arg(ap, uint32_t);
      67     1179215 :                         if (bufsize && bufsize >= len)
      68      597978 :                                 SIVAL(buf, 0, d);
      69     1178155 :                         break;
      70           0 :                 case 'p': /* pointer */
      71           0 :                         len = 4;
      72           0 :                         p = va_arg(ap, void *);
      73           0 :                         d = p?1:0;
      74           0 :                         if (bufsize && bufsize >= len)
      75           0 :                                 SIVAL(buf, 0, d);
      76           0 :                         break;
      77      482546 :                 case 'P': /* null-terminated string */
      78             :                 case 'f': /* null-terminated string */
      79      482546 :                         s = va_arg(ap,char *);
      80      482546 :                         if (s == NULL) {
      81           0 :                                 smb_panic("Invalid argument");
      82             :                         }
      83      482546 :                         w = strlen(s);
      84      482546 :                         len = w + 1;
      85      482546 :                         if (bufsize && bufsize >= len)
      86      299216 :                                 memcpy(buf, s, len);
      87      481808 :                         break;
      88     1062688 :                 case 'B': /* fixed-length string */
      89     1062688 :                         i = va_arg(ap, int);
      90     1062688 :                         s = va_arg(ap, char *);
      91     1062688 :                         len = 4+i;
      92     1062688 :                         if (bufsize && bufsize >= len) {
      93      531344 :                                 SIVAL(buf, 0, i);
      94      531344 :                                 if (s != NULL) {
      95      384506 :                                         memcpy(buf+4, s, i);
      96             :                                 }
      97             :                         }
      98     1062012 :                         break;
      99           0 :                 default:
     100           0 :                         DEBUG(0,("Unknown tdb_pack format %c in %s\n", 
     101             :                                  c, fmt));
     102           0 :                         len = 0;
     103           0 :                         break;
     104             :                 }
     105             : 
     106     2871707 :                 to_write += len;
     107     2871707 :                 if (bufsize > 0) {
     108     1502279 :                         bufsize -= len;
     109     1502279 :                         buf += len;
     110             :                 }
     111     2871707 :                 if (bufsize < 0)
     112      136598 :                         bufsize = 0;
     113             :         }
     114             : 
     115      551387 :         DEBUG(18,("tdb_pack_va(%s, %d) -> %d\n", 
     116             :                  fmt0, bufsize0, (int)to_write));
     117             : 
     118      551387 :         return to_write;
     119             : }
     120             : 
     121      551387 : size_t tdb_pack(uint8_t *buf, int bufsize, const char *fmt, ...)
     122             : {
     123             :         va_list ap;
     124             :         size_t result;
     125             : 
     126      551387 :         va_start(ap, fmt);
     127      551387 :         result = tdb_pack_va(buf, bufsize, fmt, ap);
     128      551387 :         va_end(ap);
     129      551387 :         return result;
     130             : }
     131             : 
     132             : /****************************************************************************
     133             :  Useful pair of routines for packing/unpacking data consisting of
     134             :  integers and strings.
     135             : ****************************************************************************/
     136             : 
     137     4590923 : int tdb_unpack(const uint8_t *buf, int in_bufsize, const char *fmt, ...)
     138             : {
     139             :         va_list ap;
     140             :         uint8_t *bt;
     141             :         uint16_t *w;
     142             :         uint32_t *d;
     143     4590923 :         size_t bufsize = in_bufsize;
     144             :         size_t len;
     145             :         uint32_t *i;
     146             :         void **p;
     147             :         char *s, **b, **ps;
     148             :         char c;
     149     4590923 :         const uint8_t *buf0 = buf;
     150     4590923 :         const char *fmt0 = fmt;
     151             : 
     152     4590923 :         va_start(ap, fmt);
     153             : 
     154    20560969 :         while (*fmt) {
     155    12008422 :                 switch ((c=*fmt++)) {
     156           0 :                 case 'b': /* unsigned 8-bit integer */
     157           0 :                         len = 1;
     158           0 :                         bt = va_arg(ap, uint8_t *);
     159           0 :                         if (bufsize < len)
     160           0 :                                 goto no_space;
     161           0 :                         *bt = SVAL(buf, 0);
     162           0 :                         break;
     163      143184 :                 case 'w': /* unsigned 16-bit integer */
     164      143184 :                         len = 2;
     165      143184 :                         w = va_arg(ap, uint16_t *);
     166      143184 :                         if (bufsize < len)
     167           0 :                                 goto no_space;
     168      143184 :                         *w = SVAL(buf, 0);
     169      143184 :                         break;
     170     5436273 :                 case 'd': /* unsigned 32-bit integer (standard int in most systems) */
     171     5436273 :                         len = 4;
     172     5436273 :                         d = va_arg(ap, uint32_t *);
     173     5436273 :                         if (bufsize < len)
     174           0 :                                 goto no_space;
     175     5436273 :                         *d = IVAL(buf, 0);
     176     5436273 :                         break;
     177           0 :                 case 'p': /* pointer */
     178           0 :                         len = 4;
     179           0 :                         p = va_arg(ap, void **);
     180           0 :                         if (bufsize < len)
     181           0 :                                 goto no_space;
     182             :                         /*
     183             :                          * This isn't a real pointer - only a token (1 or 0)
     184             :                          * to mark the fact a pointer is present.
     185             :                          */
     186             : 
     187           0 :                         *p = (void *)(IVAL(buf, 0) ? (void *)1 : NULL);
     188           0 :                         break;
     189        1934 :                 case 'P': /* null-terminated string */
     190             :                         /* Return malloc'ed string. */
     191        1934 :                         ps = va_arg(ap,char **);
     192        1934 :                         len = strnlen((const char *)buf, bufsize) + 1;
     193        1934 :                         if (bufsize < len)
     194           0 :                                 goto no_space;
     195        1934 :                         if (ps != NULL) {
     196        1934 :                                 *ps = SMB_STRDUP((const char *)buf);
     197        1934 :                                 if (*ps == NULL) {
     198           0 :                                         goto no_space;
     199             :                                 }
     200             :                         }
     201        1934 :                         break;
     202     5121665 :                 case 'f': /* null-terminated string */
     203     5121665 :                         s = va_arg(ap,char *);
     204     5121665 :                         len = strnlen((const char *)buf, bufsize) + 1;
     205     5121665 :                         if (bufsize < len || len > sizeof(fstring))
     206           0 :                                 goto no_space;
     207     5121665 :                         if (s != NULL) {
     208     5120563 :                                 memcpy(s, buf, len);
     209             :                         }
     210     5120563 :                         break;
     211     1305366 :                 case 'B': /* fixed-length string */
     212     1305366 :                         i = va_arg(ap, uint32_t *);
     213     1305366 :                         b = va_arg(ap, char **);
     214     1305366 :                         len = 4;
     215     1305366 :                         if (bufsize < len)
     216           0 :                                 goto no_space;
     217     1305366 :                         *i = IVAL(buf, 0);
     218     1305366 :                         if (! *i) {
     219      300551 :                                 *b = NULL;
     220      300551 :                                 break;
     221             :                         }
     222     1004815 :                         len += *i;
     223     1004815 :                         if (len < *i) {
     224           0 :                                 goto no_space;
     225             :                         }
     226     1004815 :                         if (bufsize < len)
     227           0 :                                 goto no_space;
     228     1004815 :                         if (b != NULL) {
     229     1004815 :                                 *b = (char *)SMB_MALLOC(*i);
     230     1004815 :                                 if (! *b)
     231           0 :                                         goto no_space;
     232     1004815 :                                 memcpy(*b, buf+4, *i);
     233             :                         }
     234     1004409 :                         break;
     235           0 :                 default:
     236           0 :                         DEBUG(0,("Unknown tdb_unpack format %c in %s\n",
     237             :                                  c, fmt));
     238             : 
     239           0 :                         len = 0;
     240           0 :                         break;
     241             :                 }
     242             : 
     243    12008422 :                 buf += len;
     244    12008422 :                 bufsize -= len;
     245             :         }
     246             : 
     247     4590923 :         va_end(ap);
     248             : 
     249     4590923 :         DEBUG(18,("tdb_unpack(%s, %d) -> %d\n",
     250             :                  fmt0, in_bufsize, (int)PTR_DIFF(buf, buf0)));
     251             : 
     252     4590923 :         return PTR_DIFF(buf, buf0);
     253             : 
     254           0 :  no_space:
     255           0 :         va_end(ap);
     256           0 :         return -1;
     257             : }
     258             : 
     259             : 
     260             : /****************************************************************************
     261             :  Log tdb messages via DEBUG().
     262             : ****************************************************************************/
     263             : 
     264             : static void tdb_log(TDB_CONTEXT *tdb, enum tdb_debug_level level,
     265             :                     const char *format, ...) PRINTF_ATTRIBUTE(3,4);
     266             : 
     267          43 : static void tdb_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, const char *format, ...)
     268             : {
     269             :         va_list ap;
     270          43 :         char *ptr = NULL;
     271             :         int ret;
     272             : 
     273          43 :         va_start(ap, format);
     274          43 :         ret = vasprintf(&ptr, format, ap);
     275          43 :         va_end(ap);
     276             : 
     277          43 :         if ((ret == -1) || !*ptr)
     278           0 :                 return;
     279             : 
     280          43 :         DEBUG((int)level, ("tdb(%s): %s", tdb_name(tdb) ? tdb_name(tdb) : "unnamed", ptr));
     281          43 :         SAFE_FREE(ptr);
     282             : }
     283             : 
     284             : /****************************************************************************
     285             :  Like tdb_open() but also setup a logging function that redirects to
     286             :  the samba DEBUG() system.
     287             : ****************************************************************************/
     288             : 
     289        1328 : TDB_CONTEXT *tdb_open_log(const char *name, int hash_size, int tdb_flags,
     290             :                           int open_flags, mode_t mode)
     291             : {
     292             :         TDB_CONTEXT *tdb;
     293        1328 :         struct tdb_logging_context log_ctx = { .log_fn = tdb_log };
     294             : 
     295        1328 :         if (!lp_use_mmap())
     296           0 :                 tdb_flags |= TDB_NOMMAP;
     297             : 
     298        1328 :         if ((hash_size == 0) && (name != NULL)) {
     299         176 :                 const char *base = strrchr_m(name, '/');
     300         176 :                 if (base != NULL) {
     301         176 :                         base += 1;
     302             :                 }
     303             :                 else {
     304           0 :                         base = name;
     305             :                 }
     306         176 :                 hash_size = lp_parm_int(-1, "tdb_hashsize", base, 0);
     307             :         }
     308             : 
     309        1328 :         tdb = tdb_open_ex(name, hash_size, tdb_flags,
     310             :                           open_flags, mode, &log_ctx, NULL);
     311        1328 :         if (!tdb)
     312          45 :                 return NULL;
     313             : 
     314        1283 :         return tdb;
     315             : }
     316             : 
     317      925176 : int tdb_data_cmp(TDB_DATA t1, TDB_DATA t2)
     318             : {
     319             :         int ret;
     320      925176 :         if (t1.dptr == NULL && t2.dptr != NULL) {
     321           0 :                 return -1;
     322             :         }
     323      925176 :         if (t1.dptr != NULL && t2.dptr == NULL) {
     324           0 :                 return 1;
     325             :         }
     326      925176 :         if (t1.dptr == t2.dptr) {
     327           0 :                 return t1.dsize - t2.dsize;
     328             :         }
     329      925176 :         ret = memcmp(t1.dptr, t2.dptr, MIN(t1.dsize, t2.dsize));
     330      925176 :         if (ret == 0) {
     331      925176 :                 return t1.dsize - t2.dsize;
     332             :         }
     333           0 :         return ret;
     334             : }
     335             : 
     336           8 : char *tdb_data_string(TALLOC_CTX *mem_ctx, TDB_DATA d)
     337             : {
     338             :         int len;
     339           8 :         char *ret = NULL;
     340           8 :         cbuf *ost = cbuf_new(mem_ctx);
     341             : 
     342           8 :         if (ost == NULL) {
     343           0 :                 return NULL;
     344             :         }
     345             : 
     346           8 :         len = cbuf_printf(ost, "%zu:", d.dsize);
     347           8 :         if (len == -1) {
     348           0 :                 goto done;
     349             :         }
     350             : 
     351           8 :         if (d.dptr == NULL) {
     352           0 :                 len = cbuf_puts(ost, "<NULL>", -1);
     353             :         } else {
     354           8 :                 len = cbuf_print_quoted(ost, (const char*)d.dptr, d.dsize);
     355             :         }
     356           8 :         if (len == -1) {
     357           0 :                 goto done;
     358             :         }
     359             : 
     360           8 :         cbuf_swapptr(ost, &ret, 0);
     361           8 :         talloc_steal(mem_ctx, ret);
     362             : 
     363           8 : done:
     364           8 :         talloc_free(ost);
     365           8 :         return ret;
     366             : }
     367             : 
     368             : static sig_atomic_t gotalarm;
     369             : 
     370             : /***************************************************************
     371             :  Signal function to tell us we timed out.
     372             : ****************************************************************/
     373             : 
     374           0 : static void gotalarm_sig(int signum)
     375             : {
     376           0 :         gotalarm = 1;
     377           0 : }
     378             : 
     379             : /****************************************************************************
     380             :  Lock a chain with timeout (in seconds).
     381             : ****************************************************************************/
     382             : 
     383        3760 : static int tdb_chainlock_with_timeout_internal( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout, int rw_type)
     384             : {
     385             :         /* Allow tdb_chainlock to be interrupted by an alarm. */
     386             :         int ret;
     387        3760 :         gotalarm = 0;
     388             : 
     389        3760 :         if (timeout) {
     390        3760 :                 CatchSignal(SIGALRM, gotalarm_sig);
     391        3760 :                 tdb_setalarm_sigptr(tdb, &gotalarm);
     392        3760 :                 alarm(timeout);
     393             :         }
     394             : 
     395        3760 :         if (rw_type == F_RDLCK)
     396         393 :                 ret = tdb_chainlock_read(tdb, key);
     397             :         else
     398        3367 :                 ret = tdb_chainlock(tdb, key);
     399             : 
     400        3760 :         if (timeout) {
     401        3760 :                 alarm(0);
     402        3760 :                 tdb_setalarm_sigptr(tdb, NULL);
     403        3760 :                 CatchSignal(SIGALRM, SIG_IGN);
     404        3760 :                 if (gotalarm && (ret != 0)) {
     405           0 :                         DEBUG(0,("tdb_chainlock_with_timeout_internal: alarm (%u) timed out for key %s in tdb %s\n",
     406             :                                 timeout, key.dptr, tdb_name(tdb)));
     407             :                         /* TODO: If we time out waiting for a lock, it might
     408             :                          * be nice to use F_GETLK to get the pid of the
     409             :                          * process currently holding the lock and print that
     410             :                          * as part of the debugging message. -- mbp */
     411           0 :                         return -1;
     412             :                 }
     413             :         }
     414             : 
     415        3760 :         return ret == 0 ? 0 : -1;
     416             : }
     417             : 
     418             : /****************************************************************************
     419             :  Write lock a chain. Return non-zero if timeout or lock failed.
     420             : ****************************************************************************/
     421             : 
     422        3367 : int tdb_chainlock_with_timeout( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout)
     423             : {
     424        3367 :         return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_WRLCK);
     425             : }
     426             : 
     427        2017 : int tdb_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval,
     428             :                                    int timeout)
     429             : {
     430        2017 :         TDB_DATA key = string_term_tdb_data(keyval);
     431             : 
     432        2017 :         return tdb_chainlock_with_timeout(tdb, key, timeout);
     433             : }
     434             : 
     435             : /****************************************************************************
     436             :  Read lock a chain by string. Return non-zero if timeout or lock failed.
     437             : ****************************************************************************/
     438             : 
     439         393 : int tdb_read_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval, unsigned int timeout)
     440             : {
     441         393 :         TDB_DATA key = string_term_tdb_data(keyval);
     442             : 
     443         393 :         return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_RDLCK);
     444             : }

Generated by: LCOV version 1.13